mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-26 19:01:08 +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",
|
"title": "Controls reporting of invalid escape sequences used within string literals",
|
||||||
"default": "none"
|
"default": "none"
|
||||||
},
|
},
|
||||||
|
"reportUnknownParameter": {
|
||||||
|
"$id": "#/properties/reportUnknownParameter",
|
||||||
|
"$ref": "#/definitions/diagnostic",
|
||||||
|
"title": "Controls reporting input and return parameters whose types are unknown",
|
||||||
|
"default": "none"
|
||||||
|
},
|
||||||
"pythonVersion": {
|
"pythonVersion": {
|
||||||
"$id": "#/properties/pythonVersion",
|
"$id": "#/properties/pythonVersion",
|
||||||
"type": "string",
|
"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'.
|
**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
|
## 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.
|
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;
|
let functionFlags = FunctionTypeFlags.None;
|
||||||
if (node.name.nameToken.value === '__new__') {
|
if (node.name.nameToken.value === '__new__') {
|
||||||
functionFlags |= FunctionTypeFlags.StaticMethod;
|
functionFlags |= FunctionTypeFlags.StaticMethod;
|
||||||
|
functionFlags |= FunctionTypeFlags.ConstructorMethod;
|
||||||
functionFlags &= ~FunctionTypeFlags.InstanceMethod;
|
functionFlags &= ~FunctionTypeFlags.InstanceMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +298,11 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.walk(param.typeAnnotation);
|
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
|
// Specify type of "self" or "cls" parameter for instance or class methods
|
||||||
// if the type is not explicitly provided.
|
// if the type is not explicitly provided.
|
||||||
if (containingClassType) {
|
if (containingClassType) {
|
||||||
@ -314,7 +318,7 @@ export class TypeAnalyzer extends ParseTreeWalker {
|
|||||||
if (functionType.setParameterType(index, new ObjectType(specializedClassType))) {
|
if (functionType.setParameterType(index, new ObjectType(specializedClassType))) {
|
||||||
this._setAnalysisChanged();
|
this._setAnalysisChanged();
|
||||||
}
|
}
|
||||||
} else if (functionType.isClassMethod()) {
|
} else if (functionType.isClassMethod() || functionType.isConstructorMethod()) {
|
||||||
// For class methods, the cls parameter is allowed to skip the
|
// For class methods, the cls parameter is allowed to skip the
|
||||||
// abstract class test because the caller is possibly passing
|
// abstract class test because the caller is possibly passing
|
||||||
// in a non-abstract subclass.
|
// 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);
|
this.walk(node.returnTypeAnnotation);
|
||||||
} else if (this._fileInfo.isStubFile) {
|
} else {
|
||||||
// If a return type annotation is missing in a stub file, assume
|
let inferredReturnType: Type = UnknownType.create();
|
||||||
// it's an "unknown" type. In normal source files, we can infer the
|
|
||||||
// type from the implementation.
|
if (this._fileInfo.isStubFile) {
|
||||||
functionType.setDeclaredReturnType(UnknownType.create());
|
// 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, () => {
|
let functionScope = this._enterScope(node, () => {
|
||||||
|
@ -1045,6 +1045,45 @@ export class TypeUtils {
|
|||||||
this._getMembersForClassRecursive(classType, symbolTable, includeInstanceVars);
|
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,
|
private static _getMembersForClassRecursive(classType: ClassType,
|
||||||
symbolTable: SymbolTable, includeInstanceVars: boolean,
|
symbolTable: SymbolTable, includeInstanceVars: boolean,
|
||||||
recursionCount = 0) {
|
recursionCount = 0) {
|
||||||
|
@ -619,10 +619,11 @@ export interface FunctionParameter {
|
|||||||
export enum FunctionTypeFlags {
|
export enum FunctionTypeFlags {
|
||||||
None = 0,
|
None = 0,
|
||||||
InstanceMethod = 1,
|
InstanceMethod = 1,
|
||||||
ClassMethod = 2,
|
ConstructorMethod = 2,
|
||||||
StaticMethod = 4,
|
ClassMethod = 4,
|
||||||
AbstractMethod = 8,
|
StaticMethod = 8,
|
||||||
DisableDefaultChecks = 16
|
AbstractMethod = 16,
|
||||||
|
DisableDefaultChecks = 32
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FunctionDetails {
|
interface FunctionDetails {
|
||||||
@ -711,6 +712,10 @@ export class FunctionType extends Type {
|
|||||||
this._functionDetails.flags |= FunctionTypeFlags.InstanceMethod;
|
this._functionDetails.flags |= FunctionTypeFlags.InstanceMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isConstructorMethod(): boolean {
|
||||||
|
return (this._functionDetails.flags & FunctionTypeFlags.ConstructorMethod) !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
isStaticMethod(): boolean {
|
isStaticMethod(): boolean {
|
||||||
return (this._functionDetails.flags & FunctionTypeFlags.StaticMethod) !== 0;
|
return (this._functionDetails.flags & FunctionTypeFlags.StaticMethod) !== 0;
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,9 @@ export class ConfigOptions {
|
|||||||
// Report usage of invalid escape sequences in string literals?
|
// Report usage of invalid escape sequences in string literals?
|
||||||
reportInvalidStringEscapeSequence: DiagnosticLevel = 'warning';
|
reportInvalidStringEscapeSequence: DiagnosticLevel = 'warning';
|
||||||
|
|
||||||
|
// Report usage of unknown input or return parameters?
|
||||||
|
reportUnknownParameter: DiagnosticLevel = 'none';
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Parsing and Import Resolution Settings
|
// Parsing and Import Resolution Settings
|
||||||
|
|
||||||
@ -285,6 +288,10 @@ export class ConfigOptions {
|
|||||||
this.reportInvalidStringEscapeSequence = this._convertDiagnosticLevel(
|
this.reportInvalidStringEscapeSequence = this._convertDiagnosticLevel(
|
||||||
configObj.reportInvalidStringEscapeSequence, 'reportInvalidStringEscapeSequence', 'warning');
|
configObj.reportInvalidStringEscapeSequence, 'reportInvalidStringEscapeSequence', 'warning');
|
||||||
|
|
||||||
|
// Read the "reportUnknownParameter" entry.
|
||||||
|
this.reportUnknownParameter = this._convertDiagnosticLevel(
|
||||||
|
configObj.reportUnknownParameter, 'reportUnknownParameter', 'none');
|
||||||
|
|
||||||
// Read the "venvPath".
|
// Read the "venvPath".
|
||||||
this.venvPath = undefined;
|
this.venvPath = undefined;
|
||||||
if (configObj.venvPath !== undefined) {
|
if (configObj.venvPath !== undefined) {
|
||||||
|
Loading…
Reference in New Issue
Block a user