CFLint icon indicating copy to clipboard operation
CFLint copied to clipboard

Checking MISSING_VAR in conditional

Open KamasamaK opened this issue 7 years ago • 10 comments

MISSING_VAR does not account for declaration being in a separate branch.

<cfif someCondition>
  <cfset theVal = 1>
<cfelse>
  <cfset theVal = 0>
</cfif>

In the above example, the rule only reports theVal in the first branch. It should report the declaration in both branches.

KamasamaK avatar Aug 16 '17 23:08 KamasamaK

Curious to know does CF hoist var statements?

justinmclean avatar Aug 17 '17 02:08 justinmclean

Me too.

ryaneberly avatar Aug 17 '17 02:08 ryaneberly

Very interesting. It does hoist the scoping of var statements. It does not, however, hoist the scoping of variables declared using local. Ever since the explicit local scope was introduced in CF9, I have preferred that notation, but I did not realize this difference existed.

Example

KamasamaK avatar Aug 17 '17 19:08 KamasamaK

@KamasamaK, what does your discovery mean for this task?

ryaneberly avatar Dec 24 '17 02:12 ryaneberly

@ryaneberly In general, it means that if var is used for a variable anywhere within the function, including after the initialization or in a block that is not even executed, that the variable is local-scoped everywhere in the function and fine. However, if only using local. then it has to be on the variable's first use taking into account different execution branches.

From my testing, it seems that the MISSING_VAR rule only checks the first occurrence of a variable assignment. To be technically correct, a variable is still local-scoped even if var is used after the first occurrence. However, I don't think it is good practice to do so and would probably just leave the check as-is for that case.

It gets complicated when using local. instead of var. You would have to either change the check to only consider var instead or you would have to check that local. is used anywhere a variable could be initialized at runtime. The block below would be an example of a case where the variable is conditionally local-scoped, but it will pass CFLint's check for MISSING_VAR.

string function foo() {
  local.randomBoolean = getRandomBoolean();

  if (local.randomBoolean) {
    local.bar = "Absolutely";
  } else {
    bar = "Nope";
  }

  return bar;
}

KamasamaK avatar Dec 24 '17 20:12 KamasamaK

From my testing, it seems that this rule only checks the first occurrence of a variable assignment. To be technically correct, a variable is still local-scoped even if var is used after the first occurrence. However, I don't think it is good practice to do so and would probably just leave the check as-is for that case.

Oh really, it does hoist? So you can pretty much posthumous var-scope a variable? I wasn't aware of that at all.

I agree - it's not good practice to do that. So, CFLint should report on the first occurrence, but why shouldn't it report on both?

TheRealAgentK avatar Dec 28 '17 21:12 TheRealAgentK

@TheRealAgentK Yep. See this example to demonstrate.

Can you clarify what you mean by "report on both"?

KamasamaK avatar Dec 30 '17 01:12 KamasamaK

@KamasamaK , do you still stand by the opening statement. MISSING_VAR should be reported on both branches?

ryaneberly avatar May 05 '18 18:05 ryaneberly

@ryaneberly As long as the rule recommends using var instead of local. then no, it should not be necessary to report on both from that initial example. However, the issue from this comment would still need to be addressed.

KamasamaK avatar May 05 '18 18:05 KamasamaK

@KamasamaK . I agree. And I am a fan of (consistent) local scoping over the use of var.

ryaneberly avatar May 05 '18 19:05 ryaneberly