Skip to content

Commit a9ab39d

Browse files
authored
Merge pull request github#18448 from github/tausbn/python-add-type-annotation-metrics-query
Python: Add metrics query for type annotations
2 parents 7e984ad + 4141b4f commit a9ab39d

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* @name Type metrics
3+
* @description Counts of various kinds of type annotations in Python code.
4+
* @kind table
5+
* @id py/type-metrics
6+
*/
7+
8+
import python
9+
10+
class BuiltinType extends Name {
11+
BuiltinType() { this.getId() in ["int", "float", "str", "bool", "bytes", "None"] }
12+
}
13+
14+
newtype TAnnotatable =
15+
TAnnotatedFunction(FunctionExpr f) { exists(f.getReturns()) } or
16+
TAnnotatedParameter(Parameter p) { exists(p.getAnnotation()) } or
17+
TAnnotatedAssignment(AnnAssign a) { exists(a.getAnnotation()) }
18+
19+
abstract class Annotatable extends TAnnotatable {
20+
string toString() { result = "Annotatable" }
21+
22+
abstract Expr getAnnotation();
23+
}
24+
25+
class AnnotatedFunction extends TAnnotatedFunction, Annotatable {
26+
FunctionExpr function;
27+
28+
AnnotatedFunction() { this = TAnnotatedFunction(function) }
29+
30+
override Expr getAnnotation() { result = function.getReturns() }
31+
}
32+
33+
class AnnotatedParameter extends TAnnotatedParameter, Annotatable {
34+
Parameter parameter;
35+
36+
AnnotatedParameter() { this = TAnnotatedParameter(parameter) }
37+
38+
override Expr getAnnotation() { result = parameter.getAnnotation() }
39+
}
40+
41+
class AnnotatedAssignment extends TAnnotatedAssignment, Annotatable {
42+
AnnAssign assignment;
43+
44+
AnnotatedAssignment() { this = TAnnotatedAssignment(assignment) }
45+
46+
override Expr getAnnotation() { result = assignment.getAnnotation() }
47+
}
48+
49+
/** Holds if `e` is a forward declaration of a type. */
50+
predicate is_forward_declaration(Expr e) { e instanceof StringLiteral }
51+
52+
/** Holds if `e` is a type that may be difficult to analyze. */
53+
predicate is_complex_type(Expr e) {
54+
e instanceof Subscript and not is_optional_type(e)
55+
or
56+
e instanceof Tuple
57+
or
58+
e instanceof List
59+
}
60+
61+
/** Holds if `e` is a type of the form `Optional[...]`. */
62+
predicate is_optional_type(Subscript e) { e.getObject().(Name).getId() = "Optional" }
63+
64+
/** Holds if `e` is a simple type, that is either an identifier (excluding built-in types) or an attribute of a simple type. */
65+
predicate is_simple_type(Expr e) {
66+
e instanceof Name and not e instanceof BuiltinType
67+
or
68+
is_simple_type(e.(Attribute).getObject())
69+
}
70+
71+
/** Holds if `e` is a built-in type. */
72+
predicate is_builtin_type(Expr e) { e instanceof BuiltinType }
73+
74+
predicate type_count(
75+
string kind, int total, int built_in_count, int forward_declaration_count, int simple_type_count,
76+
int complex_type_count, int optional_type_count
77+
) {
78+
kind = "Parameter annotation" and
79+
total = count(AnnotatedParameter p) and
80+
built_in_count = count(AnnotatedParameter p | is_builtin_type(p.getAnnotation())) and
81+
forward_declaration_count =
82+
count(AnnotatedParameter p | is_forward_declaration(p.getAnnotation())) and
83+
simple_type_count = count(AnnotatedParameter p | is_simple_type(p.getAnnotation())) and
84+
complex_type_count = count(AnnotatedParameter p | is_complex_type(p.getAnnotation())) and
85+
optional_type_count = count(AnnotatedParameter p | is_optional_type(p.getAnnotation()))
86+
or
87+
kind = "Return type annotation" and
88+
total = count(AnnotatedFunction f) and
89+
built_in_count = count(AnnotatedFunction f | is_builtin_type(f.getAnnotation())) and
90+
forward_declaration_count = count(AnnotatedFunction f | is_forward_declaration(f.getAnnotation())) and
91+
simple_type_count = count(AnnotatedFunction f | is_simple_type(f.getAnnotation())) and
92+
complex_type_count = count(AnnotatedFunction f | is_complex_type(f.getAnnotation())) and
93+
optional_type_count = count(AnnotatedFunction f | is_optional_type(f.getAnnotation()))
94+
or
95+
kind = "Annotated assignment" and
96+
total = count(AnnotatedAssignment a) and
97+
built_in_count = count(AnnotatedAssignment a | is_builtin_type(a.getAnnotation())) and
98+
forward_declaration_count =
99+
count(AnnotatedAssignment a | is_forward_declaration(a.getAnnotation())) and
100+
simple_type_count = count(AnnotatedAssignment a | is_simple_type(a.getAnnotation())) and
101+
complex_type_count = count(AnnotatedAssignment a | is_complex_type(a.getAnnotation())) and
102+
optional_type_count = count(AnnotatedAssignment a | is_optional_type(a.getAnnotation()))
103+
}
104+
105+
from
106+
string message, int total, int built_in, int forward_decl, int simple, int complex, int optional
107+
where type_count(message, total, built_in, forward_decl, simple, complex, optional)
108+
select message, total, built_in, forward_decl, simple, complex, optional

0 commit comments

Comments
 (0)