mirror of
https://github.com/microsoft/pyright.git
synced 2024-08-17 03:40:44 +03:00
Added new config switch "reportUnknownParameter" to control reporting of unknown input and return parameter types.
This commit is contained in:
parent
a442c60c95
commit
93595c1720
@ -151,6 +151,12 @@
|
||||
"title": "Controls reporting of invalid escape sequences used within string literals",
|
||||
"default": "none"
|
||||
},
|
||||
"reportUnknownParameter": {
|
||||
"$id": "#/properties/reportUnknownParameter",
|
||||
"$ref": "#/definitions/diagnostic",
|
||||
"title": "Controls reporting input and return parameters whose types are unknown",
|
||||
"default": "none"
|
||||
},
|
||||
"pythonVersion": {
|
||||
"$id": "#/properties/pythonVersion",
|
||||
"type": "string",
|
||||
|
@ -58,6 +58,8 @@ 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'.
|
||||
|
||||
|
||||
## Execution Environment Options
|
||||
Pyright allows multiple “execution environments” to be defined for different portions of your source tree. For example, a subtree may be designed to run with different import search paths or a different version of the python interpreter than the rest of the source base.
|
||||
|
@ -245,6 +245,7 @@ export abstract class SemanticAnalyzer extends ParseTreeWalker {
|
||||
let functionFlags = FunctionTypeFlags.None;
|
||||
if (node.name.nameToken.value === '__new__') {
|
||||
functionFlags |= FunctionTypeFlags.StaticMethod;
|
||||
functionFlags |= FunctionTypeFlags.ConstructorMethod;
|
||||
functionFlags &= ~FunctionTypeFlags.InstanceMethod;
|
||||
}
|
||||
|
||||
|
@ -298,7 +298,11 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
}
|
||||
|
||||
this.walk(param.typeAnnotation);
|
||||
} else if (index === 0 && (functionType.isInstanceMethod() || functionType.isClassMethod())) {
|
||||
} else if (index === 0 && (
|
||||
functionType.isInstanceMethod() ||
|
||||
functionType.isClassMethod() ||
|
||||
functionType.isConstructorMethod())) {
|
||||
|
||||
// Specify type of "self" or "cls" parameter for instance or class methods
|
||||
// if the type is not explicitly provided.
|
||||
if (containingClassType) {
|
||||
@ -314,7 +318,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
if (functionType.setParameterType(index, new ObjectType(specializedClassType))) {
|
||||
this._setAnalysisChanged();
|
||||
}
|
||||
} else if (functionType.isClassMethod()) {
|
||||
} else if (functionType.isClassMethod() || functionType.isConstructorMethod()) {
|
||||
// For class methods, the cls parameter is allowed to skip the
|
||||
// abstract class test because the caller is possibly passing
|
||||
// in a non-abstract subclass.
|
||||
@ -327,6 +331,13 @@ 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,
|
||||
`Type of '${ param.name.nameToken.value }' is unknown`,
|
||||
param.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -337,11 +348,26 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
||||
}
|
||||
|
||||
this.walk(node.returnTypeAnnotation);
|
||||
} else if (this._fileInfo.isStubFile) {
|
||||
// If a return type annotation is missing in a stub file, assume
|
||||
// it's an "unknown" type. In normal source files, we can infer the
|
||||
// type from the implementation.
|
||||
functionType.setDeclaredReturnType(UnknownType.create());
|
||||
} else {
|
||||
let inferredReturnType: Type = UnknownType.create();
|
||||
|
||||
if (this._fileInfo.isStubFile) {
|
||||
// If a return type annotation is missing in a stub file, assume
|
||||
// it's an "unknown" type. In normal source files, we can infer the
|
||||
// type from the implementation.
|
||||
functionType.setDeclaredReturnType(inferredReturnType);
|
||||
} else {
|
||||
inferredReturnType = functionType.getInferredReturnType().getType();
|
||||
}
|
||||
|
||||
if (inferredReturnType instanceof UnknownType) {
|
||||
this._addDiagnostic(this._fileInfo.configOptions.reportUnknownParameter,
|
||||
`Return type is unknown`, node.name);
|
||||
} else if (TypeUtils.containsUnknown(inferredReturnType)) {
|
||||
this._addDiagnostic(this._fileInfo.configOptions.reportUnknownParameter,
|
||||
`Return type '${ inferredReturnType.asString() }' is partially unknown`,
|
||||
node.name);
|
||||
}
|
||||
}
|
||||
|
||||
let functionScope = this._enterScope(node, () => {
|
||||
|
@ -1045,6 +1045,45 @@ export class TypeUtils {
|
||||
this._getMembersForClassRecursive(classType, symbolTable, includeInstanceVars);
|
||||
}
|
||||
|
||||
static containsUnknown(type: Type, recursionCount = 0): boolean {
|
||||
if (recursionCount > MaxTypeRecursion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type instanceof UnknownType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type instanceof UnionType) {
|
||||
for (const subtype of type.getTypes()) {
|
||||
if (this.containsUnknown(subtype, recursionCount + 1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type instanceof ObjectType) {
|
||||
return this.containsUnknown(type.getClassType(), recursionCount + 1);
|
||||
}
|
||||
|
||||
if (type instanceof ClassType) {
|
||||
const typeArgs = type.getTypeArguments();
|
||||
if (typeArgs) {
|
||||
for (const argType of typeArgs) {
|
||||
if (this.containsUnknown(argType, recursionCount + 1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static _getMembersForClassRecursive(classType: ClassType,
|
||||
symbolTable: SymbolTable, includeInstanceVars: boolean,
|
||||
recursionCount = 0) {
|
||||
|
@ -619,10 +619,11 @@ export interface FunctionParameter {
|
||||
export enum FunctionTypeFlags {
|
||||
None = 0,
|
||||
InstanceMethod = 1,
|
||||
ClassMethod = 2,
|
||||
StaticMethod = 4,
|
||||
AbstractMethod = 8,
|
||||
DisableDefaultChecks = 16
|
||||
ConstructorMethod = 2,
|
||||
ClassMethod = 4,
|
||||
StaticMethod = 8,
|
||||
AbstractMethod = 16,
|
||||
DisableDefaultChecks = 32
|
||||
}
|
||||
|
||||
interface FunctionDetails {
|
||||
@ -711,6 +712,10 @@ export class FunctionType extends Type {
|
||||
this._functionDetails.flags |= FunctionTypeFlags.InstanceMethod;
|
||||
}
|
||||
|
||||
isConstructorMethod(): boolean {
|
||||
return (this._functionDetails.flags & FunctionTypeFlags.ConstructorMethod) !== 0;
|
||||
}
|
||||
|
||||
isStaticMethod(): boolean {
|
||||
return (this._functionDetails.flags & FunctionTypeFlags.StaticMethod) !== 0;
|
||||
}
|
||||
|
@ -125,6 +125,9 @@ export class ConfigOptions {
|
||||
// Report usage of invalid escape sequences in string literals?
|
||||
reportInvalidStringEscapeSequence: DiagnosticLevel = 'warning';
|
||||
|
||||
// Report usage of unknown input or return parameters?
|
||||
reportUnknownParameter: DiagnosticLevel = 'none';
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Parsing and Import Resolution Settings
|
||||
|
||||
@ -285,6 +288,10 @@ 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 "venvPath".
|
||||
this.venvPath = undefined;
|
||||
if (configObj.venvPath !== undefined) {
|
||||
|
Loading…
Reference in New Issue
Block a user