@zzzen/pyright-internal 1.2.0-dev.20230507 → 1.2.0-dev.20230521
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/dist/analyzer/analyzerFileInfo.d.ts +1 -0
- package/dist/analyzer/analyzerFileInfo.js +4 -3
- package/dist/analyzer/analyzerFileInfo.js.map +1 -1
- package/dist/analyzer/backgroundAnalysisProgram.d.ts +17 -15
- package/dist/analyzer/backgroundAnalysisProgram.js +43 -53
- package/dist/analyzer/backgroundAnalysisProgram.js.map +1 -1
- package/dist/analyzer/binder.d.ts +0 -2
- package/dist/analyzer/binder.js +2 -20
- package/dist/analyzer/binder.js.map +1 -1
- package/dist/analyzer/checker.d.ts +1 -1
- package/dist/analyzer/checker.js +97 -29
- package/dist/analyzer/checker.js.map +1 -1
- package/dist/analyzer/constraintSolver.js +14 -15
- package/dist/analyzer/constraintSolver.js.map +1 -1
- package/dist/analyzer/constructorTransform.js +5 -1
- package/dist/analyzer/constructorTransform.js.map +1 -1
- package/dist/analyzer/constructors.js +248 -189
- package/dist/analyzer/constructors.js.map +1 -1
- package/dist/analyzer/dataClasses.js +5 -2
- package/dist/analyzer/dataClasses.js.map +1 -1
- package/dist/analyzer/declarationUtils.js +1 -0
- package/dist/analyzer/declarationUtils.js.map +1 -1
- package/dist/analyzer/docStringConversion.js +1 -1
- package/dist/analyzer/docStringConversion.js.map +1 -1
- package/dist/analyzer/enums.js +8 -0
- package/dist/analyzer/enums.js.map +1 -1
- package/dist/analyzer/importResolver.d.ts +4 -4
- package/dist/analyzer/importResolver.js +93 -69
- package/dist/analyzer/importResolver.js.map +1 -1
- package/dist/analyzer/importResult.d.ts +2 -2
- package/dist/analyzer/importStatementUtils.js +2 -2
- package/dist/analyzer/importStatementUtils.js.map +1 -1
- package/dist/analyzer/namedTuples.js +2 -5
- package/dist/analyzer/namedTuples.js.map +1 -1
- package/dist/analyzer/packageTypeVerifier.js +1 -1
- package/dist/analyzer/packageTypeVerifier.js.map +1 -1
- package/dist/analyzer/parseTreeUtils.js +2 -34
- package/dist/analyzer/parseTreeUtils.js.map +1 -1
- package/dist/analyzer/parseTreeWalker.js +2 -2
- package/dist/analyzer/parseTreeWalker.js.map +1 -1
- package/dist/analyzer/patternMatching.js +1 -0
- package/dist/analyzer/patternMatching.js.map +1 -1
- package/dist/analyzer/program.d.ts +18 -34
- package/dist/analyzer/program.js +57 -259
- package/dist/analyzer/program.js.map +1 -1
- package/dist/analyzer/protocols.js +4 -2
- package/dist/analyzer/protocols.js.map +1 -1
- package/dist/analyzer/service.d.ts +8 -16
- package/dist/analyzer/service.js +33 -47
- package/dist/analyzer/service.js.map +1 -1
- package/dist/analyzer/sourceFile.d.ts +1 -15
- package/dist/analyzer/sourceFile.js +14 -96
- package/dist/analyzer/sourceFile.js.map +1 -1
- package/dist/analyzer/sourceMapper.js +1 -1
- package/dist/analyzer/sourceMapper.js.map +1 -1
- package/dist/analyzer/symbol.d.ts +3 -1
- package/dist/analyzer/symbol.js +5 -0
- package/dist/analyzer/symbol.js.map +1 -1
- package/dist/analyzer/typeDocStringUtils.js +1 -1
- package/dist/analyzer/typeDocStringUtils.js.map +1 -1
- package/dist/analyzer/typeEvaluator.d.ts +2 -2
- package/dist/analyzer/typeEvaluator.js +495 -196
- package/dist/analyzer/typeEvaluator.js.map +1 -1
- package/dist/analyzer/typeEvaluatorTypes.d.ts +7 -2
- package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
- package/dist/analyzer/typeGuards.js +1 -0
- package/dist/analyzer/typeGuards.js.map +1 -1
- package/dist/analyzer/typePrinter.d.ts +3 -3
- package/dist/analyzer/typePrinter.js +255 -101
- package/dist/analyzer/typePrinter.js.map +1 -1
- package/dist/analyzer/typeUtils.d.ts +12 -7
- package/dist/analyzer/typeUtils.js +174 -49
- package/dist/analyzer/typeUtils.js.map +1 -1
- package/dist/analyzer/typeVarContext.d.ts +1 -2
- package/dist/analyzer/typeVarContext.js +16 -34
- package/dist/analyzer/typeVarContext.js.map +1 -1
- package/dist/analyzer/typedDicts.js +138 -41
- package/dist/analyzer/typedDicts.js.map +1 -1
- package/dist/analyzer/types.d.ts +10 -3
- package/dist/analyzer/types.js +32 -16
- package/dist/analyzer/types.js.map +1 -1
- package/dist/backgroundAnalysisBase.d.ts +25 -19
- package/dist/backgroundAnalysisBase.js +161 -115
- package/dist/backgroundAnalysisBase.js.map +1 -1
- package/dist/backgroundThreadBase.d.ts +1 -1
- package/dist/backgroundThreadBase.js +1 -1
- package/dist/backgroundThreadBase.js.map +1 -1
- package/dist/commands/dumpFileDebugInfoCommand.js +3 -4
- package/dist/commands/dumpFileDebugInfoCommand.js.map +1 -1
- package/dist/common/configOptions.js +1 -1
- package/dist/common/configOptions.js.map +1 -1
- package/dist/common/extensibility.d.ts +26 -5
- package/dist/common/extensibility.js.map +1 -1
- package/dist/common/logTracker.d.ts +2 -0
- package/dist/common/logTracker.js +8 -1
- package/dist/common/logTracker.js.map +1 -1
- package/dist/common/lspUtils.d.ts +4 -1
- package/dist/common/lspUtils.js +38 -1
- package/dist/common/lspUtils.js.map +1 -1
- package/dist/common/pythonVersion.d.ts +2 -1
- package/dist/common/pythonVersion.js +1 -0
- package/dist/common/pythonVersion.js.map +1 -1
- package/dist/common/textRange.js +1 -1
- package/dist/common/textRange.js.map +1 -1
- package/dist/common/workspaceEditUtils.d.ts +3 -3
- package/dist/common/workspaceEditUtils.js +15 -17
- package/dist/common/workspaceEditUtils.js.map +1 -1
- package/dist/languageServerBase.d.ts +2 -5
- package/dist/languageServerBase.js +35 -62
- package/dist/languageServerBase.js.map +1 -1
- package/dist/languageService/autoImporter.d.ts +51 -52
- package/dist/languageService/autoImporter.js +126 -211
- package/dist/languageService/autoImporter.js.map +1 -1
- package/dist/languageService/callHierarchyProvider.js +8 -33
- package/dist/languageService/callHierarchyProvider.js.map +1 -1
- package/dist/languageService/completionProvider.d.ts +42 -81
- package/dist/languageService/completionProvider.js +608 -841
- package/dist/languageService/completionProvider.js.map +1 -1
- package/dist/languageService/documentSymbolCollector.d.ts +2 -2
- package/dist/languageService/documentSymbolCollector.js +40 -30
- package/dist/languageService/documentSymbolCollector.js.map +1 -1
- package/dist/languageService/documentSymbolProvider.d.ts +13 -35
- package/dist/languageService/documentSymbolProvider.js +52 -264
- package/dist/languageService/documentSymbolProvider.js.map +1 -1
- package/dist/languageService/hoverProvider.d.ts +1 -3
- package/dist/languageService/hoverProvider.js +11 -97
- package/dist/languageService/hoverProvider.js.map +1 -1
- package/dist/languageService/referencesProvider.d.ts +3 -3
- package/dist/languageService/referencesProvider.js +6 -8
- package/dist/languageService/referencesProvider.js.map +1 -1
- package/dist/languageService/renameProvider.d.ts +0 -1
- package/dist/languageService/renameProvider.js +2 -6
- package/dist/languageService/renameProvider.js.map +1 -1
- package/dist/languageService/signatureHelpProvider.js +1 -1
- package/dist/languageService/signatureHelpProvider.js.map +1 -1
- package/dist/languageService/symbolIndexer.d.ts +23 -0
- package/dist/languageService/symbolIndexer.js +105 -0
- package/dist/languageService/symbolIndexer.js.map +1 -0
- package/dist/languageService/tooltipUtils.d.ts +8 -1
- package/dist/languageService/tooltipUtils.js +102 -1
- package/dist/languageService/tooltipUtils.js.map +1 -1
- package/dist/languageService/workspaceSymbolProvider.d.ts +17 -0
- package/dist/languageService/workspaceSymbolProvider.js +133 -0
- package/dist/languageService/workspaceSymbolProvider.js.map +1 -0
- package/dist/localization/localize.d.ts +38 -4
- package/dist/localization/localize.js +21 -4
- package/dist/localization/localize.js.map +1 -1
- package/dist/localization/package.nls.en-us.json +23 -6
- package/dist/parser/parseNodes.d.ts +8 -8
- package/dist/parser/parseNodes.js +20 -10
- package/dist/parser/parseNodes.js.map +1 -1
- package/dist/parser/parser.d.ts +3 -3
- package/dist/parser/parser.js +136 -159
- package/dist/parser/parser.js.map +1 -1
- package/dist/parser/stringTokenUtils.d.ts +3 -13
- package/dist/parser/stringTokenUtils.js +8 -181
- package/dist/parser/stringTokenUtils.js.map +1 -1
- package/dist/parser/tokenizer.d.ts +3 -0
- package/dist/parser/tokenizer.js +211 -24
- package/dist/parser/tokenizer.js.map +1 -1
- package/dist/parser/tokenizerTypes.d.ts +31 -1
- package/dist/parser/tokenizerTypes.js +51 -1
- package/dist/parser/tokenizerTypes.js.map +1 -1
- package/dist/pyright.js +26 -4
- package/dist/pyright.js.map +1 -1
- package/dist/readonlyAugmentedFileSystem.js +1 -1
- package/dist/readonlyAugmentedFileSystem.js.map +1 -1
- package/dist/tests/chainedSourceFiles.test.js +15 -20
- package/dist/tests/chainedSourceFiles.test.js.map +1 -1
- package/dist/tests/checker.test.js +14 -0
- package/dist/tests/checker.test.js.map +1 -1
- package/dist/tests/completions.test.js +11 -236
- package/dist/tests/completions.test.js.map +1 -1
- package/dist/tests/docStringConversion.test.js +36 -2
- package/dist/tests/docStringConversion.test.js.map +1 -1
- package/dist/tests/fourslash/completions.override2.fourslash.js +1 -16
- package/dist/tests/fourslash/completions.override2.fourslash.js.map +1 -1
- package/dist/tests/harness/fourslash/testLanguageService.js +1 -1
- package/dist/tests/harness/fourslash/testLanguageService.js.map +1 -1
- package/dist/tests/harness/fourslash/testState.d.ts +14 -8
- package/dist/tests/harness/fourslash/testState.js +27 -37
- package/dist/tests/harness/fourslash/testState.js.map +1 -1
- package/dist/tests/importResolver.test.js +84 -4
- package/dist/tests/importResolver.test.js.map +1 -1
- package/dist/tests/textRange.test.js +45 -0
- package/dist/tests/textRange.test.js.map +1 -0
- package/dist/tests/tokenizer.test.js +272 -58
- package/dist/tests/tokenizer.test.js.map +1 -1
- package/dist/tests/typeEvaluator2.test.js +16 -0
- package/dist/tests/typeEvaluator2.test.js.map +1 -1
- package/dist/tests/typeEvaluator3.test.js +14 -0
- package/dist/tests/typeEvaluator3.test.js.map +1 -1
- package/dist/tests/typeEvaluator4.test.js +7 -2
- package/dist/tests/typeEvaluator4.test.js.map +1 -1
- package/dist/tests/typeEvaluator5.test.js +29 -9
- package/dist/tests/typeEvaluator5.test.js.map +1 -1
- package/dist/tests/workspaceEditUtils.test.js +15 -10
- package/dist/tests/workspaceEditUtils.test.js.map +1 -1
- package/dist/workspaceFactory.js +3 -5
- package/dist/workspaceFactory.js.map +1 -1
- package/package.json +1 -1
- package/dist/languageService/importAdder.d.ts +0 -40
- package/dist/languageService/importAdder.js +0 -388
- package/dist/languageService/importAdder.js.map +0 -1
- package/dist/tests/fourslash/completions.commitChars.fourslash.d.ts +0 -1
- package/dist/tests/fourslash/completions.commitChars.fourslash.js +0 -81
- package/dist/tests/fourslash/completions.commitChars.fourslash.js.map +0 -1
- package/dist/tests/importAdder.test.js +0 -1325
- package/dist/tests/importAdder.test.js.map +0 -1
- /package/dist/tests/{importAdder.test.d.ts → textRange.test.d.ts} +0 -0
@@ -37,7 +37,6 @@ const docStringConversion_1 = require("../analyzer/docStringConversion");
|
|
37
37
|
const parameterUtils_1 = require("../analyzer/parameterUtils");
|
38
38
|
const ParseTreeUtils = __importStar(require("../analyzer/parseTreeUtils"));
|
39
39
|
const parseTreeUtils_1 = require("../analyzer/parseTreeUtils");
|
40
|
-
const pythonPathUtils_1 = require("../analyzer/pythonPathUtils");
|
41
40
|
const scopeUtils_1 = require("../analyzer/scopeUtils");
|
42
41
|
const sourceMapper_1 = require("../analyzer/sourceMapper");
|
43
42
|
const SymbolNameUtils = __importStar(require("../analyzer/symbolNameUtils"));
|
@@ -52,19 +51,15 @@ const collectionUtils_1 = require("../common/collectionUtils");
|
|
52
51
|
const debug = __importStar(require("../common/debug"));
|
53
52
|
const debug_1 = require("../common/debug");
|
54
53
|
const lspUtils_1 = require("../common/lspUtils");
|
55
|
-
const pathUtils_1 = require("../common/pathUtils");
|
56
54
|
const positionUtils_1 = require("../common/positionUtils");
|
57
55
|
const pythonVersion_1 = require("../common/pythonVersion");
|
58
56
|
const StringUtils = __importStar(require("../common/stringUtils"));
|
59
57
|
const textRange_1 = require("../common/textRange");
|
60
|
-
const textRange_2 = require("../common/textRange");
|
61
|
-
const timing_1 = require("../common/timing");
|
62
58
|
const workspaceEditUtils_1 = require("../common/workspaceEditUtils");
|
63
59
|
const parseNodes_1 = require("../parser/parseNodes");
|
64
60
|
const autoImporter_1 = require("./autoImporter");
|
65
61
|
const completionProviderUtils_1 = require("./completionProviderUtils");
|
66
62
|
const documentSymbolCollector_1 = require("./documentSymbolCollector");
|
67
|
-
const importAdder_1 = require("./importAdder");
|
68
63
|
const tooltipUtils_1 = require("./tooltipUtils");
|
69
64
|
var Keywords;
|
70
65
|
(function (Keywords) {
|
@@ -158,38 +153,455 @@ const similarityLimit = 0.25;
|
|
158
153
|
// We'll remember this many completions in the MRU list.
|
159
154
|
const maxRecentCompletions = 128;
|
160
155
|
class CompletionProvider {
|
161
|
-
constructor(
|
162
|
-
this.
|
156
|
+
constructor(program, _workspacePath, filePath, position, options, cancellationToken) {
|
157
|
+
this.program = program;
|
163
158
|
this._workspacePath = _workspacePath;
|
164
|
-
this.
|
165
|
-
this.
|
166
|
-
this.
|
167
|
-
this.
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
this.
|
172
|
-
this.
|
173
|
-
this.
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
159
|
+
this.filePath = filePath;
|
160
|
+
this.position = position;
|
161
|
+
this.options = options;
|
162
|
+
this.cancellationToken = cancellationToken;
|
163
|
+
// Indicates whether invocation position is inside of string literal
|
164
|
+
// token or an f-string expression.
|
165
|
+
this._stringLiteralContainer = undefined;
|
166
|
+
this.execEnv = this.configOptions.findExecEnvironment(this.filePath);
|
167
|
+
this.parseResults = this.program.getParseResults(this.filePath);
|
168
|
+
this.sourceMapper = this.program.getSourceMapper(this.filePath, this.cancellationToken, /* mapCompiled */ true);
|
169
|
+
}
|
170
|
+
getCompletions() {
|
171
|
+
if (!this.program.getSourceFileInfo(this.filePath)) {
|
172
|
+
return null;
|
173
|
+
}
|
174
|
+
const completionMap = this._getCompletions();
|
175
|
+
return vscode_languageserver_1.CompletionList.create(completionMap === null || completionMap === void 0 ? void 0 : completionMap.toArray());
|
176
|
+
}
|
177
|
+
// When the user selects a completion, this callback is invoked,
|
178
|
+
// allowing us to record what was selected. This allows us to
|
179
|
+
// build our MRU cache so we can better predict entries.
|
180
|
+
resolveCompletionItem(completionItem) {
|
181
|
+
(0, cancellationUtils_1.throwIfCancellationRequested)(this.cancellationToken);
|
182
|
+
const completionItemData = (0, lspUtils_1.fromLSPAny)(completionItem.data);
|
183
|
+
const label = completionItem.label;
|
184
|
+
let autoImportText = '';
|
185
|
+
if (completionItemData.autoImportText) {
|
186
|
+
autoImportText = completionItemData.autoImportText;
|
187
|
+
}
|
188
|
+
const curIndex = CompletionProvider._mostRecentCompletions.findIndex((item) => item.label === label && item.autoImportText === autoImportText);
|
189
|
+
if (curIndex > 0) {
|
190
|
+
// If there's an existing entry with the same name that's not at the
|
191
|
+
// beginning of the array, remove it.
|
192
|
+
CompletionProvider._mostRecentCompletions = CompletionProvider._mostRecentCompletions.splice(curIndex, 1);
|
193
|
+
}
|
194
|
+
if (curIndex !== 0) {
|
195
|
+
// Add to the start of the array.
|
196
|
+
CompletionProvider._mostRecentCompletions.unshift({ label, autoImportText });
|
197
|
+
}
|
198
|
+
if (CompletionProvider._mostRecentCompletions.length > maxRecentCompletions) {
|
199
|
+
// Prevent the MRU list from growing indefinitely.
|
200
|
+
CompletionProvider._mostRecentCompletions.pop();
|
201
|
+
}
|
202
|
+
if (!completionItemData.symbolLabel) {
|
203
|
+
return;
|
204
|
+
}
|
205
|
+
if (completionItemData.modulePath) {
|
206
|
+
const documentation = (0, typeDocStringUtils_1.getModuleDocStringFromPaths)([completionItemData.modulePath], this.sourceMapper);
|
207
|
+
if (!documentation) {
|
208
|
+
return;
|
209
|
+
}
|
210
|
+
if (this.options.format === vscode_languageserver_1.MarkupKind.Markdown) {
|
211
|
+
const markdownString = (0, docStringConversion_1.convertDocStringToMarkdown)(documentation);
|
212
|
+
completionItem.documentation = {
|
213
|
+
kind: vscode_languageserver_1.MarkupKind.Markdown,
|
214
|
+
value: markdownString,
|
215
|
+
};
|
216
|
+
}
|
217
|
+
else if (this.options.format === vscode_languageserver_1.MarkupKind.PlainText) {
|
218
|
+
const plainTextString = (0, docStringConversion_1.convertDocStringToPlainText)(documentation);
|
219
|
+
completionItem.documentation = {
|
220
|
+
kind: vscode_languageserver_1.MarkupKind.PlainText,
|
221
|
+
value: plainTextString,
|
222
|
+
};
|
223
|
+
}
|
224
|
+
return;
|
225
|
+
}
|
226
|
+
this._itemToResolve = completionItem;
|
227
|
+
if (!completionItemData.autoImportText) {
|
228
|
+
// Rerun the completion lookup. It will fill in additional information
|
229
|
+
// about the item to be resolved. We'll ignore the rest of the returned
|
230
|
+
// list. This is a bit wasteful, but all of that information should be
|
231
|
+
// cached, so it's not as bad as it might seem.
|
232
|
+
this.getCompletions();
|
233
|
+
}
|
234
|
+
else if (!completionItem.additionalTextEdits) {
|
235
|
+
const completionMap = new CompletionMap();
|
236
|
+
this.addAutoImportCompletions(completionItemData.symbolLabel,
|
237
|
+
/* similarityLimit */ 1,
|
238
|
+
/* lazyEdit */ false, completionMap);
|
239
|
+
}
|
240
|
+
}
|
241
|
+
get evaluator() {
|
242
|
+
return this.program.evaluator;
|
243
|
+
}
|
244
|
+
get importResolver() {
|
245
|
+
return this.program.importResolver;
|
246
|
+
}
|
247
|
+
get configOptions() {
|
248
|
+
return this.program.configOptions;
|
249
|
+
}
|
250
|
+
isSimpleDefault(node) {
|
251
|
+
switch (node.nodeType) {
|
252
|
+
case 40 /* Number */:
|
253
|
+
case 11 /* Constant */:
|
254
|
+
case 35 /* MemberAccess */:
|
255
|
+
return true;
|
256
|
+
case 49 /* String */:
|
257
|
+
return (node.token.flags & 64 /* Format */) === 0;
|
258
|
+
case 48 /* StringList */:
|
259
|
+
return node.strings.every(this.isSimpleDefault);
|
260
|
+
case 55 /* UnaryOperation */:
|
261
|
+
return this.isSimpleDefault(node.expression);
|
262
|
+
case 7 /* BinaryOperation */:
|
263
|
+
return this.isSimpleDefault(node.leftExpression) && this.isSimpleDefault(node.rightExpression);
|
264
|
+
default:
|
265
|
+
return false;
|
266
|
+
}
|
267
|
+
}
|
268
|
+
getMethodOverrideCompletions(priorWord, partialName, decorators) {
|
269
|
+
var _a, _b;
|
270
|
+
const enclosingClass = ParseTreeUtils.getEnclosingClass(partialName, /* stopAtFunction */ true);
|
271
|
+
if (!enclosingClass) {
|
272
|
+
return undefined;
|
273
|
+
}
|
274
|
+
const classResults = this.evaluator.getTypeOfClass(enclosingClass);
|
275
|
+
if (!classResults) {
|
276
|
+
return undefined;
|
277
|
+
}
|
278
|
+
const symbolTable = new Map();
|
279
|
+
for (let i = 1; i < classResults.classType.details.mro.length; i++) {
|
280
|
+
const mroClass = classResults.classType.details.mro[i];
|
281
|
+
if ((0, types_1.isInstantiableClass)(mroClass)) {
|
282
|
+
(0, typeUtils_1.getMembersForClass)(mroClass, symbolTable, /* includeInstanceVars */ false);
|
283
|
+
}
|
284
|
+
}
|
285
|
+
const staticmethod = (_a = decorators === null || decorators === void 0 ? void 0 : decorators.some((d) => this.checkDecorator(d, 'staticmethod'))) !== null && _a !== void 0 ? _a : false;
|
286
|
+
const classmethod = (_b = decorators === null || decorators === void 0 ? void 0 : decorators.some((d) => this.checkDecorator(d, 'classmethod'))) !== null && _b !== void 0 ? _b : false;
|
287
|
+
const completionMap = new CompletionMap();
|
288
|
+
symbolTable.forEach((symbol, name) => {
|
289
|
+
var _a;
|
290
|
+
let decl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(symbol);
|
291
|
+
if (decl && decl.type === 5 /* Function */) {
|
292
|
+
if (StringUtils.isPatternInSymbol(partialName.value, name)) {
|
293
|
+
const declaredType = (_a = this.evaluator.getTypeForDeclaration(decl)) === null || _a === void 0 ? void 0 : _a.type;
|
294
|
+
if (!declaredType) {
|
295
|
+
return;
|
296
|
+
}
|
297
|
+
let isProperty = (0, types_1.isClassInstance)(declaredType) && types_1.ClassType.isPropertyClass(declaredType);
|
298
|
+
if (SymbolNameUtils.isDunderName(name)) {
|
299
|
+
// Don't offer suggestions for built-in properties like "__class__", etc.
|
300
|
+
isProperty = false;
|
301
|
+
}
|
302
|
+
if (!(0, types_1.isFunction)(declaredType) && !isProperty) {
|
303
|
+
return;
|
304
|
+
}
|
305
|
+
if (isProperty) {
|
306
|
+
// For properties, we should override the "getter", which is typically
|
307
|
+
// the first declaration.
|
308
|
+
const typedDecls = symbol.getTypedDeclarations();
|
309
|
+
if (typedDecls.length > 0 && typedDecls[0].type === 5 /* Function */) {
|
310
|
+
decl = typedDecls[0];
|
311
|
+
}
|
312
|
+
}
|
313
|
+
const isDeclaredStaticMethod = (0, types_1.isFunction)(declaredType) && types_1.FunctionType.isStaticMethod(declaredType);
|
314
|
+
// Special-case the "__init__subclass__" method because it's an implicit
|
315
|
+
// classmethod that the type evaluator flags as a real classmethod.
|
316
|
+
const isDeclaredClassMethod = (0, types_1.isFunction)(declaredType) &&
|
317
|
+
types_1.FunctionType.isClassMethod(declaredType) &&
|
318
|
+
name !== '__init_subclass__';
|
319
|
+
if (staticmethod !== isDeclaredStaticMethod || classmethod !== isDeclaredClassMethod) {
|
320
|
+
return;
|
321
|
+
}
|
322
|
+
const methodSignature = this._printMethodSignature(classResults.classType, decl);
|
323
|
+
let text;
|
324
|
+
if ((0, sourceMapper_1.isStubFile)(this.filePath)) {
|
325
|
+
text = `${methodSignature}: ...`;
|
326
|
+
}
|
327
|
+
else {
|
328
|
+
const methodBody = this.printOverriddenMethodBody(classResults.classType, isDeclaredStaticMethod, isProperty, decl);
|
329
|
+
text = `${methodSignature}:\n${methodBody}`;
|
330
|
+
}
|
331
|
+
const textEdit = this.createReplaceEdits(priorWord, partialName, text);
|
332
|
+
this.addSymbol(name, symbol, partialName.value, completionMap, {
|
333
|
+
// method signature already contains ()
|
334
|
+
funcParensDisabled: true,
|
335
|
+
edits: {
|
336
|
+
format: this.options.snippet ? vscode_languageserver_1.InsertTextFormat.Snippet : undefined,
|
337
|
+
textEdit,
|
338
|
+
},
|
339
|
+
});
|
340
|
+
}
|
341
|
+
}
|
342
|
+
});
|
343
|
+
return completionMap;
|
344
|
+
}
|
345
|
+
printOverriddenMethodBody(classType, isStaticMethod, isProperty, decl) {
|
346
|
+
let sb = this.parseResults.tokenizerOutput.predominantTabSequence;
|
347
|
+
if (classType.details.baseClasses.length === 1 &&
|
348
|
+
(0, types_1.isClass)(classType.details.baseClasses[0]) &&
|
349
|
+
classType.details.baseClasses[0].details.fullName === 'builtins.object') {
|
350
|
+
sb += this.options.snippet ? '${0:pass}' : 'pass';
|
351
|
+
return sb;
|
352
|
+
}
|
353
|
+
if (decl.node.parameters.length === 0) {
|
354
|
+
sb += this.options.snippet ? '${0:pass}' : 'pass';
|
355
|
+
return sb;
|
356
|
+
}
|
357
|
+
const parameters = getParameters(isStaticMethod ? decl.node.parameters : decl.node.parameters.slice(1));
|
358
|
+
if (decl.node.name.value !== '__init__') {
|
359
|
+
sb += 'return ';
|
360
|
+
}
|
361
|
+
if (decl.node.isAsync) {
|
362
|
+
sb += 'await ';
|
363
|
+
}
|
364
|
+
if (isProperty) {
|
365
|
+
return sb + `super().${decl.node.name.value}`;
|
366
|
+
}
|
367
|
+
return sb + `super().${decl.node.name.value}(${parameters.map(convertToString).join(', ')})`;
|
368
|
+
function getParameters(parameters) {
|
369
|
+
const results = [];
|
370
|
+
let sawKeywordOnlySeparator = false;
|
371
|
+
for (const parameter of parameters) {
|
372
|
+
if (parameter.name) {
|
373
|
+
results.push([
|
374
|
+
parameter,
|
375
|
+
parameter.category === 0 /* Simple */ && !!parameter.name && sawKeywordOnlySeparator,
|
376
|
+
]);
|
377
|
+
}
|
378
|
+
// All simple parameters after a `*` or `*args` parameter
|
379
|
+
// are considered keyword only.
|
380
|
+
if (parameter.category === 1 /* VarArgList */) {
|
381
|
+
sawKeywordOnlySeparator = true;
|
382
|
+
}
|
383
|
+
}
|
384
|
+
return results;
|
385
|
+
}
|
386
|
+
function convertToString(parameter) {
|
387
|
+
var _a;
|
388
|
+
const name = (_a = parameter[0].name) === null || _a === void 0 ? void 0 : _a.value;
|
389
|
+
if (parameter[0].category === 1 /* VarArgList */) {
|
390
|
+
return `*${name}`;
|
391
|
+
}
|
392
|
+
if (parameter[0].category === 2 /* VarArgDictionary */) {
|
393
|
+
return `**${name}`;
|
394
|
+
}
|
395
|
+
return parameter[1] ? `${name}=${name}` : name;
|
396
|
+
}
|
397
|
+
}
|
398
|
+
createReplaceEdits(priorWord, node, text) {
|
399
|
+
const replaceOrInsertEndChar = (node === null || node === void 0 ? void 0 : node.nodeType) === 38 /* Name */
|
400
|
+
? this.position.character - priorWord.length + node.value.length
|
401
|
+
: this.position.character;
|
402
|
+
const range = {
|
403
|
+
start: { line: this.position.line, character: this.position.character - priorWord.length },
|
404
|
+
end: { line: this.position.line, character: replaceOrInsertEndChar },
|
405
|
+
};
|
406
|
+
return vscode_languageserver_1.TextEdit.replace(range, text);
|
407
|
+
}
|
408
|
+
addSymbol(name, symbol, priorWord, completionMap, detail) {
|
409
|
+
var _a, _b, _c, _d;
|
410
|
+
let primaryDecl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(symbol);
|
411
|
+
if (!primaryDecl) {
|
412
|
+
const declarations = symbol.getDeclarations();
|
413
|
+
if (declarations.length > 0) {
|
414
|
+
primaryDecl = declarations[declarations.length - 1];
|
415
|
+
}
|
416
|
+
}
|
417
|
+
primaryDecl = primaryDecl
|
418
|
+
? (_a = this.evaluator.resolveAliasDeclaration(primaryDecl, /* resolveLocalNames */ true)) !== null && _a !== void 0 ? _a : primaryDecl
|
419
|
+
: undefined;
|
420
|
+
const autoImportText = detail.autoImportSource
|
421
|
+
? this._getAutoImportText(name, detail.autoImportSource, detail.autoImportAlias)
|
422
|
+
: undefined;
|
423
|
+
// Are we resolving a completion item? If so, see if this symbol
|
424
|
+
// is the one that we're trying to match.
|
425
|
+
if (this._itemToResolve) {
|
426
|
+
const completionItemData = (0, lspUtils_1.fromLSPAny)(this._itemToResolve.data);
|
427
|
+
if (completionItemData.symbolLabel !== name) {
|
428
|
+
// It's not what we are looking for.
|
429
|
+
return;
|
430
|
+
}
|
431
|
+
if (completionItemData.autoImportText) {
|
432
|
+
if (completionItemData.autoImportText === (autoImportText === null || autoImportText === void 0 ? void 0 : autoImportText.importText) &&
|
433
|
+
((_b = detail.edits) === null || _b === void 0 ? void 0 : _b.additionalTextEdits)) {
|
434
|
+
this._itemToResolve.additionalTextEdits = (0, workspaceEditUtils_1.convertToTextEdits)(detail.edits.additionalTextEdits);
|
435
|
+
}
|
436
|
+
return;
|
437
|
+
}
|
438
|
+
// This call can be expensive to perform on every completion item
|
439
|
+
// that we return, so we do it lazily in the "resolve" callback.
|
440
|
+
const type = this.evaluator.getEffectiveTypeOfSymbol(symbol);
|
441
|
+
if (!type) {
|
442
|
+
// Can't resolve. so bail out.
|
443
|
+
return;
|
444
|
+
}
|
445
|
+
const typeDetail = (0, completionProviderUtils_1.getTypeDetail)(this.evaluator, primaryDecl, type, name, detail, this.configOptions.functionSignatureDisplay);
|
446
|
+
const documentation = (0, tooltipUtils_1.getDocumentationPartsForTypeAndDecl)(this.sourceMapper, type, primaryDecl, this.evaluator, {
|
447
|
+
name,
|
448
|
+
symbol,
|
449
|
+
boundObjectOrClass: detail.boundObjectOrClass,
|
450
|
+
});
|
451
|
+
if (this.options.format === vscode_languageserver_1.MarkupKind.Markdown || this.options.format === vscode_languageserver_1.MarkupKind.PlainText) {
|
452
|
+
this._itemToResolve.documentation = (0, completionProviderUtils_1.getCompletionItemDocumentation)(typeDetail, documentation, this.options.format);
|
453
|
+
}
|
454
|
+
else {
|
455
|
+
(0, debug_1.fail)(`Unsupported markup type: ${this.options.format}`);
|
456
|
+
}
|
457
|
+
// Bail out. We don't need to add items to completion.
|
458
|
+
return;
|
459
|
+
}
|
460
|
+
if (primaryDecl) {
|
461
|
+
let itemKind = this._convertDeclarationTypeToItemKind(primaryDecl);
|
462
|
+
// Handle enum members specially. Enum members normally look like
|
463
|
+
// variables, but the are declared using assignment expressions
|
464
|
+
// within an enum class.
|
465
|
+
if (primaryDecl.type === 1 /* Variable */ &&
|
466
|
+
detail.boundObjectOrClass &&
|
467
|
+
(0, types_1.isInstantiableClass)(detail.boundObjectOrClass) &&
|
468
|
+
types_1.ClassType.isEnumClass(detail.boundObjectOrClass) &&
|
469
|
+
((_c = primaryDecl.node.parent) === null || _c === void 0 ? void 0 : _c.nodeType) === 3 /* Assignment */) {
|
470
|
+
itemKind = vscode_languageserver_1.CompletionItemKind.EnumMember;
|
471
|
+
}
|
472
|
+
this._addNameToCompletions((_d = detail.autoImportAlias) !== null && _d !== void 0 ? _d : name, itemKind, priorWord, completionMap, {
|
473
|
+
autoImportText,
|
474
|
+
extraCommitChars: detail.extraCommitChars,
|
475
|
+
funcParensDisabled: detail.funcParensDisabled,
|
476
|
+
edits: detail.edits,
|
477
|
+
});
|
478
|
+
}
|
479
|
+
else {
|
480
|
+
// Does the symbol have no declaration but instead has a synthesized type?
|
481
|
+
const synthesizedType = symbol.getSynthesizedType();
|
482
|
+
if (synthesizedType) {
|
483
|
+
const itemKind = this._convertTypeToItemKind(synthesizedType);
|
484
|
+
this._addNameToCompletions(name, itemKind, priorWord, completionMap, {
|
485
|
+
extraCommitChars: detail.extraCommitChars,
|
486
|
+
funcParensDisabled: detail.funcParensDisabled,
|
487
|
+
edits: detail.edits,
|
488
|
+
});
|
489
|
+
}
|
490
|
+
}
|
491
|
+
}
|
492
|
+
getMemberAccessCompletions(leftExprNode, priorWord) {
|
493
|
+
const symbolTable = new Map();
|
494
|
+
const completionMap = new CompletionMap();
|
495
|
+
let leftType = this.evaluator.getType(leftExprNode);
|
496
|
+
if (!leftType) {
|
497
|
+
return completionMap;
|
498
|
+
}
|
499
|
+
leftType = this.evaluator.makeTopLevelTypeVarsConcrete(leftType);
|
500
|
+
// If this is an unknown type with a "possible type" associated with
|
501
|
+
// it, use the possible type.
|
502
|
+
if ((0, types_1.isUnknown)(leftType) && leftType.possibleType) {
|
503
|
+
leftType = this.evaluator.makeTopLevelTypeVarsConcrete(leftType.possibleType);
|
504
|
+
}
|
505
|
+
(0, typeUtils_1.doForEachSubtype)(leftType, (subtype) => {
|
506
|
+
subtype = this.evaluator.makeTopLevelTypeVarsConcrete(subtype);
|
507
|
+
if ((0, types_1.isClass)(subtype)) {
|
508
|
+
(0, typeUtils_1.getMembersForClass)(subtype, symbolTable, /* includeInstanceVars */ types_1.TypeBase.isInstance(subtype));
|
509
|
+
}
|
510
|
+
else if ((0, types_1.isModule)(subtype)) {
|
511
|
+
(0, typeUtils_1.getMembersForModule)(subtype, symbolTable);
|
512
|
+
}
|
513
|
+
else if ((0, types_1.isFunction)(subtype) || (0, types_1.isOverloadedFunction)(subtype)) {
|
514
|
+
const functionClass = this.evaluator.getBuiltInType(leftExprNode, 'function');
|
515
|
+
if (functionClass && (0, types_1.isInstantiableClass)(functionClass)) {
|
516
|
+
(0, typeUtils_1.getMembersForClass)(functionClass, symbolTable, /* includeInstanceVars */ true);
|
517
|
+
}
|
518
|
+
}
|
519
|
+
else if ((0, types_1.isNoneInstance)(subtype)) {
|
520
|
+
const objectClass = this.evaluator.getBuiltInType(leftExprNode, 'object');
|
521
|
+
if (objectClass && (0, types_1.isInstantiableClass)(objectClass)) {
|
522
|
+
(0, typeUtils_1.getMembersForClass)(objectClass, symbolTable, types_1.TypeBase.isInstance(subtype));
|
523
|
+
}
|
524
|
+
}
|
525
|
+
this._addSymbolsForSymbolTable(symbolTable, () => true, priorWord, leftExprNode,
|
526
|
+
/* isInImport */ false, (0, types_1.isClass)(subtype) ? subtype : undefined, completionMap);
|
527
|
+
});
|
528
|
+
return completionMap;
|
529
|
+
}
|
530
|
+
addAutoImportCompletions(priorWord, similarityLimit, lazyEdit, completionMap) {
|
531
|
+
if (!this.configOptions.autoImportCompletions) {
|
532
|
+
// If auto import on the server is turned off or this particular invocation
|
533
|
+
// is turned off (ex, notebook), don't do any thing.
|
534
|
+
return;
|
535
|
+
}
|
536
|
+
const currentFile = this.program.getSourceFileInfo(this.filePath);
|
537
|
+
const moduleSymbolMap = (0, autoImporter_1.buildModuleSymbolsMap)(this.program.getSourceFileInfoList().filter((s) => s !== currentFile));
|
538
|
+
const autoImporter = new autoImporter_1.AutoImporter(this.execEnv, this.importResolver, this.parseResults, this.position, completionMap, moduleSymbolMap, {
|
539
|
+
lazyEdit,
|
540
|
+
});
|
541
|
+
const results = [];
|
542
|
+
(0, collectionUtils_1.appendArray)(results, autoImporter.getAutoImportCandidates(priorWord, similarityLimit,
|
543
|
+
/* abbrFromUsers */ undefined, this.cancellationToken));
|
544
|
+
this.addImportResults(results, priorWord, completionMap);
|
545
|
+
}
|
546
|
+
addImportResults(results, priorWord, completionMap) {
|
178
547
|
var _a, _b;
|
179
|
-
const
|
548
|
+
for (const result of results) {
|
549
|
+
if (result.symbol) {
|
550
|
+
this.addSymbol(result.name, result.symbol, priorWord, completionMap, {
|
551
|
+
extraCommitChars: true,
|
552
|
+
autoImportSource: result.source,
|
553
|
+
autoImportAlias: result.alias,
|
554
|
+
edits: {
|
555
|
+
textEdit: this.createReplaceEdits(priorWord, /* node */ undefined, result.insertionText),
|
556
|
+
additionalTextEdits: result.edits,
|
557
|
+
},
|
558
|
+
});
|
559
|
+
}
|
560
|
+
else {
|
561
|
+
this._addNameToCompletions((_a = result.alias) !== null && _a !== void 0 ? _a : result.name, (_b = result.kind) !== null && _b !== void 0 ? _b : vscode_languageserver_1.CompletionItemKind.Module, priorWord, completionMap, {
|
562
|
+
extraCommitChars: true,
|
563
|
+
autoImportText: this._getAutoImportText(result.name, result.source, result.alias),
|
564
|
+
edits: {
|
565
|
+
textEdit: this.createReplaceEdits(priorWord, /* node */ undefined, result.insertionText),
|
566
|
+
additionalTextEdits: result.edits,
|
567
|
+
},
|
568
|
+
});
|
569
|
+
}
|
570
|
+
}
|
571
|
+
}
|
572
|
+
checkDecorator(node, value) {
|
573
|
+
return node.expression.nodeType === 38 /* Name */ && node.expression.value === value;
|
574
|
+
}
|
575
|
+
addExtraCommitChar(item) {
|
576
|
+
// extra commit char is not supported.
|
577
|
+
}
|
578
|
+
get _fileContents() {
|
579
|
+
var _a, _b;
|
580
|
+
return (_b = (_a = this.parseResults) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : '';
|
581
|
+
}
|
582
|
+
_getCompletions() {
|
583
|
+
var _a, _b;
|
584
|
+
const offset = (0, positionUtils_1.convertPositionToOffset)(this.position, this.parseResults.tokenizerOutput.lines);
|
180
585
|
if (offset === undefined) {
|
181
586
|
return undefined;
|
182
587
|
}
|
183
|
-
|
588
|
+
let node = ParseTreeUtils.findNodeByOffset(this.parseResults.parseTree, offset);
|
589
|
+
// See if we're inside a string literal or an f-string statement.
|
590
|
+
const token = ParseTreeUtils.getTokenOverlapping(this.parseResults.tokenizerOutput.tokens, offset);
|
184
591
|
if ((token === null || token === void 0 ? void 0 : token.type) === 5 /* String */) {
|
185
592
|
const stringToken = token;
|
186
|
-
this.
|
593
|
+
this._stringLiteralContainer = textRange_1.TextRange.contains(stringToken, offset)
|
187
594
|
? stringToken
|
188
595
|
: stringToken.flags & 65536 /* Unterminated */
|
189
596
|
? stringToken
|
190
597
|
: undefined;
|
191
598
|
}
|
192
|
-
|
599
|
+
else if (node) {
|
600
|
+
const fStringContainer = ParseTreeUtils.getParentNodeOfType(node, 27 /* FormatString */);
|
601
|
+
if (fStringContainer) {
|
602
|
+
this._stringLiteralContainer = fStringContainer.token;
|
603
|
+
}
|
604
|
+
}
|
193
605
|
// See if we can get to a "better" node by backing up a few columns.
|
194
606
|
// A "better" node is defined as one that's deeper than the current
|
195
607
|
// node.
|
@@ -208,7 +620,7 @@ class CompletionProvider {
|
|
208
620
|
if (curChar === ',') {
|
209
621
|
sawComma = true;
|
210
622
|
}
|
211
|
-
const curNode = ParseTreeUtils.findNodeByOffset(this.
|
623
|
+
const curNode = ParseTreeUtils.findNodeByOffset(this.parseResults.parseTree, curOffset);
|
212
624
|
if (curNode && curNode !== initialNode) {
|
213
625
|
if (ParseTreeUtils.getNodeDepth(curNode) > initialDepth) {
|
214
626
|
node = curNode;
|
@@ -226,10 +638,10 @@ class CompletionProvider {
|
|
226
638
|
return undefined;
|
227
639
|
}
|
228
640
|
// Get the text on that line prior to the insertion point.
|
229
|
-
const lineTextRange = this.
|
641
|
+
const lineTextRange = this.parseResults.tokenizerOutput.lines.getItemAt(this.position.line);
|
230
642
|
const textOnLine = this._fileContents.substr(lineTextRange.start, lineTextRange.length);
|
231
|
-
const priorText = textOnLine.substr(0, this.
|
232
|
-
const postText = textOnLine.substr(this.
|
643
|
+
const priorText = textOnLine.substr(0, this.position.character);
|
644
|
+
const postText = textOnLine.substr(this.position.character);
|
233
645
|
const priorWordIndex = priorText.search(/\w+$/);
|
234
646
|
const priorWord = priorWordIndex >= 0 ? priorText.substr(priorWordIndex) : '';
|
235
647
|
// Don't offer completions if we're within a comment.
|
@@ -249,7 +661,7 @@ class CompletionProvider {
|
|
249
661
|
// that of its ancestors.
|
250
662
|
let curNode = errorNode || node;
|
251
663
|
while (true) {
|
252
|
-
(0, cancellationUtils_1.throwIfCancellationRequested)(this.
|
664
|
+
(0, cancellationUtils_1.throwIfCancellationRequested)(this.cancellationToken);
|
253
665
|
if (curNode.nodeType === 49 /* String */) {
|
254
666
|
return this._getLiteralCompletions(curNode, offset, priorWord, priorText, postText);
|
255
667
|
}
|
@@ -263,13 +675,13 @@ class CompletionProvider {
|
|
263
675
|
return this._getExpressionErrorCompletions(curNode, offset, priorWord, priorText, postText);
|
264
676
|
}
|
265
677
|
if (curNode.nodeType === 35 /* MemberAccess */) {
|
266
|
-
return this.
|
678
|
+
return this.getMemberAccessCompletions(curNode.leftExpression, priorWord);
|
267
679
|
}
|
268
680
|
if (curNode.nodeType === 15 /* Dictionary */) {
|
269
681
|
const completionMap = new CompletionMap();
|
270
682
|
if (this._tryAddTypedDictKeysFromDictionary(curNode,
|
271
683
|
/* stringNode */ undefined, priorWord, priorText, postText, completionMap)) {
|
272
|
-
return
|
684
|
+
return completionMap;
|
273
685
|
}
|
274
686
|
}
|
275
687
|
const dictionaryEntry = ParseTreeUtils.getFirstAncestorOrSelfOfKind(curNode, 17 /* DictionaryKeyEntry */);
|
@@ -280,7 +692,7 @@ class CompletionProvider {
|
|
280
692
|
const completionMap = new CompletionMap();
|
281
693
|
if (this._tryAddTypedDictKeysFromDictionary(dictionaryNode,
|
282
694
|
/* stringNode */ undefined, priorWord, priorText, postText, completionMap)) {
|
283
|
-
return
|
695
|
+
return completionMap;
|
284
696
|
}
|
285
697
|
}
|
286
698
|
}
|
@@ -294,7 +706,7 @@ class CompletionProvider {
|
|
294
706
|
return result;
|
295
707
|
}
|
296
708
|
}
|
297
|
-
if (curNode.nodeType === 31 /* List */ && this.
|
709
|
+
if (curNode.nodeType === 31 /* List */ && this.options.triggerCharacter === '[') {
|
298
710
|
// If this is an empty list, don't start putting completions up yet.
|
299
711
|
return undefined;
|
300
712
|
}
|
@@ -309,7 +721,7 @@ class CompletionProvider {
|
|
309
721
|
curNode.parent.nodeType === 25 /* Except */ &&
|
310
722
|
!curNode.parent.name &&
|
311
723
|
curNode.parent.typeExpression &&
|
312
|
-
|
724
|
+
textRange_1.TextRange.getEnd(curNode.parent.typeExpression) < offset &&
|
313
725
|
offset <= curNode.parent.exceptSuite.start) {
|
314
726
|
// except Exception as [<empty>]
|
315
727
|
return undefined;
|
@@ -341,84 +753,6 @@ class CompletionProvider {
|
|
341
753
|
}
|
342
754
|
return undefined;
|
343
755
|
}
|
344
|
-
// When the user selects a completion, this callback is invoked,
|
345
|
-
// allowing us to record what was selected. This allows us to
|
346
|
-
// build our MRU cache so we can better predict entries.
|
347
|
-
resolveCompletionItem(completionItem) {
|
348
|
-
(0, cancellationUtils_1.throwIfCancellationRequested)(this._cancellationToken);
|
349
|
-
const completionItemData = (0, lspUtils_1.fromLSPAny)(completionItem.data);
|
350
|
-
const label = completionItem.label;
|
351
|
-
let autoImportText = '';
|
352
|
-
if (completionItemData.autoImportText) {
|
353
|
-
autoImportText = completionItemData.autoImportText;
|
354
|
-
}
|
355
|
-
const curIndex = CompletionProvider._mostRecentCompletions.findIndex((item) => item.label === label && item.autoImportText === autoImportText);
|
356
|
-
if (curIndex > 0) {
|
357
|
-
// If there's an existing entry with the same name that's not at the
|
358
|
-
// beginning of the array, remove it.
|
359
|
-
CompletionProvider._mostRecentCompletions = CompletionProvider._mostRecentCompletions.splice(curIndex, 1);
|
360
|
-
}
|
361
|
-
if (curIndex !== 0) {
|
362
|
-
// Add to the start of the array.
|
363
|
-
CompletionProvider._mostRecentCompletions.unshift({ label, autoImportText });
|
364
|
-
}
|
365
|
-
if (CompletionProvider._mostRecentCompletions.length > maxRecentCompletions) {
|
366
|
-
// Prevent the MRU list from growing indefinitely.
|
367
|
-
CompletionProvider._mostRecentCompletions.pop();
|
368
|
-
}
|
369
|
-
if (!completionItemData.symbolLabel) {
|
370
|
-
return;
|
371
|
-
}
|
372
|
-
if (completionItemData.modulePath) {
|
373
|
-
const documentation = (0, typeDocStringUtils_1.getModuleDocStringFromPaths)([completionItemData.modulePath], this._sourceMapper);
|
374
|
-
if (!documentation) {
|
375
|
-
return;
|
376
|
-
}
|
377
|
-
if (this._options.format === vscode_languageserver_1.MarkupKind.Markdown) {
|
378
|
-
const markdownString = (0, docStringConversion_1.convertDocStringToMarkdown)(documentation);
|
379
|
-
completionItem.documentation = {
|
380
|
-
kind: vscode_languageserver_1.MarkupKind.Markdown,
|
381
|
-
value: markdownString,
|
382
|
-
};
|
383
|
-
}
|
384
|
-
else if (this._options.format === vscode_languageserver_1.MarkupKind.PlainText) {
|
385
|
-
const plainTextString = (0, docStringConversion_1.convertDocStringToPlainText)(documentation);
|
386
|
-
completionItem.documentation = {
|
387
|
-
kind: vscode_languageserver_1.MarkupKind.PlainText,
|
388
|
-
value: plainTextString,
|
389
|
-
};
|
390
|
-
}
|
391
|
-
return;
|
392
|
-
}
|
393
|
-
this._itemToResolve = completionItem;
|
394
|
-
if (!completionItemData.autoImportText) {
|
395
|
-
// Rerun the completion lookup. It will fill in additional information
|
396
|
-
// about the item to be resolved. We'll ignore the rest of the returned
|
397
|
-
// list. This is a bit wasteful, but all of that information should be
|
398
|
-
// cached, so it's not as bad as it might seem.
|
399
|
-
this.getCompletionsForPosition();
|
400
|
-
}
|
401
|
-
else if (!completionItem.additionalTextEdits) {
|
402
|
-
const completionMap = new CompletionMap();
|
403
|
-
const completionResults = { completionMap };
|
404
|
-
this._addAutoImportCompletions(completionItemData.symbolLabel,
|
405
|
-
/* similarityLimit */ 1,
|
406
|
-
/* lazyEdit */ false, completionResults);
|
407
|
-
}
|
408
|
-
}
|
409
|
-
get _importResolver() {
|
410
|
-
return this._program.importResolver;
|
411
|
-
}
|
412
|
-
get _configOptions() {
|
413
|
-
return this._program.configOptions;
|
414
|
-
}
|
415
|
-
get _evaluator() {
|
416
|
-
return this._program.evaluator;
|
417
|
-
}
|
418
|
-
get _fileContents() {
|
419
|
-
var _a, _b;
|
420
|
-
return (_b = (_a = this._parseResults) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : '';
|
421
|
-
}
|
422
756
|
// This method will return false if it wants1
|
423
757
|
// caller to walk up the tree. it will return
|
424
758
|
// CompletionResults or undefined if it wants caller
|
@@ -437,7 +771,7 @@ class CompletionProvider {
|
|
437
771
|
if (curNode.parent.parent &&
|
438
772
|
curNode.parent.parent.nodeType === 21 /* ImportAs */ &&
|
439
773
|
!curNode.parent.parent.alias &&
|
440
|
-
|
774
|
+
textRange_1.TextRange.getEnd(curNode.parent.parent) < offset) {
|
441
775
|
return undefined;
|
442
776
|
}
|
443
777
|
// Are we within a "from X import Y as Z" statement and
|
@@ -452,7 +786,7 @@ class CompletionProvider {
|
|
452
786
|
const parentNode = curNode.parent.parent;
|
453
787
|
if (parentNode && parentNode.nodeType === 22 /* ImportFrom */) {
|
454
788
|
// Are we within a "from X import Y as [<empty>]"?
|
455
|
-
if (!curNode.parent.alias &&
|
789
|
+
if (!curNode.parent.alias && textRange_1.TextRange.getEnd(curNode.parent) < offset) {
|
456
790
|
return undefined;
|
457
791
|
}
|
458
792
|
if (curNode.parent.name === curNode) {
|
@@ -463,7 +797,7 @@ class CompletionProvider {
|
|
463
797
|
return false;
|
464
798
|
}
|
465
799
|
if (curNode.parent.nodeType === 35 /* MemberAccess */ && curNode === curNode.parent.memberName) {
|
466
|
-
return this.
|
800
|
+
return this.getMemberAccessCompletions(curNode.parent.leftExpression, priorWord);
|
467
801
|
}
|
468
802
|
if (curNode.parent.nodeType === 25 /* Except */ && curNode === curNode.parent.name) {
|
469
803
|
return undefined;
|
@@ -481,11 +815,11 @@ class CompletionProvider {
|
|
481
815
|
return undefined;
|
482
816
|
}
|
483
817
|
if (curNode.parent.nodeType === 26 /* For */ &&
|
484
|
-
|
818
|
+
textRange_1.TextRange.contains(curNode.parent.targetExpression, curNode.start)) {
|
485
819
|
return undefined;
|
486
820
|
}
|
487
821
|
if (curNode.parent.nodeType === 33 /* ListComprehensionFor */ &&
|
488
|
-
|
822
|
+
textRange_1.TextRange.contains(curNode.parent.targetExpression, curNode.start)) {
|
489
823
|
return undefined;
|
490
824
|
}
|
491
825
|
// For assignments that implicitly declare variables, remove itself (var decl) from completion.
|
@@ -497,15 +831,15 @@ class CompletionProvider {
|
|
497
831
|
if (leftNode !== curNode || priorWord.length === 0) {
|
498
832
|
return false;
|
499
833
|
}
|
500
|
-
const decls = this.
|
834
|
+
const decls = this.evaluator.getDeclarationsForNameNode(curNode);
|
501
835
|
if ((decls === null || decls === void 0 ? void 0 : decls.length) !== 1 || !(0, declaration_1.isVariableDeclaration)(decls[0]) || decls[0].node !== curNode) {
|
502
836
|
return false;
|
503
837
|
}
|
504
|
-
const
|
505
|
-
if (
|
506
|
-
|
838
|
+
const completionMap = this._getExpressionCompletions(curNode, priorWord, priorText, postText);
|
839
|
+
if (completionMap) {
|
840
|
+
completionMap.delete(curNode.value);
|
507
841
|
}
|
508
|
-
return
|
842
|
+
return completionMap;
|
509
843
|
}
|
510
844
|
// Defining class variables.
|
511
845
|
// ex) class A:
|
@@ -522,12 +856,12 @@ class CompletionProvider {
|
|
522
856
|
}
|
523
857
|
_isWithinComment(offset) {
|
524
858
|
var _a, _b;
|
525
|
-
const token = getTokenAfter(offset, this.
|
859
|
+
const token = getTokenAfter(offset, this.parseResults.tokenizerOutput.tokens);
|
526
860
|
if (!token) {
|
527
861
|
// If we're in the middle of a token, we're not in a comment.
|
528
862
|
return false;
|
529
863
|
}
|
530
|
-
return (_b = (_a = token.comments) === null || _a === void 0 ? void 0 : _a.some((c) =>
|
864
|
+
return (_b = (_a = token.comments) === null || _a === void 0 ? void 0 : _a.some((c) => textRange_1.TextRange.overlaps(c, offset))) !== null && _b !== void 0 ? _b : false;
|
531
865
|
function getTokenAfter(offset, tokens) {
|
532
866
|
const tokenIndex = tokens.getItemAtPosition(offset);
|
533
867
|
if (tokenIndex < 0) {
|
@@ -572,8 +906,8 @@ class CompletionProvider {
|
|
572
906
|
case 7 /* MissingMemberAccessName */:
|
573
907
|
case 2 /* MissingExpression */: {
|
574
908
|
// Don't show completion after random dots.
|
575
|
-
const tokenizerOutput = this.
|
576
|
-
const offset = (0, positionUtils_1.convertPositionToOffset)(this.
|
909
|
+
const tokenizerOutput = this.parseResults.tokenizerOutput;
|
910
|
+
const offset = (0, positionUtils_1.convertPositionToOffset)(this.position, tokenizerOutput.lines);
|
577
911
|
const index = ParseTreeUtils.getTokenIndexAtLeft(tokenizerOutput.tokens, offset);
|
578
912
|
const token = ParseTreeUtils.getTokenAtIndex(tokenizerOutput.tokens, index);
|
579
913
|
const prevToken = ParseTreeUtils.getTokenAtIndex(tokenizerOutput.tokens, index - 1);
|
@@ -591,14 +925,14 @@ class CompletionProvider {
|
|
591
925
|
// since parser won't see "is" as partially written member name instead it will see it as
|
592
926
|
// expression statement with missing expression after "is" keyword.
|
593
927
|
// In such case, use "MyType." to get completion.
|
594
|
-
if ((token === null || token === void 0 ? void 0 : token.type) !== 8 /* Keyword */ ||
|
928
|
+
if ((token === null || token === void 0 ? void 0 : token.type) !== 8 /* Keyword */ || textRange_1.TextRange.getEnd(token) !== offset) {
|
595
929
|
return this._getExpressionCompletions(node, priorWord, priorText, postText);
|
596
930
|
}
|
597
931
|
if ((prevToken === null || prevToken === void 0 ? void 0 : prevToken.type) !== 20 /* Dot */) {
|
598
932
|
return this._getExpressionCompletions(node, priorWord, priorText, postText);
|
599
933
|
}
|
600
|
-
const previousOffset =
|
601
|
-
const previousNode = ParseTreeUtils.findNodeByOffset(this.
|
934
|
+
const previousOffset = textRange_1.TextRange.getEnd(prevToken);
|
935
|
+
const previousNode = ParseTreeUtils.findNodeByOffset(this.parseResults.parseTree, previousOffset);
|
602
936
|
if ((previousNode === null || previousNode === void 0 ? void 0 : previousNode.nodeType) !== 0 /* Error */ ||
|
603
937
|
previousNode.category !== 7 /* MissingMemberAccessName */) {
|
604
938
|
return this._getExpressionCompletions(node, priorWord, priorText, postText);
|
@@ -635,7 +969,7 @@ class CompletionProvider {
|
|
635
969
|
}
|
636
970
|
// Determine if the partial name is a method that's overriding
|
637
971
|
// a method in a base class.
|
638
|
-
return this.
|
972
|
+
return this.getMethodOverrideCompletions(priorWord, node.child, node.decorators);
|
639
973
|
}
|
640
974
|
break;
|
641
975
|
}
|
@@ -646,13 +980,10 @@ class CompletionProvider {
|
|
646
980
|
if (!node.child || !(0, parseNodes_1.isExpressionNode)(node.child)) {
|
647
981
|
return undefined;
|
648
982
|
}
|
649
|
-
return this.
|
983
|
+
return this.getMemberAccessCompletions(node.child, priorWord);
|
650
984
|
}
|
651
985
|
_isOverload(node) {
|
652
|
-
return this.
|
653
|
-
}
|
654
|
-
_checkDecorator(node, value) {
|
655
|
-
return node.expression.nodeType === 38 /* Name */ && node.expression.value === value;
|
986
|
+
return this.checkDecorator(node, 'overload');
|
656
987
|
}
|
657
988
|
_createSingleKeywordCompletion(keyword) {
|
658
989
|
const completionItem = vscode_languageserver_1.CompletionItem.create(keyword);
|
@@ -660,7 +991,7 @@ class CompletionProvider {
|
|
660
991
|
completionItem.sortText = this._makeSortText(SortCategory.LikelyKeyword, keyword);
|
661
992
|
const completionMap = new CompletionMap();
|
662
993
|
completionMap.set(completionItem);
|
663
|
-
return
|
994
|
+
return completionMap;
|
664
995
|
}
|
665
996
|
_addClassVariableTypeAnnotationCompletions(priorWord, parseNode, completionMap) {
|
666
997
|
var _a, _b, _c, _d;
|
@@ -679,7 +1010,7 @@ class CompletionProvider {
|
|
679
1010
|
if (!enclosingClass) {
|
680
1011
|
return;
|
681
1012
|
}
|
682
|
-
const classResults = this.
|
1013
|
+
const classResults = this.evaluator.getTypeOfClass(enclosingClass);
|
683
1014
|
if (!classResults) {
|
684
1015
|
return undefined;
|
685
1016
|
}
|
@@ -687,8 +1018,8 @@ class CompletionProvider {
|
|
687
1018
|
const classMember = (0, typeUtils_1.lookUpClassMember)(classResults.classType, classVariableName, 8 /* SkipInstanceVariables */ | 1 /* SkipOriginalClass */);
|
688
1019
|
// First, see whether we can use semantic info to get variable type.
|
689
1020
|
if (classMember) {
|
690
|
-
const memberType = this.
|
691
|
-
const text = this.
|
1021
|
+
const memberType = this.evaluator.getTypeOfMember(classMember);
|
1022
|
+
const text = this.evaluator.printType(memberType, {
|
692
1023
|
enforcePythonSyntax: true,
|
693
1024
|
expandTypeAlias: false,
|
694
1025
|
});
|
@@ -724,7 +1055,7 @@ class CompletionProvider {
|
|
724
1055
|
if (declWithTypeAnnotations.length === 0) {
|
725
1056
|
return;
|
726
1057
|
}
|
727
|
-
const printFlags = (0, sourceMapper_1.isStubFile)(this.
|
1058
|
+
const printFlags = (0, sourceMapper_1.isStubFile)(this.filePath)
|
728
1059
|
? 1 /* ForwardDeclarations */ |
|
729
1060
|
2 /* DoNotLimitStringLength */
|
730
1061
|
: 2 /* DoNotLimitStringLength */;
|
@@ -738,7 +1069,7 @@ class CompletionProvider {
|
|
738
1069
|
if (!enclosingClass) {
|
739
1070
|
return undefined;
|
740
1071
|
}
|
741
|
-
const classResults = this.
|
1072
|
+
const classResults = this.evaluator.getTypeOfClass(enclosingClass);
|
742
1073
|
if (!classResults) {
|
743
1074
|
return undefined;
|
744
1075
|
}
|
@@ -764,13 +1095,13 @@ class CompletionProvider {
|
|
764
1095
|
decls.some((d) => d.node && ParseTreeUtils.getEnclosingClass(d.node, false) === enclosingClass)) {
|
765
1096
|
return;
|
766
1097
|
}
|
767
|
-
this.
|
1098
|
+
this.addSymbol(name, symbol, partialName.value, completionMap, {});
|
768
1099
|
});
|
769
|
-
return completionMap.size > 0 ?
|
1100
|
+
return completionMap.size > 0 ? completionMap : undefined;
|
770
1101
|
}
|
771
1102
|
_getMethodOverloadsCompletions(priorWord, partialName) {
|
772
1103
|
var _a;
|
773
|
-
const symbolTable = getSymbolTable(this.
|
1104
|
+
const symbolTable = getSymbolTable(this.evaluator, partialName);
|
774
1105
|
if (!symbolTable) {
|
775
1106
|
return undefined;
|
776
1107
|
}
|
@@ -792,14 +1123,14 @@ class CompletionProvider {
|
|
792
1123
|
return;
|
793
1124
|
}
|
794
1125
|
if (StringUtils.isPatternInSymbol(partialName.value, name)) {
|
795
|
-
const textEdit = this.
|
796
|
-
this.
|
1126
|
+
const textEdit = this.createReplaceEdits(priorWord, partialName, decl.node.name.value);
|
1127
|
+
this.addSymbol(name, symbol, partialName.value, completionMap, {
|
797
1128
|
funcParensDisabled,
|
798
1129
|
edits: { textEdit },
|
799
1130
|
});
|
800
1131
|
}
|
801
1132
|
});
|
802
|
-
return
|
1133
|
+
return completionMap;
|
803
1134
|
function getSymbolTable(evaluator, partialName) {
|
804
1135
|
const enclosingClass = ParseTreeUtils.getEnclosingClass(partialName, false);
|
805
1136
|
if (enclosingClass) {
|
@@ -808,155 +1139,39 @@ class CompletionProvider {
|
|
808
1139
|
return undefined;
|
809
1140
|
}
|
810
1141
|
const symbolTable = new Map();
|
811
|
-
for (const mroClass of classResults.classType.details.mro) {
|
812
|
-
if ((0, types_1.isInstantiableClass)(mroClass)) {
|
813
|
-
(0, typeUtils_1.getMembersForClass)(mroClass, symbolTable, /* includeInstanceVars */ false);
|
814
|
-
}
|
815
|
-
}
|
816
|
-
return symbolTable;
|
817
|
-
}
|
818
|
-
// For function overload, we only care about top level functions
|
819
|
-
const moduleNode = ParseTreeUtils.getEnclosingModule(partialName);
|
820
|
-
if (moduleNode) {
|
821
|
-
const moduleScope = AnalyzerNodeInfo.getScope(moduleNode);
|
822
|
-
return moduleScope === null || moduleScope === void 0 ? void 0 : moduleScope.symbolTable;
|
823
|
-
}
|
824
|
-
return undefined;
|
825
|
-
}
|
826
|
-
}
|
827
|
-
_getMethodOverrideCompletions(priorWord, partialName, decorators) {
|
828
|
-
var _a, _b;
|
829
|
-
const enclosingClass = ParseTreeUtils.getEnclosingClass(partialName, /* stopAtFunction */ true);
|
830
|
-
if (!enclosingClass) {
|
831
|
-
return undefined;
|
832
|
-
}
|
833
|
-
const classResults = this._evaluator.getTypeOfClass(enclosingClass);
|
834
|
-
if (!classResults) {
|
835
|
-
return undefined;
|
836
|
-
}
|
837
|
-
const staticmethod = (_a = decorators === null || decorators === void 0 ? void 0 : decorators.some((d) => this._checkDecorator(d, 'staticmethod'))) !== null && _a !== void 0 ? _a : false;
|
838
|
-
const classmethod = (_b = decorators === null || decorators === void 0 ? void 0 : decorators.some((d) => this._checkDecorator(d, 'classmethod'))) !== null && _b !== void 0 ? _b : false;
|
839
|
-
const fallbackPath = (0, pythonPathUtils_1.getTypeShedFallbackPath)(this._importResolver.fileSystem);
|
840
|
-
const typingFilePath = fallbackPath ? (0, pathUtils_1.combinePaths)(fallbackPath, 'stdlib/typing.pyi') : undefined;
|
841
|
-
const appendMember = (map, member, name) => {
|
842
|
-
if (!(0, types_1.isInstantiableClass)(member.classType) ||
|
843
|
-
member.classType.details === classResults.classType.details ||
|
844
|
-
!StringUtils.isPatternInSymbol(partialName.value, name)) {
|
845
|
-
// Quick bail out if member is something we don't want to override.
|
846
|
-
return;
|
847
|
-
}
|
848
|
-
const symbol = member.symbol;
|
849
|
-
const decl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(symbol);
|
850
|
-
if (!decl || decl.type !== 5 /* Function */) {
|
851
|
-
return;
|
852
|
-
}
|
853
|
-
const declaredType = this._evaluator.getTypeOfMember(member);
|
854
|
-
if (!declaredType) {
|
855
|
-
return;
|
856
|
-
}
|
857
|
-
const isDeclaredStaticMethod = (0, types_1.isFunction)(declaredType) && types_1.FunctionType.isStaticMethod(declaredType);
|
858
|
-
// Special-case the "__init__subclass__" method because it's an implicit
|
859
|
-
// classmethod that the type evaluator flags as a real classmethod.
|
860
|
-
const isDeclaredClassMethod = (0, types_1.isFunction)(declaredType) && types_1.FunctionType.isClassMethod(declaredType) && name !== '__init_subclass__';
|
861
|
-
if (staticmethod !== isDeclaredStaticMethod || classmethod !== isDeclaredClassMethod) {
|
862
|
-
return;
|
863
|
-
}
|
864
|
-
let isProperty = (0, types_1.isClassInstance)(declaredType) && types_1.ClassType.isPropertyClass(declaredType);
|
865
|
-
if (SymbolNameUtils.isDunderName(name)) {
|
866
|
-
// Don't offer suggestions for built-in properties like "__class__", etc.
|
867
|
-
isProperty = false;
|
868
|
-
}
|
869
|
-
let funcType = undefined;
|
870
|
-
if ((0, types_1.isFunction)(declaredType)) {
|
871
|
-
funcType = declaredType;
|
872
|
-
}
|
873
|
-
else if (isProperty) {
|
874
|
-
const getter = (0, typeUtils_1.lookUpClassMember)(declaredType, 'fget');
|
875
|
-
if (!getter) {
|
876
|
-
return;
|
877
|
-
}
|
878
|
-
const member = this._evaluator.getTypeOfMember(getter);
|
879
|
-
if (!(0, types_1.isFunction)(member)) {
|
880
|
-
return;
|
1142
|
+
for (const mroClass of classResults.classType.details.mro) {
|
1143
|
+
if ((0, types_1.isInstantiableClass)(mroClass)) {
|
1144
|
+
(0, typeUtils_1.getMembersForClass)(mroClass, symbolTable, /* includeInstanceVars */ false);
|
1145
|
+
}
|
881
1146
|
}
|
882
|
-
|
883
|
-
}
|
884
|
-
if (!funcType || !funcType.details.declaration) {
|
885
|
-
return;
|
1147
|
+
return symbolTable;
|
886
1148
|
}
|
887
|
-
|
888
|
-
const
|
889
|
-
|
890
|
-
|
891
|
-
|
1149
|
+
// For function overload, we only care about top level functions
|
1150
|
+
const moduleNode = ParseTreeUtils.getEnclosingModule(partialName);
|
1151
|
+
if (moduleNode) {
|
1152
|
+
const moduleScope = AnalyzerNodeInfo.getScope(moduleNode);
|
1153
|
+
return moduleScope === null || moduleScope === void 0 ? void 0 : moduleScope.symbolTable;
|
892
1154
|
}
|
893
|
-
|
894
|
-
const methodBody = this._printOverriddenMethodBody(classResults.classType, isDeclaredStaticMethod, isProperty, decl);
|
895
|
-
text = `${result.methodSignature}:\n${methodBody}`;
|
896
|
-
}
|
897
|
-
const textEdit = this._createReplaceEdits(priorWord, partialName, text);
|
898
|
-
// This will add new import statements, but for now, it won't add new
|
899
|
-
// `TypeVar` statement such as TypeVar, TypeVarTuple, ParamSpec even if
|
900
|
-
// the overridden method uses them.
|
901
|
-
const additionalTextEdits = importAdder.applyImports(result.importData, this._filePath, this._parseResults, this._parseResults.parseTree.length, "absolute" /* Absolute */, this._cancellationToken);
|
902
|
-
this._addSymbol(name, symbol, partialName.value, map, {
|
903
|
-
// method signature already contains ()
|
904
|
-
funcParensDisabled: true,
|
905
|
-
edits: {
|
906
|
-
format: this._options.snippet ? vscode_languageserver_1.InsertTextFormat.Snippet : undefined,
|
907
|
-
textEdit,
|
908
|
-
additionalTextEdits,
|
909
|
-
},
|
910
|
-
});
|
911
|
-
};
|
912
|
-
const completionMap = new CompletionMap();
|
913
|
-
const classMemberMap = (0, typeUtils_1.getClassFieldsRecursive)(classResults.classType);
|
914
|
-
classMemberMap.forEach((member, name) => appendMember(completionMap, member, name));
|
915
|
-
if (classResults.classType.details.effectiveMetaclass &&
|
916
|
-
!(0, types_1.isUnknown)(classResults.classType.details.effectiveMetaclass)) {
|
917
|
-
const metaClassMemberMap = (0, typeUtils_1.getClassFieldsRecursive)(classResults.classType.details.effectiveMetaclass);
|
918
|
-
metaClassMemberMap.forEach((member, name) => appendMember(completionMap, member, name));
|
1155
|
+
return undefined;
|
919
1156
|
}
|
920
|
-
return { completionMap };
|
921
|
-
}
|
922
|
-
_createReplaceEdits(priorWord, node, text) {
|
923
|
-
const replaceOrInsertEndChar = (node === null || node === void 0 ? void 0 : node.nodeType) === 38 /* Name */
|
924
|
-
? this._position.character - priorWord.length + node.value.length
|
925
|
-
: this._position.character;
|
926
|
-
const range = {
|
927
|
-
start: { line: this._position.line, character: this._position.character - priorWord.length },
|
928
|
-
end: { line: this._position.line, character: replaceOrInsertEndChar },
|
929
|
-
};
|
930
|
-
return vscode_languageserver_1.TextEdit.replace(range, text);
|
931
1157
|
}
|
932
|
-
_printMethodSignature(
|
933
|
-
const
|
1158
|
+
_printMethodSignature(classType, decl) {
|
1159
|
+
const node = decl.node;
|
934
1160
|
let ellipsisForDefault;
|
935
|
-
if ((0, sourceMapper_1.isStubFile)(this.
|
1161
|
+
if ((0, sourceMapper_1.isStubFile)(this.filePath)) {
|
936
1162
|
// In stubs, always use "...".
|
937
1163
|
ellipsisForDefault = true;
|
938
1164
|
}
|
939
|
-
else if (classType.details.moduleName ===
|
1165
|
+
else if (classType.details.moduleName === decl.moduleName) {
|
940
1166
|
// In the same file, always print the full default.
|
941
1167
|
ellipsisForDefault = false;
|
942
1168
|
}
|
943
|
-
const
|
1169
|
+
const printFlags = (0, sourceMapper_1.isStubFile)(this.filePath)
|
944
1170
|
? 1 /* ForwardDeclarations */ |
|
945
1171
|
2 /* DoNotLimitStringLength */
|
946
1172
|
: 2 /* DoNotLimitStringLength */;
|
947
|
-
const
|
948
|
-
|
949
|
-
expandTypeAlias: false,
|
950
|
-
omitTypeArgumentsIfUnknown: true,
|
951
|
-
printUnknownWithAny: true,
|
952
|
-
};
|
953
|
-
const getTypeToPrint = (mainType, fallbackType) => {
|
954
|
-
return mainType && (!(0, types_1.isUnknown)(mainType) || (fallbackType === null || fallbackType === void 0 ? void 0 : fallbackType.category) === 10 /* TypeVar */)
|
955
|
-
? mainType
|
956
|
-
: fallbackType;
|
957
|
-
};
|
958
|
-
const importData = createImportData(importAdder, funcType, declaration, typingFilePath, (t) => this._sourceMapper.findClassDeclarationsByType(this._filePath, t), this._cancellationToken);
|
959
|
-
const paramList = funcType.details.parameters.map((param, index) => {
|
1173
|
+
const paramList = node.parameters
|
1174
|
+
.map((param, index) => {
|
960
1175
|
let paramString = '';
|
961
1176
|
if (param.category === 1 /* VarArgList */) {
|
962
1177
|
paramString += '*';
|
@@ -965,325 +1180,35 @@ class CompletionProvider {
|
|
965
1180
|
paramString += '**';
|
966
1181
|
}
|
967
1182
|
if (param.name) {
|
968
|
-
paramString += param.name;
|
969
|
-
}
|
970
|
-
if (param.typeAnnotation) {
|
971
|
-
const originalType = funcType.details.parameters[index].type;
|
972
|
-
const typeToPrint = getTypeToPrint(types_1.FunctionType.getEffectiveParameterType(funcType, index), originalType);
|
973
|
-
// If we have actual type, then use type to generate string representation of the type, otherwise, use syntax (text).
|
974
|
-
const strType = isTypeUsableForPrint(typeToPrint, originalType)
|
975
|
-
? this._evaluator.printType(typeToPrint, printOptionsUsingType)
|
976
|
-
: ParseTreeUtils.printExpression(param.typeAnnotation, printOptionsUsingSyntax);
|
977
|
-
paramString += ': ' + strType;
|
978
|
-
}
|
979
|
-
if (param.defaultValueExpression) {
|
980
|
-
paramString += param.typeAnnotation ? ' = ' : '=';
|
981
|
-
const useEllipsis = ellipsisForDefault !== null && ellipsisForDefault !== void 0 ? ellipsisForDefault : !isSimpleDefault(param.defaultValueExpression);
|
982
|
-
paramString += useEllipsis
|
983
|
-
? '...'
|
984
|
-
: ParseTreeUtils.printExpression(param.defaultValueExpression, printOptionsUsingSyntax);
|
985
|
-
}
|
986
|
-
if (!paramString &&
|
987
|
-
!param.name &&
|
988
|
-
param.category === 0 /* Simple */ &&
|
989
|
-
index < funcType.details.parameters.length - 1) {
|
990
|
-
return '/';
|
991
|
-
}
|
992
|
-
return paramString;
|
993
|
-
});
|
994
|
-
// Remove empty parameters at the end.
|
995
|
-
for (let i = paramList.length - 1; i >= 0; i--) {
|
996
|
-
if (paramList[i] !== '') {
|
997
|
-
break;
|
998
|
-
}
|
999
|
-
paramList.pop();
|
1000
|
-
}
|
1001
|
-
let methodSignature = funcType.details.name + '(' + paramList.join(', ') + ')';
|
1002
|
-
const strReturnType = getReturnTypeStr(this._evaluator, funcType, printOptionsUsingSyntax);
|
1003
|
-
if (strReturnType) {
|
1004
|
-
methodSignature += ' -> ' + strReturnType;
|
1005
|
-
}
|
1006
|
-
return { methodSignature, importData };
|
1007
|
-
function createImportData(importAdder, funcType, declaration, typingFilePath, declarationGetter, token) {
|
1008
|
-
var _a, _b;
|
1009
|
-
// Handle regular case. In this case, we can get import info from
|
1010
|
-
// import used in the file where the function is declared.
|
1011
|
-
const ranges = [];
|
1012
|
-
(0, collectionUtils_1.addIfNotNull)(ranges, textRange_2.TextRange.combine(declaration.node.parameters));
|
1013
|
-
(0, collectionUtils_1.addIfNotNull)(ranges, declaration.node.returnTypeAnnotation);
|
1014
|
-
(0, collectionUtils_1.addIfNotNull)(ranges, declaration.node.functionAnnotationComment);
|
1015
|
-
const moduleNode = ParseTreeUtils.getModuleNode(declaration.node);
|
1016
|
-
const importData = importAdder.collectImportsForSymbolsUsed(moduleNode, ranges, token);
|
1017
|
-
// Handle special case where function has type arguments. In this case,
|
1018
|
-
// we can't use the file the function is declared in because it doesn't
|
1019
|
-
// have those type arguments. It just has the type vars.
|
1020
|
-
// We could walk the mro to discover imports for the type arguments, but
|
1021
|
-
// for now, instead, this creates import statement out of type arguments itself.
|
1022
|
-
const effectiveTypes = [];
|
1023
|
-
funcType.details.parameters.forEach((param, index) => {
|
1024
|
-
if (!param.typeAnnotation) {
|
1025
|
-
return;
|
1026
|
-
}
|
1027
|
-
const originalType = funcType.details.parameters[index].type;
|
1028
|
-
if (!(0, types_1.isTypeVar)(originalType)) {
|
1029
|
-
return;
|
1030
|
-
}
|
1031
|
-
const effectiveType = types_1.FunctionType.getEffectiveParameterType(funcType, index);
|
1032
|
-
effectiveTypes.push([effectiveType, param.typeAnnotation]);
|
1033
|
-
});
|
1034
|
-
const node = declaration.node;
|
1035
|
-
const originalType = funcType.details.declaredReturnType;
|
1036
|
-
if (originalType &&
|
1037
|
-
(0, types_1.isTypeVar)(originalType) &&
|
1038
|
-
(node.returnTypeAnnotation || ((_a = node.functionAnnotationComment) === null || _a === void 0 ? void 0 : _a.returnTypeAnnotation))) {
|
1039
|
-
effectiveTypes.push([
|
1040
|
-
types_1.FunctionType.getSpecializedReturnType(funcType),
|
1041
|
-
(_b = node.returnTypeAnnotation) !== null && _b !== void 0 ? _b : node.functionAnnotationComment.returnTypeAnnotation,
|
1042
|
-
]);
|
1043
|
-
}
|
1044
|
-
const visited = new Set();
|
1045
|
-
const addImport = (t, n) => {
|
1046
|
-
var _a, _b;
|
1047
|
-
if (visited.has(t)) {
|
1048
|
-
return;
|
1049
|
-
}
|
1050
|
-
visited.add(t);
|
1051
|
-
// We need to special case `Any` since we can't get decl from `Any`.
|
1052
|
-
if ((0, types_1.isAny)(t)) {
|
1053
|
-
if (!typingFilePath) {
|
1054
|
-
return;
|
1055
|
-
}
|
1056
|
-
importAdder.addImportInfo({ filePath: typingFilePath, nameInfo: { name: 'Any' } }, importData);
|
1057
|
-
}
|
1058
|
-
if (!(0, types_1.isClass)(t)) {
|
1059
|
-
return;
|
1060
|
-
}
|
1061
|
-
// We need to special case `List`, `Dict` and `Tuple` since user might have
|
1062
|
-
// used typing.List or typing.Dict in the code, but we internally already
|
1063
|
-
// converted them to built-in `list` and `dict`.
|
1064
|
-
// We could avoid doing this if class type holds onto decl it was created from
|
1065
|
-
// if it is not synthesized like func type.
|
1066
|
-
if (typingFilePath && types_1.ClassType.isBuiltIn(t)) {
|
1067
|
-
const name = (_a = t.aliasName) !== null && _a !== void 0 ? _a : t.details.name;
|
1068
|
-
if (t.details.moduleName === 'typing' && name) {
|
1069
|
-
importAdder.addImportInfo({
|
1070
|
-
filePath: typingFilePath,
|
1071
|
-
nameInfo: { name },
|
1072
|
-
}, importData);
|
1073
|
-
}
|
1074
|
-
else if (t.details.moduleName === 'builtins' && t.aliasName) {
|
1075
|
-
importAdder.addImportInfo({
|
1076
|
-
filePath: typingFilePath,
|
1077
|
-
nameInfo: { name },
|
1078
|
-
}, importData);
|
1079
|
-
}
|
1080
|
-
}
|
1081
|
-
else {
|
1082
|
-
const decls = declarationGetter(t);
|
1083
|
-
if (decls.length === 0) {
|
1084
|
-
return;
|
1085
|
-
}
|
1086
|
-
importAdder.addDeclaration(decls[0], n, importData);
|
1087
|
-
}
|
1088
|
-
if (t.isTypeArgumentExplicit) {
|
1089
|
-
(_b = t.typeArguments) === null || _b === void 0 ? void 0 : _b.forEach((ta) => {
|
1090
|
-
addImport(ta, n);
|
1091
|
-
(0, typeUtils_1.doForEachSubtype)(ta, (subtype) => {
|
1092
|
-
addImport(subtype, n);
|
1093
|
-
});
|
1094
|
-
});
|
1095
|
-
}
|
1096
|
-
};
|
1097
|
-
effectiveTypes.forEach(([t, n]) => {
|
1098
|
-
addImport(t, n);
|
1099
|
-
(0, typeUtils_1.doForEachSubtype)(t, (subtype) => {
|
1100
|
-
addImport(subtype, n);
|
1101
|
-
});
|
1102
|
-
});
|
1103
|
-
return importData;
|
1104
|
-
}
|
1105
|
-
function getReturnTypeStr(evaluator, funcType, printFlags) {
|
1106
|
-
var _a;
|
1107
|
-
const originalType = funcType.details.declaredReturnType;
|
1108
|
-
const typeToPrint = getTypeToPrint(types_1.FunctionType.getSpecializedReturnType(funcType), originalType);
|
1109
|
-
const node = funcType.details.declaration.node;
|
1110
|
-
if (!node.returnTypeAnnotation && !((_a = node.functionAnnotationComment) === null || _a === void 0 ? void 0 : _a.returnTypeAnnotation)) {
|
1111
|
-
return undefined;
|
1112
|
-
}
|
1113
|
-
if (typeToPrint && isTypeUsableForPrint(typeToPrint, originalType)) {
|
1114
|
-
return evaluator.printType(typeToPrint, printOptionsUsingType);
|
1115
|
-
}
|
1116
|
-
if (node.returnTypeAnnotation) {
|
1117
|
-
return ParseTreeUtils.printExpression(node.returnTypeAnnotation, printFlags);
|
1118
|
-
}
|
1119
|
-
if (node.functionAnnotationComment) {
|
1120
|
-
return ParseTreeUtils.printExpression(node.functionAnnotationComment.returnTypeAnnotation, printFlags);
|
1121
|
-
}
|
1122
|
-
return undefined;
|
1123
|
-
}
|
1124
|
-
function isTypeUsableForPrint(effectiveType, originalType) {
|
1125
|
-
if (!effectiveType) {
|
1126
|
-
return false;
|
1127
|
-
}
|
1128
|
-
// If original type was `TypeVar`, we want to use `Unknown` as `Any`
|
1129
|
-
return !(0, types_1.isUnknown)(effectiveType) || (originalType === null || originalType === void 0 ? void 0 : originalType.category) === 10 /* TypeVar */;
|
1130
|
-
}
|
1131
|
-
function isSimpleDefault(node) {
|
1132
|
-
switch (node.nodeType) {
|
1133
|
-
case 40 /* Number */:
|
1134
|
-
case 11 /* Constant */:
|
1135
|
-
case 35 /* MemberAccess */:
|
1136
|
-
return true;
|
1137
|
-
case 49 /* String */:
|
1138
|
-
return (node.token.flags & 64 /* Format */) === 0;
|
1139
|
-
case 48 /* StringList */:
|
1140
|
-
return node.strings.every(isSimpleDefault);
|
1141
|
-
case 55 /* UnaryOperation */:
|
1142
|
-
return isSimpleDefault(node.expression);
|
1143
|
-
case 7 /* BinaryOperation */:
|
1144
|
-
return isSimpleDefault(node.leftExpression) && isSimpleDefault(node.rightExpression);
|
1145
|
-
default:
|
1146
|
-
return false;
|
1147
|
-
}
|
1148
|
-
}
|
1149
|
-
}
|
1150
|
-
_printOverriddenMethodBody(classType, isStaticMethod, isProperty, decl) {
|
1151
|
-
let sb = this._parseResults.tokenizerOutput.predominantTabSequence;
|
1152
|
-
if (classType.details.baseClasses.length === 1 &&
|
1153
|
-
(0, types_1.isClass)(classType.details.baseClasses[0]) &&
|
1154
|
-
classType.details.baseClasses[0].details.fullName === 'builtins.object') {
|
1155
|
-
sb += this._options.snippet ? '${0:pass}' : 'pass';
|
1156
|
-
return sb;
|
1157
|
-
}
|
1158
|
-
if (decl.node.parameters.length === 0) {
|
1159
|
-
sb += this._options.snippet ? '${0:pass}' : 'pass';
|
1160
|
-
return sb;
|
1161
|
-
}
|
1162
|
-
const parameters = getParameters(isStaticMethod ? decl.node.parameters : decl.node.parameters.slice(1));
|
1163
|
-
if (decl.node.name.value !== '__init__') {
|
1164
|
-
sb += 'return ';
|
1165
|
-
}
|
1166
|
-
if (decl.node.isAsync) {
|
1167
|
-
sb += 'await ';
|
1168
|
-
}
|
1169
|
-
if (isProperty) {
|
1170
|
-
return sb + `super().${decl.node.name.value}`;
|
1171
|
-
}
|
1172
|
-
return sb + `super().${decl.node.name.value}(${parameters.map(convertToString).join(', ')})`;
|
1173
|
-
function getParameters(parameters) {
|
1174
|
-
const results = [];
|
1175
|
-
let sawKeywordOnlySeparator = false;
|
1176
|
-
for (const parameter of parameters) {
|
1177
|
-
if (parameter.name) {
|
1178
|
-
results.push([
|
1179
|
-
parameter,
|
1180
|
-
parameter.category === 0 /* Simple */ && !!parameter.name && sawKeywordOnlySeparator,
|
1181
|
-
]);
|
1182
|
-
}
|
1183
|
-
// All simple parameters after a `*` or `*args` parameter
|
1184
|
-
// are considered keyword only.
|
1185
|
-
if (parameter.category === 1 /* VarArgList */) {
|
1186
|
-
sawKeywordOnlySeparator = true;
|
1187
|
-
}
|
1188
|
-
}
|
1189
|
-
return results;
|
1190
|
-
}
|
1191
|
-
function convertToString(parameter) {
|
1192
|
-
var _a;
|
1193
|
-
const name = (_a = parameter[0].name) === null || _a === void 0 ? void 0 : _a.value;
|
1194
|
-
if (parameter[0].category === 1 /* VarArgList */) {
|
1195
|
-
return `*${name}`;
|
1196
|
-
}
|
1197
|
-
if (parameter[0].category === 2 /* VarArgDictionary */) {
|
1198
|
-
return `**${name}`;
|
1183
|
+
paramString += param.name.value;
|
1199
1184
|
}
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
const completionMap = new CompletionMap();
|
1206
|
-
let memberAccessInfo = {};
|
1207
|
-
let leftType = this._evaluator.getType(leftExprNode);
|
1208
|
-
if (leftType) {
|
1209
|
-
leftType = this._evaluator.makeTopLevelTypeVarsConcrete(leftType);
|
1210
|
-
// If this is an unknown type with a "possible type" associated with
|
1211
|
-
// it, use the possible type.
|
1212
|
-
if ((0, types_1.isUnknown)(leftType) && leftType.possibleType) {
|
1213
|
-
leftType = this._evaluator.makeTopLevelTypeVarsConcrete(leftType.possibleType);
|
1214
|
-
}
|
1215
|
-
(0, typeUtils_1.doForEachSubtype)(leftType, (subtype) => {
|
1216
|
-
subtype = this._evaluator.makeTopLevelTypeVarsConcrete(subtype);
|
1217
|
-
if ((0, types_1.isClass)(subtype)) {
|
1218
|
-
(0, typeUtils_1.getMembersForClass)(subtype, symbolTable, /* includeInstanceVars */ types_1.TypeBase.isInstance(subtype));
|
1219
|
-
}
|
1220
|
-
else if ((0, types_1.isModule)(subtype)) {
|
1221
|
-
(0, typeUtils_1.getMembersForModule)(subtype, symbolTable);
|
1222
|
-
}
|
1223
|
-
else if ((0, types_1.isFunction)(subtype) || (0, types_1.isOverloadedFunction)(subtype)) {
|
1224
|
-
const functionClass = this._evaluator.getBuiltInType(leftExprNode, 'function');
|
1225
|
-
if (functionClass && (0, types_1.isInstantiableClass)(functionClass)) {
|
1226
|
-
(0, typeUtils_1.getMembersForClass)(functionClass, symbolTable, /* includeInstanceVars */ true);
|
1227
|
-
}
|
1228
|
-
}
|
1229
|
-
else if ((0, types_1.isNoneInstance)(subtype)) {
|
1230
|
-
const objectClass = this._evaluator.getBuiltInType(leftExprNode, 'object');
|
1231
|
-
if (objectClass && (0, types_1.isInstantiableClass)(objectClass)) {
|
1232
|
-
(0, typeUtils_1.getMembersForClass)(objectClass, symbolTable, types_1.TypeBase.isInstance(subtype));
|
1233
|
-
}
|
1234
|
-
}
|
1235
|
-
this._addSymbolsForSymbolTable(symbolTable, () => true, priorWord, leftExprNode,
|
1236
|
-
/* isInImport */ false, (0, types_1.isClass)(subtype) ? subtype : undefined, completionMap);
|
1237
|
-
});
|
1238
|
-
}
|
1239
|
-
// Save member access info for every request
|
1240
|
-
memberAccessInfo = this._getLastKnownModule(leftExprNode, leftType);
|
1241
|
-
return { completionMap, memberAccessInfo };
|
1242
|
-
}
|
1243
|
-
_getLastKnownModule(leftExprNode, leftType) {
|
1244
|
-
var _a;
|
1245
|
-
let curNode = leftExprNode;
|
1246
|
-
let curType = leftType;
|
1247
|
-
let unknownMemberName = leftExprNode.nodeType === 35 /* MemberAccess */ ? leftExprNode === null || leftExprNode === void 0 ? void 0 : leftExprNode.memberName.value : undefined;
|
1248
|
-
// Walk left of the expression scope till we find a known type. A.B.Unknown.<-- return B.
|
1249
|
-
while (curNode) {
|
1250
|
-
if (curNode.nodeType === 9 /* Call */ || curNode.nodeType === 35 /* MemberAccess */) {
|
1251
|
-
// Move left
|
1252
|
-
curNode = curNode.leftExpression;
|
1253
|
-
// First time in the loop remember the name of the unknown type.
|
1254
|
-
if (unknownMemberName === undefined) {
|
1255
|
-
unknownMemberName =
|
1256
|
-
curNode.nodeType === 35 /* MemberAccess */ ? (_a = curNode === null || curNode === void 0 ? void 0 : curNode.memberName.value) !== null && _a !== void 0 ? _a : '' : '';
|
1257
|
-
}
|
1185
|
+
// Currently, we don't automatically add import if the type used in the annotation is not imported
|
1186
|
+
// in current file.
|
1187
|
+
const paramTypeAnnotation = ParseTreeUtils.getTypeAnnotationForParameter(node, index);
|
1188
|
+
if (paramTypeAnnotation) {
|
1189
|
+
paramString += ': ' + ParseTreeUtils.printExpression(paramTypeAnnotation, printFlags);
|
1258
1190
|
}
|
1259
|
-
|
1260
|
-
|
1191
|
+
if (param.defaultValue) {
|
1192
|
+
paramString += paramTypeAnnotation ? ' = ' : '=';
|
1193
|
+
const useEllipsis = ellipsisForDefault !== null && ellipsisForDefault !== void 0 ? ellipsisForDefault : !this.isSimpleDefault(param.defaultValue);
|
1194
|
+
paramString += useEllipsis ? '...' : ParseTreeUtils.printExpression(param.defaultValue, printFlags);
|
1261
1195
|
}
|
1262
|
-
if (
|
1263
|
-
|
1264
|
-
// Breakout if we found a known type.
|
1265
|
-
if (curType !== undefined && !(0, types_1.isUnknown)(curType) && !(0, types_1.isUnbound)(curType)) {
|
1266
|
-
break;
|
1267
|
-
}
|
1196
|
+
if (!paramString && !param.name && param.category === 0 /* Simple */) {
|
1197
|
+
return '/';
|
1268
1198
|
}
|
1199
|
+
return paramString;
|
1200
|
+
})
|
1201
|
+
.join(', ');
|
1202
|
+
let methodSignature = node.name.value + '(' + paramList + ')';
|
1203
|
+
if (node.returnTypeAnnotation) {
|
1204
|
+
methodSignature += ' -> ' + ParseTreeUtils.printExpression(node.returnTypeAnnotation, printFlags);
|
1269
1205
|
}
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
memberAccessInfo.lastKnownModule = moduleNamesForType.find((n) => n !== 'typing');
|
1275
|
-
if (curNode.nodeType === 35 /* MemberAccess */) {
|
1276
|
-
memberAccessInfo.lastKnownMemberName = curNode.memberName.value;
|
1277
|
-
}
|
1278
|
-
else if (curNode.nodeType === 38 /* Name */ && (0, types_1.isInstantiableClass)(curType)) {
|
1279
|
-
memberAccessInfo.lastKnownMemberName = curType.details.name;
|
1280
|
-
}
|
1281
|
-
else if (curNode.nodeType === 38 /* Name */ && (0, types_1.isClassInstance)(curType)) {
|
1282
|
-
memberAccessInfo.lastKnownMemberName = curType.details.name;
|
1283
|
-
}
|
1284
|
-
memberAccessInfo.unknownMemberName = unknownMemberName;
|
1206
|
+
else if (node.functionAnnotationComment) {
|
1207
|
+
methodSignature +=
|
1208
|
+
' -> ' +
|
1209
|
+
ParseTreeUtils.printExpression(node.functionAnnotationComment.returnTypeAnnotation, printFlags);
|
1285
1210
|
}
|
1286
|
-
return
|
1211
|
+
return methodSignature;
|
1287
1212
|
}
|
1288
1213
|
_getStatementCompletions(parseNode, priorWord, priorText, postText) {
|
1289
1214
|
// For now, use the same logic for expressions and statements.
|
@@ -1304,10 +1229,9 @@ class CompletionProvider {
|
|
1304
1229
|
return undefined;
|
1305
1230
|
}
|
1306
1231
|
const completionMap = new CompletionMap();
|
1307
|
-
const completionResults = { completionMap };
|
1308
1232
|
// Return empty completionList for Ellipsis
|
1309
1233
|
if (priorText.slice(-2) === '..') {
|
1310
|
-
return
|
1234
|
+
return completionMap;
|
1311
1235
|
}
|
1312
1236
|
// Defining type annotation for class variables.
|
1313
1237
|
// ex) class A:
|
@@ -1319,7 +1243,7 @@ class CompletionProvider {
|
|
1319
1243
|
// Add symbols that are in scope.
|
1320
1244
|
this._addSymbols(parseNode, priorWord, completionMap);
|
1321
1245
|
// Add keywords.
|
1322
|
-
this._findMatchingKeywords(Keywords.forVersion(this.
|
1246
|
+
this._findMatchingKeywords(Keywords.forVersion(this.execEnv.pythonVersion), priorWord).map((keyword) => {
|
1323
1247
|
if (completionMap.has(keyword)) {
|
1324
1248
|
return;
|
1325
1249
|
}
|
@@ -1331,11 +1255,11 @@ class CompletionProvider {
|
|
1331
1255
|
// Add auto-import suggestions from other modules.
|
1332
1256
|
// Ignore this check for privates, since they are not imported.
|
1333
1257
|
if (!priorWord.startsWith('_') && !this._itemToResolve) {
|
1334
|
-
this.
|
1258
|
+
this.addAutoImportCompletions(priorWord, similarityLimit, this.options.lazyEdit, completionMap);
|
1335
1259
|
}
|
1336
1260
|
// Add literal values if appropriate.
|
1337
1261
|
this._tryAddLiterals(parseNode, priorWord, priorText, postText, completionMap);
|
1338
|
-
return
|
1262
|
+
return completionMap;
|
1339
1263
|
}
|
1340
1264
|
_isIndexArgument(node) {
|
1341
1265
|
const currentNode = node.parent;
|
@@ -1349,16 +1273,16 @@ class CompletionProvider {
|
|
1349
1273
|
}
|
1350
1274
|
_addCallArgumentCompletions(parseNode, priorWord, priorText, postText, atArgument, completionMap) {
|
1351
1275
|
// If we're within the argument list of a call, add parameter names.
|
1352
|
-
const offset = (0, positionUtils_1.convertPositionToOffset)(this.
|
1353
|
-
const callInfo = (0, parseTreeUtils_1.getCallNodeAndActiveParameterIndex)(parseNode, offset, this.
|
1276
|
+
const offset = (0, positionUtils_1.convertPositionToOffset)(this.position, this.parseResults.tokenizerOutput.lines);
|
1277
|
+
const callInfo = (0, parseTreeUtils_1.getCallNodeAndActiveParameterIndex)(parseNode, offset, this.parseResults.tokenizerOutput.tokens);
|
1354
1278
|
if (!callInfo) {
|
1355
1279
|
return;
|
1356
1280
|
}
|
1357
|
-
const signatureInfo = this.
|
1281
|
+
const signatureInfo = this.evaluator.getCallSignatureInfo(callInfo.callNode, callInfo.activeIndex, callInfo.activeOrFake);
|
1358
1282
|
if (signatureInfo) {
|
1359
1283
|
// Are we past the call expression and within the argument list?
|
1360
|
-
const callNameEnd = (0, positionUtils_1.convertOffsetToPosition)(signatureInfo.callNode.leftExpression.start + signatureInfo.callNode.leftExpression.length, this.
|
1361
|
-
if ((0, textRange_1.comparePositions)(this.
|
1284
|
+
const callNameEnd = (0, positionUtils_1.convertOffsetToPosition)(signatureInfo.callNode.leftExpression.start + signatureInfo.callNode.leftExpression.length, this.parseResults.tokenizerOutput.lines);
|
1285
|
+
if ((0, textRange_1.comparePositions)(this.position, callNameEnd) > 0) {
|
1362
1286
|
if (!atArgument) {
|
1363
1287
|
this._addNamedParameters(signatureInfo, priorWord, completionMap);
|
1364
1288
|
}
|
@@ -1449,7 +1373,7 @@ class CompletionProvider {
|
|
1449
1373
|
if (member === null || member === void 0 ? void 0 : member.symbol.hasDeclarations()) {
|
1450
1374
|
const declaration = member.symbol.getDeclarations()[0];
|
1451
1375
|
if ((0, declaration_1.isFunctionDeclaration)(declaration) && declaration.isMethod) {
|
1452
|
-
const getItemType = (_b = this.
|
1376
|
+
const getItemType = (_b = this.evaluator.getTypeForDeclaration(declaration)) === null || _b === void 0 ? void 0 : _b.type;
|
1453
1377
|
if (getItemType && (0, types_1.isFunction)(getItemType) && getItemType.details.parameters.length === 2) {
|
1454
1378
|
return getItemType.details.parameters[1].type;
|
1455
1379
|
}
|
@@ -1459,7 +1383,7 @@ class CompletionProvider {
|
|
1459
1383
|
}
|
1460
1384
|
_getIndexerKeys(indexNode, invocationNode) {
|
1461
1385
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
1462
|
-
const baseType = this.
|
1386
|
+
const baseType = this.evaluator.getType(indexNode.baseExpression);
|
1463
1387
|
if (!baseType || !(0, types_1.isClassInstance)(baseType)) {
|
1464
1388
|
return [];
|
1465
1389
|
}
|
@@ -1475,7 +1399,7 @@ class CompletionProvider {
|
|
1475
1399
|
!types_1.ClassType.isEnumClass(v)) {
|
1476
1400
|
return;
|
1477
1401
|
}
|
1478
|
-
keys.push((0, typePrinter_1.printLiteralValue)(v, this.
|
1402
|
+
keys.push((0, typePrinter_1.printLiteralValue)(v, this.parseResults.tokenizerOutput.predominantSingleQuoteCharacter));
|
1479
1403
|
});
|
1480
1404
|
if (keys.length > 0) {
|
1481
1405
|
return keys;
|
@@ -1486,13 +1410,13 @@ class CompletionProvider {
|
|
1486
1410
|
return [];
|
1487
1411
|
}
|
1488
1412
|
// Must be local variable/parameter
|
1489
|
-
const declarations = (_a = this.
|
1413
|
+
const declarations = (_a = this.evaluator.getDeclarationsForNameNode(indexNode.baseExpression)) !== null && _a !== void 0 ? _a : [];
|
1490
1414
|
const declaration = declarations.length > 0 ? declarations[0] : undefined;
|
1491
1415
|
if (!declaration ||
|
1492
1416
|
(declaration.type !== 1 /* Variable */ && declaration.type !== 2 /* Parameter */)) {
|
1493
1417
|
return [];
|
1494
1418
|
}
|
1495
|
-
if (declaration.path !== this.
|
1419
|
+
if (declaration.path !== this.filePath) {
|
1496
1420
|
return [];
|
1497
1421
|
}
|
1498
1422
|
let startingNode = indexNode.baseExpression;
|
@@ -1504,7 +1428,7 @@ class CompletionProvider {
|
|
1504
1428
|
startingNode = scopeRoot;
|
1505
1429
|
}
|
1506
1430
|
}
|
1507
|
-
const results = documentSymbolCollector_1.DocumentSymbolCollector.collectFromNode(this.
|
1431
|
+
const results = documentSymbolCollector_1.DocumentSymbolCollector.collectFromNode(this.program, indexNode.baseExpression, this.cancellationToken, startingNode);
|
1508
1432
|
const keys = new Set();
|
1509
1433
|
for (const result of results) {
|
1510
1434
|
const node = ((_d = result.node.parent) === null || _d === void 0 ? void 0 : _d.nodeType) === 54 /* TypeAnnotation */ ? result.node.parent : result.node;
|
@@ -1513,7 +1437,7 @@ class CompletionProvider {
|
|
1513
1437
|
if (node.parent.rightExpression.nodeType === 15 /* Dictionary */) {
|
1514
1438
|
const dictionary = node.parent.rightExpression;
|
1515
1439
|
for (const entry of dictionary.entries.filter((e) => e.nodeType === 17 /* DictionaryKeyEntry */)) {
|
1516
|
-
const key = this.
|
1440
|
+
const key = this.parseResults.text
|
1517
1441
|
.substr(entry.keyExpression.start, entry.keyExpression.length)
|
1518
1442
|
.trim();
|
1519
1443
|
if (key.length > 0)
|
@@ -1522,13 +1446,13 @@ class CompletionProvider {
|
|
1522
1446
|
}
|
1523
1447
|
if (node.parent.rightExpression.nodeType === 9 /* Call */) {
|
1524
1448
|
const call = node.parent.rightExpression;
|
1525
|
-
const type = this.
|
1449
|
+
const type = this.evaluator.getType(call.leftExpression);
|
1526
1450
|
if (!type || !(0, types_1.isInstantiableClass)(type) || !types_1.ClassType.isBuiltIn(type, 'dict')) {
|
1527
1451
|
continue;
|
1528
1452
|
}
|
1529
1453
|
for (const arg of call.arguments) {
|
1530
1454
|
const key = (_h = (_g = arg.name) === null || _g === void 0 ? void 0 : _g.value.trim()) !== null && _h !== void 0 ? _h : '';
|
1531
|
-
const quote = this.
|
1455
|
+
const quote = this.parseResults.tokenizerOutput.predominantSingleQuoteCharacter;
|
1532
1456
|
if (key.length > 0) {
|
1533
1457
|
keys.add(`${quote}${key}${quote}`);
|
1534
1458
|
}
|
@@ -1538,19 +1462,19 @@ class CompletionProvider {
|
|
1538
1462
|
if (((_j = node.parent) === null || _j === void 0 ? void 0 : _j.nodeType) === 24 /* Index */ &&
|
1539
1463
|
node.parent.items.length === 1 &&
|
1540
1464
|
node.parent.items[0].valueExpression.nodeType !== 0 /* Error */ &&
|
1541
|
-
!
|
1465
|
+
!textRange_1.TextRange.containsRange(node.parent, invocationNode)) {
|
1542
1466
|
const indexArgument = node.parent.items[0];
|
1543
|
-
const key = this.
|
1467
|
+
const key = this.parseResults.text
|
1544
1468
|
.substr(indexArgument.valueExpression.start, indexArgument.valueExpression.length)
|
1545
1469
|
.trim();
|
1546
1470
|
if (key.length > 0)
|
1547
1471
|
keys.add(key);
|
1548
1472
|
}
|
1549
1473
|
}
|
1550
|
-
return
|
1474
|
+
return Array.from(keys);
|
1551
1475
|
}
|
1552
1476
|
_getLiteralCompletions(parseNode, offset, priorWord, priorText, postText) {
|
1553
|
-
if (this.
|
1477
|
+
if (this.options.triggerCharacter === '"' || this.options.triggerCharacter === "'") {
|
1554
1478
|
if (parseNode.start !== offset - 1) {
|
1555
1479
|
// If completion is triggered by typing " or ', it must be the one that starts a string
|
1556
1480
|
// literal. In another word, it can't be something inside of another string or comment
|
@@ -1561,7 +1485,7 @@ class CompletionProvider {
|
|
1561
1485
|
if (!this._tryAddLiterals(parseNode, priorWord, priorText, postText, completionMap)) {
|
1562
1486
|
return undefined;
|
1563
1487
|
}
|
1564
|
-
return
|
1488
|
+
return completionMap;
|
1565
1489
|
}
|
1566
1490
|
_tryAddLiterals(parseNode, priorWord, priorText, postText, completionMap) {
|
1567
1491
|
var _a, _b, _c, _d, _e, _f;
|
@@ -1579,7 +1503,7 @@ class CompletionProvider {
|
|
1579
1503
|
? parentAndChild.child
|
1580
1504
|
: undefined;
|
1581
1505
|
if (nodeForExpectedType) {
|
1582
|
-
const expectedTypeResult = this.
|
1506
|
+
const expectedTypeResult = this.evaluator.getExpectedType(nodeForExpectedType);
|
1583
1507
|
if (expectedTypeResult && (0, typeUtils_1.isLiteralTypeOrUnion)(expectedTypeResult.type)) {
|
1584
1508
|
this._addLiteralValuesForTargetType(expectedTypeResult.type, priorWord, priorText, postText, completionMap);
|
1585
1509
|
return true;
|
@@ -1648,7 +1572,7 @@ class CompletionProvider {
|
|
1648
1572
|
const comparison = parentAndChild.parent;
|
1649
1573
|
const supportedOperators = [2 /* Assign */, 12 /* Equals */, 28 /* NotEquals */];
|
1650
1574
|
if (comparison.nodeType === 7 /* BinaryOperation */ && supportedOperators.includes(comparison.operator)) {
|
1651
|
-
const type = this.
|
1575
|
+
const type = this.evaluator.getType(comparison.leftExpression);
|
1652
1576
|
if (type && (0, typeUtils_1.isLiteralTypeOrUnion)(type)) {
|
1653
1577
|
this._addLiteralValuesForTargetType(type, priorWord, priorText, postText, completionMap);
|
1654
1578
|
return true;
|
@@ -1658,7 +1582,7 @@ class CompletionProvider {
|
|
1658
1582
|
const assignmentExpression = parentAndChild.parent;
|
1659
1583
|
if (assignmentExpression.nodeType === 4 /* AssignmentExpression */ &&
|
1660
1584
|
assignmentExpression.rightExpression === parentAndChild.child) {
|
1661
|
-
const type = this.
|
1585
|
+
const type = this.evaluator.getType(assignmentExpression.name);
|
1662
1586
|
if (type && (0, typeUtils_1.isLiteralTypeOrUnion)(type)) {
|
1663
1587
|
this._addLiteralValuesForTargetType(type, priorWord, priorText, postText, completionMap);
|
1664
1588
|
return true;
|
@@ -1673,7 +1597,7 @@ class CompletionProvider {
|
|
1673
1597
|
caseNode.pattern.category === 11 /* MissingPattern */ &&
|
1674
1598
|
caseNode.suite === parentAndChild.child &&
|
1675
1599
|
((_c = caseNode.parent) === null || _c === void 0 ? void 0 : _c.nodeType) === 63 /* Match */) {
|
1676
|
-
const type = this.
|
1600
|
+
const type = this.evaluator.getType(caseNode.parent.subjectExpression);
|
1677
1601
|
if (type && (0, typeUtils_1.isLiteralTypeOrUnion)(type)) {
|
1678
1602
|
this._addLiteralValuesForTargetType(type, priorWord, priorText, postText, completionMap);
|
1679
1603
|
return true;
|
@@ -1688,15 +1612,15 @@ class CompletionProvider {
|
|
1688
1612
|
((_d = patternLiteral.parent) === null || _d === void 0 ? void 0 : _d.nodeType) === 66 /* PatternAs */ &&
|
1689
1613
|
((_e = patternLiteral.parent.parent) === null || _e === void 0 ? void 0 : _e.nodeType) === 64 /* Case */ &&
|
1690
1614
|
((_f = patternLiteral.parent.parent.parent) === null || _f === void 0 ? void 0 : _f.nodeType) === 63 /* Match */) {
|
1691
|
-
const type = this.
|
1615
|
+
const type = this.evaluator.getType(patternLiteral.parent.parent.parent.subjectExpression);
|
1692
1616
|
if (type && (0, typeUtils_1.isLiteralTypeOrUnion)(type)) {
|
1693
1617
|
this._addLiteralValuesForTargetType(type, priorWord, priorText, postText, completionMap);
|
1694
1618
|
return true;
|
1695
1619
|
}
|
1696
1620
|
}
|
1697
1621
|
if (parseNode.nodeType === 49 /* String */) {
|
1698
|
-
const offset = (0, positionUtils_1.convertPositionToOffset)(this.
|
1699
|
-
const atArgument = parseNode.parent.start < offset && offset <
|
1622
|
+
const offset = (0, positionUtils_1.convertPositionToOffset)(this.position, this.parseResults.tokenizerOutput.lines);
|
1623
|
+
const atArgument = parseNode.parent.start < offset && offset < textRange_1.TextRange.getEnd(parseNode);
|
1700
1624
|
this._addCallArgumentCompletions(parseNode, priorWord, priorText, postText, atArgument, completionMap);
|
1701
1625
|
return true;
|
1702
1626
|
}
|
@@ -1732,7 +1656,7 @@ class CompletionProvider {
|
|
1732
1656
|
const quoteInfo = this._getQuoteInfo(priorWord, priorText);
|
1733
1657
|
const excludes = new Set(existingKeys);
|
1734
1658
|
typedDicts.forEach((typedDict) => {
|
1735
|
-
(0, typedDicts_1.getTypedDictMembersForClass)(this.
|
1659
|
+
(0, typedDicts_1.getTypedDictMembersForClass)(this.evaluator, typedDict, /* allowNarrowed */ true).forEach((_, key) => {
|
1736
1660
|
// Unions of TypedDicts may define the same key.
|
1737
1661
|
if (excludes.has(key) || completionMap.has(key)) {
|
1738
1662
|
return;
|
@@ -1745,7 +1669,7 @@ class CompletionProvider {
|
|
1745
1669
|
}
|
1746
1670
|
_tryAddTypedDictKeysFromDictionary(dictionaryNode, stringNode, priorWord, priorText, postText, completionMap) {
|
1747
1671
|
var _a;
|
1748
|
-
const expectedTypeResult = this.
|
1672
|
+
const expectedTypeResult = this.evaluator.getExpectedType(dictionaryNode);
|
1749
1673
|
if (!expectedTypeResult) {
|
1750
1674
|
return false;
|
1751
1675
|
}
|
@@ -1759,7 +1683,7 @@ class CompletionProvider {
|
|
1759
1683
|
}
|
1760
1684
|
_tryNarrowTypedDicts(types, keys) {
|
1761
1685
|
const newTypes = types.flatMap((type) => {
|
1762
|
-
const entries = (0, typedDicts_1.getTypedDictMembersForClass)(this.
|
1686
|
+
const entries = (0, typedDicts_1.getTypedDictMembersForClass)(this.evaluator, type, /* allowNarrowed */ true);
|
1763
1687
|
for (let index = 0; index < keys.length; index++) {
|
1764
1688
|
if (!entries.has(keys[index])) {
|
1765
1689
|
return [];
|
@@ -1773,16 +1697,16 @@ class CompletionProvider {
|
|
1773
1697
|
}
|
1774
1698
|
return newTypes;
|
1775
1699
|
}
|
1776
|
-
// Find
|
1700
|
+
// Find quotation and string prefix to use for string literals
|
1777
1701
|
// completion under current context.
|
1778
1702
|
_getQuoteInfo(priorWord, priorText) {
|
1779
1703
|
let filterText = priorWord;
|
1780
1704
|
let stringValue = undefined;
|
1781
|
-
let quoteCharacter = this.
|
1705
|
+
let quoteCharacter = this.parseResults.tokenizerOutput.predominantSingleQuoteCharacter;
|
1782
1706
|
// If completion is not inside of the existing string literal
|
1783
1707
|
// ex) typedDict[ |<= here
|
1784
1708
|
// use default quotation char without any string prefix.
|
1785
|
-
if (!this.
|
1709
|
+
if (!this._stringLiteralContainer) {
|
1786
1710
|
return { priorWord, priorText, filterText, stringValue, quoteCharacter };
|
1787
1711
|
}
|
1788
1712
|
const singleQuote = "'";
|
@@ -1802,16 +1726,15 @@ class CompletionProvider {
|
|
1802
1726
|
quoteCharacter = doubleQuote;
|
1803
1727
|
}
|
1804
1728
|
}
|
1805
|
-
// If the
|
1806
|
-
//
|
1807
|
-
//
|
1808
|
-
//
|
1809
|
-
//
|
1810
|
-
//
|
1811
|
-
|
1812
|
-
|
1813
|
-
|
1814
|
-
quoteCharacter = this._insideStringLiteral.flags & 1 /* SingleQuote */ ? doubleQuote : singleQuote;
|
1729
|
+
// If the invocation position is within an f-string, use a double or
|
1730
|
+
// single quote that doesn't match the f-string. Prior to Python 3.12,
|
1731
|
+
// using the same quotation mark nested within an f-string was not
|
1732
|
+
// permitted. For example, f"..{typedDict[|<= here ]}", we need to use
|
1733
|
+
// single quotes. Note that this doesn't account for deeper nested
|
1734
|
+
// f-strings.
|
1735
|
+
if (this._stringLiteralContainer.flags & 64 /* Format */) {
|
1736
|
+
quoteCharacter =
|
1737
|
+
this._stringLiteralContainer.flags & 1 /* SingleQuote */ ? doubleQuote : singleQuote;
|
1815
1738
|
}
|
1816
1739
|
if (stringValue) {
|
1817
1740
|
filterText = stringValue;
|
@@ -1822,7 +1745,7 @@ class CompletionProvider {
|
|
1822
1745
|
if (!indexNode) {
|
1823
1746
|
return false;
|
1824
1747
|
}
|
1825
|
-
const baseType = this.
|
1748
|
+
const baseType = this.evaluator.getType(indexNode.baseExpression);
|
1826
1749
|
if (!baseType) {
|
1827
1750
|
return false;
|
1828
1751
|
}
|
@@ -1837,7 +1760,7 @@ class CompletionProvider {
|
|
1837
1760
|
const completionItem = vscode_languageserver_1.CompletionItem.create(valueWithQuotes);
|
1838
1761
|
completionItem.kind = vscode_languageserver_1.CompletionItemKind.Constant;
|
1839
1762
|
completionItem.sortText = this._makeSortText(SortCategory.LiteralValue, valueWithQuotes);
|
1840
|
-
let rangeStartCol = this.
|
1763
|
+
let rangeStartCol = this.position.character;
|
1841
1764
|
if (quoteInfo.stringValue !== undefined) {
|
1842
1765
|
rangeStartCol -= quoteInfo.stringValue.length + 1;
|
1843
1766
|
}
|
@@ -1846,80 +1769,23 @@ class CompletionProvider {
|
|
1846
1769
|
}
|
1847
1770
|
// If the text after the insertion point is the closing quote,
|
1848
1771
|
// replace it.
|
1849
|
-
let rangeEndCol = this.
|
1772
|
+
let rangeEndCol = this.position.character;
|
1850
1773
|
if (postText !== undefined) {
|
1851
1774
|
if (postText.startsWith(quoteInfo.quoteCharacter)) {
|
1852
1775
|
rangeEndCol++;
|
1853
1776
|
}
|
1854
1777
|
}
|
1855
1778
|
const range = {
|
1856
|
-
start: { line: this.
|
1857
|
-
end: { line: this.
|
1779
|
+
start: { line: this.position.line, character: rangeStartCol },
|
1780
|
+
end: { line: this.position.line, character: rangeEndCol },
|
1858
1781
|
};
|
1859
1782
|
completionItem.textEdit = vscode_languageserver_1.TextEdit.replace(range, valueWithQuotes);
|
1860
1783
|
completionItem.detail = detail;
|
1861
1784
|
completionMap.set(completionItem);
|
1862
1785
|
}
|
1863
1786
|
}
|
1864
|
-
_addAutoImportCompletions(priorWord, similarityLimit, lazyEdit, completionResults) {
|
1865
|
-
var _a, _b, _c;
|
1866
|
-
if (!this._configOptions.autoImportCompletions || !this._options.autoImport) {
|
1867
|
-
// If auto import on the server is turned off or this particular invocation
|
1868
|
-
// is turned off (ex, notebook), don't do any thing.
|
1869
|
-
return;
|
1870
|
-
}
|
1871
|
-
const moduleSymbolMap = this._autoImportMaps.getModuleSymbolsMap();
|
1872
|
-
const autoImporter = new autoImporter_1.AutoImporter(this._execEnv, this._importResolver, this._parseResults, this._position, completionResults.completionMap, moduleSymbolMap, {
|
1873
|
-
libraryMap: this._autoImportMaps.libraryMap,
|
1874
|
-
lazyEdit,
|
1875
|
-
importFormat: this._options.importFormat,
|
1876
|
-
});
|
1877
|
-
const results = [];
|
1878
|
-
const info = (_a = this._autoImportMaps.nameMap) === null || _a === void 0 ? void 0 : _a.get(priorWord);
|
1879
|
-
if (info && priorWord.length > 1 && !completionResults.completionMap.has(priorWord)) {
|
1880
|
-
(0, collectionUtils_1.appendArray)(results, autoImporter.getAutoImportCandidatesForAbbr(priorWord, info, this._cancellationToken));
|
1881
|
-
}
|
1882
|
-
results.push(...autoImporter.getAutoImportCandidates(priorWord, similarityLimit,
|
1883
|
-
/* abbrFromUsers */ undefined, this._cancellationToken));
|
1884
|
-
const perfInfo = autoImporter.getPerfInfo();
|
1885
|
-
const additionDuration = new timing_1.Duration();
|
1886
|
-
for (const result of results) {
|
1887
|
-
if (result.symbol) {
|
1888
|
-
this._addSymbol(result.name, result.symbol, priorWord, completionResults.completionMap, {
|
1889
|
-
extraCommitChars: true,
|
1890
|
-
autoImportSource: result.source,
|
1891
|
-
autoImportAlias: result.alias,
|
1892
|
-
edits: {
|
1893
|
-
textEdit: this._createReplaceEdits(priorWord, /* node */ undefined, result.insertionText),
|
1894
|
-
additionalTextEdits: result.edits,
|
1895
|
-
},
|
1896
|
-
});
|
1897
|
-
}
|
1898
|
-
else {
|
1899
|
-
this._addNameToCompletions((_b = result.alias) !== null && _b !== void 0 ? _b : result.name, (_c = result.kind) !== null && _c !== void 0 ? _c : vscode_languageserver_1.CompletionItemKind.Module, priorWord, completionResults.completionMap, {
|
1900
|
-
extraCommitChars: true,
|
1901
|
-
autoImportText: this._getAutoImportText(result.name, result.source, result.alias),
|
1902
|
-
edits: {
|
1903
|
-
textEdit: this._createReplaceEdits(priorWord, /* node */ undefined, result.insertionText),
|
1904
|
-
additionalTextEdits: result.edits,
|
1905
|
-
},
|
1906
|
-
});
|
1907
|
-
}
|
1908
|
-
}
|
1909
|
-
completionResults.autoImportInfo = {
|
1910
|
-
indexUsed: perfInfo.indexUsed,
|
1911
|
-
totalTimeInMS: perfInfo.totalInMs,
|
1912
|
-
moduleTimeInMS: perfInfo.moduleTimeInMS,
|
1913
|
-
indexTimeInMS: perfInfo.indexTimeInMS,
|
1914
|
-
importAliasTimeInMS: perfInfo.importAliasTimeInMS,
|
1915
|
-
itemCount: results.length,
|
1916
|
-
symbolCount: perfInfo.symbolCount,
|
1917
|
-
indexCount: perfInfo.indexCount,
|
1918
|
-
importAliasCount: perfInfo.importAliasCount,
|
1919
|
-
additionTimeInMS: additionDuration.getDurationInMilliseconds(),
|
1920
|
-
};
|
1921
|
-
}
|
1922
1787
|
_getImportFromCompletions(importFromNode, priorWord) {
|
1788
|
+
var _a;
|
1923
1789
|
// Don't attempt to provide completions for "from X import *".
|
1924
1790
|
if (importFromNode.isWildcardImport) {
|
1925
1791
|
return undefined;
|
@@ -1932,16 +1798,21 @@ class CompletionProvider {
|
|
1932
1798
|
}
|
1933
1799
|
const completionMap = new CompletionMap();
|
1934
1800
|
const resolvedPath = importInfo.resolvedPaths.length > 0 ? importInfo.resolvedPaths[importInfo.resolvedPaths.length - 1] : '';
|
1935
|
-
const
|
1936
|
-
if (
|
1937
|
-
|
1938
|
-
// Don't suggest built in symbols or ones that have already been imported.
|
1939
|
-
return (symbol.getDeclarations().some((d) => !(0, declaration_1.isIntrinsicDeclaration)(d)) &&
|
1940
|
-
!importFromNode.imports.find((imp) => imp.name.value === name));
|
1941
|
-
}, priorWord, importFromNode,
|
1942
|
-
/* isInImport */ true,
|
1943
|
-
/* boundObject */ undefined, completionMap);
|
1801
|
+
const parseResults = this.program.getParseResults(resolvedPath);
|
1802
|
+
if (!parseResults) {
|
1803
|
+
return completionMap;
|
1944
1804
|
}
|
1805
|
+
const symbolTable = (_a = AnalyzerNodeInfo.getScope(parseResults.parseTree)) === null || _a === void 0 ? void 0 : _a.symbolTable;
|
1806
|
+
if (!symbolTable) {
|
1807
|
+
return completionMap;
|
1808
|
+
}
|
1809
|
+
this._addSymbolsForSymbolTable(symbolTable, (symbol, name) => {
|
1810
|
+
// Don't suggest built in symbols or ones that have already been imported.
|
1811
|
+
return (symbol.getDeclarations().some((d) => !(0, declaration_1.isIntrinsicDeclaration)(d)) &&
|
1812
|
+
!importFromNode.imports.find((imp) => imp.name.value === name));
|
1813
|
+
}, priorWord, importFromNode,
|
1814
|
+
/* isInImport */ true,
|
1815
|
+
/* boundObject */ undefined, completionMap);
|
1945
1816
|
// Add the implicit imports.
|
1946
1817
|
importInfo.implicitImports.forEach((implImport) => {
|
1947
1818
|
if (!importFromNode.imports.find((imp) => imp.name.value === implImport.name)) {
|
@@ -1950,7 +1821,7 @@ class CompletionProvider {
|
|
1950
1821
|
});
|
1951
1822
|
}
|
1952
1823
|
});
|
1953
|
-
return
|
1824
|
+
return completionMap;
|
1954
1825
|
}
|
1955
1826
|
_findMatchingKeywords(keywordList, partialMatch) {
|
1956
1827
|
return keywordList.filter((keyword) => {
|
@@ -1984,8 +1855,8 @@ class CompletionProvider {
|
|
1984
1855
|
completionItem.kind = vscode_languageserver_1.CompletionItemKind.Variable;
|
1985
1856
|
const completionItemData = {
|
1986
1857
|
workspacePath: this._workspacePath,
|
1987
|
-
filePath: this.
|
1988
|
-
position: this.
|
1858
|
+
filePath: this.filePath,
|
1859
|
+
position: this.position,
|
1989
1860
|
};
|
1990
1861
|
completionItem.data = (0, lspUtils_1.toLSPAny)(completionItemData);
|
1991
1862
|
completionItem.sortText = this._makeSortText(SortCategory.NamedParameter, argName);
|
@@ -2024,7 +1895,7 @@ class CompletionProvider {
|
|
2024
1895
|
}
|
2025
1896
|
// If this is a class scope, add symbols from parent classes.
|
2026
1897
|
if (curNode.nodeType === 10 /* Class */) {
|
2027
|
-
const classType = this.
|
1898
|
+
const classType = this.evaluator.getTypeOfClass(curNode);
|
2028
1899
|
if (classType && (0, types_1.isInstantiableClass)(classType.classType)) {
|
2029
1900
|
classType.classType.details.mro.forEach((baseClass, index) => {
|
2030
1901
|
if ((0, types_1.isInstantiableClass)(baseClass)) {
|
@@ -2056,14 +1927,14 @@ class CompletionProvider {
|
|
2056
1927
|
// exported from this scope, don't include it in the
|
2057
1928
|
// suggestion list unless we are in the same file.
|
2058
1929
|
const hidden = !(0, symbolUtils_1.isVisibleExternally)(symbol) &&
|
2059
|
-
!symbol.getDeclarations().some((d) => (0, declarationUtils_1.isDefinedInFile)(d, this.
|
1930
|
+
!symbol.getDeclarations().some((d) => (0, declarationUtils_1.isDefinedInFile)(d, this.filePath));
|
2060
1931
|
if (!hidden && includeSymbolCallback(symbol, name)) {
|
2061
1932
|
// Don't add a symbol more than once. It may have already been
|
2062
1933
|
// added from an inner scope's symbol table.
|
2063
1934
|
if (!completionMap.has(name)) {
|
2064
1935
|
// Skip func parens for classes when not a direct assignment or an argument (passed as a value)
|
2065
1936
|
const skipForClass = !this._shouldShowAutoParensForClass(symbol, node);
|
2066
|
-
this.
|
1937
|
+
this.addSymbol(name, symbol, priorWord, completionMap, {
|
2067
1938
|
boundObjectOrClass,
|
2068
1939
|
funcParensDisabled: isInImport || insideTypeAnnotation || skipForClass,
|
2069
1940
|
extraCommitChars: !isInImport && !!priorWord,
|
@@ -2083,107 +1954,23 @@ class CompletionProvider {
|
|
2083
1954
|
return true;
|
2084
1955
|
}
|
2085
1956
|
// Otherwise only show when the class is being assigned to a variable.
|
2086
|
-
const nodeIndex = ParseTreeUtils.getTokenIndexAtLeft(this.
|
2087
|
-
const prevToken = ParseTreeUtils.getTokenAtIndex(this.
|
1957
|
+
const nodeIndex = ParseTreeUtils.getTokenIndexAtLeft(this.parseResults.tokenizerOutput.tokens, node.start);
|
1958
|
+
const prevToken = ParseTreeUtils.getTokenAtIndex(this.parseResults.tokenizerOutput.tokens, nodeIndex);
|
2088
1959
|
return (prevToken &&
|
2089
1960
|
prevToken.type === 9 /* Operator */ &&
|
2090
1961
|
prevToken.operatorType === 2 /* Assign */);
|
2091
1962
|
}
|
2092
|
-
_addSymbol(name, symbol, priorWord, completionMap, detail) {
|
2093
|
-
var _a, _b, _c, _d;
|
2094
|
-
let primaryDecl = (0, symbolUtils_1.getLastTypedDeclaredForSymbol)(symbol);
|
2095
|
-
if (!primaryDecl) {
|
2096
|
-
const declarations = symbol.getDeclarations();
|
2097
|
-
if (declarations.length > 0) {
|
2098
|
-
primaryDecl = declarations[declarations.length - 1];
|
2099
|
-
}
|
2100
|
-
}
|
2101
|
-
primaryDecl = primaryDecl
|
2102
|
-
? (_a = this._evaluator.resolveAliasDeclaration(primaryDecl, /* resolveLocalNames */ true)) !== null && _a !== void 0 ? _a : primaryDecl
|
2103
|
-
: undefined;
|
2104
|
-
const autoImportText = detail.autoImportSource
|
2105
|
-
? this._getAutoImportText(name, detail.autoImportSource, detail.autoImportAlias)
|
2106
|
-
: undefined;
|
2107
|
-
// Are we resolving a completion item? If so, see if this symbol
|
2108
|
-
// is the one that we're trying to match.
|
2109
|
-
if (this._itemToResolve) {
|
2110
|
-
const completionItemData = (0, lspUtils_1.fromLSPAny)(this._itemToResolve.data);
|
2111
|
-
if (completionItemData.symbolLabel !== name) {
|
2112
|
-
// It's not what we are looking for.
|
2113
|
-
return;
|
2114
|
-
}
|
2115
|
-
if (completionItemData.autoImportText) {
|
2116
|
-
if (completionItemData.autoImportText === (autoImportText === null || autoImportText === void 0 ? void 0 : autoImportText.importText) &&
|
2117
|
-
((_b = detail.edits) === null || _b === void 0 ? void 0 : _b.additionalTextEdits)) {
|
2118
|
-
this._itemToResolve.additionalTextEdits = (0, workspaceEditUtils_1.convertToTextEdits)(detail.edits.additionalTextEdits);
|
2119
|
-
}
|
2120
|
-
return;
|
2121
|
-
}
|
2122
|
-
// This call can be expensive to perform on every completion item
|
2123
|
-
// that we return, so we do it lazily in the "resolve" callback.
|
2124
|
-
const type = this._evaluator.getEffectiveTypeOfSymbol(symbol);
|
2125
|
-
if (!type) {
|
2126
|
-
// Can't resolve. so bail out.
|
2127
|
-
return;
|
2128
|
-
}
|
2129
|
-
const typeDetail = (0, completionProviderUtils_1.getTypeDetail)(this._evaluator, primaryDecl, type, name, detail, this._configOptions.functionSignatureDisplay);
|
2130
|
-
const documentation = (0, tooltipUtils_1.getDocumentationPartsForTypeAndDecl)(this._sourceMapper, type, primaryDecl, this._evaluator, {
|
2131
|
-
name,
|
2132
|
-
symbol,
|
2133
|
-
boundObjectOrClass: detail.boundObjectOrClass,
|
2134
|
-
});
|
2135
|
-
if (this._options.format === vscode_languageserver_1.MarkupKind.Markdown || this._options.format === vscode_languageserver_1.MarkupKind.PlainText) {
|
2136
|
-
this._itemToResolve.documentation = (0, completionProviderUtils_1.getCompletionItemDocumentation)(typeDetail, documentation, this._options.format);
|
2137
|
-
}
|
2138
|
-
else {
|
2139
|
-
(0, debug_1.fail)(`Unsupported markup type: ${this._options.format}`);
|
2140
|
-
}
|
2141
|
-
// Bail out. We don't need to add items to completion.
|
2142
|
-
return;
|
2143
|
-
}
|
2144
|
-
if (primaryDecl) {
|
2145
|
-
let itemKind = this._convertDeclarationTypeToItemKind(primaryDecl);
|
2146
|
-
// Handle enum members specially. Enum members normally look like
|
2147
|
-
// variables, but the are declared using assignment expressions
|
2148
|
-
// within an enum class.
|
2149
|
-
if (primaryDecl.type === 1 /* Variable */ &&
|
2150
|
-
detail.boundObjectOrClass &&
|
2151
|
-
(0, types_1.isInstantiableClass)(detail.boundObjectOrClass) &&
|
2152
|
-
types_1.ClassType.isEnumClass(detail.boundObjectOrClass) &&
|
2153
|
-
((_c = primaryDecl.node.parent) === null || _c === void 0 ? void 0 : _c.nodeType) === 3 /* Assignment */) {
|
2154
|
-
itemKind = vscode_languageserver_1.CompletionItemKind.EnumMember;
|
2155
|
-
}
|
2156
|
-
this._addNameToCompletions((_d = detail.autoImportAlias) !== null && _d !== void 0 ? _d : name, itemKind, priorWord, completionMap, {
|
2157
|
-
autoImportText,
|
2158
|
-
extraCommitChars: detail.extraCommitChars,
|
2159
|
-
funcParensDisabled: detail.funcParensDisabled,
|
2160
|
-
edits: detail.edits,
|
2161
|
-
});
|
2162
|
-
}
|
2163
|
-
else {
|
2164
|
-
// Does the symbol have no declaration but instead has a synthesized type?
|
2165
|
-
const synthesizedType = symbol.getSynthesizedType();
|
2166
|
-
if (synthesizedType) {
|
2167
|
-
const itemKind = this._convertTypeToItemKind(synthesizedType);
|
2168
|
-
this._addNameToCompletions(name, itemKind, priorWord, completionMap, {
|
2169
|
-
extraCommitChars: detail.extraCommitChars,
|
2170
|
-
funcParensDisabled: detail.funcParensDisabled,
|
2171
|
-
edits: detail.edits,
|
2172
|
-
});
|
2173
|
-
}
|
2174
|
-
}
|
2175
|
-
}
|
2176
1963
|
_getAutoImportText(importName, importFrom, importAlias) {
|
2177
1964
|
const autoImportText = (0, tooltipUtils_1.getAutoImportText)(importName, importFrom, importAlias);
|
2178
1965
|
let importText = '';
|
2179
|
-
if (this.
|
1966
|
+
if (this.options.format === vscode_languageserver_1.MarkupKind.Markdown) {
|
2180
1967
|
importText = `\`\`\`\n${autoImportText}\n\`\`\``;
|
2181
1968
|
}
|
2182
|
-
else if (this.
|
1969
|
+
else if (this.options.format === vscode_languageserver_1.MarkupKind.PlainText) {
|
2183
1970
|
importText = autoImportText;
|
2184
1971
|
}
|
2185
1972
|
else {
|
2186
|
-
(0, debug_1.fail)(`Unsupported markup type: ${this.
|
1973
|
+
(0, debug_1.fail)(`Unsupported markup type: ${this.options.format}`);
|
2187
1974
|
}
|
2188
1975
|
return {
|
2189
1976
|
source: importFrom !== null && importFrom !== void 0 ? importFrom : '',
|
@@ -2203,14 +1990,14 @@ class CompletionProvider {
|
|
2203
1990
|
const completionItem = vscode_languageserver_1.CompletionItem.create(name);
|
2204
1991
|
completionItem.kind = itemKind;
|
2205
1992
|
if (detail === null || detail === void 0 ? void 0 : detail.extraCommitChars) {
|
2206
|
-
this.
|
1993
|
+
this.addExtraCommitChar(completionItem);
|
2207
1994
|
}
|
2208
1995
|
const completionItemData = {
|
2209
1996
|
workspacePath: this._workspacePath,
|
2210
|
-
filePath: this.
|
2211
|
-
position: this.
|
1997
|
+
filePath: this.filePath,
|
1998
|
+
position: this.position,
|
2212
1999
|
};
|
2213
|
-
if ((detail === null || detail === void 0 ? void 0 : detail.funcParensDisabled) || !this.
|
2000
|
+
if ((detail === null || detail === void 0 ? void 0 : detail.funcParensDisabled) || !this.options.snippet) {
|
2214
2001
|
completionItemData.funcParensDisabled = true;
|
2215
2002
|
}
|
2216
2003
|
if (detail === null || detail === void 0 ? void 0 : detail.modulePath) {
|
@@ -2248,7 +2035,7 @@ class CompletionProvider {
|
|
2248
2035
|
completionItem.sortText = this._makeSortText(SortCategory.NormalSymbol, name);
|
2249
2036
|
}
|
2250
2037
|
completionItemData.symbolLabel = name;
|
2251
|
-
if (this.
|
2038
|
+
if (this.options.format === vscode_languageserver_1.MarkupKind.Markdown) {
|
2252
2039
|
let markdownString = '';
|
2253
2040
|
if (detail === null || detail === void 0 ? void 0 : detail.autoImportText) {
|
2254
2041
|
markdownString += detail.autoImportText.importText;
|
@@ -2272,7 +2059,7 @@ class CompletionProvider {
|
|
2272
2059
|
};
|
2273
2060
|
}
|
2274
2061
|
}
|
2275
|
-
else if (this.
|
2062
|
+
else if (this.options.format === vscode_languageserver_1.MarkupKind.PlainText) {
|
2276
2063
|
let plainTextString = '';
|
2277
2064
|
if (detail === null || detail === void 0 ? void 0 : detail.autoImportText) {
|
2278
2065
|
plainTextString += detail.autoImportText.importText;
|
@@ -2296,7 +2083,7 @@ class CompletionProvider {
|
|
2296
2083
|
}
|
2297
2084
|
}
|
2298
2085
|
else {
|
2299
|
-
(0, debug_1.fail)(`Unsupported markup type: ${this.
|
2086
|
+
(0, debug_1.fail)(`Unsupported markup type: ${this.options.format}`);
|
2300
2087
|
}
|
2301
2088
|
if ((_b = detail === null || detail === void 0 ? void 0 : detail.edits) === null || _b === void 0 ? void 0 : _b.format) {
|
2302
2089
|
completionItem.insertTextFormat = detail.edits.format;
|
@@ -2358,7 +2145,7 @@ class CompletionProvider {
|
|
2358
2145
|
return result;
|
2359
2146
|
}
|
2360
2147
|
_convertDeclarationTypeToItemKind(declaration) {
|
2361
|
-
const resolvedDeclaration = this.
|
2148
|
+
const resolvedDeclaration = this.evaluator.resolveAliasDeclaration(declaration, /* resolveLocalNames */ true);
|
2362
2149
|
if (!resolvedDeclaration) {
|
2363
2150
|
return vscode_languageserver_1.CompletionItemKind.Variable;
|
2364
2151
|
}
|
@@ -2379,7 +2166,7 @@ class CompletionProvider {
|
|
2379
2166
|
return vscode_languageserver_1.CompletionItemKind.Variable;
|
2380
2167
|
case 5 /* Function */: {
|
2381
2168
|
if (this._isPossiblePropertyDeclaration(resolvedDeclaration)) {
|
2382
|
-
const functionType = this.
|
2169
|
+
const functionType = this.evaluator.getTypeOfFunction(resolvedDeclaration.node);
|
2383
2170
|
if (functionType &&
|
2384
2171
|
(0, typeUtils_1.isMaybeDescriptorInstance)(functionType.decoratedType, /* requireSetter */ false)) {
|
2385
2172
|
return vscode_languageserver_1.CompletionItemKind.Property;
|
@@ -2417,9 +2204,9 @@ class CompletionProvider {
|
|
2417
2204
|
leadingDots: node.leadingDots,
|
2418
2205
|
hasTrailingDot: node.hasTrailingDot || false,
|
2419
2206
|
nameParts: node.nameParts.map((part) => part.value),
|
2420
|
-
importedSymbols:
|
2207
|
+
importedSymbols: new Set(),
|
2421
2208
|
};
|
2422
|
-
const completions = this.
|
2209
|
+
const completions = this.importResolver.getCompletionSuggestions(this.filePath, this.execEnv, moduleDescriptor);
|
2423
2210
|
const completionMap = new CompletionMap();
|
2424
2211
|
// If we're in the middle of a "from X import Y" statement, offer
|
2425
2212
|
// the "import" keyword as a completion.
|
@@ -2439,27 +2226,7 @@ class CompletionProvider {
|
|
2439
2226
|
modulePath,
|
2440
2227
|
});
|
2441
2228
|
});
|
2442
|
-
return
|
2443
|
-
}
|
2444
|
-
_getExtraCommitCharsForKind(kind) {
|
2445
|
-
switch (kind) {
|
2446
|
-
case vscode_languageserver_1.CompletionItemKind.Class:
|
2447
|
-
return ['.', '('];
|
2448
|
-
case vscode_languageserver_1.CompletionItemKind.Function:
|
2449
|
-
case vscode_languageserver_1.CompletionItemKind.Method:
|
2450
|
-
return ['('];
|
2451
|
-
case vscode_languageserver_1.CompletionItemKind.Module:
|
2452
|
-
case vscode_languageserver_1.CompletionItemKind.Enum:
|
2453
|
-
return ['.'];
|
2454
|
-
default:
|
2455
|
-
return [];
|
2456
|
-
}
|
2457
|
-
}
|
2458
|
-
_addExtraCommitChar(item, ...commitChars) {
|
2459
|
-
if (!this._options.extraCommitChars || commitChars.length === 0) {
|
2460
|
-
return;
|
2461
|
-
}
|
2462
|
-
item.commitCharacters = commitChars;
|
2229
|
+
return completionMap;
|
2463
2230
|
}
|
2464
2231
|
_isPossiblePropertyDeclaration(decl) {
|
2465
2232
|
// Do cheap check using only nodes that will cover 99.9% cases
|