All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.RemoveUnnecessarySyntheticExterns Maven / Gradle / Ivy

There is a newer version: 9.0.8
Show newest version
/*
 * Copyright 2021 The Closure Compiler Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.javascript.jscomp;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.javascript.jscomp.SyntacticScopeCreator.RedeclarationHandler;
import com.google.javascript.rhino.Node;
import java.util.LinkedHashSet;

/**
 * Deletes name declarations from synthetic externs if they are in fact declared in source
 *
 * 

The VarCheck pass will create synthetic extern declarations (`var someName;`) for every * variable name referenced without a corresponding externs or code declaration. Such names are * "unfulfilled". VarCheck only does this because later compiler passes expect the following * invariant to hold: all variable names referenced in externs or code are also declared in externs * or code. * *

When running optimizations based on precompiled TypedAST library shards, it's possible for a * name to be unfulfilled in shard A, but declared in another shard B. Shard B "fulfills" the * reference from shard A. This pass removes the corresponding synthetic extern that came from shard * A now that the name is fulfilled. The purpose is to improve optimizations, e.g. to allow mangling * the name if it is not defined in externs. */ final class RemoveUnnecessarySyntheticExterns implements CompilerPass { private final AbstractCompiler compiler; private final LinkedHashSet nodesToDetach = new LinkedHashSet<>(); RemoveUnnecessarySyntheticExterns(AbstractCompiler compiler) { this.compiler = compiler; } @Override public void process(Node externs, Node root) { Node globalRoot = externs.getParent(); ScopeCreator scopeCreator = new SyntacticScopeCreator(compiler, new RedeclarationCheckHandler()); // This call will invoke the RedeclarationCheckHandler on duplicate synthetic names scopeCreator.createScope(globalRoot, /* parent= */ null); if (nodesToDetach.isEmpty()) { return; } for (Node n : nodesToDetach) { n.detach(); } Node syntheticExternsScript = compiler.getSynthesizedExternsInput().getAstRoot(compiler); compiler.reportChangeToEnclosingScope(syntheticExternsScript); } /** The handler for duplicate declarations. */ private class RedeclarationCheckHandler implements RedeclarationHandler { @Override public void onRedeclaration(Scope s, String name, Node n, CompilerInput input) { checkArgument(s.isGlobal(), "Unexpected non-global redeclaration %s in scope %s", n, s); boolean isSynthetic = input.equals(compiler.getSynthesizedExternsInput()); Var origVar = s.getVar(name); // origNode will be null for `arguments`, since there's no node that declares it. Node origNode = origVar.getNode(); if (isSynthetic) { // Delete duplicate unfulfilled synthetic declarations. // The original declaration will be deleted later iff it's also synthetic and we visit a // non-synthetic duplicate declaration. if (n.getParent().isSynthesizedUnfulfilledNameDeclaration()) { nodesToDetach.add(n.getParent()); } } else if (origNode != null && origNode.getParent().isSynthesizedUnfulfilledNameDeclaration()) { // Found a synthetic extern declaration that's fulfilled by some non-synthetic code. nodesToDetach.add(origNode.getParent()); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy