mirror of
https://github.com/microsoft/pyright.git
synced 2024-09-11 16:06:39 +03:00
Merge branch 'move_declarations6'
This commit is contained in:
commit
361dbbd072
24
client/package-lock.json
generated
24
client/package-lock.json
generated
@ -5,9 +5,9 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "12.7.8",
|
"version": "12.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.1.tgz",
|
||||||
"integrity": "sha512-FMdVn84tJJdV+xe+53sYiZS4R5yn1mAIxfj+DVoNiQjTYz1+OYmjwEZr1ev9nU0axXwda0QDbYl06QHanRVH3A==",
|
"integrity": "sha512-TJtwsqZ39pqcljJpajeoofYRfeZ7/I/OMUQ5pR4q5wOKf2ocrUvBAZUMhWsOvKx3dVc/aaV5GluBivt0sWqA5A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"agent-base": {
|
"agent-base": {
|
||||||
@ -199,9 +199,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "2.20.1",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==",
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
@ -1016,9 +1016,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.6.3",
|
"version": "3.6.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz",
|
||||||
"integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==",
|
"integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"uc.micro": {
|
"uc.micro": {
|
||||||
@ -1082,9 +1082,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vsce": {
|
"vsce": {
|
||||||
"version": "1.66.0",
|
"version": "1.68.0",
|
||||||
"resolved": "https://registry.npmjs.org/vsce/-/vsce-1.66.0.tgz",
|
"resolved": "https://registry.npmjs.org/vsce/-/vsce-1.68.0.tgz",
|
||||||
"integrity": "sha512-Zf4+WD4PhEcOr7jkU08SI9lwFqDhmhk73YOCGQ/tNLaBy+PnnX4eSdqj9LdzDLuI2dsyomJLXzDSNgxuaInxCQ==",
|
"integrity": "sha512-yFbRYu4x4GbdQzZdEQQeRJBxgPdummgcUOFHUtnclW8XQl3MTuKgXL3TtI09gb5oq7jE6kdyvBmpBcmDGsmhcQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"azure-devops-node-api": "^7.2.0",
|
"azure-devops-node-api": "^7.2.0",
|
||||||
|
@ -104,8 +104,8 @@
|
|||||||
"postinstall": "node ./node_modules/vscode/bin/install"
|
"postinstall": "node ./node_modules/vscode/bin/install"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^3.6.3",
|
"typescript": "^3.6.4",
|
||||||
"vsce": "^1.66.0",
|
"vsce": "^1.68.0",
|
||||||
"vscode": "^1.1.36"
|
"vscode": "^1.1.36"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
12
package-lock.json
generated
12
package-lock.json
generated
@ -11,15 +11,15 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "11.13.21",
|
"version": "11.13.22",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.21.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.22.tgz",
|
||||||
"integrity": "sha512-fLwcSjMmDnjfk4FP7/QDiNzXSCEOGNvEe9eA6vaITmC784+Gm70wF7woaFQxUb2CpMjgLBhSPyhH0oIe1JS2uw==",
|
"integrity": "sha512-rOsaPRUGTOXbRBOKToy4cgZXY4Y+QSVhxcLwdEveozbk7yuudhWMpxxcaXqYizLMP3VY7OcWCFtx9lGFh5j5kg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.6.3",
|
"version": "3.6.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz",
|
||||||
"integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==",
|
"integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "^11.13.21",
|
"@types/node": "^11.13.22",
|
||||||
"typescript": "^3.6.3"
|
"typescript": "^3.6.4"
|
||||||
},
|
},
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
42
server/package-lock.json
generated
42
server/package-lock.json
generated
@ -484,9 +484,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/jest": {
|
"@types/jest": {
|
||||||
"version": "24.0.18",
|
"version": "24.0.19",
|
||||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.18.tgz",
|
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.19.tgz",
|
||||||
"integrity": "sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ==",
|
"integrity": "sha512-YYiqfSjocv7lk5H/T+v5MjATYjaTMsUkbDnjGqSMoO88jWdtJXJV4ST/7DKZcoMHMBvB2SeSfyOzZfkxXHR5xg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/jest-diff": "*"
|
"@types/jest-diff": "*"
|
||||||
@ -499,9 +499,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "11.13.21",
|
"version": "11.13.22",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.21.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.22.tgz",
|
||||||
"integrity": "sha512-fLwcSjMmDnjfk4FP7/QDiNzXSCEOGNvEe9eA6vaITmC784+Gm70wF7woaFQxUb2CpMjgLBhSPyhH0oIe1JS2uw==",
|
"integrity": "sha512-rOsaPRUGTOXbRBOKToy4cgZXY4Y+QSVhxcLwdEveozbk7yuudhWMpxxcaXqYizLMP3VY7OcWCFtx9lGFh5j5kg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/stack-utils": {
|
"@types/stack-utils": {
|
||||||
@ -1070,9 +1070,9 @@
|
|||||||
"integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow=="
|
"integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow=="
|
||||||
},
|
},
|
||||||
"bluebird": {
|
"bluebird": {
|
||||||
"version": "3.5.5",
|
"version": "3.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz",
|
||||||
"integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==",
|
"integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"bn.js": {
|
"bn.js": {
|
||||||
@ -6131,9 +6131,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"terser": {
|
"terser": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.9",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-4.3.9.tgz",
|
||||||
"integrity": "sha512-Kcrn3RiW8NtHBP0ssOAzwa2MsIRQ8lJWiBG/K7JgqPlomA3mtb2DEmp4/hrUA+Jujx+WZ02zqd7GYD+QRBB/2Q==",
|
"integrity": "sha512-NFGMpHjlzmyOtPL+fDw3G7+6Ueh/sz4mkaUYa4lJCxOPTNzd0Uj0aZJOmsDYoSQyfuVoWDMSWTPU3huyOm2zdA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"commander": "^2.20.0",
|
"commander": "^2.20.0",
|
||||||
@ -6415,9 +6415,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.6.3",
|
"version": "3.6.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.4.tgz",
|
||||||
"integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==",
|
"integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"typescript-char": {
|
"typescript-char": {
|
||||||
@ -6780,9 +6780,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"webpack": {
|
"webpack": {
|
||||||
"version": "4.41.0",
|
"version": "4.41.2",
|
||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.0.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz",
|
||||||
"integrity": "sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g==",
|
"integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@webassemblyjs/ast": "1.8.5",
|
"@webassemblyjs/ast": "1.8.5",
|
||||||
@ -6989,9 +6989,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
"integrity": "sha512-6gpP93MR+VOOehKbCPchro3wFZNSNmek8A2kbkOAZLIZAYx1KP/zAqwO0sOHi3xJEb+UBz8NaYt/17UNit1Q9w==",
|
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
|
@ -32,8 +32,8 @@
|
|||||||
"@types/chokidar": "^2.1.3",
|
"@types/chokidar": "^2.1.3",
|
||||||
"@types/command-line-args": "^5.0.0",
|
"@types/command-line-args": "^5.0.0",
|
||||||
"@types/fs-extra": "^5.1.0",
|
"@types/fs-extra": "^5.1.0",
|
||||||
"@types/jest": "^24.0.18",
|
"@types/jest": "^24.0.19",
|
||||||
"@types/node": "^11.13.21",
|
"@types/node": "^11.13.22",
|
||||||
"fs-extra": "^7.0.1",
|
"fs-extra": "^7.0.1",
|
||||||
"jest": "^24.9.0",
|
"jest": "^24.9.0",
|
||||||
"node-loader": "^0.6.0",
|
"node-loader": "^0.6.0",
|
||||||
@ -41,8 +41,8 @@
|
|||||||
"ts-loader": "^5.4.5",
|
"ts-loader": "^5.4.5",
|
||||||
"tslint": "^5.20.0",
|
"tslint": "^5.20.0",
|
||||||
"tslint-microsoft-contrib": "^6.2.0",
|
"tslint-microsoft-contrib": "^6.2.0",
|
||||||
"typescript": "^3.6.3",
|
"typescript": "^3.6.4",
|
||||||
"webpack": "^4.41.0",
|
"webpack": "^4.41.2",
|
||||||
"webpack-cli": "^3.3.9"
|
"webpack-cli": "^3.3.9"
|
||||||
},
|
},
|
||||||
"types": "out/main.d.ts",
|
"types": "out/main.d.ts",
|
||||||
|
@ -13,16 +13,22 @@ import StringMap from '../common/stringMap';
|
|||||||
import { TextRange } from '../common/textRange';
|
import { TextRange } from '../common/textRange';
|
||||||
import { TextRangeCollection } from '../common/textRangeCollection';
|
import { TextRangeCollection } from '../common/textRangeCollection';
|
||||||
import { Scope } from './scope';
|
import { Scope } from './scope';
|
||||||
import { ModuleType } from './types';
|
import { SymbolTable } from './symbol';
|
||||||
|
|
||||||
// Maps import paths to the parse tree for the imported module.
|
// Maps import paths to the symbol table for the imported module.
|
||||||
export type ImportMap = Map<string, ModuleType>;
|
export type ImportLookup = (filePath: string) => ImportLookupResult | undefined;
|
||||||
|
|
||||||
|
export interface ImportLookupResult {
|
||||||
|
symbolTable: SymbolTable;
|
||||||
|
docString?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AnalyzerFileInfo {
|
export interface AnalyzerFileInfo {
|
||||||
importMap: ImportMap;
|
importLookup: ImportLookup;
|
||||||
futureImports: StringMap<boolean>;
|
futureImports: StringMap<boolean>;
|
||||||
builtinsScope?: Scope;
|
builtinsScope?: Scope;
|
||||||
typingModulePath?: string;
|
typingModulePath?: string;
|
||||||
|
collectionsModulePath?: string;
|
||||||
diagnosticSink: TextRangeDiagnosticSink;
|
diagnosticSink: TextRangeDiagnosticSink;
|
||||||
executionEnvironment: ExecutionEnvironment;
|
executionEnvironment: ExecutionEnvironment;
|
||||||
diagnosticSettings: DiagnosticSettings;
|
diagnosticSettings: DiagnosticSettings;
|
||||||
|
@ -27,18 +27,18 @@ import StringMap from '../common/stringMap';
|
|||||||
import { TextRange } from '../common/textRange';
|
import { TextRange } from '../common/textRange';
|
||||||
import { AssignmentExpressionNode, AssignmentNode, AugmentedAssignmentExpressionNode,
|
import { AssignmentExpressionNode, AssignmentNode, AugmentedAssignmentExpressionNode,
|
||||||
AwaitExpressionNode, ClassNode, DelNode, ExceptNode, ExpressionNode, ForNode,
|
AwaitExpressionNode, ClassNode, DelNode, ExceptNode, ExpressionNode, ForNode,
|
||||||
FunctionNode, GlobalNode, IfNode, ImportAsNode, ImportFromAsNode, LambdaNode,
|
FunctionNode, GlobalNode, IfNode, ImportAsNode, ImportFromNode, LambdaNode,
|
||||||
ListComprehensionNode, ModuleNameNode, ModuleNode, NameNode, NonlocalNode, ParseNode,
|
ListComprehensionNode, ModuleNameNode, ModuleNode, NameNode, NonlocalNode,
|
||||||
ParseNodeArray, ParseNodeType, RaiseNode, StatementNode, StringListNode, SuiteNode,
|
ParseNode, ParseNodeArray, ParseNodeType, RaiseNode, StatementNode, StringListNode,
|
||||||
TryNode, TypeAnnotationExpressionNode, WhileNode, WithNode, YieldExpressionNode,
|
SuiteNode, TryNode, TypeAnnotationExpressionNode, WhileNode, WithNode,
|
||||||
YieldFromExpressionNode } from '../parser/parseNodes';
|
YieldExpressionNode, YieldFromExpressionNode } from '../parser/parseNodes';
|
||||||
import * as StringTokenUtils from '../parser/stringTokenUtils';
|
import * as StringTokenUtils from '../parser/stringTokenUtils';
|
||||||
import { StringTokenFlags } from '../parser/tokenizerTypes';
|
import { StringTokenFlags } from '../parser/tokenizerTypes';
|
||||||
import { AnalyzerFileInfo } from './analyzerFileInfo';
|
import { AnalyzerFileInfo } from './analyzerFileInfo';
|
||||||
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
|
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
|
||||||
import { DeclarationType } from './declaration';
|
import { AliasDeclaration, DeclarationType, ModuleLoaderActions } from './declaration';
|
||||||
import * as DocStringUtils from './docStringUtils';
|
import * as DocStringUtils from './docStringUtils';
|
||||||
import { ImportType } from './importResult';
|
import { ImplicitImport, ImportResult, ImportType } from './importResult';
|
||||||
import { defaultTypeSourceId, TypeSourceId } from './inferredType';
|
import { defaultTypeSourceId, TypeSourceId } from './inferredType';
|
||||||
import * as ParseTreeUtils from './parseTreeUtils';
|
import * as ParseTreeUtils from './parseTreeUtils';
|
||||||
import { ParseTreeWalker } from './parseTreeWalker';
|
import { ParseTreeWalker } from './parseTreeWalker';
|
||||||
@ -593,18 +593,171 @@ export abstract class Binder extends ParseTreeWalker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitImportAs(node: ImportAsNode): boolean {
|
visitImportAs(node: ImportAsNode): boolean {
|
||||||
if (node.alias) {
|
if (node.module.nameParts.length > 0) {
|
||||||
this._bindNameToScope(this._currentScope, node.alias.nameToken.value);
|
const firstNamePartValue = node.module.nameParts[0].nameToken.value;
|
||||||
} else if (node.module.nameParts.length > 0) {
|
|
||||||
this._bindNameToScope(this._currentScope, node.module.nameParts[0].nameToken.value);
|
let symbolName: string | undefined;
|
||||||
|
if (node.alias) {
|
||||||
|
// The symbol name is defined by the alias.
|
||||||
|
symbolName = node.alias.nameToken.value;
|
||||||
|
} else {
|
||||||
|
// There was no alias, so we need to use the first element of
|
||||||
|
// the name parts as the symbol.
|
||||||
|
symbolName = firstNamePartValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const symbol = this._bindNameToScope(this._currentScope, symbolName);
|
||||||
|
|
||||||
|
const importInfo = AnalyzerNodeInfo.getImportInfo(node.module);
|
||||||
|
assert(importInfo !== undefined);
|
||||||
|
|
||||||
|
if (importInfo && importInfo.isImportFound && importInfo.resolvedPaths.length > 0 && symbol) {
|
||||||
|
// See if there's already a matching alias delaration for this import.
|
||||||
|
// if so, we'll update it rather than creating a new one. This is required
|
||||||
|
// to handle cases where multiple import statements target the same
|
||||||
|
// starting symbol such as "import a.b.c" and "import a.d". In this case,
|
||||||
|
// we'll build a single declaration that describes the combined actions
|
||||||
|
// of both import statements, thus reflecting the behavior of the
|
||||||
|
// python module loader.
|
||||||
|
const existingDecl = symbol.getDeclarations().find(
|
||||||
|
decl => decl.type === DeclarationType.Alias &&
|
||||||
|
decl.firstNamePart === firstNamePartValue);
|
||||||
|
|
||||||
|
const newDecl: AliasDeclaration = existingDecl as AliasDeclaration || {
|
||||||
|
type: DeclarationType.Alias,
|
||||||
|
path: '',
|
||||||
|
range: getEmptyRange(),
|
||||||
|
firstNamePart: firstNamePartValue,
|
||||||
|
implicitImports: new Map<string, ModuleLoaderActions>()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the implicit imports for this module if it's the last
|
||||||
|
// name part we're resolving.
|
||||||
|
if (node.alias || node.module.nameParts.length === 1) {
|
||||||
|
newDecl.path = importInfo.resolvedPaths[importInfo.resolvedPaths.length - 1];
|
||||||
|
this._addImplicitImportsToLoaderActions(importInfo, newDecl);
|
||||||
|
} else {
|
||||||
|
// Fill in the remaining name parts.
|
||||||
|
let curLoaderActions: ModuleLoaderActions = newDecl;
|
||||||
|
|
||||||
|
for (let i = 1; i < node.module.nameParts.length; i++) {
|
||||||
|
if (i >= importInfo.resolvedPaths.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const namePartValue = node.module.nameParts[i].nameToken.value;
|
||||||
|
|
||||||
|
// Is there an existing loader action for this name?
|
||||||
|
let loaderActions = curLoaderActions.implicitImports.get(namePartValue);
|
||||||
|
if (!loaderActions) {
|
||||||
|
// Allocate a new loader action.
|
||||||
|
loaderActions = {
|
||||||
|
path: '',
|
||||||
|
implicitImports: new Map<string, ModuleLoaderActions>()
|
||||||
|
};
|
||||||
|
curLoaderActions.implicitImports.set(namePartValue, loaderActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the last name part we're resolving, add in the
|
||||||
|
// implicit imports as well.
|
||||||
|
if (i === node.module.nameParts.length - 1) {
|
||||||
|
loaderActions.path = importInfo.resolvedPaths[i];
|
||||||
|
this._addImplicitImportsToLoaderActions(importInfo, loaderActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
curLoaderActions = loaderActions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existingDecl) {
|
||||||
|
symbol.addDeclaration(newDecl);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitImportFromAs(node: ImportFromAsNode): boolean {
|
visitImportFrom(node: ImportFromNode): boolean {
|
||||||
const nameNode = node.alias || node.name;
|
const importInfo = AnalyzerNodeInfo.getImportInfo(node.module);
|
||||||
this._bindNameToScope(this._currentScope, nameNode.nameToken.value);
|
|
||||||
|
let resolvedPath = '';
|
||||||
|
if (importInfo && importInfo.isImportFound) {
|
||||||
|
resolvedPath = importInfo.resolvedPaths[importInfo.resolvedPaths.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.isWildcardImport) {
|
||||||
|
if (importInfo && importInfo.implicitImports) {
|
||||||
|
const lookupInfo = this._fileInfo.importLookup(resolvedPath);
|
||||||
|
if (lookupInfo) {
|
||||||
|
lookupInfo.symbolTable.forEach((_, name) => {
|
||||||
|
const symbol = this._bindNameToScope(this._currentScope, name);
|
||||||
|
if (symbol) {
|
||||||
|
const aliasDecl: AliasDeclaration = {
|
||||||
|
type: DeclarationType.Alias,
|
||||||
|
path: resolvedPath,
|
||||||
|
range: getEmptyRange(),
|
||||||
|
symbolName: name,
|
||||||
|
implicitImports: new Map<string, ModuleLoaderActions>()
|
||||||
|
};
|
||||||
|
symbol.addDeclaration(aliasDecl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also add all of the implicitly-imported modules for
|
||||||
|
// the import module.
|
||||||
|
importInfo.implicitImports.forEach(implicitImport => {
|
||||||
|
const symbol = this._bindNameToScope(this._currentScope, implicitImport.name);
|
||||||
|
if (symbol) {
|
||||||
|
const aliasDecl: AliasDeclaration = {
|
||||||
|
type: DeclarationType.Alias,
|
||||||
|
path: implicitImport.path,
|
||||||
|
range: getEmptyRange(),
|
||||||
|
implicitImports: new Map<string, ModuleLoaderActions>()
|
||||||
|
};
|
||||||
|
symbol.addDeclaration(aliasDecl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node.imports.forEach(importSymbolNode => {
|
||||||
|
const importedName = importSymbolNode.name.nameToken.value;
|
||||||
|
const nameNode = importSymbolNode.alias || importSymbolNode.name;
|
||||||
|
const symbol = this._bindNameToScope(this._currentScope, nameNode.nameToken.value);
|
||||||
|
|
||||||
|
if (symbol) {
|
||||||
|
let aliasDecl: AliasDeclaration | undefined;
|
||||||
|
|
||||||
|
// Is the import referring to an implicitly-imported module?
|
||||||
|
let implicitImport: ImplicitImport | undefined;
|
||||||
|
if (importInfo && importInfo.implicitImports) {
|
||||||
|
implicitImport = importInfo.implicitImports.find(imp => imp.name === importedName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (implicitImport) {
|
||||||
|
aliasDecl = {
|
||||||
|
type: DeclarationType.Alias,
|
||||||
|
path: implicitImport.path,
|
||||||
|
range: getEmptyRange(),
|
||||||
|
implicitImports: new Map<string, ModuleLoaderActions>()
|
||||||
|
};
|
||||||
|
} else if (resolvedPath) {
|
||||||
|
aliasDecl = {
|
||||||
|
type: DeclarationType.Alias,
|
||||||
|
path: resolvedPath,
|
||||||
|
range: getEmptyRange(),
|
||||||
|
symbolName: importedName,
|
||||||
|
implicitImports: new Map<string, ModuleLoaderActions>()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aliasDecl) {
|
||||||
|
symbol.addDeclaration(aliasDecl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -775,6 +928,20 @@ export abstract class Binder extends ParseTreeWalker {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _addImplicitImportsToLoaderActions(importResult: ImportResult, loaderActions: ModuleLoaderActions) {
|
||||||
|
importResult.implicitImports.forEach(implicitImport => {
|
||||||
|
const existingLoaderAction = loaderActions.implicitImports.get(implicitImport.name);
|
||||||
|
if (existingLoaderAction) {
|
||||||
|
existingLoaderAction.path = implicitImport.path;
|
||||||
|
} else {
|
||||||
|
loaderActions.implicitImports.set(implicitImport.name, {
|
||||||
|
path: implicitImport.path,
|
||||||
|
implicitImports: new Map<string, ModuleLoaderActions>()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Handles some special-case assignment statements that are found
|
// Handles some special-case assignment statements that are found
|
||||||
// within the typings.pyi file.
|
// within the typings.pyi file.
|
||||||
private _handleTypingStubAssignment(node: AssignmentNode) {
|
private _handleTypingStubAssignment(node: AssignmentNode) {
|
||||||
@ -943,6 +1110,8 @@ export abstract class Binder extends ParseTreeWalker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ModuleScopeBinder extends Binder {
|
export class ModuleScopeBinder extends Binder {
|
||||||
|
private _moduleDocString?: string;
|
||||||
|
|
||||||
constructor(node: ModuleNode, fileInfo: AnalyzerFileInfo) {
|
constructor(node: ModuleNode, fileInfo: AnalyzerFileInfo) {
|
||||||
super(node, fileInfo.builtinsScope ? ScopeType.Module : ScopeType.Builtin,
|
super(node, fileInfo.builtinsScope ? ScopeType.Module : ScopeType.Builtin,
|
||||||
fileInfo.builtinsScope, fileInfo);
|
fileInfo.builtinsScope, fileInfo);
|
||||||
@ -963,15 +1132,16 @@ export class ModuleScopeBinder extends Binder {
|
|||||||
this._addParentLinks(moduleNode, moduleNode.statements);
|
this._addParentLinks(moduleNode, moduleNode.statements);
|
||||||
this.walkMultiple(moduleNode.statements);
|
this.walkMultiple(moduleNode.statements);
|
||||||
|
|
||||||
// Associate the module's scope with the module type.
|
this._moduleDocString = this._getDocString((this._scopedNode as ModuleNode).statements);
|
||||||
const moduleType = ModuleType.create(this._currentScope.getSymbolTable(),
|
|
||||||
this._getDocString((this._scopedNode as ModuleNode).statements));
|
|
||||||
AnalyzerNodeInfo.setExpressionType(this._scopedNode, moduleType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bind() {
|
bind() {
|
||||||
this.bindDeferred();
|
this.bindDeferred();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getModuleDocString() {
|
||||||
|
return this._moduleDocString;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClassScopeBinder extends Binder {
|
export class ClassScopeBinder extends Binder {
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
import { DiagnosticTextRange } from '../common/diagnostic';
|
import { DiagnosticTextRange } from '../common/diagnostic';
|
||||||
import { ClassNode, ExpressionNode, FunctionNode, NameNode,
|
import { ClassNode, ExpressionNode, FunctionNode, NameNode,
|
||||||
ParameterNode, ParseNode, StringListNode } from '../parser/parseNodes';
|
ParameterNode, ParseNode, StringListNode } from '../parser/parseNodes';
|
||||||
import { ModuleType, Type } from './types';
|
import { Type } from './types';
|
||||||
|
|
||||||
export const enum DeclarationType {
|
export const enum DeclarationType {
|
||||||
BuiltIn,
|
BuiltIn,
|
||||||
@ -21,7 +21,6 @@ export const enum DeclarationType {
|
|||||||
Function,
|
Function,
|
||||||
Method,
|
Method,
|
||||||
Class,
|
Class,
|
||||||
Module,
|
|
||||||
Alias
|
Alias
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,26 +69,42 @@ export interface VariableDeclaration extends DeclarationBase {
|
|||||||
isConstant?: boolean;
|
isConstant?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModuleDeclaration extends DeclarationBase {
|
|
||||||
type: DeclarationType.Module;
|
|
||||||
moduleType: ModuleType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alias declarations are used for imports. They are resolved
|
// Alias declarations are used for imports. They are resolved
|
||||||
// after the binding phase.
|
// after the binding phase.
|
||||||
export interface AliasDeclaration extends DeclarationBase {
|
export interface AliasDeclaration extends DeclarationBase {
|
||||||
type: DeclarationType.Alias;
|
type: DeclarationType.Alias;
|
||||||
|
|
||||||
// If a symbol is present, the alias refers to the symbol
|
// If a symbolName is defined, the alias refers to a symbol
|
||||||
// within a module (whose path is defined in the 'path'
|
// within a resolved module (whose path is defined in the
|
||||||
// field). If symbolName is missing, the alias refers to
|
// 'path' field). If symbolName is missing, the alias refers
|
||||||
// the module itself.
|
// to the module itself.
|
||||||
symbolName?: string;
|
symbolName?: string;
|
||||||
|
|
||||||
// The resolved declaration.
|
// The first part of the multi-part name used in the import
|
||||||
resolvedDeclarations?: Declaration[];
|
// statement (e.g. for "import a.b.c", firstNamePart would
|
||||||
|
// be "a").
|
||||||
|
firstNamePart?: string;
|
||||||
|
|
||||||
|
// If the alias is targeting a module, multiple other modules
|
||||||
|
// may also need to be resolved and inserted implicitly into
|
||||||
|
// the module's namespace to emulate the behavior of the python
|
||||||
|
// module loader. This can be recursive (e.g. in the case of
|
||||||
|
// an "import a.b.c.d" statement).
|
||||||
|
implicitImports: Map<string, ModuleLoaderActions>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This interface represents a set of actions that the python loader
|
||||||
|
// performs when a module import is encountered.
|
||||||
|
export interface ModuleLoaderActions {
|
||||||
|
// The resolved path of the implicit import. This can be empty
|
||||||
|
// if the resolved path doesn't reference a module (e.g. it's
|
||||||
|
// a directory).
|
||||||
|
path: string;
|
||||||
|
|
||||||
|
// See comment for "implicitImports" field in AliasDeclaration.
|
||||||
|
implicitImports: Map<string, ModuleLoaderActions>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Declaration = BuiltInDeclaration | ClassDeclaration |
|
export type Declaration = BuiltInDeclaration | ClassDeclaration |
|
||||||
FunctionDeclaration | ParameterDeclaration | VariableDeclaration |
|
FunctionDeclaration | ParameterDeclaration | VariableDeclaration |
|
||||||
ModuleDeclaration | AliasDeclaration;
|
AliasDeclaration;
|
||||||
|
@ -9,12 +9,14 @@
|
|||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
|
|
||||||
|
import { getEmptyRange } from '../common/diagnostic';
|
||||||
import { NameNode, ParseNode, ParseNodeType } from '../parser/parseNodes';
|
import { NameNode, ParseNode, ParseNodeType } from '../parser/parseNodes';
|
||||||
|
import { ImportLookup } from './analyzerFileInfo';
|
||||||
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
|
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
|
||||||
import { AliasDeclaration, Declaration, DeclarationType } from './declaration';
|
import { AliasDeclaration, Declaration, DeclarationType, ModuleLoaderActions } from './declaration';
|
||||||
import * as ParseTreeUtils from './parseTreeUtils';
|
import * as ParseTreeUtils from './parseTreeUtils';
|
||||||
import { Symbol } from './symbol';
|
import { Symbol } from './symbol';
|
||||||
import { ClassType, ModuleType, ObjectType, Type, TypeCategory, UnknownType } from './types';
|
import { ClassType, ModuleType, ObjectType, Type, TypeCategory } from './types';
|
||||||
import * as TypeUtils from './typeUtils';
|
import * as TypeUtils from './typeUtils';
|
||||||
|
|
||||||
export function getDeclarationsForNameNode(node: NameNode): Declaration[] | undefined {
|
export function getDeclarationsForNameNode(node: NameNode): Declaration[] | undefined {
|
||||||
@ -51,6 +53,22 @@ export function getDeclarationsForNameNode(node: NameNode): Declaration[] | unde
|
|||||||
return subtype;
|
return subtype;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} else if (node.parent && node.parent.nodeType === ParseNodeType.ModuleName) {
|
||||||
|
const namePartIndex = node.parent.nameParts.findIndex(part => part === node);
|
||||||
|
const importInfo = AnalyzerNodeInfo.getImportInfo(node.parent);
|
||||||
|
if (namePartIndex >= 0 && importInfo && namePartIndex < importInfo.resolvedPaths.length) {
|
||||||
|
if (importInfo.resolvedPaths[namePartIndex]) {
|
||||||
|
// Synthesize an alias declaration for this name part. The only
|
||||||
|
// time this case is used is for the hover provider.
|
||||||
|
const aliasDeclaration: AliasDeclaration = {
|
||||||
|
type: DeclarationType.Alias,
|
||||||
|
path: importInfo.resolvedPaths[namePartIndex],
|
||||||
|
range: getEmptyRange(),
|
||||||
|
implicitImports: new Map<string, ModuleLoaderActions>()
|
||||||
|
};
|
||||||
|
declarations = [aliasDeclaration];
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const scopeNode = ParseTreeUtils.getScopeNodeForNode(node);
|
const scopeNode = ParseTreeUtils.getScopeNodeForNode(node);
|
||||||
if (scopeNode) {
|
if (scopeNode) {
|
||||||
@ -73,44 +91,65 @@ export function isFunctionOrMethodDeclaration(declaration: Declaration) {
|
|||||||
return declaration.type === DeclarationType.Method || declaration.type === DeclarationType.Function;
|
return declaration.type === DeclarationType.Method || declaration.type === DeclarationType.Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveDeclarationAliases(declaration: Declaration) {
|
// If the specified declaration is an alias declaration that points
|
||||||
let resolvedDeclaration: Declaration | undefined = declaration;
|
// to a symbol, it resolves the alias and looks up the symbol, then
|
||||||
const resolvedDeclarations: AliasDeclaration[] = [];
|
// returns the first declaration associated with that symbol. It does
|
||||||
|
// this recursively if necessary. If a symbol lookup fails, undefined
|
||||||
|
// is returned.
|
||||||
|
export function resolveAliasDeclaration(declaration: Declaration, importLookup: ImportLookup):
|
||||||
|
Declaration | undefined {
|
||||||
|
|
||||||
while (resolvedDeclaration && resolvedDeclaration.type === DeclarationType.Alias) {
|
let curDeclaration: Declaration | undefined = declaration;
|
||||||
// Detect circular dependencies.
|
const alreadyVisited: Declaration[] = [];
|
||||||
if (resolvedDeclarations.find(decl => decl === resolvedDeclaration)) {
|
|
||||||
|
while (true) {
|
||||||
|
if (curDeclaration.type !== DeclarationType.Alias) {
|
||||||
|
return curDeclaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!curDeclaration.symbolName) {
|
||||||
|
return curDeclaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lookupResult = importLookup(declaration.path);
|
||||||
|
if (!lookupResult) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolvedDeclarations.push(resolvedDeclaration);
|
const symbol = lookupResult.symbolTable.get(curDeclaration.symbolName);
|
||||||
resolvedDeclaration = resolvedDeclaration.resolvedDeclarations ?
|
if (!symbol) {
|
||||||
resolvedDeclaration.resolvedDeclarations[0] : undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolvedDeclaration;
|
const declarations = symbol.getDeclarations();
|
||||||
|
if (declarations.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
curDeclaration = declarations[0];
|
||||||
|
|
||||||
|
// Make sure we don't follow a circular list indefinitely.
|
||||||
|
if (alreadyVisited.find(decl => decl === curDeclaration)) {
|
||||||
|
return declaration;
|
||||||
|
}
|
||||||
|
alreadyVisited.push(curDeclaration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTypeForDeclaration(declaration: Declaration): Type | undefined {
|
export function getTypeForDeclaration(declaration: Declaration): Type | undefined {
|
||||||
const resolvedDeclaration = resolveDeclarationAliases(declaration);
|
switch (declaration.type) {
|
||||||
|
|
||||||
if (!resolvedDeclaration) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (resolvedDeclaration.type) {
|
|
||||||
case DeclarationType.BuiltIn:
|
case DeclarationType.BuiltIn:
|
||||||
return resolvedDeclaration.declaredType;
|
return declaration.declaredType;
|
||||||
|
|
||||||
case DeclarationType.Class:
|
case DeclarationType.Class:
|
||||||
return AnalyzerNodeInfo.getExpressionType(resolvedDeclaration.node.name);
|
return AnalyzerNodeInfo.getExpressionType(declaration.node.name);
|
||||||
|
|
||||||
case DeclarationType.Function:
|
case DeclarationType.Function:
|
||||||
case DeclarationType.Method:
|
case DeclarationType.Method:
|
||||||
return AnalyzerNodeInfo.getExpressionType(resolvedDeclaration.node.name);
|
return AnalyzerNodeInfo.getExpressionType(declaration.node.name);
|
||||||
|
|
||||||
case DeclarationType.Parameter: {
|
case DeclarationType.Parameter: {
|
||||||
let typeAnnotationNode = resolvedDeclaration.node.typeAnnotation;
|
let typeAnnotationNode = declaration.node.typeAnnotation;
|
||||||
if (typeAnnotationNode && typeAnnotationNode.nodeType === ParseNodeType.StringList) {
|
if (typeAnnotationNode && typeAnnotationNode.nodeType === ParseNodeType.StringList) {
|
||||||
typeAnnotationNode = typeAnnotationNode.typeAnnotation;
|
typeAnnotationNode = typeAnnotationNode.typeAnnotation;
|
||||||
}
|
}
|
||||||
@ -125,7 +164,7 @@ export function getTypeForDeclaration(declaration: Declaration): Type | undefine
|
|||||||
}
|
}
|
||||||
|
|
||||||
case DeclarationType.Variable: {
|
case DeclarationType.Variable: {
|
||||||
let typeAnnotationNode = resolvedDeclaration.typeAnnotationNode;
|
let typeAnnotationNode = declaration.typeAnnotationNode;
|
||||||
if (typeAnnotationNode && typeAnnotationNode.nodeType === ParseNodeType.StringList) {
|
if (typeAnnotationNode && typeAnnotationNode.nodeType === ParseNodeType.StringList) {
|
||||||
typeAnnotationNode = typeAnnotationNode.typeAnnotation;
|
typeAnnotationNode = typeAnnotationNode.typeAnnotation;
|
||||||
}
|
}
|
||||||
@ -140,20 +179,14 @@ export function getTypeForDeclaration(declaration: Declaration): Type | undefine
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DeclarationType.Module:
|
case DeclarationType.Alias: {
|
||||||
return resolvedDeclaration.moduleType;
|
return undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasTypeForDeclaration(declaration: Declaration, resolveAliases = true): boolean {
|
export function hasTypeForDeclaration(declaration: Declaration): boolean {
|
||||||
const resolvedDeclaration = resolveAliases ?
|
switch (declaration.type) {
|
||||||
resolveDeclarationAliases(declaration) : declaration;
|
|
||||||
|
|
||||||
if (!resolvedDeclaration) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (resolvedDeclaration.type) {
|
|
||||||
case DeclarationType.BuiltIn:
|
case DeclarationType.BuiltIn:
|
||||||
case DeclarationType.Class:
|
case DeclarationType.Class:
|
||||||
case DeclarationType.Function:
|
case DeclarationType.Function:
|
||||||
@ -161,13 +194,10 @@ export function hasTypeForDeclaration(declaration: Declaration, resolveAliases =
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case DeclarationType.Parameter:
|
case DeclarationType.Parameter:
|
||||||
return !!resolvedDeclaration.node.typeAnnotation;
|
return !!declaration.node.typeAnnotation;
|
||||||
|
|
||||||
case DeclarationType.Variable:
|
case DeclarationType.Variable:
|
||||||
return !!resolvedDeclaration.typeAnnotationNode;
|
return !!declaration.typeAnnotationNode;
|
||||||
|
|
||||||
case DeclarationType.Module:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case DeclarationType.Alias:
|
case DeclarationType.Alias:
|
||||||
return false;
|
return false;
|
||||||
|
@ -608,16 +608,12 @@ export class ExpressionEvaluator {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const moduleType = this._fileInfo.importMap.get(typingImportPath);
|
const lookupResult = this._fileInfo.importLookup(typingImportPath);
|
||||||
if (!moduleType) {
|
if (!lookupResult) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moduleType.category !== TypeCategory.Module) {
|
const symbol = lookupResult.symbolTable.get(symbolName);
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const symbol = ModuleType.getField(moduleType, symbolName);
|
|
||||||
if (!symbol) {
|
if (!symbol) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -23,14 +23,13 @@ import { Duration, timingStats } from '../common/timing';
|
|||||||
import { ModuleSymbolMap } from '../languageService/completionProvider';
|
import { ModuleSymbolMap } from '../languageService/completionProvider';
|
||||||
import { HoverResults } from '../languageService/hoverProvider';
|
import { HoverResults } from '../languageService/hoverProvider';
|
||||||
import { SignatureHelpResults } from '../languageService/signatureHelpProvider';
|
import { SignatureHelpResults } from '../languageService/signatureHelpProvider';
|
||||||
import { ImportMap } from './analyzerFileInfo';
|
import { ImportLookupResult } from './analyzerFileInfo';
|
||||||
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
|
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
|
||||||
import { CircularDependency } from './circularDependency';
|
import { CircularDependency } from './circularDependency';
|
||||||
import { ImportResolver } from './importResolver';
|
import { ImportResolver } from './importResolver';
|
||||||
import { ImportResult, ImportType } from './importResult';
|
import { ImportResult, ImportType } from './importResult';
|
||||||
import { Scope } from './scope';
|
import { Scope } from './scope';
|
||||||
import { SourceFile } from './sourceFile';
|
import { SourceFile } from './sourceFile';
|
||||||
import { ModuleType } from './types';
|
|
||||||
import { TypeStubWriter } from './typeStubWriter';
|
import { TypeStubWriter } from './typeStubWriter';
|
||||||
|
|
||||||
const _maxImportDepth = 256;
|
const _maxImportDepth = 256;
|
||||||
@ -308,7 +307,9 @@ export class Program {
|
|||||||
|
|
||||||
// Now do binding of the open files.
|
// Now do binding of the open files.
|
||||||
for (const sourceFileInfo of openFiles) {
|
for (const sourceFileInfo of openFiles) {
|
||||||
this._bindFile(sourceFileInfo, options, importResolver);
|
if (this._bindFile(sourceFileInfo, options, importResolver, isTimeElapsedOpenFiles)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (isTimeElapsedOpenFiles()) {
|
if (isTimeElapsedOpenFiles()) {
|
||||||
return true;
|
return true;
|
||||||
@ -505,11 +506,15 @@ export class Program {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Binds the specified file and all of its dependencies, recursively. If
|
||||||
|
// it runs out of time, it returns true. If it completes, it returns false.
|
||||||
private _bindFile(fileToAnalyze: SourceFileInfo,
|
private _bindFile(fileToAnalyze: SourceFileInfo,
|
||||||
options: ConfigOptions, importResolver: ImportResolver) {
|
options: ConfigOptions, importResolver: ImportResolver,
|
||||||
|
timeElapsedCallback: () => boolean,
|
||||||
|
recursionMap: Map<string, true> = new Map<string, true>()): boolean {
|
||||||
|
|
||||||
if (!this._isFileNeeded(fileToAnalyze) || !fileToAnalyze.sourceFile.isBindingRequired()) {
|
if (!this._isFileNeeded(fileToAnalyze) || !fileToAnalyze.sourceFile.isBindingRequired()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._parseFile(fileToAnalyze, options, importResolver);
|
this._parseFile(fileToAnalyze, options, importResolver);
|
||||||
@ -517,7 +522,11 @@ export class Program {
|
|||||||
// We need to parse and bind the builtins import first.
|
// We need to parse and bind the builtins import first.
|
||||||
let builtinsScope: Scope | undefined;
|
let builtinsScope: Scope | undefined;
|
||||||
if (fileToAnalyze.builtinsImport) {
|
if (fileToAnalyze.builtinsImport) {
|
||||||
this._bindFile(fileToAnalyze.builtinsImport, options, importResolver);
|
if (this._bindFile(fileToAnalyze.builtinsImport, options,
|
||||||
|
importResolver, timeElapsedCallback)) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the builtins scope to pass to the binding pass.
|
// Get the builtins scope to pass to the binding pass.
|
||||||
const parseResults = fileToAnalyze.builtinsImport.sourceFile.getParseResults();
|
const parseResults = fileToAnalyze.builtinsImport.sourceFile.getParseResults();
|
||||||
@ -525,22 +534,49 @@ export class Program {
|
|||||||
builtinsScope = AnalyzerNodeInfo.getScope(parseResults.parseTree);
|
builtinsScope = AnalyzerNodeInfo.getScope(parseResults.parseTree);
|
||||||
assert(builtinsScope !== undefined);
|
assert(builtinsScope !== undefined);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fileToAnalyze.sourceFile.bind(options, builtinsScope);
|
const filePath = fileToAnalyze.sourceFile.getFilePath();
|
||||||
}
|
if (recursionMap.has(filePath)) {
|
||||||
|
// Avoid infinite recursion for cyclical dependencies.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private _buildImportMap(sourceFileInfo: SourceFileInfo): ImportMap {
|
// Bind any other files that this file depends upon.
|
||||||
const importMap: ImportMap = new Map<string, ModuleType>();
|
recursionMap.set(filePath, true);
|
||||||
|
for (const importedFile of fileToAnalyze.imports) {
|
||||||
|
if (this._bindFile(importedFile, options, importResolver,
|
||||||
|
timeElapsedCallback, recursionMap)) {
|
||||||
|
|
||||||
for (const importedFileInfo of sourceFileInfo.imports) {
|
return true;
|
||||||
const moduleType = importedFileInfo.sourceFile.getModuleType();
|
}
|
||||||
if (moduleType) {
|
|
||||||
importMap.set(importedFileInfo.sourceFile.getFilePath(), moduleType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return importMap;
|
if (timeElapsedCallback()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileToAnalyze.sourceFile.bind(options, this._lookUpImport, builtinsScope);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _lookUpImport = (filePath: string): ImportLookupResult | undefined => {
|
||||||
|
const sourceFileInfo = this._sourceFileMap[filePath];
|
||||||
|
if (!sourceFileInfo) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const symbolTable = sourceFileInfo.sourceFile.getModuleSymbolTable();
|
||||||
|
if (!symbolTable) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const docString = sourceFileInfo.sourceFile.getModuleDocString();
|
||||||
|
|
||||||
|
return {
|
||||||
|
symbolTable,
|
||||||
|
docString
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a map of all modules within this program and the module-
|
// Build a map of all modules within this program and the module-
|
||||||
@ -550,9 +586,9 @@ export class Program {
|
|||||||
|
|
||||||
this._sourceFileList.forEach(fileInfo => {
|
this._sourceFileList.forEach(fileInfo => {
|
||||||
if (fileInfo !== sourceFileToExclude) {
|
if (fileInfo !== sourceFileToExclude) {
|
||||||
const moduleType = fileInfo.sourceFile.getModuleType();
|
const symbolTable = fileInfo.sourceFile.getModuleSymbolTable();
|
||||||
if (moduleType) {
|
if (symbolTable) {
|
||||||
moduleSymbolMap[fileInfo.sourceFile.getFilePath()] = moduleType.fields;
|
moduleSymbolMap[fileInfo.sourceFile.getFilePath()] = symbolTable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -590,15 +626,12 @@ export class Program {
|
|||||||
closureMap.set(fileToAnalyze.sourceFile.getFilePath(), false);
|
closureMap.set(fileToAnalyze.sourceFile.getFilePath(), false);
|
||||||
|
|
||||||
if (fileToAnalyze.sourceFile.isTypeAnalysisRequired()) {
|
if (fileToAnalyze.sourceFile.isTypeAnalysisRequired()) {
|
||||||
// Build the import map for the file.
|
|
||||||
const importMap = this._buildImportMap(fileToAnalyze);
|
|
||||||
|
|
||||||
// Do a type analysis pass and determine if any internal changes occurred
|
// Do a type analysis pass and determine if any internal changes occurred
|
||||||
// during the pass. If so, continue to analyze until it stops changing and
|
// during the pass. If so, continue to analyze until it stops changing and
|
||||||
// mark all of its dependencies as needing to be reanalyzed.
|
// mark all of its dependencies as needing to be reanalyzed.
|
||||||
let didAnalysisChange = false;
|
let didAnalysisChange = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
fileToAnalyze.sourceFile.doTypeAnalysis(options, importMap);
|
fileToAnalyze.sourceFile.doTypeAnalysis(options, this._lookUpImport);
|
||||||
|
|
||||||
if (!fileToAnalyze.sourceFile.isTypeAnalysisRequired()) {
|
if (!fileToAnalyze.sourceFile.isTypeAnalysisRequired()) {
|
||||||
break;
|
break;
|
||||||
@ -690,7 +723,10 @@ export class Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the file is parsed and bound.
|
// Make sure the file is parsed and bound.
|
||||||
this._bindFile(fileToAnalyze, options, importResolver);
|
if (this._bindFile(fileToAnalyze, options, importResolver, timeElapsedCallback)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (timeElapsedCallback()) {
|
if (timeElapsedCallback()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -840,7 +876,7 @@ export class Program {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sourceFile.getDefinitionsForPosition(position);
|
return sourceFile.getDefinitionsForPosition(position, this._lookUpImport);
|
||||||
}
|
}
|
||||||
|
|
||||||
getReferencesForPosition(filePath: string, position: DiagnosticTextPosition,
|
getReferencesForPosition(filePath: string, position: DiagnosticTextPosition,
|
||||||
@ -860,7 +896,7 @@ export class Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const referencesResult = sourceFileInfo.sourceFile.getReferencesForPosition(
|
const referencesResult = sourceFileInfo.sourceFile.getReferencesForPosition(
|
||||||
position, includeDeclaration);
|
position, includeDeclaration, this._lookUpImport);
|
||||||
|
|
||||||
if (!referencesResult) {
|
if (!referencesResult) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -878,7 +914,7 @@ export class Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
curSourceFileInfo.sourceFile.addReferences(referencesResult,
|
curSourceFileInfo.sourceFile.addReferences(referencesResult,
|
||||||
includeDeclaration);
|
includeDeclaration, this._lookUpImport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -889,7 +925,8 @@ export class Program {
|
|||||||
addSymbolsForDocument(filePath: string, symbolList: SymbolInformation[]) {
|
addSymbolsForDocument(filePath: string, symbolList: SymbolInformation[]) {
|
||||||
const sourceFileInfo = this._sourceFileMap[filePath];
|
const sourceFileInfo = this._sourceFileMap[filePath];
|
||||||
if (sourceFileInfo) {
|
if (sourceFileInfo) {
|
||||||
sourceFileInfo.sourceFile.addSymbolsForDocument(symbolList);
|
sourceFileInfo.sourceFile.addSymbolsForDocument(
|
||||||
|
symbolList, this._lookUpImport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -901,7 +938,8 @@ export class Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const sourceFileInfo of this._sourceFileList) {
|
for (const sourceFileInfo of this._sourceFileList) {
|
||||||
sourceFileInfo.sourceFile.addSymbolsForDocument(symbolList, query);
|
sourceFileInfo.sourceFile.addSymbolsForDocument(
|
||||||
|
symbolList, this._lookUpImport, query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -914,7 +952,7 @@ export class Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return sourceFileInfo.sourceFile.getHoverForPosition(position,
|
return sourceFileInfo.sourceFile.getHoverForPosition(position,
|
||||||
this._buildImportMap(sourceFileInfo));
|
this._lookUpImport);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSignatureHelpForPosition(filePath: string, position: DiagnosticTextPosition,
|
getSignatureHelpForPosition(filePath: string, position: DiagnosticTextPosition,
|
||||||
@ -955,7 +993,7 @@ export class Program {
|
|||||||
|
|
||||||
return sourceFileInfo.sourceFile.getCompletionsForPosition(
|
return sourceFileInfo.sourceFile.getCompletionsForPosition(
|
||||||
position, options, importResolver,
|
position, options, importResolver,
|
||||||
() => this._buildImportMap(sourceFileInfo),
|
this._lookUpImport,
|
||||||
() => this._buildModuleSymbolsMap(sourceFileInfo));
|
() => this._buildModuleSymbolsMap(sourceFileInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -989,7 +1027,7 @@ export class Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const referencesResult = sourceFileInfo.sourceFile.getReferencesForPosition(
|
const referencesResult = sourceFileInfo.sourceFile.getReferencesForPosition(
|
||||||
position, true);
|
position, true, this._lookUpImport);
|
||||||
|
|
||||||
if (!referencesResult) {
|
if (!referencesResult) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -1006,7 +1044,8 @@ export class Program {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
curSourceFileInfo.sourceFile.addReferences(referencesResult, true);
|
curSourceFileInfo.sourceFile.addReferences(referencesResult,
|
||||||
|
true, this._lookUpImport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1178,30 +1217,26 @@ export class Program {
|
|||||||
const newImportPathMap = new Map<string, UpdateImportInfo>();
|
const newImportPathMap = new Map<string, UpdateImportInfo>();
|
||||||
imports.forEach(importResult => {
|
imports.forEach(importResult => {
|
||||||
if (importResult.isImportFound) {
|
if (importResult.isImportFound) {
|
||||||
if (!this._isImportAllowed(sourceFileInfo, importResult, importResult.isStubFile)) {
|
if (this._isImportAllowed(sourceFileInfo, importResult, importResult.isStubFile)) {
|
||||||
return;
|
if (importResult.resolvedPaths.length > 0) {
|
||||||
}
|
const filePath = importResult.resolvedPaths[
|
||||||
|
importResult.resolvedPaths.length - 1];
|
||||||
if (importResult.resolvedPaths.length > 0) {
|
if (filePath) {
|
||||||
const filePath = importResult.resolvedPaths[
|
newImportPathMap.set(filePath, {
|
||||||
importResult.resolvedPaths.length - 1];
|
isTypeshedFile: !!importResult.isTypeshedFile,
|
||||||
if (filePath) {
|
isThirdPartyImport: importResult.importType === ImportType.ThirdParty
|
||||||
newImportPathMap.set(filePath, {
|
});
|
||||||
isTypeshedFile: !!importResult.isTypeshedFile,
|
}
|
||||||
isThirdPartyImport: importResult.importType === ImportType.ThirdParty
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
importResult.implicitImports.forEach(implicitImport => {
|
importResult.implicitImports.forEach(implicitImport => {
|
||||||
if (!this._isImportAllowed(sourceFileInfo, importResult, implicitImport.isStubFile)) {
|
if (this._isImportAllowed(sourceFileInfo, importResult, implicitImport.isStubFile)) {
|
||||||
return;
|
newImportPathMap.set(implicitImport.path, {
|
||||||
|
isTypeshedFile: !!importResult.isTypeshedFile,
|
||||||
|
isThirdPartyImport: importResult.importType === ImportType.ThirdParty
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
newImportPathMap.set(implicitImport.path, {
|
|
||||||
isTypeshedFile: !!importResult.isTypeshedFile,
|
|
||||||
isThirdPartyImport: importResult.importType === ImportType.ThirdParty
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
} else if (options.verboseOutput) {
|
} else if (options.verboseOutput) {
|
||||||
if (!sourceFileInfo.isTypeshedFile || options.diagnosticSettings.reportTypeshedErrors) {
|
if (!sourceFileInfo.isTypeshedFile || options.diagnosticSettings.reportTypeshedErrors) {
|
||||||
|
@ -34,7 +34,7 @@ import { SignatureHelpProvider, SignatureHelpResults } from '../languageService/
|
|||||||
import { ModuleNode } from '../parser/parseNodes';
|
import { ModuleNode } from '../parser/parseNodes';
|
||||||
import { ModuleImport, ParseOptions, Parser, ParseResults } from '../parser/parser';
|
import { ModuleImport, ParseOptions, Parser, ParseResults } from '../parser/parser';
|
||||||
import { Token } from '../parser/tokenizerTypes';
|
import { Token } from '../parser/tokenizerTypes';
|
||||||
import { AnalyzerFileInfo, ImportMap } from './analyzerFileInfo';
|
import { AnalyzerFileInfo, ImportLookup } from './analyzerFileInfo';
|
||||||
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
|
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
|
||||||
import { ModuleScopeBinder } from './binder';
|
import { ModuleScopeBinder } from './binder';
|
||||||
import { CircularDependency } from './circularDependency';
|
import { CircularDependency } from './circularDependency';
|
||||||
@ -43,9 +43,9 @@ import { ImportResolver } from './importResolver';
|
|||||||
import { ImportResult } from './importResult';
|
import { ImportResult } from './importResult';
|
||||||
import { ParseTreeCleanerWalker } from './parseTreeCleaner';
|
import { ParseTreeCleanerWalker } from './parseTreeCleaner';
|
||||||
import { Scope } from './scope';
|
import { Scope } from './scope';
|
||||||
|
import { SymbolTable } from './symbol';
|
||||||
import { TestWalker } from './testWalker';
|
import { TestWalker } from './testWalker';
|
||||||
import { TypeAnalyzer } from './typeAnalyzer';
|
import { TypeAnalyzer } from './typeAnalyzer';
|
||||||
import { ModuleType, TypeCategory } from './types';
|
|
||||||
|
|
||||||
const _maxImportCyclesPerFile = 4;
|
const _maxImportCyclesPerFile = 4;
|
||||||
|
|
||||||
@ -107,7 +107,8 @@ export class SourceFile {
|
|||||||
private _parseTreeNeedsCleaning = false;
|
private _parseTreeNeedsCleaning = false;
|
||||||
|
|
||||||
private _parseResults?: ParseResults;
|
private _parseResults?: ParseResults;
|
||||||
private _moduleType?: ModuleType;
|
private _moduleSymbolTable?: SymbolTable;
|
||||||
|
private _moduleDocString?: string;
|
||||||
|
|
||||||
// Diagnostics generated during different phases of analysis.
|
// Diagnostics generated during different phases of analysis.
|
||||||
private _parseDiagnostics: Diagnostic[] = [];
|
private _parseDiagnostics: Diagnostic[] = [];
|
||||||
@ -144,6 +145,7 @@ export class SourceFile {
|
|||||||
private _imports?: ImportResult[];
|
private _imports?: ImportResult[];
|
||||||
private _builtinsImport?: ImportResult;
|
private _builtinsImport?: ImportResult;
|
||||||
private _typingModulePath?: string;
|
private _typingModulePath?: string;
|
||||||
|
private _collectionsModulePath?: string;
|
||||||
|
|
||||||
constructor(filePath: string, isTypeshedStubFile: boolean, isThirdPartyImport: boolean,
|
constructor(filePath: string, isTypeshedStubFile: boolean, isThirdPartyImport: boolean,
|
||||||
console?: ConsoleInterface) {
|
console?: ConsoleInterface) {
|
||||||
@ -280,8 +282,12 @@ export class SourceFile {
|
|||||||
return this._builtinsImport;
|
return this._builtinsImport;
|
||||||
}
|
}
|
||||||
|
|
||||||
getModuleType(): ModuleType | undefined {
|
getModuleSymbolTable(): SymbolTable | undefined {
|
||||||
return this._moduleType;
|
return this._moduleSymbolTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
getModuleDocString(): string | undefined {
|
||||||
|
return this._moduleDocString;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicates whether the contents of the file have changed since
|
// Indicates whether the contents of the file have changed since
|
||||||
@ -318,7 +324,8 @@ export class SourceFile {
|
|||||||
this._fileContentsVersion++;
|
this._fileContentsVersion++;
|
||||||
this._isTypeAnalysisFinalized = false;
|
this._isTypeAnalysisFinalized = false;
|
||||||
this._isTypeAnalysisPassNeeded = true;
|
this._isTypeAnalysisPassNeeded = true;
|
||||||
this._moduleType = undefined;
|
this._moduleSymbolTable = undefined;
|
||||||
|
this._moduleDocString = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
markReanalysisRequired(): void {
|
markReanalysisRequired(): void {
|
||||||
@ -327,6 +334,14 @@ export class SourceFile {
|
|||||||
this._typeAnalysisPassNumber = 1;
|
this._typeAnalysisPassNumber = 1;
|
||||||
this._isTypeAnalysisFinalized = false;
|
this._isTypeAnalysisFinalized = false;
|
||||||
this._isTypeAnalysisPassNeeded = true;
|
this._isTypeAnalysisPassNeeded = true;
|
||||||
|
|
||||||
|
// If the file continas a wildcard import, we need to rebind
|
||||||
|
// also because the dependent import may have changed.
|
||||||
|
if (this._parseResults && this._parseResults.containsWildcardImport) {
|
||||||
|
this._isBindingNeeded = true;
|
||||||
|
this._moduleSymbolTable = undefined;
|
||||||
|
this._moduleDocString = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setClientVersion(version: number | null, contents: string): void {
|
setClientVersion(version: number | null, contents: string): void {
|
||||||
@ -450,7 +465,7 @@ export class SourceFile {
|
|||||||
|
|
||||||
// Resolve imports.
|
// Resolve imports.
|
||||||
timingStats.resolveImportsTime.timeOperation(() => {
|
timingStats.resolveImportsTime.timeOperation(() => {
|
||||||
[this._imports, this._builtinsImport, this._typingModulePath] =
|
[this._imports, this._builtinsImport, this._typingModulePath, this._collectionsModulePath] =
|
||||||
this._resolveImports(importResolver, parseResults.importedModules, execEnvironment);
|
this._resolveImports(importResolver, parseResults.importedModules, execEnvironment);
|
||||||
this._parseDiagnostics = diagSink.diagnostics;
|
this._parseDiagnostics = diagSink.diagnostics;
|
||||||
});
|
});
|
||||||
@ -481,7 +496,8 @@ export class SourceFile {
|
|||||||
typeIgnoreLines: {},
|
typeIgnoreLines: {},
|
||||||
predominantEndOfLineSequence: '\n',
|
predominantEndOfLineSequence: '\n',
|
||||||
predominantTabSequence: ' '
|
predominantTabSequence: ' '
|
||||||
}
|
},
|
||||||
|
containsWildcardImport: false
|
||||||
};
|
};
|
||||||
this._imports = undefined;
|
this._imports = undefined;
|
||||||
this._builtinsImport = undefined;
|
this._builtinsImport = undefined;
|
||||||
@ -502,18 +518,20 @@ export class SourceFile {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefinitionsForPosition(position: DiagnosticTextPosition): DocumentTextRange[] | undefined {
|
getDefinitionsForPosition(position: DiagnosticTextPosition, importLookup: ImportLookup):
|
||||||
|
DocumentTextRange[] | undefined {
|
||||||
|
|
||||||
// If we have no completed analysis job, there's nothing to do.
|
// If we have no completed analysis job, there's nothing to do.
|
||||||
if (!this._parseResults) {
|
if (!this._parseResults) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefinitionProvider.getDefinitionsForPosition(
|
return DefinitionProvider.getDefinitionsForPosition(
|
||||||
this._parseResults, position);
|
this._parseResults, position, importLookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
getReferencesForPosition(position: DiagnosticTextPosition, includeDeclaration: boolean):
|
getReferencesForPosition(position: DiagnosticTextPosition, includeDeclaration: boolean,
|
||||||
ReferencesResult | undefined {
|
importLookup: ImportLookup): ReferencesResult | undefined {
|
||||||
|
|
||||||
// If we have no completed analysis job, there's nothing to do.
|
// If we have no completed analysis job, there's nothing to do.
|
||||||
if (!this._parseResults) {
|
if (!this._parseResults) {
|
||||||
@ -521,37 +539,43 @@ export class SourceFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ReferencesProvider.getReferencesForPosition(
|
return ReferencesProvider.getReferencesForPosition(
|
||||||
this._parseResults, this._filePath, position, includeDeclaration);
|
this._parseResults, this._filePath, position, includeDeclaration, importLookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
addReferences(referencesResult: ReferencesResult, includeDeclaration: boolean): void {
|
addReferences(referencesResult: ReferencesResult, includeDeclaration: boolean,
|
||||||
|
importLookup: ImportLookup): void {
|
||||||
|
|
||||||
// If we have no completed analysis job, there's nothing to do.
|
// If we have no completed analysis job, there's nothing to do.
|
||||||
if (!this._parseResults) {
|
if (!this._parseResults) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReferencesProvider.addReferences(
|
ReferencesProvider.addReferences(
|
||||||
this._parseResults, this._filePath, referencesResult, includeDeclaration);
|
this._parseResults, this._filePath, referencesResult, includeDeclaration, importLookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
addSymbolsForDocument(symbolList: SymbolInformation[], query?: string) {
|
addSymbolsForDocument(symbolList: SymbolInformation[], importLookup: ImportLookup,
|
||||||
|
query?: string) {
|
||||||
|
|
||||||
// If we have no completed analysis job, there's nothing to do.
|
// If we have no completed analysis job, there's nothing to do.
|
||||||
if (!this._parseResults) {
|
if (!this._parseResults) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentSymbolProvider.addSymbolsForDocument(symbolList, query,
|
DocumentSymbolProvider.addSymbolsForDocument(symbolList, query,
|
||||||
this._filePath, this._parseResults);
|
this._filePath, this._parseResults, importLookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
getHoverForPosition(position: DiagnosticTextPosition, importMap: ImportMap): HoverResults | undefined {
|
getHoverForPosition(position: DiagnosticTextPosition,
|
||||||
|
importLookup: ImportLookup): HoverResults | undefined {
|
||||||
|
|
||||||
// If we have no completed analysis job, there's nothing to do.
|
// If we have no completed analysis job, there's nothing to do.
|
||||||
if (!this._parseResults) {
|
if (!this._parseResults) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return HoverProvider.getHoverForPosition(
|
return HoverProvider.getHoverForPosition(
|
||||||
this._parseResults, position, importMap);
|
this._parseResults, position, importLookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSignatureHelpForPosition(position: DiagnosticTextPosition): SignatureHelpResults | undefined {
|
getSignatureHelpForPosition(position: DiagnosticTextPosition): SignatureHelpResults | undefined {
|
||||||
@ -572,7 +596,7 @@ export class SourceFile {
|
|||||||
|
|
||||||
getCompletionsForPosition(position: DiagnosticTextPosition,
|
getCompletionsForPosition(position: DiagnosticTextPosition,
|
||||||
configOptions: ConfigOptions, importResolver: ImportResolver,
|
configOptions: ConfigOptions, importResolver: ImportResolver,
|
||||||
importMapCallback: () => ImportMap,
|
importLookup: ImportLookup,
|
||||||
moduleSymbolsCallback: () => ModuleSymbolMap): CompletionList | undefined {
|
moduleSymbolsCallback: () => ModuleSymbolMap): CompletionList | undefined {
|
||||||
|
|
||||||
// If we have no completed analysis job, there's nothing to do.
|
// If we have no completed analysis job, there's nothing to do.
|
||||||
@ -589,7 +613,7 @@ export class SourceFile {
|
|||||||
const completionProvider = new CompletionProvider(
|
const completionProvider = new CompletionProvider(
|
||||||
this._parseResults, this._fileContents,
|
this._parseResults, this._fileContents,
|
||||||
importResolver, position,
|
importResolver, position,
|
||||||
this._filePath, configOptions, importMapCallback,
|
this._filePath, configOptions, importLookup,
|
||||||
moduleSymbolsCallback);
|
moduleSymbolsCallback);
|
||||||
|
|
||||||
return completionProvider.getCompletionsForPosition();
|
return completionProvider.getCompletionsForPosition();
|
||||||
@ -623,7 +647,7 @@ export class SourceFile {
|
|||||||
this._isTypeAnalysisFinalized = false;
|
this._isTypeAnalysisFinalized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bind(configOptions: ConfigOptions, builtinsScope?: Scope) {
|
bind(configOptions: ConfigOptions, importLookup: ImportLookup, builtinsScope?: Scope) {
|
||||||
assert(!this.isParseRequired());
|
assert(!this.isParseRequired());
|
||||||
assert(this.isBindingRequired());
|
assert(this.isBindingRequired());
|
||||||
assert(this._parseResults);
|
assert(this._parseResults);
|
||||||
@ -631,7 +655,7 @@ export class SourceFile {
|
|||||||
try {
|
try {
|
||||||
// Perform name binding.
|
// Perform name binding.
|
||||||
timingStats.bindTime.timeOperation(() => {
|
timingStats.bindTime.timeOperation(() => {
|
||||||
const fileInfo = this._buildFileInfo(configOptions, undefined, builtinsScope);
|
const fileInfo = this._buildFileInfo(configOptions, importLookup, builtinsScope);
|
||||||
this._cleanParseTreeIfRequired();
|
this._cleanParseTreeIfRequired();
|
||||||
|
|
||||||
const binder = new ModuleScopeBinder(
|
const binder = new ModuleScopeBinder(
|
||||||
@ -648,10 +672,8 @@ export class SourceFile {
|
|||||||
this._bindDiagnostics = fileInfo.diagnosticSink.diagnostics;
|
this._bindDiagnostics = fileInfo.diagnosticSink.diagnostics;
|
||||||
const moduleScope = AnalyzerNodeInfo.getScope(this._parseResults!.parseTree);
|
const moduleScope = AnalyzerNodeInfo.getScope(this._parseResults!.parseTree);
|
||||||
assert(moduleScope !== undefined);
|
assert(moduleScope !== undefined);
|
||||||
const moduleType = AnalyzerNodeInfo.getExpressionType(
|
this._moduleSymbolTable = moduleScope!.getSymbolTable();
|
||||||
this._parseResults!.parseTree);
|
this._moduleDocString = binder.getModuleDocString();
|
||||||
assert(moduleType && moduleType.category === TypeCategory.Module);
|
|
||||||
this._moduleType = moduleType as ModuleType;
|
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const message: string = (e.stack ? e.stack.toString() : undefined) ||
|
const message: string = (e.stack ? e.stack.toString() : undefined) ||
|
||||||
@ -675,7 +697,7 @@ export class SourceFile {
|
|||||||
this._isBindingNeeded = false;
|
this._isBindingNeeded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
doTypeAnalysis(configOptions: ConfigOptions, importMap: ImportMap) {
|
doTypeAnalysis(configOptions: ConfigOptions, importLookup: ImportLookup) {
|
||||||
assert(!this.isParseRequired());
|
assert(!this.isParseRequired());
|
||||||
assert(!this.isBindingRequired());
|
assert(!this.isBindingRequired());
|
||||||
assert(this.isTypeAnalysisRequired());
|
assert(this.isTypeAnalysisRequired());
|
||||||
@ -683,7 +705,7 @@ export class SourceFile {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
timingStats.typeAnalyzerTime.timeOperation(() => {
|
timingStats.typeAnalyzerTime.timeOperation(() => {
|
||||||
const fileInfo = this._buildFileInfo(configOptions, importMap, undefined);
|
const fileInfo = this._buildFileInfo(configOptions, importLookup, undefined);
|
||||||
|
|
||||||
// Perform static type analysis.
|
// Perform static type analysis.
|
||||||
const typeAnalyzer = new TypeAnalyzer(this._parseResults!.parseTree,
|
const typeAnalyzer = new TypeAnalyzer(this._parseResults!.parseTree,
|
||||||
@ -741,15 +763,18 @@ export class SourceFile {
|
|||||||
this._diagnosticVersion++;
|
this._diagnosticVersion++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _buildFileInfo(configOptions: ConfigOptions, importMap?: ImportMap, builtinsScope?: Scope) {
|
private _buildFileInfo(configOptions: ConfigOptions, importLookup: ImportLookup,
|
||||||
|
builtinsScope?: Scope) {
|
||||||
|
|
||||||
assert(this._parseResults !== undefined);
|
assert(this._parseResults !== undefined);
|
||||||
const analysisDiagnostics = new TextRangeDiagnosticSink(this._parseResults!.tokenizerOutput.lines);
|
const analysisDiagnostics = new TextRangeDiagnosticSink(this._parseResults!.tokenizerOutput.lines);
|
||||||
|
|
||||||
const fileInfo: AnalyzerFileInfo = {
|
const fileInfo: AnalyzerFileInfo = {
|
||||||
importMap: importMap || new Map<string, ModuleType>(),
|
importLookup,
|
||||||
futureImports: this._parseResults!.futureImports,
|
futureImports: this._parseResults!.futureImports,
|
||||||
builtinsScope,
|
builtinsScope,
|
||||||
typingModulePath: this._typingModulePath,
|
typingModulePath: this._typingModulePath,
|
||||||
|
collectionsModulePath: this._collectionsModulePath,
|
||||||
diagnosticSink: analysisDiagnostics,
|
diagnosticSink: analysisDiagnostics,
|
||||||
executionEnvironment: configOptions.findExecEnvironment(this._filePath),
|
executionEnvironment: configOptions.findExecEnvironment(this._filePath),
|
||||||
diagnosticSettings: this._diagnosticSettings,
|
diagnosticSettings: this._diagnosticSettings,
|
||||||
@ -775,7 +800,7 @@ export class SourceFile {
|
|||||||
private _resolveImports(importResolver: ImportResolver,
|
private _resolveImports(importResolver: ImportResolver,
|
||||||
moduleImports: ModuleImport[],
|
moduleImports: ModuleImport[],
|
||||||
execEnv: ExecutionEnvironment):
|
execEnv: ExecutionEnvironment):
|
||||||
[ImportResult[], ImportResult?, string?] {
|
[ImportResult[], ImportResult?, string?, string?] {
|
||||||
|
|
||||||
const imports: ImportResult[] = [];
|
const imports: ImportResult[] = [];
|
||||||
|
|
||||||
@ -817,6 +842,8 @@ export class SourceFile {
|
|||||||
typingModulePath = typingImportResult.resolvedPaths[0];
|
typingModulePath = typingImportResult.resolvedPaths[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let collectionsModulePath: string | undefined;
|
||||||
|
|
||||||
for (const moduleImport of moduleImports) {
|
for (const moduleImport of moduleImports) {
|
||||||
const importResult = importResolver.resolveImport(
|
const importResult = importResolver.resolveImport(
|
||||||
this._filePath,
|
this._filePath,
|
||||||
@ -827,6 +854,16 @@ export class SourceFile {
|
|||||||
importedSymbols: moduleImport.importedSymbols
|
importedSymbols: moduleImport.importedSymbols
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If the file imports the stdlib 'collections' module, stash
|
||||||
|
// away its file path. The type analyzer may need this to
|
||||||
|
// access types defined in the collections module.
|
||||||
|
if (importResult.isImportFound && importResult.isTypeshedFile) {
|
||||||
|
if (moduleImport.nameParts.length >= 1 && moduleImport.nameParts[0] === 'collections') {
|
||||||
|
collectionsModulePath = importResult.resolvedPaths[importResult.resolvedPaths.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
imports.push(importResult);
|
imports.push(importResult);
|
||||||
|
|
||||||
// Associate the import results with the module import
|
// Associate the import results with the module import
|
||||||
@ -835,6 +872,6 @@ export class SourceFile {
|
|||||||
AnalyzerNodeInfo.setImportInfo(moduleImport.nameNode, importResult);
|
AnalyzerNodeInfo.setImportInfo(moduleImport.nameNode, importResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [imports, builtinsImportResult, typingModulePath];
|
return [imports, builtinsImportResult, typingModulePath, collectionsModulePath];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ export class Symbol {
|
|||||||
|
|
||||||
getTypedDeclarations() {
|
getTypedDeclarations() {
|
||||||
return this.getDeclarations().filter(
|
return this.getDeclarations().filter(
|
||||||
decl => hasTypeForDeclaration(decl, false));
|
decl => hasTypeForDeclaration(decl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
|
|
||||||
import { DiagnosticLevel } from '../common/configOptions';
|
import { DiagnosticLevel } from '../common/configOptions';
|
||||||
import { AddMissingOptionalToParamAction, Diagnostic,
|
import { AddMissingOptionalToParamAction, Diagnostic, DiagnosticAddendum } from '../common/diagnostic';
|
||||||
DiagnosticAddendum, getEmptyRange } from '../common/diagnostic';
|
|
||||||
import { DiagnosticRule } from '../common/diagnosticRules';
|
import { DiagnosticRule } from '../common/diagnosticRules';
|
||||||
import { convertOffsetsToRange } from '../common/positionUtils';
|
import { convertOffsetsToRange } from '../common/positionUtils';
|
||||||
import { PythonVersion } from '../common/pythonVersion';
|
import { PythonVersion } from '../common/pythonVersion';
|
||||||
@ -22,15 +21,15 @@ import { AssertNode, AssignmentExpressionNode, AssignmentNode, AugmentedAssignme
|
|||||||
BinaryExpressionNode, BreakNode, CallExpressionNode, ClassNode, ContinueNode, DecoratorNode,
|
BinaryExpressionNode, BreakNode, CallExpressionNode, ClassNode, ContinueNode, DecoratorNode,
|
||||||
DelNode, ErrorExpressionNode, ExceptNode, ExpressionNode, FormatStringNode, ForNode,
|
DelNode, ErrorExpressionNode, ExceptNode, ExpressionNode, FormatStringNode, ForNode,
|
||||||
FunctionNode, IfNode, ImportAsNode, ImportFromNode, IndexExpressionNode, LambdaNode,
|
FunctionNode, IfNode, ImportAsNode, ImportFromNode, IndexExpressionNode, LambdaNode,
|
||||||
ListComprehensionNode, MemberAccessExpressionNode, ModuleNode, NameNode, ParameterCategory, ParameterNode,
|
ListComprehensionNode, MemberAccessExpressionNode, ModuleNode, NameNode, ParameterCategory,
|
||||||
ParseNode, ParseNodeType, RaiseNode, ReturnNode, SliceExpressionNode, StringListNode,
|
ParameterNode, ParseNode, ParseNodeType, RaiseNode, ReturnNode, SliceExpressionNode,
|
||||||
SuiteNode, TernaryExpressionNode, TryNode, TupleExpressionNode,
|
StringListNode, SuiteNode, TernaryExpressionNode, TryNode, TupleExpressionNode,
|
||||||
TypeAnnotationExpressionNode, UnaryExpressionNode, UnpackExpressionNode, WhileNode, WithNode,
|
TypeAnnotationExpressionNode, UnaryExpressionNode, UnpackExpressionNode, WhileNode, WithNode,
|
||||||
YieldExpressionNode, YieldFromExpressionNode } from '../parser/parseNodes';
|
YieldExpressionNode, YieldFromExpressionNode } from '../parser/parseNodes';
|
||||||
import { KeywordType } from '../parser/tokenizerTypes';
|
import { KeywordType } from '../parser/tokenizerTypes';
|
||||||
import { AnalyzerFileInfo } from './analyzerFileInfo';
|
import { AnalyzerFileInfo } from './analyzerFileInfo';
|
||||||
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
|
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
|
||||||
import { AliasDeclaration, Declaration, DeclarationType, ModuleDeclaration,
|
import { AliasDeclaration, Declaration, DeclarationType, ModuleLoaderActions,
|
||||||
VariableDeclaration } from './declaration';
|
VariableDeclaration } from './declaration';
|
||||||
import * as DeclarationUtils from './declarationUtils';
|
import * as DeclarationUtils from './declarationUtils';
|
||||||
import { EvaluatorFlags, ExpressionEvaluator } from './expressionEvaluator';
|
import { EvaluatorFlags, ExpressionEvaluator } from './expressionEvaluator';
|
||||||
@ -1297,95 +1296,62 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitImportAs(node: ImportAsNode): boolean {
|
visitImportAs(node: ImportAsNode): boolean {
|
||||||
const importInfo = AnalyzerNodeInfo.getImportInfo(node.module);
|
if (node.module.nameParts.length === 0) {
|
||||||
assert(importInfo !== undefined);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (importInfo && importInfo.isImportFound && importInfo.resolvedPaths.length > 0) {
|
let symbolNameNode: NameNode;
|
||||||
const resolvedPath = importInfo.resolvedPaths[importInfo.resolvedPaths.length - 1];
|
if (node.alias) {
|
||||||
|
// The symbol name is defined by the alias.
|
||||||
|
symbolNameNode = node.alias;
|
||||||
|
} else {
|
||||||
|
// There was no alias, so we need to use the first element of
|
||||||
|
// the name parts as the symbol.
|
||||||
|
symbolNameNode = node.module.nameParts[0];
|
||||||
|
}
|
||||||
|
|
||||||
let moduleType = this._getModuleTypeForImportPath(importInfo, resolvedPath);
|
// Look up the symbol to find the alias declaration.
|
||||||
|
let symbolType: Type | undefined;
|
||||||
|
let symbol: Symbol | undefined;
|
||||||
|
[symbol, symbolType] = this._getAliasedSymbolTypeForName(symbolNameNode.nameToken.value);
|
||||||
|
if (!symbolType) {
|
||||||
|
symbolType = UnknownType.create();
|
||||||
|
}
|
||||||
|
|
||||||
// Is there a cached module type associated with this node?
|
// Is there a cached module type associated with this node? If so, use
|
||||||
const cachedModuleType = AnalyzerNodeInfo.getExpressionType(node) as ModuleType;
|
// it instead of the type we just created. This will preserve the
|
||||||
if (cachedModuleType && cachedModuleType.category === TypeCategory.Module && moduleType) {
|
// symbol accessed flags.
|
||||||
// If the fields match, use the cached version instead of the
|
const cachedModuleType = AnalyzerNodeInfo.getExpressionType(node) as ModuleType;
|
||||||
// newly-created version so we preserve the work done to
|
if (cachedModuleType && cachedModuleType.category === TypeCategory.Module && symbolType) {
|
||||||
// populate the loader fields.
|
if (isTypeSame(symbolType, cachedModuleType)) {
|
||||||
if (moduleType.fields === cachedModuleType.fields) {
|
symbolType = cachedModuleType;
|
||||||
moduleType = cachedModuleType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (moduleType) {
|
// Cache the module type for subsequent passes.
|
||||||
// Import the implicit imports in the module's namespace.
|
AnalyzerNodeInfo.setExpressionType(node, symbolType);
|
||||||
importInfo.implicitImports.forEach(implicitImport => {
|
|
||||||
const implicitModuleType = this._getModuleTypeForImportPath(
|
|
||||||
importInfo, implicitImport.path);
|
|
||||||
if (implicitModuleType) {
|
|
||||||
if (!ModuleType.getField(moduleType!, implicitImport.name)) {
|
|
||||||
const moduleDeclaration: ModuleDeclaration = {
|
|
||||||
type: DeclarationType.Module,
|
|
||||||
moduleType: implicitModuleType,
|
|
||||||
path: implicitImport.path,
|
|
||||||
range: getEmptyRange()
|
|
||||||
};
|
|
||||||
const aliasDeclaration: AliasDeclaration = {
|
|
||||||
type: DeclarationType.Alias,
|
|
||||||
resolvedDeclarations: [moduleDeclaration],
|
|
||||||
path: '',
|
|
||||||
range: getEmptyRange()
|
|
||||||
};
|
|
||||||
|
|
||||||
const newSymbol = Symbol.createWithType(
|
this._assignTypeToNameNode(symbolNameNode, symbolType);
|
||||||
SymbolFlags.ClassMember, implicitModuleType, defaultTypeSourceId);
|
this._updateExpressionTypeForNode(symbolNameNode, symbolType);
|
||||||
newSymbol.addDeclaration(aliasDeclaration);
|
|
||||||
setSymbolPreservingAccess(moduleType!.loaderFields!, implicitImport.name,
|
|
||||||
newSymbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const moduleDeclaration: ModuleDeclaration = {
|
if (node.alias) {
|
||||||
type: DeclarationType.Module,
|
this._conditionallyReportUnusedName(symbolNameNode, false,
|
||||||
moduleType,
|
this._fileInfo.diagnosticSettings.reportUnusedImport,
|
||||||
path: resolvedPath,
|
DiagnosticRule.reportUnusedImport,
|
||||||
range: getEmptyRange()
|
`Import '${ node.alias.nameToken.value }' is not accessed`);
|
||||||
};
|
} else {
|
||||||
|
if (symbol && !symbol.isAccessed()) {
|
||||||
|
const nameParts = node.module.nameParts;
|
||||||
|
if (nameParts.length > 0) {
|
||||||
|
const multipartName = nameParts.map(np => np.nameToken.value).join('.');
|
||||||
|
const textRange: TextRange = { start: nameParts[0].start, length: nameParts[0].length };
|
||||||
|
TextRange.extend(textRange, nameParts[nameParts.length - 1]);
|
||||||
|
this._fileInfo.diagnosticSink.addUnusedCodeWithTextRange(
|
||||||
|
`'${ multipartName }' is not accessed`, textRange);
|
||||||
|
|
||||||
if (node.alias) {
|
this._addDiagnostic(this._fileInfo.diagnosticSettings.reportUnusedImport,
|
||||||
this._assignTypeToNameNode(node.alias, moduleType, moduleDeclaration);
|
|
||||||
this._updateExpressionTypeForNode(node.alias, moduleType);
|
|
||||||
|
|
||||||
this._conditionallyReportUnusedName(node.alias, false,
|
|
||||||
this._fileInfo.diagnosticSettings.reportUnusedImport,
|
|
||||||
DiagnosticRule.reportUnusedImport,
|
DiagnosticRule.reportUnusedImport,
|
||||||
`Import '${ node.alias.nameToken.value }' is not accessed`);
|
`Import '${ multipartName }' is not accessed`, textRange);
|
||||||
} else {
|
|
||||||
this._bindMultiPartModuleNameToType(node.module.nameParts,
|
|
||||||
moduleType, moduleDeclaration);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache the module type for subsequent passes.
|
|
||||||
AnalyzerNodeInfo.setExpressionType(node, moduleType);
|
|
||||||
} else {
|
|
||||||
// We were unable to resolve the import. Bind the names (or alias)
|
|
||||||
// to an unknown type.
|
|
||||||
const symbolType = UnknownType.create();
|
|
||||||
const nameNode = node.module.nameParts.length > 0 ? node.module.nameParts[0] : undefined;
|
|
||||||
const aliasNode = node.alias || nameNode;
|
|
||||||
|
|
||||||
if (node.alias && nameNode) {
|
|
||||||
this._updateExpressionTypeForNode(nameNode, symbolType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aliasNode) {
|
|
||||||
this._assignTypeToNameNode(aliasNode, symbolType);
|
|
||||||
this._updateExpressionTypeForNode(aliasNode, symbolType);
|
|
||||||
|
|
||||||
this._conditionallyReportUnusedName(aliasNode, false,
|
|
||||||
this._fileInfo.diagnosticSettings.reportUnusedImport,
|
|
||||||
DiagnosticRule.reportUnusedImport,
|
|
||||||
`Import '${ aliasNode.nameToken.value }' is not accessed`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1395,72 +1361,44 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
|||||||
|
|
||||||
visitImportFrom(node: ImportFromNode): boolean {
|
visitImportFrom(node: ImportFromNode): boolean {
|
||||||
const importInfo = AnalyzerNodeInfo.getImportInfo(node.module);
|
const importInfo = AnalyzerNodeInfo.getImportInfo(node.module);
|
||||||
|
let symbol: Symbol | undefined;
|
||||||
|
let symbolType: Type | undefined;
|
||||||
|
|
||||||
if (importInfo && importInfo.isImportFound) {
|
if (importInfo && importInfo.isImportFound) {
|
||||||
const resolvedPath = importInfo.resolvedPaths.length > 0 ?
|
const resolvedPath = importInfo.resolvedPaths.length > 0 ?
|
||||||
importInfo.resolvedPaths[importInfo.resolvedPaths.length - 1] : '';
|
importInfo.resolvedPaths[importInfo.resolvedPaths.length - 1] : '';
|
||||||
|
|
||||||
// Empty list implies "import *"
|
|
||||||
if (node.isWildcardImport) {
|
if (node.isWildcardImport) {
|
||||||
const moduleType = this._getModuleTypeForImportPath(importInfo, resolvedPath);
|
if (resolvedPath) {
|
||||||
if (moduleType) {
|
|
||||||
// Import the fields in the current permanent scope.
|
// Import the fields in the current permanent scope.
|
||||||
const moduleFields = moduleType.fields;
|
const lookupInfo = this._fileInfo.importLookup(resolvedPath);
|
||||||
moduleFields.forEach((boundValue, fieldName) => {
|
if (lookupInfo) {
|
||||||
this._addSymbolToPermanentScope(fieldName);
|
lookupInfo.symbolTable.forEach((_, name) => {
|
||||||
this._addTypeSourceToName(fieldName, TypeUtils.getEffectiveTypeOfSymbol(boundValue),
|
[symbol, symbolType] = this._getAliasedSymbolTypeForName(name);
|
||||||
node.id, boundValue.hasDeclarations() ? boundValue.getDeclarations()[0] : undefined);
|
if (symbol) {
|
||||||
});
|
this._addTypeSourceToName(name, symbolType || UnknownType.create(),
|
||||||
|
node.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Import the fields in the current permanent scope.
|
|
||||||
importInfo.implicitImports.forEach(implicitImport => {
|
importInfo.implicitImports.forEach(implicitImport => {
|
||||||
const moduleType = this._getModuleTypeForImportPath(importInfo, resolvedPath);
|
[symbol, symbolType] = this._getAliasedSymbolTypeForName(implicitImport.name);
|
||||||
if (moduleType) {
|
if (symbol) {
|
||||||
this._addSymbolToPermanentScope(implicitImport.name);
|
this._addTypeSourceToName(implicitImport.name,
|
||||||
this._addTypeSourceToName(implicitImport.name, moduleType, node.id);
|
symbolType || UnknownType.create(), node.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
node.imports.forEach(importAs => {
|
node.imports.forEach(importAs => {
|
||||||
const name = importAs.name.nameToken.value;
|
|
||||||
const aliasNode = importAs.alias || importAs.name;
|
const aliasNode = importAs.alias || importAs.name;
|
||||||
let symbolType: Type | undefined;
|
[symbol, symbolType] = this._getAliasedSymbolTypeForName(aliasNode.nameToken.value);
|
||||||
let declarations: Declaration[] | undefined;
|
|
||||||
|
|
||||||
// Is the name referring to an implicit import?
|
|
||||||
const implicitImport = importInfo.implicitImports.find(impImport => impImport.name === name);
|
|
||||||
if (implicitImport) {
|
|
||||||
const moduleType = this._getModuleTypeForImportPath(importInfo, implicitImport.path);
|
|
||||||
if (moduleType && this._fileInfo.importMap.has(implicitImport.path)) {
|
|
||||||
symbolType = moduleType;
|
|
||||||
declarations = [{
|
|
||||||
type: DeclarationType.Module,
|
|
||||||
moduleType,
|
|
||||||
path: implicitImport.path,
|
|
||||||
range: getEmptyRange()
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const moduleType = this._getModuleTypeForImportPath(importInfo, resolvedPath);
|
|
||||||
if (moduleType) {
|
|
||||||
const symbol = ModuleType.getField(moduleType, name);
|
|
||||||
|
|
||||||
// For imports of the form "from . import X", the symbol
|
|
||||||
// will have no declarations.
|
|
||||||
if (symbol && symbol.hasDeclarations()) {
|
|
||||||
symbolType = TypeUtils.getEffectiveTypeOfSymbol(symbol);
|
|
||||||
declarations = symbol.getDeclarations();
|
|
||||||
} else {
|
|
||||||
this._addError(
|
|
||||||
`'${ importAs.name.nameToken.value }' is unknown import symbol`,
|
|
||||||
importAs.name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!symbolType) {
|
if (!symbolType) {
|
||||||
|
this._addError(
|
||||||
|
`'${ importAs.name.nameToken.value }' is unknown import symbol`,
|
||||||
|
importAs.name
|
||||||
|
);
|
||||||
symbolType = UnknownType.create();
|
symbolType = UnknownType.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1468,53 +1406,27 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
|||||||
if (importAs.alias) {
|
if (importAs.alias) {
|
||||||
this._updateExpressionTypeForNode(importAs.alias, symbolType);
|
this._updateExpressionTypeForNode(importAs.alias, symbolType);
|
||||||
}
|
}
|
||||||
|
this._addTypeSourceToName(aliasNode.nameToken.value, symbolType, node.id);
|
||||||
let aliasDeclaration: AliasDeclaration | undefined;
|
this._assignTypeToNameNode(aliasNode, symbolType);
|
||||||
if (declarations) {
|
|
||||||
aliasDeclaration = {
|
|
||||||
type: DeclarationType.Alias,
|
|
||||||
resolvedDeclarations: declarations,
|
|
||||||
symbolName: name,
|
|
||||||
path: '',
|
|
||||||
range: getEmptyRange()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
this._assignTypeToNameNode(aliasNode, symbolType, aliasDeclaration);
|
|
||||||
|
|
||||||
// Python files generated by protoc ("_pb2.py" files) contain
|
|
||||||
// unused imports. Don't report these because they're in generated
|
|
||||||
// files that shouldn't be edited.
|
|
||||||
if (importInfo.importName !== '__future__' &&
|
|
||||||
!this._fileInfo.filePath.endsWith('_pb2.py')) {
|
|
||||||
|
|
||||||
this._conditionallyReportUnusedName(aliasNode, false,
|
|
||||||
this._fileInfo.diagnosticSettings.reportUnusedImport,
|
|
||||||
DiagnosticRule.reportUnusedImport,
|
|
||||||
`Import '${ aliasNode.nameToken.value }' is not accessed`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// We were unable to resolve the import. Bind the names (or aliases)
|
|
||||||
// to an unknown type.
|
|
||||||
if (!node.isWildcardImport) {
|
|
||||||
node.imports.forEach(importAs => {
|
|
||||||
const aliasNode = importAs.alias || importAs.name;
|
|
||||||
const symbolType = UnknownType.create();
|
|
||||||
|
|
||||||
this._updateExpressionTypeForNode(importAs.name, symbolType);
|
if (!node.isWildcardImport) {
|
||||||
if (importAs.alias) {
|
node.imports.forEach(importAs => {
|
||||||
this._updateExpressionTypeForNode(importAs.name, symbolType);
|
const aliasNode = importAs.alias || importAs.name;
|
||||||
}
|
// Python files generated by protoc ("_pb2.py" files) contain
|
||||||
|
// unused imports. Don't report these because they're in generated
|
||||||
|
// files that shouldn't be edited.
|
||||||
|
if ((!importInfo || importInfo.importName !== '__future__') &&
|
||||||
|
!this._fileInfo.filePath.endsWith('_pb2.py')) {
|
||||||
|
|
||||||
this._assignTypeToNameNode(aliasNode, symbolType);
|
|
||||||
this._conditionallyReportUnusedName(aliasNode, false,
|
this._conditionallyReportUnusedName(aliasNode, false,
|
||||||
this._fileInfo.diagnosticSettings.reportUnusedImport,
|
this._fileInfo.diagnosticSettings.reportUnusedImport,
|
||||||
DiagnosticRule.reportUnusedImport,
|
DiagnosticRule.reportUnusedImport,
|
||||||
`Import '${ aliasNode.nameToken.value }' is not accessed`);
|
`Import '${ aliasNode.nameToken.value }' is not accessed`);
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -1587,6 +1499,58 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _getAliasedSymbolTypeForName(name: string): [Symbol | undefined, Type | undefined] {
|
||||||
|
const symbolWithScope = this._currentScope.lookUpSymbolRecursive(name);
|
||||||
|
if (!symbolWithScope) {
|
||||||
|
return [undefined, undefined];
|
||||||
|
}
|
||||||
|
|
||||||
|
const aliasDecl = symbolWithScope.symbol.getDeclarations().find(
|
||||||
|
decl => decl.type === DeclarationType.Alias);
|
||||||
|
|
||||||
|
let symbolType: Type | undefined;
|
||||||
|
if (aliasDecl && aliasDecl.type === DeclarationType.Alias) {
|
||||||
|
if (aliasDecl.symbolName) {
|
||||||
|
assert(aliasDecl.path);
|
||||||
|
const lookupResults = this._fileInfo.importLookup(aliasDecl.path);
|
||||||
|
if (lookupResults) {
|
||||||
|
const symbol = lookupResults.symbolTable.get(aliasDecl.symbolName);
|
||||||
|
if (symbol) {
|
||||||
|
symbolType = TypeUtils.getEffectiveTypeOfSymbol(symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Build a module type that corresponds to the declaration and
|
||||||
|
// its associated loader actions.
|
||||||
|
const moduleType = ModuleType.create();
|
||||||
|
this._applyLoaderActionsToModuleType(moduleType, aliasDecl);
|
||||||
|
symbolType = moduleType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [symbolWithScope ? symbolWithScope.symbol : undefined, symbolType];
|
||||||
|
}
|
||||||
|
|
||||||
|
private _applyLoaderActionsToModuleType(moduleType: ModuleType, loaderActions: ModuleLoaderActions) {
|
||||||
|
if (loaderActions.path) {
|
||||||
|
const lookupResults = this._fileInfo.importLookup(loaderActions.path);
|
||||||
|
if (lookupResults) {
|
||||||
|
moduleType.fields = lookupResults.symbolTable;
|
||||||
|
moduleType.docString = lookupResults.docString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loaderActions.implicitImports.forEach((implicitImport, name) => {
|
||||||
|
const importedModuleType = ModuleType.create();
|
||||||
|
const importedModuleSymbol = Symbol.createWithType(
|
||||||
|
SymbolFlags.None, importedModuleType, defaultTypeSourceId);
|
||||||
|
moduleType.loaderFields.set(name, importedModuleSymbol);
|
||||||
|
|
||||||
|
// Recursively apply loader actions.
|
||||||
|
this._applyLoaderActionsToModuleType(importedModuleType, implicitImport);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Validates that a call to isinstance is necessary. This is a
|
// Validates that a call to isinstance is necessary. This is a
|
||||||
// common source of programming errors.
|
// common source of programming errors.
|
||||||
private _validateIsInstanceCallNecessary(node: CallExpressionNode) {
|
private _validateIsInstanceCallNecessary(node: CallExpressionNode) {
|
||||||
@ -2082,7 +2046,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
primaryDeclaration = DeclarationUtils.resolveDeclarationAliases(primaryDeclaration);
|
primaryDeclaration = DeclarationUtils.resolveAliasDeclaration(primaryDeclaration,
|
||||||
|
this._fileInfo.importLookup);
|
||||||
if (!primaryDeclaration || primaryDeclaration.node === node) {
|
if (!primaryDeclaration || primaryDeclaration.node === node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2683,18 +2648,13 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _findCollectionsImportSymbolTable(): SymbolTable | undefined {
|
private _findCollectionsImportSymbolTable(): SymbolTable | undefined {
|
||||||
let moduleType: ModuleType | undefined;
|
if (this._fileInfo.collectionsModulePath) {
|
||||||
for (const key of this._fileInfo.importMap.keys()) {
|
const lookupResult = this._fileInfo.importLookup(this._fileInfo.collectionsModulePath);
|
||||||
if (key.endsWith('collections/__init__.pyi')) {
|
if (lookupResult) {
|
||||||
moduleType = this._fileInfo.importMap.get(key);
|
return lookupResult.symbolTable;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moduleType) {
|
|
||||||
return moduleType.fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3055,23 +3015,24 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const moduleType = this._fileInfo.importMap.get(path);
|
const lookupResults = this._fileInfo.importLookup(path);
|
||||||
if (moduleType) {
|
if (lookupResults) {
|
||||||
return ModuleType.cloneForLoadedModule(moduleType);
|
const moduleType = ModuleType.create(lookupResults.symbolTable);
|
||||||
|
moduleType.docString = lookupResults.docString;
|
||||||
|
return moduleType;
|
||||||
} else if (importResult) {
|
} else if (importResult) {
|
||||||
// There was no module even though the import was resolved. This
|
// There was no module even though the import was resolved. This
|
||||||
// happens in the case of namespace packages, where an __init__.py
|
// happens in the case of namespace packages, where an __init__.py
|
||||||
// is not necessarily present. We'll synthesize a module type in
|
// is not necessarily present. We'll synthesize a module type in
|
||||||
// this case.
|
// this case.
|
||||||
const moduleType = ModuleType.cloneForLoadedModule(
|
const moduleType = ModuleType.create();
|
||||||
ModuleType.create(new SymbolTable()));
|
|
||||||
|
|
||||||
// Add the implicit imports.
|
// Add the implicit imports.
|
||||||
importResult.implicitImports.forEach(implicitImport => {
|
importResult.implicitImports.forEach(implicitImport => {
|
||||||
const implicitModuleType = this._getModuleTypeForImportPath(
|
const implicitModuleType = this._getModuleTypeForImportPath(
|
||||||
undefined, implicitImport.path);
|
undefined, implicitImport.path);
|
||||||
if (implicitModuleType) {
|
if (implicitModuleType) {
|
||||||
setSymbolPreservingAccess(moduleType.loaderFields!, implicitImport.name,
|
setSymbolPreservingAccess(moduleType.loaderFields, implicitImport.name,
|
||||||
Symbol.createWithType(
|
Symbol.createWithType(
|
||||||
SymbolFlags.ClassMember, implicitModuleType, defaultTypeSourceId));
|
SymbolFlags.ClassMember, implicitModuleType, defaultTypeSourceId));
|
||||||
}
|
}
|
||||||
@ -3364,83 +3325,6 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
|||||||
this._evaluateExpressionForAssignment(target, srcType, srcExpr);
|
this._evaluateExpressionForAssignment(target, srcType, srcExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _bindMultiPartModuleNameToType(nameParts: NameNode[], type: ModuleType,
|
|
||||||
declaration?: Declaration): void {
|
|
||||||
|
|
||||||
// The target symbol table will change as we progress through
|
|
||||||
// the multi-part name. Start with the current scope's symbol
|
|
||||||
// table, which should include the first part of the name.
|
|
||||||
const permanentScope = ScopeUtils.getPermanentScope(this._currentScope);
|
|
||||||
let targetSymbolTable = permanentScope.getSymbolTable();
|
|
||||||
|
|
||||||
for (let i = 0; i < nameParts.length; i++) {
|
|
||||||
const name = nameParts[i].nameToken.value;
|
|
||||||
|
|
||||||
// Does this symbol already exist within this scope?
|
|
||||||
let targetSymbol = targetSymbolTable.get(name);
|
|
||||||
let symbolType = targetSymbol ?
|
|
||||||
TypeUtils.getEffectiveTypeOfSymbol(targetSymbol) : undefined;
|
|
||||||
|
|
||||||
if (!symbolType || symbolType.category !== TypeCategory.Module) {
|
|
||||||
symbolType = ModuleType.create(new SymbolTable());
|
|
||||||
symbolType = ModuleType.cloneForLoadedModule(symbolType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the symbol didn't exist, create a new one.
|
|
||||||
if (!targetSymbol) {
|
|
||||||
targetSymbol = Symbol.createWithType(SymbolFlags.ClassMember,
|
|
||||||
symbolType, defaultTypeSourceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i === 0) {
|
|
||||||
// Assign the first part of the multi-part name to the current scope.
|
|
||||||
this._assignTypeToNameNode(nameParts[0], symbolType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i === nameParts.length - 1) {
|
|
||||||
const moduleType = symbolType;
|
|
||||||
moduleType.fields = type.fields;
|
|
||||||
moduleType.docString = type.docString;
|
|
||||||
|
|
||||||
if (type.loaderFields) {
|
|
||||||
assert(moduleType.loaderFields !== undefined);
|
|
||||||
|
|
||||||
// Copy the loader fields, which may include implicit
|
|
||||||
// imports for the module.
|
|
||||||
type.loaderFields.forEach((symbol, name) => {
|
|
||||||
setSymbolPreservingAccess(moduleType.loaderFields!, name, symbol);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (declaration) {
|
|
||||||
targetSymbol.addDeclaration(declaration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setSymbolPreservingAccess(targetSymbolTable, name, targetSymbol);
|
|
||||||
assert(symbolType.loaderFields !== undefined);
|
|
||||||
targetSymbolTable = symbolType.loaderFields!;
|
|
||||||
|
|
||||||
// If this is the last element, determine if it's accessed.
|
|
||||||
if (i === nameParts.length - 1) {
|
|
||||||
// Is this module ever accessed?
|
|
||||||
if (targetSymbol && !targetSymbol.isAccessed()) {
|
|
||||||
const multipartName = nameParts.map(np => np.nameToken.value).join('.');
|
|
||||||
const textRange = { start: nameParts[0].start, length: nameParts[0].length };
|
|
||||||
if (nameParts.length > 1) {
|
|
||||||
TextRange.extend(textRange, nameParts[nameParts.length - 1]);
|
|
||||||
}
|
|
||||||
this._fileInfo.diagnosticSink.addUnusedCodeWithTextRange(
|
|
||||||
`'${ multipartName }' is not accessed`, textRange);
|
|
||||||
|
|
||||||
this._addDiagnostic(this._fileInfo.diagnosticSettings.reportUnusedImport,
|
|
||||||
DiagnosticRule.reportUnusedImport,
|
|
||||||
`Import '${ multipartName }' is not accessed`, textRange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _assignTypeToNameNode(nameNode: NameNode, srcType: Type, declaration?: Declaration,
|
private _assignTypeToNameNode(nameNode: NameNode, srcType: Type, declaration?: Declaration,
|
||||||
srcExpressionNode?: ParseNode) {
|
srcExpressionNode?: ParseNode) {
|
||||||
|
|
||||||
@ -3508,28 +3392,6 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
|||||||
this._addAssignmentTypeConstraint(node, type);
|
this._addAssignmentTypeConstraint(node, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finds the nearest permanent scope (as opposed to temporary scope) and
|
|
||||||
// adds a new symbol with the specified name if it doesn't already exist.
|
|
||||||
private _addSymbolToPermanentScope(name: string) {
|
|
||||||
const permanentScope = ScopeUtils.getPermanentScope(this._currentScope);
|
|
||||||
assert(permanentScope.getType() !== ScopeType.Temporary);
|
|
||||||
|
|
||||||
let symbol = permanentScope.lookUpSymbol(name);
|
|
||||||
if (!symbol) {
|
|
||||||
symbol = permanentScope.addSymbol(name, SymbolFlags.ClassMember);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variables that are defined within a module or a class
|
|
||||||
// are considered public by default. Don't flag them
|
|
||||||
// "not access" unless the name indicates that it's private.
|
|
||||||
const scopeType = permanentScope.getType();
|
|
||||||
if (scopeType === ScopeType.Class || scopeType === ScopeType.Module) {
|
|
||||||
if (!this._isSymbolPrivate(name, scopeType)) {
|
|
||||||
this._setSymbolAccessed(symbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _addTypeSourceToName(name: string, type: Type, typeSourceId: TypeSourceId,
|
private _addTypeSourceToName(name: string, type: Type, typeSourceId: TypeSourceId,
|
||||||
declaration?: Declaration) {
|
declaration?: Declaration) {
|
||||||
|
|
||||||
|
@ -115,24 +115,14 @@ export interface ModuleType extends TypeBase {
|
|||||||
// A "loader" module includes symbols that were injected by
|
// A "loader" module includes symbols that were injected by
|
||||||
// the module loader. We keep these separate so we don't
|
// the module loader. We keep these separate so we don't
|
||||||
// pollute the symbols exported by the module itself.
|
// pollute the symbols exported by the module itself.
|
||||||
loaderFields?: SymbolTable;
|
loaderFields: SymbolTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ModuleType {
|
export namespace ModuleType {
|
||||||
export function create(fields: SymbolTable, docString?: string) {
|
export function create(symbolTable?: SymbolTable) {
|
||||||
const newModuleType: ModuleType = {
|
const newModuleType: ModuleType = {
|
||||||
category: TypeCategory.Module,
|
category: TypeCategory.Module,
|
||||||
fields,
|
fields: symbolTable || new SymbolTable(),
|
||||||
docString
|
|
||||||
};
|
|
||||||
return newModuleType;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cloneForLoadedModule(moduleType: ModuleType) {
|
|
||||||
const newModuleType: ModuleType = {
|
|
||||||
category: TypeCategory.Module,
|
|
||||||
fields: moduleType.fields,
|
|
||||||
docString: moduleType.docString,
|
|
||||||
loaderFields: new SymbolTable()
|
loaderFields: new SymbolTable()
|
||||||
};
|
};
|
||||||
return newModuleType;
|
return newModuleType;
|
||||||
@ -1217,6 +1207,24 @@ export function isTypeSame(type1: Type, type2: Type, recursionCount = 0): boolea
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case TypeCategory.Module: {
|
||||||
|
const type2Module = type2 as ModuleType;
|
||||||
|
|
||||||
|
// Module types are the same if they share the same
|
||||||
|
// module symbol table.
|
||||||
|
if (type1.fields === type2Module.fields) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both symbol tables are empty, we can also assume
|
||||||
|
// they're equal.
|
||||||
|
if (type1.fields.isEmpty() && type2Module.fields.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -11,10 +11,10 @@
|
|||||||
import { CompletionItem, CompletionItemKind, CompletionList,
|
import { CompletionItem, CompletionItemKind, CompletionList,
|
||||||
MarkupKind, TextEdit } from 'vscode-languageserver';
|
MarkupKind, TextEdit } from 'vscode-languageserver';
|
||||||
|
|
||||||
import { ImportMap } from '../analyzer/analyzerFileInfo';
|
import { ImportLookup } from '../analyzer/analyzerFileInfo';
|
||||||
import * as AnalyzerNodeInfo from '../analyzer/analyzerNodeInfo';
|
import * as AnalyzerNodeInfo from '../analyzer/analyzerNodeInfo';
|
||||||
import { Declaration, DeclarationType } from '../analyzer/declaration';
|
import { Declaration, DeclarationType } from '../analyzer/declaration';
|
||||||
import { getTypeForDeclaration } from '../analyzer/declarationUtils';
|
import { getTypeForDeclaration, resolveAliasDeclaration } from '../analyzer/declarationUtils';
|
||||||
import { ImportedModuleDescriptor, ImportResolver, ModuleNameAndType } from '../analyzer/importResolver';
|
import { ImportedModuleDescriptor, ImportResolver, ModuleNameAndType } from '../analyzer/importResolver';
|
||||||
import { ImportType } from '../analyzer/importResult';
|
import { ImportType } from '../analyzer/importResult';
|
||||||
import * as ImportStatementUtils from '../analyzer/importStatementUtils';
|
import * as ImportStatementUtils from '../analyzer/importStatementUtils';
|
||||||
@ -142,7 +142,7 @@ export class CompletionProvider {
|
|||||||
private _position: DiagnosticTextPosition,
|
private _position: DiagnosticTextPosition,
|
||||||
private _filePath: string,
|
private _filePath: string,
|
||||||
private _configOptions: ConfigOptions,
|
private _configOptions: ConfigOptions,
|
||||||
private _importMapCallback: () => ImportMap,
|
private _importLookup: ImportLookup,
|
||||||
private _moduleSymbolsCallback: () => ModuleSymbolMap) {
|
private _moduleSymbolsCallback: () => ModuleSymbolMap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,13 +566,9 @@ export class CompletionProvider {
|
|||||||
const resolvedPath = importInfo.resolvedPaths.length > 0 ?
|
const resolvedPath = importInfo.resolvedPaths.length > 0 ?
|
||||||
importInfo.resolvedPaths[importInfo.resolvedPaths.length - 1] : '';
|
importInfo.resolvedPaths[importInfo.resolvedPaths.length - 1] : '';
|
||||||
|
|
||||||
const importMap = this._importMapCallback();
|
const lookupResults = this._importLookup(resolvedPath);
|
||||||
|
if (lookupResults) {
|
||||||
const moduleType = importMap.get(resolvedPath);
|
this._addSymbolsForSymbolTable(lookupResults.symbolTable,
|
||||||
if (moduleType) {
|
|
||||||
const symbolTable = new SymbolTable();
|
|
||||||
TypeUtils.getMembersForModule(moduleType, symbolTable);
|
|
||||||
this._addSymbolsForSymbolTable(symbolTable,
|
|
||||||
name => {
|
name => {
|
||||||
// Don't suggest symbols that have already been imported.
|
// Don't suggest symbols that have already been imported.
|
||||||
return !importFromNode.imports.find(
|
return !importFromNode.imports.find(
|
||||||
@ -646,46 +642,60 @@ export class CompletionProvider {
|
|||||||
let typeDetail: string | undefined;
|
let typeDetail: string | undefined;
|
||||||
let documentation: string | undefined;
|
let documentation: string | undefined;
|
||||||
|
|
||||||
const declaration = declarations[0];
|
const declaration = resolveAliasDeclaration(declarations[0], this._importLookup);
|
||||||
const type = getTypeForDeclaration(declaration);
|
if (declaration) {
|
||||||
itemKind = this._convertDeclarationTypeToItemKind(declaration, type);
|
const type = getTypeForDeclaration(declaration);
|
||||||
|
itemKind = this._convertDeclarationTypeToItemKind(declaration, type);
|
||||||
|
|
||||||
if (type) {
|
if (type) {
|
||||||
switch (declaration.type) {
|
switch (declaration.type) {
|
||||||
case DeclarationType.BuiltIn:
|
case DeclarationType.BuiltIn:
|
||||||
case DeclarationType.Variable:
|
case DeclarationType.Variable:
|
||||||
case DeclarationType.Parameter:
|
case DeclarationType.Parameter:
|
||||||
typeDetail = name + ': ' + printType(type);
|
typeDetail = name + ': ' + printType(type);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DeclarationType.Function:
|
case DeclarationType.Function:
|
||||||
case DeclarationType.Method:
|
case DeclarationType.Method:
|
||||||
if (type.category === TypeCategory.OverloadedFunction) {
|
if (type.category === TypeCategory.OverloadedFunction) {
|
||||||
typeDetail = type.overloads.map(overload =>
|
typeDetail = type.overloads.map(overload =>
|
||||||
name + printType(overload.type)).join('\n');
|
name + printType(overload.type)).join('\n');
|
||||||
} else {
|
} else {
|
||||||
typeDetail = name + printType(type);
|
typeDetail = name + printType(type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeclarationType.Class: {
|
||||||
|
typeDetail = 'class ' + name + '()';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case DeclarationType.Class:
|
case DeclarationType.Alias: {
|
||||||
typeDetail = 'class ' + name + '()';
|
typeDetail = name;
|
||||||
break;
|
if (declaration.path) {
|
||||||
|
const lookupResults = this._importLookup(declaration.path);
|
||||||
|
if (lookupResults) {
|
||||||
|
documentation = lookupResults.docString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DeclarationType.Module:
|
default: {
|
||||||
default:
|
typeDetail = name;
|
||||||
typeDetail = name;
|
break;
|
||||||
break;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (type) {
|
if (type) {
|
||||||
if (type.category === TypeCategory.Module) {
|
if (type.category === TypeCategory.Module) {
|
||||||
documentation = type.docString;
|
documentation = type.docString;
|
||||||
} else if (type.category === TypeCategory.Class) {
|
} else if (type.category === TypeCategory.Class) {
|
||||||
documentation = ClassType.getDocString(type);
|
documentation = ClassType.getDocString(type);
|
||||||
} else if (type.category === TypeCategory.Function) {
|
} else if (type.category === TypeCategory.Function) {
|
||||||
documentation = FunctionType.getDocString(type);
|
documentation = FunctionType.getDocString(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,7 +844,12 @@ export class CompletionProvider {
|
|||||||
private _convertDeclarationTypeToItemKind(declaration: Declaration,
|
private _convertDeclarationTypeToItemKind(declaration: Declaration,
|
||||||
type?: Type): CompletionItemKind {
|
type?: Type): CompletionItemKind {
|
||||||
|
|
||||||
switch (declaration.type) {
|
const resolvedDeclaration = resolveAliasDeclaration(declaration, this._importLookup);
|
||||||
|
if (!resolvedDeclaration) {
|
||||||
|
return CompletionItemKind.Variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (resolvedDeclaration.type) {
|
||||||
case DeclarationType.BuiltIn:
|
case DeclarationType.BuiltIn:
|
||||||
if (type) {
|
if (type) {
|
||||||
if (type.category === TypeCategory.Class) {
|
if (type.category === TypeCategory.Class) {
|
||||||
@ -849,7 +864,7 @@ export class CompletionProvider {
|
|||||||
return CompletionItemKind.Variable;
|
return CompletionItemKind.Variable;
|
||||||
|
|
||||||
case DeclarationType.Variable:
|
case DeclarationType.Variable:
|
||||||
return declaration.isConstant ?
|
return resolvedDeclaration.isConstant ?
|
||||||
CompletionItemKind.Constant :
|
CompletionItemKind.Constant :
|
||||||
CompletionItemKind.Variable;
|
CompletionItemKind.Variable;
|
||||||
|
|
||||||
@ -865,15 +880,8 @@ export class CompletionProvider {
|
|||||||
case DeclarationType.Class:
|
case DeclarationType.Class:
|
||||||
return CompletionItemKind.Class;
|
return CompletionItemKind.Class;
|
||||||
|
|
||||||
case DeclarationType.Module:
|
|
||||||
return CompletionItemKind.Module;
|
|
||||||
|
|
||||||
case DeclarationType.Alias:
|
case DeclarationType.Alias:
|
||||||
if (declaration.resolvedDeclarations) {
|
return CompletionItemKind.Module;
|
||||||
return this._convertDeclarationTypeToItemKind(
|
|
||||||
declaration.resolvedDeclarations[0], type);
|
|
||||||
}
|
|
||||||
return CompletionItemKind.Variable;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,9 +10,10 @@
|
|||||||
* definition is the top of the resolved import file.
|
* definition is the top of the resolved import file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ImportLookup } from '../analyzer/analyzerFileInfo';
|
||||||
import * as AnalyzerNodeInfo from '../analyzer/analyzerNodeInfo';
|
import * as AnalyzerNodeInfo from '../analyzer/analyzerNodeInfo';
|
||||||
import { Declaration } from '../analyzer/declaration';
|
import { Declaration } from '../analyzer/declaration';
|
||||||
import { resolveDeclarationAliases } from '../analyzer/declarationUtils';
|
import { resolveAliasDeclaration } from '../analyzer/declarationUtils';
|
||||||
import * as ParseTreeUtils from '../analyzer/parseTreeUtils';
|
import * as ParseTreeUtils from '../analyzer/parseTreeUtils';
|
||||||
import { Symbol } from '../analyzer/symbol';
|
import { Symbol } from '../analyzer/symbol';
|
||||||
import { ModuleType, TypeCategory } from '../analyzer/types';
|
import { ModuleType, TypeCategory } from '../analyzer/types';
|
||||||
@ -29,7 +30,8 @@ const _startOfFileRange: DiagnosticTextRange = { start: _startOfFilePosition, en
|
|||||||
|
|
||||||
export class DefinitionProvider {
|
export class DefinitionProvider {
|
||||||
static getDefinitionsForPosition(parseResults: ParseResults,
|
static getDefinitionsForPosition(parseResults: ParseResults,
|
||||||
position: DiagnosticTextPosition): DocumentTextRange[] | undefined {
|
position: DiagnosticTextPosition, importLookup: ImportLookup):
|
||||||
|
DocumentTextRange[] | undefined {
|
||||||
|
|
||||||
const offset = convertPositionToOffset(position, parseResults.tokenizerOutput.lines);
|
const offset = convertPositionToOffset(position, parseResults.tokenizerOutput.lines);
|
||||||
if (offset === undefined) {
|
if (offset === undefined) {
|
||||||
@ -43,17 +45,17 @@ export class DefinitionProvider {
|
|||||||
|
|
||||||
const definitions: DocumentTextRange[] = [];
|
const definitions: DocumentTextRange[] = [];
|
||||||
|
|
||||||
if (node.nodeType === ParseNodeType.ModuleName) {
|
if (node.nodeType === ParseNodeType.Name) {
|
||||||
this._addDefinitionsForModuleNameNode(definitions, node, offset);
|
|
||||||
} else if (node.nodeType === ParseNodeType.Name) {
|
|
||||||
// Is the user hovering over a member name? If so, we need to search
|
// Is the user hovering over a member name? If so, we need to search
|
||||||
// in the scope of that type rather than the current node's scope.
|
// in the scope of that type rather than the current node's scope.
|
||||||
if (node.parent && node.parent.nodeType === ParseNodeType.MemberAccess &&
|
if (node.parent && node.parent.nodeType === ParseNodeType.MemberAccess &&
|
||||||
node === node.parent.memberName) {
|
node === node.parent.memberName) {
|
||||||
|
|
||||||
this._addDefinitionsForMemberAccessNode(definitions, node.parent);
|
this._addDefinitionsForMemberAccessNode(definitions, node.parent, importLookup);
|
||||||
|
} else if (node.parent && node.parent.nodeType === ParseNodeType.ModuleName) {
|
||||||
|
this._addDefinitionsForModuleNameNode(definitions, node.parent, offset);
|
||||||
} else {
|
} else {
|
||||||
this._addDefinitionsForNameNode(definitions, node);
|
this._addDefinitionsForNameNode(definitions, node, importLookup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ export class DefinitionProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static _addDefinitionsForMemberAccessNode(definitions: DocumentTextRange[],
|
private static _addDefinitionsForMemberAccessNode(definitions: DocumentTextRange[],
|
||||||
node: MemberAccessExpressionNode) {
|
node: MemberAccessExpressionNode, importLookup: ImportLookup) {
|
||||||
|
|
||||||
const baseType = AnalyzerNodeInfo.getExpressionType(node.leftExpression);
|
const baseType = AnalyzerNodeInfo.getExpressionType(node.leftExpression);
|
||||||
if (!baseType) {
|
if (!baseType) {
|
||||||
@ -88,14 +90,16 @@ export class DefinitionProvider {
|
|||||||
|
|
||||||
if (symbol) {
|
if (symbol) {
|
||||||
const declarations = symbol.getDeclarations();
|
const declarations = symbol.getDeclarations();
|
||||||
this._addResultsForDeclarations(definitions, declarations);
|
this._addResultsForDeclarations(definitions, declarations, importLookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
return subtype;
|
return subtype;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _addDefinitionsForNameNode(definitions: DocumentTextRange[], node: NameNode) {
|
private static _addDefinitionsForNameNode(definitions: DocumentTextRange[],
|
||||||
|
node: NameNode, importLookup: ImportLookup) {
|
||||||
|
|
||||||
const scopeNode = ParseTreeUtils.getScopeNodeForNode(node);
|
const scopeNode = ParseTreeUtils.getScopeNodeForNode(node);
|
||||||
if (!scopeNode) {
|
if (!scopeNode) {
|
||||||
return;
|
return;
|
||||||
@ -113,15 +117,15 @@ export class DefinitionProvider {
|
|||||||
|
|
||||||
const declarations = symbolWithScope.symbol.getDeclarations();
|
const declarations = symbolWithScope.symbol.getDeclarations();
|
||||||
if (declarations) {
|
if (declarations) {
|
||||||
this._addResultsForDeclarations(definitions, declarations);
|
this._addResultsForDeclarations(definitions, declarations, importLookup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _addResultsForDeclarations(definitions: DocumentTextRange[],
|
private static _addResultsForDeclarations(definitions: DocumentTextRange[],
|
||||||
declarations: Declaration[]) {
|
declarations: Declaration[], importLookup: ImportLookup) {
|
||||||
|
|
||||||
declarations.forEach(decl => {
|
declarations.forEach(decl => {
|
||||||
const resolvedDecl = resolveDeclarationAliases(decl);
|
const resolvedDecl = resolveAliasDeclaration(decl, importLookup);
|
||||||
if (resolvedDecl && resolvedDecl.path) {
|
if (resolvedDecl && resolvedDecl.path) {
|
||||||
definitions.push({
|
definitions.push({
|
||||||
path: resolvedDecl.path,
|
path: resolvedDecl.path,
|
||||||
|
@ -11,9 +11,10 @@
|
|||||||
import { Location, Position, Range, SymbolInformation, SymbolKind } from 'vscode-languageserver';
|
import { Location, Position, Range, SymbolInformation, SymbolKind } from 'vscode-languageserver';
|
||||||
import VSCodeUri from 'vscode-uri';
|
import VSCodeUri from 'vscode-uri';
|
||||||
|
|
||||||
|
import { ImportLookup } from '../analyzer/analyzerFileInfo';
|
||||||
import * as AnalyzerNodeInfo from '../analyzer/analyzerNodeInfo';
|
import * as AnalyzerNodeInfo from '../analyzer/analyzerNodeInfo';
|
||||||
import { Declaration, DeclarationType } from '../analyzer/declaration';
|
import { Declaration, DeclarationType } from '../analyzer/declaration';
|
||||||
import { getTypeForDeclaration } from '../analyzer/declarationUtils';
|
import { getTypeForDeclaration, resolveAliasDeclaration } from '../analyzer/declarationUtils';
|
||||||
import * as ParseTreeUtils from '../analyzer/parseTreeUtils';
|
import * as ParseTreeUtils from '../analyzer/parseTreeUtils';
|
||||||
import { ParseTreeWalker } from '../analyzer/parseTreeWalker';
|
import { ParseTreeWalker } from '../analyzer/parseTreeWalker';
|
||||||
import { TypeCategory } from '../analyzer/types';
|
import { TypeCategory } from '../analyzer/types';
|
||||||
@ -31,15 +32,18 @@ class FindSymbolTreeWalker extends ParseTreeWalker {
|
|||||||
private _parseResults: ParseResults;
|
private _parseResults: ParseResults;
|
||||||
private _symbolResults: SymbolInformation[];
|
private _symbolResults: SymbolInformation[];
|
||||||
private _query: string | undefined;
|
private _query: string | undefined;
|
||||||
|
private _importLookup: ImportLookup;
|
||||||
|
|
||||||
constructor(filePath: string, parseResults: ParseResults,
|
constructor(filePath: string, parseResults: ParseResults,
|
||||||
results: SymbolInformation[], query: string | undefined) {
|
results: SymbolInformation[], query: string | undefined,
|
||||||
|
importLookup: ImportLookup) {
|
||||||
|
|
||||||
super();
|
super();
|
||||||
this._filePath = filePath;
|
this._filePath = filePath;
|
||||||
this._parseResults = parseResults;
|
this._parseResults = parseResults;
|
||||||
this._symbolResults = results;
|
this._symbolResults = results;
|
||||||
this._query = query;
|
this._query = query;
|
||||||
|
this._importLookup = importLookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
findSymbols() {
|
findSymbols() {
|
||||||
@ -99,6 +103,11 @@ class FindSymbolTreeWalker extends ParseTreeWalker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resolvedSymbol = resolveAliasDeclaration(declaration, this._importLookup);
|
||||||
|
if (!resolvedSymbol) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let symbolKind: SymbolKind;
|
let symbolKind: SymbolKind;
|
||||||
switch (declaration.type) {
|
switch (declaration.type) {
|
||||||
case DeclarationType.Class:
|
case DeclarationType.Class:
|
||||||
@ -118,7 +127,7 @@ class FindSymbolTreeWalker extends ParseTreeWalker {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DeclarationType.Module:
|
case DeclarationType.Alias:
|
||||||
symbolKind = SymbolKind.Module;
|
symbolKind = SymbolKind.Module;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -173,10 +182,10 @@ class FindSymbolTreeWalker extends ParseTreeWalker {
|
|||||||
|
|
||||||
export class DocumentSymbolProvider {
|
export class DocumentSymbolProvider {
|
||||||
static addSymbolsForDocument(symbolList: SymbolInformation[], query: string | undefined,
|
static addSymbolsForDocument(symbolList: SymbolInformation[], query: string | undefined,
|
||||||
filePath: string, parseResults: ParseResults) {
|
filePath: string, parseResults: ParseResults, importLookup: ImportLookup) {
|
||||||
|
|
||||||
const symbolTreeWalker = new FindSymbolTreeWalker(filePath, parseResults,
|
const symbolTreeWalker = new FindSymbolTreeWalker(filePath, parseResults,
|
||||||
symbolList, query);
|
symbolList, query, importLookup);
|
||||||
symbolTreeWalker.findSymbols();
|
symbolTreeWalker.findSymbols();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,16 @@
|
|||||||
* position within a smart editor.
|
* position within a smart editor.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ImportMap } from '../analyzer/analyzerFileInfo';
|
import { ImportLookup } from '../analyzer/analyzerFileInfo';
|
||||||
import * as AnalyzerNodeInfo from '../analyzer/analyzerNodeInfo';
|
import * as AnalyzerNodeInfo from '../analyzer/analyzerNodeInfo';
|
||||||
import { Declaration, DeclarationType } from '../analyzer/declaration';
|
import { Declaration, DeclarationType } from '../analyzer/declaration';
|
||||||
import * as DeclarationUtils from '../analyzer/declarationUtils';
|
import * as DeclarationUtils from '../analyzer/declarationUtils';
|
||||||
import { ImportType } from '../analyzer/importResult';
|
|
||||||
import * as ParseTreeUtils from '../analyzer/parseTreeUtils';
|
import * as ParseTreeUtils from '../analyzer/parseTreeUtils';
|
||||||
import { ClassType, FunctionType, printType, Type, TypeCategory, UnknownType } from '../analyzer/types';
|
import { ClassType, FunctionType, printType, Type, TypeCategory, UnknownType } from '../analyzer/types';
|
||||||
import { DiagnosticTextPosition, DiagnosticTextRange } from '../common/diagnostic';
|
import { DiagnosticTextPosition, DiagnosticTextRange } from '../common/diagnostic';
|
||||||
import { convertOffsetToPosition, convertPositionToOffset } from '../common/positionUtils';
|
import { convertOffsetToPosition, convertPositionToOffset } from '../common/positionUtils';
|
||||||
import { TextRange } from '../common/textRange';
|
import { TextRange } from '../common/textRange';
|
||||||
import { ModuleNameNode, ParseNode, ParseNodeType } from '../parser/parseNodes';
|
import { ParseNode, ParseNodeType } from '../parser/parseNodes';
|
||||||
import { ParseResults } from '../parser/parser';
|
import { ParseResults } from '../parser/parser';
|
||||||
|
|
||||||
export interface HoverTextPart {
|
export interface HoverTextPart {
|
||||||
@ -34,7 +33,7 @@ export interface HoverResults {
|
|||||||
|
|
||||||
export class HoverProvider {
|
export class HoverProvider {
|
||||||
static getHoverForPosition(parseResults: ParseResults, position: DiagnosticTextPosition,
|
static getHoverForPosition(parseResults: ParseResults, position: DiagnosticTextPosition,
|
||||||
importMap: ImportMap): HoverResults | undefined {
|
importLookup: ImportLookup): HoverResults | undefined {
|
||||||
|
|
||||||
const offset = convertPositionToOffset(position, parseResults.tokenizerOutput.lines);
|
const offset = convertPositionToOffset(position, parseResults.tokenizerOutput.lines);
|
||||||
if (offset === undefined) {
|
if (offset === undefined) {
|
||||||
@ -54,18 +53,19 @@ export class HoverProvider {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (node.nodeType === ParseNodeType.ModuleName) {
|
if (node.nodeType === ParseNodeType.Name) {
|
||||||
this._addResultsForModuleNameNode(results.parts, node, offset, importMap);
|
|
||||||
} else if (node.nodeType === ParseNodeType.Name) {
|
|
||||||
const declarations = DeclarationUtils.getDeclarationsForNameNode(node);
|
const declarations = DeclarationUtils.getDeclarationsForNameNode(node);
|
||||||
if (declarations && declarations.length > 0) {
|
if (declarations && declarations.length > 0) {
|
||||||
this._addResultsForDeclaration(results.parts, declarations[0], node);
|
this._addResultsForDeclaration(results.parts, declarations[0], node, importLookup);
|
||||||
}
|
} else if (!node.parent || node.parent.nodeType !== ParseNodeType.ModuleName) {
|
||||||
|
// If we had no declaration, see if we can provide a minimal tooltip. We'll skip
|
||||||
// If we had no declaration, see if we can provide a minimal tooltip.
|
// this if it's part of a module name, since a module name part with no declaration
|
||||||
if (results.parts.length === 0) {
|
// is a directory (a namespace package), and we don't want to provide any hover
|
||||||
this._addResultsPart(results.parts, node.nameToken.value + this._getTypeText(node), true);
|
// information in that case.
|
||||||
this._addDocumentationPart(results.parts, node);
|
if (results.parts.length === 0) {
|
||||||
|
this._addResultsPart(results.parts, node.nameToken.value + this._getTypeText(node), true);
|
||||||
|
this._addDocumentationPart(results.parts, node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,16 +73,11 @@ export class HoverProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static _addResultsForDeclaration(parts: HoverTextPart[],
|
private static _addResultsForDeclaration(parts: HoverTextPart[],
|
||||||
declaration: Declaration, node: ParseNode): void {
|
declaration: Declaration, node: ParseNode, importLookup: ImportLookup): void {
|
||||||
|
|
||||||
let resolvedDecl: Declaration | undefined = declaration;
|
|
||||||
while (resolvedDecl && resolvedDecl.type === DeclarationType.Alias) {
|
|
||||||
resolvedDecl = resolvedDecl.resolvedDeclarations ?
|
|
||||||
resolvedDecl.resolvedDeclarations[0] : undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const resolvedDecl = DeclarationUtils.resolveAliasDeclaration(declaration, importLookup);
|
||||||
if (!resolvedDecl) {
|
if (!resolvedDecl) {
|
||||||
return undefined;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (resolvedDecl.type) {
|
switch (resolvedDecl.type) {
|
||||||
@ -109,7 +104,7 @@ export class HoverProvider {
|
|||||||
|
|
||||||
case DeclarationType.Class: {
|
case DeclarationType.Class: {
|
||||||
if (node.nodeType === ParseNodeType.Name) {
|
if (node.nodeType === ParseNodeType.Name) {
|
||||||
this._addResultsPart(parts, '(class) ' + this._getTypeText(node), true);
|
this._addResultsPart(parts, '(class) ' + node.nameToken.value, true);
|
||||||
this._addDocumentationPart(parts, node);
|
this._addDocumentationPart(parts, node);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -139,7 +134,7 @@ export class HoverProvider {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DeclarationType.Module: {
|
case DeclarationType.Alias: {
|
||||||
if (node.nodeType === ParseNodeType.Name) {
|
if (node.nodeType === ParseNodeType.Name) {
|
||||||
this._addResultsPart(parts, '(module) ' + node.nameToken.value, true);
|
this._addResultsPart(parts, '(module) ' + node.nameToken.value, true);
|
||||||
this._addDocumentationPart(parts, node);
|
this._addDocumentationPart(parts, node);
|
||||||
@ -150,46 +145,6 @@ export class HoverProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static _addResultsForModuleNameNode(parts: HoverTextPart[], node: ModuleNameNode,
|
|
||||||
offset: number, importMap: ImportMap) {
|
|
||||||
|
|
||||||
// If this is an imported module name, try to map the position
|
|
||||||
// to the resolved import path.
|
|
||||||
const importInfo = AnalyzerNodeInfo.getImportInfo(node);
|
|
||||||
if (!importInfo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let pathOffset = node.nameParts.findIndex(range => {
|
|
||||||
return offset >= range.start && offset < TextRange.getEnd(range);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (pathOffset < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pathOffset >= importInfo.resolvedPaths.length) {
|
|
||||||
pathOffset = importInfo.resolvedPaths.length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (importInfo.resolvedPaths[pathOffset]) {
|
|
||||||
const resolvedPath = importInfo.resolvedPaths[pathOffset];
|
|
||||||
this._addResultsPart(parts, '(module) "' + resolvedPath + '"', true);
|
|
||||||
|
|
||||||
if (importInfo.importType === ImportType.ThirdParty && !importInfo.isStubFile) {
|
|
||||||
this._addResultsPart(parts,
|
|
||||||
'No type stub found for this module. Imported symbol types are unknown.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the module has been resolved and already analyzed,
|
|
||||||
// we can add the docString for it as well.
|
|
||||||
const moduleType = importMap.get(resolvedPath);
|
|
||||||
if (moduleType) {
|
|
||||||
this._addDocumentationPartForType(parts, moduleType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static _getTypeFromNode(node: ParseNode): Type | undefined {
|
private static _getTypeFromNode(node: ParseNode): Type | undefined {
|
||||||
return AnalyzerNodeInfo.getExpressionType(node);
|
return AnalyzerNodeInfo.getExpressionType(node);
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
* by a location within a file.
|
* by a location within a file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ImportLookup } from '../analyzer/analyzerFileInfo';
|
||||||
import { Declaration, DeclarationType } from '../analyzer/declaration';
|
import { Declaration, DeclarationType } from '../analyzer/declaration';
|
||||||
import * as DeclarationUtils from '../analyzer/declarationUtils';
|
import * as DeclarationUtils from '../analyzer/declarationUtils';
|
||||||
import * as ParseTreeUtils from '../analyzer/parseTreeUtils';
|
import * as ParseTreeUtils from '../analyzer/parseTreeUtils';
|
||||||
import { ParseTreeWalker } from '../analyzer/parseTreeWalker';
|
import { ParseTreeWalker } from '../analyzer/parseTreeWalker';
|
||||||
import { Symbol } from '../analyzer/symbol';
|
|
||||||
import { DiagnosticTextPosition, DocumentTextRange } from '../common/diagnostic';
|
import { DiagnosticTextPosition, DocumentTextRange } from '../common/diagnostic';
|
||||||
import { convertOffsetToPosition, convertPositionToOffset } from '../common/positionUtils';
|
import { convertOffsetToPosition, convertPositionToOffset } from '../common/positionUtils';
|
||||||
import { TextRange } from '../common/textRange';
|
import { TextRange } from '../common/textRange';
|
||||||
@ -31,15 +31,18 @@ class FindReferencesTreeWalker extends ParseTreeWalker {
|
|||||||
private _filePath: string;
|
private _filePath: string;
|
||||||
private _referencesResult: ReferencesResult;
|
private _referencesResult: ReferencesResult;
|
||||||
private _includeDeclaration: boolean;
|
private _includeDeclaration: boolean;
|
||||||
|
private _importLookup: ImportLookup;
|
||||||
|
|
||||||
constructor(parseResults: ParseResults, filePath: string,
|
constructor(parseResults: ParseResults, filePath: string,
|
||||||
referencesResult: ReferencesResult, includeDeclaration: boolean) {
|
referencesResult: ReferencesResult, includeDeclaration: boolean,
|
||||||
|
importLookup: ImportLookup) {
|
||||||
|
|
||||||
super();
|
super();
|
||||||
this._parseResults = parseResults;
|
this._parseResults = parseResults;
|
||||||
this._filePath = filePath;
|
this._filePath = filePath;
|
||||||
this._referencesResult = referencesResult;
|
this._referencesResult = referencesResult;
|
||||||
this._includeDeclaration = includeDeclaration;
|
this._includeDeclaration = includeDeclaration;
|
||||||
|
this._importLookup = importLookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
findReferences() {
|
findReferences() {
|
||||||
@ -69,14 +72,22 @@ class FindReferencesTreeWalker extends ParseTreeWalker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _resultsContainsDeclaration(declaration: Declaration) {
|
private _resultsContainsDeclaration(declaration: Declaration) {
|
||||||
|
const resolvedDecl = DeclarationUtils.resolveAliasDeclaration(declaration, this._importLookup);
|
||||||
|
if (!resolvedDecl) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The reference results declarations are already resolved, so we don't
|
||||||
|
// need to call resolveAliasDeclaration on them.
|
||||||
return this._referencesResult.declarations.some(decl =>
|
return this._referencesResult.declarations.some(decl =>
|
||||||
DeclarationUtils.areDeclarationsSame(decl, declaration));
|
DeclarationUtils.areDeclarationsSame(decl, resolvedDecl));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ReferencesProvider {
|
export class ReferencesProvider {
|
||||||
static getReferencesForPosition(parseResults: ParseResults, filePath: string,
|
static getReferencesForPosition(parseResults: ParseResults, filePath: string,
|
||||||
position: DiagnosticTextPosition, includeDeclaration: boolean):
|
position: DiagnosticTextPosition, includeDeclaration: boolean,
|
||||||
|
importLookup: ImportLookup):
|
||||||
ReferencesResult | undefined {
|
ReferencesResult | undefined {
|
||||||
|
|
||||||
const offset = convertPositionToOffset(position, parseResults.tokenizerOutput.lines);
|
const offset = convertPositionToOffset(position, parseResults.tokenizerOutput.lines);
|
||||||
@ -94,12 +105,24 @@ export class ReferencesProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const declarations = DeclarationUtils.getDeclarationsForNameNode(node);
|
const declarations = DeclarationUtils.getDeclarationsForNameNode(node);
|
||||||
if (!declarations || declarations.length === 0) {
|
if (!declarations) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvedDeclarations: Declaration[] = [];
|
||||||
|
declarations.forEach(decl => {
|
||||||
|
const resovledDecl = DeclarationUtils.resolveAliasDeclaration(decl, importLookup);
|
||||||
|
if (resovledDecl) {
|
||||||
|
resolvedDeclarations.push(resovledDecl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (resolvedDeclarations.length === 0) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this a type that potentially requires a global search?
|
// Is this a type that potentially requires a global search?
|
||||||
const symbolDeclType = declarations[0].type;
|
const symbolDeclType = resolvedDeclarations[0].type;
|
||||||
|
|
||||||
// Parameters are local to a scope, so they don't require a global search.
|
// Parameters are local to a scope, so they don't require a global search.
|
||||||
const requiresGlobalSearch = symbolDeclType !== DeclarationType.Parameter;
|
const requiresGlobalSearch = symbolDeclType !== DeclarationType.Parameter;
|
||||||
@ -107,22 +130,23 @@ export class ReferencesProvider {
|
|||||||
const results: ReferencesResult = {
|
const results: ReferencesResult = {
|
||||||
requiresGlobalSearch,
|
requiresGlobalSearch,
|
||||||
nodeAtOffset: node,
|
nodeAtOffset: node,
|
||||||
declarations,
|
declarations: resolvedDeclarations,
|
||||||
locations: []
|
locations: []
|
||||||
};
|
};
|
||||||
|
|
||||||
const refTreeWalker = new FindReferencesTreeWalker(parseResults,
|
const refTreeWalker = new FindReferencesTreeWalker(parseResults,
|
||||||
filePath, results, includeDeclaration);
|
filePath, results, includeDeclaration, importLookup);
|
||||||
refTreeWalker.findReferences();
|
refTreeWalker.findReferences();
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
static addReferences(parseResults: ParseResults, filePath: string,
|
static addReferences(parseResults: ParseResults, filePath: string,
|
||||||
referencesResult: ReferencesResult, includeDeclaration: boolean): void {
|
referencesResult: ReferencesResult, includeDeclaration: boolean,
|
||||||
|
importLookup: ImportLookup): void {
|
||||||
|
|
||||||
const refTreeWalker = new FindReferencesTreeWalker(parseResults,
|
const refTreeWalker = new FindReferencesTreeWalker(parseResults,
|
||||||
filePath, referencesResult, includeDeclaration);
|
filePath, referencesResult, includeDeclaration, importLookup);
|
||||||
refTreeWalker.findReferences();
|
refTreeWalker.findReferences();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,7 @@ export interface ParseResults {
|
|||||||
importedModules: ModuleImport[];
|
importedModules: ModuleImport[];
|
||||||
futureImports: StringMap<boolean>;
|
futureImports: StringMap<boolean>;
|
||||||
tokenizerOutput: TokenizerOutput;
|
tokenizerOutput: TokenizerOutput;
|
||||||
|
containsWildcardImport: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParseExpressionTextResults {
|
export interface ParseExpressionTextResults {
|
||||||
@ -92,6 +93,7 @@ export class Parser {
|
|||||||
private _isParsingTypeAnnotation = false;
|
private _isParsingTypeAnnotation = false;
|
||||||
private _futureImportMap = new StringMap<boolean>();
|
private _futureImportMap = new StringMap<boolean>();
|
||||||
private _importedModules: ModuleImport[] = [];
|
private _importedModules: ModuleImport[] = [];
|
||||||
|
private _containsWildcardImport = false;
|
||||||
|
|
||||||
parseSourceFile(fileContents: string, parseOptions: ParseOptions,
|
parseSourceFile(fileContents: string, parseOptions: ParseOptions,
|
||||||
diagSink: DiagnosticSink, cancelToken?: CancelToken): ParseResults {
|
diagSink: DiagnosticSink, cancelToken?: CancelToken): ParseResults {
|
||||||
@ -132,7 +134,8 @@ export class Parser {
|
|||||||
parseTree: moduleNode,
|
parseTree: moduleNode,
|
||||||
importedModules: this._importedModules,
|
importedModules: this._importedModules,
|
||||||
futureImports: this._futureImportMap,
|
futureImports: this._futureImportMap,
|
||||||
tokenizerOutput: this._tokenizerOutput!
|
tokenizerOutput: this._tokenizerOutput!,
|
||||||
|
containsWildcardImport: this._containsWildcardImport
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -979,6 +982,7 @@ export class Parser {
|
|||||||
if (this._consumeTokenIfOperator(OperatorType.Multiply)) {
|
if (this._consumeTokenIfOperator(OperatorType.Multiply)) {
|
||||||
extendRange(importFromNode, possibleStarToken);
|
extendRange(importFromNode, possibleStarToken);
|
||||||
importFromNode.isWildcardImport = true;
|
importFromNode.isWildcardImport = true;
|
||||||
|
this._containsWildcardImport = true;
|
||||||
} else {
|
} else {
|
||||||
const inParen = this._consumeTokenIfType(TokenType.OpenParenthesis);
|
const inParen = this._consumeTokenIfType(TokenType.OpenParenthesis);
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ import { AnalyzerFileInfo } from '../analyzer/analyzerFileInfo';
|
|||||||
import { ModuleScopeBinder } from '../analyzer/binder';
|
import { ModuleScopeBinder } from '../analyzer/binder';
|
||||||
import { ImportResolver } from '../analyzer/importResolver';
|
import { ImportResolver } from '../analyzer/importResolver';
|
||||||
import { Program } from '../analyzer/program';
|
import { Program } from '../analyzer/program';
|
||||||
|
import { SymbolTable } from '../analyzer/symbol';
|
||||||
import { TestWalker } from '../analyzer/testWalker';
|
import { TestWalker } from '../analyzer/testWalker';
|
||||||
import { ModuleType } from '../analyzer/types';
|
|
||||||
import { cloneDiagnosticSettings, ConfigOptions, ExecutionEnvironment } from '../common/configOptions';
|
import { cloneDiagnosticSettings, ConfigOptions, ExecutionEnvironment } from '../common/configOptions';
|
||||||
import { Diagnostic, DiagnosticCategory } from '../common/diagnostic';
|
import { Diagnostic, DiagnosticCategory } from '../common/diagnostic';
|
||||||
import { DiagnosticSink, TextRangeDiagnosticSink } from '../common/diagnosticSink';
|
import { DiagnosticSink, TextRangeDiagnosticSink } from '../common/diagnosticSink';
|
||||||
@ -77,7 +77,7 @@ export function buildAnalyzerFileInfo(filePath: string, parseResults: ParseResul
|
|||||||
const analysisDiagnostics = new TextRangeDiagnosticSink(parseResults.tokenizerOutput.lines);
|
const analysisDiagnostics = new TextRangeDiagnosticSink(parseResults.tokenizerOutput.lines);
|
||||||
|
|
||||||
const fileInfo: AnalyzerFileInfo = {
|
const fileInfo: AnalyzerFileInfo = {
|
||||||
importMap: new Map<string, ModuleType>(),
|
importLookup: _ => undefined,
|
||||||
futureImports: new StringMap<boolean>(),
|
futureImports: new StringMap<boolean>(),
|
||||||
builtinsScope: undefined,
|
builtinsScope: undefined,
|
||||||
diagnosticSink: analysisDiagnostics,
|
diagnosticSink: analysisDiagnostics,
|
||||||
|
Loading…
Reference in New Issue
Block a user