@tslite/services 0.0.0-stage → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +55 -0
- package/NOTICE +13 -0
- package/dist/_namespaces/edit.d.ts +8 -0
- package/dist/_namespaces/edit.js +11 -0
- package/dist/_namespaces/ts.Completions.StringCompletions.d.ts +1 -0
- package/dist/_namespaces/ts.Completions.StringCompletions.js +2 -0
- package/dist/_namespaces/ts.Completions.d.ts +2 -0
- package/dist/_namespaces/ts.Completions.js +3 -0
- package/dist/_namespaces/ts.FindAllReferences.d.ts +2 -0
- package/dist/_namespaces/ts.FindAllReferences.js +3 -0
- package/dist/_namespaces/ts.GoToDefinition.d.ts +1 -0
- package/dist/_namespaces/ts.GoToDefinition.js +2 -0
- package/dist/_namespaces/ts.NavigationBar.d.ts +1 -0
- package/dist/_namespaces/ts.NavigationBar.js +2 -0
- package/dist/_namespaces/ts.OrganizeImports.d.ts +1 -0
- package/dist/_namespaces/ts.OrganizeImports.js +2 -0
- package/dist/_namespaces/ts.OutliningElementsCollector.d.ts +1 -0
- package/dist/_namespaces/ts.OutliningElementsCollector.js +2 -0
- package/dist/_namespaces/ts.Rename.d.ts +1 -0
- package/dist/_namespaces/ts.Rename.js +2 -0
- package/dist/_namespaces/ts.SignatureHelp.d.ts +1 -0
- package/dist/_namespaces/ts.SignatureHelp.js +2 -0
- package/dist/_namespaces/ts.SmartSelectionRange.d.ts +1 -0
- package/dist/_namespaces/ts.SmartSelectionRange.js +2 -0
- package/dist/_namespaces/ts.SymbolDisplay.d.ts +1 -0
- package/dist/_namespaces/ts.SymbolDisplay.js +2 -0
- package/dist/_namespaces/ts.codefix.d.ts +26 -0
- package/dist/_namespaces/ts.codefix.js +27 -0
- package/dist/_namespaces/ts.d.ts +17 -0
- package/dist/_namespaces/ts.formatting.d.ts +7 -0
- package/dist/_namespaces/ts.formatting.js +8 -0
- package/dist/_namespaces/ts.js +20 -0
- package/dist/_namespaces/ts.refactor.addOrRemoveBracesToArrowFunction.d.ts +1 -0
- package/dist/_namespaces/ts.refactor.addOrRemoveBracesToArrowFunction.js +2 -0
- package/dist/_namespaces/ts.refactor.convertParamsToDestructuredObject.d.ts +1 -0
- package/dist/_namespaces/ts.refactor.convertParamsToDestructuredObject.js +2 -0
- package/dist/_namespaces/ts.refactor.convertStringOrTemplateLiteral.d.ts +1 -0
- package/dist/_namespaces/ts.refactor.convertStringOrTemplateLiteral.js +2 -0
- package/dist/_namespaces/ts.refactor.d.ts +9 -0
- package/dist/_namespaces/ts.refactor.extractSymbol.d.ts +1 -0
- package/dist/_namespaces/ts.refactor.extractSymbol.js +2 -0
- package/dist/_namespaces/ts.refactor.js +10 -0
- package/dist/_namespaces/ts.textChanges.d.ts +1 -0
- package/dist/_namespaces/ts.textChanges.js +2 -0
- package/dist/classifier.d.ts +5 -0
- package/dist/classifier.js +439 -0
- package/dist/codeFixProvider.d.ts +13 -0
- package/dist/codeFixProvider.js +84 -0
- package/dist/codefixes/addConvertToUnknownForNonOverlappingTypes.d.ts +1 -0
- package/dist/codefixes/addConvertToUnknownForNonOverlappingTypes.js +21 -0
- package/dist/codefixes/addEmptyExportDeclaration.d.ts +1 -0
- package/dist/codefixes/addEmptyExportDeclaration.js +17 -0
- package/dist/codefixes/addMissingAsync.d.ts +1 -0
- package/dist/codefixes/addMissingAsync.js +75 -0
- package/dist/codefixes/addMissingAwait.d.ts +1 -0
- package/dist/codefixes/addMissingAwait.js +236 -0
- package/dist/codefixes/addMissingConst.d.ts +1 -0
- package/dist/codefixes/addMissingConst.js +91 -0
- package/dist/codefixes/addNameToNamelessParameter.d.ts +1 -0
- package/dist/codefixes/addNameToNamelessParameter.js +29 -0
- package/dist/codefixes/convertConstToLet.d.ts +1 -0
- package/dist/codefixes/convertConstToLet.js +30 -0
- package/dist/codefixes/convertToAsyncFunction.d.ts +1 -0
- package/dist/codefixes/convertToAsyncFunction.js +495 -0
- package/dist/codefixes/convertToMappedObjectType.d.ts +1 -0
- package/dist/codefixes/convertToMappedObjectType.js +48 -0
- package/dist/codefixes/correctQualifiedNameToIndexedAccessType.d.ts +1 -0
- package/dist/codefixes/correctQualifiedNameToIndexedAccessType.js +33 -0
- package/dist/codefixes/fixAddModuleReferTypeMissingTypeof.d.ts +1 -0
- package/dist/codefixes/fixAddModuleReferTypeMissingTypeof.js +27 -0
- package/dist/codefixes/fixAwaitInSyncFunction.d.ts +1 -0
- package/dist/codefixes/fixAwaitInSyncFunction.js +69 -0
- package/dist/codefixes/fixExpectedComma.d.ts +1 -0
- package/dist/codefixes/fixExpectedComma.js +35 -0
- package/dist/codefixes/fixInvalidJsxCharacters.d.ts +1 -0
- package/dist/codefixes/fixInvalidJsxCharacters.js +41 -0
- package/dist/codefixes/fixMissingCallParentheses.d.ts +1 -0
- package/dist/codefixes/fixMissingCallParentheses.js +42 -0
- package/dist/codefixes/fixSpelling.d.ts +1 -0
- package/dist/codefixes/fixSpelling.js +94 -0
- package/dist/codefixes/fixUnreachableCode.d.ts +1 -0
- package/dist/codefixes/fixUnreachableCode.js +65 -0
- package/dist/codefixes/fixUnusedIdentifier.d.ts +1 -0
- package/dist/codefixes/fixUnusedIdentifier.js +224 -0
- package/dist/codefixes/helpers.d.ts +8 -0
- package/dist/codefixes/helpers.js +53 -0
- package/dist/codefixes/importFixes.d.ts +14 -0
- package/dist/codefixes/importFixes.js +441 -0
- package/dist/codefixes/inferFromUsage.d.ts +1 -0
- package/dist/codefixes/inferFromUsage.js +742 -0
- package/dist/codefixes/removeUnnecessaryAwait.d.ts +1 -0
- package/dist/codefixes/removeUnnecessaryAwait.js +41 -0
- package/dist/codefixes/returnValueCorrect.d.ts +1 -0
- package/dist/codefixes/returnValueCorrect.js +132 -0
- package/dist/codefixes/splitTypeOnlyImport.d.ts +1 -0
- package/dist/codefixes/splitTypeOnlyImport.js +32 -0
- package/dist/codefixes/useBigintLiteral.d.ts +1 -0
- package/dist/codefixes/useBigintLiteral.js +29 -0
- package/dist/completions.d.ts +83 -0
- package/dist/completions.js +1720 -0
- package/dist/documentHighlights.d.ts +8 -0
- package/dist/documentHighlights.js +367 -0
- package/dist/documentRegistry.d.ts +36 -0
- package/dist/documentRegistry.js +63 -0
- package/dist/editingServices.d.ts +1 -0
- package/dist/editingServices.js +4 -0
- package/dist/findAllReferences.d.ts +113 -0
- package/dist/findAllReferences.js +1366 -0
- package/dist/formatting/formatting.d.ts +26 -0
- package/dist/formatting/formatting.js +1021 -0
- package/dist/formatting/formattingContext.d.ts +34 -0
- package/dist/formatting/formattingContext.js +78 -0
- package/dist/formatting/formattingScanner.d.ts +14 -0
- package/dist/formatting/formattingScanner.js +228 -0
- package/dist/formatting/rule.d.ts +31 -0
- package/dist/formatting/rule.js +22 -0
- package/dist/formatting/rules.d.ts +7 -0
- package/dist/formatting/rules.js +610 -0
- package/dist/formatting/rulesMap.d.ts +5 -0
- package/dist/formatting/rulesMap.js +127 -0
- package/dist/formatting/smartIndenter.d.ts +44 -0
- package/dist/formatting/smartIndenter.js +518 -0
- package/dist/getEditsForFileRename.d.ts +6 -0
- package/dist/getEditsForFileRename.js +86 -0
- package/dist/goToDefinition.d.ts +8 -0
- package/dist/goToDefinition.js +246 -0
- package/dist/importTracker.d.ts +50 -0
- package/dist/importTracker.js +422 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/navigationBar.d.ts +3 -0
- package/dist/navigationBar.js +549 -0
- package/dist/organizeImports.d.ts +18 -0
- package/dist/organizeImports.js +290 -0
- package/dist/outliningElementsCollector.d.ts +2 -0
- package/dist/outliningElementsCollector.js +261 -0
- package/dist/refactorProvider.d.ts +5 -0
- package/dist/refactorProvider.js +16 -0
- package/dist/refactors/addOrRemoveBracesToArrowFunction.d.ts +1 -0
- package/dist/refactors/addOrRemoveBracesToArrowFunction.js +86 -0
- package/dist/refactors/convertExport.d.ts +1 -0
- package/dist/refactors/convertExport.js +126 -0
- package/dist/refactors/convertImport.d.ts +1 -0
- package/dist/refactors/convertImport.js +116 -0
- package/dist/refactors/convertParamsToDestructuredObject.d.ts +1 -0
- package/dist/refactors/convertParamsToDestructuredObject.js +282 -0
- package/dist/refactors/convertStringOrTemplateLiteral.d.ts +1 -0
- package/dist/refactors/convertStringOrTemplateLiteral.js +148 -0
- package/dist/refactors/extractSymbol.d.ts +60 -0
- package/dist/refactors/extractSymbol.js +1281 -0
- package/dist/refactors/extractType.d.ts +1 -0
- package/dist/refactors/extractType.js +102 -0
- package/dist/refactors/moveToNewFile.d.ts +1 -0
- package/dist/refactors/moveToNewFile.js +477 -0
- package/dist/rename.d.ts +2 -0
- package/dist/rename.js +100 -0
- package/dist/services.d.ts +48 -0
- package/dist/services.js +1480 -0
- package/dist/signatureHelp.d.ts +8 -0
- package/dist/signatureHelp.js +414 -0
- package/dist/smartSelection.d.ts +2 -0
- package/dist/smartSelection.js +243 -0
- package/dist/stringCompletions.d.ts +4 -0
- package/dist/stringCompletions.js +220 -0
- package/dist/suggestionDiagnostics.d.ts +6 -0
- package/dist/suggestionDiagnostics.js +92 -0
- package/dist/symbolDisplay.d.ts +16 -0
- package/dist/symbolDisplay.js +400 -0
- package/dist/textChanges.d.ts +161 -0
- package/dist/textChanges.js +1163 -0
- package/dist/types.d.ts +908 -0
- package/dist/types.js +263 -0
- package/dist/utilities.d.ts +283 -0
- package/dist/utilities.js +1981 -0
- package/package.json +45 -3
- package/README.md +0 -3
|
@@ -0,0 +1,742 @@
|
|
|
1
|
+
// Modificado de microsoft/TypeScript v3.9.10, src/services/codefixes/inferFromUsage.ts: o namespace virou módulo ES, com os imports explícitos.
|
|
2
|
+
import { Debug, Diagnostics, FindAllReferences, ObjectFlags, ScriptTarget, SignatureFlags, SymbolFlags, SyntaxKind, TypeFlags, UnionReduction, cast, createMultiMap, createSymbolTable, createToken, createUnderscoreEscapedMap, escapeLeadingUnderscores, findChildOfKind, first, flatMap, forEach, forEachEntry, getContainingFunction, getNameOfDeclaration, getObjectFlags, getTokenAtPosition, getTypeNodeIfAccessible, isArrowFunction, isAssignmentExpression, isCallExpression, isExpressionNode, isIdentifier, isParameter, isPropertySignature, isRestParameter, isRightSideOfQualifiedNameOrPropertyAccess, isVariableDeclaration, last, mapDefined, mapEntries, nodeSeenTracker, returnTrue, singleOrUndefined, textChanges, tryCast, } from "../_namespaces/edit.js";
|
|
3
|
+
import { codeFixAll, createCodeFixAction, createImportAdder, registerCodeFix, tryGetAutoImportableReferenceFromImportTypeNode, } from "../_namespaces/ts.codefix.js";
|
|
4
|
+
const fixId = "inferFromUsage";
|
|
5
|
+
// Na tag, também o retorno de um getter e o parâmetro de um setter sem anotação, o retorno implícito de uma `function`,
|
|
6
|
+
// de um método ou de um acessor com nome, e o `this` de uma função (CK-02); e a variante de sugestão de cada erro, que só
|
|
7
|
+
// vinha com o `noImplicitAny` desligado (CK-24). A cópia não acusa nenhum deles.
|
|
8
|
+
const errorCodes = [
|
|
9
|
+
// Variable declarations
|
|
10
|
+
Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code,
|
|
11
|
+
// Variable uses
|
|
12
|
+
Diagnostics.Variable_0_implicitly_has_an_1_type.code,
|
|
13
|
+
// Parameter declarations
|
|
14
|
+
Diagnostics.Parameter_0_implicitly_has_an_1_type.code,
|
|
15
|
+
Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code,
|
|
16
|
+
// Property declarations
|
|
17
|
+
Diagnostics.Member_0_implicitly_has_an_1_type.code,
|
|
18
|
+
];
|
|
19
|
+
// O alvo da configuração fixa (CK-24): o do nome que se importa.
|
|
20
|
+
const languageVersion = ScriptTarget.ES2020;
|
|
21
|
+
registerCodeFix({
|
|
22
|
+
errorCodes,
|
|
23
|
+
getCodeActions(context) {
|
|
24
|
+
const { sourceFile, program, span: { start }, errorCode, cancellationToken, host, preferences } = context;
|
|
25
|
+
const token = getTokenAtPosition(sourceFile, start);
|
|
26
|
+
let declaration;
|
|
27
|
+
const changes = textChanges.ChangeTracker.with(context, changes => { declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken, /*markSeen*/ returnTrue, host, preferences); });
|
|
28
|
+
const name = declaration && getNameOfDeclaration(declaration);
|
|
29
|
+
return !name || changes.length === 0 ? undefined
|
|
30
|
+
: [createCodeFixAction(fixId, changes, [getDiagnostic(errorCode), name.getText(sourceFile)], fixId, Diagnostics.Infer_all_types_from_usage)];
|
|
31
|
+
},
|
|
32
|
+
fixIds: [fixId],
|
|
33
|
+
getAllCodeActions(context) {
|
|
34
|
+
const { sourceFile, program, cancellationToken, host, preferences } = context;
|
|
35
|
+
const markSeen = nodeSeenTracker();
|
|
36
|
+
return codeFixAll(context, errorCodes, (changes, err) => {
|
|
37
|
+
doChange(changes, sourceFile, getTokenAtPosition(err.file, err.start), err.code, program, cancellationToken, markSeen, host, preferences);
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
// Na tag, recebia também o token, e o parâmetro de um setter dava o texto do tipo, e não o dos parâmetros; e o `this`
|
|
42
|
+
// de uma função tinha o texto dele (CK-02).
|
|
43
|
+
function getDiagnostic(errorCode) {
|
|
44
|
+
switch (errorCode) {
|
|
45
|
+
case Diagnostics.Parameter_0_implicitly_has_an_1_type.code:
|
|
46
|
+
return Diagnostics.Infer_parameter_types_from_usage;
|
|
47
|
+
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
|
|
48
|
+
return Diagnostics.Infer_parameter_types_from_usage;
|
|
49
|
+
default:
|
|
50
|
+
return Diagnostics.Infer_type_of_0_from_usage;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Na tag, aqui vinha o `mapSuggestionDiagnostic`, que trocava o código de cada sugestão pelo do erro dela: a cópia só dá
|
|
54
|
+
// o erro (CK-24).
|
|
55
|
+
function doChange(changes, sourceFile, token, errorCode, program, cancellationToken, markSeen, host, preferences) {
|
|
56
|
+
// Na tag, também o modificador de uma parameter property e o `this` (CK-02).
|
|
57
|
+
if (token.kind !== SyntaxKind.Identifier && token.kind !== SyntaxKind.DotDotDotToken) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
const { parent } = token;
|
|
61
|
+
const importAdder = createImportAdder(sourceFile, program, preferences, host);
|
|
62
|
+
switch (errorCode) {
|
|
63
|
+
// Variable and Property declarations
|
|
64
|
+
case Diagnostics.Member_0_implicitly_has_an_1_type.code:
|
|
65
|
+
case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code:
|
|
66
|
+
// Na tag, também a propriedade de classe (CK-02), e o acesso a uma propriedade num arquivo JavaScript, que
|
|
67
|
+
// ganhava uma tag `@type` do JSDoc (CK-03).
|
|
68
|
+
if ((isVariableDeclaration(parent) && markSeen(parent)) || isPropertySignature(parent)) { // handle bad location
|
|
69
|
+
annotateVariableDeclaration(changes, importAdder, sourceFile, parent, program, host, cancellationToken);
|
|
70
|
+
importAdder.writeFixes(changes);
|
|
71
|
+
return parent;
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
case Diagnostics.Variable_0_implicitly_has_an_1_type.code: {
|
|
75
|
+
const symbol = program.getTypeChecker().getSymbolAtLocation(token);
|
|
76
|
+
if (symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && markSeen(symbol.valueDeclaration)) {
|
|
77
|
+
annotateVariableDeclaration(changes, importAdder, sourceFile, symbol.valueDeclaration, program, host, cancellationToken);
|
|
78
|
+
importAdder.writeFixes(changes);
|
|
79
|
+
return symbol.valueDeclaration;
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const containingFunction = getContainingFunction(token);
|
|
85
|
+
if (containingFunction === undefined) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
let declaration;
|
|
89
|
+
switch (errorCode) {
|
|
90
|
+
// Parameter declarations
|
|
91
|
+
// Na tag, o parâmetro de um setter anotava o setter (CK-02).
|
|
92
|
+
case Diagnostics.Parameter_0_implicitly_has_an_1_type.code:
|
|
93
|
+
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
|
|
94
|
+
if (markSeen(containingFunction)) {
|
|
95
|
+
const param = cast(parent, isParameter);
|
|
96
|
+
annotateParameters(changes, importAdder, sourceFile, param, containingFunction, program, host, cancellationToken);
|
|
97
|
+
declaration = param;
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
// Na tag, também o retorno de um getter, o parâmetro de um setter e o `this` de uma função (CK-02).
|
|
101
|
+
default:
|
|
102
|
+
return Debug.fail(String(errorCode));
|
|
103
|
+
}
|
|
104
|
+
importAdder.writeFixes(changes);
|
|
105
|
+
return declaration;
|
|
106
|
+
}
|
|
107
|
+
// Na tag, também a propriedade de classe (CK-02).
|
|
108
|
+
function annotateVariableDeclaration(changes, importAdder, sourceFile, declaration, program, host, cancellationToken) {
|
|
109
|
+
if (isIdentifier(declaration.name)) {
|
|
110
|
+
annotate(changes, importAdder, sourceFile, declaration, inferTypeForVariableFromUsage(declaration.name, program, cancellationToken), program, host);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function annotateParameters(changes, importAdder, sourceFile, parameterDeclaration, containingFunction, program, host, cancellationToken) {
|
|
114
|
+
if (!isIdentifier(parameterDeclaration.name)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const parameterInferences = inferTypeForParametersFromUsage(containingFunction, program, cancellationToken);
|
|
118
|
+
Debug.assert(containingFunction.parameters.length === parameterInferences.length, "Parameter count and inference count should match");
|
|
119
|
+
// Na tag, num arquivo JavaScript, os tipos iam para tags `@param` do JSDoc (CK-03).
|
|
120
|
+
const needParens = isArrowFunction(containingFunction) && !findChildOfKind(containingFunction, SyntaxKind.OpenParenToken, sourceFile);
|
|
121
|
+
if (needParens)
|
|
122
|
+
changes.insertNodeBefore(sourceFile, first(containingFunction.parameters), createToken(SyntaxKind.OpenParenToken));
|
|
123
|
+
for (const { declaration, type } of parameterInferences) {
|
|
124
|
+
if (declaration && !declaration.type && !declaration.initializer) {
|
|
125
|
+
annotate(changes, importAdder, sourceFile, declaration, type, program, host);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (needParens)
|
|
129
|
+
changes.insertNodeAfter(sourceFile, last(containingFunction.parameters), createToken(SyntaxKind.CloseParenToken));
|
|
130
|
+
}
|
|
131
|
+
// Na tag, aqui vinham o `annotateThis` e o `annotateJSDocThis`, do `this` de uma função, e o `annotateSetAccessor`, do
|
|
132
|
+
// parâmetro de um setter (CK-02).
|
|
133
|
+
function annotate(changes, importAdder, sourceFile, declaration, type, program, host) {
|
|
134
|
+
const typeNode = getTypeNodeIfAccessible(type, declaration, program, host);
|
|
135
|
+
if (typeNode) {
|
|
136
|
+
// Na tag, num arquivo JavaScript, o tipo ia para uma tag `@type` ou `@return` do JSDoc (CK-03).
|
|
137
|
+
if (!tryReplaceImportTypeNodeWithAutoImport(typeNode, declaration, type, sourceFile, changes, importAdder, languageVersion)) {
|
|
138
|
+
changes.tryInsertTypeAnnotation(sourceFile, declaration, typeNode);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function tryReplaceImportTypeNodeWithAutoImport(typeNode, declaration, type, sourceFile, changes, importAdder, scriptTarget) {
|
|
143
|
+
const importableReference = tryGetAutoImportableReferenceFromImportTypeNode(typeNode, type, scriptTarget);
|
|
144
|
+
if (importableReference && changes.tryInsertTypeAnnotation(sourceFile, declaration, importableReference.typeReference)) {
|
|
145
|
+
forEach(importableReference.symbols, s => importAdder.addImportFromExportedSymbol(s, /*usageIsTypeOnly*/ true));
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
// Na tag, aqui vinham o `annotateJSDocParameters`, o `addJSDocTags`, o `getJsDocNodeForArrowFunction` e o
|
|
151
|
+
// `tryMergeJsdocTags`, que escreviam as tags do JSDoc de um arquivo JavaScript (CK-03).
|
|
152
|
+
// Na tag, o token podia ser também a palavra `constructor` (CK-02).
|
|
153
|
+
function getReferences(token, program, cancellationToken) {
|
|
154
|
+
// Position shouldn't matter since token is not a SourceFile.
|
|
155
|
+
return mapDefined(FindAllReferences.getReferenceEntriesForNode(-1, token, program, program.getSourceFiles(), cancellationToken), entry => entry.kind !== 0 /* FindAllReferences.EntryKind.Span */ ? tryCast(entry.node, isIdentifier) : undefined);
|
|
156
|
+
}
|
|
157
|
+
// Na tag, o token podia ser também o nome `#private` (CK-02).
|
|
158
|
+
function inferTypeForVariableFromUsage(token, program, cancellationToken) {
|
|
159
|
+
const references = getReferences(token, program, cancellationToken);
|
|
160
|
+
return inferTypeFromReferences(program, references, cancellationToken).single();
|
|
161
|
+
}
|
|
162
|
+
// Na tag, recebia também o arquivo, que só repassava.
|
|
163
|
+
function inferTypeForParametersFromUsage(func, program, cancellationToken) {
|
|
164
|
+
const references = getFunctionReferences(func, program, cancellationToken);
|
|
165
|
+
return references && inferTypeFromReferences(program, references, cancellationToken).parameters(func) ||
|
|
166
|
+
func.parameters.map(p => ({
|
|
167
|
+
declaration: p,
|
|
168
|
+
type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : program.getTypeChecker().getAnyType()
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
// Na tag, recebia também o arquivo, que só a palavra `constructor` pedia (CK-02).
|
|
172
|
+
function getFunctionReferences(containingFunction, program, cancellationToken) {
|
|
173
|
+
let searchToken;
|
|
174
|
+
// Na tag, também o construtor, a function expression, a `function` declarada e o método (CK-02).
|
|
175
|
+
switch (containingFunction.kind) {
|
|
176
|
+
case SyntaxKind.ArrowFunction:
|
|
177
|
+
const parent = containingFunction.parent;
|
|
178
|
+
searchToken = isVariableDeclaration(parent) && isIdentifier(parent.name) ?
|
|
179
|
+
parent.name :
|
|
180
|
+
containingFunction.name;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
if (!searchToken) {
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
return getReferences(searchToken, program, cancellationToken);
|
|
187
|
+
}
|
|
188
|
+
function inferTypeFromReferences(program, references, cancellationToken) {
|
|
189
|
+
const checker = program.getTypeChecker();
|
|
190
|
+
const builtinConstructors = {
|
|
191
|
+
string: () => checker.getStringType(),
|
|
192
|
+
number: () => checker.getNumberType(),
|
|
193
|
+
Array: t => checker.createArrayType(t),
|
|
194
|
+
Promise: t => checker.createPromiseType(t),
|
|
195
|
+
};
|
|
196
|
+
const builtins = [
|
|
197
|
+
checker.getStringType(),
|
|
198
|
+
checker.getNumberType(),
|
|
199
|
+
checker.createArrayType(checker.getAnyType()),
|
|
200
|
+
checker.createPromiseType(checker.getAnyType()),
|
|
201
|
+
];
|
|
202
|
+
// Na tag, também o tipo do `this` (CK-02).
|
|
203
|
+
return {
|
|
204
|
+
single,
|
|
205
|
+
parameters,
|
|
206
|
+
};
|
|
207
|
+
function createEmptyUsage() {
|
|
208
|
+
return {
|
|
209
|
+
isNumber: undefined,
|
|
210
|
+
isString: undefined,
|
|
211
|
+
isNumberOrString: undefined,
|
|
212
|
+
candidateTypes: undefined,
|
|
213
|
+
properties: undefined,
|
|
214
|
+
calls: undefined,
|
|
215
|
+
numberIndex: undefined,
|
|
216
|
+
stringIndex: undefined,
|
|
217
|
+
inferredTypes: undefined,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function combineUsages(usages) {
|
|
221
|
+
const combinedProperties = createUnderscoreEscapedMap();
|
|
222
|
+
for (const u of usages) {
|
|
223
|
+
if (u.properties) {
|
|
224
|
+
u.properties.forEach((p, name) => {
|
|
225
|
+
if (!combinedProperties.has(name)) {
|
|
226
|
+
combinedProperties.set(name, []);
|
|
227
|
+
}
|
|
228
|
+
combinedProperties.get(name).push(p);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const properties = createUnderscoreEscapedMap();
|
|
233
|
+
combinedProperties.forEach((ps, name) => {
|
|
234
|
+
properties.set(name, combineUsages(ps));
|
|
235
|
+
});
|
|
236
|
+
return {
|
|
237
|
+
isNumber: usages.some(u => u.isNumber),
|
|
238
|
+
isString: usages.some(u => u.isString),
|
|
239
|
+
isNumberOrString: usages.some(u => u.isNumberOrString),
|
|
240
|
+
candidateTypes: flatMap(usages, u => u.candidateTypes),
|
|
241
|
+
properties,
|
|
242
|
+
calls: flatMap(usages, u => u.calls),
|
|
243
|
+
numberIndex: forEach(usages, u => u.numberIndex),
|
|
244
|
+
stringIndex: forEach(usages, u => u.stringIndex),
|
|
245
|
+
inferredTypes: undefined, // clear type cache
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function single() {
|
|
249
|
+
return combineTypes(inferTypesFromReferencesSingle(references));
|
|
250
|
+
}
|
|
251
|
+
function parameters(declaration) {
|
|
252
|
+
if (references.length === 0 || !declaration.parameters) {
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
const usage = createEmptyUsage();
|
|
256
|
+
for (const reference of references) {
|
|
257
|
+
cancellationToken.throwIfCancellationRequested();
|
|
258
|
+
calculateUsageOfNode(reference, usage);
|
|
259
|
+
}
|
|
260
|
+
// Na tag, primeiro as chamadas com `new` (CK-02).
|
|
261
|
+
const calls = [...usage.calls || []];
|
|
262
|
+
return declaration.parameters.map((parameter, parameterIndex) => {
|
|
263
|
+
const types = [];
|
|
264
|
+
const isRest = isRestParameter(parameter);
|
|
265
|
+
for (const call of calls) {
|
|
266
|
+
if (call.argumentTypes.length <= parameterIndex) {
|
|
267
|
+
// Na tag, num arquivo JavaScript, o parâmetro ficava também opcional (CK-03).
|
|
268
|
+
types.push(checker.getUndefinedType());
|
|
269
|
+
}
|
|
270
|
+
else if (isRest) {
|
|
271
|
+
for (let i = parameterIndex; i < call.argumentTypes.length; i++) {
|
|
272
|
+
types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[i]));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
types.push(checker.getBaseTypeOfLiteralType(call.argumentTypes[parameterIndex]));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (isIdentifier(parameter.name)) {
|
|
280
|
+
const inferred = inferTypesFromReferencesSingle(getReferences(parameter.name, program, cancellationToken));
|
|
281
|
+
types.push(...(isRest ? mapDefined(inferred, checker.getElementTypeOfArrayType) : inferred));
|
|
282
|
+
}
|
|
283
|
+
const type = combineTypes(types);
|
|
284
|
+
return {
|
|
285
|
+
type: isRest ? checker.createArrayType(type) : type,
|
|
286
|
+
declaration: parameter
|
|
287
|
+
};
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
// Na tag, aqui vinha o `thisParameter`, o tipo do `this` pelos usos (CK-02).
|
|
291
|
+
function inferTypesFromReferencesSingle(references) {
|
|
292
|
+
const usage = createEmptyUsage();
|
|
293
|
+
for (const reference of references) {
|
|
294
|
+
cancellationToken.throwIfCancellationRequested();
|
|
295
|
+
calculateUsageOfNode(reference, usage);
|
|
296
|
+
}
|
|
297
|
+
return inferTypes(usage);
|
|
298
|
+
}
|
|
299
|
+
function calculateUsageOfNode(node, usage) {
|
|
300
|
+
while (isRightSideOfQualifiedNameOrPropertyAccess(node)) {
|
|
301
|
+
node = node.parent;
|
|
302
|
+
}
|
|
303
|
+
switch (node.parent.kind) {
|
|
304
|
+
case SyntaxKind.ExpressionStatement:
|
|
305
|
+
inferTypeFromExpressionStatement(node, usage);
|
|
306
|
+
break;
|
|
307
|
+
case SyntaxKind.PostfixUnaryExpression:
|
|
308
|
+
usage.isNumber = true;
|
|
309
|
+
break;
|
|
310
|
+
case SyntaxKind.PrefixUnaryExpression:
|
|
311
|
+
inferTypeFromPrefixUnaryExpression(node.parent, usage);
|
|
312
|
+
break;
|
|
313
|
+
case SyntaxKind.BinaryExpression:
|
|
314
|
+
inferTypeFromBinaryExpression(node, node.parent, usage);
|
|
315
|
+
break;
|
|
316
|
+
case SyntaxKind.CaseClause:
|
|
317
|
+
case SyntaxKind.DefaultClause:
|
|
318
|
+
inferTypeFromSwitchStatementLabel(node.parent, usage);
|
|
319
|
+
break;
|
|
320
|
+
// Na tag, também a chamada com `new` (CK-02).
|
|
321
|
+
case SyntaxKind.CallExpression:
|
|
322
|
+
if (node.parent.expression === node) {
|
|
323
|
+
inferTypeFromCallExpression(node.parent, usage);
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
inferTypeFromContextualType(node, usage);
|
|
327
|
+
}
|
|
328
|
+
break;
|
|
329
|
+
case SyntaxKind.PropertyAccessExpression:
|
|
330
|
+
inferTypeFromPropertyAccessExpression(node.parent, usage);
|
|
331
|
+
break;
|
|
332
|
+
case SyntaxKind.ElementAccessExpression:
|
|
333
|
+
inferTypeFromPropertyElementExpression(node.parent, node, usage);
|
|
334
|
+
break;
|
|
335
|
+
case SyntaxKind.PropertyAssignment:
|
|
336
|
+
case SyntaxKind.ShorthandPropertyAssignment:
|
|
337
|
+
// Na tag, o tipo do object literal ia para os candidatos ao tipo do `this` de quem o usava (CK-02).
|
|
338
|
+
break;
|
|
339
|
+
// Na tag, também a propriedade de classe, que dava o tipo do `this` (CK-02).
|
|
340
|
+
case SyntaxKind.VariableDeclaration: {
|
|
341
|
+
const { name, initializer } = node.parent;
|
|
342
|
+
if (node === name) {
|
|
343
|
+
if (initializer) { // This can happen for `let x = null;` which still has an implicit-any error.
|
|
344
|
+
addCandidateType(usage, checker.getTypeAtLocation(initializer));
|
|
345
|
+
}
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
// falls through
|
|
350
|
+
default:
|
|
351
|
+
return inferTypeFromContextualType(node, usage);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function inferTypeFromContextualType(node, usage) {
|
|
355
|
+
if (isExpressionNode(node)) {
|
|
356
|
+
addCandidateType(usage, checker.getContextualType(node));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function inferTypeFromExpressionStatement(node, usage) {
|
|
360
|
+
addCandidateType(usage, isCallExpression(node) ? checker.getVoidType() : checker.getAnyType());
|
|
361
|
+
}
|
|
362
|
+
function inferTypeFromPrefixUnaryExpression(node, usage) {
|
|
363
|
+
switch (node.operator) {
|
|
364
|
+
case SyntaxKind.PlusPlusToken:
|
|
365
|
+
case SyntaxKind.MinusMinusToken:
|
|
366
|
+
case SyntaxKind.MinusToken:
|
|
367
|
+
case SyntaxKind.TildeToken:
|
|
368
|
+
usage.isNumber = true;
|
|
369
|
+
break;
|
|
370
|
+
case SyntaxKind.PlusToken:
|
|
371
|
+
usage.isNumberOrString = true;
|
|
372
|
+
break;
|
|
373
|
+
// case SyntaxKind.ExclamationToken:
|
|
374
|
+
// no inferences here;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function inferTypeFromBinaryExpression(node, parent, usage) {
|
|
378
|
+
switch (parent.operatorToken.kind) {
|
|
379
|
+
// ExponentiationOperator
|
|
380
|
+
case SyntaxKind.AsteriskAsteriskToken:
|
|
381
|
+
// MultiplicativeOperator
|
|
382
|
+
// falls through
|
|
383
|
+
case SyntaxKind.AsteriskToken:
|
|
384
|
+
case SyntaxKind.SlashToken:
|
|
385
|
+
case SyntaxKind.PercentToken:
|
|
386
|
+
// ShiftOperator
|
|
387
|
+
// falls through
|
|
388
|
+
case SyntaxKind.LessThanLessThanToken:
|
|
389
|
+
case SyntaxKind.GreaterThanGreaterThanToken:
|
|
390
|
+
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
|
|
391
|
+
// BitwiseOperator
|
|
392
|
+
// falls through
|
|
393
|
+
case SyntaxKind.AmpersandToken:
|
|
394
|
+
case SyntaxKind.BarToken:
|
|
395
|
+
case SyntaxKind.CaretToken:
|
|
396
|
+
// CompoundAssignmentOperator
|
|
397
|
+
// falls through
|
|
398
|
+
case SyntaxKind.MinusEqualsToken:
|
|
399
|
+
case SyntaxKind.AsteriskAsteriskEqualsToken:
|
|
400
|
+
case SyntaxKind.AsteriskEqualsToken:
|
|
401
|
+
case SyntaxKind.SlashEqualsToken:
|
|
402
|
+
case SyntaxKind.PercentEqualsToken:
|
|
403
|
+
case SyntaxKind.AmpersandEqualsToken:
|
|
404
|
+
case SyntaxKind.BarEqualsToken:
|
|
405
|
+
case SyntaxKind.CaretEqualsToken:
|
|
406
|
+
case SyntaxKind.LessThanLessThanEqualsToken:
|
|
407
|
+
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
|
|
408
|
+
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
|
|
409
|
+
// AdditiveOperator
|
|
410
|
+
// falls through
|
|
411
|
+
case SyntaxKind.MinusToken:
|
|
412
|
+
// RelationalOperator
|
|
413
|
+
// falls through
|
|
414
|
+
case SyntaxKind.LessThanToken:
|
|
415
|
+
case SyntaxKind.LessThanEqualsToken:
|
|
416
|
+
case SyntaxKind.GreaterThanToken:
|
|
417
|
+
case SyntaxKind.GreaterThanEqualsToken:
|
|
418
|
+
// Na tag, o operando de um enum dava o tipo do enum (CK-02).
|
|
419
|
+
usage.isNumber = true;
|
|
420
|
+
break;
|
|
421
|
+
case SyntaxKind.PlusEqualsToken:
|
|
422
|
+
case SyntaxKind.PlusToken:
|
|
423
|
+
const otherOperandType = checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left);
|
|
424
|
+
// Na tag, primeiro o operando de um enum, que dava o tipo do enum (CK-02).
|
|
425
|
+
if (otherOperandType.flags & TypeFlags.NumberLike) {
|
|
426
|
+
usage.isNumber = true;
|
|
427
|
+
}
|
|
428
|
+
else if (otherOperandType.flags & TypeFlags.StringLike) {
|
|
429
|
+
usage.isString = true;
|
|
430
|
+
}
|
|
431
|
+
else if (otherOperandType.flags & TypeFlags.Any) {
|
|
432
|
+
// do nothing, maybe we'll learn something elsewhere
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
usage.isNumberOrString = true;
|
|
436
|
+
}
|
|
437
|
+
break;
|
|
438
|
+
// AssignmentOperators
|
|
439
|
+
// Na tag, também o `===` e o `!==`, que a Linguagem não tem (CK-70).
|
|
440
|
+
case SyntaxKind.EqualsToken:
|
|
441
|
+
case SyntaxKind.EqualsEqualsToken:
|
|
442
|
+
case SyntaxKind.ExclamationEqualsToken:
|
|
443
|
+
addCandidateType(usage, checker.getTypeAtLocation(parent.left === node ? parent.right : parent.left));
|
|
444
|
+
break;
|
|
445
|
+
case SyntaxKind.InKeyword:
|
|
446
|
+
if (node === parent.left) {
|
|
447
|
+
usage.isString = true;
|
|
448
|
+
}
|
|
449
|
+
break;
|
|
450
|
+
// LogicalOperator Or NullishCoalescing
|
|
451
|
+
case SyntaxKind.BarBarToken:
|
|
452
|
+
case SyntaxKind.QuestionQuestionToken:
|
|
453
|
+
if (node === parent.left &&
|
|
454
|
+
(node.parent.parent.kind === SyntaxKind.VariableDeclaration || isAssignmentExpression(node.parent.parent, /*excludeCompoundAssignment*/ true))) {
|
|
455
|
+
// var x = x || {};
|
|
456
|
+
// TODO: use getFalsyflagsOfType
|
|
457
|
+
addCandidateType(usage, checker.getTypeAtLocation(parent.right));
|
|
458
|
+
}
|
|
459
|
+
break;
|
|
460
|
+
// Na tag, também a vírgula e o `instanceof`, de que nada se infere (CK-02).
|
|
461
|
+
case SyntaxKind.AmpersandAmpersandToken:
|
|
462
|
+
// nothing to infer here
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
function inferTypeFromSwitchStatementLabel(parent, usage) {
|
|
467
|
+
addCandidateType(usage, checker.getTypeAtLocation(parent.parent.parent.expression));
|
|
468
|
+
}
|
|
469
|
+
// Na tag, também a chamada com `new` (CK-02).
|
|
470
|
+
function inferTypeFromCallExpression(parent, usage) {
|
|
471
|
+
const call = {
|
|
472
|
+
argumentTypes: [],
|
|
473
|
+
return_: createEmptyUsage()
|
|
474
|
+
};
|
|
475
|
+
if (parent.arguments) {
|
|
476
|
+
for (const argument of parent.arguments) {
|
|
477
|
+
call.argumentTypes.push(checker.getTypeAtLocation(argument));
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
calculateUsageOfNode(parent, call.return_);
|
|
481
|
+
(usage.calls || (usage.calls = [])).push(call);
|
|
482
|
+
}
|
|
483
|
+
function inferTypeFromPropertyAccessExpression(parent, usage) {
|
|
484
|
+
const name = escapeLeadingUnderscores(parent.name.text);
|
|
485
|
+
if (!usage.properties) {
|
|
486
|
+
usage.properties = createUnderscoreEscapedMap();
|
|
487
|
+
}
|
|
488
|
+
const propertyUsage = usage.properties.get(name) || createEmptyUsage();
|
|
489
|
+
calculateUsageOfNode(parent, propertyUsage);
|
|
490
|
+
usage.properties.set(name, propertyUsage);
|
|
491
|
+
}
|
|
492
|
+
function inferTypeFromPropertyElementExpression(parent, node, usage) {
|
|
493
|
+
if (node === parent.argumentExpression) {
|
|
494
|
+
usage.isNumberOrString = true;
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
const indexType = checker.getTypeAtLocation(parent.argumentExpression);
|
|
499
|
+
const indexUsage = createEmptyUsage();
|
|
500
|
+
calculateUsageOfNode(parent, indexUsage);
|
|
501
|
+
if (indexType.flags & TypeFlags.NumberLike) {
|
|
502
|
+
usage.numberIndex = indexUsage;
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
usage.stringIndex = indexUsage;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
function removeLowPriorityInferences(inferences, priorities) {
|
|
510
|
+
const toRemove = [];
|
|
511
|
+
for (const i of inferences) {
|
|
512
|
+
for (const { high, low } of priorities) {
|
|
513
|
+
if (high(i)) {
|
|
514
|
+
Debug.assert(!low(i), "Priority can't have both low and high");
|
|
515
|
+
toRemove.push(low);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return inferences.filter(i => toRemove.every(f => !f(i)));
|
|
520
|
+
}
|
|
521
|
+
function combineFromUsage(usage) {
|
|
522
|
+
return combineTypes(inferTypes(usage));
|
|
523
|
+
}
|
|
524
|
+
function combineTypes(inferences) {
|
|
525
|
+
if (!inferences.length)
|
|
526
|
+
return checker.getAnyType();
|
|
527
|
+
// 1. string or number individually override string | number
|
|
528
|
+
// 2. non-any, non-void overrides any or void
|
|
529
|
+
// 3. non-nullable, non-any, non-void, non-anonymous overrides anonymous types
|
|
530
|
+
const stringNumber = checker.getUnionType([checker.getStringType(), checker.getNumberType()]);
|
|
531
|
+
const priorities = [
|
|
532
|
+
{
|
|
533
|
+
high: t => t === checker.getStringType() || t === checker.getNumberType(),
|
|
534
|
+
low: t => t === stringNumber
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
high: t => !(t.flags & (TypeFlags.Any | TypeFlags.Void)),
|
|
538
|
+
low: t => !!(t.flags & (TypeFlags.Any | TypeFlags.Void))
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
high: t => !(t.flags & (TypeFlags.Nullable | TypeFlags.Any | TypeFlags.Void)) && !(getObjectFlags(t) & ObjectFlags.Anonymous),
|
|
542
|
+
low: t => !!(getObjectFlags(t) & ObjectFlags.Anonymous)
|
|
543
|
+
}
|
|
544
|
+
];
|
|
545
|
+
let good = removeLowPriorityInferences(inferences, priorities);
|
|
546
|
+
const anons = good.filter(i => getObjectFlags(i) & ObjectFlags.Anonymous);
|
|
547
|
+
if (anons.length) {
|
|
548
|
+
good = good.filter(i => !(getObjectFlags(i) & ObjectFlags.Anonymous));
|
|
549
|
+
good.push(combineAnonymousTypes(anons));
|
|
550
|
+
}
|
|
551
|
+
return checker.getWidenedType(checker.getUnionType(good.map(checker.getBaseTypeOfLiteralType), UnionReduction.Subtype));
|
|
552
|
+
}
|
|
553
|
+
// Na tag, também as construct signatures dos tipos (CK-02).
|
|
554
|
+
function combineAnonymousTypes(anons) {
|
|
555
|
+
if (anons.length === 1) {
|
|
556
|
+
return anons[0];
|
|
557
|
+
}
|
|
558
|
+
const calls = [];
|
|
559
|
+
const stringIndices = [];
|
|
560
|
+
const numberIndices = [];
|
|
561
|
+
let stringIndexReadonly = false;
|
|
562
|
+
let numberIndexReadonly = false;
|
|
563
|
+
const props = createMultiMap();
|
|
564
|
+
for (const anon of anons) {
|
|
565
|
+
for (const p of checker.getPropertiesOfType(anon)) {
|
|
566
|
+
props.add(p.name, checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration));
|
|
567
|
+
}
|
|
568
|
+
calls.push(...checker.getSignaturesOfType(anon));
|
|
569
|
+
if (anon.stringIndexInfo) {
|
|
570
|
+
stringIndices.push(anon.stringIndexInfo.type);
|
|
571
|
+
stringIndexReadonly = stringIndexReadonly || anon.stringIndexInfo.isReadonly;
|
|
572
|
+
}
|
|
573
|
+
if (anon.numberIndexInfo) {
|
|
574
|
+
numberIndices.push(anon.numberIndexInfo.type);
|
|
575
|
+
numberIndexReadonly = numberIndexReadonly || anon.numberIndexInfo.isReadonly;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
const members = mapEntries(props, (name, types) => {
|
|
579
|
+
const isOptional = types.length < anons.length ? SymbolFlags.Optional : 0;
|
|
580
|
+
const s = checker.createSymbol(SymbolFlags.Property | isOptional, name);
|
|
581
|
+
s.type = checker.getUnionType(types);
|
|
582
|
+
return [name, s];
|
|
583
|
+
});
|
|
584
|
+
return checker.createAnonymousType(anons[0].symbol, members, calls, stringIndices.length ? checker.createIndexInfo(checker.getUnionType(stringIndices), stringIndexReadonly) : undefined, numberIndices.length ? checker.createIndexInfo(checker.getUnionType(numberIndices), numberIndexReadonly) : undefined);
|
|
585
|
+
}
|
|
586
|
+
function inferTypes(usage) {
|
|
587
|
+
const types = [];
|
|
588
|
+
if (usage.isNumber) {
|
|
589
|
+
types.push(checker.getNumberType());
|
|
590
|
+
}
|
|
591
|
+
if (usage.isString) {
|
|
592
|
+
types.push(checker.getStringType());
|
|
593
|
+
}
|
|
594
|
+
if (usage.isNumberOrString) {
|
|
595
|
+
types.push(checker.getUnionType([checker.getStringType(), checker.getNumberType()]));
|
|
596
|
+
}
|
|
597
|
+
if (usage.numberIndex) {
|
|
598
|
+
types.push(checker.createArrayType(combineFromUsage(usage.numberIndex)));
|
|
599
|
+
}
|
|
600
|
+
// Na tag, também as chamadas com `new` (CK-02).
|
|
601
|
+
if (usage.properties?.size || usage.calls?.length || usage.stringIndex) {
|
|
602
|
+
types.push(inferStructuralType(usage));
|
|
603
|
+
}
|
|
604
|
+
types.push(...(usage.candidateTypes || []).map(t => checker.getBaseTypeOfLiteralType(t)));
|
|
605
|
+
types.push(...inferNamedTypesFromProperties(usage));
|
|
606
|
+
return types;
|
|
607
|
+
}
|
|
608
|
+
// Na tag, também a construct signature das chamadas com `new` (CK-02).
|
|
609
|
+
function inferStructuralType(usage) {
|
|
610
|
+
const members = createUnderscoreEscapedMap();
|
|
611
|
+
if (usage.properties) {
|
|
612
|
+
usage.properties.forEach((u, name) => {
|
|
613
|
+
const symbol = checker.createSymbol(SymbolFlags.Property, name);
|
|
614
|
+
symbol.type = combineFromUsage(u);
|
|
615
|
+
members.set(name, symbol);
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
const callSignatures = usage.calls ? [getSignatureFromCalls(usage.calls)] : [];
|
|
619
|
+
const stringIndexInfo = usage.stringIndex && checker.createIndexInfo(combineFromUsage(usage.stringIndex), /*isReadonly*/ false);
|
|
620
|
+
return checker.createAnonymousType(/*symbol*/ undefined, members, callSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined);
|
|
621
|
+
}
|
|
622
|
+
function inferNamedTypesFromProperties(usage) {
|
|
623
|
+
if (!usage.properties || !usage.properties.size)
|
|
624
|
+
return [];
|
|
625
|
+
const types = builtins.filter(t => allPropertiesAreAssignableToUsage(t, usage));
|
|
626
|
+
if (0 < types.length && types.length < 3) {
|
|
627
|
+
return types.map(t => inferInstantiationFromUsage(t, usage));
|
|
628
|
+
}
|
|
629
|
+
return [];
|
|
630
|
+
}
|
|
631
|
+
function allPropertiesAreAssignableToUsage(type, usage) {
|
|
632
|
+
if (!usage.properties)
|
|
633
|
+
return false;
|
|
634
|
+
return !forEachEntry(usage.properties, (propUsage, name) => {
|
|
635
|
+
const source = checker.getTypeOfPropertyOfType(type, name);
|
|
636
|
+
if (!source) {
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
if (propUsage.calls) {
|
|
640
|
+
const sigs = checker.getSignaturesOfType(source);
|
|
641
|
+
return !sigs.length || !checker.isTypeAssignableTo(source, getFunctionFromCalls(propUsage.calls));
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
return !checker.isTypeAssignableTo(source, combineFromUsage(propUsage));
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* inference is limited to
|
|
650
|
+
* 1. generic types with a single parameter
|
|
651
|
+
* 2. inference to/from calls with a single signature
|
|
652
|
+
*/
|
|
653
|
+
function inferInstantiationFromUsage(type, usage) {
|
|
654
|
+
if (!(getObjectFlags(type) & ObjectFlags.Reference) || !usage.properties) {
|
|
655
|
+
return type;
|
|
656
|
+
}
|
|
657
|
+
const generic = type.target;
|
|
658
|
+
const singleTypeParameter = singleOrUndefined(generic.typeParameters);
|
|
659
|
+
if (!singleTypeParameter)
|
|
660
|
+
return type;
|
|
661
|
+
const types = [];
|
|
662
|
+
usage.properties.forEach((propUsage, name) => {
|
|
663
|
+
const genericPropertyType = checker.getTypeOfPropertyOfType(generic, name);
|
|
664
|
+
Debug.assert(!!genericPropertyType, "generic should have all the properties of its reference.");
|
|
665
|
+
types.push(...inferTypeParameters(genericPropertyType, combineFromUsage(propUsage), singleTypeParameter));
|
|
666
|
+
});
|
|
667
|
+
return builtinConstructors[type.symbol.escapedName](combineTypes(types));
|
|
668
|
+
}
|
|
669
|
+
function inferTypeParameters(genericType, usageType, typeParameter) {
|
|
670
|
+
if (genericType === typeParameter) {
|
|
671
|
+
return [usageType];
|
|
672
|
+
}
|
|
673
|
+
else if (genericType.flags & TypeFlags.UnionOrIntersection) {
|
|
674
|
+
return flatMap(genericType.types, t => inferTypeParameters(t, usageType, typeParameter));
|
|
675
|
+
}
|
|
676
|
+
else if (getObjectFlags(genericType) & ObjectFlags.Reference && getObjectFlags(usageType) & ObjectFlags.Reference) {
|
|
677
|
+
// this is wrong because we need a reference to the targetType to, so we can check that it's also a reference
|
|
678
|
+
const genericArgs = checker.getTypeArguments(genericType);
|
|
679
|
+
const usageArgs = checker.getTypeArguments(usageType);
|
|
680
|
+
const types = [];
|
|
681
|
+
if (genericArgs && usageArgs) {
|
|
682
|
+
for (let i = 0; i < genericArgs.length; i++) {
|
|
683
|
+
if (usageArgs[i]) {
|
|
684
|
+
types.push(...inferTypeParameters(genericArgs[i], usageArgs[i], typeParameter));
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
return types;
|
|
689
|
+
}
|
|
690
|
+
const genericSigs = checker.getSignaturesOfType(genericType);
|
|
691
|
+
const usageSigs = checker.getSignaturesOfType(usageType);
|
|
692
|
+
if (genericSigs.length === 1 && usageSigs.length === 1) {
|
|
693
|
+
return inferFromSignatures(genericSigs[0], usageSigs[0], typeParameter);
|
|
694
|
+
}
|
|
695
|
+
return [];
|
|
696
|
+
}
|
|
697
|
+
function inferFromSignatures(genericSig, usageSig, typeParameter) {
|
|
698
|
+
const types = [];
|
|
699
|
+
for (let i = 0; i < genericSig.parameters.length; i++) {
|
|
700
|
+
const genericParam = genericSig.parameters[i];
|
|
701
|
+
const usageParam = usageSig.parameters[i];
|
|
702
|
+
const isRest = genericSig.declaration && isRestParameter(genericSig.declaration.parameters[i]);
|
|
703
|
+
if (!usageParam) {
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
let genericParamType = checker.getTypeOfSymbolAtLocation(genericParam, genericParam.valueDeclaration);
|
|
707
|
+
const elementType = isRest && checker.getElementTypeOfArrayType(genericParamType);
|
|
708
|
+
if (elementType) {
|
|
709
|
+
genericParamType = elementType;
|
|
710
|
+
}
|
|
711
|
+
const targetType = usageParam.type || checker.getTypeOfSymbolAtLocation(usageParam, usageParam.valueDeclaration);
|
|
712
|
+
types.push(...inferTypeParameters(genericParamType, targetType, typeParameter));
|
|
713
|
+
}
|
|
714
|
+
const genericReturn = checker.getReturnTypeOfSignature(genericSig);
|
|
715
|
+
const usageReturn = checker.getReturnTypeOfSignature(usageSig);
|
|
716
|
+
types.push(...inferTypeParameters(genericReturn, usageReturn, typeParameter));
|
|
717
|
+
return types;
|
|
718
|
+
}
|
|
719
|
+
function getFunctionFromCalls(calls) {
|
|
720
|
+
return checker.createAnonymousType(/*symbol*/ undefined, createSymbolTable(), [getSignatureFromCalls(calls)], /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined);
|
|
721
|
+
}
|
|
722
|
+
function getSignatureFromCalls(calls) {
|
|
723
|
+
const parameters = [];
|
|
724
|
+
const length = Math.max(...calls.map(c => c.argumentTypes.length));
|
|
725
|
+
for (let i = 0; i < length; i++) {
|
|
726
|
+
const symbol = checker.createSymbol(SymbolFlags.FunctionScopedVariable, escapeLeadingUnderscores(`arg${i}`));
|
|
727
|
+
symbol.type = combineTypes(calls.map(call => call.argumentTypes[i] || checker.getUndefinedType()));
|
|
728
|
+
if (calls.some(call => call.argumentTypes[i] === undefined)) {
|
|
729
|
+
symbol.flags |= SymbolFlags.Optional;
|
|
730
|
+
}
|
|
731
|
+
parameters.push(symbol);
|
|
732
|
+
}
|
|
733
|
+
const returnType = combineFromUsage(combineUsages(calls.map(call => call.return_)));
|
|
734
|
+
return checker.createSignature(/*declaration*/ undefined, /*typeParameters*/ undefined, parameters, returnType, /*typePredicate*/ undefined, length, SignatureFlags.None);
|
|
735
|
+
}
|
|
736
|
+
function addCandidateType(usage, type) {
|
|
737
|
+
if (type && !(type.flags & TypeFlags.Any) && !(type.flags & TypeFlags.Never)) {
|
|
738
|
+
(usage.candidateTypes || (usage.candidateTypes = [])).push(type);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
// Na tag, aqui vinha o `addCandidateThisType` (CK-02).
|
|
742
|
+
}
|