JSModule getRefModule(ReferenceCollectingCallback.Reference ref) { CompilerInput input = compiler.getInput(ref.getInputId()); return input == null ? null : input.getModule(); }
private boolean inlineAliasIfPossible(Name name, Ref alias, GlobalNamespace namespace) { // Ensure that the alias is assigned to a local variable at that // variable's declaration. If the alias's parent is a NAME, // then the NAME must be the child of a VAR node, and we must // be in a VAR assignment. Node aliasParent = alias.node.getParent(); if (aliasParent.isName()) { // Ensure that the local variable is well defined and never reassigned. Scope scope = alias.scope; String aliasVarName = aliasParent.getString(); Var aliasVar = scope.getVar(aliasVarName); ReferenceCollectingCallback collector = new ReferenceCollectingCallback( compiler, ReferenceCollectingCallback.DO_NOTHING_BEHAVIOR, Predicates.equalTo(aliasVar)); collector.processScope(scope); ReferenceCollection aliasRefs = collector.getReferences(aliasVar); Set<AstChange> newNodes = new LinkedHashSet<>(); if (aliasRefs.isWellDefined() && aliasRefs.firstReferenceIsAssigningDeclaration()) { if (!aliasRefs.isAssignedOnceInLifetime()) { // Static properties of constructors are always collapsed. // So, if a constructor is aliased and its properties are accessed from // the alias, we would like to inline the alias here to access the // properties correctly. // But if the aliased variable is assigned more than once, we can't // inline, so we warn. if (name.isConstructor()) { boolean accessPropsAfterAliasing = false; for (Reference ref : aliasRefs.references) { if (ref.getNode().getParent().isGetProp()) { accessPropsAfterAliasing = true; break; } } if (accessPropsAfterAliasing) { compiler.report(JSError.make(aliasParent, UNSAFE_CTOR_ALIASING, aliasVarName)); } } return false; } // The alias is well-formed, so do the inlining now. int size = aliasRefs.references.size(); for (int i = 1; i < size; i++) { ReferenceCollectingCallback.Reference aliasRef = aliasRefs.references.get(i); Node newNode = alias.node.cloneTree(); aliasRef.getParent().replaceChild(aliasRef.getNode(), newNode); newNodes.add(new AstChange(getRefModule(aliasRef), aliasRef.getScope(), newNode)); } // just set the original alias to null. aliasParent.replaceChild(alias.node, IR.nullNode()); compiler.reportCodeChange(); // Inlining the variable may have introduced new references // to descendants of {@code name}. So those need to be collected now. namespace.scanNewNodes(newNodes); return true; } } return false; }