Skip to content

Commit c497b48

Browse files
Add undefined to Symbol.valueDeclaration (#43033)
* About halfway through the checker I'm going to merge with master to avoid clashing with the declaration fix. * Add undefined to Symbol.valueDeclaration Also add undefined to a number of utility functions that have always accepted it, but never added it to their type. * Fix lint from code review Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com> * remove obsoleted fix from inferFromUsage Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
1 parent 3d1c6e8 commit c497b48

18 files changed

+98
-72
lines changed

src/compiler/binder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3187,7 +3187,7 @@ namespace ts {
31873187
undefined;
31883188
init = init && getRightMostAssignedExpression(init);
31893189
if (init) {
3190-
const isPrototypeAssignment = isPrototypeAccess(isVariableDeclaration(node) ? node.name : isBinaryExpression(node) ? node.left : node);
3190+
const isPrototypeAssignment = isPrototypeAccess(isVariableDeclaration(node!) ? node.name : isBinaryExpression(node!) ? node.left : node!);
31913191
return !!getExpandoInitializer(isBinaryExpression(init) && (init.operatorToken.kind === SyntaxKind.BarBarToken || init.operatorToken.kind === SyntaxKind.QuestionQuestionToken) ? init.right : init, isPrototypeAssignment);
31923192
}
31933193
return false;

src/compiler/checker.ts

Lines changed: 59 additions & 40 deletions
Large diffs are not rendered by default.

src/compiler/factory/nodeFactory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5507,7 +5507,7 @@ namespace ts {
55075507
: reduceLeft(expressions, factory.createComma)!;
55085508
}
55095509

5510-
function getName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean, emitFlags: EmitFlags = 0) {
5510+
function getName(node: Declaration | undefined, allowComments?: boolean, allowSourceMaps?: boolean, emitFlags: EmitFlags = 0) {
55115511
const nodeName = getNameOfDeclaration(node);
55125512
if (nodeName && isIdentifier(nodeName) && !isGeneratedIdentifier(nodeName)) {
55135513
// TODO(rbuckton): Does this need to be parented?
@@ -5571,7 +5571,7 @@ namespace ts {
55715571
* @param allowComments A value indicating whether comments may be emitted for the name.
55725572
* @param allowSourceMaps A value indicating whether source maps may be emitted for the name.
55735573
*/
5574-
function getDeclarationName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean) {
5574+
function getDeclarationName(node: Declaration | undefined, allowComments?: boolean, allowSourceMaps?: boolean) {
55755575
return getName(node, allowComments, allowSourceMaps);
55765576
}
55775577

src/compiler/moduleSpecifiers.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ namespace ts.moduleSpecifiers {
103103

104104
const info = getInfo(importingSourceFile.path, host);
105105
const moduleSourceFile = getSourceFileOfNode(moduleSymbol.valueDeclaration || getNonAugmentationDeclaration(moduleSymbol));
106+
if (!moduleSourceFile) {
107+
return [];
108+
}
106109
const modulePaths = getAllModulePaths(importingSourceFile.path, moduleSourceFile.originalFileName, host);
107110
const preferences = getPreferences(userPreferences, compilerOptions, importingSourceFile);
108111

src/compiler/transformers/declarations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1202,7 +1202,7 @@ namespace ts {
12021202
fakespace.symbol = props[0].parent!;
12031203
const exportMappings: [Identifier, string][] = [];
12041204
let declarations: (VariableStatement | ExportDeclaration)[] = mapDefined(props, p => {
1205-
if (!isPropertyAccessExpression(p.valueDeclaration)) {
1205+
if (!p.valueDeclaration || !isPropertyAccessExpression(p.valueDeclaration)) {
12061206
return undefined; // TODO GH#33569: Handle element access expressions that created late bound names (rather than silently omitting them)
12071207
}
12081208
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.valueDeclaration);

src/compiler/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4046,7 +4046,7 @@ namespace ts {
40464046
* The function returns the value (local variable) symbol of an identifier in the short-hand property assignment.
40474047
* This is necessary as an identifier in short-hand property assignment can contains two meaning: property name and property value.
40484048
*/
4049-
getShorthandAssignmentValueSymbol(location: Node): Symbol | undefined;
4049+
getShorthandAssignmentValueSymbol(location: Node | undefined): Symbol | undefined;
40504050

40514051
getExportSpecifierLocalTargetSymbol(location: ExportSpecifier | Identifier): Symbol | undefined;
40524052
/**
@@ -4715,7 +4715,7 @@ namespace ts {
47154715
flags: SymbolFlags; // Symbol flags
47164716
escapedName: __String; // Name of symbol
47174717
declarations?: Declaration[]; // Declarations associated with this symbol
4718-
valueDeclaration: Declaration; // First value declaration of the symbol
4718+
valueDeclaration?: Declaration; // First value declaration of the symbol
47194719
members?: SymbolTable; // Class, interface or object literal instance members
47204720
exports?: SymbolTable; // Module exports
47214721
globalExports?: SymbolTable; // Conditional global UMD exports
@@ -7394,7 +7394,7 @@ namespace ts {
73947394
* @param allowComments A value indicating whether comments may be emitted for the name.
73957395
* @param allowSourceMaps A value indicating whether source maps may be emitted for the name.
73967396
*/
7397-
/* @internal */ getDeclarationName(node: Declaration, allowComments?: boolean, allowSourceMaps?: boolean): Identifier;
7397+
/* @internal */ getDeclarationName(node: Declaration | undefined, allowComments?: boolean, allowSourceMaps?: boolean): Identifier;
73987398
/**
73997399
* Gets a namespace-qualified name for use in expressions.
74007400
*

src/compiler/utilities.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -734,9 +734,9 @@ namespace ts {
734734
return isShorthandAmbientModule(moduleSymbol.valueDeclaration);
735735
}
736736

737-
function isShorthandAmbientModule(node: Node): boolean {
737+
function isShorthandAmbientModule(node: Node | undefined): boolean {
738738
// The only kind of module that can be missing a body is a shorthand ambient module.
739-
return node && node.kind === SyntaxKind.ModuleDeclaration && (!(<ModuleDeclaration>node).body);
739+
return !!node && node.kind === SyntaxKind.ModuleDeclaration && (!(<ModuleDeclaration>node).body);
740740
}
741741

742742
export function isBlockScopedContainerTopLevel(node: Node): boolean {

src/compiler/utilitiesPublic.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ namespace ts {
614614
return (declaration as NamedDeclaration).name;
615615
}
616616

617-
export function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined {
617+
export function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined {
618618
if (declaration === undefined) return undefined;
619619
return getNonAssignedNameOfDeclaration(declaration) ||
620620
(isFunctionExpression(declaration) || isClassExpression(declaration) ? getAssignedName(declaration) : undefined);
@@ -1208,8 +1208,8 @@ namespace ts {
12081208

12091209
// Functions
12101210

1211-
export function isFunctionLike(node: Node): node is SignatureDeclaration {
1212-
return node && isFunctionLikeKind(node.kind);
1211+
export function isFunctionLike(node: Node | undefined): node is SignatureDeclaration {
1212+
return !!node && isFunctionLikeKind(node.kind);
12131213
}
12141214

12151215
/* @internal */

src/services/codefixes/convertConstToLet.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace ts.codefix {
1818
const token = getTokenAtPosition(sourceFile, pos);
1919
const checker = program.getTypeChecker();
2020
const symbol = checker.getSymbolAtLocation(token);
21-
if (symbol) {
21+
if (symbol?.valueDeclaration) {
2222
return symbol.valueDeclaration.parent.parent as VariableStatement;
2323
}
2424
}

src/services/codefixes/convertFunctionToEs6Class.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace ts.codefix {
1616

1717
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker, preferences: UserPreferences, compilerOptions: CompilerOptions): void {
1818
const ctorSymbol = checker.getSymbolAtLocation(getTokenAtPosition(sourceFile, position))!;
19-
if (!ctorSymbol || !(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable))) {
19+
if (!ctorSymbol || !ctorSymbol.valueDeclaration || !(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable))) {
2020
// Bad input
2121
return undefined;
2222
}
@@ -46,7 +46,7 @@ namespace ts.codefix {
4646
// all instance members are stored in the "member" array of symbol
4747
if (symbol.members) {
4848
symbol.members.forEach((member, key) => {
49-
if (key === "constructor") {
49+
if (key === "constructor" && member.valueDeclaration) {
5050
// fn.prototype.constructor = fn
5151
changes.delete(sourceFile, member.valueDeclaration.parent);
5252
return;

src/services/codefixes/convertToAsyncFunction.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,10 @@ namespace ts.codefix {
168168
// so we push an entry for 'response'.
169169
if (lastCallSignature && !isParameter(node.parent) && !isFunctionLikeDeclaration(node.parent) && !synthNamesMap.has(symbolIdString)) {
170170
const firstParameter = firstOrUndefined(lastCallSignature.parameters);
171-
const ident = firstParameter && isParameter(firstParameter.valueDeclaration) && tryCast(firstParameter.valueDeclaration.name, isIdentifier) || factory.createUniqueName("result", GeneratedIdentifierFlags.Optimistic);
171+
const ident = firstParameter?.valueDeclaration
172+
&& isParameter(firstParameter.valueDeclaration)
173+
&& tryCast(firstParameter.valueDeclaration.name, isIdentifier)
174+
|| factory.createUniqueName("result", GeneratedIdentifierFlags.Optimistic);
172175
const synthName = getNewNameIfConflict(ident, collidingSymbolMap);
173176
synthNamesMap.set(symbolIdString, synthName);
174177
collidingSymbolMap.add(ident.text, symbol);

src/services/codefixes/fixSpelling.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ namespace ts.codefix {
8787
const suggestion = symbolName(suggestedSymbol);
8888
if (!isIdentifierText(suggestion, target) && isPropertyAccessExpression(node.parent)) {
8989
const valDecl = suggestedSymbol.valueDeclaration;
90-
if (isNamedDeclaration(valDecl) && isPrivateIdentifier(valDecl.name)) {
90+
if (valDecl && isNamedDeclaration(valDecl) && isPrivateIdentifier(valDecl.name)) {
9191
changes.replaceNode(sourceFile, node, factory.createIdentifier(suggestion));
9292
}
9393
else {

src/services/codefixes/importFixes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@ namespace ts.codefix {
10251025
}
10261026

10271027
function allowsImportingAmbientModule(moduleSymbol: Symbol): boolean {
1028-
if (!packageJsons.length) {
1028+
if (!packageJsons.length || !moduleSymbol.valueDeclaration) {
10291029
return true;
10301030
}
10311031

src/services/codefixes/inferFromUsage.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,7 @@ namespace ts.codefix {
950950
const props = createMultiMap<Type>();
951951
for (const anon of anons) {
952952
for (const p of checker.getPropertiesOfType(anon)) {
953-
props.add(p.name, checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration));
953+
props.add(p.name, p.valueDeclaration ? checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration) : checker.getAnyType());
954954
}
955955
calls.push(...checker.getSignaturesOfType(anon, SignatureKind.Call));
956956
constructs.push(...checker.getSignaturesOfType(anon, SignatureKind.Construct));
@@ -1104,12 +1104,13 @@ namespace ts.codefix {
11041104
if (!usageParam) {
11051105
break;
11061106
}
1107-
let genericParamType = checker.getTypeOfSymbolAtLocation(genericParam, genericParam.valueDeclaration);
1107+
let genericParamType = genericParam.valueDeclaration ? checker.getTypeOfSymbolAtLocation(genericParam, genericParam.valueDeclaration) : checker.getAnyType();
11081108
const elementType = isRest && checker.getElementTypeOfArrayType(genericParamType);
11091109
if (elementType) {
11101110
genericParamType = elementType;
11111111
}
1112-
const targetType = (usageParam as SymbolLinks).type || checker.getTypeOfSymbolAtLocation(usageParam, usageParam.valueDeclaration);
1112+
const targetType = (usageParam as SymbolLinks).type
1113+
|| (usageParam.valueDeclaration ? checker.getTypeOfSymbolAtLocation(usageParam, usageParam.valueDeclaration) : checker.getAnyType());
11131114
types.push(...inferTypeParameters(genericParamType, targetType, typeParameter));
11141115
}
11151116
const genericReturn = checker.getReturnTypeOfSignature(genericSig);

src/services/importTracker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ namespace ts.FindAllReferences {
360360
const checker = program.getTypeChecker();
361361
for (const referencingFile of sourceFiles) {
362362
const searchSourceFile = searchModuleSymbol.valueDeclaration;
363-
if (searchSourceFile.kind === SyntaxKind.SourceFile) {
363+
if (searchSourceFile?.kind === SyntaxKind.SourceFile) {
364364
for (const ref of referencingFile.referencedFiles) {
365365
if (program.getSourceFileFromReference(referencingFile, ref) === searchSourceFile) {
366366
refs.push({ kind: "reference", referencingFile, ref });
@@ -582,7 +582,7 @@ namespace ts.FindAllReferences {
582582
return Debug.checkDefined(checker.getImmediateAliasedSymbol(importedSymbol));
583583
}
584584

585-
const decl = importedSymbol.valueDeclaration;
585+
const decl = Debug.checkDefined(importedSymbol.valueDeclaration);
586586
if (isExportAssignment(decl)) { // `export = class {}`
587587
return Debug.checkDefined(decl.expression.symbol);
588588
}

src/services/refactors/extractType.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ namespace ts.refactor {
168168
else if (isTypeQueryNode(node)) {
169169
if (isIdentifier(node.exprName)) {
170170
const symbol = checker.resolveName(node.exprName.text, node.exprName, SymbolFlags.Value, /* excludeGlobals */ false);
171-
if (symbol && rangeContainsSkipTrivia(statement, symbol.valueDeclaration, file) && !rangeContainsSkipTrivia(selection, symbol.valueDeclaration, file)) {
171+
if (symbol?.valueDeclaration && rangeContainsSkipTrivia(statement, symbol.valueDeclaration, file) && !rangeContainsSkipTrivia(selection, symbol.valueDeclaration, file)) {
172172
return true;
173173
}
174174
}

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2187,7 +2187,7 @@ declare namespace ts {
21872187
* The function returns the value (local variable) symbol of an identifier in the short-hand property assignment.
21882188
* This is necessary as an identifier in short-hand property assignment can contains two meaning: property name and property value.
21892189
*/
2190-
getShorthandAssignmentValueSymbol(location: Node): Symbol | undefined;
2190+
getShorthandAssignmentValueSymbol(location: Node | undefined): Symbol | undefined;
21912191
getExportSpecifierLocalTargetSymbol(location: ExportSpecifier | Identifier): Symbol | undefined;
21922192
/**
21932193
* If a symbol is a local symbol with an associated exported symbol, returns the exported symbol.
@@ -2409,7 +2409,7 @@ declare namespace ts {
24092409
flags: SymbolFlags;
24102410
escapedName: __String;
24112411
declarations?: Declaration[];
2412-
valueDeclaration: Declaration;
2412+
valueDeclaration?: Declaration;
24132413
members?: SymbolTable;
24142414
exports?: SymbolTable;
24152415
globalExports?: SymbolTable;
@@ -4107,7 +4107,7 @@ declare namespace ts {
41074107
function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): string;
41084108
function symbolName(symbol: Symbol): string;
41094109
function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateIdentifier | undefined;
4110-
function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined;
4110+
function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined;
41114111
/**
41124112
* Gets the JSDoc parameter tags for the node if present.
41134113
*
@@ -4233,7 +4233,7 @@ declare namespace ts {
42334233
function isEntityName(node: Node): node is EntityName;
42344234
function isPropertyName(node: Node): node is PropertyName;
42354235
function isBindingName(node: Node): node is BindingName;
4236-
function isFunctionLike(node: Node): node is SignatureDeclaration;
4236+
function isFunctionLike(node: Node | undefined): node is SignatureDeclaration;
42374237
function isClassElement(node: Node): node is ClassElement;
42384238
function isClassLike(node: Node): node is ClassLikeDeclaration;
42394239
function isAccessor(node: Node): node is AccessorDeclaration;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2187,7 +2187,7 @@ declare namespace ts {
21872187
* The function returns the value (local variable) symbol of an identifier in the short-hand property assignment.
21882188
* This is necessary as an identifier in short-hand property assignment can contains two meaning: property name and property value.
21892189
*/
2190-
getShorthandAssignmentValueSymbol(location: Node): Symbol | undefined;
2190+
getShorthandAssignmentValueSymbol(location: Node | undefined): Symbol | undefined;
21912191
getExportSpecifierLocalTargetSymbol(location: ExportSpecifier | Identifier): Symbol | undefined;
21922192
/**
21932193
* If a symbol is a local symbol with an associated exported symbol, returns the exported symbol.
@@ -2409,7 +2409,7 @@ declare namespace ts {
24092409
flags: SymbolFlags;
24102410
escapedName: __String;
24112411
declarations?: Declaration[];
2412-
valueDeclaration: Declaration;
2412+
valueDeclaration?: Declaration;
24132413
members?: SymbolTable;
24142414
exports?: SymbolTable;
24152415
globalExports?: SymbolTable;
@@ -4107,7 +4107,7 @@ declare namespace ts {
41074107
function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): string;
41084108
function symbolName(symbol: Symbol): string;
41094109
function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateIdentifier | undefined;
4110-
function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined;
4110+
function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined;
41114111
/**
41124112
* Gets the JSDoc parameter tags for the node if present.
41134113
*
@@ -4233,7 +4233,7 @@ declare namespace ts {
42334233
function isEntityName(node: Node): node is EntityName;
42344234
function isPropertyName(node: Node): node is PropertyName;
42354235
function isBindingName(node: Node): node is BindingName;
4236-
function isFunctionLike(node: Node): node is SignatureDeclaration;
4236+
function isFunctionLike(node: Node | undefined): node is SignatureDeclaration;
42374237
function isClassElement(node: Node): node is ClassElement;
42384238
function isClassLike(node: Node): node is ClassLikeDeclaration;
42394239
function isAccessor(node: Node): node is AccessorDeclaration;

0 commit comments

Comments
 (0)