import { CancellationToken , CompletionItem , DocumentHighlight , DocumentSymbol , MarkupKind , } from 'vscode-languageserver' ; import { TextDocument , TextDocumentContentChangeEvent } from 'vscode-languageserver-textdocument' ; import { isMainThread } from 'worker_threads' ; import * as SymbolNameUtils from '../analyzer/symbolNameUtils' ; import { OperationCanceledException } from '../common/cancellationUtils' ; import { ConfigOptions , ExecutionEnvironment , getBasicDiagnosticRuleSet } from '../common/configOptions' ; import { ConsoleInterface , StandardConsole } from '../common/console' ; import { assert } from '../common/debug' ; import { convertLevelToCategory , Diagnostic , DiagnosticCategory } from '../common/diagnostic' ; import { DiagnosticSink , TextRangeDiagnosticSink } from '../common/diagnosticSink' ; import { TextEditAction } from '../common/editAction' ; import { FileSystem } from '../common/fileSystem' ; import { LogTracker } from '../common/logTracker' ; import { getFileName , normalizeSlashes , stripFileExtension } from '../common/pathUtils' ; import * as StringUtils from '../common/stringUtils' ; import { DocumentRange , getEmptyRange , Position , TextRange } from '../common/textRange' ; import { TextRangeCollection } from '../common/textRangeCollection' ; import { timingStats } from '../common/timing' ; import { ModuleSymbolMap } from '../languageService/autoImporter' ; import { AbbreviationMap , CompletionOptions , CompletionResults } from '../languageService/completionProvider' ; import { CompletionItemData , CompletionProvider } from '../languageService/completionProvider' ; import { DefinitionFilter , DefinitionProvider } from '../languageService/definitionProvider' ; import { DocumentHighlightProvider } from '../languageService/documentHighlightProvider' ; import { DocumentSymbolProvider , IndexOptions , IndexResults } from '../languageService/documentSymbolProvider' ; import { HoverProvider , HoverResults } from '../languageService/hoverProvider' ; import { performQuickAction } from '../languageService/quickActions' ; import { ReferenceCallback , ReferencesProvider , ReferencesResult } from '../languageService/referencesProvider' ; import { SignatureHelpProvider , SignatureHelpResults } from '../languageService/signatureHelpProvider' ; import { Localizer } from '../localization/localize' ; import { ModuleNode , NameNode } from '../parser/parseNodes' ; import { ModuleImport , ParseOptions , Parser , ParseResults } from '../parser/parser' ; import { Token } from '../parser/tokenizerTypes' ; import { AnalyzerFileInfo , ImportLookup } from './analyzerFileInfo' ; import * as AnalyzerNodeInfo from './analyzerNodeInfo' ; import { Binder } from './binder' ; import { Checker } from './checker' ; import { CircularDependency } from './circularDependency' ; import * as CommentUtils from './commentUtils' ; import { ImportResolver } from './importResolver' ; import { ImportResult } from './importResult' ; import { ParseTreeCleanerWalker } from './parseTreeCleaner' ; import { Scope } from './scope' ; import { SourceMapper } from './sourceMapper' ; import { SymbolTable } from './symbol' ; import { TestWalker } from './testWalker' ; import { TypeEvaluator } from './typeEvaluatorTypes' ; const _maxImportCyclesPerFile = 4 ; const _maxSourceFileSize = 50 * 1024 * 1024 ; interface ResolveImportResult { imports : ImportResult [ ] ; builtinsImportResult ? : ImportResult | undefined ; typingModulePath ? : string | undefined ; typeshedModulePath ? : string | undefined ; collectionsModulePath ? : string | undefined ; } export class SourceFile { private _console : ConsoleInterface ; private readonly _filePath : string ; private readonly _moduleName : string ; private readonly _isStubFile : boolean ; private readonly _isThirdPartyImport : boolean ; private readonly _isTypingStubFile : boolean ; private readonly _isTypingExtensionsStubFile : boolean ; private readonly _isBuiltInStubFile : boolean ; private readonly _isThirdPartyPyTypedPresent : boolean ; private _isFileDeleted = false ; private _diagnosticVersion = 0 ; private _fileContentsVersion = 0 ; private _lastFileContentLength : number | undefined = undefined ; private _lastFileContentHash : number | undefined = undefined ; private _clientDocument : TextDocument | undefined ; private _analyzedFileContentsVersion = - 1 ; private _parseTreeNeedsCleaning = false ; private _parseResults : ParseResults | undefined ; private _moduleSymbolTable : SymbolTable | undefined ; private _cachedIndexResults : IndexResults | undefined ; private _isBindingInProgress = false ; private _parseDiagnostics : Diagnostic [ ] = [ ] ; private _bindDiagnostics : Diagnostic [ ] = [ ] ; private _checkerDiagnostics : Diagnostic [ ] = [ ] ; private _typeIgnoreLines : { [ line ] : boolean ; } = { } ; private _typeIgnoreAll = false ; private _diagnosticRuleSet = getBasicDiagnosticRuleSet ( ) ; private _circularDependencies : CircularDependency [ ] = [ ] ; private _hitMaxImportDepth : number | undefined ; private _isBindingNeeded = true ; private _isCheckingNeeded = true ; private _indexingNeeded = true ; private _imports : ImportResult [ ] | undefined ; private _builtinsImport : ImportResult | undefined ; private _typingModulePath : string | undefined ; private _typeshedModulePath : string | undefined ; private _collectionsModulePath : string | undefined ; private _logTracker : LogTracker ; readonly fileSystem : FileSystem ; constructor ( fs , filePath , moduleName , isThirdPartyImport , isThirdPartyPyTypedPresent , console ? , logTracker ? ) { this . fileSystem = fs ; this . _console = console || new StandardConsole ( ) ; this . _filePath = filePath ; this . _moduleName = moduleName ; this . _isStubFile = filePath . endsWith ( '.pyi' ) ; this . _isThirdPartyImport = isThirdPartyImport ; this . _isThirdPartyPyTypedPresent = isThirdPartyPyTypedPresent ; const fileName = getFileName ( filePath ) ; this . _isTypingStubFile = this . _isStubFile && ( this . _filePath . endsWith ( normalizeSlashes ( 'stdlib/typing.pyi' ) ) || fileName === 'typing_extensions.pyi' ) ; this . _isTypingExtensionsStubFile = this . _isStubFile && fileName === 'typing_extensions.pyi' ; this . _isBuiltInStubFile = false ; if ( this . _isStubFile ) { if ( this . _filePath . endsWith ( normalizeSlashes ( 'stdlib/collections/__init__.pyi' ) ) || this . _filePath . endsWith ( normalizeSlashes ( 'stdlib/asyncio/futures.pyi' ) ) || this . _filePath . endsWith ( normalizeSlashes ( 'stdlib/asyncio/tasks.pyi' ) ) || this . _filePath . endsWith ( normalizeSlashes ( 'stdlib/builtins.pyi' ) ) || this . _filePath . endsWith ( normalizeSlashes ( 'stdlib/_importlib_modulespec.pyi' ) ) || this . _filePath . endsWith ( normalizeSlashes ( 'stdlib/dataclasses.pyi' ) ) || this . _filePath . endsWith ( normalizeSlashes ( 'stdlib/abc.pyi' ) ) || this . _filePath . endsWith ( normalizeSlashes ( 'stdlib/enum.pyi' ) ) || this . _filePath . endsWith ( normalizeSlashes ( 'stdlib/queue.pyi' ) ) || this . _filePath . endsWith ( normalizeSlashes ( 'stdlib/types.pyi' ) ) ) { this . _isBuiltInStubFile = true ; } } this . _logTracker = logTracker ?? new LogTracker ( console , isMainThread ? 'FG' : 'BG' ) ; } getFilePath ( ) { return this . _filePath ; } getDiagnosticVersion ( ) { return this . _diagnosticVersion ; } isStubFile ( ) { return this . _isStubFile ; } isThirdPartyPyTypedPresent ( ) { return this . _isThirdPartyPyTypedPresent ; } getDiagnostics ( options , prevDiagnosticVersion ? ) { if ( this . _diagnosticVersion === prevDiagnosticVersion ) { return undefined ; } let includeWarningsAndErrors = true ; if ( this . _isThirdPartyImport ) { includeWarningsAndErrors = false ; } let diagList = [ ] ; diagList = diagList . concat ( this . _parseDiagnostics , this . _bindDiagnostics , this . _checkerDiagnostics ) ; if ( options . diagnosticRuleSet . enableTypeIgnoreComments ) { if ( Object . keys ( this . _typeIgnoreLines ) . length > 0 ) { diagList = diagList . filter ( ( d ) => { if ( d . category !== DiagnosticCategory . UnusedCode && d . category !== DiagnosticCategory . Deprecated ) { for ( let line = d . range . start . line ; line <= d . range . end . line ; line ++ ) { if ( this . _typeIgnoreLines [ line ] ) { return false ; } } } return true ; } ) ; } } if ( options . diagnosticRuleSet . reportImportCycles !== 'none' && this . _circularDependencies . length > 0 ) { const category = convertLevelToCategory ( options . diagnosticRuleSet . reportImportCycles ) ; this . _circularDependencies . forEach ( ( cirDep ) => { diagList . push ( new Diagnostic ( category , Localizer . Diagnostic . importCycleDetected ( ) + '\n' + cirDep . getPaths ( ) . map ( ( path ) => '  ' + path ) . join ( '\n' ) , getEmptyRange ( ) ) ) ; } ) ; } if ( this . _hitMaxImportDepth !== undefined ) { diagList . push ( new Diagnostic ( DiagnosticCategory . Error , Localizer . Diagnostic . importDepthExceeded ( ) . format ( { depth : this . _hitMaxImportDepth } ) , getEmptyRange ( ) ) ) ; } if ( options . ignore . find ( ( ignoreFileSpec ) => ignoreFileSpec . regExp . test ( this . _filePath ) ) ) { diagList = [ ] ; } if ( options . diagnosticRuleSet . enableTypeIgnoreComments ) { if ( this . _typeIgnoreAll ) { diagList = [ ] ; } } if ( ! includeWarningsAndErrors ) { diagList = diagList . filter ( ( diag ) => diag . category === DiagnosticCategory . UnusedCode || diag . category === DiagnosticCategory . Deprecated ) ; } return diagList ; } getImports ( ) { return this . _imports || [ ] ; } getBuiltinsImport ( ) { return this . _builtinsImport ; } getModuleSymbolTable ( ) { return this . _moduleSymbolTable ; } didContentsChangeOnDisk ( ) { if ( this . _clientDocument ) { return false ; } if ( this . _lastFileContentLength === undefined ) { return false ; } try { const fileContents = this . fileSystem . readFileSync ( this . _filePath , 'utf8' ) ; if ( fileContents . length !== this . _lastFileContentLength ) { return true ; } if ( StringUtils . hashString ( fileContents ) !== this . _lastFileContentHash ) { return true ; } } catch ( error ) { return true ; } return false ; } dropParseAndBindInfo ( ) { this . _parseResults = undefined ; this . _moduleSymbolTable = undefined ; this . _isBindingNeeded = true ; } markDirty ( ) { this . _fileContentsVersion ++ ; this . _isCheckingNeeded = true ; this . _isBindingNeeded = true ; this . _indexingNeeded = true ; this . _moduleSymbolTable = undefined ; this . _cachedIndexResults = undefined ; } markReanalysisRequired ( ) { this . _isCheckingNeeded = true ; if ( this . _parseResults ) { if ( this . _parseResults . containsWildcardImport || AnalyzerNodeInfo . getDunderAllInfo ( this . _parseResults . parseTree ) !== undefined ) { this . _parseTreeNeedsCleaning = true ; this . _isBindingNeeded = true ; this . _indexingNeeded = true ; this . _moduleSymbolTable = undefined ; this . _cachedIndexResults = undefined ; } } } getClientVersion ( ) { return this . _clientDocument ?. version ; } getOpenFileContents ( ) { return this . _clientDocument ?. getText ( ) ; } getFileContent ( ) { const openFileContent = this . getOpenFileContents ( ) ; if ( openFileContent ) { return openFileContent ; } try { const fileStat = this . fileSystem . statSync ( this . _filePath ) ; if ( fileStat . size > _maxSourceFileSize ) { this . _console . error ( `File length of "${ this . _filePath }" is ${ fileStat . size } ` + `which exceeds the maximum supported file size of ${ _maxSourceFileSize }` ) ; throw new Error ( 'File larger than max' ) ; } return this . fileSystem . readFileSync ( this . _filePath , 'utf8' ) ; } catch ( error ) { return undefined ; } } setClientVersion ( version , contents ) { if ( version === null ) { this . _clientDocument = undefined ; } else { if ( ! this . _clientDocument ) { this . _clientDocument = TextDocument . create ( this . _filePath , 'python' , version , '' ) ; } this . _clientDocument = TextDocument . update ( this . _clientDocument , contents , version ) ; const fileContents = this . _clientDocument . getText ( ) ; const contentsHash = StringUtils . hashString ( fileContents ) ; if ( fileContents . length !== this . _lastFileContentLength || contentsHash !== this . _lastFileContentHash ) { this . markDirty ( ) ; } this . _lastFileContentLength = fileContents . length ; this . _lastFileContentHash = contentsHash ; this . _isFileDeleted = false ; } } prepareForClose ( ) { } isFileDeleted ( ) { return this . _isFileDeleted ; } isParseRequired ( ) { return ! this . _parseResults || this . _analyzedFileContentsVersion !== this . _fileContentsVersion ; } isBindingRequired ( ) { if ( this . _isBindingInProgress ) { return false ; } if ( this . isParseRequired ( ) ) { return true ; } return this . _isBindingNeeded ; } isIndexingRequired ( ) { return this . _indexingNeeded ; } isCheckingRequired ( ) { return this . _isCheckingNeeded ; } getParseResults ( ) { if ( ! this . isParseRequired ( ) ) { return this . _parseResults ; } return undefined ; } getCachedIndexResults ( ) { return this . _cachedIndexResults ; } cacheIndexResults ( indexResults ) { this . _cachedIndexResults = indexResults ; } addCircularDependency ( circDependency ) { let updatedDependencyList = false ; if ( this . _circularDependencies . length < _maxImportCyclesPerFile ) { if ( ! this . _circularDependencies . some ( ( dep ) => dep . isEqual ( circDependency ) ) ) { this . _circularDependencies . push ( circDependency ) ; updatedDependencyList = true ; } } if ( updatedDependencyList ) { this . _diagnosticVersion ++ ; } } setHitMaxImportDepth ( maxImportDepth ) { this . _hitMaxImportDepth = maxImportDepth ; } parse ( configOptions , importResolver , content ? ) { return this . _logTracker . log ( `parsing: ${ this . _getPathForLogging ( this . _filePath ) }` , ( logState ) => { if ( ! this . isParseRequired ( ) ) { logState . suppress ( ) ; return false ; } const diagSink = new DiagnosticSink ( ) ; let fileContents = this . getOpenFileContents ( ) ; if ( fileContents === undefined ) { try { const startTime = timingStats . readFileTime . totalTime ; timingStats . readFileTime . timeOperation ( ( ) => { fileContents = content ?? this . getFileContent ( ) ; if ( fileContents === undefined ) { throw new Error ( "Can't get file content" ) ; } this . _lastFileContentLength = fileContents . length ; this . _lastFileContentHash = StringUtils . hashString ( fileContents ) ; } ) ; logState . add ( `fs read ${ timingStats . readFileTime . totalTime - startTime }ms` ) ; } catch ( error ) { diagSink . addError ( `Source file could not be read` , getEmptyRange ( ) ) ; fileContents = '' ; if ( ! this . fileSystem . existsSync ( this . _filePath ) ) { this . _isFileDeleted = true ; } } } const execEnvironment = configOptions . findExecEnvironment ( this . _filePath ) ; const parseOptions = new ParseOptions ( ) ; if ( this . _filePath . endsWith ( 'pyi' ) ) { parseOptions . isStubFile = true ; } parseOptions . pythonVersion = execEnvironment . pythonVersion ; parseOptions . skipFunctionAndClassBody = configOptions . indexGenerationMode ?? false ; try { const parser = new Parser ( ) ; const parseResults = parser . parseSourceFile ( fileContents ! , parseOptions , diagSink ) ; assert ( parseResults !== undefined && parseResults . tokenizerOutput !== undefined ) ; this . _parseResults = parseResults ; this . _typeIgnoreLines = this . _parseResults . tokenizerOutput . typeIgnoreLines ; this . _typeIgnoreAll = this . _parseResults . tokenizerOutput . typeIgnoreAll ; timingStats . resolveImportsTime . timeOperation ( ( ) => { const importResult = this . _resolveImports ( importResolver , parseResults . importedModules , execEnvironment ) ; this . _imports = importResult . imports ; this . _builtinsImport = importResult . builtinsImportResult ; this . _typingModulePath = importResult . typingModulePath ; this . _typeshedModulePath = importResult . typeshedModulePath ; this . _collectionsModulePath = importResult . collectionsModulePath ; this . _parseDiagnostics = diagSink . fetchAndClear ( ) ; } ) ; const useStrict = configOptions . strict . find ( ( strictFileSpec ) => strictFileSpec . regExp . test ( this . _filePath ) ) !== undefined ; this . _diagnosticRuleSet = CommentUtils . getFileLevelDirectives ( this . _parseResults . tokenizerOutput . tokens , configOptions . diagnosticRuleSet , useStrict ) ; } catch ( e ) { const message = ( e . stack ? e . stack . toString ( ) : undefined ) || ( typeof e . message === 'string' ? e . message : undefined ) || JSON . stringify ( e ) ; this . _console . error ( Localizer . Diagnostic . internalParseError ( ) . format ( { file : this . getFilePath ( ) , message } ) ) ; this . _parseResults = { text : '' , parseTree : ModuleNode . create ( { start : 0 , length : 0 } ) , importedModules : [ ] , futureImports : new Map < string , boolean > ( ) , tokenizerOutput : { tokens : new TextRangeCollection < Token > ( [ ] ) , lines : new TextRangeCollection < TextRange > ( [ ] ) , typeIgnoreAll : false , typeIgnoreLines : { } , predominantEndOfLineSequence : '\n' , predominantTabSequence : '    ' , predominantSingleQuoteCharacter : "'" , } , containsWildcardImport : false , } ; this . _imports = undefined ; this . _builtinsImport = undefined ; const diagSink = new DiagnosticSink ( ) ; diagSink . addError ( Localizer . Diagnostic . internalParseError ( ) . format ( { file : this . getFilePath ( ) , message } ) , getEmptyRange ( ) ) ; this . _parseDiagnostics = diagSink . fetchAndClear ( ) ; } this . _analyzedFileContentsVersion = this . _fileContentsVersion ; this . _indexingNeeded = true ; this . _isBindingNeeded = true ; this . _isCheckingNeeded = true ; this . _parseTreeNeedsCleaning = false ; this . _hitMaxImportDepth = undefined ; this . _diagnosticVersion ++ ; return true ; } ) ; } index ( options , token ) { return this . _logTracker . log ( `indexing: ${ this . _getPathForLogging ( this . _filePath ) }` , ( ls ) => { if ( ! this . _parseResults || ! this . isIndexingRequired ( ) ) { ls . suppress ( ) ; return undefined ; } this . _indexingNeeded = false ; const symbols = DocumentSymbolProvider . indexSymbols ( AnalyzerNodeInfo . getFileInfo ( this . _parseResults . parseTree ) ! , this . _parseResults , options , token ) ; ls . add ( `found ${ symbols . length }` ) ; const name = stripFileExtension ( getFileName ( this . _filePath ) ) ; const privateOrProtected = SymbolNameUtils . isPrivateOrProtectedName ( name ) ; return { privateOrProtected , symbols } ; } ) ; } getDefinitionsForPosition ( sourceMapper , position , filter , evaluator , token ) { if ( ! this . _parseResults ) { return undefined ; } return DefinitionProvider . getDefinitionsForPosition ( sourceMapper , this . _parseResults , position , filter , evaluator , token ) ; } getTypeDefinitionsForPosition ( sourceMapper , position , evaluator , filePath , token ) { if ( ! this . _parseResults ) { return undefined ; } return DefinitionProvider . getTypeDefinitionsForPosition ( sourceMapper , this . _parseResults , position , evaluator , filePath , token ) ; } getDeclarationForNode ( sourceMapper , node , evaluator , reporter , token ) { if ( ! this . _parseResults ) { return undefined ; } return ReferencesProvider . getDeclarationForNode ( sourceMapper , this . _filePath , node , evaluator , reporter , token ) ; } getDeclarationForPosition ( sourceMapper , position , evaluator , reporter , token ) { if ( ! this . _parseResults ) { return undefined ; } return ReferencesProvider . getDeclarationForPosition ( sourceMapper , this . _parseResults , this . _filePath , position , evaluator , reporter , token ) ; } addReferences ( referencesResult , includeDeclaration , evaluator , token ) { if ( ! this . _parseResults ) { return ; } ReferencesProvider . addReferences ( this . _parseResults , this . _filePath , referencesResult , includeDeclaration , evaluator , token ) ; } addHierarchicalSymbolsForDocument ( symbolList , token ) { if ( ! this . _parseResults && ! this . _cachedIndexResults ) { return ; } DocumentSymbolProvider . addHierarchicalSymbolsForDocument ( this . _parseResults ? AnalyzerNodeInfo . getFileInfo ( this . _parseResults . parseTree ) : undefined , this . getCachedIndexResults ( ) , this . _parseResults , symbolList , token ) ; } getSymbolsForDocument ( query , token ) { if ( ! this . _parseResults && ! this . _cachedIndexResults ) { return [ ] ; } return DocumentSymbolProvider . getSymbolsForDocument ( this . _parseResults ? AnalyzerNodeInfo . getFileInfo ( this . _parseResults . parseTree ) : undefined , this . getCachedIndexResults ( ) , this . _parseResults , this . _filePath , query , token ) ; } getHoverForPosition ( sourceMapper , position , format , evaluator , token ) { if ( this . _isBindingNeeded || ! this . _parseResults ) { return undefined ; } return HoverProvider . getHoverForPosition ( sourceMapper , this . _parseResults , position , format , evaluator , token ) ; } getDocumentHighlight ( sourceMapper , position , evaluator , token ) { if ( this . _isBindingNeeded || ! this . _parseResults ) { return undefined ; } return DocumentHighlightProvider . getDocumentHighlight ( this . _parseResults , position , evaluator , token ) ; } getSignatureHelpForPosition ( position , sourceMapper , evaluator , format , token ) { if ( ! this . _parseResults ) { return undefined ; } return SignatureHelpProvider . getSignatureHelpForPosition ( this . _parseResults , position , sourceMapper , evaluator , format , token ) ; } getCompletionsForPosition ( position , workspacePath , configOptions , importResolver , importLookup , evaluator , options , sourceMapper , nameMap , libraryMap , moduleSymbolsCallback , token ) { if ( ! this . _parseResults ) { return undefined ; } const fileContents = this . getOpenFileContents ( ) ; if ( fileContents === undefined ) { return undefined ; } const completionProvider = new CompletionProvider ( workspacePath , this . _parseResults , fileContents , importResolver , position , this . _filePath , configOptions , importLookup , evaluator , options , sourceMapper , { nameMap , libraryMap , getModuleSymbolsMap : moduleSymbolsCallback , } , token ) ; return completionProvider . getCompletionsForPosition ( ) ; } resolveCompletionItem ( configOptions , importResolver , importLookup , evaluator , options , sourceMapper , nameMap , libraryMap , moduleSymbolsCallback , completionItem , token ) { const fileContents = this . getOpenFileContents ( ) ; if ( ! this . _parseResults || fileContents === undefined ) { return ; } const completionData = completionItem . data as CompletionItemData ; const completionProvider = new CompletionProvider ( completionData . workspacePath , this . _parseResults , fileContents , importResolver , completionData . position , this . _filePath , configOptions , importLookup , evaluator , options , sourceMapper , { nameMap , libraryMap , getModuleSymbolsMap : moduleSymbolsCallback , } , token ) ; completionProvider . resolveCompletionItem ( completionItem ) ; } performQuickAction ( command , args , token ) { if ( ! this . _parseResults ) { return undefined ; } if ( this . getClientVersion ( ) === undefined ) { return undefined ; } return performQuickAction ( command , args , this . _parseResults , token ) ; } bind ( configOptions , importLookup , builtinsScope ) { assert ( ! this . isParseRequired ( ) , 'Bind called before parsing' ) ; assert ( this . isBindingRequired ( ) , 'Bind called unnecessarily' ) ; assert ( ! this . _isBindingInProgress , 'Bind called while binding in progress' ) ; assert ( this . _parseResults !== undefined , 'Parse results not available' ) ; return this . _logTracker . log ( `binding: ${ this . _getPathForLogging ( this . _filePath ) }` , ( ) => { try { timingStats . bindTime . timeOperation ( ( ) => { this . _cleanParseTreeIfRequired ( ) ; const fileInfo = this . _buildFileInfo ( configOptions , this . _parseResults ! . text , importLookup , builtinsScope ) ; AnalyzerNodeInfo . setFileInfo ( this . _parseResults ! . parseTree , fileInfo ) ; const binder = new Binder ( fileInfo , configOptions . indexGenerationMode ) ; this . _isBindingInProgress = true ; binder . bindModule ( this . _parseResults ! . parseTree ) ; if ( configOptions . internalTestMode ) { const testWalker = new TestWalker ( ) ; testWalker . walk ( this . _parseResults ! . parseTree ) ; } this . _bindDiagnostics = fileInfo . diagnosticSink . fetchAndClear ( ) ; const moduleScope = AnalyzerNodeInfo . getScope ( this . _parseResults ! . parseTree ) ; assert ( moduleScope !== undefined , 'Module scope not returned by binder' ) ; this . _moduleSymbolTable = moduleScope ! . symbolTable ; } ) ; } catch ( e ) { const message = ( e . stack ? e . stack . toString ( ) : undefined ) || ( typeof e . message === 'string' ? e . message : undefined ) || JSON . stringify ( e ) ; this . _console . error ( Localizer . Diagnostic . internalBindError ( ) . format ( { file : this . getFilePath ( ) , message } ) ) ; const diagSink = new DiagnosticSink ( ) ; diagSink . addError ( Localizer . Diagnostic . internalBindError ( ) . format ( { file : this . getFilePath ( ) , message } ) , getEmptyRange ( ) ) ; this . _bindDiagnostics = diagSink . fetchAndClear ( ) ; } finally { this . _isBindingInProgress = false ; } this . _diagnosticVersion ++ ; this . _isCheckingNeeded = true ; this . _indexingNeeded = true ; this . _isBindingNeeded = false ; } ) ; } check ( evaluator ) { assert ( ! this . isParseRequired ( ) , 'Check called before parsing' ) ; assert ( ! this . isBindingRequired ( ) , 'Check called before binding' ) ; assert ( ! this . _isBindingInProgress , 'Check called while binding in progress' ) ; assert ( this . isCheckingRequired ( ) , 'Check called unnecessarily' ) ; assert ( this . _parseResults !== undefined , 'Parse results not available' ) ; return this . _logTracker . log ( `checking: ${ this . _getPathForLogging ( this . _filePath ) }` , ( ) => { try { timingStats . typeCheckerTime . timeOperation ( ( ) => { const checker = new Checker ( this . _parseResults ! . parseTree , evaluator ) ; checker . check ( ) ; this . _isCheckingNeeded = false ; const fileInfo = AnalyzerNodeInfo . getFileInfo ( this . _parseResults ! . parseTree ) ! ; this . _checkerDiagnostics = fileInfo . diagnosticSink . fetchAndClear ( ) ; } ) ; } catch ( e ) { const isCancellation = OperationCanceledException . is ( e ) ; if ( ! isCancellation ) { const message = ( e . stack ? e . stack . toString ( ) : undefined ) || ( typeof e . message === 'string' ? e . message : undefined ) || JSON . stringify ( e ) ; this . _console . error ( Localizer . Diagnostic . internalTypeCheckingError ( ) . format ( { file : this . getFilePath ( ) , message } ) ) ; const diagSink = new DiagnosticSink ( ) ; diagSink . addError ( Localizer . Diagnostic . internalTypeCheckingError ( ) . format ( { file : this . getFilePath ( ) , message } ) , getEmptyRange ( ) ) ; this . _checkerDiagnostics = diagSink . fetchAndClear ( ) ; this . _isCheckingNeeded = false ; } throw e ; } finally { this . _circularDependencies = [ ] ; this . _diagnosticVersion ++ ; } } ) ; } private _buildFileInfo ( configOptions , fileContents , importLookup , builtinsScope ? ) { assert ( this . _parseResults !== undefined , 'Parse results not available' ) ; const analysisDiagnostics = new TextRangeDiagnosticSink ( this . _parseResults ! . tokenizerOutput . lines ) ; const fileInfo = { importLookup , futureImports : this . _parseResults ! . futureImports , builtinsScope , typingModulePath : this . _typingModulePath , typeshedModulePath : this . _typeshedModulePath , collectionsModulePath : this . _collectionsModulePath , diagnosticSink : analysisDiagnostics , executionEnvironment : configOptions . findExecEnvironment ( this . _filePath ) , diagnosticRuleSet : this . _diagnosticRuleSet , fileContents , lines : this . _parseResults ! . tokenizerOutput . lines , filePath : this . _filePath , moduleName : this . _moduleName , isStubFile : this . _isStubFile , isTypingStubFile : this . _isTypingStubFile , isTypingExtensionsStubFile : this . _isTypingExtensionsStubFile , isBuiltInStubFile : this . _isBuiltInStubFile , isInPyTypedPackage : this . _isThirdPartyPyTypedPresent , accessedSymbolMap : new Map < number , true > ( ) , } ; return fileInfo ; } private _cleanParseTreeIfRequired ( ) { if ( this . _parseResults ) { if ( this . _parseTreeNeedsCleaning ) { const cleanerWalker = new ParseTreeCleanerWalker ( this . _parseResults . parseTree ) ; cleanerWalker . clean ( ) ; this . _parseTreeNeedsCleaning = false ; } } } private _resolveImports ( importResolver , moduleImports , execEnv ) { const imports = [ ] ; let builtinsImportResult = importResolver . resolveImport ( this . _filePath , execEnv , { leadingDots : 0 , nameParts : [ 'builtins' ] , importedSymbols : undefined , } ) ; if ( builtinsImportResult . resolvedPaths . length === 0 || builtinsImportResult . resolvedPaths [ 0 ] !== this . getFilePath ( ) ) { imports . push ( builtinsImportResult ) ; } else { builtinsImportResult = undefined ; } const typingImportResult = importResolver . resolveImport ( this . _filePath , execEnv , { leadingDots : 0 , nameParts : [ 'typing' ] , importedSymbols : undefined , } ) ; let typingModulePath ; if ( typingImportResult . resolvedPaths . length === 0 || typingImportResult . resolvedPaths [ 0 ] !== this . getFilePath ( ) ) { imports . push ( typingImportResult ) ; typingModulePath = typingImportResult . resolvedPaths [ 0 ] ; } const typeshedImportResult = importResolver . resolveImport ( this . _filePath , execEnv , { leadingDots : 0 , nameParts : [ '_typeshed' ] , importedSymbols : undefined , } ) ; let typeshedModulePath ; if ( typeshedImportResult . resolvedPaths . length === 0 || typeshedImportResult . resolvedPaths [ 0 ] !== this . getFilePath ( ) ) { imports . push ( typeshedImportResult ) ; typeshedModulePath = typeshedImportResult . resolvedPaths [ 0 ] ; } let collectionsModulePath ; for ( const moduleImport of moduleImports ) { const importResult = importResolver . resolveImport ( this . _filePath , execEnv , { leadingDots : moduleImport . leadingDots , nameParts : moduleImport . nameParts , importedSymbols : moduleImport . importedSymbols , } ) ; if ( importResult . isImportFound && importResult . isTypeshedFile ) { if ( moduleImport . nameParts . length >= 1 && moduleImport . nameParts [ 0 ] === 'collections' ) { collectionsModulePath = importResult . resolvedPaths [ importResult . resolvedPaths . length - 1 ] ; } } imports . push ( importResult ) ; AnalyzerNodeInfo . setImportInfo ( moduleImport . nameNode , importResult ) ; } return { imports , builtinsImportResult , typingModulePath , typeshedModulePath , collectionsModulePath , } ; } private _getPathForLogging ( filepath ) { if ( ! this . fileSystem . isMappedFilePath ( filepath ) ) { return filepath ; } return '[virtual] ' + filepath ; } }