Skip to content

Commit db23ca7

Browse files
committed
Guard public API surface of TypeChecker against synthesized nodes
1 parent 75fa22c commit db23ca7

File tree

2 files changed

+129
-42
lines changed

2 files changed

+129
-42
lines changed

src/compiler/checker.ts

Lines changed: 116 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ namespace ts {
6464
undefinedSymbol.declarations = [];
6565
const argumentsSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "arguments");
6666

67+
// for public members that accept a Node or one of its subtypes, we must guard against
68+
// synthetic nodes created during transformations by calling `getParseTreeNode`.
69+
// for most of these, we perform the guard only on `checker` to avoid any possible
70+
// extra cost of calling `getParseTreeNode` when calling these functions from inside the
71+
// checker.
6772
const checker: TypeChecker = {
6873
getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"),
6974
getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
@@ -74,46 +79,104 @@ namespace ts {
7479
isUnknownSymbol: symbol => symbol === unknownSymbol,
7580
getDiagnostics,
7681
getGlobalDiagnostics,
77-
getTypeOfSymbolAtLocation,
78-
getSymbolsOfParameterPropertyDeclaration,
82+
getTypeOfSymbolAtLocation: (symbol, location) => {
83+
location = getParseTreeNode(location);
84+
return location ? getTypeOfSymbolAtLocation(symbol, location) : unknownType;
85+
},
86+
getSymbolsOfParameterPropertyDeclaration: (parameter, parameterName) => {
87+
parameter = getParseTreeNode(parameter, isParameter);
88+
Debug.assert(parameter !== undefined, "Cannot get symbols of a synthetic parameter that cannot be resolved to a parse-tree node.");
89+
return getSymbolsOfParameterPropertyDeclaration(parameter, parameterName);
90+
},
7991
getDeclaredTypeOfSymbol,
8092
getPropertiesOfType,
8193
getPropertyOfType,
8294
getIndexInfoOfType,
8395
getSignaturesOfType,
8496
getIndexTypeOfType,
8597
getBaseTypes,
86-
getTypeFromTypeNode,
98+
getTypeFromTypeNode: node => {
99+
node = getParseTreeNode(node, isTypeNode);
100+
return node ? getTypeFromTypeNode(node) : unknownType;
101+
},
87102
getParameterType: getTypeAtPosition,
88103
getReturnTypeOfSignature,
89104
getNonNullableType,
90-
getSymbolsInScope,
91-
getSymbolAtLocation,
92-
getShorthandAssignmentValueSymbol,
93-
getExportSpecifierLocalTargetSymbol,
94-
getTypeAtLocation: getTypeOfNode,
95-
getPropertySymbolOfDestructuringAssignment,
96-
signatureToString,
97-
typeToString,
105+
getSymbolsInScope: (location, meaning) => {
106+
location = getParseTreeNode(location);
107+
return location ? getSymbolsInScope(location, meaning) : [];
108+
},
109+
getSymbolAtLocation: node => {
110+
node = getParseTreeNode(node);
111+
return node ? getSymbolAtLocation(node) : undefined;
112+
},
113+
getShorthandAssignmentValueSymbol: node => {
114+
node = getParseTreeNode(node);
115+
return node ? getShorthandAssignmentValueSymbol(node) : undefined;
116+
},
117+
getExportSpecifierLocalTargetSymbol: node => {
118+
node = getParseTreeNode(node, isExportSpecifier);
119+
return node ? getExportSpecifierLocalTargetSymbol(node) : undefined;
120+
},
121+
getTypeAtLocation: node => {
122+
node = getParseTreeNode(node);
123+
return node ? getTypeOfNode(node) : unknownType;
124+
},
125+
getPropertySymbolOfDestructuringAssignment: location => {
126+
location = getParseTreeNode(location, isIdentifier);
127+
return location ? getPropertySymbolOfDestructuringAssignment(location) : undefined;
128+
},
129+
signatureToString: (signature, enclosingDeclaration?, flags?, kind?) => {
130+
return signatureToString(signature, getParseTreeNode(enclosingDeclaration), flags, kind);
131+
},
132+
typeToString: (type, enclosingDeclaration?, flags?) => {
133+
return typeToString(type, getParseTreeNode(enclosingDeclaration), flags);
134+
},
98135
getSymbolDisplayBuilder,
99-
symbolToString,
136+
symbolToString: (symbol, enclosingDeclaration?, meaning?) => {
137+
return symbolToString(symbol, getParseTreeNode(enclosingDeclaration), meaning);
138+
},
100139
getAugmentedPropertiesOfType,
101140
getRootSymbols,
102-
getContextualType,
141+
getContextualType: node => {
142+
node = getParseTreeNode(node, isExpression)
143+
return node ? getContextualType(node) : undefined;
144+
},
103145
getFullyQualifiedName,
104-
getResolvedSignature,
105-
getConstantValue,
106-
isValidPropertyAccess,
107-
getSignatureFromDeclaration,
108-
isImplementationOfOverload,
146+
getResolvedSignature: (node, candidatesOutArray?) => {
147+
node = getParseTreeNode(node, isCallLikeExpression);
148+
return node ? getResolvedSignature(node, candidatesOutArray) : undefined;
149+
},
150+
getConstantValue: node => {
151+
node = getParseTreeNode(node, canHaveConstantValue);
152+
return node ? getConstantValue(node) : undefined;
153+
},
154+
isValidPropertyAccess: (node, propertyName) => {
155+
node = getParseTreeNode(node, isPropertyAccessOrQualifiedName);
156+
return node ? isValidPropertyAccess(node, propertyName) : false;
157+
},
158+
getSignatureFromDeclaration: declaration => {
159+
declaration = getParseTreeNode(declaration, isFunctionLike);
160+
return declaration ? getSignatureFromDeclaration(declaration) : undefined;
161+
},
162+
isImplementationOfOverload: node => {
163+
node = getParseTreeNode(node, isFunctionLike);
164+
return node ? isImplementationOfOverload(node) : undefined;
165+
},
109166
getAliasedSymbol: resolveAlias,
110167
getEmitResolver,
111168
getExportsOfModule: getExportsOfModuleAsArray,
112169
getExportsAndPropertiesOfModule,
113170
getAmbientModules,
114-
getJsxElementAttributesType,
171+
getJsxElementAttributesType: node => {
172+
node = getParseTreeNode(node, isJsxOpeningLikeElement);
173+
return node ? getJsxElementAttributesType(node) : undefined;
174+
},
115175
getJsxIntrinsicTagNames,
116-
isOptionalParameter,
176+
isOptionalParameter: node => {
177+
node = getParseTreeNode(node, isParameter);
178+
return node ? isOptionalParameter(node) : false;
179+
},
117180
tryGetMemberInModuleExports,
118181
tryFindAmbientModuleWithoutAugmentations: moduleName => {
119182
// we deliberately exclude augmentations
@@ -19819,14 +19882,14 @@ namespace ts {
1981919882
}
1982019883

1982119884
function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[] {
19822-
const symbols = createMap<Symbol>();
19823-
let memberFlags: ModifierFlags = ModifierFlags.None;
19824-
1982519885
if (isInsideWithStatementBody(location)) {
1982619886
// We cannot answer semantic questions within a with block, do not proceed any further
1982719887
return [];
1982819888
}
1982919889

19890+
const symbols = createMap<Symbol>();
19891+
let memberFlags: ModifierFlags = ModifierFlags.None;
19892+
1983019893
populateSymbols();
1983119894

1983219895
return symbolsToArray(symbols);
@@ -20086,6 +20149,7 @@ namespace ts {
2008620149
if (node.kind === SyntaxKind.SourceFile) {
2008720150
return isExternalModule(<SourceFile>node) ? getMergedSymbol(node.symbol) : undefined;
2008820151
}
20152+
2008920153
if (isInsideWithStatementBody(node)) {
2009020154
// We cannot answer semantic questions within a with block, do not proceed any further
2009120155
return undefined;
@@ -20536,12 +20600,6 @@ namespace ts {
2053620600
}
2053720601

2053820602
function isValueAliasDeclaration(node: Node): boolean {
20539-
node = getParseTreeNode(node);
20540-
if (node === undefined) {
20541-
// A synthesized node comes from an emit transformation and is always a value.
20542-
return true;
20543-
}
20544-
2054520603
switch (node.kind) {
2054620604
case SyntaxKind.ImportEqualsDeclaration:
2054720605
case SyntaxKind.ImportClause:
@@ -20588,12 +20646,6 @@ namespace ts {
2058820646
}
2058920647

2059020648
function isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean {
20591-
node = getParseTreeNode(node);
20592-
// Purely synthesized nodes are always emitted.
20593-
if (node === undefined) {
20594-
return true;
20595-
}
20596-
2059720649
if (isAliasSymbolDeclaration(node)) {
2059820650
const symbol = getSymbolOfNode(node);
2059920651
if (symbol && getSymbolLinks(symbol).referenced) {
@@ -20629,15 +20681,24 @@ namespace ts {
2062920681
}
2063020682

2063120683
function getNodeCheckFlags(node: Node): NodeCheckFlags {
20632-
node = getParseTreeNode(node);
20633-
return node ? getNodeLinks(node).flags : undefined;
20684+
return getNodeLinks(node).flags;
2063420685
}
2063520686

2063620687
function getEnumMemberValue(node: EnumMember): number {
2063720688
computeEnumMemberValues(<EnumDeclaration>node.parent);
2063820689
return getNodeLinks(node).enumMemberValue;
2063920690
}
2064020691

20692+
function canHaveConstantValue(node: Node): node is EnumMember | PropertyAccessExpression | ElementAccessExpression {
20693+
switch (node.kind) {
20694+
case SyntaxKind.EnumMember:
20695+
case SyntaxKind.PropertyAccessExpression:
20696+
case SyntaxKind.ElementAccessExpression:
20697+
return true;
20698+
}
20699+
return false;
20700+
}
20701+
2064120702
function getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number {
2064220703
if (node.kind === SyntaxKind.EnumMember) {
2064320704
return getEnumMemberValue(<EnumMember>node);
@@ -20814,10 +20875,21 @@ namespace ts {
2081420875
getReferencedImportDeclaration,
2081520876
getReferencedDeclarationWithCollidingName,
2081620877
isDeclarationWithCollidingName,
20817-
isValueAliasDeclaration,
20878+
isValueAliasDeclaration: node => {
20879+
node = getParseTreeNode(node);
20880+
// Synthesized nodes are always treated like values.
20881+
return node ? isValueAliasDeclaration(node) : true;
20882+
},
2081820883
hasGlobalName,
20819-
isReferencedAliasDeclaration,
20820-
getNodeCheckFlags,
20884+
isReferencedAliasDeclaration: (node, checkChildren?) => {
20885+
node = getParseTreeNode(node);
20886+
// Synthesized nodes are always treated as referenced.
20887+
return node ? isReferencedAliasDeclaration(node, checkChildren) : true;
20888+
},
20889+
getNodeCheckFlags: node => {
20890+
node = getParseTreeNode(node);
20891+
return node ? getNodeCheckFlags(node) : undefined;
20892+
},
2082120893
isTopLevelValueImportEqualsWithEntityName,
2082220894
isDeclarationVisible,
2082320895
isImplementationOfOverload,
@@ -20827,7 +20899,10 @@ namespace ts {
2082720899
writeBaseConstructorTypeOfClass,
2082820900
isSymbolAccessible,
2082920901
isEntityNameVisible,
20830-
getConstantValue,
20902+
getConstantValue: node => {
20903+
node = getParseTreeNode(node, canHaveConstantValue);
20904+
return node ? getConstantValue(node) : undefined;
20905+
},
2083120906
collectLinkedAliases,
2083220907
getReferencedValueDeclaration,
2083320908
getTypeReferenceSerializationKind,

src/compiler/utilities.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3731,6 +3731,12 @@ namespace ts {
37313731
return node.kind === SyntaxKind.PropertyAccessExpression;
37323732
}
37333733

3734+
export function isPropertyAccessOrQualifiedName(node: Node): node is PropertyAccessExpression | QualifiedName {
3735+
const kind = node.kind;
3736+
return kind === SyntaxKind.PropertyAccessExpression
3737+
|| kind === SyntaxKind.QualifiedName;
3738+
}
3739+
37343740
export function isElementAccessExpression(node: Node): node is ElementAccessExpression {
37353741
return node.kind === SyntaxKind.ElementAccessExpression;
37363742
}
@@ -4081,6 +4087,12 @@ namespace ts {
40814087
|| kind === SyntaxKind.JsxExpression;
40824088
}
40834089

4090+
export function isJsxOpeningLikeElement(node: Node): node is JsxOpeningLikeElement {
4091+
const kind = node.kind;
4092+
return kind === SyntaxKind.JsxOpeningElement
4093+
|| kind === SyntaxKind.JsxSelfClosingElement;
4094+
}
4095+
40844096
// Clauses
40854097

40864098
export function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause {
@@ -4531,7 +4543,7 @@ namespace ts {
45314543
*/
45324544
export function getParseTreeNode<T extends Node>(node: Node, nodeTest?: (node: Node) => node is T): T;
45334545
export function getParseTreeNode(node: Node, nodeTest?: (node: Node) => boolean): Node {
4534-
if (isParseTreeNode(node)) {
4546+
if (node == undefined || isParseTreeNode(node)) {
45354547
return node;
45364548
}
45374549

0 commit comments

Comments
 (0)