Switched parse nodes from classes to interfaces with an enumerated union type.

This commit is contained in:
Eric Traut 2019-09-07 17:37:36 -07:00
parent 499f8bff30
commit 80d120c838
33 changed files with 1976 additions and 1283 deletions

View File

@ -1010,9 +1010,9 @@
}
},
"typescript": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz",
"integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==",
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz",
"integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==",
"dev": true
},
"uc.micro": {

View File

@ -104,7 +104,7 @@
"postinstall": "node ./node_modules/vscode/bin/install"
},
"devDependencies": {
"typescript": "^3.5.2",
"typescript": "^3.6.2",
"vsce": "^1.64.0",
"vscode": "^1.1.35"
},

6
package-lock.json generated
View File

@ -17,9 +17,9 @@
"dev": true
},
"typescript": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz",
"integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==",
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz",
"integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==",
"dev": true
}
}

View File

@ -25,7 +25,7 @@
"devDependencies": {
"@types/mocha": "^5.2.7",
"@types/node": "^11.13.15",
"typescript": "^3.5.2"
"typescript": "^3.6.2"
},
"main": "index.js",
"bin": {

View File

@ -6387,9 +6387,9 @@
"dev": true
},
"typescript": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz",
"integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==",
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz",
"integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==",
"dev": true
},
"typescript-char": {

View File

@ -38,7 +38,7 @@
"ts-loader": "^5.4.5",
"tslint": "^5.18.0",
"tslint-microsoft-contrib": "^6.2.0",
"typescript": "^3.5.2",
"typescript": "^3.6.2",
"webpack": "^4.35.0",
"webpack-cli": "^3.3.5"
},

View File

@ -16,16 +16,13 @@ import { TextRangeDiagnosticSink } from '../common/diagnosticSink';
import { convertOffsetsToRange } from '../common/positionUtils';
import StringMap from '../common/stringMap';
import { TextRange } from '../common/textRange';
import { ArgumentCategory, AssignmentNode, AugmentedAssignmentExpressionNode,
AwaitExpressionNode, BinaryExpressionNode, CallExpressionNode, ClassNode,
ConstantNode, DecoratorNode, DictionaryExpandEntryNode, DictionaryKeyEntryNode,
DictionaryNode, EllipsisNode, ErrorExpressionNode, ExpressionNode,
IndexExpressionNode, IndexItemsNode, LambdaNode, ListComprehensionForNode,
ListComprehensionIfNode, ListComprehensionNode, ListNode, MemberAccessExpressionNode,
NameNode, NumberNode, ParameterCategory, ParseNode, SetNode, SliceExpressionNode,
StatementListNode, StringListNode, TernaryExpressionNode, TupleExpressionNode,
TypeAnnotationExpressionNode, UnaryExpressionNode, UnpackExpressionNode,
YieldExpressionNode, YieldFromExpressionNode } from '../parser/parseNodes';
import { ArgumentCategory, AugmentedAssignmentExpressionNode, BinaryExpressionNode,
CallExpressionNode, ClassNode, ConstantNode, DecoratorNode, DictionaryNode,
ExpressionNode, IndexExpressionNode, IndexItemsNode, isExpressionNode, LambdaNode,
ListComprehensionNode, ListNode, MemberAccessExpressionNode, NameNode, ParameterCategory,
ParseNode, ParseNodeType, SetNode, SliceExpressionNode, TernaryExpressionNode,
TupleExpressionNode, UnaryExpressionNode, YieldExpressionNode,
YieldFromExpressionNode } from '../parser/parseNodes';
import { KeywordToken, KeywordType, OperatorType, StringTokenFlags,
TokenType } from '../parser/tokenizerTypes';
import { ScopeUtils } from '../scopeUtils';
@ -232,7 +229,7 @@ export class ExpressionEvaluator {
// Gets a member type from an object and if it's a function binds
// it to the object.
getTypeFromObjectMember(errorNode: ParseNode, objectType: ObjectType, memberName: string,
getTypeFromObjectMember(errorNode: ExpressionNode, objectType: ObjectType, memberName: string,
usage: EvaluatorUsage, memberAccessFlags = MemberAccessFlags.None): Type | undefined {
const memberInfo = this._getTypeFromClassMemberName(errorNode,
@ -250,7 +247,7 @@ export class ExpressionEvaluator {
// Gets a member type from a class and if it's a function binds
// it to the object.
getTypeFromClassMember(errorNode: ParseNode, classType: ClassType, memberName: string,
getTypeFromClassMember(errorNode: ExpressionNode, classType: ClassType, memberName: string,
usage: EvaluatorUsage, memberAccessFlags = MemberAccessFlags.None): Type | undefined {
const memberInfo = this._getTypeFromClassMemberName(errorNode,
@ -445,19 +442,19 @@ export class ExpressionEvaluator {
});
node.suite.statements.forEach(statementList => {
if (statementList instanceof StatementListNode) {
if (statementList.nodeType === ParseNodeType.StatementList) {
statementList.statements.forEach(statement => {
let variableNameNode: NameNode | undefined;
let variableType: Type | undefined;
let hasDefaultValue = false;
if (statement instanceof AssignmentNode) {
if (statement.leftExpression instanceof NameNode) {
if (statement.nodeType === ParseNodeType.Assignment) {
if (statement.leftExpression.nodeType === ParseNodeType.Name) {
variableNameNode = statement.leftExpression;
variableType = TypeUtils.stripLiteralValue(
this.getType(statement.rightExpression, { method: 'get' }));
} else if (statement.leftExpression instanceof TypeAnnotationExpressionNode &&
statement.leftExpression.valueExpression instanceof NameNode) {
} else if (statement.leftExpression.nodeType === ParseNodeType.TypeAnnotation &&
statement.leftExpression.valueExpression.nodeType === ParseNodeType.Name) {
variableNameNode = statement.leftExpression.valueExpression;
variableType = TypeUtils.convertClassToObject(
@ -466,8 +463,8 @@ export class ExpressionEvaluator {
}
hasDefaultValue = true;
} else if (statement instanceof TypeAnnotationExpressionNode) {
if (statement.valueExpression instanceof NameNode) {
} else if (statement.nodeType === ParseNodeType.TypeAnnotation) {
if (statement.valueExpression.nodeType === ParseNodeType.Name) {
variableNameNode = statement.valueExpression;
variableType = TypeUtils.convertClassToObject(
this.getType(statement.typeAnnotation, { method: 'get' },
@ -609,21 +606,21 @@ export class ExpressionEvaluator {
let typeResult: TypeResult | undefined;
if (node instanceof NameNode) {
if (node.nodeType === ParseNodeType.Name) {
typeResult = this._getTypeFromName(node, usage, flags);
} else if (node instanceof MemberAccessExpressionNode) {
} else if (node.nodeType === ParseNodeType.MemberAccess) {
typeResult = this._getTypeFromMemberAccessExpression(node, usage, flags);
} else if (node instanceof IndexExpressionNode) {
} else if (node.nodeType === ParseNodeType.Index) {
typeResult = this._getTypeFromIndexExpression(node, usage);
} else if (node instanceof CallExpressionNode) {
} else if (node.nodeType === ParseNodeType.Call) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromCallExpression(node, flags);
} else if (node instanceof TupleExpressionNode) {
} else if (node.nodeType === ParseNodeType.Tuple) {
typeResult = this._getTypeFromTupleExpression(node, usage);
} else if (node instanceof ConstantNode) {
} else if (node.nodeType === ParseNodeType.Constant) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromConstantExpression(node);
} else if (node instanceof StringListNode) {
} else if (node.nodeType === ParseNodeType.StringList) {
this._reportUsageErrorForReadOnly(node, usage);
if (node.typeAnnotation && !AnalyzerNodeInfo.getIgnoreTypeAnnotation(node)) {
let typeResult: TypeResult = { node, type: UnknownType.create() };
@ -639,12 +636,12 @@ export class ExpressionEvaluator {
const isBytes = (node.strings[0].token.flags & StringTokenFlags.Bytes) !== 0;
typeResult = { node, type: this._cloneBuiltinTypeWithLiteral(
isBytes ? 'bytes' : 'str', node.getValue()) };
} else if (node instanceof NumberNode) {
isBytes ? 'bytes' : 'str', node.strings.map(s => s.value).join('')) };
} else if (node.nodeType === ParseNodeType.Number) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = { node, type: this._cloneBuiltinTypeWithLiteral(
node.token.isInteger ? 'int' : 'float', node.token.value) };
} else if (node instanceof EllipsisNode) {
} else if (node.nodeType === ParseNodeType.Ellipsis) {
this._reportUsageErrorForReadOnly(node, usage);
if ((flags & EvaluatorFlags.ConvertEllipsisToAny) !== 0) {
typeResult = { type: AnyType.create(true), node };
@ -653,61 +650,61 @@ export class ExpressionEvaluator {
AnyType.create();
typeResult = { type: ellipsisType, node };
}
} else if (node instanceof UnaryExpressionNode) {
} else if (node.nodeType === ParseNodeType.UnaryOperation) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromUnaryExpression(node);
} else if (node instanceof BinaryExpressionNode) {
} else if (node.nodeType === ParseNodeType.BinaryOperation) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromBinaryExpression(node);
} else if (node instanceof AugmentedAssignmentExpressionNode) {
} else if (node.nodeType === ParseNodeType.AugmentedAssignment) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromAugmentedExpression(node);
} else if (node instanceof ListNode) {
} else if (node.nodeType === ParseNodeType.List) {
typeResult = this._getTypeFromListExpression(node);
} else if (node instanceof SliceExpressionNode) {
} else if (node.nodeType === ParseNodeType.Slice) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromSliceExpression(node);
} else if (node instanceof AwaitExpressionNode) {
} else if (node.nodeType === ParseNodeType.Await) {
typeResult = this._getTypeFromExpression(
node.expression, { method: 'get' }, flags);
typeResult = {
type: this.getTypeFromAwaitable(typeResult.type, node.expression),
node
};
} else if (node instanceof TernaryExpressionNode) {
} else if (node.nodeType === ParseNodeType.Ternary) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromTernaryExpression(node, flags);
} else if (node instanceof ListComprehensionNode) {
} else if (node.nodeType === ParseNodeType.ListComprehension) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromListComprehensionExpression(node);
} else if (node instanceof DictionaryNode) {
} else if (node.nodeType === ParseNodeType.Dictionary) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromDictionaryExpression(node);
} else if (node instanceof LambdaNode) {
} else if (node.nodeType === ParseNodeType.Lambda) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromLambdaExpression(node);
} else if (node instanceof SetNode) {
} else if (node.nodeType === ParseNodeType.Set) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromSetExpression(node);
} else if (node instanceof AssignmentNode) {
} else if (node.nodeType === ParseNodeType.Assignment) {
this._reportUsageErrorForReadOnly(node, usage);
// Don't validate the type match for the assignment here. Simply
// return the type result of the RHS.
typeResult = this._getTypeFromExpression(node.rightExpression);
} else if (node instanceof YieldExpressionNode) {
} else if (node.nodeType === ParseNodeType.Yield) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromYieldExpression(node);
} else if (node instanceof YieldFromExpressionNode) {
} else if (node.nodeType === ParseNodeType.YieldFrom) {
this._reportUsageErrorForReadOnly(node, usage);
typeResult = this._getTypeFromYieldFromExpression(node);
} else if (node instanceof UnpackExpressionNode) {
} else if (node.nodeType === ParseNodeType.Unpack) {
const iterType = this._getTypeFromExpression(node.expression, usage).type;
const type = this.getTypeFromIterable(iterType, false, node, false);
typeResult = { type, node };
} else if (node instanceof TypeAnnotationExpressionNode) {
} else if (node.nodeType === ParseNodeType.TypeAnnotation) {
typeResult = this._getTypeFromExpression(node.typeAnnotation);
} else if (node instanceof ErrorExpressionNode) {
} else if (node.nodeType === ParseNodeType.Error) {
// Evaluate the child expression as best we can so the
// type information is cached for the completion handler.
this._silenceDiagnostics(() => {
@ -971,7 +968,7 @@ export class ExpressionEvaluator {
return undefined;
}
private _getTypeFromClassMemberName(errorNode: ParseNode, classType: ClassType, memberName: string,
private _getTypeFromClassMemberName(errorNode: ExpressionNode, classType: ClassType, memberName: string,
usage: EvaluatorUsage, flags: MemberAccessFlags): ClassMemberLookup | undefined {
// If this is a special type (like "List") that has an alias
@ -1270,8 +1267,8 @@ export class ExpressionEvaluator {
baseTypeClass.getClassName() === 'Tuple' &&
baseTypeClass.getTypeArguments()) {
if (node.items.items[0] instanceof NumberNode) {
const numberToken = (node.items.items[0] as NumberNode).token;
if (node.items.items[0].nodeType === ParseNodeType.Number) {
const numberToken = node.items.items[0].token;
const baseClassTypeArgs = baseTypeClass.getTypeArguments()!;
if (numberToken.isInteger && numberToken.value >= 0 &&
@ -1324,7 +1321,7 @@ export class ExpressionEvaluator {
private _getTypeArg(node: ExpressionNode): TypeResult {
let typeResult: TypeResult;
if (node instanceof ListNode) {
if (node.nodeType === ParseNodeType.List) {
typeResult = {
type: UnknownType.create(),
typeList: node.entries.map(entry => this._getTypeFromExpression(entry)),
@ -1361,7 +1358,7 @@ export class ExpressionEvaluator {
{ method: 'get' }, EvaluatorFlags.DoNotSpecialize);
// Handle the built-in "super" call specially.
if (node.leftExpression instanceof NameNode && node.leftExpression.nameToken.value === 'super') {
if (node.leftExpression.nodeType === ParseNodeType.Name && node.leftExpression.nameToken.value === 'super') {
return {
type: this._getTypeFromSuperCall(node),
node
@ -1447,8 +1444,9 @@ export class ExpressionEvaluator {
// Python docs indicate that super() isn't valid for
// operations other than member accesses.
if (node.parent! instanceof MemberAccessExpressionNode) {
const memberName = node.parent.memberName.nameToken.value;
const parentNode = node.parent!;
if (parentNode.nodeType === ParseNodeType.MemberAccess) {
const memberName = parentNode.memberName.nameToken.value;
const lookupResults = TypeUtils.lookUpClassMember(
targetClassType, memberName, ClassMemberLookupFlags.SkipOriginalClass);
if (lookupResults && lookupResults.classType instanceof ClassType) {
@ -2052,8 +2050,8 @@ export class ExpressionEvaluator {
}
const firstArg = argList[0];
if (firstArg.valueExpression instanceof StringListNode) {
typeVarName = firstArg.valueExpression.getValue();
if (firstArg.valueExpression && firstArg.valueExpression.nodeType === ParseNodeType.StringList) {
typeVarName = firstArg.valueExpression.strings.map(s => s.value).join('');
} else {
this._addError('Expected name of type var as first parameter',
firstArg.valueExpression || errorNode);
@ -2134,7 +2132,7 @@ export class ExpressionEvaluator {
}
private _getBooleanValue(node: ExpressionNode): boolean {
if (node instanceof ConstantNode) {
if (node.nodeType === ParseNodeType.Constant) {
if (node.token instanceof KeywordToken) {
if (node.token.keywordType === KeywordType.False) {
return false;
@ -2160,8 +2158,8 @@ export class ExpressionEvaluator {
if (nameArg.argumentCategory !== ArgumentCategory.Simple) {
this._addError('Expected enum class name as first parameter',
argList[0].valueExpression || errorNode);
} else if (nameArg.valueExpression instanceof StringListNode) {
className = nameArg.valueExpression.getValue();
} else if (nameArg.valueExpression && nameArg.valueExpression.nodeType === ParseNodeType.StringList) {
className = nameArg.valueExpression.strings.map(s => s.value).join('');
}
}
@ -2192,11 +2190,12 @@ export class ExpressionEvaluator {
} else {
const entriesArg = argList[1];
if (entriesArg.argumentCategory !== ArgumentCategory.Simple ||
!(entriesArg.valueExpression instanceof StringListNode)) {
!entriesArg.valueExpression ||
entriesArg.valueExpression.nodeType !== ParseNodeType.StringList) {
this._addError('Expected enum item string as second parameter', errorNode);
} else {
const entries = entriesArg.valueExpression.getValue().split(' ');
const entries = entriesArg.valueExpression.strings.map(s => s.value).join('').split(' ');
entries.forEach(entryName => {
entryName = entryName.trim();
if (entryName) {
@ -2215,7 +2214,8 @@ export class ExpressionEvaluator {
path: this._fileInfo.filePath,
declaredType: entryType,
range: convertOffsetsToRange(
stringNode.start, stringNode.end, this._fileInfo.lines)
stringNode.start, TextRange.getEnd(stringNode),
this._fileInfo.lines)
};
newSymbol.addDeclaration(declaration);
setSymbolPreservingAccess(classFields, entryName, newSymbol);
@ -2237,8 +2237,8 @@ export class ExpressionEvaluator {
if (argList.length >= 1) {
const nameArg = argList[0];
if (nameArg.argumentCategory === ArgumentCategory.Simple) {
if (nameArg.valueExpression instanceof StringListNode) {
className = nameArg.valueExpression.getValue();
if (nameArg.valueExpression && nameArg.valueExpression.nodeType === ParseNodeType.StringList) {
className = nameArg.valueExpression.strings.map(s => s.value).join('');
}
}
}
@ -2286,8 +2286,8 @@ export class ExpressionEvaluator {
if (nameArg.argumentCategory !== ArgumentCategory.Simple) {
this._addError('Expected named tuple class name as first parameter',
argList[0].valueExpression || errorNode);
} else if (nameArg.valueExpression instanceof StringListNode) {
className = nameArg.valueExpression.getValue();
} else if (nameArg.valueExpression && nameArg.valueExpression.nodeType === ParseNodeType.StringList) {
className = nameArg.valueExpression.strings.map(s => s.value).join('');
}
}
@ -2342,8 +2342,10 @@ export class ExpressionEvaluator {
if (entriesArg.argumentCategory !== ArgumentCategory.Simple) {
addGenericGetAttribute = true;
} else {
if (!includesTypes && entriesArg.valueExpression instanceof StringListNode) {
const entries = entriesArg.valueExpression.getValue().split(' ');
if (!includesTypes && entriesArg.valueExpression &&
entriesArg.valueExpression.nodeType === ParseNodeType.StringList) {
const entries = entriesArg.valueExpression.strings.map(s => s.value).join('').split(' ');
entries.forEach(entryName => {
entryName = entryName.trim();
if (entryName) {
@ -2368,13 +2370,13 @@ export class ExpressionEvaluator {
path: this._fileInfo.filePath,
declaredType: entryType,
range: convertOffsetsToRange(
stringNode.start, stringNode.end, this._fileInfo.lines)
stringNode.start, TextRange.getEnd(stringNode), this._fileInfo.lines)
};
newSymbol.addDeclaration(declaration);
setSymbolPreservingAccess(instanceFields, entryName, newSymbol);
}
});
} else if (entriesArg.valueExpression instanceof ListNode) {
} else if (entriesArg.valueExpression && entriesArg.valueExpression.nodeType === ParseNodeType.List) {
const entryList = entriesArg.valueExpression;
const entryMap: { [name: string]: string } = {};
@ -2385,7 +2387,7 @@ export class ExpressionEvaluator {
if (includesTypes) {
// Handle the variant that includes name/type tuples.
if (entry instanceof TupleExpressionNode && entry.expressions.length === 2) {
if (entry.nodeType === ParseNodeType.Tuple && entry.expressions.length === 2) {
entryNameNode = entry.expressions[0];
const entryTypeInfo = this._getTypeFromExpression(entry.expressions[1]);
if (entryTypeInfo) {
@ -2400,8 +2402,8 @@ export class ExpressionEvaluator {
entryType = UnknownType.create();
}
if (entryNameNode instanceof StringListNode) {
entryName = entryNameNode.getValue();
if (entryNameNode && entryNameNode.nodeType === ParseNodeType.StringList) {
entryName = entryNameNode.strings.map(s => s.value).join('');
if (!entryName) {
this._addError(
'Names within a named tuple cannot be empty', entryNameNode);
@ -2443,7 +2445,8 @@ export class ExpressionEvaluator {
path: this._fileInfo.filePath,
declaredType: entryType,
range: convertOffsetsToRange(
entryNameNode.start, entryNameNode.end, this._fileInfo.lines)
entryNameNode.start, TextRange.getEnd(entryNameNode),
this._fileInfo.lines)
};
newSymbol.addDeclaration(declaration);
}
@ -2878,7 +2881,7 @@ export class ExpressionEvaluator {
// Infer the set type based on the entries.
node.entries.forEach(entryNode => {
if (entryNode instanceof ListComprehensionNode) {
if (entryNode.nodeType === ParseNodeType.ListComprehension) {
const setEntryType = this._getElementTypeFromListComprehensionExpression(entryNode);
entryTypes.push(setEntryType);
} else {
@ -2906,15 +2909,14 @@ export class ExpressionEvaluator {
node.entries.forEach(entryNode => {
let addUnknown = true;
if (entryNode instanceof DictionaryKeyEntryNode) {
if (entryNode.nodeType === ParseNodeType.DictionaryKeyEntry) {
keyTypes.push(TypeUtils.stripLiteralValue(
this.getType(entryNode.keyExpression)));
valueTypes.push(TypeUtils.stripLiteralValue(
this.getType(entryNode.valueExpression)));
addUnknown = false;
} else if (entryNode instanceof DictionaryExpandEntryNode) {
} else if (entryNode.nodeType === ParseNodeType.DictionaryExpandEntry) {
const unexpandedType = this.getType(entryNode.expandExpression);
if (unexpandedType.isAny()) {
addUnknown = false;
@ -2936,9 +2938,9 @@ export class ExpressionEvaluator {
}
}
}
} else if (entryNode instanceof ListComprehensionNode) {
} else if (entryNode.nodeType === ParseNodeType.ListComprehension) {
const dictEntryType = this._getElementTypeFromListComprehensionExpression(
node.entries[0] as ListComprehensionNode<DictionaryKeyEntryNode>);
node.entries[0] as ListComprehensionNode);
// The result should be a Tuple
if (dictEntryType instanceof ObjectType) {
@ -2985,9 +2987,8 @@ export class ExpressionEvaluator {
private _getTypeFromListExpression(node: ListNode): TypeResult {
let listEntryType: Type = AnyType.create();
if (node.entries.length === 1 && node.entries[0] instanceof ListComprehensionNode) {
listEntryType = this._getElementTypeFromListComprehensionExpression(
node.entries[0] as ListComprehensionNode<ExpressionNode>);
if (node.entries.length === 1 && node.entries[0].nodeType === ParseNodeType.ListComprehension) {
listEntryType = this._getElementTypeFromListComprehensionExpression(node.entries[0]);
} else {
const entryTypes = node.entries.map(
entry => TypeUtils.stripLiteralValue(this.getType(entry)));
@ -3106,9 +3107,9 @@ export class ExpressionEvaluator {
private _assignTypeToExpression(targetExpr: ExpressionNode, type: Type, srcExpr: ExpressionNode): boolean {
let understoodType = true;
if (targetExpr instanceof NameNode) {
if (targetExpr.nodeType === ParseNodeType.Name) {
this._assignTypeToNameNode(targetExpr, type);
} else if (targetExpr instanceof TupleExpressionNode) {
} else if (targetExpr.nodeType === ParseNodeType.Tuple) {
// Initialize the array of target types, one for each target.
const targetTypes: Type[][] = new Array(targetExpr.expressions.length);
for (let i = 0; i < targetExpr.expressions.length; i++) {
@ -3186,7 +3187,7 @@ export class ExpressionEvaluator {
for (let i = 0; i < node.comprehensions.length; i++) {
const comprehension = node.comprehensions[i];
if (comprehension instanceof ListComprehensionForNode) {
if (comprehension.nodeType === ParseNodeType.ListComprehensionFor) {
const iterableType = TypeUtils.stripLiteralValue(
this.getType(comprehension.iterableExpression));
const itemType = this.getTypeFromIterable(iterableType, !!comprehension.isAsync,
@ -3197,7 +3198,7 @@ export class ExpressionEvaluator {
understoodType = false;
break;
}
} else if (comprehension instanceof ListComprehensionIfNode) {
} else if (comprehension.nodeType === ParseNodeType.ListComprehensionIf) {
// Use the if node (if present) to create a type constraint.
typeConstraints = TypeConstraintBuilder.buildTypeConstraintsForConditional(
comprehension.testExpression, expr => TypeUtils.stripLiteralValue(
@ -3208,7 +3209,7 @@ export class ExpressionEvaluator {
let type = UnknownType.create();
this._useExpressionTypeConstraint(typeConstraints, true, () => {
if (understoodType) {
if (node.expression instanceof DictionaryKeyEntryNode) {
if (node.expression.nodeType === ParseNodeType.DictionaryKeyEntry) {
// Create a tuple with the key/value types.
const keyType = TypeUtils.stripLiteralValue(
this.getType(node.expression.keyExpression));
@ -3217,12 +3218,12 @@ export class ExpressionEvaluator {
type = ScopeUtils.getBuiltInObject(
this._scope, 'Tuple', [keyType, valueType]);
} else if (node.expression instanceof DictionaryExpandEntryNode) {
} else if (node.expression.nodeType === ParseNodeType.DictionaryExpandEntry) {
const unexpandedType = this.getType(node.expression.expandExpression);
// TODO - need to implement
} else if (node.expression instanceof ExpressionNode) {
type = TypeUtils.stripLiteralValue(this.getType(node.expression));
} else if (isExpressionNode(node)) {
type = TypeUtils.stripLiteralValue(this.getType(node.expression as ExpressionNode));
}
}
});
@ -3315,7 +3316,7 @@ export class ExpressionEvaluator {
}
// Creates an Optional[X, Y, Z] type.
private _createOptionalType(errorNode: ExpressionNode, typeArgs?: TypeResult[]): Type {
private _createOptionalType(errorNode: ParseNode, typeArgs?: TypeResult[]): Type {
if (!typeArgs || typeArgs.length !== 1) {
this._addError(`Expected one type parameter after Optional`, errorNode);
return UnknownType.create();
@ -3356,23 +3357,24 @@ export class ExpressionEvaluator {
for (const item of node.items.items) {
let type: Type | undefined;
if (item instanceof StringListNode) {
if (item.nodeType === ParseNodeType.StringList) {
// Note that the contents of the string should not be treated
// as a type annotation, as they normally are for quoted type
// arguments.
AnalyzerNodeInfo.setIgnoreTypeAnnotation(item);
const isBytes = (item.strings[0].token.flags & StringTokenFlags.Bytes) !== 0;
const value = item.strings.map(s => s.value).join('');
if (isBytes) {
type = this._cloneBuiltinTypeWithLiteral('bytes', item.getValue());
type = this._cloneBuiltinTypeWithLiteral('bytes', value);
} else {
type = this._cloneBuiltinTypeWithLiteral('str', item.getValue());
type = this._cloneBuiltinTypeWithLiteral('str', value);
}
} else if (item instanceof NumberNode) {
} else if (item.nodeType === ParseNodeType.Number) {
if (item.token.isInteger) {
type = this._cloneBuiltinTypeWithLiteral('int', item.token.value);
}
} else if (item instanceof ConstantNode) {
} else if (item.nodeType === ParseNodeType.Constant) {
if (item.token.keywordType === KeywordType.True) {
type = this._cloneBuiltinTypeWithLiteral('bool', true);
} else if (item.token.keywordType === KeywordType.False) {
@ -3393,7 +3395,7 @@ export class ExpressionEvaluator {
}
// Creates a ClassVar type.
private _createClassVarType(errorNode: ExpressionNode, typeArgs: TypeResult[] | undefined): Type {
private _createClassVarType(errorNode: ParseNode, typeArgs: TypeResult[] | undefined): Type {
if (!typeArgs || typeArgs.length === 0) {
this._addError(`Expected a type parameter after ClassVar`, errorNode);
return UnknownType.create();
@ -3481,7 +3483,7 @@ export class ExpressionEvaluator {
// Creates a type that represents "Generic[T1, T2, ...]", used in the
// definition of a generic class.
private _createGenericType(errorNode: ExpressionNode, classType: ClassType,
private _createGenericType(errorNode: ParseNode, classType: ClassType,
typeArgs?: TypeResult[]): Type {
// Make sure there's at least one type arg.
@ -3619,7 +3621,7 @@ export class ExpressionEvaluator {
// Returns the specialized type and a boolean indicating whether
// the type indicates a class type (true) or an object type (false).
private _createSpecializeClassType(classType: ClassType, typeArgs: TypeResult[] | undefined,
errorNode: ExpressionNode): Type {
errorNode: ParseNode): Type {
// Handle the special-case classes that are not defined
// in the type stubs.

View File

@ -9,9 +9,7 @@
*/
import { ExecutionEnvironment } from '../common/configOptions';
import { BinaryExpressionNode, ConstantNode, ExpressionNode, IndexExpressionNode,
MemberAccessExpressionNode, NameNode, NumberNode, StringListNode,
TupleExpressionNode } from '../parser/parseNodes';
import { ExpressionNode, NumberNode, ParseNodeType, TupleExpressionNode } from '../parser/parseNodes';
import { KeywordType, OperatorType } from '../parser/tokenizerTypes';
export class ExpressionUtils {
@ -20,50 +18,50 @@ export class ExpressionUtils {
static evaluateConstantExpression(node: ExpressionNode,
execEnv: ExecutionEnvironment): boolean | undefined {
if (node instanceof BinaryExpressionNode) {
if (node.nodeType === ParseNodeType.BinaryOperation) {
if (this._isSysVersionInfoExpression(node.leftExpression) &&
node.rightExpression instanceof TupleExpressionNode) {
node.rightExpression.nodeType === ParseNodeType.Tuple) {
// Handle the special case of "sys.version_info >= (3, x)"
const comparisonVersion = this._convertTupleToVersion(node.rightExpression);
return this._evaluateNumericBinaryOperation(node.operator,
execEnv.pythonVersion, comparisonVersion);
} else if (node.leftExpression instanceof IndexExpressionNode &&
} else if (node.leftExpression.nodeType === ParseNodeType.Index &&
this._isSysVersionInfoExpression(node.leftExpression.baseExpression) &&
node.leftExpression.items.items.length === 1 &&
node.leftExpression.items.items[0] instanceof NumberNode &&
(node.leftExpression.items.items[0] as NumberNode).token.value === 0 &&
node.rightExpression instanceof NumberNode) {
node.leftExpression.items.items[0].nodeType === ParseNodeType.Number &&
node.leftExpression.items.items[0].token.value === 0 &&
node.rightExpression.nodeType === ParseNodeType.Number) {
// Handle the special case of "sys.version_info[0] >= X"
return this._evaluateNumericBinaryOperation(node.operator,
Math.floor(execEnv.pythonVersion / 256), node.rightExpression.token.value);
} else if (this._isSysPlatformInfoExpression(node.leftExpression) &&
node.rightExpression instanceof StringListNode) {
node.rightExpression.nodeType === ParseNodeType.StringList) {
// Handle the special case of "sys.platform != 'X'"
const comparisonPlatform = node.rightExpression.getValue();
const comparisonPlatform = node.rightExpression.strings.map(s => s.value).join('');
if (execEnv.pythonPlatform !== undefined) {
return this._evaluateStringBinaryOperation(node.operator,
execEnv.pythonPlatform, comparisonPlatform);
}
} else if (this._isOsNameInfoExpression(node.leftExpression) &&
node.rightExpression instanceof StringListNode) {
node.rightExpression.nodeType === ParseNodeType.StringList) {
// Handle the special case of "os.name == 'X'"
const comparisonOsName = node.rightExpression.getValue();
const comparisonOsName = node.rightExpression.strings.map(s => s.value).join('');
const expectedOsName = this._getExpectedOsNameFromPlatform(execEnv);
if (expectedOsName !== undefined) {
return this._evaluateStringBinaryOperation(node.operator,
expectedOsName, comparisonOsName);
}
}
} else if (node instanceof ConstantNode) {
} else if (node.nodeType === ParseNodeType.Constant) {
if (node.token.keywordType === KeywordType.True) {
return true;
} else if (node.token.keywordType === KeywordType.False) {
return false;
}
} else if (node instanceof NameNode) {
} else if (node.nodeType === ParseNodeType.Name) {
if (node.nameToken.value === 'TYPE_CHECKING') {
return true;
}
@ -75,10 +73,10 @@ export class ExpressionUtils {
private static _convertTupleToVersion(node: TupleExpressionNode): number | undefined {
let comparisonVersion: number | undefined;
if (node.expressions.length === 2) {
if (node.expressions[0] instanceof NumberNode &&
node.expressions[1] instanceof NumberNode) {
const majorVersion = node.expressions[0] as NumberNode;
const minorVersion = node.expressions[1] as NumberNode;
if (node.expressions[0].nodeType === ParseNodeType.Number &&
node.expressions[1].nodeType === ParseNodeType.Number) {
const majorVersion = node.expressions[0];
const minorVersion = node.expressions[1];
comparisonVersion = majorVersion.token.value * 256 + minorVersion.token.value;
}
} else if (node.expressions.length === 1) {
@ -124,8 +122,8 @@ export class ExpressionUtils {
}
private static _isSysVersionInfoExpression(node: ExpressionNode): boolean {
if (node instanceof MemberAccessExpressionNode) {
if (node.leftExpression instanceof NameNode &&
if (node.nodeType === ParseNodeType.MemberAccess) {
if (node.leftExpression.nodeType === ParseNodeType.Name &&
node.leftExpression.nameToken.value === 'sys' &&
node.memberName.nameToken.value === 'version_info') {
return true;
@ -136,8 +134,8 @@ export class ExpressionUtils {
}
private static _isSysPlatformInfoExpression(node: ExpressionNode): boolean {
if (node instanceof MemberAccessExpressionNode) {
if (node.leftExpression instanceof NameNode &&
if (node.nodeType === ParseNodeType.MemberAccess) {
if (node.leftExpression.nodeType === ParseNodeType.Name &&
node.leftExpression.nameToken.value === 'sys' &&
node.memberName.nameToken.value === 'platform') {
return true;
@ -148,8 +146,8 @@ export class ExpressionUtils {
}
private static _isOsNameInfoExpression(node: ExpressionNode): boolean {
if (node instanceof MemberAccessExpressionNode) {
if (node.leftExpression instanceof NameNode &&
if (node.nodeType === ParseNodeType.MemberAccess) {
if (node.leftExpression.nodeType === ParseNodeType.Name &&
node.leftExpression.nameToken.value === 'os' &&
node.memberName.nameToken.value === 'name') {
return true;

View File

@ -11,9 +11,9 @@
import { DiagnosticTextPosition } from '../common/diagnostic';
import { TextEditAction } from '../common/editAction';
import { convertOffsetToPosition } from '../common/positionUtils';
import { AssignmentNode, ImportAsNode, ImportFromAsNode, ImportFromNode,
ImportNode, ModuleNameNode, ModuleNode, NameNode, StatementListNode,
StringListNode } from '../parser/parseNodes';
import { TextRange } from '../common/textRange';
import { ImportAsNode, ImportFromAsNode, ImportFromNode, ImportNode,
ModuleNameNode, ModuleNode, ParseNodeType } from '../parser/parseNodes';
import { ParseResults } from '../parser/parser';
import { AnalyzerNodeInfo } from './analyzerNodeInfo';
import { ImportResult, ImportType } from './importResult';
@ -46,13 +46,13 @@ export class ImportStatementUtils {
let foundFirstImportStatement = false;
parseTree.statements.forEach(statement => {
if (statement instanceof StatementListNode) {
if (statement.nodeType === ParseNodeType.StatementList) {
statement.statements.forEach(subStatement => {
if (subStatement instanceof ImportNode) {
if (subStatement.nodeType === ParseNodeType.Import) {
foundFirstImportStatement = true;
this._processImportNode(subStatement, localImports, followsNonImportStatement);
followsNonImportStatement = false;
} else if (subStatement instanceof ImportFromNode) {
} else if (subStatement.nodeType === ParseNodeType.ImportFrom) {
foundFirstImportStatement = true;
this._processImportFromNode(subStatement, localImports, followsNonImportStatement);
followsNonImportStatement = false;
@ -77,7 +77,7 @@ export class ImportStatementUtils {
// assuming we want to keep the imports alphebetized.
let priorImport: ImportFromAsNode | undefined;
if (importStatement.node instanceof ImportFromNode) {
if (importStatement.node && importStatement.node.nodeType === ParseNodeType.ImportFrom) {
for (const curImport of importStatement.node.imports) {
if (priorImport && curImport.name.nameToken.value > symbolName) {
break;
@ -87,7 +87,7 @@ export class ImportStatementUtils {
}
if (priorImport) {
const insertionOffset = priorImport.name.end;
const insertionOffset = TextRange.getEnd(priorImport.name);
const insertionPosition = convertOffsetToPosition(insertionOffset, parseResults.lines);
textEditList.push({
@ -173,7 +173,7 @@ export class ImportStatementUtils {
}
insertionPosition = convertOffsetToPosition(
insertBefore ? insertionImport.node.start : insertionImport.node.end,
insertBefore ? insertionImport.node.start : TextRange.getEnd(insertionImport.node),
parseResults.lines);
} else {
insertionPosition = { line: 0, column: 0 };
@ -186,14 +186,14 @@ export class ImportStatementUtils {
for (const statement of parseResults.parseTree.statements) {
let stopHere = true;
if (statement instanceof StatementListNode && statement.statements.length === 1) {
if (statement.nodeType === ParseNodeType.StatementList && statement.statements.length === 1) {
const simpleStatement = statement.statements[0];
if (simpleStatement instanceof StringListNode) {
if (simpleStatement.nodeType === ParseNodeType.StringList) {
// Assume that it's a file header doc string.
stopHere = false;
} else if (simpleStatement instanceof AssignmentNode) {
if (simpleStatement.leftExpression instanceof NameNode) {
} else if (simpleStatement.nodeType === ParseNodeType.Assignment) {
if (simpleStatement.leftExpression.nodeType === ParseNodeType.Name) {
if (SymbolUtils.isDunderName(simpleStatement.leftExpression.nameToken.value)) {
// Assume that it's an assignment of __copyright__, __author__, etc.
stopHere = false;
@ -208,7 +208,8 @@ export class ImportStatementUtils {
addNewLineBefore = false;
break;
} else {
insertionPosition = convertOffsetToPosition(statement.end,
insertionPosition = convertOffsetToPosition(
statement.start + statement.length,
parseResults.lines);
addNewLineBefore = true;
}
@ -292,7 +293,9 @@ export class ImportStatementUtils {
// Overwrite existing import statements because we always want to prefer
// 'import from' over 'import'. Also, overwrite existing 'import from' if
// the module name is shorter.
if (!prevEntry || prevEntry.node instanceof ImportNode || prevEntry.moduleName.length > localImport.moduleName.length) {
if (!prevEntry || prevEntry.node.nodeType === ParseNodeType.Import ||
prevEntry.moduleName.length > localImport.moduleName.length) {
localImports.mapByFilePath[resolvedPath] = localImport;
}
}

View File

@ -28,8 +28,8 @@ export class ParseTreeCleanerWalker extends ParseTreeWalker {
this.walk(this._parseTree);
}
visitNode(node: ParseNode): boolean {
visitNode(node: ParseNode) {
AnalyzerNodeInfo.cleanNodeAnalysisInfo(node);
return true;
return super.visitNode(node);
}
}

View File

@ -11,17 +11,10 @@ import { DiagnosticTextPosition } from '../common/diagnostic';
import { convertPositionToOffset } from '../common/positionUtils';
import { TextRange } from '../common/textRange';
import { TextRangeCollection } from '../common/textRangeCollection';
import { ArgumentCategory, AssignmentNode, AugmentedAssignmentExpressionNode,
AwaitExpressionNode, BinaryExpressionNode, CallExpressionNode, ClassNode,
ConstantNode, DictionaryExpandEntryNode, DictionaryKeyEntryNode, DictionaryNode,
EllipsisNode, ExpressionNode, FunctionNode, IndexExpressionNode, LambdaNode,
ListComprehensionForNode, ListComprehensionNode, ListNode, MemberAccessExpressionNode, ModuleNode,
NameNode, NumberNode, ParameterCategory, ParseNode, SetNode, SliceExpressionNode,
StringListNode, StringNode, TernaryExpressionNode, TupleExpressionNode,
TypeAnnotationExpressionNode, UnaryExpressionNode, UnpackExpressionNode,
YieldExpressionNode,
YieldFromExpressionNode } from '../parser/parseNodes';
import { ArgumentCategory, ClassNode, ExpressionNode, FunctionNode, isExpressionNode,
ModuleNode, ParameterCategory, ParseNode, ParseNodeType } from '../parser/parseNodes';
import { KeywordType, OperatorType, StringTokenFlags } from '../parser/tokenizerTypes';
import { ParseTreeWalker } from './parseTreeWalker';
export enum PrintExpressionFlags {
None = 0,
@ -57,13 +50,15 @@ export class ParseTreeUtils {
// Returns the deepest node that contains the specified offset.
static findNodeByOffset(node: ParseNode, offset: number): ParseNode | undefined {
if (offset < node.start || offset > node.end) {
if (offset < node.start || offset > TextRange.getEnd(node)) {
return undefined;
}
const parseTreeWalker = new ParseTreeWalker();
// The range is found within this node. See if we can localize it
// further by checking its children.
const children = node.getChildren();
const children = parseTreeWalker.visitNode(node);
for (const child of children) {
if (child) {
const containingChild = ParseTreeUtils.findNodeByOffset(child, offset);
@ -77,12 +72,12 @@ export class ParseTreeUtils {
}
static printExpression(node: ExpressionNode, flags = PrintExpressionFlags.None): string {
if (node instanceof NameNode) {
if (node.nodeType === ParseNodeType.Name) {
return node.nameToken.value;
} else if (node instanceof MemberAccessExpressionNode) {
} else if (node.nodeType === ParseNodeType.MemberAccess) {
return ParseTreeUtils.printExpression(node.leftExpression, flags) + '.' +
node.memberName.nameToken.value;
} else if (node instanceof CallExpressionNode) {
} else if (node.nodeType === ParseNodeType.Call) {
return ParseTreeUtils.printExpression(node.leftExpression, flags) + '(' +
node.arguments.map(arg => {
let argStr = '';
@ -98,20 +93,20 @@ export class ParseTreeUtils {
return argStr;
}).join(', ') +
')';
} else if (node instanceof IndexExpressionNode) {
} else if (node.nodeType === ParseNodeType.Index) {
return ParseTreeUtils.printExpression(node.baseExpression, flags) + '[' +
node.items.items.map(item => this.printExpression(item, flags)).join(', ') +
']';
} else if (node instanceof UnaryExpressionNode) {
} else if (node.nodeType === ParseNodeType.UnaryOperation) {
return ParseTreeUtils.printOperator(node.operator) + ' ' +
ParseTreeUtils.printExpression(node.expression, flags);
} else if (node instanceof BinaryExpressionNode) {
} else if (node.nodeType === ParseNodeType.BinaryOperation) {
return ParseTreeUtils.printExpression(node.leftExpression, flags) + ' ' +
ParseTreeUtils.printOperator(node.operator) + ' ' +
ParseTreeUtils.printExpression(node.rightExpression, flags);
} else if (node instanceof NumberNode) {
} else if (node.nodeType === ParseNodeType.Number) {
return node.token.value.toString();
} else if (node instanceof StringListNode) {
} else if (node.nodeType === ParseNodeType.StringList) {
if ((flags & PrintExpressionFlags.ForwardDeclarations) && node.typeAnnotation) {
return ParseTreeUtils.printExpression(node.typeAnnotation, flags);
} else {
@ -119,7 +114,7 @@ export class ParseTreeUtils {
return ParseTreeUtils.printExpression(str, flags);
}).join(' ');
}
} else if (node instanceof StringNode) {
} else if (node.nodeType === ParseNodeType.String) {
let exprString = '';
if (node.token.flags & StringTokenFlags.Raw) {
exprString += 'r';
@ -152,30 +147,30 @@ export class ParseTreeUtils {
}
return exprString;
} else if (node instanceof AssignmentNode) {
} else if (node.nodeType === ParseNodeType.Assignment) {
return ParseTreeUtils.printExpression(node.leftExpression, flags) + ' = ' +
ParseTreeUtils.printExpression(node.rightExpression, flags);
} else if (node instanceof TypeAnnotationExpressionNode) {
} else if (node.nodeType === ParseNodeType.TypeAnnotation) {
return ParseTreeUtils.printExpression(node.valueExpression, flags) + ': ' +
ParseTreeUtils.printExpression(node.typeAnnotation, flags);
} else if (node instanceof AugmentedAssignmentExpressionNode) {
} else if (node.nodeType === ParseNodeType.AugmentedAssignment) {
return ParseTreeUtils.printExpression(node.leftExpression, flags) + ' ' +
ParseTreeUtils.printOperator(node.operator) + ' ' +
ParseTreeUtils.printExpression(node.rightExpression, flags);
} else if (node instanceof AwaitExpressionNode) {
} else if (node.nodeType === ParseNodeType.Await) {
return 'await ' + ParseTreeUtils.printExpression(node.expression, flags);
} else if (node instanceof TernaryExpressionNode) {
} else if (node.nodeType === ParseNodeType.Ternary) {
return ParseTreeUtils.printExpression(node.ifExpression, flags) + ' if ' +
ParseTreeUtils.printExpression(node.testExpression, flags) + ' else ' +
ParseTreeUtils.printExpression(node.elseExpression, flags);
} else if (node instanceof ListNode) {
} else if (node.nodeType === ParseNodeType.List) {
const expressions = node.entries.map(expr => {
return ParseTreeUtils.printExpression(expr, flags);
});
return `[${ expressions.join(', ') }]`;
} else if (node instanceof UnpackExpressionNode) {
} else if (node.nodeType === ParseNodeType.Unpack) {
return '*' + ParseTreeUtils.printExpression(node.expression, flags);
} else if (node instanceof TupleExpressionNode) {
} else if (node.nodeType === ParseNodeType.Tuple) {
const expressions = node.expressions.map(expr => {
return ParseTreeUtils.printExpression(expr, flags);
});
@ -183,18 +178,18 @@ export class ParseTreeUtils {
return `(${ expressions[0] }, )`;
}
return `(${ expressions.join(', ') })`;
} else if (node instanceof YieldExpressionNode) {
} else if (node.nodeType === ParseNodeType.Yield) {
return 'yield ' + ParseTreeUtils.printExpression(node.expression, flags);
} else if (node instanceof YieldFromExpressionNode) {
} else if (node.nodeType === ParseNodeType.YieldFrom) {
return 'yield from ' + ParseTreeUtils.printExpression(node.expression, flags);
} else if (node instanceof EllipsisNode) {
} else if (node.nodeType === ParseNodeType.Ellipsis) {
return '...';
} else if (node instanceof ListComprehensionNode) {
} else if (node.nodeType === ParseNodeType.ListComprehension) {
let listStr = '<ListExpression>';
if (node.expression instanceof ExpressionNode) {
listStr = ParseTreeUtils.printExpression(node.expression, flags);
} else if (node.expression instanceof DictionaryKeyEntryNode) {
if (isExpressionNode(node.expression)) {
listStr = ParseTreeUtils.printExpression(node.expression as ExpressionNode, flags);
} else if (node.expression.nodeType === ParseNodeType.DictionaryKeyEntry) {
const keyStr = ParseTreeUtils.printExpression(node.expression.keyExpression, flags);
const valueStr = ParseTreeUtils.printExpression(node.expression.valueExpression, flags);
listStr = `${ keyStr }: ${ valueStr }`;
@ -202,7 +197,7 @@ export class ParseTreeUtils {
return listStr + ' ' +
node.comprehensions.map(expr => {
if (expr instanceof ListComprehensionForNode) {
if (expr.nodeType === ParseNodeType.ListComprehensionFor) {
return `${ expr.isAsync ? 'async ' : '' }for ` +
ParseTreeUtils.printExpression(expr.targetExpression, flags) +
` in ${ ParseTreeUtils.printExpression(expr.iterableExpression, flags) }`;
@ -210,7 +205,7 @@ export class ParseTreeUtils {
return `if ${ ParseTreeUtils.printExpression(expr.testExpression, flags) }`;
}
}).join(' ');
} else if (node instanceof SliceExpressionNode) {
} else if (node.nodeType === ParseNodeType.Slice) {
let result = '';
if (node.startValue) {
result += ParseTreeUtils.printExpression(node.startValue, flags);
@ -222,7 +217,7 @@ export class ParseTreeUtils {
result += ': ' + ParseTreeUtils.printExpression(node.stepValue, flags);
}
return result;
} else if (node instanceof LambdaNode) {
} else if (node.nodeType === ParseNodeType.Lambda) {
return 'lambda ' + node.parameters.map(param => {
let paramStr = '';
@ -241,7 +236,7 @@ export class ParseTreeUtils {
}
return paramStr;
}).join(', ') + ': ' + ParseTreeUtils.printExpression(node.expression, flags);
} else if (node instanceof ConstantNode) {
} else if (node.nodeType === ParseNodeType.Constant) {
if (node.token.keywordType === KeywordType.True) {
return 'True';
} else if (node.token.keywordType === KeywordType.False) {
@ -251,18 +246,18 @@ export class ParseTreeUtils {
} else if (node.token.keywordType === KeywordType.None) {
return 'None';
}
} else if (node instanceof DictionaryNode) {
} else if (node.nodeType === ParseNodeType.Dictionary) {
return `{ ${ node.entries.map(entry => {
if (entry instanceof DictionaryKeyEntryNode) {
if (entry.nodeType === ParseNodeType.DictionaryKeyEntry) {
return `${ ParseTreeUtils.printExpression(entry.keyExpression, flags) }: ` +
`${ ParseTreeUtils.printExpression(entry.valueExpression, flags) }`;
} else {
return ParseTreeUtils.printExpression(entry, flags);
}
})} }`;
} else if (node instanceof DictionaryExpandEntryNode) {
} else if (node.nodeType === ParseNodeType.DictionaryExpandEntry) {
return `**${ ParseTreeUtils.printExpression(node.expandExpression, flags) }`;
} else if (node instanceof SetNode) {
} else if (node.nodeType === ParseNodeType.Set) {
return node.entries.map(entry => ParseTreeUtils.printExpression(entry, flags)).join(', ');
}
@ -324,15 +319,15 @@ export class ParseTreeUtils {
static getEnclosingClass(node: ParseNode, stopAtFunction = false): ClassNode | undefined {
let curNode = node.parent;
while (curNode) {
if (curNode instanceof ClassNode) {
if (curNode.nodeType === ParseNodeType.Class) {
return curNode;
}
if (curNode instanceof ModuleNode) {
if (curNode.nodeType === ParseNodeType.Module) {
return undefined;
}
if (curNode instanceof FunctionNode) {
if (curNode.nodeType === ParseNodeType.Function) {
if (stopAtFunction) {
return undefined;
}
@ -349,15 +344,15 @@ export class ParseTreeUtils {
let curNode = node.parent;
while (curNode) {
if (curNode instanceof ClassNode) {
if (curNode.nodeType === ParseNodeType.Class) {
return curNode;
}
if (curNode instanceof ModuleNode) {
if (curNode.nodeType === ParseNodeType.Module) {
return curNode;
}
if (curNode instanceof FunctionNode) {
if (curNode.nodeType === ParseNodeType.Function) {
if (stopAtFunction) {
return undefined;
}
@ -372,11 +367,11 @@ export class ParseTreeUtils {
static getEnclosingFunction(node: ParseNode): FunctionNode | undefined {
let curNode = node.parent;
while (curNode) {
if (curNode instanceof FunctionNode) {
if (curNode.nodeType === ParseNodeType.Function) {
return curNode;
}
if (curNode instanceof ClassNode) {
if (curNode.nodeType === ParseNodeType.Class) {
return undefined;
}

View File

@ -17,9 +17,9 @@ import { ArgumentNode, AssertNode, AssignmentNode, AugmentedAssignmentExpression
ImportFromAsNode, ImportFromNode, ImportNode, IndexExpressionNode, IndexItemsNode,
LambdaNode, ListComprehensionForNode, ListComprehensionIfNode, ListComprehensionNode,
ListNode, MemberAccessExpressionNode, ModuleNameNode, ModuleNode, NameNode, NonlocalNode,
NumberNode, ParameterNode, ParseNode, ParseNodeArray, ParseNodeType, PassNode, RaiseNode,
ReturnNode, SetNode, SliceExpressionNode, StatementListNode, StringListNode, StringNode,
SuiteNode, TernaryExpressionNode, TryNode, TupleExpressionNode,
NumberNode, ParameterNode, ParseNode, ParseNodeArray, ParseNodeType, PassNode,
RaiseNode, ReturnNode, SetNode, SliceExpressionNode, StatementListNode, StringListNode,
StringNode, SuiteNode, TernaryExpressionNode, TryNode, TupleExpressionNode,
TypeAnnotationExpressionNode, UnaryExpressionNode, UnpackExpressionNode, WhileNode,
WithItemNode, WithNode, YieldExpressionNode, YieldFromExpressionNode } from '../parser/parseNodes';
@ -27,8 +27,9 @@ import { ArgumentNode, AssertNode, AssignmentNode, AugmentedAssignmentExpression
// visitXXX methods that you want to handle.
export class ParseTreeWalker {
walk(node: ParseNode): void {
if (this.visitNode(node)) {
this.walkChildren(node);
const childrenToWalk = this.visitNode(node);
if (childrenToWalk.length > 0) {
this.walkMultiple(childrenToWalk);
}
}
@ -40,207 +41,392 @@ export class ParseTreeWalker {
});
}
walkChildren(node: ParseNode) {
node.getChildren().forEach(node => {
if (node) {
this.walk(node);
}
});
}
visitNode(node: ParseNode): boolean {
// Calls the node-specific method (visitXXXX). If the method
// returns true, all child nodes for the node are returned.
// If the moethod returns false, we assume that the handler
// has already handled the child nodes, so an empty list is
// returned.
visitNode(node: ParseNode): ParseNodeArray {
switch (node.nodeType) {
case ParseNodeType.Argument:
return this.visitArgument(node as ArgumentNode);
if (this.visitArgument(node)) {
return [node.valueExpression];
}
break;
case ParseNodeType.Assert:
return this.visitAssert(node as AssertNode);
if (this.visitAssert(node)) {
return [node.testExpression, node.exceptionExpression];
}
break;
case ParseNodeType.Assignment:
return this.visitAssignment(node as AssignmentNode);
if (this.visitAssignment(node)) {
return [node.leftExpression, node.rightExpression, node.typeAnnotationComment];
}
break;
case ParseNodeType.AugmentedAssignment:
return this.visitAugmentedAssignment(node as AugmentedAssignmentExpressionNode);
if (this.visitAugmentedAssignment(node)) {
return [node.leftExpression, node.rightExpression];
}
break;
case ParseNodeType.Await:
return this.visitAwait(node as AwaitExpressionNode);
if (this.visitAwait(node)) {
return [node.expression];
}
break;
case ParseNodeType.BinaryOperation:
return this.visitBinaryOperation(node as BinaryExpressionNode);
if (this.visitBinaryOperation(node)) {
return [node.leftExpression, node.rightExpression];
}
break;
case ParseNodeType.Break:
return this.visitBreak(node as BreakNode);
if (this.visitBreak(node)) {
return [];
}
break;
case ParseNodeType.Call:
return this.visitCall(node as CallExpressionNode);
if (this.visitCall(node)) {
return [node.leftExpression, ...node.arguments];
}
break;
case ParseNodeType.Class:
return this.visitClass(node as ClassNode);
if (this.visitClass(node)) {
return [...node.decorators, node.name, ...node.arguments, node.suite];
}
break;
case ParseNodeType.Ternary:
return this.visitTernary(node as TernaryExpressionNode);
if (this.visitTernary(node)) {
return [node.ifExpression, node.testExpression, node.elseExpression];
}
break;
case ParseNodeType.Constant:
return this.visitConstant(node as ConstantNode);
if (this.visitConstant(node)) {
return [];
}
break;
case ParseNodeType.Continue:
return this.visitContinue(node as ContinueNode);
if (this.visitContinue(node)) {
return [];
}
break;
case ParseNodeType.Decorator:
return this.visitDecorator(node as DecoratorNode);
if (this.visitDecorator(node)) {
return [node.leftExpression, ...(node.arguments || [])];
}
break;
case ParseNodeType.Del:
return this.visitDel(node as DelNode);
if (this.visitDel(node)) {
return node.expressions;
}
break;
case ParseNodeType.Dictionary:
return this.visitDictionary(node as DictionaryNode);
if (this.visitDictionary(node)) {
return node.entries;
}
break;
case ParseNodeType.DictionaryKeyEntry:
return this.visitDictionaryKeyEntry(node as DictionaryKeyEntryNode);
if (this.visitDictionaryKeyEntry(node)) {
return [node.keyExpression, node.valueExpression];
}
break;
case ParseNodeType.DictionaryExpandEntry:
return this.visitDictionaryExpandEntry(node as DictionaryExpandEntryNode);
if (this.visitDictionaryExpandEntry(node)) {
return [node.expandExpression];
}
break;
case ParseNodeType.Error:
return this.visitError(node as ErrorExpressionNode);
if (this.visitError(node)) {
return [node.child];
}
break;
case ParseNodeType.If:
return this.visitIf(node as IfNode);
if (this.visitIf(node)) {
return [node.testExpression, node.ifSuite, node.elseSuite];
}
break;
case ParseNodeType.Import:
return this.visitImport(node as ImportNode);
if (this.visitImport(node)) {
return node.list;
}
break;
case ParseNodeType.ImportAs:
return this.visitImportAs(node as ImportAsNode);
if (this.visitImportAs(node)) {
return [node.module, node.alias];
}
break;
case ParseNodeType.ImportFrom:
return this.visitImportFrom(node as ImportFromNode);
if (this.visitImportFrom(node)) {
return [node.module, ...node.imports];
}
break;
case ParseNodeType.ImportFromAs:
return this.visitImportFromAs(node as ImportFromAsNode);
if (this.visitImportFromAs(node)) {
return [node.name, node.alias];
}
break;
case ParseNodeType.Index:
return this.visitIndex(node as IndexExpressionNode);
if (this.visitIndex(node)) {
return [node.baseExpression, node.items];
}
break;
case ParseNodeType.IndexItems:
return this.visitIndexItems(node as IndexItemsNode);
if (this.visitIndexItems(node)) {
return node.items;
}
break;
case ParseNodeType.Ellipsis:
return this.visitEllipsis(node as EllipsisNode);
if (this.visitEllipsis(node)) {
return [];
}
break;
case ParseNodeType.Except:
return this.visitExcept(node as ExceptNode);
if (this.visitExcept(node)) {
return [node.typeExpression, node.name, node.exceptSuite];
}
break;
case ParseNodeType.For:
return this.visitFor(node as ForNode);
if (this.visitFor(node)) {
return [node.targetExpression, node.iterableExpression, node.forSuite, node.elseSuite];
}
break;
case ParseNodeType.FormatString:
return this.visitFormatString(node as FormatStringNode);
if (this.visitFormatString(node)) {
return node.expressions;
}
break;
case ParseNodeType.Function:
return this.visitFunction(node as FunctionNode);
if (this.visitFunction(node)) {
return [...node.decorators, node.name, ...node.parameters,
node.returnTypeAnnotation, node.suite];
}
break;
case ParseNodeType.Global:
return this.visitGlobal(node as GlobalNode);
if (this.visitGlobal(node)) {
return node.nameList;
}
break;
case ParseNodeType.Lambda:
return this.visitLambda(node as LambdaNode);
if (this.visitLambda(node)) {
return [...node.parameters, node.expression];
}
break;
case ParseNodeType.List:
return this.visitList(node as ListNode);
if (this.visitList(node)) {
return node.entries;
}
break;
case ParseNodeType.ListComprehension:
return this.visitListComprehension(node as ListComprehensionNode);
if (this.visitListComprehension(node)) {
return [node.expression, ...node.comprehensions];
}
break;
case ParseNodeType.ListComprehensionFor:
return this.visitListComprehensionFor(node as ListComprehensionForNode);
if (this.visitListComprehensionFor(node)) {
return [node.targetExpression, node.iterableExpression];
}
break;
case ParseNodeType.ListComprehensionIf:
return this.visitListComprehensionIf(node as ListComprehensionIfNode);
if (this.visitListComprehensionIf(node)) {
return [node.testExpression];
}
break;
case ParseNodeType.MemberAccess:
return this.visitMemberAccess(node as MemberAccessExpressionNode);
if (this.visitMemberAccess(node)) {
return [node.leftExpression, node.memberName];
}
break;
case ParseNodeType.Module:
return this.visitModule(node as ModuleNode);
if (this.visitModule(node)) {
return [...node.statements];
}
break;
case ParseNodeType.ModuleName:
return this.visitModuleName(node as ModuleNameNode);
if (this.visitModuleName(node)) {
return [];
}
break;
case ParseNodeType.Name:
return this.visitName(node as NameNode);
if (this.visitName(node)) {
return [];
}
break;
case ParseNodeType.Nonlocal:
return this.visitNonlocal(node as NonlocalNode);
if (this.visitNonlocal(node)) {
return node.nameList;
}
break;
case ParseNodeType.Number:
return this.visitNumber(node as NumberNode);
if (this.visitNumber(node)) {
return [];
}
break;
case ParseNodeType.Parameter:
return this.visitParameter(node as ParameterNode);
if (this.visitParameter(node)) {
return [node.name, node.typeAnnotation, node.defaultValue];
}
break;
case ParseNodeType.Pass:
return this.visitPass(node as PassNode);
if (this.visitPass(node)) {
return [];
}
break;
case ParseNodeType.Raise:
return this.visitRaise(node as RaiseNode);
if (this.visitRaise(node)) {
return [node.typeExpression, node.valueExpression, node.tracebackExpression];
}
break;
case ParseNodeType.Return:
return this.visitReturn(node as ReturnNode);
if (this.visitReturn(node)) {
return [node.returnExpression];
}
break;
case ParseNodeType.Set:
return this.visitSet(node as SetNode);
if (this.visitSet(node)) {
return node.entries;
}
break;
case ParseNodeType.Slice:
return this.visitSlice(node as SliceExpressionNode);
if (this.visitSlice(node)) {
return [node.startValue, node.endValue, node.stepValue];
}
break;
case ParseNodeType.StatementList:
return this.visitStatementList(node as StatementListNode);
if (this.visitStatementList(node)) {
return node.statements;
}
break;
case ParseNodeType.String:
return this.visitString(node as StringNode);
if (this.visitString(node)) {
return [];
}
break;
case ParseNodeType.StringList:
return this.visitStringList(node as StringListNode);
if (this.visitStringList(node)) {
return [node.typeAnnotation, ...node.strings];
}
break;
case ParseNodeType.Suite:
return this.visitSuite(node as SuiteNode);
if (this.visitSuite(node)) {
return [...node.statements];
}
break;
case ParseNodeType.Tuple:
return this.visitTuple(node as TupleExpressionNode);
if (this.visitTuple(node)) {
return node.expressions;
}
break;
case ParseNodeType.Try:
return this.visitTry(node as TryNode);
if (this.visitTry(node)) {
return [node.trySuite, ...node.exceptClauses, node.elseSuite, node.finallySuite];
}
break;
case ParseNodeType.TypeAnnotation:
return this.visitTypeAnnotation(node as TypeAnnotationExpressionNode);
if (this.visitTypeAnnotation(node)) {
return [node.valueExpression, node.typeAnnotation];
}
break;
case ParseNodeType.UnaryOperation:
return this.visitUnaryOperation(node as UnaryExpressionNode);
if (this.visitUnaryOperation(node)) {
return [node.expression];
}
break;
case ParseNodeType.Unpack:
return this.visitUnpack(node as UnpackExpressionNode);
if (this.visitUnpack(node)) {
return [node.expression];
}
break;
case ParseNodeType.While:
return this.visitWhile(node as WhileNode);
if (this.visitWhile(node)) {
return [node.testExpression, node.whileSuite, node.elseSuite];
}
break;
case ParseNodeType.With:
return this.visitWith(node as WithNode);
if (this.visitWith(node)) {
return [...node.withItems, node.suite];
}
break;
case ParseNodeType.WithItem:
return this.visitWithItem(node as WithItemNode);
if (this.visitWithItem(node)) {
return [node.expression, node.target];
}
break;
case ParseNodeType.Yield:
return this.visitYield(node as YieldExpressionNode);
if (this.visitYield(node)) {
return [node.expression];
}
break;
case ParseNodeType.YieldFrom:
return this.visitYieldFrom(node as YieldFromExpressionNode);
if (this.visitYieldFrom(node)) {
return [node.expression];
}
break;
case ParseNodeType.None:
default:
assert.fail('Unexpected node type');
return true;
break;
}
return [];
}
// Override these methods as necessary.

View File

@ -18,9 +18,9 @@ import { TextRangeDiagnosticSink } from '../common/diagnosticSink';
import { NameBindings, NameBindingType } from '../parser/nameBindings';
import { AssignmentNode, AugmentedAssignmentExpressionNode, ClassNode, DelNode,
ExpressionNode, ForNode, FunctionNode, GlobalNode, ImportAsNode,
ImportFromAsNode, ImportFromNode, LambdaNode, ListNode, ModuleNameNode, ModuleNode,
NameNode, NonlocalNode, ParseNode, TupleExpressionNode,
TypeAnnotationExpressionNode, UnpackExpressionNode, WithNode } from '../parser/parseNodes';
ImportFromAsNode, ImportFromNode, LambdaNode, ModuleNameNode, ModuleNode,
NonlocalNode, ParseNode, ParseNodeArray, ParseNodeType, TypeAnnotationExpressionNode,
WithNode } from '../parser/parseNodes';
import { AnalyzerNodeInfo } from './analyzerNodeInfo';
import { ParseTreeWalker } from './parseTreeWalker';
@ -62,17 +62,12 @@ export class PostParseWalker extends ParseTreeWalker {
return this._importedModules;
}
visitNode(node: ParseNode): boolean {
const children = node.getChildren();
visitNode(node: ParseNode) {
const children = super.visitNode(node);
// Add the parent link to each of the child nodes.
children.forEach(child => {
if (child) {
child.parent = node;
}
});
this._addParentLinks(node, children);
return super.visitNode(node);
return children;
}
visitImportAs(node: ImportAsNode): boolean {
@ -110,22 +105,17 @@ export class PostParseWalker extends ParseTreeWalker {
this._addName(node.name.nameToken.value);
}
return false;
return true;
}
visitWith(node: WithNode): boolean {
node.withItems.forEach(item => {
this.walk(item);
});
node.withItems.forEach(item => {
if (item.target) {
this._addPossibleTupleNamedTarget(item.target);
}
});
this.walk(node.suite);
return false;
return true;
}
visitFunction(node: FunctionNode): boolean {
@ -154,6 +144,12 @@ export class PostParseWalker extends ParseTreeWalker {
this.walk(node.suite);
});
// Because we're returning false here, we need to
// call addParentLinks ourselves.
const children = [...node.decorators, node.name, ...node.parameters,
node.returnTypeAnnotation, node.suite];
this._addParentLinks(node, children);
return false;
}
@ -171,6 +167,11 @@ export class PostParseWalker extends ParseTreeWalker {
this.walk(node.suite);
});
// Because we're returning false here, we need to
// call addParentLinks ourselves.
const children = [...node.decorators, node.name, ...node.arguments, node.suite];
this._addParentLinks(node, children);
return false;
}
@ -192,6 +193,11 @@ export class PostParseWalker extends ParseTreeWalker {
this.walk(node.expression);
});
// Because we're returning false here, we need to
// call addParentLinks ourselves.
const children = [...node.parameters, node.expression];
this._addParentLinks(node, children);
return false;
}
@ -264,20 +270,29 @@ export class PostParseWalker extends ParseTreeWalker {
return true;
}
private _addParentLinks(parentNode: ParseNode, children: ParseNodeArray) {
// Add the parent link to each of the child nodes.
children.forEach(child => {
if (child) {
child.parent = parentNode;
}
});
}
private _addPossibleTupleNamedTarget(node: ExpressionNode) {
if (node instanceof NameNode) {
if (node.nodeType === ParseNodeType.Name) {
this._addName(node.nameToken.value);
} else if (node instanceof TupleExpressionNode) {
} else if (node.nodeType === ParseNodeType.Tuple) {
node.expressions.forEach(expr => {
this._addPossibleTupleNamedTarget(expr);
});
} else if (node instanceof ListNode) {
} else if (node.nodeType === ParseNodeType.List) {
node.entries.forEach(expr => {
this._addPossibleTupleNamedTarget(expr);
});
} else if (node instanceof TypeAnnotationExpressionNode) {
} else if (node.nodeType === ParseNodeType.TypeAnnotation) {
this._addPossibleTupleNamedTarget(node.valueExpression);
} else if (node instanceof UnpackExpressionNode) {
} else if (node.nodeType === ParseNodeType.Unpack) {
this._addPossibleTupleNamedTarget(node.expression);
}
}

View File

@ -23,11 +23,11 @@ import { DiagnosticLevel } from '../common/configOptions';
import { CreateTypeStubFileAction } from '../common/diagnostic';
import { PythonVersion } from '../common/pythonVersion';
import { TextRange } from '../common/textRange';
import { AwaitExpressionNode, ClassNode, ErrorExpressionNode,
ExpressionNode, FunctionNode, GlobalNode, IfNode, LambdaNode, ModuleNameNode,
ModuleNode, NonlocalNode, RaiseNode, StatementListNode, StatementNode,
StringListNode, SuiteNode, TryNode, TypeAnnotationExpressionNode, WhileNode,
YieldExpressionNode, YieldFromExpressionNode } from '../parser/parseNodes';
import { AwaitExpressionNode, ClassNode, ErrorExpressionNode, ExpressionNode, FunctionNode,
GlobalNode, IfNode, LambdaNode, ModuleNameNode, ModuleNode, NonlocalNode, ParseNode,
ParseNodeType, RaiseNode, StatementNode, StringListNode, SuiteNode, TryNode,
TypeAnnotationExpressionNode, WhileNode, YieldExpressionNode,
YieldFromExpressionNode } from '../parser/parseNodes';
import { StringTokenUtils, UnescapeErrorType } from '../parser/stringTokenUtils';
import { StringTokenFlags } from '../parser/tokenizerTypes';
import { ScopeUtils } from '../scopeUtils';
@ -283,10 +283,10 @@ export abstract class SemanticAnalyzer extends ParseTreeWalker {
// Find the function or module that contains this function and use its scope.
// We can't simply use this._currentScope because functions within a class use
// the scope of the containing function or module when they execute.
let functionOrModuleNode = node.parent;
let functionOrModuleNode: ParseNode | undefined = node.parent;
while (functionOrModuleNode) {
if (functionOrModuleNode instanceof ModuleNode ||
functionOrModuleNode instanceof FunctionNode) {
if (functionOrModuleNode.nodeType === ParseNodeType.Module ||
functionOrModuleNode.nodeType === ParseNodeType.Function) {
break;
}
@ -399,7 +399,7 @@ export abstract class SemanticAnalyzer extends ParseTreeWalker {
unescapedResult.unescapeErrors.forEach(error => {
const start = stringNode.token.start + stringNode.token.prefixLength +
stringNode.token.quoteMarkLength + error.offset;
const textRange = new TextRange(start, error.length);
const textRange = { start, length: error.length };
if (error.errorType === UnescapeErrorType.InvalidEscapeSequence) {
this._addDiagnostic(this._fileInfo.diagnosticSettings.reportInvalidStringEscapeSequence,
@ -503,19 +503,19 @@ export abstract class SemanticAnalyzer extends ParseTreeWalker {
return undefined;
}
if (!(statemetns[0] instanceof StatementListNode)) {
if (statemetns[0].nodeType !== ParseNodeType.StatementList) {
return undefined;
}
// If the first statement in the suite isn't a StringNode,
// assume there is no docString.
const statementList = statemetns[0] as StatementListNode;
const statementList = statemetns[0];
if (statementList.statements.length === 0 ||
!(statementList.statements[0] instanceof StringListNode)) {
statementList.statements[0].nodeType !== ParseNodeType.StringList) {
return undefined;
}
const docStringNode = statementList.statements[0] as StringListNode;
const docStringNode = statementList.statements[0];
const docStringToken = docStringNode.strings[0].token;
// Ignore f-strings.
@ -532,7 +532,7 @@ export abstract class SemanticAnalyzer extends ParseTreeWalker {
if (!functionNode) {
this._addError(
`'yield' not allowed outside of a function`, node);
} else if (functionNode.isAsync && node instanceof YieldFromExpressionNode) {
} else if (functionNode.isAsync && node.nodeType === ParseNodeType.YieldFrom) {
// PEP 525 indicates that 'yield from' is not allowed in an
// async function.
this._addError(
@ -605,7 +605,8 @@ export class ModuleScopeAnalyzer extends SemanticAnalyzer {
assert(nameBindings !== undefined);
this._addNamesToScope(nameBindings!.getGlobalNames());
this.walkChildren(this._scopedNode);
const moduleNode = this._scopedNode as ModuleNode;
this.walkMultiple(moduleNode.statements);
// Associate the module's scope with the module type.
const moduleType = new ModuleType(this._currentScope.getSymbolTable(),

View File

@ -467,18 +467,14 @@ export class SourceFile {
this._analysisJob.parseResults.tokens, configOptions.diagnosticSettings,
useStrict);
} catch (e) {
let message: string;
if (e instanceof Error) {
message = e.stack || e.message;
} else {
message = JSON.stringify(e);
}
const message: string = (e.stack ? e.stack.toString() : undefined) ||
(typeof e.message === 'string' ? e.message : undefined) ||
JSON.stringify(e);
this._console.log(
`An internal error occurred while parsing ${ this.getFilePath() }: ` + message);
this._analysisJob.parseResults = {
parseTree: new ModuleNode(new TextRange(0, 0)),
parseTree: ModuleNode.create({ start: 0, length: 0 }),
futureImports: new StringMap<boolean>(),
tokens: new TextRangeCollection<Token>([]),
lines: new TextRangeCollection<TextRange>([]),
@ -650,13 +646,9 @@ export class SourceFile {
assert(moduleType instanceof ModuleType);
this._analysisJob.moduleType = moduleType as ModuleType;
} catch (e) {
let message: string;
if (e instanceof Error) {
message = e.stack || e.message;
} else {
message = JSON.stringify(e);
}
const message: string = (e.stack ? e.stack.toString() : undefined) ||
(typeof e.message === 'string' ? e.message : undefined) ||
JSON.stringify(e);
this._console.log(
`An internal error occurred while performing semantic analysis for ${ this.getFilePath() }: ` + message);
@ -701,13 +693,9 @@ export class SourceFile {
}
});
} catch (e) {
let message: string;
if (e instanceof Error) {
message = e.stack || e.message;
} else {
message = JSON.stringify(e);
}
const message: string = (e.stack ? e.stack.toString() : undefined) ||
(typeof e.message === 'string' ? e.message : undefined) ||
JSON.stringify(e);
this._console.log(
`An internal error occurred while while performing type analysis for ${ this.getFilePath() }: ` + message);
const diagSink = new DiagnosticSink();

View File

@ -17,16 +17,16 @@ import { convertOffsetsToRange } from '../common/positionUtils';
import { PythonVersion } from '../common/pythonVersion';
import { TextRange } from '../common/textRange';
import { AssertNode, AssignmentNode, AugmentedAssignmentExpressionNode,
BinaryExpressionNode, BreakNode, CallExpressionNode, ClassNode, ConstantNode,
BinaryExpressionNode, BreakNode, CallExpressionNode, ClassNode,
ContinueNode, DecoratorNode, DelNode, ErrorExpressionNode, ExceptNode, ExpressionNode,
FormatStringNode, ForNode, FunctionNode, IfNode, ImportAsNode,
ImportFromNode, IndexExpressionNode, LambdaNode, ListComprehensionForNode,
ListComprehensionNode, ListNode, MemberAccessExpressionNode, ModuleNode, NameNode,
ParameterCategory, ParseNode, RaiseNode, ReturnNode, SliceExpressionNode,
StringListNode, StringNode, SuiteNode, TernaryExpressionNode, TryNode,
TupleExpressionNode, TypeAnnotationExpressionNode, UnaryExpressionNode,
UnpackExpressionNode, WhileNode, WithNode, YieldExpressionNode,
YieldFromExpressionNode } from '../parser/parseNodes';
FormatStringNode, ForNode, FunctionNode, IfNode,
ImportAsNode, ImportFromNode, IndexExpressionNode, LambdaNode,
ListComprehensionNode, MemberAccessExpressionNode, ModuleNode,
NameNode, ParameterCategory, ParameterNode, ParseNode, ParseNodeType,
RaiseNode, ReturnNode, SliceExpressionNode, StringListNode,
SuiteNode, TernaryExpressionNode, TryNode,
TupleExpressionNode, TypeAnnotationExpressionNode, UnaryExpressionNode, UnpackExpressionNode,
WhileNode, WithNode, YieldExpressionNode, YieldFromExpressionNode } from '../parser/parseNodes';
import { KeywordType } from '../parser/tokenizerTypes';
import { ScopeUtils } from '../scopeUtils';
import { AnalyzerFileInfo } from './analyzerFileInfo';
@ -288,7 +288,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
node: node.name,
declaredType: decoratedType,
path: this._fileInfo.filePath,
range: convertOffsetsToRange(node.name.start, node.name.end, this._fileInfo.lines)
range: convertOffsetsToRange(node.name.start,
TextRange.getEnd(node.name), this._fileInfo.lines)
};
this._assignTypeToNameNode(node.name, decoratedType, declaration);
@ -366,7 +367,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
}
}
node.parameters.forEach((param, index) => {
node.parameters.forEach((param: ParameterNode, index) => {
let annotatedType: Type | undefined;
let defaultValueType: Type | undefined;
@ -386,7 +387,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
// PEP 484 indicates that if a parameter has a default value of 'None'
// the type checker should assume that the type is optional (i.e. a union
// of the specified type and 'None').
if (param.defaultValue instanceof ConstantNode) {
if (param.defaultValue && param.defaultValue.nodeType === ParseNodeType.Constant) {
if (param.defaultValue.token.keywordType === KeywordType.None) {
isNoneWithoutOptional = true;
@ -514,7 +515,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
category: DeclarationCategory.Parameter,
node: paramNode,
path: this._fileInfo.filePath,
range: convertOffsetsToRange(paramNode.start, paramNode.end, this._fileInfo.lines),
range: convertOffsetsToRange(paramNode.start, TextRange.getEnd(paramNode),
this._fileInfo.lines),
declaredType: specializedParamType
};
assert(paramNode !== undefined && paramNode.name !== undefined);
@ -542,7 +544,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
category: containingClassNode ? DeclarationCategory.Method : DeclarationCategory.Function,
node: node.name,
path: this._fileInfo.filePath,
range: convertOffsetsToRange(node.name.start, node.name.end, this._fileInfo.lines),
range: convertOffsetsToRange(node.name.start, TextRange.getEnd(node.name),
this._fileInfo.lines),
declaredType: decoratedType
};
this._assignTypeToNameNode(node.name, decoratedType, declaration);
@ -579,7 +582,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
category: DeclarationCategory.Parameter,
node: param,
path: this._fileInfo.filePath,
range: convertOffsetsToRange(param.start, param.end, this._fileInfo.lines)
range: convertOffsetsToRange(param.start, TextRange.getEnd(param),
this._fileInfo.lines)
};
const paramType = UnknownType.create();
this._addTypeSourceToNameNode(param.name, paramType, declaration);
@ -602,7 +606,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
functionType.getInferredReturnType().addSource(
returnType, AnalyzerNodeInfo.getTypeSourceId(node.expression));
this.walkChildren(node.expression);
// Walk the children.
this.walkMultiple([...node.parameters, node.expression]);
});
// Cache the function type.
@ -684,7 +689,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
// when complete.
this._enterTemporaryScope(() => {
node.comprehensions.forEach(compr => {
if (compr instanceof ListComprehensionForNode) {
if (compr.nodeType === ParseNodeType.ListComprehensionFor) {
this.walk(compr.iterableExpression);
const iteratorType = this._getTypeOfExpression(compr.iterableExpression);
@ -987,7 +992,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
category: DeclarationCategory.Variable,
node: node.name,
path: this._fileInfo.filePath,
range: convertOffsetsToRange(node.name.start, node.name.end, this._fileInfo.lines)
range: convertOffsetsToRange(node.name.start, TextRange.getEnd(node.name),
this._fileInfo.lines)
};
this._addNamedTargetToCurrentScope(node.name);
this._assignTypeToNameNode(node.name, exceptionType, declaration);
@ -1119,7 +1125,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
// If this is an enum, transform the type as required.
let effectiveType = srcType;
if (node.leftExpression instanceof NameNode && !node.typeAnnotationComment) {
if (node.leftExpression.nodeType === ParseNodeType.Name && !node.typeAnnotationComment) {
effectiveType = this._transformTypeForPossibleEnumClass(
node.leftExpression, effectiveType);
}
@ -1139,7 +1145,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
// Did the caller pass an optional assert message as a second parameter?
// If so, strip it off and include only the test.
if (node.testExpression instanceof TupleExpressionNode) {
if (node.testExpression.nodeType === ParseNodeType.Tuple) {
assertTestExpression = node.testExpression.expressions[0];
}
@ -1217,7 +1223,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
visitFormatString(node: FormatStringNode): boolean {
node.expressions.forEach(formatExpr => {
this._getTypeOfExpression(formatExpr.expression,
this._getTypeOfExpression(formatExpr,
EvaluatorFlags.AllowForwardReferences);
});
@ -1261,7 +1267,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
this._markExpressionAccessed(expr);
this._evaluateExpressionForDeletion(expr);
if (expr instanceof NameNode) {
if (expr.nodeType === ParseNodeType.Name) {
const symbolWithScope = this._currentScope.lookUpSymbolRecursive(expr.nameToken.value);
if (symbolWithScope) {
if (symbolWithScope.symbol.hasDeclarations()) {
@ -1507,7 +1513,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
let typeHintType = this._getTypeOfAnnotation(node.typeAnnotation);
// If this is within an enum, transform the type.
if (node.valueExpression instanceof NameNode) {
if (node.valueExpression && node.valueExpression.nodeType === ParseNodeType.Name) {
typeHintType = this._transformTypeForPossibleEnumClass(
node.valueExpression, typeHintType);
}
@ -1552,8 +1558,9 @@ export class TypeAnalyzer extends ParseTreeWalker {
// Create a text range that covers the next statement through
// the end of the suite.
const start = node.statements[index + 1].start;
const end = node.statements[node.statements.length - 1].end;
this._addUnusedCode(new TextRange(start, end - start));
const lastStatement = node.statements[node.statements.length - 1];
const end = TextRange.getEnd(lastStatement);
this._addUnusedCode({ start, length: end - start });
}
// Note that we already reported this so we don't do it again.
@ -1572,7 +1579,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
return;
}
if (!(node.leftExpression instanceof NameNode) ||
if (node.leftExpression.nodeType !== ParseNodeType.Name ||
node.leftExpression.nameToken.value !== 'isinstance' ||
node.arguments.length !== 2) {
return;
@ -1687,7 +1694,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
return false;
}
if (node.leftExpression instanceof NameNode) {
if (node.leftExpression.nodeType === ParseNodeType.Name) {
const assignedName = node.leftExpression.nameToken.value;
let specialType: Type | undefined;
@ -1754,14 +1761,14 @@ export class TypeAnalyzer extends ParseTreeWalker {
node: node.leftExpression,
path: this._fileInfo.filePath,
range: convertOffsetsToRange(node.leftExpression.start,
node.leftExpression.end, this._fileInfo.lines)
TextRange.getEnd(node.leftExpression), this._fileInfo.lines)
};
this._assignTypeToNameNode(node.leftExpression, specialType, declaration);
this._updateExpressionTypeForNode(node.leftExpression, specialType);
return true;
}
} else if (node.leftExpression instanceof TypeAnnotationExpressionNode &&
node.leftExpression.valueExpression instanceof NameNode) {
} else if (node.leftExpression.nodeType === ParseNodeType.TypeAnnotation &&
node.leftExpression.valueExpression.nodeType === ParseNodeType.Name) {
const nameNode = node.leftExpression.valueExpression;
const assignedName = nameNode.nameToken.value;
@ -1804,7 +1811,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
node: nameNode,
path: this._fileInfo.filePath,
range: convertOffsetsToRange(nameNode.start,
nameNode.end, this._fileInfo.lines)
TextRange.getEnd(nameNode), this._fileInfo.lines)
};
this._assignTypeToNameNode(nameNode, specialType, declaration);
this._updateExpressionTypeForNode(nameNode, specialType);
@ -1869,7 +1876,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
let declarationHandled = false;
if (target instanceof NameNode) {
if (target.nodeType === ParseNodeType.Name) {
const name = target.nameToken;
const declaration: Declaration = {
category: DeclarationCategory.Variable,
@ -1877,7 +1884,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
isConstant: SymbolUtils.isConstantName(name.value),
path: this._fileInfo.filePath,
declaredType,
range: convertOffsetsToRange(name.start, name.end, this._fileInfo.lines)
range: convertOffsetsToRange(name.start, TextRange.getEnd(name), this._fileInfo.lines)
};
const symbolWithScope = this._currentScope.lookUpSymbolRecursive(name.value);
@ -1886,11 +1893,11 @@ export class TypeAnalyzer extends ParseTreeWalker {
}
AnalyzerNodeInfo.setDeclarations(target, [declaration]);
declarationHandled = true;
} else if (target instanceof MemberAccessExpressionNode) {
} else if (target.nodeType === ParseNodeType.MemberAccess) {
const targetNode = target.leftExpression;
// Handle member accesses (e.g. self.x or cls.y).
if (targetNode instanceof NameNode) {
if (targetNode && targetNode.nodeType === ParseNodeType.Name) {
// Determine whether we're writing to a class or instance member.
const enclosingClassNode = ParseTreeUtils.getEnclosingClass(target);
@ -2028,14 +2035,14 @@ export class TypeAnalyzer extends ParseTreeWalker {
if (primaryDeclaration.node &&
primaryDeclaration.node.parent &&
primaryDeclaration.node.parent === classOrModuleNode &&
classOrModuleNode instanceof ClassNode) {
classOrModuleNode.nodeType === ParseNodeType.Class) {
classOrModuleNode = ParseTreeUtils.getEnclosingClassOrModule(classOrModuleNode);
}
// If it's a class member, check whether it's a legal protected access.
let isProtectedAccess = false;
if (classOrModuleNode instanceof ClassNode) {
if (classOrModuleNode && classOrModuleNode.nodeType === ParseNodeType.Class) {
if (isProtectedName) {
const declarationClassType = AnalyzerNodeInfo.getExpressionType(classOrModuleNode);
if (declarationClassType && declarationClassType instanceof ClassType) {
@ -2065,7 +2072,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
`'${ nameValue }' is protected and used outside of a derived class`,
node);
} else {
const scopeName = classOrModuleNode instanceof ClassNode ?
const scopeName = classOrModuleNode.nodeType === ParseNodeType.Class ?
'class' : 'module';
this._addDiagnostic(this._fileInfo.diagnosticSettings.reportPrivateUsage,
@ -2325,7 +2332,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
}
// Handle property setters and deleters.
if (decoratorNode.leftExpression instanceof MemberAccessExpressionNode) {
if (decoratorNode.leftExpression.nodeType === ParseNodeType.MemberAccess) {
const baseType = this._getTypeOfExpression(decoratorNode.leftExpression.leftExpression);
if (baseType instanceof PropertyType) {
const memberName = decoratorNode.leftExpression.memberName.nameToken.value;
@ -2736,7 +2743,9 @@ export class TypeAnalyzer extends ParseTreeWalker {
node: node.memberName,
isConstant,
path: this._fileInfo.filePath,
range: convertOffsetsToRange(node.memberName.start, node.memberName.end, this._fileInfo.lines)
range: convertOffsetsToRange(node.memberName.start,
node.memberName.start + node.memberName.length,
this._fileInfo.lines)
};
if (typeAnnotationNode) {
@ -3021,7 +3030,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
}
private _markExpressionAccessed(target: ExpressionNode) {
if (target instanceof NameNode) {
if (target.nodeType === ParseNodeType.Name) {
const nameValue = target.nameToken.value;
const symbolWithScope = this._currentScope.lookUpSymbolRecursive(nameValue);
@ -3032,14 +3041,15 @@ export class TypeAnalyzer extends ParseTreeWalker {
}
private _assignTypeToExpression(target: ExpressionNode, srcType: Type, srcExpr: ExpressionNode): void {
if (target instanceof NameNode) {
if (target.nodeType === ParseNodeType.Name) {
const name = target.nameToken;
const declaration: Declaration = {
category: DeclarationCategory.Variable,
node: target,
isConstant: SymbolUtils.isConstantName(name.value),
path: this._fileInfo.filePath,
range: convertOffsetsToRange(name.start, name.end, this._fileInfo.lines)
range: convertOffsetsToRange(name.start, TextRange.getEnd(name),
this._fileInfo.lines)
};
// Handle '__all__' as a special case in the module scope.
@ -3047,10 +3057,12 @@ export class TypeAnalyzer extends ParseTreeWalker {
// It's common for modules to include the expression
// __all__ = ['a', 'b', 'c']
// We will mark the symbols referenced by these strings as accessed.
if (srcExpr instanceof ListNode) {
if (srcExpr.nodeType === ParseNodeType.List) {
srcExpr.entries.forEach(entryExpr => {
if (entryExpr instanceof StringListNode || entryExpr instanceof StringNode) {
const symbolName = entryExpr.getValue();
if (entryExpr.nodeType === ParseNodeType.StringList || entryExpr.nodeType === ParseNodeType.String) {
const symbolName = entryExpr.nodeType === ParseNodeType.String ?
entryExpr.value :
entryExpr.strings.map(s => s.value).join('');
const symbolInScope = this._currentScope.lookUpSymbolRecursive(symbolName);
if (symbolInScope) {
this._setSymbolAccessed(symbolInScope.symbol);
@ -3065,11 +3077,11 @@ export class TypeAnalyzer extends ParseTreeWalker {
target, srcType, srcExpr);
this._assignTypeToNameNode(target, srcType, declaration, srcExpr);
} else if (target instanceof MemberAccessExpressionNode) {
} else if (target.nodeType === ParseNodeType.MemberAccess) {
const targetNode = target.leftExpression;
// Handle member accesses (e.g. self.x or cls.y).
if (targetNode instanceof NameNode) {
if (targetNode.nodeType === ParseNodeType.Name) {
// Determine whether we're writing to a class or instance member.
const enclosingClassNode = ParseTreeUtils.getEnclosingClass(target);
@ -3092,7 +3104,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
}
}
}
} else if (target instanceof TupleExpressionNode) {
} else if (target.nodeType === ParseNodeType.Tuple) {
// Initialize the array of target types, one for each target.
const targetTypes: Type[][] = new Array(target.expressions.length);
for (let i = 0; i < target.expressions.length; i++) {
@ -3113,7 +3125,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
}
const targetEndsWithUnpackOperator = target.expressions.length > 0 &&
target.expressions[target.expressions.length - 1] instanceof UnpackExpressionNode;
target.expressions[target.expressions.length - 1].nodeType === ParseNodeType.Unpack;
if (targetEndsWithUnpackOperator) {
if (entryCount >= target.expressions.length) {
@ -3169,7 +3181,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
const targetType = typeList.length === 0 ? UnknownType.create() : TypeUtils.combineTypes(typeList);
this._assignTypeToExpression(expr, targetType, srcExpr);
});
} else if (target instanceof TypeAnnotationExpressionNode) {
} else if (target.nodeType === ParseNodeType.TypeAnnotation) {
const typeHintType = this._getTypeOfAnnotation(target.typeAnnotation);
const diagAddendum = new DiagnosticAddendum();
if (TypeUtils.canAssignType(typeHintType, srcType, diagAddendum)) {
@ -3177,15 +3189,16 @@ export class TypeAnalyzer extends ParseTreeWalker {
}
this._assignTypeToExpression(target.valueExpression, srcType, srcExpr);
} else if (target instanceof UnpackExpressionNode) {
if (target.expression instanceof NameNode) {
} else if (target.nodeType === ParseNodeType.Unpack) {
if (target.expression.nodeType === ParseNodeType.Name) {
const name = target.expression.nameToken;
const declaration: Declaration = {
category: DeclarationCategory.Variable,
node: target.expression,
isConstant: SymbolUtils.isConstantName(name.value),
path: this._fileInfo.filePath,
range: convertOffsetsToRange(name.start, name.end, this._fileInfo.lines)
range: convertOffsetsToRange(name.start, TextRange.getEnd(name),
this._fileInfo.lines)
};
if (!srcType.isAny()) {
@ -3199,7 +3212,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
}
this._assignTypeToNameNode(target.expression, srcType, declaration, srcExpr);
}
} else if (target instanceof ListNode) {
} else if (target.nodeType === ParseNodeType.List) {
target.entries.forEach(entry => {
this._assignTypeToExpression(entry, UnknownType.create(), srcExpr);
});
@ -3210,20 +3223,20 @@ export class TypeAnalyzer extends ParseTreeWalker {
}
private _addNamedTargetToCurrentScope(node: ExpressionNode) {
if (node instanceof NameNode) {
if (node.nodeType === ParseNodeType.Name) {
const symbol = this._currentScope.addSymbol(node.nameToken.value, true);
// Mark the symbol as accessed. These symbols are not persisted
// between analysis passes, so we never have an opportunity to
// mark them as accessed.
symbol.setIsAcccessed();
} else if (node instanceof TypeAnnotationExpressionNode) {
} else if (node.nodeType === ParseNodeType.TypeAnnotation) {
this._addNamedTargetToCurrentScope(node.valueExpression);
} else if (node instanceof TupleExpressionNode) {
} else if (node.nodeType === ParseNodeType.Tuple) {
node.expressions.forEach(expr => {
this._addNamedTargetToCurrentScope(expr);
});
} else if (node instanceof ListNode) {
} else if (node.nodeType === ParseNodeType.List) {
node.entries.forEach(expr => {
this._addNamedTargetToCurrentScope(expr);
});
@ -3292,9 +3305,9 @@ export class TypeAnalyzer extends ParseTreeWalker {
// Is this module ever accessed?
if (targetSymbol && !targetSymbol.isAccessed()) {
const multipartName = nameParts.map(np => np.nameToken.value).join('.');
const textRange = new TextRange(nameParts[0].start, nameParts[0].length);
const textRange = { start: nameParts[0].start, length: nameParts[0].length };
if (nameParts.length > 1) {
textRange.extend(nameParts[nameParts.length - 1]);
TextRange.extend(textRange, nameParts[nameParts.length - 1]);
}
this._fileInfo.diagnosticSink.addUnusedCodeWithTextRange(
`'${ multipartName }' is not accessed`, textRange);
@ -3581,6 +3594,12 @@ export class TypeAnalyzer extends ParseTreeWalker {
const newScope = AnalyzerNodeInfo.getScope(node);
assert(newScope !== undefined);
// Clear the defaultValueInitializerExpression because we want
// to allow calls within lambdas that are used to initialize
// parameters.
const wasDefaultValueInitizer = this._defaultValueInitializerExpression;
this._defaultValueInitializerExpression = false;
let prevParent: Scope | undefined;
if (!newScope!.isIndependentlyExecutable()) {
// Temporary reparent the scope in case it is contained
@ -3608,6 +3627,8 @@ export class TypeAnalyzer extends ParseTreeWalker {
newScope!.setParent(prevParent);
}
this._defaultValueInitializerExpression = wasDefaultValueInitizer;
return newScope!;
}

View File

@ -12,10 +12,7 @@
* None within that scope.
*/
import { ArgumentCategory, BinaryExpressionNode, CallExpressionNode, ConstantNode,
ExpressionNode, MemberAccessExpressionNode, NameNode,
TypeAnnotationExpressionNode,
UnaryExpressionNode } from '../parser/parseNodes';
import { ArgumentCategory, ExpressionNode, ParseNodeType } from '../parser/parseNodes';
import { KeywordType, OperatorType } from '../parser/tokenizerTypes';
import { ClassType, NeverType, NoneType, ObjectType, Type, TypeCategory, UnionType } from './types';
import { TypeUtils } from './typeUtils';
@ -102,9 +99,9 @@ export class TypeConstraint {
// For now, we support only simple names and member access chains
// that include only simple names (e.g. "A.B.C.D").
static isSupportedExpression(expression: ExpressionNode) {
if (expression instanceof NameNode) {
if (expression.nodeType === ParseNodeType.Name) {
return true;
} else if (expression instanceof MemberAccessExpressionNode) {
} else if (expression.nodeType === ParseNodeType.MemberAccess) {
if (!this.isSupportedExpression(expression.leftExpression)) {
return false;
}
@ -122,12 +119,12 @@ export class TypeConstraint {
private _doesExpressionMatchRecursive(expression1: ExpressionNode,
expression2: ExpressionNode): boolean {
if (expression1 instanceof NameNode) {
if (expression2 instanceof NameNode) {
if (expression1.nodeType === ParseNodeType.Name) {
if (expression2.nodeType === ParseNodeType.Name) {
return expression1.nameToken.value === expression2.nameToken.value;
}
} else if (expression1 instanceof MemberAccessExpressionNode) {
if (expression2 instanceof MemberAccessExpressionNode) {
} else if (expression1.nodeType === ParseNodeType.MemberAccess) {
if (expression2.nodeType === ParseNodeType.MemberAccess) {
return this._doesExpressionMatchRecursive(expression1.leftExpression, expression2.leftExpression) &&
this._doesExpressionMatchRecursive(expression1.memberName, expression2.memberName);
}
@ -145,7 +142,7 @@ export class TypeConstraintBuilder {
typeEvaluator: (node: ExpressionNode) => Type):
ConditionalTypeConstraintResults | undefined {
if (testExpression instanceof BinaryExpressionNode) {
if (testExpression.nodeType === ParseNodeType.BinaryOperation) {
const results: ConditionalTypeConstraintResults = {
ifConstraints: [],
elseConstraints: []
@ -157,7 +154,7 @@ export class TypeConstraintBuilder {
// Look for "X is None" or "X is not None". These are commonly-used
// patterns used in control flow.
if (TypeConstraint.isSupportedExpression(testExpression.leftExpression)) {
if (testExpression.rightExpression instanceof ConstantNode &&
if (testExpression.rightExpression.nodeType === ParseNodeType.Constant &&
testExpression.rightExpression.token.keywordType === KeywordType.None) {
const originalType = typeEvaluator(testExpression.leftExpression);
@ -175,7 +172,7 @@ export class TypeConstraintBuilder {
}
// Look for "type(X) is Y" or "type(X) is not Y".
if (testExpression.leftExpression instanceof CallExpressionNode) {
if (testExpression.leftExpression.nodeType === ParseNodeType.Call) {
const callType = typeEvaluator(testExpression.leftExpression.leftExpression);
if (callType instanceof ClassType && callType.isBuiltIn() &&
callType.getClassName() === 'type' &&
@ -242,7 +239,7 @@ export class TypeConstraintBuilder {
}
return results;
}
} else if (testExpression instanceof UnaryExpressionNode) {
} else if (testExpression.nodeType === ParseNodeType.UnaryOperation) {
if (testExpression.operator === OperatorType.Not) {
const constraints = this.buildTypeConstraintsForConditional(
testExpression.expression, typeEvaluator);
@ -255,8 +252,8 @@ export class TypeConstraintBuilder {
};
}
}
} else if (testExpression instanceof NameNode ||
testExpression instanceof MemberAccessExpressionNode) {
} else if (testExpression.nodeType === ParseNodeType.Name ||
testExpression.nodeType === ParseNodeType.MemberAccess) {
if (TypeConstraint.isSupportedExpression(testExpression)) {
const originalType = typeEvaluator(testExpression);
@ -269,8 +266,8 @@ export class TypeConstraintBuilder {
elseConstraints: [falseConstraint]
};
}
} else if (testExpression instanceof CallExpressionNode) {
if (testExpression.leftExpression instanceof NameNode &&
} else if (testExpression.nodeType === ParseNodeType.Call) {
if (testExpression.leftExpression.nodeType === ParseNodeType.Name &&
testExpression.leftExpression.nameToken.value === 'isinstance' &&
testExpression.arguments.length === 2) {
@ -329,7 +326,7 @@ export class TypeConstraintBuilder {
static buildTypeConstraintForAssignment(targetNode: ExpressionNode,
assignmentType: Type): TypeConstraint | undefined {
if (targetNode instanceof TypeAnnotationExpressionNode) {
if (targetNode.nodeType === ParseNodeType.TypeAnnotation) {
if (TypeConstraint.isSupportedExpression(targetNode.valueExpression)) {
return new TypeConstraint(targetNode.valueExpression, assignmentType);
}

View File

@ -13,8 +13,9 @@ import * as fs from 'fs';
import { ArgumentCategory, ArgumentNode, AssignmentNode, AugmentedAssignmentExpressionNode,
ClassNode, DecoratorNode, ExpressionNode, ForNode, FunctionNode, IfNode,
ImportFromNode, ImportNode, MemberAccessExpressionNode, ModuleNameNode, NameNode,
ParameterCategory, ParameterNode, ParseNode, StatementListNode,
StringListNode, StringNode, TryNode, TypeAnnotationExpressionNode, WhileNode,
ParameterCategory, ParameterNode, ParseNode, ParseNodeType,
StatementListNode, StringListNode, StringNode, TryNode, TypeAnnotationExpressionNode,
WhileNode,
WithNode } from '../parser/parseNodes';
import { AnalyzerNodeInfo } from './analyzerNodeInfo';
import { ParseTreeUtils, PrintExpressionFlags } from './parseTreeUtils';
@ -86,7 +87,7 @@ class ImportSymbolWalker extends ParseTreeWalker {
visitString(node: StringNode) {
if (this._treatStringsAsSymbols) {
const value = node.getValue();
const value = node.value;
this._markNameAccessed(node, value);
}
@ -173,7 +174,7 @@ export class TypeStubWriter extends ParseTreeWalker {
this._emitSuite(() => {
this._classNestCount++;
this.walkChildren(node);
this.walk(node.suite);
this._classNestCount--;
});
@ -228,7 +229,7 @@ export class TypeStubWriter extends ParseTreeWalker {
this._emitSuite(() => {
// Don't emit any nested functions.
this._functionNestCount++;
this.walkChildren(node);
this.walk(node.suite);
this._functionNestCount--;
});
@ -273,13 +274,18 @@ export class TypeStubWriter extends ParseTreeWalker {
this._emittedSuite = true;
this._emitLine('if ' + this._printExpression(node.testExpression) + ':');
this._emitSuite(() => {
this.walkChildren(node.ifSuite);
this.walkMultiple(node.ifSuite.statements);
});
if (node.elseSuite) {
const elseSuite = node.elseSuite;
if (elseSuite) {
this._emitLine('else:');
this._emitSuite(() => {
this.walkChildren(node.elseSuite!);
if (elseSuite.nodeType === ParseNodeType.If) {
this.walkMultiple([elseSuite.testExpression, elseSuite.ifSuite, elseSuite.elseSuite]);
} else {
this.walkMultiple(elseSuite.statements);
}
});
}
this._ifNestCount--;
@ -291,7 +297,7 @@ export class TypeStubWriter extends ParseTreeWalker {
visitAssignment(node: AssignmentNode) {
let line = '';
if (node.leftExpression instanceof NameNode) {
if (node.leftExpression.nodeType === ParseNodeType.Name) {
if (this._functionNestCount === 0) {
line = this._printExpression(node.leftExpression);
}
@ -299,9 +305,9 @@ export class TypeStubWriter extends ParseTreeWalker {
if (node.leftExpression.nameToken.value === '__all__') {
this._emitLine(this._printExpression(node, false, true));
}
} else if (node.leftExpression instanceof MemberAccessExpressionNode) {
} else if (node.leftExpression.nodeType === ParseNodeType.MemberAccess) {
const baseExpression = node.leftExpression.leftExpression;
if (baseExpression instanceof NameNode) {
if (baseExpression.nodeType === ParseNodeType.Name) {
if (baseExpression.nameToken.value === 'self') {
const memberName = node.leftExpression.memberName.nameToken.value;
if (!SymbolUtils.isProtectedName(memberName) &&
@ -342,7 +348,7 @@ export class TypeStubWriter extends ParseTreeWalker {
visitAugmentedAssignment(node: AugmentedAssignmentExpressionNode) {
if (this._classNestCount === 0 && this._functionNestCount === 0) {
if (node.leftExpression instanceof NameNode) {
if (node.leftExpression.nodeType === ParseNodeType.Name) {
if (node.leftExpression.nameToken.value === '__all__') {
this._emitLine(this._printExpression(node, false, true));
}
@ -355,11 +361,11 @@ export class TypeStubWriter extends ParseTreeWalker {
visitTypeAnnotation(node: TypeAnnotationExpressionNode) {
if (this._functionNestCount === 0) {
let line = '';
if (node.valueExpression instanceof NameNode) {
if (node.valueExpression.nodeType === ParseNodeType.Name) {
line = this._printExpression(node.valueExpression);
} else if (node.valueExpression instanceof MemberAccessExpressionNode) {
} else if (node.valueExpression.nodeType === ParseNodeType.MemberAccess) {
const baseExpression = node.valueExpression.leftExpression;
if (baseExpression instanceof NameNode) {
if (baseExpression.nodeType === ParseNodeType.Name) {
if (baseExpression.nameToken.value === 'self') {
const memberName = node.valueExpression.memberName.nameToken.value;
if (!SymbolUtils.isProtectedName(memberName) &&
@ -438,7 +444,7 @@ export class TypeStubWriter extends ParseTreeWalker {
}
visitStatementList(node: StatementListNode) {
if (node.statements.length > 0 && node.statements[0] instanceof StringListNode) {
if (node.statements.length > 0 && node.statements[0].nodeType === ParseNodeType.StringList) {
// Is this the first statement in a suite? If it's a string
// literal, assume it's a doc string and emit it.
if (!this._emittedSuite && this._emitDocString) {
@ -449,7 +455,7 @@ export class TypeStubWriter extends ParseTreeWalker {
// Don't emit a doc string after the first statement.
this._emitDocString = false;
this.walkChildren(node);
this.walkMultiple(node.statements);
return false;
}

View File

@ -71,14 +71,14 @@ export class TextRangeDiagnosticSink extends DiagnosticSink {
}
addErrorWithTextRange(message: string, range: TextRange) {
return this.addError(message, convertOffsetsToRange(range.start, range.end, this._lines));
return this.addError(message, convertOffsetsToRange(range.start, range.start + range.length, this._lines));
}
addWarningWithTextRange(message: string, range: TextRange) {
return this.addWarning(message, convertOffsetsToRange(range.start, range.end, this._lines));
return this.addWarning(message, convertOffsetsToRange(range.start, range.start + range.length, this._lines));
}
addUnusedCodeWithTextRange(message: string, range: TextRange) {
return this.addUnusedCode(message, convertOffsetsToRange(range.start, range.end, this._lines));
return this.addUnusedCode(message, convertOffsetsToRange(range.start, range.start + range.length, this._lines));
}
}

View File

@ -7,43 +7,44 @@
* Specifies the range of text within a larger string.
*/
export class TextRange {
export interface TextRange {
start: number;
length: number;
}
constructor(start: number, length: number) {
export namespace TextRange {
export function create(start: number, length: number): TextRange {
if (start < 0) {
throw new Error('start must be non-negative');
}
if (length < 0) {
throw new Error('length must be non-negative');
}
this.start = start;
this.length = length;
return { start, length };
}
get end(): number {
return this.start + this.length;
export function getEnd(range: TextRange): number {
return range.start + range.length;
}
contains(position: number): boolean {
return position >= this.start && position < this.end;
export function contains(range: TextRange, position: number): boolean {
return position >= range.start && position < getEnd(range);
}
extend(range: TextRange | TextRange[] | undefined) {
if (range) {
if (Array.isArray(range)) {
range.forEach(r => {
this.extend(r);
export function extend(range: TextRange, extension: TextRange | TextRange[] | undefined) {
if (extension) {
if (Array.isArray(extension)) {
extension.forEach(r => {
extend(range, r);
});
} else {
if (range.start < this.start) {
this.length += this.start - range.start;
this.start = range.start;
if (extension.start < range.start) {
range.length += range.start - extension.start;
range.start = extension.start;
}
if (range.end > this.end) {
this.length += range.end - this.end;
if (getEnd(extension) > getEnd(range)) {
range.length += getEnd(extension) - getEnd(range);
}
}
}

View File

@ -25,7 +25,8 @@ export class TextRangeCollection<T extends TextRange> {
}
get end(): number {
return this._items.length > 0 ? this._items[this._items.length - 1].end : 0;
const lastItem = this._items[this._items.length - 1];
return this._items.length > 0 ? lastItem.start + lastItem.length : 0;
}
get length(): number {
@ -102,10 +103,13 @@ export class TextRangeCollection<T extends TextRange> {
const mid = Math.floor(min + (max - min) / 2);
const item = this._items[mid];
if (item.contains(position)) {
if (TextRange.contains(item, position)) {
return mid;
}
if (mid < this.count - 1 && item.end <= position && position < this._items[mid + 1].start) {
if (mid < this.count - 1 && TextRange.getEnd(item) <= position &&
position < this._items[mid + 1].start) {
return -1;
}

View File

@ -9,8 +9,7 @@
*/
import { CompletionItem, CompletionItemKind, CompletionList,
MarkupKind,
TextEdit } from 'vscode-languageserver';
MarkupKind, TextEdit } from 'vscode-languageserver';
import { ImportMap } from '../analyzer/analyzerFileInfo';
import { AnalyzerNodeInfo } from '../analyzer/analyzerNodeInfo';
@ -32,10 +31,10 @@ import { TextEditAction } from '../common/editAction';
import { getFileName, stripFileExtension } from '../common/pathUtils';
import { convertPositionToOffset } from '../common/positionUtils';
import { StringUtils } from '../common/stringUtils';
import { TextRange } from '../common/textRange';
import { ErrorExpressionCategory, ErrorExpressionNode,
ExpressionNode, ImportFromAsNode, ImportFromNode,
MemberAccessExpressionNode, ModuleNameNode, ModuleNode, NameNode,
ParseNode, StringListNode, SuiteNode } from '../parser/parseNodes';
ExpressionNode, ImportFromNode, isExpressionNode, ModuleNameNode,
ParseNode, ParseNodeType } from '../parser/parseNodes';
import { ParseResults } from '../parser/parser';
import { TokenType } from '../parser/tokenizerTypes';
@ -230,7 +229,7 @@ export class CompletionProvider {
// precendence.
let errorNode: ParseNode | undefined = node;
while (errorNode) {
if (errorNode instanceof ErrorExpressionNode) {
if (errorNode.nodeType === ParseNodeType.Error) {
break;
}
@ -242,50 +241,50 @@ export class CompletionProvider {
let curNode = errorNode || node;
while (true) {
// Don't offer completions inside of a string node.
if (curNode instanceof StringListNode) {
if (curNode.nodeType === ParseNodeType.StringList) {
return undefined;
}
if (curNode instanceof ModuleNameNode) {
if (curNode.nodeType === ParseNodeType.ModuleName) {
return this._getImportModuleCompletions(curNode);
}
if (curNode instanceof ErrorExpressionNode) {
if (curNode.nodeType === ParseNodeType.Error) {
return this._getExpressionErrorCompletions(curNode, priorWord);
}
if (curNode instanceof MemberAccessExpressionNode) {
if (curNode.nodeType === ParseNodeType.MemberAccess) {
return this._getMemberAccessCompletions(curNode.leftExpression, priorWord);
}
if (curNode instanceof NameNode) {
if (curNode.nodeType === ParseNodeType.Name) {
// Are we within a "from X import Y as Z" statement and
// more specifically within the "Y"?
if (curNode.parent instanceof ImportFromAsNode) {
if (curNode.parent && curNode.parent.nodeType === ParseNodeType.ImportFromAs) {
const parentNode = curNode.parent.parent;
if (parentNode instanceof ImportFromNode) {
if (parentNode && parentNode.nodeType === ParseNodeType.ImportFrom) {
if (curNode.parent.name === curNode) {
return this._getImportFromCompletions(parentNode, priorWord);
} else {
return this._getImportFromCompletions(parentNode, '');
}
}
} else if (curNode.parent instanceof MemberAccessExpressionNode) {
} else if (curNode.parent && curNode.parent.nodeType === ParseNodeType.MemberAccess) {
return this._getMemberAccessCompletions(
curNode.parent.leftExpression, priorWord);
}
}
if (curNode instanceof ImportFromNode) {
if (curNode.nodeType === ParseNodeType.ImportFrom) {
return this._getImportFromCompletions(curNode, priorWord);
}
if (curNode instanceof ExpressionNode) {
if (isExpressionNode(curNode)) {
return this._getExpressionCompletions(curNode, priorWord);
}
if (curNode instanceof SuiteNode || curNode instanceof ModuleNode) {
if (curNode.nodeType === ParseNodeType.Suite || curNode.nodeType === ParseNodeType.Module) {
return this._getStatementCompletions(curNode, priorWord);
}
@ -312,7 +311,7 @@ export class CompletionProvider {
}
// If we're in the middle of a token, we're not in a comment.
if (offset > token.start && offset < token.end) {
if (offset > token.start && offset < TextRange.getEnd(token)) {
return false;
}
@ -342,7 +341,7 @@ export class CompletionProvider {
}
case ErrorExpressionCategory.MissingMemberAccessName: {
if (node.child instanceof ExpressionNode) {
if (node.child && isExpressionNode(node.child)) {
return this._getMemberAccessCompletions(node.child, priorWord);
}
break;
@ -482,7 +481,7 @@ export class CompletionProvider {
// Does an 'import from' statement already exist? If so, we'll reuse it.
const importStatement = importStatements.mapByFilePath[filePath];
if (importStatement && importStatement.node instanceof ImportFromNode) {
if (importStatement && importStatement.node.nodeType === ParseNodeType.ImportFrom) {
return ImportStatementUtils.getTextEditsForAutoImportSymbolAddition(
symbolName, importStatement, this._parseResults);
}
@ -804,7 +803,9 @@ export class CompletionProvider {
// If we're in the middle of a "from X import Y" statement, offer
// the "import" keyword as a completion.
if (!node.hasTrailingDot && node.parent instanceof ImportFromNode && node.parent.missingImportKeyword) {
if (!node.hasTrailingDot && node.parent && node.parent.nodeType === ParseNodeType.ImportFrom &&
node.parent.missingImportKeyword) {
const keyword = 'import';
const completionItem = CompletionItem.create(keyword);
completionItem.kind = CompletionItemKind.Keyword;

View File

@ -15,7 +15,8 @@ import { ParseTreeUtils } from '../analyzer/parseTreeUtils';
import { DiagnosticTextPosition, DiagnosticTextRange, DocumentTextRange } from '../common/diagnostic';
import { isFile } from '../common/pathUtils';
import { convertPositionToOffset } from '../common/positionUtils';
import { ModuleNameNode } from '../parser/parseNodes';
import { TextRange } from '../common/textRange';
import { ParseNodeType } from '../parser/parseNodes';
import { ParseResults } from '../parser/parser';
const _startOfFilePosition: DiagnosticTextPosition = { line: 0, column: 0 };
@ -35,7 +36,7 @@ export class DefinitionProvider {
return undefined;
}
if (node instanceof ModuleNameNode) {
if (node.nodeType === ParseNodeType.ModuleName) {
// If this is an imported module name, try to map the position
// to the resolved import path.
const importInfo = AnalyzerNodeInfo.getImportInfo(node);
@ -44,7 +45,7 @@ export class DefinitionProvider {
}
const pathOffset = node.nameParts.findIndex(range => {
return offset >= range.start && offset < range.end;
return offset >= range.start && offset < TextRange.getEnd(range);
});
if (pathOffset < 0) {

View File

@ -18,7 +18,8 @@ import { ClassType, FunctionType, ModuleType, OverloadedFunctionType,
Type, UnknownType } from '../analyzer/types';
import { DiagnosticTextPosition, DiagnosticTextRange } from '../common/diagnostic';
import { convertOffsetToPosition, convertPositionToOffset } from '../common/positionUtils';
import { ModuleNameNode, NameNode, ParseNode } from '../parser/parseNodes';
import { TextRange } from '../common/textRange';
import { ParseNode, ParseNodeType } from '../parser/parseNodes';
import { ParseResults } from '../parser/parser';
export interface HoverTextPart {
@ -49,11 +50,11 @@ export class HoverProvider {
parts: [],
range: {
start: convertOffsetToPosition(node.start, parseResults.lines),
end: convertOffsetToPosition(node.end, parseResults.lines)
end: convertOffsetToPosition(TextRange.getEnd(node), parseResults.lines)
}
};
if (node instanceof ModuleNameNode) {
if (node.nodeType === ParseNodeType.ModuleName) {
// If this is an imported module name, try to map the position
// to the resolved import path.
const importInfo = AnalyzerNodeInfo.getImportInfo(node);
@ -62,7 +63,7 @@ export class HoverProvider {
}
let pathOffset = node.nameParts.findIndex(range => {
return offset >= range.start && offset < range.end;
return offset >= range.start && offset < TextRange.getEnd(range);
});
if (pathOffset < 0) {
@ -104,7 +105,7 @@ export class HoverProvider {
switch (declaration.category) {
case DeclarationCategory.Variable: {
if (node instanceof NameNode) {
if (node.nodeType === ParseNodeType.Name) {
this._addResultsPart(results, '(variable) ' + node.nameToken.value +
this._getTypeText(node), true);
this._addDocumentationPart(results, node);
@ -114,7 +115,7 @@ export class HoverProvider {
}
case DeclarationCategory.Parameter: {
if (node instanceof NameNode) {
if (node.nodeType === ParseNodeType.Name) {
this._addResultsPart(results, '(parameter) ' + node.nameToken.value +
this._getTypeText(node), true);
this._addDocumentationPart(results, node);
@ -124,7 +125,7 @@ export class HoverProvider {
}
case DeclarationCategory.Class: {
if (node instanceof NameNode) {
if (node.nodeType === ParseNodeType.Name) {
this._addResultsPart(results, '(class) ' + this._getTypeText(node), true);
this._addDocumentationPart(results, node);
return results;
@ -133,7 +134,7 @@ export class HoverProvider {
}
case DeclarationCategory.Function: {
if (node instanceof NameNode) {
if (node.nodeType === ParseNodeType.Name) {
this._addResultsPart(results, '(function) ' + node.nameToken.value +
this._getTypeText(node), true);
this._addDocumentationPart(results, node);
@ -143,7 +144,7 @@ export class HoverProvider {
}
case DeclarationCategory.Method: {
if (node instanceof NameNode) {
if (node.nodeType === ParseNodeType.Name) {
this._addResultsPart(results, '(method) ' + node.nameToken.value +
this._getTypeText(node), true);
this._addDocumentationPart(results, node);
@ -153,7 +154,7 @@ export class HoverProvider {
}
case DeclarationCategory.Module: {
if (node instanceof NameNode) {
if (node.nodeType === ParseNodeType.Name) {
this._addResultsPart(results, '(module) ' + node.nameToken.value, true);
this._addDocumentationPart(results, node);
return results;
@ -164,12 +165,10 @@ export class HoverProvider {
}
// If we had no declaration, see if we can provide a minimal tooltip.
if (node instanceof NameNode) {
if (node instanceof NameNode) {
this._addResultsPart(results, node.nameToken.value + this._getTypeText(node), true);
this._addDocumentationPart(results, node);
return results;
}
if (node.nodeType === ParseNodeType.Name) {
this._addResultsPart(results, node.nameToken.value + this._getTypeText(node), true);
this._addDocumentationPart(results, node);
return results;
}
return undefined;

View File

@ -13,7 +13,8 @@ import { ImportStatement, ImportStatementUtils } from '../analyzer/importStateme
import { DiagnosticTextRange } from '../common/diagnostic';
import { TextEditAction } from '../common/editAction';
import { convertOffsetToPosition } from '../common/positionUtils';
import { ImportAsNode, ImportFromAsNode, ImportFromNode, ImportNode } from '../parser/parseNodes';
import { TextRange } from '../common/textRange';
import { ImportAsNode, ImportFromAsNode, ImportFromNode, ParseNodeType } from '../parser/parseNodes';
import { ParseResults } from '../parser/parser';
const _maxLineLength = 80;
@ -99,11 +100,12 @@ export class ImportSorter {
statementLimit = statements.length;
}
const lastStatement = statements[statementLimit - 1].node;
return {
start: convertOffsetToPosition(
statements[0].node.start, this._parseResults.lines),
end: convertOffsetToPosition(
statements[statementLimit - 1].node.end, this._parseResults.lines)
TextRange.getEnd(lastStatement), this._parseResults.lines)
};
}
@ -128,7 +130,7 @@ export class ImportSorter {
statements[secondaryBlockStart].node.start,
this._parseResults.lines),
end: convertOffsetToPosition(
statements[secondaryBlockLimit - 1].node.end,
TextRange.getEnd(statements[secondaryBlockLimit - 1].node),
this._parseResults.lines)
},
replacementText: ''
@ -154,7 +156,7 @@ export class ImportSorter {
}
let importLine: string;
if (statement.node instanceof ImportNode) {
if (statement.node.nodeType === ParseNodeType.Import) {
importLine = this._formatImportNode(statement.subnode!,
statement.moduleName);
} else {

View File

@ -12,7 +12,8 @@ import { ImportStatementUtils } from '../analyzer/importStatementUtils';
import { ParseTreeUtils } from '../analyzer/parseTreeUtils';
import { TextEditAction } from '../common/editAction';
import { convertOffsetToPosition } from '../common/positionUtils';
import { ImportFromNode, ParameterNode, ParseNode } from '../parser/parseNodes';
import { TextRange } from '../common/textRange';
import { ParseNode, ParseNodeType } from '../parser/parseNodes';
import { ParseResults } from '../parser/parser';
import { commandAddMissingOptionalToParam, commandOrderImports } from './commands';
import { ImportSorter } from './importSorter';
@ -40,7 +41,7 @@ function _addMissingOptionalToParam(parseResults: ParseResults,
let node: ParseNode | undefined = ParseTreeUtils.findNodeByOffset(parseResults.parseTree, offset);
while (node) {
if (node instanceof ParameterNode) {
if (node.nodeType === ParseNodeType.Parameter) {
break;
}
@ -56,7 +57,7 @@ function _addMissingOptionalToParam(parseResults: ParseResults,
const startPos = convertOffsetToPosition(
node.typeAnnotation.start, parseResults.lines);
const endPos = convertOffsetToPosition(
node.typeAnnotation.end, parseResults.lines);
TextRange.getEnd(node.typeAnnotation), parseResults.lines);
editActions.push({
range: { start: startPos, end: startPos },
@ -74,7 +75,7 @@ function _addMissingOptionalToParam(parseResults: ParseResults,
imp => imp.moduleName === 'typing');
// If there's an existing import statement, insert into it.
if (importStatement && importStatement.node instanceof ImportFromNode) {
if (importStatement && importStatement.node.nodeType === ParseNodeType.ImportFrom) {
const additionalEditActions = ImportStatementUtils.getTextEditsForAutoImportSymbolAddition(
'Optional', importStatement, parseResults);
editActions.push(...additionalEditActions);

View File

@ -15,6 +15,7 @@ import { ParseTreeWalker } from '../analyzer/parseTreeWalker';
import { Symbol } from '../analyzer/symbol';
import { DiagnosticTextPosition, DocumentTextRange } from '../common/diagnostic';
import { convertOffsetToPosition, convertPositionToOffset } from '../common/positionUtils';
import { TextRange } from '../common/textRange';
import { NameNode, ParseNode } from '../parser/parseNodes';
import { ParseResults } from '../parser/parser';
@ -75,7 +76,7 @@ class FindReferencesTreeWalker extends ParseTreeWalker {
path: this._filePath,
range: {
start: convertOffsetToPosition(node.start, this._parseResults.lines),
end: convertOffsetToPosition(node.end, this._parseResults.lines)
end: convertOffsetToPosition(TextRange.getEnd(node), this._parseResults.lines)
}
});
}

View File

@ -16,7 +16,8 @@ import { ClassType, FunctionType, ObjectType,
import { ClassMemberLookupFlags, TypeUtils } from '../analyzer/typeUtils';
import { DiagnosticTextPosition } from '../common/diagnostic';
import { convertPositionToOffset } from '../common/positionUtils';
import { CallExpressionNode, ParseNode } from '../parser/parseNodes';
import { TextRange } from '../common/textRange';
import { CallExpressionNode, ParseNode, ParseNodeType } from '../parser/parseNodes';
import { ParseResults } from '../parser/parser';
export interface ParamInfo {
@ -74,7 +75,7 @@ export class SignatureHelpProvider {
return undefined;
}
if (offset > callNode.end) {
if (offset > TextRange.getEnd(callNode)) {
return undefined;
}
@ -87,7 +88,7 @@ export class SignatureHelpProvider {
let activeParameter = 0;
const args = callNode.arguments;
for (let i = args.length - 1; i >= 0; i--) {
if (offset > args[i].valueExpression.end) {
if (offset > TextRange.getEnd(args[i].valueExpression)) {
activeParameter = i + 1;
break;
}
@ -193,7 +194,7 @@ export class SignatureHelpProvider {
let curNode: ParseNode | undefined = node;
while (curNode !== undefined) {
if (curNode instanceof CallExpressionNode) {
if (curNode.nodeType === ParseNodeType.Call) {
return curNode;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -405,7 +405,7 @@ export class Tokenizer {
private _addLineRange() {
const lineLength = this._cs.position - this._prevLineStart;
if (lineLength > 0) {
this._lineRanges.push(new TextRange(this._prevLineStart, lineLength));
this._lineRanges.push({ start: this._prevLineStart, length: lineLength });
}
this._prevLineStart = this._cs.position;

View File

@ -158,25 +158,29 @@ export enum StringTokenFlags {
Unterminated = 0x1000
}
export class Comment extends TextRange {
export class Comment {
readonly value: string;
readonly range: TextRange;
constructor(start: number, length: number, value: string) {
super(start, length);
this.range = { start, length };
this.value = value;
}
}
export class Token extends TextRange implements Token {
export class Token implements TextRange {
readonly type: TokenType;
// Comments prior to the token.
readonly start: number;
readonly length: number;
readonly comments?: Comment[];
constructor(type: TokenType, start: number, length: number,
comments: Comment[] | undefined) {
super(start, length);
this.start = start;
this.length = length;
this.type = type;
this.comments = comments;
}

View File

@ -7,19 +7,20 @@
import * as assert from 'assert';
import { ParseTreeWalker } from '../analyzer/parseTreeWalker';
import { AssignmentNode, ParseNode, ParseNodeArray, StringListNode } from '../parser/parseNodes';
import { TextRange } from '../common/textRange';
import { ParseNode, ParseNodeArray, ParseNodeType, StringListNode } from '../parser/parseNodes';
export class TestWalker extends ParseTreeWalker {
constructor() {
super();
}
visitNode(node: ParseNode): boolean {
const children = node.getChildren();
visitNode(node: ParseNode) {
const children = super.visitNode(node);
this._verifyParentChildLinks(node, children);
this._verifyChildRanges(node, children);
return super.visitNode(node);
return children;
}
// Make sure that all of the children point to their parent.
@ -44,13 +45,13 @@ export class TestWalker extends ParseTreeWalker {
// There are a few exceptions we need to deal with here. Comment
// annotations can occur outside of an assignment node's range.
if (node instanceof AssignmentNode) {
if (node.nodeType === ParseNodeType.Assignment) {
if (child === node.typeAnnotationComment) {
skipCheck = true;
}
}
if (node instanceof StringListNode) {
if (node.nodeType === ParseNodeType.StringList) {
if (child === node.typeAnnotation) {
skipCheck = true;
}
@ -58,10 +59,10 @@ export class TestWalker extends ParseTreeWalker {
if (!skipCheck) {
// Make sure the child is contained within the parent.
assert(child.start >= node.start && child.end <= node.end);
assert(child.start >= node.start && TextRange.getEnd(child) <= TextRange.getEnd(node));
if (prevNode) {
// Make sure the child is after the previous child.
assert(child.start >= prevNode.end);
assert(child.start >= TextRange.getEnd(prevNode));
}
prevNode = child;