Code with Misuse: |
class VariableReferenceCheck.ReferenceCheckingBehavior {
/**
* If the variable is declared more than once in a basic block, generate a
* warning. Also check if a variable is used in a given scope before it is
* declared, which suggest a likely error. Relies on the fact that
* references is in parse-tree order.
*/
private void checkVar(NodeTraversal t, Var v, List<Reference> references) {
blocksWithDeclarations.clear();
boolean isDeclaredInScope = false;
boolean isUnhoistedNamedFunction = false;
Reference hoistedFn = null;
// Look for hoisted functions.
for (Reference reference : references) {
if (reference.isHoistedFunction()) {
blocksWithDeclarations.add(reference.getBasicBlock());
isDeclaredInScope = true;
hoistedFn = reference;
break;
} else if (NodeUtil.isFunctionDeclaration(
reference.getNameNode().getParent())) {
isUnhoistedNamedFunction = true;
}
}
for (Reference reference : references) {
if (reference == hoistedFn) {
continue;
}
BasicBlock basicBlock = reference.getBasicBlock();
boolean isDeclaration = reference.isDeclaration();
if (isDeclaration) {
// Look through all the declarations we've found so far, and
// check if any of them are before this block.
for (BasicBlock declaredBlock : blocksWithDeclarations) {
if (declaredBlock.provablyExecutesBefore(basicBlock)) {
compiler.report(
JSError.make(reference.getSourceName(),
reference.getNameNode(),
checkLevel,
REDECLARED_VARIABLE, v.name));
break;
}
}
}
if (isUnhoistedNamedFunction && !isDeclaration && isDeclaredInScope) {
// Only allow an unhoisted named function to be used within the
// block it is declared.
for (BasicBlock declaredBlock : blocksWithDeclarations) {
if (!declaredBlock.provablyExecutesBefore(basicBlock)) {
compiler.report(
JSError.make(reference.getSourceName(),
reference.getNameNode(),
AMBIGUOUS_FUNCTION_DECL, v.name));
break;
}
}
}
if (!isDeclaration && !isDeclaredInScope) {
// Special case to deal with var goog = goog || {}
Node grandparent = reference.getGrandparent();
if (grandparent.getType() == Token.NAME
&& grandparent.getString() == v.name) {
continue;
}
// Only generate warnings if the scopes do not match in order
// to deal with possible forward declarations and recursion
if (reference.getScope() == v.scope) {
compiler.report(
JSError.make(reference.getSourceName(),
reference.getNameNode(),
checkLevel,
UNDECLARED_REFERENCE, v.name));
}
}
if (isDeclaration) {
blocksWithDeclarations.add(basicBlock);
isDeclaredInScope = true;
}
}
}
}
|