mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
Python: Add support for forward declarations in unused var query
Fixes the false positive reported in https://github.com/github/codeql/issues/18910 Adds a new `Annotation` class (subclass of `Expr`) which encompasses all possible kinds of annotations in Python. Using this, we look for string literals which are part of an annotation, and which have the same content as the name of a (potentially) unused global variable, and in that case we do not produce an alert. In future, we may want to support inspecting such string literals more deeply (e.g. to support stuff like "list[unused_var]"), but I think for now this level of support is sufficient.
This commit is contained in:
@@ -746,6 +746,24 @@ class Guard extends Guard_ {
|
||||
override Expr getASubExpression() { result = this.getTest() }
|
||||
}
|
||||
|
||||
/** An annotation, such as the `int` part of `x: int` */
|
||||
class Annotation extends Expr {
|
||||
Annotation() {
|
||||
this = any(AnnAssign a).getAnnotation()
|
||||
or
|
||||
exists(Arguments args | args = any(FunctionExpr f).getArgs() |
|
||||
this in [
|
||||
args.getAnAnnotation(),
|
||||
args.getAKwAnnotation(),
|
||||
args.getKwargannotation(),
|
||||
args.getVarargannotation()
|
||||
]
|
||||
)
|
||||
or
|
||||
this = any(FunctionExpr f).getReturns()
|
||||
}
|
||||
}
|
||||
|
||||
/* Expression Contexts */
|
||||
/** A context in which an expression used */
|
||||
class ExprContext extends ExprContext_ { }
|
||||
|
||||
@@ -34,6 +34,14 @@ predicate complex_all(Module m) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate used_in_forward_declaration(Name used, Module mod) {
|
||||
exists(StringLiteral s, Annotation annotation |
|
||||
s.getS() = used.getId() and
|
||||
s.getEnclosingModule() = mod and
|
||||
annotation.getASubExpression*() = s
|
||||
)
|
||||
}
|
||||
|
||||
predicate unused_global(Name unused, GlobalVariable v) {
|
||||
not exists(ImportingStmt is | is.contains(unused)) and
|
||||
forex(DefinitionNode defn | defn.getNode() = unused |
|
||||
@@ -55,7 +63,8 @@ predicate unused_global(Name unused, GlobalVariable v) {
|
||||
unused.defines(v) and
|
||||
not name_acceptable_for_unused_variable(v) and
|
||||
not complex_all(unused.getEnclosingModule())
|
||||
)
|
||||
) and
|
||||
not used_in_forward_declaration(unused, unused.getEnclosingModule())
|
||||
}
|
||||
|
||||
from Name unused, GlobalVariable v
|
||||
|
||||
@@ -4,6 +4,3 @@
|
||||
| variables_test.py:86:3:86:3 | b | The global variable 'b' is not used. |
|
||||
| variables_test.py:86:5:86:5 | c | The global variable 'c' is not used. |
|
||||
| variables_test.py:100:1:100:8 | glob_var | The global variable 'glob_var' is not used. |
|
||||
| variables_test.py:147:5:147:26 | ForwardParamAnnotation | The global variable 'ForwardParamAnnotation' is not used. |
|
||||
| variables_test.py:148:5:148:27 | ForwardReturnAnnotation | The global variable 'ForwardReturnAnnotation' is not used. |
|
||||
| variables_test.py:149:5:149:31 | ForwardAssignmentAnnotation | The global variable 'ForwardAssignmentAnnotation' is not used. |
|
||||
|
||||
Reference in New Issue
Block a user