Renamed reportUnknownParameter to reportUnknownParameterType. Added reportUnknownVariableType and reportUnknownMemberType.

This commit is contained in:
Eric Traut 2019-04-28 22:20:29 -07:00
parent f8e9dacccb
commit 71ffa702ed
5 changed files with 100 additions and 11 deletions

View File

@ -151,12 +151,24 @@
"title": "Controls reporting of invalid escape sequences used within string literals",
"default": "none"
},
"reportUnknownParameter": {
"$id": "#/properties/reportUnknownParameter",
"reportUnknownParameterType": {
"$id": "#/properties/reportUnknownParameterType",
"$ref": "#/definitions/diagnostic",
"title": "Controls reporting input and return parameters whose types are unknown",
"default": "none"
},
"reportUnknownVariableType": {
"$id": "#/properties/reportUnknownVariableType",
"$ref": "#/definitions/diagnostic",
"title": "Controls reporting local variables whose types are unknown",
"default": "none"
},
"reportUnknownMemberType": {
"$id": "#/properties/reportUnknownMemberType",
"$ref": "#/definitions/diagnostic",
"title": "Controls reporting class and instance variables whose types are unknown",
"default": "none"
},
"pythonVersion": {
"$id": "#/properties/pythonVersion",
"type": "string",

View File

@ -58,7 +58,11 @@ The following settings control pyright's diagnostic output (warnings or errors).
**reportInvalidStringEscapeSequence** [boolean or string, optional]: Generate or suppress diagnostics for invalid escape sequences used within string literals. The Python specification indicates that such sequences will generate a syntax error in future versions. The default value for this setting is 'warning'.
**reportUnknownParameter** [boolean or string, optional]: Generate or suppress diagnostics for input or return parameters that have an unknown type. The default value for this setting is 'none'.
**reportUnknownParameterType** [boolean or string, optional]: Generate or suppress diagnostics for input or return parameters that have an unknown type. The default value for this setting is 'none'.
**reportUnknownVariableType** [boolean or string, optional]: Generate or suppress diagnostics for variables that have an unknown type. The default value for this setting is 'none'.
**reportUnknownMemberType** [boolean or string, optional]: Generate or suppress diagnostics for class or instance variables that have an unknown type. The default value for this setting is 'none'.
## Execution Environment Options

View File

@ -110,6 +110,10 @@ export class TypeAnalyzer extends ParseTreeWalker {
this.walk(this._moduleNode);
// Validate that global variables have known types.
this._reportUnknownSymbolsForCurrentScope(
this._fileInfo.configOptions.reportUnknownVariableType);
// If we've already analyzed the file the max number of times,
// just give up and admit defeat. This should happen only in
// the case of analyzer bugs.
@ -238,6 +242,9 @@ export class TypeAnalyzer extends ParseTreeWalker {
this.walkMultiple(node.decorators);
this.walkMultiple(node.arguments);
this._reportUnknownMembersForClass(classType);
return false;
}
@ -332,7 +339,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
} else {
// There is no annotation, and we can't infer the type.
if (param.name && param.category === ParameterCategory.Simple) {
this._addDiagnostic(this._fileInfo.configOptions.reportUnknownParameter,
this._addDiagnostic(this._fileInfo.configOptions.reportUnknownParameterType,
`Type of '${ param.name.nameToken.value }' is unknown`,
param.name);
}
@ -361,16 +368,16 @@ export class TypeAnalyzer extends ParseTreeWalker {
// Include Any in this check. If "Any" really is desired, it should
// be made explicit through a type annotation.
if (inferredReturnType.isAny()) {
this._addDiagnostic(this._fileInfo.configOptions.reportUnknownParameter,
this._addDiagnostic(this._fileInfo.configOptions.reportUnknownParameterType,
`Inferred return type is unknown`, node.name);
} else if (TypeUtils.containsUnknown(inferredReturnType)) {
this._addDiagnostic(this._fileInfo.configOptions.reportUnknownParameter,
this._addDiagnostic(this._fileInfo.configOptions.reportUnknownParameterType,
`Return type '${ inferredReturnType.asString() }' is partially unknown`,
node.name);
}
}
let functionScope = this._enterScope(node, () => {
const functionScope = this._enterScope(node, () => {
const parameters = functionType.getParameters();
assert(parameters.length === node.parameters.length);
@ -446,6 +453,9 @@ export class TypeAnalyzer extends ParseTreeWalker {
}
this.walk(node.suite);
this._reportUnknownSymbolsForCurrentScope(
this._fileInfo.configOptions.reportUnknownVariableType);
});
// Validate that the function returns the declared type.
@ -508,6 +518,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
this._updateExpressionTypeForNode(node.name, functionType);
this.walkMultiple(node.decorators);
return false;
}
@ -1387,6 +1398,52 @@ export class TypeAnalyzer extends ParseTreeWalker {
return false;
}
private _reportUnknownMembersForClass(classType: ClassType) {
// Don't bother if the feature is disabled.
const diagLevel = this._fileInfo.configOptions.reportUnknownMemberType;
// Report issues for both class and instance members.
this._reportUnknownSymbols(diagLevel, classType.getClassFields());
this._reportUnknownSymbols(diagLevel, classType.getInstanceFields());
}
// Reports any local variables within the current scope that have
// unknown or partially-unknown types.
private _reportUnknownSymbolsForCurrentScope(diagLevel: DiagnosticLevel) {
this._reportUnknownSymbols(diagLevel, this._currentScope.getSymbolTable());
}
private _reportUnknownSymbols(diagLevel: DiagnosticLevel, symbolTable: SymbolTable) {
// Don't bother if the feature is disabled.
if (diagLevel === 'none' && !this._fileInfo.useStrictMode) {
return;
}
symbolTable.forEach((symbol, name) => {
if (symbol.declarations && symbol.declarations.length > 0) {
const primaryDecl = symbol.declarations[0];
// Don't generate errors for symbols that are declared
// imported from other files. Also, don't report errors
// for parameters, since those are covered under a separate
// configuration switch.
if (primaryDecl.path === this._fileInfo.filePath &&
primaryDecl.category !== SymbolCategory.Parameter) {
const effectiveType = TypeUtils.getEffectiveTypeOfSymbol(symbol);
if (effectiveType instanceof UnknownType) {
this._addDiagnostic(diagLevel,
`Inferred type of '${ name }' is unknown`, primaryDecl.node);
} else if (TypeUtils.containsUnknown(effectiveType)) {
this._addDiagnostic(diagLevel,
`Inferred type of '${ name }', '${ effectiveType.asString() }', ` +
`is partially unknown`, primaryDecl.node);
}
}
}
});
}
// Assigns a declared type (as opposed to an inferred type) to an expression
// (e.g. a local variable, class variable, instance variable, etc.).
private _declareTypeForExpression(target: ExpressionNode, declaredType: Type,

View File

@ -1054,6 +1054,7 @@ export class TypeUtils {
return true;
}
// See if a union contains an unknown type.
if (type instanceof UnionType) {
for (const subtype of type.getTypes()) {
if (this.containsUnknown(subtype, recursionCount + 1)) {
@ -1064,6 +1065,7 @@ export class TypeUtils {
return false;
}
// See if an object or class has an unknown type argument.
if (type instanceof ObjectType) {
return this.containsUnknown(type.getClassType(), recursionCount + 1);
}

View File

@ -126,7 +126,13 @@ export class ConfigOptions {
reportInvalidStringEscapeSequence: DiagnosticLevel = 'warning';
// Report usage of unknown input or return parameters?
reportUnknownParameter: DiagnosticLevel = 'none';
reportUnknownParameterType: DiagnosticLevel = 'none';
// Report usage of unknown input or return parameters?
reportUnknownVariableType: DiagnosticLevel = 'none';
// Report usage of unknown input or return parameters?
reportUnknownMemberType: DiagnosticLevel = 'none';
//---------------------------------------------------------------
// Parsing and Import Resolution Settings
@ -288,9 +294,17 @@ export class ConfigOptions {
this.reportInvalidStringEscapeSequence = this._convertDiagnosticLevel(
configObj.reportInvalidStringEscapeSequence, 'reportInvalidStringEscapeSequence', 'warning');
// Read the "reportUnknownParameter" entry.
this.reportUnknownParameter = this._convertDiagnosticLevel(
configObj.reportUnknownParameter, 'reportUnknownParameter', 'none');
// Read the "reportUnknownParameterType" entry.
this.reportUnknownParameterType = this._convertDiagnosticLevel(
configObj.reportUnknownParameterType, 'reportUnknownParameterType', 'none');
// Read the "reportUnknownVariableType" entry.
this.reportUnknownVariableType = this._convertDiagnosticLevel(
configObj.reportUnknownVariableType, 'reportUnknownVariableType', 'none');
// Read the "reportUnknownMemberType" entry.
this.reportUnknownMemberType = this._convertDiagnosticLevel(
configObj.reportUnknownMemberType, 'reportUnknownMemberType', 'none');
// Read the "venvPath".
this.venvPath = undefined;