Java Code Examples for com.google.javascript.rhino.Node#isGetProp()

The following examples show how to use com.google.javascript.rhino.Node#isGetProp() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: Closure_17_TypedScopeCreator_t.java    From coming with MIT License 6 votes vote down vote up
/**
 * Returns the type specified in a JSDoc annotation near a GETPROP or NAME.
 *
 * Extracts type information from either the {@code @type} tag or from
 * the {@code @return} and {@code @param} tags.
 */
private JSType getDeclaredTypeInAnnotation(String sourceName,
    Node node, JSDocInfo info) {
  JSType jsType = null;
  Node objNode =
      node.isGetProp() ? node.getFirstChild() :
      NodeUtil.isObjectLitKey(node, node.getParent()) ? node.getParent() :
      null;
  if (info != null) {
    if (info.hasType()) {
      jsType = info.getType().evaluate(scope, typeRegistry);
    } else if (FunctionTypeBuilder.isFunctionTypeDeclaration(info)) {
      String fnName = node.getQualifiedName();
      jsType = createFunctionTypeFromNodes(
          null, fnName, info, node);
    }
  }
  return jsType;
}
 
Example 2
Source File: Closure_48_TypedScopeCreator_s.java    From coming with MIT License 6 votes vote down vote up
/**
 * Returns the type specified in a JSDoc annotation near a GETPROP or NAME.
 *
 * Extracts type information from either the {@code @type} tag or from
 * the {@code @return} and {@code @param} tags.
 */
private JSType getDeclaredTypeInAnnotation(String sourceName,
    Node node, JSDocInfo info) {
  JSType jsType = null;
  Node objNode =
      node.isGetProp() ? node.getFirstChild() :
      NodeUtil.isObjectLitKey(node, node.getParent()) ? node.getParent() :
      null;
  if (info != null) {
    if (info.hasType()) {
      jsType = info.getType().evaluate(scope, typeRegistry);
    } else if (FunctionTypeBuilder.isFunctionTypeDeclaration(info)) {
      String fnName = node.getQualifiedName();
      jsType = createFunctionTypeFromNodes(
          null, fnName, info, node);
    }
  }
  return jsType;
}
 
Example 3
Source File: PeepholeSubstituteAlternateSyntax.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
/**
 * @return Whether the node is a block with a single statement that is
 *     an expression.
 */
private boolean isFoldableExpressBlock(Node n) {
  if (n.isBlock()) {
    if (n.hasOneChild()) {
      Node maybeExpr = n.getFirstChild();
      if (maybeExpr.isExprResult()) {
        // IE has a bug where event handlers behave differently when
        // their return value is used vs. when their return value is in
        // an EXPR_RESULT. It's pretty freaking weird. See:
        // http://code.google.com/p/closure-compiler/issues/detail?id=291
        // We try to detect this case, and not fold EXPR_RESULTs
        // into other expressions.
        if (maybeExpr.getFirstChild().isCall()) {
          Node calledFn = maybeExpr.getFirstChild().getFirstChild();

          // We only have to worry about methods with an implicit 'this'
          // param, or this doesn't happen.
          if (calledFn.isGetElem()) {
            return false;
          } else if (calledFn.isGetProp() &&
                     calledFn.getLastChild().getString().startsWith("on")) {
            return false;
          }
        }

        return true;
      }
      return false;
    }
  }

  return false;
}
 
Example 4
Source File: TypeCheck.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
/** Check that we don't create new properties on structs. */
private void checkPropCreation(NodeTraversal t, Node lvalue) {
  if (lvalue.isGetProp()) {
    Node obj = lvalue.getFirstChild();
    Node prop = lvalue.getLastChild();
    JSType objType = getJSType(obj);
    String pname = prop.getString();
    if (objType.isStruct() && !objType.hasProperty(pname)) {
      if (!(obj.isThis() &&
            getJSType(t.getScope().getRootNode()).isConstructor())) {
        report(t, prop, ILLEGAL_PROPERTY_CREATION);
      }
    }
  }
}
 
Example 5
Source File: Closure_20_PeepholeSubstituteAlternateSyntax_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * @return Whether the node is a block with a single statement that is
 *     an expression.
 */
private boolean isFoldableExpressBlock(Node n) {
  if (n.isBlock()) {
    if (n.hasOneChild()) {
      Node maybeExpr = n.getFirstChild();
      if (maybeExpr.isExprResult()) {
        // IE has a bug where event handlers behave differently when
        // their return value is used vs. when their return value is in
        // an EXPR_RESULT. It's pretty freaking weird. See:
        // http://code.google.com/p/closure-compiler/issues/detail?id=291
        // We try to detect this case, and not fold EXPR_RESULTs
        // into other expressions.
        if (maybeExpr.getFirstChild().isCall()) {
          Node calledFn = maybeExpr.getFirstChild().getFirstChild();

          // We only have to worry about methods with an implicit 'this'
          // param, or this doesn't happen.
          if (calledFn.isGetElem()) {
            return false;
          } else if (calledFn.isGetProp() &&
                     calledFn.getLastChild().getString().startsWith("on")) {
            return false;
          }
        }

        return true;
      }
      return false;
    }
  }

  return false;
}
 
Example 6
Source File: Cardumen_0087_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * @return The class name part of a qualified prototype name.
 */
static Node getPrototypeClassName(Node qName) {
  Node cur = qName;
  while (cur.isGetProp()) {
    if (cur.getLastChild().getString().equals("prototype")) {
      return cur.getFirstChild();
    } else {
      cur = cur.getFirstChild();
    }
  }
  return null;
}
 
Example 7
Source File: Cardumen_0021_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * If this is an assign to a variable or its property, return it.
 * Otherwise, return null.
 */
static Assign maybeCreateAssign(Node assignNode) {
  Preconditions.checkState(NodeUtil.isAssignmentOp(assignNode));

  // Skip one level of GETPROPs or GETELEMs.
  //
  // Don't skip more than one level, because then we get into
  // situations where assigns to properties of properties will always
  // trigger side-effects, and the variable they're on cannot be removed.
  boolean isPropAssign = false;
  Node current = assignNode.getFirstChild();
  if (NodeUtil.isGet(current)) {
    current = current.getFirstChild();
    isPropAssign = true;

    if (current.isGetProp() &&
        current.getLastChild().getString().equals("prototype")) {
      // Prototype properties sets should be considered like normal
      // property sets.
      current = current.getFirstChild();
    }
  }

  if (current.isName()) {
    return new Assign(assignNode, current, isPropAssign);
  }
  return null;
}
 
Example 8
Source File: Closure_10_NodeUtil_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * @return The class name part of a qualified prototype name.
 */
static Node getPrototypeClassName(Node qName) {
  Node cur = qName;
  while (cur.isGetProp()) {
    if (cur.getLastChild().getString().equals("prototype")) {
      return cur.getFirstChild();
    } else {
      cur = cur.getFirstChild();
    }
  }
  return null;
}
 
Example 9
Source File: Closure_20_PeepholeSubstituteAlternateSyntax_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * @return Whether the node is a block with a single statement that is
 *     an expression.
 */
private boolean isFoldableExpressBlock(Node n) {
  if (n.isBlock()) {
    if (n.hasOneChild()) {
      Node maybeExpr = n.getFirstChild();
      if (maybeExpr.isExprResult()) {
        // IE has a bug where event handlers behave differently when
        // their return value is used vs. when their return value is in
        // an EXPR_RESULT. It's pretty freaking weird. See:
        // http://code.google.com/p/closure-compiler/issues/detail?id=291
        // We try to detect this case, and not fold EXPR_RESULTs
        // into other expressions.
        if (maybeExpr.getFirstChild().isCall()) {
          Node calledFn = maybeExpr.getFirstChild().getFirstChild();

          // We only have to worry about methods with an implicit 'this'
          // param, or this doesn't happen.
          if (calledFn.isGetElem()) {
            return false;
          } else if (calledFn.isGetProp() &&
                     calledFn.getLastChild().getString().startsWith("on")) {
            return false;
          }
        }

        return true;
      }
      return false;
    }
  }

  return false;
}
 
Example 10
Source File: Closure_132_PeepholeSubstituteAlternateSyntax_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Does the expression contain a property assignment?
 */
private boolean isPropertyAssignmentInExpression(Node n) {
  Predicate<Node> isPropertyAssignmentInExpressionPredicate =
      new Predicate<Node>() {
    @Override
    public boolean apply(Node input) {
      return (input.isGetProp() &&
          input.getParent().isAssign());
    }
  };

  return NodeUtil.has(n, isPropertyAssignmentInExpressionPredicate,
      DONT_TRAVERSE_FUNCTIONS_PREDICATE);
}
 
Example 11
Source File: NameReferenceGraphConstruction.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
/**
 * @return true if n MUST be a prototype name reference.
 */
private boolean isPrototypeNameReference(Node n) {
  if (!n.isGetProp()) {
    return false;
  }
  JSType type = getType(n.getFirstChild());
  if (type.isUnknownType() || type.isUnionType()) {
    return false;
  }
  return (type.isInstanceType() || type.autoboxesTo() != null);
}
 
Example 12
Source File: Closure_119_GlobalNamespace_s.java    From coming with MIT License 5 votes vote down vote up
private void scanFromNode(
  BuildGlobalNamespace builder, JSModule module, Scope scope, Node n) {
  // Check affected parent nodes first.
  if (n.isName() || n.isGetProp()) {
    scanFromNode(builder, module, scope, n.getParent());
  }
  builder.collect(module, scope, n);
}
 
Example 13
Source File: Cardumen_0093_s.java    From coming with MIT License 4 votes vote down vote up
/**
 * @return Whether the definitionSite represents a function whose call
 *      signature can be modified.
 */
private boolean canChangeSignature(Node function) {
  Definition definition = getFunctionDefinition(function);
  CodingConvention convention = compiler.getCodingConvention();

  Preconditions.checkState(!definition.isExtern());

  Collection<UseSite> useSites = defFinder.getUseSites(definition);
  for (UseSite site : useSites) {
    Node parent = site.node.getParent();

    // This was a use site removed by something else before we run.
    // 1. By another pass before us which means the definition graph is
    //    no updated properly.
    // 2. By the continuations algorithm above.
    if (parent == null) {
      continue; // Ignore it.
    }

    // Ignore references within goog.inherits calls.
    if (parent.isCall() &&
        convention.getClassesDefinedByCall(parent) != null) {
      continue;
    }

    // Accessing the property directly prevents rewrite.
    if (!SimpleDefinitionFinder.isCallOrNewSite(site)) {
      if (!(parent.isGetProp() &&
          NodeUtil.isFunctionObjectCall(parent.getParent()))) {
        return false;
      }
    }

    if (NodeUtil.isFunctionObjectApply(parent)) {
      return false;
    }

    // TODO(johnlenz): support specialization

    // Multiple definitions prevent rewrite.
    // Attempt to validate the state of the simple definition finder.
    Node nameNode = site.node;
    Collection<Definition> singleSiteDefinitions =
        defFinder.getDefinitionsReferencedAt(nameNode);
    Preconditions.checkState(singleSiteDefinitions.size() == 1);
    Preconditions.checkState(singleSiteDefinitions.contains(definition));
  }

  return true;
}
 
Example 14
Source File: GenerateExports.java    From astor with GNU General Public License v2.0 4 votes vote down vote up
@Override
public void process(Node externs, Node root) {
  FindExportableNodes findExportableNodes = new FindExportableNodes(compiler);
  NodeTraversal.traverse(compiler, root, findExportableNodes);
  Map<String, GenerateNodeContext> exports = findExportableNodes
      .getExports();

  CodingConvention convention = compiler.getCodingConvention();
  for (Map.Entry<String, GenerateNodeContext> entry : exports.entrySet()) {
    String export = entry.getKey();
    GenerateNodeContext context = entry.getValue();

    // Emit the proper CALL expression.
    // This is an optimization to avoid exporting everything as a symbol
    // because exporting a property is significantly simpler/faster.
    // Only export the property if the parent is being exported or
    // if the parent is "prototype" and the grandparent is being exported.
    String parent = null;
    String grandparent = null;

    Node node = context.getNode().getFirstChild();
    if (node.isGetProp()) {
      parent = node.getFirstChild().getQualifiedName();
      if (node.getFirstChild().isGetProp() &&
          getPropertyName(node.getFirstChild()).equals(PROTOTYPE_PROPERTY)) {
        grandparent = node.getFirstChild().getFirstChild().getQualifiedName();
      }
    }

    boolean useExportSymbol = true;
    if (grandparent != null && exports.containsKey(grandparent)) {
      useExportSymbol = false;
    } else if (parent != null && exports.containsKey(parent)) {
      useExportSymbol = false;
    }

    Node call;
    if (useExportSymbol) {
      // exportSymbol(publicPath, object);
      call = IR.call(
          NodeUtil.newQualifiedNameNode(
              convention, exportSymbolFunction,
              context.getNode(), export),
          IR.string(export),
          NodeUtil.newQualifiedNameNode(
              convention, export,
              context.getNode(), export));
    } else {
      // exportProperty(object, publicName, symbol);
      String property = getPropertyName(node);
      call = IR.call(
          NodeUtil.newQualifiedNameNode(
              convention, exportPropertyFunction,
              context.getNode(), exportPropertyFunction),
          NodeUtil.newQualifiedNameNode(
              convention, parent,
              context.getNode(), exportPropertyFunction),
          IR.string(property),
          NodeUtil.newQualifiedNameNode(
              convention, export,
              context.getNode(), exportPropertyFunction));
    }

    Node expression = IR.exprResult(call);
    annotate(expression);

    // It's important that any class-building calls (goog.inherits)
    // come right after the class definition, so move the export after that.
    Node insertionPoint = context.getContextNode().getNext();
    while (insertionPoint != null &&
        NodeUtil.isExprCall(insertionPoint) &&
        convention.getClassesDefinedByCall(
            insertionPoint.getFirstChild()) != null) {
      insertionPoint = insertionPoint.getNext();
    }

    if (insertionPoint == null) {
      context.getScriptNode().addChildToBack(expression);
    } else {
      context.getScriptNode().addChildBefore(expression, insertionPoint);
    }
    compiler.reportCodeChange();
  }
}
 
Example 15
Source File: CrossModuleCodeMotion.java    From astor with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Process the references to named variables
 */
private void processReference(NodeTraversal t, NamedInfo info, String name) {
  // A name is recursively defined if:
  //   1: It is calling itself.
  //   2: One of its property calls itself.
  // Recursive definition should not block movement.

  boolean recursive = false;
  Node rootNode = t.getScope().getRootNode();
  if (rootNode.isFunction()) {

    // CASE #1:
    String scopeFuncName = rootNode.getFirstChild().getString();
    Node scopeFuncParent = rootNode.getParent();
    if (scopeFuncName.equals(name)) {
      recursive = true;
    } else if (scopeFuncParent.isName() &&
        scopeFuncParent.getString().equals(name)) {
      recursive = true;
    } else {
      // CASE #2:
      // Suppose name is Foo, we keep look up the scope stack to look for
      // a scope with "Foo.prototype.bar = function() { ..... "
      for (Scope s = t.getScope();
           s.getParent() != null; s = s.getParent()) {
        Node curRoot = s.getRootNode();
        if (curRoot.getParent().isAssign()) {
          Node owner = curRoot.getParent().getFirstChild();
          while (owner.isGetProp()) {
            owner = owner.getFirstChild();
          }
          if (owner.isName() &&
              owner.getString().equals(name)) {
            recursive = true;
            break;
          }
        }
      }
    }
  }

  if (!recursive) {
    info.addUsedModule(t.getModule());
  }
}
 
Example 16
Source File: TypeValidator.java    From astor with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Given a node, get a human-readable name for the type of that node so
 * that will be easy for the programmer to find the original declaration.
 *
 * For example, if SubFoo's property "bar" might have the human-readable
 * name "Foo.prototype.bar".
 *
 * @param n The node.
 * @param dereference If true, the type of the node will be dereferenced
 *     to an Object type, if possible.
 */
String getReadableJSTypeName(Node n, boolean dereference) {
  // If we're analyzing a GETPROP, the property may be inherited by the
  // prototype chain. So climb the prototype chain and find out where
  // the property was originally defined.
  if (n.isGetProp()) {
    ObjectType objectType = getJSType(n.getFirstChild()).dereference();
    if (objectType != null) {
      String propName = n.getLastChild().getString();
      if (objectType.getConstructor() != null &&
          objectType.getConstructor().isInterface()) {
        objectType = FunctionType.getTopDefiningInterface(
            objectType, propName);
      } else {
        // classes
        while (objectType != null && !objectType.hasOwnProperty(propName)) {
          objectType = objectType.getImplicitPrototype();
        }
      }

      // Don't show complex function names or anonymous types.
      // Instead, try to get a human-readable type name.
      if (objectType != null &&
          (objectType.getConstructor() != null ||
           objectType.isFunctionPrototypeType())) {
        return objectType.toString() + "." + propName;
      }
    }
  }

  JSType type = getJSType(n);
  if (dereference) {
    ObjectType dereferenced = type.dereference();
    if (dereferenced != null) {
      type = dereferenced;
    }
  }

  String qualifiedName = n.getQualifiedName();
  if (type.isFunctionPrototypeType() ||
      (type.toObjectType() != null &&
       type.toObjectType().getConstructor() != null)) {
    return type.toString();
  } else if (qualifiedName != null) {
    return qualifiedName;
  } else if (type.isFunctionType()) {
    // Don't show complex function names.
    return "function";
  } else {
    return type.toString();
  }
}
 
Example 17
Source File: Closure_114_NameAnalyzer_t.java    From coming with MIT License 4 votes vote down vote up
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
  if (!(n.isName() || (NodeUtil.isGet(n) && !parent.isGetProp()))) {
    // This is not a simple or qualified name.
    return;
  }

  NameInformation nameInfo = createNameInformation(t, n);
  if (nameInfo == null) {
    // The name is not a global name
    return;
  }

  if (nameInfo.onlyAffectsClassDef) {
    if (nameInfo.superclass != null) {
      recordReference(
          nameInfo.name, nameInfo.superclass, RefType.INHERITANCE);
    }

    // Make sure that we record a reference to the function that does
    // the inheritance, so that the inherits() function itself does
    // not get stripped.
    String nodeName = n.getQualifiedName();
    if (nodeName != null) {
      recordReference(
          nameInfo.name, nodeName, RefType.REGULAR);
    }

    return;
  }

  if (parent.isInstanceOf() &&
      parent.getLastChild() == n &&
      // Don't cover GETELEMs with a global root node.
      n.isQualifiedName()) {
    JsName checkedClass = getName(nameInfo.name, true);
    refNodes.add(new InstanceOfCheckNode(checkedClass, n));
    checkedClass.hasInstanceOfReference = true;
    return;
  }

  // Determine which name might be potentially referring to this one by
  // looking up the nearest enclosing dependency scope. It's unnecessary to
  // determine all enclosing dependency scopes because this callback should
  // create a chain of references between them.
  List<NameInformation> referers = getDependencyScope(n);
  if (referers.isEmpty()) {
    maybeRecordReferenceOrAlias(t, n, parent, nameInfo, null);
  } else {
    for (NameInformation referring : referers) {
      maybeRecordReferenceOrAlias(t, n, parent, nameInfo, referring);
    }
    recordAliases(referers);
  }
}
 
Example 18
Source File: Cardumen_00248_t.java    From coming with MIT License 4 votes vote down vote up
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
  // VOID nodes appear when there are extra semicolons at the BLOCK level.
  // I've been unable to think of any cases where this indicates a bug,
  // and apparently some people like keeping these semicolons around,
  // so we'll allow it.
  if (n.isEmpty() ||
      n.isComma()) {
    return;
  }

  if (parent == null) {
    return;
  }

  // Do not try to remove a block or an expr result. We already handle
  // these cases when we visit the child, and the peephole passes will
  // fix up the tree in more clever ways when these are removed.
  if (n.isExprResult()) {
    return;
  }

  // This no-op statement was there so that JSDoc information could
  // be attached to the name. This check should not complain about it.
  if (n.isQualifiedName() && n.getJSDocInfo() != null) {
    return;
  }

  boolean isResultUsed = NodeUtil.isExpressionResultUsed(n);
  boolean isSimpleOp = NodeUtil.isSimpleOperatorType(n.getType());
  if (parent.getType() == Token.COMMA) {
    if (isResultUsed) {
      return;
    }
    if ((((!isSimpleOp) && (n.isGetProp())) && (parent.isAssign())) && ("prototype".equals(n.getLastChild().getString()))) {
      for (Node an : parent.getAncestors()) {
        int ancestorType = an.getType();
        if (ancestorType == Token.COMMA) continue;
        if (ancestorType != Token.EXPR_RESULT && ancestorType != Token.BLOCK) return;
        else break;
      }
    }
  } else if (parent.getType() != Token.EXPR_RESULT && parent.getType() != Token.BLOCK) {
    if (! (parent.getType() == Token.FOR && parent.getChildCount() == 4 && (n == parent.getFirstChild() || n == parent.getFirstChild().getNext().getNext()))) {
      return;
    }
  }
  if (
      (isSimpleOp || !NodeUtil.mayHaveSideEffects(n, t.getCompiler()))) {
    String msg = "This code lacks side-effects. Is there a bug?";
    if (n.isString()) {
      msg = "Is there a missing '+' on the previous line?";
    } else if (isSimpleOp) {
      msg = "The result of the '" + Token.name(n.getType()).toLowerCase() +
          "' operator is not being used.";
    }

    t.getCompiler().report(
        t.makeError(n, level, USELESS_CODE_ERROR, msg));
    // TODO(johnlenz): determine if it is necessary to
    // try to protect side-effect free statements as well.
    if (!NodeUtil.isStatement(n)) {
      problemNodes.add(n);
    }
  }
}
 
Example 19
Source File: Cardumen_00249_t.java    From coming with MIT License 4 votes vote down vote up
/**
 * @return Whether the definitionSite represents a function whose call
 *      signature can be modified.
 */
private boolean canChangeSignature(Node function) {
  Definition definition = getFunctionDefinition(function);
  CodingConvention convention = compiler.getCodingConvention();

  Preconditions.checkState(!definition.isExtern());

  Collection<UseSite> useSites = defFinder.getUseSites(definition);
  for (UseSite site : useSites) {
    Node parent = site.node.getParent();

    // This was a use site removed by something else before we run.
    // 1. By another pass before us which means the definition graph is
    //    no updated properly.
    // 2. By the continuations algorithm above.
    if (parent == null) {
      continue; // Ignore it.
    }

    // Ignore references within goog.inherits calls.
    if (parent.isCall() &&
        convention.getClassesDefinedByCall(parent) != null) {
      continue;
    }

    // Accessing the property directly prevents rewrite.
    if (!SimpleDefinitionFinder.isCallOrNewSite(site)) {
      if (!(parent.isGetProp() &&
          NodeUtil.isFunctionObjectCall(parent.getParent()))) {
        return false;
      }
    }

    if (NodeUtil.isFunctionObjectApply(parent)) {
      return false;
    }

    // TODO(johnlenz): support specialization

    // Multiple definitions prevent rewrite.
    // Attempt to validate the state of the simple definition finder.
    Node nameNode = site.node;
    Collection<Definition> singleSiteDefinitions =
        defFinder.getDefinitionsReferencedAt(nameNode);
    Preconditions.checkState(singleSiteDefinitions.size() == 1);
    Preconditions.checkState(singleSiteDefinitions.contains(definition));
  }

  return true;
}
 
Example 20
Source File: Cardumen_00203_t.java    From coming with MIT License 4 votes vote down vote up
/**
 * @return Whether the definitionSite represents a function whose call
 *      signature can be modified.
 */
private boolean canChangeSignature(Node function) {
  Definition definition = getFunctionDefinition(function);
  CodingConvention convention = compiler.getCodingConvention();

  Preconditions.checkState(!definition.isExtern());

  Collection<UseSite> useSites = defFinder.getUseSites(definition);
  for (UseSite site : useSites) {
    Node parent = site.node.getParent();

    // This was a use site removed by something else before we run.
    // 1. By another pass before us which means the definition graph is
    //    no updated properly.
    // 2. By the continuations algorithm above.
    if (parent == null) {
      continue; // Ignore it.
    }

    // Ignore references within goog.inherits calls.
    if (parent.isCall() &&
        convention.getClassesDefinedByCall(parent) != null) {
      continue;
    }

    // Accessing the property directly prevents rewrite.
    if (!SimpleDefinitionFinder.isCallOrNewSite(site)) {
      if (!(parent.isGetProp() &&
          NodeUtil.isFunctionObjectCall(parent.getParent()))) {
        return false;
      }
    }

    if (NodeUtil.isFunctionObjectApply(parent)) {
      return false;
    }

    // TODO(johnlenz): support specialization

    // Multiple definitions prevent rewrite.
    // Attempt to validate the state of the simple definition finder.
    Node nameNode = site.node;
    Collection<Definition> singleSiteDefinitions =
        defFinder.getDefinitionsReferencedAt(nameNode);
    Preconditions.checkState(singleSiteDefinitions.size() == 1);
    Preconditions.checkState(singleSiteDefinitions.contains(definition));
  }

  return true;
}