@@ -410,6 +410,7 @@ private boolean declarationHasFollowingObjectSpreadSibling(Node declaration) {
410
410
private class BuildGlobalNamespace extends NodeTraversal .AbstractPreOrderCallback {
411
411
private @ Nullable Node curModuleRoot = null ;
412
412
private @ Nullable ModuleMetadata curMetadata = null ;
413
+
413
414
/** Collect the references in pre-order. */
414
415
@ Override
415
416
public boolean shouldTraverse (NodeTraversal t , Node n , Node parent ) {
@@ -1216,9 +1217,13 @@ final class Name implements StaticSlot {
1216
1217
1217
1218
// The children of this name. Must be null if there are no children.
1218
1219
@ Nullable List <Name > props ;
1219
- /** The first global assignment to a name. */
1220
+
1221
+ /** The declaration of a name. */
1220
1222
private @ Nullable Ref declaration ;
1221
1223
1224
+ /** The first global assignment to a name. */
1225
+ private @ Nullable Ref initialization ;
1226
+
1222
1227
/**
1223
1228
* Keep track of which Nodes are Refs for this Name.
1224
1229
*
@@ -1311,6 +1316,10 @@ boolean usesHasOwnProperty() {
1311
1316
return declaration ;
1312
1317
}
1313
1318
1319
+ public @ Nullable Ref getInitialization () {
1320
+ return initialization ;
1321
+ }
1322
+
1314
1323
boolean isFunction () {
1315
1324
return getBooleanProperty (NameProp .FUNCTION );
1316
1325
}
@@ -1455,6 +1464,12 @@ private void updateStateForAddedRef(Ref ref) {
1455
1464
if (declaration == null ) {
1456
1465
declaration = ref ;
1457
1466
}
1467
+ if (initialization == null && !ref .isUninitializedDeclaration ()) {
1468
+ // Record the reference where the first value is actually assigned.
1469
+ // Do not include the automatically-assigned `undefined` value case.
1470
+ // e.g. `var name;`
1471
+ initialization = ref ;
1472
+ }
1458
1473
if (firstDeclarationJSDocInfo == null ) {
1459
1474
// JSDocInfo from the first SET_FROM_GLOBAL will be assumed to be canonical
1460
1475
// Note that this will not change if the first declaration is later removed
@@ -1725,7 +1740,8 @@ boolean isCollapsingExplicitlyDenied() {
1725
1740
*/
1726
1741
Inlinability calculateInlinability () {
1727
1742
// Only simple aliases with direct usage are inlineable.
1728
- if (inExterns () || globalSets != 1 || localSets != 0 ) {
1743
+ // Exactly 2 global sets could be OK, if the first is the declaration with no initializer.
1744
+ if (inExterns () || !hasOneRealGlobalSet () || localSets != 0 ) {
1729
1745
return Inlinability .DO_NOT_INLINE ;
1730
1746
}
1731
1747
@@ -1761,6 +1777,10 @@ Inlinability calculateInlinability() {
1761
1777
return collapsibility ;
1762
1778
}
1763
1779
1780
+ private boolean hasOneRealGlobalSet () {
1781
+ return globalSets == 1 || (globalSets == 2 && declaration .isUninitializedDeclaration ());
1782
+ }
1783
+
1764
1784
boolean canCollapse () {
1765
1785
return canCollapseOrInline ().canCollapse ();
1766
1786
}
@@ -1914,13 +1934,13 @@ private void logDecision(Inlinability inlinability, String reason) {
1914
1934
1915
1935
private Inlinability getUnsafeInlinabilityBasedOnDeclaredType () {
1916
1936
if (this .getBooleanProperty (NameProp .CONSTRUCTOR_TYPE )) {
1917
- return Inlinability .INLINE_BUT_KEEP_DECLARATION_CLASS ;
1937
+ return Inlinability .INLINE_BUT_KEEP_DECLARATION_CLASS ;
1918
1938
} else if (this .getBooleanProperty (NameProp .INTERFACE_TYPE )) {
1919
- return Inlinability .INLINE_BUT_KEEP_DECLARATION_INTERFACE ;
1939
+ return Inlinability .INLINE_BUT_KEEP_DECLARATION_INTERFACE ;
1920
1940
} else if (this .getBooleanProperty (NameProp .ENUM_TYPE )) {
1921
- return Inlinability .INLINE_BUT_KEEP_DECLARATION_ENUM ;
1941
+ return Inlinability .INLINE_BUT_KEEP_DECLARATION_ENUM ;
1922
1942
} else if (this .getBooleanProperty (NameProp .NOT_A_TYPE )) {
1923
- return Inlinability .DO_NOT_INLINE ;
1943
+ return Inlinability .DO_NOT_INLINE ;
1924
1944
}
1925
1945
throw new IllegalStateException (
1926
1946
SimpleFormat .format ("name missing declaredType value: %s" , this ));
@@ -2133,11 +2153,11 @@ private boolean valueImplicitlySupportsAliasing() {
2133
2153
return true ;
2134
2154
}
2135
2155
if (getBooleanProperty (NameProp .FUNCTION )) {
2136
- // We want ES5 ctors/interfaces to behave consistently with ES6 because:
2137
- // - transpilation should not change behaviour
2138
- // - updating code shouldn't be hindered by behaviour changes
2139
- @ Nullable JSDocInfo jsdoc = getJSDocInfo ();
2140
- return jsdoc != null && jsdoc .isConstructorOrInterface ();
2156
+ // We want ES5 ctors/interfaces to behave consistently with ES6 because:
2157
+ // - transpilation should not change behaviour
2158
+ // - updating code shouldn't be hindered by behaviour changes
2159
+ @ Nullable JSDocInfo jsdoc = getJSDocInfo ();
2160
+ return jsdoc != null && jsdoc .isConstructorOrInterface ();
2141
2161
}
2142
2162
return false ;
2143
2163
}
@@ -2472,6 +2492,11 @@ boolean isSetFromGlobal() {
2472
2492
return this .type == Type .SET_FROM_GLOBAL || this .type == Type .GET_AND_SET_FROM_GLOBAL ;
2473
2493
}
2474
2494
2495
+ /** True for `var name;` and similar cases. */
2496
+ boolean isUninitializedDeclaration () {
2497
+ return node .isName () && NodeUtil .isNameDeclaration (node .getParent ()) && !node .hasChildren ();
2498
+ }
2499
+
2475
2500
@ Override
2476
2501
public String toString () {
2477
2502
return MoreObjects .toStringHelper (this )
0 commit comments