mirror of
https://github.com/microsoft/pyright.git
synced 2024-08-17 03:40:44 +03:00
Implemented new diagnostic rule reportUnusedCallResult that checks whether a call expression's results are consumed. If the results are None or Any, no diagnostic is produced.
This commit is contained in:
parent
aca23b2ae6
commit
cf1a5790d2
@ -134,6 +134,8 @@ The following settings control pyright’s diagnostic output (warnings or errors
|
||||
|
||||
**reportUnsupportedDunderAll** [boolean or string, optional]: Generate or suppress diagnostics for statements that define or manipulate `__all__` in a way that is not allowed by a static type checker, thus rendering the contents of `__all__` to be unknown or incorrect. The default value for this setting is 'warning'.
|
||||
|
||||
**reportUnusedCallResult** [boolean or string, optional]: Generate or suppress diagnostics for call statements whose return value is not used in any way and is not None. 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.
|
||||
|
@ -421,6 +421,28 @@ export class Checker extends ParseTreeWalker {
|
||||
);
|
||||
}
|
||||
|
||||
if (this._fileInfo.diagnosticRuleSet.reportUnusedCallResult !== 'none') {
|
||||
if (node.parent?.nodeType === ParseNodeType.StatementList) {
|
||||
const returnType = this._evaluator.getType(node);
|
||||
if (
|
||||
returnType &&
|
||||
!isNone(returnType) &&
|
||||
!isNoReturnType(returnType) &&
|
||||
!isNever(returnType) &&
|
||||
!isAnyOrUnknown(returnType)
|
||||
) {
|
||||
this._evaluator.addDiagnostic(
|
||||
this._fileInfo.diagnosticRuleSet.reportUnusedCallResult,
|
||||
DiagnosticRule.reportUnusedCallResult,
|
||||
Localizer.Diagnostic.unusedCallResult().format({
|
||||
type: this._evaluator.printType(returnType, /* expandTypeAlias */ false),
|
||||
}),
|
||||
node
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -229,6 +229,10 @@ export interface DiagnosticRuleSet {
|
||||
// Report operations on __all__ symbol that are not supported
|
||||
// by a static type checker.
|
||||
reportUnsupportedDunderAll: DiagnosticLevel;
|
||||
|
||||
// Report cases where a call expression's return result is not
|
||||
// None and is not used in any way.
|
||||
reportUnusedCallResult: DiagnosticLevel;
|
||||
}
|
||||
|
||||
export function cloneDiagnosticRuleSet(diagSettings: DiagnosticRuleSet): DiagnosticRuleSet {
|
||||
@ -295,6 +299,7 @@ export function getDiagLevelDiagnosticRules() {
|
||||
DiagnosticRule.reportUnboundVariable,
|
||||
DiagnosticRule.reportInvalidStubStatement,
|
||||
DiagnosticRule.reportUnsupportedDunderAll,
|
||||
DiagnosticRule.reportUnusedCallResult,
|
||||
];
|
||||
}
|
||||
|
||||
@ -358,6 +363,7 @@ export function getOffDiagnosticRuleSet(): DiagnosticRuleSet {
|
||||
reportUndefinedVariable: 'warning',
|
||||
reportInvalidStubStatement: 'none',
|
||||
reportUnsupportedDunderAll: 'none',
|
||||
reportUnusedCallResult: 'none',
|
||||
};
|
||||
|
||||
return diagSettings;
|
||||
@ -417,6 +423,7 @@ export function getBasicDiagnosticRuleSet(): DiagnosticRuleSet {
|
||||
reportUndefinedVariable: 'error',
|
||||
reportInvalidStubStatement: 'none',
|
||||
reportUnsupportedDunderAll: 'warning',
|
||||
reportUnusedCallResult: 'none',
|
||||
};
|
||||
|
||||
return diagSettings;
|
||||
@ -476,6 +483,7 @@ export function getStrictDiagnosticRuleSet(): DiagnosticRuleSet {
|
||||
reportUndefinedVariable: 'error',
|
||||
reportInvalidStubStatement: 'error',
|
||||
reportUnsupportedDunderAll: 'error',
|
||||
reportUnusedCallResult: 'none',
|
||||
};
|
||||
|
||||
return diagSettings;
|
||||
@ -1111,6 +1119,13 @@ export class ConfigOptions {
|
||||
DiagnosticRule.reportUnsupportedDunderAll,
|
||||
defaultSettings.reportUnsupportedDunderAll
|
||||
),
|
||||
|
||||
// Read the "reportUnusedCallResult" entry.
|
||||
reportUnusedCallResult: this._convertDiagnosticLevel(
|
||||
configObj.reportUnusedCallResult,
|
||||
DiagnosticRule.reportUnusedCallResult,
|
||||
defaultSettings.reportUnusedCallResult
|
||||
),
|
||||
};
|
||||
|
||||
// Read the "venvPath".
|
||||
|
@ -60,4 +60,5 @@ export enum DiagnosticRule {
|
||||
reportUnboundVariable = 'reportUnboundVariable',
|
||||
reportInvalidStubStatement = 'reportInvalidStubStatement',
|
||||
reportUnsupportedDunderAll = 'reportUnsupportedDunderAll',
|
||||
reportUnusedCallResult = 'reportUnusedCallResult',
|
||||
}
|
||||
|
@ -657,6 +657,10 @@ export namespace Localizer {
|
||||
export const unreachableCode = () => getRawString('Diagnostic.unreachableCode');
|
||||
export const unsupportedDunderAllAssignment = () => getRawString('Diagnostic.unsupportedDunderAllAssignment');
|
||||
export const unsupportedDunderAllOperation = () => getRawString('Diagnostic.unsupportedDunderAllOperation');
|
||||
export const unusedCallResult = () =>
|
||||
new ParameterizedString<{ type: string }>(
|
||||
getRawString('Diagnostic.unusedCallResult')
|
||||
);
|
||||
export const varAnnotationIllegal = () => getRawString('Diagnostic.varAnnotationIllegal');
|
||||
export const walrusIllegal = () => getRawString('Diagnostic.walrusIllegal');
|
||||
export const walrusNotAllowed = () => getRawString('Diagnostic.walrusNotAllowed');
|
||||
|
@ -328,6 +328,7 @@
|
||||
"unreachableCode": "Code is unreachable",
|
||||
"unsupportedDunderAllAssignment": "Expression assigned to \"__all__\" is not supported, so exported symbol list may be incorrect; use list or tuple of string literal values in assignment",
|
||||
"unsupportedDunderAllOperation": "Operation on \"__all__\" is not supported, so exported symbol list may not be incorrect",
|
||||
"unusedCallResult": "Result of call expression is of type \"{type}\" and is not used; assign to variable \"_\" if this is intentional",
|
||||
"varAnnotationIllegal": "Type annotations for variables requires Python 3.6 or newer; use type comment for compatibility with previous versions",
|
||||
"walrusIllegal": "Operator \":=\" requires Python 3.8 or newer",
|
||||
"walrusNotAllowed": "Operator \":=\" not allowed in this context",
|
||||
|
@ -0,0 +1,54 @@
|
||||
# This sample tests the reportUnusedCallResult diagnostic rule.
|
||||
|
||||
from typing import Any, Iterable, List, Union
|
||||
|
||||
|
||||
def func1():
|
||||
pass
|
||||
|
||||
|
||||
def func2():
|
||||
raise RuntimeError()
|
||||
|
||||
|
||||
def func3() -> Any:
|
||||
pass
|
||||
|
||||
|
||||
def func4():
|
||||
return 3
|
||||
|
||||
|
||||
def func5(a: int) -> Union[int, List[int]]:
|
||||
if a < 0:
|
||||
return 5
|
||||
return [3]
|
||||
|
||||
|
||||
def func6() -> Iterable[int]:
|
||||
return []
|
||||
|
||||
|
||||
func1()
|
||||
|
||||
func2()
|
||||
|
||||
func3()
|
||||
|
||||
# This should generate a diagnostic if reportUnusedCallResult is enabled.
|
||||
func4()
|
||||
|
||||
# This should generate a diagnostic if reportUnusedCallResult is enabled.
|
||||
func5(3)
|
||||
|
||||
# This should generate a diagnostic if reportUnusedCallResult is enabled.
|
||||
func6()
|
||||
|
||||
_, _ = func5(3), func6()
|
||||
|
||||
_ = func5(3)
|
||||
|
||||
_ = func5(func4())
|
||||
|
||||
for _ in func6():
|
||||
pass
|
@ -1211,3 +1211,16 @@ test('ClassGetItem1', () => {
|
||||
|
||||
TestUtils.validateResults(analysisResults, 0, 1);
|
||||
});
|
||||
|
||||
test('UnusedCallResult1', () => {
|
||||
const configOptions = new ConfigOptions('.');
|
||||
|
||||
// By default, this is disabled.
|
||||
let analysisResults = TestUtils.typeAnalyzeSampleFiles(['unusedCallResult1.py'], configOptions);
|
||||
TestUtils.validateResults(analysisResults, 0);
|
||||
|
||||
// Enable it as an error.
|
||||
configOptions.diagnosticRuleSet.reportUnusedCallResult = 'error';
|
||||
analysisResults = TestUtils.typeAnalyzeSampleFiles(['unusedCallResult1.py'], configOptions);
|
||||
TestUtils.validateResults(analysisResults, 3);
|
||||
});
|
||||
|
@ -587,6 +587,17 @@
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"reportUnusedCallResult": {
|
||||
"type": "string",
|
||||
"description": "Diagnostics for call expressions whose results are not consumed and are not None.",
|
||||
"default": "none",
|
||||
"enum": [
|
||||
"none",
|
||||
"information",
|
||||
"warning",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"reportUnsupportedDunderAll": {
|
||||
"type": "string",
|
||||
"description": "Diagnostics for unsupported operations performed on __all__.",
|
||||
|
@ -387,6 +387,12 @@
|
||||
"title": "Controls reporting of unsupported operations performed on __all__",
|
||||
"default": "warning"
|
||||
},
|
||||
"reportUnusedCallResult": {
|
||||
"$id": "#/properties/reportUnusedCallResult",
|
||||
"$ref": "#/definitions/diagnostic",
|
||||
"title": "Controls reporting of call expressions whose results are not consumed",
|
||||
"default": "none"
|
||||
},
|
||||
"pythonVersion": {
|
||||
"$id": "#/properties/pythonVersion",
|
||||
"type": "string",
|
||||
|
Loading…
Reference in New Issue
Block a user