@Override public Node getRootNode() { return syntacticScope.getRootNode(); }
@Override public Node getRootNode() { return getFunctionScope().getRootNode(); }
private boolean inCurrentScope(NodeTraversal t) { Node traversalScopeRoot = t.getScopeRoot(); // NOTE: we need special handling for SCRIPT nodes, since Compiler.replaceScript causes a // traversal rooted at a SCRIPT but with the global scope whose root node is the ROOT. if (traversalScopeRoot.isScript()) { return currentScope.isGlobal(); } // Otherwise we're in the current scope as long as the root nodes match up. return traversalScopeRoot == currentScope.getRootNode(); }
@Override void visitPreorder(NodeTraversal t, Node n, Node parent) { // These are not descended into, so must be done preorder if (n.isFunction()) { if (parent.isMemberFunctionDef() && parent.getString().equals("constructor")) { // Constructor has already been analyzed, so pull that here. setDeferredType(n, currentScope.getRootNode().getJSType()); } else { defineFunctionLiteral(n); } } }
@Override public void hotSwapScript(Node scriptRoot, Node originalRoot) { GlobalVarReferenceMap refMap = compiler.getGlobalVarReferences(); if (refMap != null) { // We don't have a suitable untyped scope to use, but the actual scope probably doesn't // matter, so long as it's a global scope and doesn't persist references to things that // need to be cleaned up. So we just generate a new simple root scope. refMap.updateReferencesWithGlobalScope( Scope.createGlobalScope(compiler.getTopScope().getRootNode())); } }
/** * Declares a variable with the given {@code name} and {@code type} on the given {@code scope}, * returning the newly-declared {@link TypedVar}. Additionally checks the {@link * #escapedVarNames} and {@link #assignedVarNames} maps (which were populated during the {@link * FirstOrderFunctionAnalyzer} and marks the result as escaped or assigned exactly once if * appropriate. */ private TypedVar declare( TypedScope scope, String name, Node n, JSType type, CompilerInput input, boolean inferred) { TypedVar var = scope.declare(name, n, type, input, inferred); ScopedName scopedName = ScopedName.of(name, scope.getRootNode()); if (escapedVarNames.contains(scopedName)) { var.markEscaped(); } if (assignedVarNames.count(scopedName) == 1) { var.markAssignedExactlyOnce(); } return var; }
/** * Traverse the scope root and build it. */ void build() { NodeTraversal.traverseTyped(compiler, scope.getRootNode(), this); AstFunctionContents contents = getFunctionAnalysisResults(scope.getRootNode()); if (contents != null) { for (String varName : contents.getEscapedVarNames()) { TypedVar v = scope.getVar(varName); Preconditions.checkState(v.getScope() == scope); v.markEscaped(); } for (Multiset.Entry<String> entry : contents.getAssignedNameCounts().entrySet()) { TypedVar v = scope.getVar(entry.getElement()); Preconditions.checkState(v.getScope() == scope); if (entry.getCount() == 1) { v.markAssignedExactlyOnce(); } } } }
private ObjectType getThisTypeForCollectingProperties() { Node rootNode = scope.getRootNode(); if (rootNode.isFromExterns()) return null; JSType type = rootNode.getJSType(); if (type == null || !type.isFunctionType()) return null; FunctionType fnType = type.toMaybeFunctionType(); JSType fnThisType = fnType.getTypeOfThis(); return fnThisType.isUnknownType() ? null : fnThisType.toObjectType(); }
/** * Visit a node in a local scope, and add any local variables or catch * parameters into the local symbol table. * * @param t The node traversal. * @param n The node being visited. * @param parent The parent of n */ @Override public void visit(NodeTraversal t, Node n, Node parent) { if (n == scope.getRootNode()) { return; } if (n.isParamList() && parent == scope.getRootNode()) { handleFunctionInputs(parent); return; } // Gather the properties declared in the function, // if that function has a @this type that we can // build properties on. // TODO(nick): It's not clear to me why this is necessary; // it appears to be papering over bugs in the main analyzer. if (thisTypeForProperties != null && n.getParent().isExprResult()) { if (n.isAssign()) { maybeCollectMember(n.getFirstChild(), n, n.getLastChild()); } else if (n.isGetProp()) { maybeCollectMember(n, n, null); } } super.visit(t, n, parent); }
while (scope != null && !NodeUtil.isVanillaFunction(scope.getRootNode())) { scope = scope.getParent(); return; Node root = scope.getRootNode(); Node parent = root.getParent(); if (parent.isMemberFunctionDef() && parent.getGrandparent().isClass()) {
@Override void visitPostorder(NodeTraversal t, Node n, Node parent) { if (n.isName() && parent == currentScope.getRootNode() && NodeUtil.isClassExpression(parent)) { // Declare bleeding class name in scope. Pull the type off the AST. checkState(!n.getString().isEmpty()); // anonymous classes have EMPTY nodes, not NAME new SlotDefiner() .forDeclarationNode(n) .readVariableNameFromDeclarationNode() .inScope(currentScope) .withType(parent.getJSType()) .allowLaterTypeInference(false) .defineSlot(); } else if (n.isMemberFunctionDef() && !"constructor".equals(n.getString())) { // Ignore "constructor" since it has special handling in `createClassTypeFromNodes()`. defineMemberFunction(n); } else if (n.isGetterDef() || n.isSetterDef()) { defineGetterSetter(n); } }
TypeInference(AbstractCompiler compiler, ControlFlowGraph<Node> cfg, ReverseAbstractInterpreter reverseInterpreter, TypedScope functionScope, Map<String, AssertionFunctionSpec> assertionFunctionsMap) { super(cfg, new LinkedFlowScope.FlowScopeJoinOp()); this.compiler = compiler; this.registry = compiler.getTypeRegistry(); this.reverseInterpreter = reverseInterpreter; this.unknownType = registry.getNativeObjectType(UNKNOWN_TYPE); this.syntacticScope = functionScope; inferArguments(functionScope); this.functionScope = LinkedFlowScope.createEntryLattice(functionScope); this.assertionFunctionsMap = assertionFunctionsMap; // For each local variable declared with the VAR keyword, the entry // type is VOID. Iterator<TypedVar> varIt = functionScope.getDeclarativelyUnboundVarsWithoutTypes(); while (varIt.hasNext()) { TypedVar var = varIt.next(); if (isUnflowable(var)) { continue; } this.functionScope.inferSlotType( var.getName(), getNativeType(VOID_TYPE)); } this.bottomScope = LinkedFlowScope.createEntryLattice( TypedScope.createLatticeBottom(functionScope.getRootNode())); }
TypedScope ownerScope = var.getScope(); if (ownerScope.isLocal()) { data.get(ownerScope.getRootNode()).recordAssignedName(name); data.get(ownerScope.getRootNode()).recordEscapedVarName(name); TypedScope ownerScope = var.getScope(); if (scope != ownerScope && ownerScope.isLocal()) { data.get(ownerScope.getRootNode()) .recordEscapedQualifiedName(n.getQualifiedName());
TypeInference(AbstractCompiler compiler, ControlFlowGraph<Node> cfg, ReverseAbstractInterpreter reverseInterpreter, TypedScope syntacticScope, TypedScopeCreator scopeCreator, Map<String, AssertionFunctionSpec> assertionFunctionsMap) { super(cfg, new LinkedFlowScope.FlowScopeJoinOp()); this.compiler = compiler; this.registry = compiler.getTypeRegistry(); this.reverseInterpreter = reverseInterpreter; this.unknownType = registry.getNativeObjectType(UNKNOWN_TYPE); this.containerScope = syntacticScope; this.scopeCreator = scopeCreator; this.assertionFunctionsMap = assertionFunctionsMap; FlowScope entryScope = inferDeclarativelyUnboundVarsWithoutTypes( LinkedFlowScope.createEntryLattice(syntacticScope)); this.functionScope = inferParameters(entryScope); this.bottomScope = LinkedFlowScope.createEntryLattice( TypedScope.createLatticeBottom(syntacticScope.getRootNode())); }
@Override public final boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { inputId = t.getInputId(); if (n.isFunction() || n.isScript()) { Preconditions.checkNotNull(inputId); sourceName = NodeUtil.getSourceName(n); } // We do want to traverse the name of a named function, but we don't // want to traverse the arguments or body. boolean descend = parent == null || !parent.isFunction() || n == parent.getFirstChild() || parent == scope.getRootNode(); if (descend) { // Handle hoisted functions on pre-order traversal, so that they // get hit before other things in the scope. if (NodeUtil.isStatementParent(n)) { for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { if (NodeUtil.isHoistedFunctionDeclaration(child)) { defineFunctionLiteral(child); } } } } return descend; }
private void traverseSuper(Node superNode) { while (scope != null && !NodeUtil.isVanillaFunction(scope.getRootNode())) { scope = scope.getParent(); return; Node root = scope.getRootNode(); JSType jsType = root.getJSType(); FunctionType functionType = jsType != null ? jsType.toMaybeFunctionType() : null; Node classNode = scope.getParent().getRootNode(); checkState(classNode.isClass()); FunctionType thisCtor = JSType.toMaybeFunctionType(classNode.getJSType());
/** * Gets the type of {@code this} in the current scope. */ @Override public JSType getTypeOfThis() { Node root = getRootNode(); if (isGlobal()) { return ObjectType.cast(root.getJSType()); } else if (NodeUtil.isVanillaFunction(root)) { JSType nodeType = root.getJSType(); if (nodeType != null && nodeType.isFunctionType()) { return nodeType.toMaybeFunctionType().getTypeOfThis(); } else { // Executed when the current scope has not been typechecked. return null; } } else { return getParent().getTypeOfThis(); } }
/** Handle bleeding functions and function parameters. */ void handleFunctionInputs() { // Handle bleeding functions. Node fnNode = currentScope.getRootNode(); Node fnNameNode = fnNode.getFirstChild(); String fnName = fnNameNode.getString(); if (!fnName.isEmpty()) { TypedVar fnVar = currentScope.getVar(fnName); if (fnVar == null // Make sure we're not touching a native function. Native // functions aren't bleeding, but may not have a declaration // node. || (fnVar.getNameNode() != null // Make sure that the function is actually bleeding by checking // if has already been declared. && fnVar.getInitialValue() != fnNode)) { new SlotDefiner() .forDeclarationNode(fnNameNode) .forVariableName(fnName) .inScope(currentScope) .withType(fnNode.getJSType()) .allowLaterTypeInference(false) .defineSlot(); } } declareParameters(); }
Node functionNode = currentScope.getRootNode(); Node astParameters = functionNode.getSecondChild(); Node iifeArgumentNode = null;
Node functionNode = functionScope.getRootNode(); Node astParameters = functionNode.getSecondChild(); Node iifeArgumentNode = null;