/** @param globalScope a new Global Scope to replace the scope of references with. */ public void updateReferencesWithGlobalScope(Scope globalScope) { for (ReferenceCollection collection : refMap.values()) { List<Reference> newRefs = new ArrayList<>(collection.references.size()); for (Reference ref : collection.references) { if (ref.getScope() != globalScope) { newRefs.add(ref.cloneWithNewScope(globalScope)); } else { newRefs.add(ref); } } collection.references = newRefs; } }
private void removeScriptReferences(InputId inputId) { Preconditions.checkNotNull(inputId); if (!inputOrder.containsKey(inputId)) { return; // Input did not exist when last computed, so skip } // TODO(bashir): If this is too slow it is not too difficult to make it // faster with keeping an index for variables accessed in sourceName. for (ReferenceCollection collection : refMap.values()) { if (collection == null) { continue; } List<Reference> oldRefs = collection.references; SourceRefRange range = findSourceRefRange(oldRefs, inputId); List<Reference> newRefs = new ArrayList<>(range.refsBefore()); newRefs.addAll(range.refsAfter()); collection.references = newRefs; } }
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; }