mirror of
https://github.com/microsoft/pyright.git
synced 2024-08-17 11:50:22 +03:00
Switched parse nodes from classes to interfaces with an enumerated union type.
This commit is contained in:
parent
499f8bff30
commit
80d120c838
6
client/package-lock.json
generated
6
client/package-lock.json
generated
@ -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": {
|
||||
|
@ -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
6
package-lock.json
generated
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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": {
|
||||
|
6
server/package-lock.json
generated
6
server/package-lock.json
generated
@ -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": {
|
||||
|
@ -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"
|
||||
},
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
|
@ -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();
|
||||
|
@ -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!;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user