Fixed crashing bug in type stub writer.

This commit is contained in:
Eric Traut 2019-11-16 23:17:08 -08:00
parent 940acae881
commit 69980ab8dd
5 changed files with 54 additions and 42 deletions

View File

@ -13,7 +13,7 @@
import { ClassNode, FunctionNode, LambdaNode, ListComprehensionNode, ModuleNode,
ParseNode } from '../parser/parseNodes';
import { AnalyzerFileInfo } from './analyzerFileInfo';
import { FlowNode } from './codeFlow';
import { FlowFlags, FlowNode } from './codeFlow';
import { Declaration } from './declaration';
import { ImportResult } from './importResult';
import { Scope } from './scope';
@ -119,3 +119,19 @@ export function setFileInfo(node: ModuleNode, fileInfo: AnalyzerFileInfo) {
const analyzerNode = node as AnalyzerNodeInfo;
analyzerNode.fileInfo = fileInfo;
}
export function isCodeUnreachable(node: ParseNode): boolean {
let curNode: ParseNode | undefined = node;
// Walk up the parse tree until we find a node with
// an associated flow node.
while (curNode) {
const flowNode = getFlowNode(curNode);
if (flowNode) {
return !!(flowNode.flags & FlowFlags.Unreachable);
}
curNode = curNode.parent;
}
return false;
}

View File

@ -70,7 +70,7 @@ export class Checker extends ParseTreeWalker {
}
walk(node: ParseNode) {
if (!this._isCodeUnreachable(node)) {
if (!AnalyzerNodeInfo.isCodeUnreachable(node)) {
super.walk(node);
}
}
@ -991,7 +991,7 @@ export class Checker extends ParseTreeWalker {
};
suiteNode.statements.forEach(statement => {
if (!this._isCodeUnreachable(statement)) {
if (!AnalyzerNodeInfo.isCodeUnreachable(statement)) {
if (statement.nodeType === ParseNodeType.StatementList) {
for (const substatement of statement.statements) {
if (substatement.nodeType !== ParseNodeType.TypeAnnotation &&
@ -1009,22 +1009,6 @@ export class Checker extends ParseTreeWalker {
});
}
private _isCodeUnreachable(node: ParseNode): boolean {
let curNode: ParseNode | undefined = node;
// Walk up the parse tree until we find a node with
// an associated flow node.
while (curNode) {
const flowNode = AnalyzerNodeInfo.getFlowNode(curNode);
if (flowNode) {
return !!(flowNode.flags & FlowFlags.Unreachable);
}
curNode = curNode.parent;
}
return false;
}
private _validateFunctionReturn(node: FunctionNode, functionType: FunctionType) {
// Stub files are allowed not to return an actual value,
// so skip this if it's a stub file.

View File

@ -571,9 +571,23 @@ export class AnalyzerService {
// don't include those.
const resolvedPath = importResult.resolvedPaths[
importResult.resolvedPaths.length - 1];
this._typeStubTargetPath = importResult.resolvedPaths[0];
if (isFile(this._typeStubTargetPath)) {
this._typeStubTargetPath = getDirectoryPath(this._typeStubTargetPath);
// Get the directory that contains the root package.
let targetPath = getDirectoryPath(resolvedPath);
for (let i = importResult.resolvedPaths.length - 2; i >= 0; i--) {
const resolvedPath = importResult.resolvedPaths[i];
if (resolvedPath) {
targetPath = getDirectoryPath(resolvedPath);
} else {
// If there was no file corresponding to this portion
// of the name path, assume that it's contained
// within its parent directory.
targetPath = getDirectoryPath(targetPath);
}
}
if (isDirectory(targetPath)) {
this._typeStubTargetPath = targetPath;
}
if (!resolvedPath) {

View File

@ -13,8 +13,9 @@ import * as fs from 'fs';
import { ArgumentCategory, ArgumentNode, AssignmentNode, AugmentedAssignmentNode,
ClassNode, DecoratorNode, ExpressionNode, ForNode, FunctionNode, IfNode,
ImportFromNode, ImportNode, ModuleNameNode, NameNode, ParameterCategory, ParameterNode,
ParseNodeType, StatementListNode, StringNode, TryNode, TypeAnnotationNode,
WhileNode, WithNode } from '../parser/parseNodes';
ParseNode, ParseNodeType, StatementListNode, StringNode, TryNode,
TypeAnnotationNode, WhileNode, WithNode } from '../parser/parseNodes';
import * as AnalyzerNodeInfo from './analyzerNodeInfo';
import * as ParseTreeUtils from './parseTreeUtils';
import { ParseTreeWalker } from './parseTreeWalker';
import { getScopeForNode } from './scopeUtils';
@ -47,10 +48,11 @@ interface TrackedImportSymbol {
}
class TrackedImportFrom extends TrackedImport {
symbols: TrackedImportSymbol[] = [];
constructor(importName: string, public isWildcardImport: boolean, public node?: ImportFromNode) {
super(importName);
}
symbols: TrackedImportSymbol[] = [];
addSymbol(symbol: Symbol | undefined, name: string,
alias: string | undefined, isAccessed = false) {
@ -78,6 +80,12 @@ class ImportSymbolWalker extends ParseTreeWalker {
this.walk(node);
}
walk(node: ParseNode) {
if (!AnalyzerNodeInfo.isCodeUnreachable(node)) {
super.walk(node);
}
}
visitName(node: NameNode) {
this._accessedImportedSymbols.set(node.value, true);
return true;
@ -129,6 +137,12 @@ export class TypeStubWriter extends ParseTreeWalker {
this._writeFile();
}
walk(node: ParseNode) {
if (!AnalyzerNodeInfo.isCodeUnreachable(node)) {
super.walk(node);
}
}
visitClass(node: ClassNode) {
const className = node.name.value;

View File

@ -52,7 +52,7 @@ class FindReferencesTreeWalker extends ParseTreeWalker {
}
walk(node: ParseNode) {
if (!this._isCodeUnreachable(node)) {
if (!AnalyzerNodeInfo.isCodeUnreachable(node)) {
super.walk(node);
}
}
@ -90,22 +90,6 @@ class FindReferencesTreeWalker extends ParseTreeWalker {
return this._referencesResult.declarations.some(decl =>
DeclarationUtils.areDeclarationsSame(decl, resolvedDecl));
}
private _isCodeUnreachable(node: ParseNode): boolean {
let curNode: ParseNode | undefined = node;
// Walk up the parse tree until we find a node with
// an associated flow node.
while (curNode) {
const flowNode = AnalyzerNodeInfo.getFlowNode(curNode);
if (flowNode) {
return !!(flowNode.flags & FlowFlags.Unreachable);
}
curNode = curNode.parent;
}
return false;
}
}
export class ReferencesProvider {