Skip to content

Commit 814f7d0

Browse files
brad4dcopybara-github
authored andcommitted
Use LinkedHash(Map|Set) to guarantee deterministic iteration order
PiperOrigin-RevId: 568277917
1 parent bcca67e commit 814f7d0

File tree

7 files changed

+119
-150
lines changed

7 files changed

+119
-150
lines changed

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import com.google.javascript.rhino.Node;
3131
import java.util.ArrayDeque;
3232
import java.util.Comparator;
33-
import java.util.HashSet;
33+
import java.util.LinkedHashSet;
3434
import java.util.List;
3535
import java.util.Map;
3636
import java.util.PriorityQueue;
@@ -127,10 +127,9 @@ abstract class DataFlowAnalysis<N, L extends LatticeElement> {
127127
}
128128

129129
/**
130-
* Returns the control flow graph that this analysis was performed on.
131-
* Modifications can be done on this graph, however, the only time that the
132-
* annotations are correct is after {@link #analyze()} is called and before
133-
* the graph has been modified.
130+
* Returns the control flow graph that this analysis was performed on. Modifications can be done
131+
* on this graph, however, the only time that the annotations are correct is after {@link
132+
* #analyze()} is called and before the graph has been modified.
134133
*/
135134
final ControlFlowGraph<N> getCfg() {
136135
return cfg;
@@ -474,7 +473,7 @@ public void visit(NodeTraversal t, Node n, Node parent) {
474473
}
475474

476475
private static final class UniqueQueue<T> {
477-
private final HashSet<T> seenSet = new HashSet<>();
476+
private final LinkedHashSet<T> seenSet = new LinkedHashSet<>();
478477
private final Queue<T> queue;
479478

480479
UniqueQueue(@Nullable Comparator<T> priority) {

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

Lines changed: 66 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,25 @@
4949
import com.google.javascript.rhino.jstype.TemplateType;
5050
import java.util.ArrayList;
5151
import java.util.Collections;
52-
import java.util.HashSet;
5352
import java.util.Iterator;
5453
import java.util.LinkedHashMap;
54+
import java.util.LinkedHashSet;
5555
import java.util.List;
5656
import java.util.Map;
5757
import java.util.Set;
5858
import org.jspecify.nullness.Nullable;
5959

6060
/**
61-
* A builder for FunctionTypes, because FunctionTypes are so
62-
* ridiculously complex. All methods return {@code this} for ease of use.
61+
* A builder for FunctionTypes, because FunctionTypes are so ridiculously complex. All methods
62+
* return {@code this} for ease of use.
6363
*
64-
* Right now, this mostly uses JSDocInfo to infer type information about
65-
* functions. In the long term, developers should extend it to use other
66-
* signals by overloading the various "inferXXX" methods. For example, we
67-
* might want to use {@code goog.inherits} calls as a signal for inheritance, or
68-
* {@code return} statements as a signal for return type.
64+
* <p>Right now, this mostly uses JSDocInfo to infer type information about functions. In the long
65+
* term, developers should extend it to use other signals by overloading the various "inferXXX"
66+
* methods. For example, we might want to use {@code goog.inherits} calls as a signal for
67+
* inheritance, or {@code return} statements as a signal for return type.
6968
*
70-
* NOTE(nicksantos): Organizationally, this feels like it should be in Rhino.
71-
* But it depends on some coding convention stuff that's really part
72-
* of JSCompiler.
69+
* <p>NOTE(nicksantos): Organizationally, this feels like it should be in Rhino. But it depends on
70+
* some coding convention stuff that's really part of JSCompiler.
7371
*/
7472
final class FunctionTypeBuilder {
7573

@@ -104,39 +102,34 @@ final class FunctionTypeBuilder {
104102
private @Nullable TypedScope declarationScope = null;
105103
private StaticTypedScope templateScope;
106104

107-
static final DiagnosticType EXTENDS_WITHOUT_TYPEDEF = DiagnosticType.warning(
108-
"JSC_EXTENDS_WITHOUT_TYPEDEF",
109-
"@extends used without @constructor or @interface for {0}");
105+
static final DiagnosticType EXTENDS_WITHOUT_TYPEDEF =
106+
DiagnosticType.warning(
107+
"JSC_EXTENDS_WITHOUT_TYPEDEF",
108+
"@extends used without @constructor or @interface for {0}");
110109

111-
static final DiagnosticType EXTENDS_NON_OBJECT = DiagnosticType.warning(
112-
"JSC_EXTENDS_NON_OBJECT",
113-
"{0} @extends non-object type {1}");
110+
static final DiagnosticType EXTENDS_NON_OBJECT =
111+
DiagnosticType.warning("JSC_EXTENDS_NON_OBJECT", "{0} @extends non-object type {1}");
114112

115-
static final DiagnosticType RESOLVED_TAG_EMPTY = DiagnosticType.warning(
116-
"JSC_RESOLVED_TAG_EMPTY",
117-
"Could not resolve type in {0} tag of {1}");
113+
static final DiagnosticType RESOLVED_TAG_EMPTY =
114+
DiagnosticType.warning("JSC_RESOLVED_TAG_EMPTY", "Could not resolve type in {0} tag of {1}");
118115

119116
static final DiagnosticType CONSTRUCTOR_REQUIRED =
120-
DiagnosticType.warning("JSC_CONSTRUCTOR_REQUIRED",
121-
"{0} used without @constructor for {1}");
117+
DiagnosticType.warning("JSC_CONSTRUCTOR_REQUIRED", "{0} used without @constructor for {1}");
122118

123-
static final DiagnosticType VAR_ARGS_MUST_BE_LAST = DiagnosticType.warning(
124-
"JSC_VAR_ARGS_MUST_BE_LAST",
125-
"variable length argument must be last");
119+
static final DiagnosticType VAR_ARGS_MUST_BE_LAST =
120+
DiagnosticType.warning("JSC_VAR_ARGS_MUST_BE_LAST", "variable length argument must be last");
126121

127-
static final DiagnosticType OPTIONAL_ARG_AT_END = DiagnosticType.warning(
128-
"JSC_OPTIONAL_ARG_AT_END",
129-
"optional arguments must be at the end");
122+
static final DiagnosticType OPTIONAL_ARG_AT_END =
123+
DiagnosticType.warning("JSC_OPTIONAL_ARG_AT_END", "optional arguments must be at the end");
130124

131-
static final DiagnosticType INEXISTENT_PARAM = DiagnosticType.warning(
132-
"JSC_INEXISTENT_PARAM",
133-
"parameter {0} does not appear in {1}''s parameter list");
125+
static final DiagnosticType INEXISTENT_PARAM =
126+
DiagnosticType.warning(
127+
"JSC_INEXISTENT_PARAM", "parameter {0} does not appear in {1}''s parameter list");
134128

135-
static final DiagnosticType TYPE_REDEFINITION = DiagnosticType.warning(
136-
"JSC_TYPE_REDEFINITION",
137-
"attempted re-definition of type {0}\n"
138-
+ "found : {1}\n"
139-
+ "expected: {2}");
129+
static final DiagnosticType TYPE_REDEFINITION =
130+
DiagnosticType.warning(
131+
"JSC_TYPE_REDEFINITION",
132+
"attempted re-definition of type {0}\n" + "found : {1}\n" + "expected: {2}");
140133

141134
static final DiagnosticType TEMPLATE_TRANSFORMATION_ON_CLASS =
142135
DiagnosticType.warning(
@@ -326,8 +319,7 @@ FunctionTypeBuilder inferFromOverriddenFunction(
326319
} else {
327320
// We're overriding with a function literal. Apply type information
328321
// to each parameter of the literal.
329-
FunctionParamBuilder paramBuilder =
330-
new FunctionParamBuilder(typeRegistry);
322+
FunctionParamBuilder paramBuilder = new FunctionParamBuilder(typeRegistry);
331323
Iterator<Parameter> oldParams = oldType.getParameters().iterator();
332324
boolean warnedAboutArgList = false;
333325
boolean oldParamsListHitOptArgs = false;
@@ -388,8 +380,7 @@ FunctionTypeBuilder inferFromOverriddenFunction(
388380
@CanIgnoreReturnValue
389381
FunctionTypeBuilder inferReturnType(@Nullable JSDocInfo info, boolean fromInlineDoc) {
390382
if (info != null) {
391-
JSTypeExpression returnTypeExpr =
392-
fromInlineDoc ? info.getType() : info.getReturnType();
383+
JSTypeExpression returnTypeExpr = fromInlineDoc ? info.getType() : info.getReturnType();
393384
if (returnTypeExpr != null) {
394385
returnType = returnTypeExpr.evaluate(templateScope, typeRegistry);
395386
returnTypeInferred = false;
@@ -612,9 +603,7 @@ FunctionTypeBuilder inferThisType(JSDocInfo info) {
612603
return this;
613604
}
614605

615-
/**
616-
* Infer the parameter types from the doc info alone.
617-
*/
606+
/** Infer the parameter types from the doc info alone. */
618607
FunctionTypeBuilder inferParameterTypes(JSDocInfo info) {
619608
// Create a fake args parent.
620609
Node lp = IR.paramList();
@@ -648,7 +637,7 @@ FunctionTypeBuilder inferParameterTypes(@Nullable Node paramsParent, @Nullable J
648637
FunctionParamBuilder builder = new FunctionParamBuilder(typeRegistry);
649638
boolean warnedAboutArgList = false;
650639
Set<String> allJsDocParams =
651-
(info == null) ? new HashSet<>() : new HashSet<>(info.getParameterNames());
640+
(info == null) ? new LinkedHashSet<>() : new LinkedHashSet<>(info.getParameterNames());
652641
boolean isVarArgs = false;
653642
int paramIndex = 0;
654643
for (Node param = paramsParent.getFirstChild(); param != null; param = param.getNext()) {
@@ -694,19 +683,16 @@ FunctionTypeBuilder inferParameterTypes(@Nullable Node paramsParent, @Nullable J
694683
parameterType = parameterTypeExpression.evaluate(templateScope, typeRegistry);
695684
isOptionalParam = parameterTypeExpression.isOptionalArg();
696685
isVarArgs = parameterTypeExpression.isVarArgs();
697-
} else if (oldParameterType != null &&
698-
oldParameterType.getJSType() != null) {
686+
} else if (oldParameterType != null && oldParameterType.getJSType() != null) {
699687
parameterType = oldParameterType.getJSType();
700688
isOptionalParam = oldParameterType.isOptional();
701689
isVarArgs = oldParameterType.isVariadic();
702690
} else {
703691
parameterType = typeRegistry.getNativeType(UNKNOWN_TYPE);
704692
}
705693

706-
warnedAboutArgList |= addParameter(
707-
builder, parameterType, warnedAboutArgList,
708-
isOptionalParam,
709-
isVarArgs);
694+
warnedAboutArgList |=
695+
addParameter(builder, parameterType, warnedAboutArgList, isOptionalParam, isVarArgs);
710696

711697
oldParameterType = oldParameters.hasNext() ? oldParameters.next() : null;
712698
paramIndex++;
@@ -781,7 +767,9 @@ private void setConstructorTemplateTypeNames(List<TemplateType> templates, @Null
781767
}
782768
}
783769

784-
/** @return Whether the given param is an optional param. */
770+
/**
771+
* @return Whether the given param is an optional param.
772+
*/
785773
private boolean isOptionalParameterByConvention(Node param) {
786774
if (param.isDestructuringPattern()) {
787775
return false;
@@ -897,17 +885,21 @@ FunctionTypeBuilder inferTemplateTypeName(@Nullable JSDocInfo info, @Nullable JS
897885

898886
/**
899887
* Add a parameter to the param list.
888+
*
900889
* @param builder A builder.
901890
* @param paramType The parameter type.
902-
* @param warnedAboutArgList Whether we've already warned about arg ordering
903-
* issues (like if optional args appeared before required ones).
891+
* @param warnedAboutArgList Whether we've already warned about arg ordering issues (like if
892+
* optional args appeared before required ones).
904893
* @param isOptional Is this an optional parameter?
905894
* @param isVarArgs Is this a var args parameter?
906895
* @return Whether a warning was emitted.
907896
*/
908-
private boolean addParameter(FunctionParamBuilder builder,
909-
JSType paramType, boolean warnedAboutArgList,
910-
boolean isOptional, boolean isVarArgs) {
897+
private boolean addParameter(
898+
FunctionParamBuilder builder,
899+
JSType paramType,
900+
boolean warnedAboutArgList,
901+
boolean isOptional,
902+
boolean isVarArgs) {
911903
boolean emittedWarning = false;
912904
if (isOptional) {
913905
// Remembering that an optional parameter has been encountered
@@ -985,18 +977,15 @@ private void provideDefaultReturnType() {
985977
}
986978
}
987979

988-
/**
989-
* Builds the function type, and puts it in the registry.
990-
*/
980+
/** Builds the function type, and puts it in the registry. */
991981
FunctionType buildAndRegister() {
992982
if (returnType == null) {
993983
provideDefaultReturnType();
994984
checkNotNull(returnType);
995985
}
996986

997987
if (parameters == null) {
998-
throw new IllegalStateException(
999-
"All Function types must have params and a return type");
988+
throw new IllegalStateException("All Function types must have params and a return type");
1000989
}
1001990

1002991
final FunctionType fnType;
@@ -1050,17 +1039,14 @@ private FunctionType.Builder createDefaultBuilder() {
10501039
}
10511040

10521041
/**
1053-
* Returns a constructor function either by returning it from the
1054-
* registry if it exists or creating and registering a new type. If
1055-
* there is already a type, then warn if the existing type is
1056-
* different than the one we are creating, though still return the
1057-
* existing function if possible. The primary purpose of this is
1058-
* that registering a constructor will fail for all built-in types
1059-
* that are initialized in {@link JSTypeRegistry}. We a) want to
1060-
* make sure that the type information specified in the externs file
1061-
* matches what is in the registry and b) annotate the externs with
1062-
* the {@link JSType} from the registry so that there are not two
1063-
* separate JSType objects for one type.
1042+
* Returns a constructor function either by returning it from the registry if it exists or
1043+
* creating and registering a new type. If there is already a type, then warn if the existing type
1044+
* is different than the one we are creating, though still return the existing function if
1045+
* possible. The primary purpose of this is that registering a constructor will fail for all
1046+
* built-in types that are initialized in {@link JSTypeRegistry}. We a) want to make sure that the
1047+
* type information specified in the externs file matches what is in the registry and b) annotate
1048+
* the externs with the {@link JSType} from the registry so that there are not two separate JSType
1049+
* objects for one type.
10641050
*/
10651051
private FunctionType getOrCreateConstructor() {
10661052
FunctionType fnType =
@@ -1090,17 +1076,17 @@ private FunctionType getOrCreateConstructor() {
10901076
boolean isInstanceObject = existingType.isInstanceType();
10911077
if (isInstanceObject || fnName.equals("Function")) {
10921078
FunctionType existingFn =
1093-
isInstanceObject ?
1094-
existingType.toObjectType().getConstructor() :
1095-
typeRegistry.getNativeFunctionType(FUNCTION_FUNCTION_TYPE);
1079+
isInstanceObject
1080+
? existingType.toObjectType().getConstructor()
1081+
: typeRegistry.getNativeFunctionType(FUNCTION_FUNCTION_TYPE);
10961082

10971083
if (existingFn.getSource() == null) {
10981084
existingFn.setSource(contents.getSourceNode());
10991085
}
11001086

11011087
if (!existingFn.hasEqualCallType(fnType)) {
1102-
reportWarning(TYPE_REDEFINITION, formatFnName(),
1103-
fnType.toString(), existingFn.toString());
1088+
reportWarning(
1089+
TYPE_REDEFINITION, formatFnName(), fnType.toString(), existingFn.toString());
11041090
}
11051091

11061092
// If the existing function is a built-in type, set its base type in case it @extends
@@ -1156,17 +1142,15 @@ private FunctionType getOrCreateInterface() {
11561142
return fnType;
11571143
}
11581144

1159-
private void reportWarning(DiagnosticType warning, String ... args) {
1145+
private void reportWarning(DiagnosticType warning, String... args) {
11601146
compiler.report(JSError.make(errorRoot, warning, args));
11611147
}
11621148

1163-
private void reportError(DiagnosticType error, String ... args) {
1149+
private void reportError(DiagnosticType error, String... args) {
11641150
compiler.report(JSError.make(errorRoot, error, args));
11651151
}
11661152

1167-
/**
1168-
* Determines whether the given JsDoc info declares a function type.
1169-
*/
1153+
/** Determines whether the given JsDoc info declares a function type. */
11701154
static boolean isFunctionTypeDeclaration(JSDocInfo info) {
11711155
return info.getParameterCount() > 0
11721156
|| info.hasReturnType()
@@ -1276,6 +1260,4 @@ public boolean mayHaveSingleThrow() {
12761260
return block.hasOneChild() && block.getFirstChild().isThrow();
12771261
}
12781262
}
1279-
1280-
12811263
}

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
import com.google.javascript.jscomp.graph.LatticeElement;
2525
import com.google.javascript.rhino.Node;
2626
import java.util.BitSet;
27-
import java.util.HashMap;
28-
import java.util.HashSet;
27+
import java.util.LinkedHashMap;
28+
import java.util.LinkedHashSet;
2929
import java.util.List;
3030
import java.util.Map;
3131
import java.util.Set;
@@ -71,7 +71,9 @@ public LiveVariableLattice finish() {
7171
static class LiveVariableLattice implements LatticeElement {
7272
private final BitSet liveSet;
7373

74-
/** @param numVars Number of all local variables. */
74+
/**
75+
* @param numVars Number of all local variables.
76+
*/
7577
private LiveVariableLattice(int numVars) {
7678
this.liveSet = new BitSet(numVars);
7779
}
@@ -128,6 +130,7 @@ public int hashCode() {
128130
private final List<Var> orderedVars;
129131

130132
private final Map<String, Var> allVarsInFn;
133+
131134
/**
132135
* Live Variables Analysis using the ES6 scope creator. This analysis should only be done on
133136
* function where jsScope is the function scope. If we call LiveVariablesAnalysis from the
@@ -155,8 +158,8 @@ public int hashCode() {
155158

156159
this.jsScope = jsScope;
157160
this.jsScopeChild = jsScopeChild;
158-
this.escaped = new HashSet<>();
159-
this.scopeVariables = new HashMap<>();
161+
this.escaped = new LinkedHashSet<>();
162+
this.scopeVariables = new LinkedHashMap<>();
160163
this.orderedVars = allVarsDeclaredInFunction.getAllVariablesInOrder();
161164
this.allVarsInFn = allVarsDeclaredInFunction.getAllVariables();
162165

0 commit comments

Comments
 (0)