Skip to content

Commit fc053fc

Browse files
brad4dcopybara-github
authored andcommitted
Invert Normalization variable renaming for transpile-only cases
Instead of skipping variable renaming for the transpile-only case, we should be doing the same rename-inversion that is done for full builds when variable renaming is supposed to be disabled. This will allow the transpilation passes that run after normalization to fully rely on all variables being unique. The rename inversion maintains the user's "no renaming" expectations and avoids breaking runtime behavior that depends on function parameter names. In particular Angular likes to use function parameter names to control injection of parameter values at runtime. Bonus: Fix the CompilerTestCase externs diff. It was backwards. PiperOrigin-RevId: 551422263
1 parent 21b36e8 commit fc053fc

File tree

5 files changed

+47
-48
lines changed

5 files changed

+47
-48
lines changed

src/com/google/javascript/jscomp/DefaultPassConfig.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -170,18 +170,18 @@ protected PassListBuilder getTranspileOnlyPasses() {
170170
TranspilationPasses.addEarlyOptimizationTranspilationPasses(passes, options);
171171

172172
// Passes below this point may rely on normalization and must maintain normalization.
173-
passes.maybeAdd(
174-
PassFactory.builder()
175-
.setName(PassNames.NORMALIZE)
176-
.setInternalFactory(
177-
// Since we're doing only transpilation
178-
// we want to avoid renaming all variables to be unique.
179-
// Doing that would break Angular runtime behavior
180-
// that injects function parameters based on their names.
181-
(compiler) -> Normalize.builder(compiler).makeDeclaredNamesUnique(false).build())
182-
.build());
183-
173+
passes.maybeAdd(normalize);
184174
TranspilationPasses.addPostNormalizationTranspilationPasses(passes, options);
175+
// The transpilation passes may rely on normalize making all variables unique,
176+
// but we're doing only transpilation, so we want to put back the original variable names
177+
// wherever we can to meet user expectations.
178+
//
179+
// Also, if we don't do this, we could end up breaking runtime behavior that depends on specific
180+
// variable names.
181+
//
182+
// The primary concern is function parameter names, because some frameworks, like Angular,
183+
// do runtime injection of function call arguments based on the function parameter names.
184+
passes.maybeAdd(invertContextualRenaming);
185185

186186
passes.assertAllOneTimePasses();
187187
assertValidOrderForChecks(passes);

src/com/google/javascript/jscomp/Normalize.java

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,10 @@ final class Normalize implements CompilerPass {
6262
private final AbstractCompiler compiler;
6363
private final AstFactory astFactory;
6464
private final boolean assertOnChange;
65-
private final boolean makeDeclaredNamesUnique;
6665

6766
Normalize(Builder builder) {
6867
this.compiler = builder.compiler;
6968
this.assertOnChange = builder.assertOnChange;
70-
makeDeclaredNamesUnique = builder.makeDeclaredNamesUnique;
7169
this.astFactory = builder.compiler.createAstFactory();
7270
}
7371

@@ -84,7 +82,6 @@ static Builder builder(AbstractCompiler compiler) {
8482
static class Builder {
8583
private final AbstractCompiler compiler;
8684
private boolean assertOnChange = false;
87-
private boolean makeDeclaredNamesUnique = true;
8885

8986
Builder(AbstractCompiler compiler) {
9087
this.compiler = compiler;
@@ -102,20 +99,6 @@ Builder assertOnChange(boolean assertOnChange) {
10299
return this;
103100
}
104101

105-
/**
106-
* Rename variables as needed to enforce that every unique variable has a unique name.
107-
*
108-
* <p>This option should be disabled only for cases where no optimization is to be performed.
109-
* Many optimizations rely on all variables having unique names in order to avoid having to
110-
* worry about variable scoping.
111-
*
112-
* <p>This option is {@code true} by default.
113-
*/
114-
public Builder makeDeclaredNamesUnique(boolean makeDeclaredNamesUnique) {
115-
this.makeDeclaredNamesUnique = makeDeclaredNamesUnique;
116-
return this;
117-
}
118-
119102
Normalize build() {
120103
return new Normalize(this);
121104
}
@@ -148,11 +131,9 @@ private void reportCodeChange(String changeDescription, Node n) {
148131

149132
@Override
150133
public void process(Node externs, Node root) {
151-
if (makeDeclaredNamesUnique) {
152-
MakeDeclaredNamesUnique renamer =
153-
MakeDeclaredNamesUnique.builder().withAssertOnChange(assertOnChange).build();
154-
NodeTraversal.traverseRoots(compiler, renamer, externs, root);
155-
}
134+
MakeDeclaredNamesUnique renamer =
135+
MakeDeclaredNamesUnique.builder().withAssertOnChange(assertOnChange).build();
136+
NodeTraversal.traverseRoots(compiler, renamer, externs, root);
156137

157138
NodeTraversal.traverseRoots(
158139
compiler, new NormalizeStatements(compiler, assertOnChange), externs, root);

test/com/google/javascript/jscomp/CompilerTestCase.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,9 +1734,9 @@ private void testInternal(
17341734

17351735
// Generally, externs should not be changed by the compiler passes.
17361736
if (externsChange && !allowExternsChanges) {
1737-
assertNode(externsRootClone)
1737+
assertNode(externsRoot)
17381738
.usingSerializer(createPrettyPrinter(compiler))
1739-
.isEqualTo(externsRoot);
1739+
.isEqualTo(externsRootClone);
17401740
}
17411741

17421742
if (checkAstChangeMarking) {
@@ -1867,18 +1867,21 @@ private void transpileToEs5(AbstractCompiler compiler, Node externsRoot, Node co
18671867
TranspilationPasses.addTranspilationRuntimeLibraries(factories);
18681868
TranspilationPasses.addRewritePolyfillPass(factories);
18691869
TranspilationPasses.addEarlyOptimizationTranspilationPasses(factories, options);
1870-
// Transpilation requires most of normalization.
1870+
// Transpilation requires normalization.
18711871
factories.maybeAdd(
18721872
PassFactory.builder()
18731873
.setName(PassNames.NORMALIZE)
1874-
.setInternalFactory(
1875-
abstractCompiler ->
1876-
Normalize.builder(abstractCompiler)
1877-
// Only do unique variable renaming if normalize is explicitly enabled.
1878-
.makeDeclaredNamesUnique(normalizeEnabled)
1879-
.build())
1874+
.setInternalFactory(abstractCompiler -> Normalize.builder(abstractCompiler).build())
18801875
.build());
18811876
TranspilationPasses.addPostNormalizationTranspilationPasses(factories, options);
1877+
// We need to put back the original variable names where possible once transpilation is
1878+
// complete. This matches the behavior in DefaultPassConfig. See comments there for further
1879+
// explanation.
1880+
factories.maybeAdd(
1881+
PassFactory.builder()
1882+
.setName("invertContextualRenaming")
1883+
.setInternalFactory(MakeDeclaredNamesUnique::getContextualRenameInverter)
1884+
.build());
18821885
for (PassFactory factory : factories.build()) {
18831886
factory.create(compiler).process(externsRoot, codeRoot);
18841887
}

test/com/google/javascript/jscomp/Es6TranspilationIntegrationTest.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ public void setUp() throws Exception {
7878
disableNormalize();
7979
disableTypeCheck();
8080
disableCompareJsDoc(); // optimization passes see simplified JSDoc.
81+
// Normalization does renaming on the externs (parameter names and maybe other things) and the
82+
// pass that inverts renaming ignores the externs, leaving them changed.
83+
allowExternsChanges();
84+
// Our getProcessor() returns a fake "pass" that actually runs several passes,
85+
// including one that undoes some of the changes that were made.
86+
// this confuses the logic for validating AST change marking.
87+
// That logic is really only valid when testing a single, real pass.
88+
disableValidateAstChangeMarking();
8189
}
8290

8391
@Override
@@ -105,14 +113,17 @@ protected CompilerPass getProcessor(final Compiler compiler) {
105113
passes.maybeAdd(
106114
PassFactory.builder()
107115
.setName(PassNames.NORMALIZE)
108-
.setInternalFactory(
109-
// Disable creation of unique names to make the test cases less confusing and
110-
// brittle. We're not trying to test whether Normalize will rename variables
111-
// to be unique or not.
112-
(abstractCompiler) ->
113-
Normalize.builder(abstractCompiler).makeDeclaredNamesUnique(false).build())
116+
.setInternalFactory((abstractCompiler) -> Normalize.builder(abstractCompiler).build())
114117
.build());
115118
TranspilationPasses.addPostNormalizationTranspilationPasses(passes, compilerOptions);
119+
// Since we're testing the transpile-only case, we need to put back the original variable names
120+
// where possible once transpilation is complete. This matches the behavior in
121+
// DefaultPassConfig. See comments there for further explanation.
122+
passes.maybeAdd(
123+
PassFactory.builder()
124+
.setName("invertContextualRenaming")
125+
.setInternalFactory(MakeDeclaredNamesUnique::getContextualRenameInverter)
126+
.build());
116127
optimizer.consume(passes.build());
117128

118129
return optimizer;

test/com/google/javascript/jscomp/lint/CheckArrayWithGoogObjectTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ protected CompilerOptions getOptions() {
5353
public void setUp() throws Exception {
5454
super.setUp();
5555
enableTranspile();
56+
// Transpilation runs normalization, which does renaming on the externs.
57+
// It also runs a pass that reverts the renaming, but it ignores the externs, leaving them
58+
// changed.
59+
allowExternsChanges();
5660
enableTypeCheck();
5761
}
5862

0 commit comments

Comments
 (0)