-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathConfusingOverloading.ql
More file actions
119 lines (107 loc) · 3.89 KB
/
ConfusingOverloading.ql
File metadata and controls
119 lines (107 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* @name Confusing overloading of methods
* @description Overloaded methods that have the same number of parameters, where each pair of
* corresponding parameter types is convertible by casting or autoboxing, may be
* confusing.
* @kind problem
* @problem.severity recommendation
* @precision high
* @id java/confusing-method-signature
* @tags maintainability
* readability
* naming
*/
import java
pragma[nomagic]
private predicate confusingPrimitiveBoxedTypes(Type t, Type u) {
t.(PrimitiveType).getBoxedType() = u or
u.(PrimitiveType).getBoxedType() = t
}
private predicate overloadedMethods(Method n, Method m) {
n.fromSource() and
exists(RefType rt, string name, int numParams |
candidateMethod(rt, m, name, numParams) and
candidateMethod(rt, n, name, numParams)
) and
n != m and
n.getSourceDeclaration().getSignature() < m.getSourceDeclaration().getSignature()
}
private predicate overloadedMethodsMostSpecific(Method n, Method m) {
overloadedMethods(n, m) and
not exists(Method nSup, Method mSup |
n.overridesOrInstantiates*(nSup) and m.overridesOrInstantiates*(mSup)
|
overloadedMethods(nSup, mSup) and
(n != nSup or m != mSup)
)
}
/**
* A whitelist of names that are commonly overloaded in odd ways and should
* not be reported by this query.
*/
private predicate whitelist(string name) { name = "visit" }
/**
* Method `m` has name `name`, number of parameters `numParams`
* and is declared in `t` or inherited from a supertype of `t`.
*/
pragma[nomagic]
private predicate candidateMethod(RefType t, Method m, string name, int numParam) {
exists(Method n | n.getSourceDeclaration() = m | t.inherits(n)) and
m.getName() = name and
m.getNumberOfParameters() = numParam and
m = m.getSourceDeclaration() and
not m.getAnAnnotation() instanceof DeprecatedAnnotation and
not whitelist(name)
}
pragma[inline]
private predicate potentiallyConfusingTypes(Type a, Type b) {
exists(RefType commonSubtype | hasSubtypeOrInstantiation*(a, commonSubtype) |
hasSubtypeOrInstantiation*(b, commonSubtype)
)
or
confusingPrimitiveBoxedTypes(a, b)
}
private predicate hasSubtypeOrInstantiation(RefType t, RefType sub) {
hasSubtype(t, sub) or
sub.getSourceDeclaration() = t
}
private predicate confusinglyOverloaded(Method m, Method n) {
overloadedMethodsMostSpecific(n, m) and
forall(int i, Parameter p, Parameter q | p = n.getParameter(i) and q = m.getParameter(i) |
potentiallyConfusingTypes(p.getType(), q.getType())
) and
// There is no possibility for confusion between two methods with identical behavior.
not exists(Method target | delegate*(m, target) and delegate*(n, target))
}
private predicate wrappedAccess(Expr e, MethodAccess ma) {
e = ma or
wrappedAccess(e.(CastingExpr).getExpr(), ma)
}
private predicate delegate(Method caller, Method callee) {
exists(MethodAccess ma | ma.getMethod() = callee |
exists(Stmt stmt | stmt = caller.getBody().(SingletonBlock).getStmt() |
wrappedAccess(stmt.(ExprStmt).getExpr(), ma) or
wrappedAccess(stmt.(ReturnStmt).getResult(), ma)
) and
forex(Parameter p, int i, Expr arg | p = caller.getParameter(i) and ma.getArgument(i) = arg |
// The parameter is propagated without modification.
arg = p.getAnAccess()
or
// The parameter is cast to a supertype.
arg.(CastingExpr).getExpr() = p.getAnAccess() and
arg.getType().(RefType).getASubtype() = p.getType()
)
)
}
from Method m, Method n, string messageQualifier
where
confusinglyOverloaded(m, n) and
(
if m.getDeclaringType() = n.getDeclaringType()
then messageQualifier = ""
else messageQualifier = m.getDeclaringType().getName() + "."
)
select n,
"Method " + n.getDeclaringType() + "." + n +
"(..) could be confused with overloaded method $@, since dispatch depends on static types.",
m.getSourceDeclaration(), messageQualifier + m.getName()