-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathUselessUpcast.ql
More file actions
132 lines (120 loc) · 3.98 KB
/
UselessUpcast.ql
File metadata and controls
132 lines (120 loc) · 3.98 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
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
* @name Useless upcast
* @description Casting an expression is normally not needed when there exists an implicit conversion.
* @kind problem
* @problem.severity warning
* @precision medium
* @id cs/useless-upcast
* @tags maintainability
* language-features
* external/cwe/cwe-561
*/
import csharp
/** A callable that is not an extension method. */
private class NonExtensionMethod extends Callable {
NonExtensionMethod() {
not this instanceof ExtensionMethod
}
}
/** Holds if non-extension callable `c` is a member of type `t` with name `name`. */
pragma [noinline]
private predicate hasCallable(ValueOrRefType t, NonExtensionMethod c, string name) {
t.hasMember(c) and
name = c.getName()
}
/** Holds if extension method `m` is a method on `t` with name `name`. */
pragma [noinline]
private predicate hasExtensionMethod(ValueOrRefType t, ExtensionMethod m, string name) {
t.isImplicitlyConvertibleTo(m.getExtendedType()) and
name = m.getName()
}
/** An explicit upcast. */
class ExplicitUpcast extends ExplicitCast {
ValueOrRefType src;
ValueOrRefType dest;
ExplicitUpcast() {
src = this.getSourceType() and
dest = this.getTargetType() and
(src instanceof RefType or src instanceof Struct) and
src.isImplicitlyConvertibleTo(dest) and
src != dest // Handled by `cs/useless-cast-to-self`
}
/** Holds if this upcast is the argument of a call to `target`. */
private predicate isArgument(Call c, Callable target) {
exists(Parameter p |
this = p.getAnAssignedArgument() and
p.getType() = this.getType() and
c.getAnArgument() = this and
target = c.getTarget()
)
}
pragma [noinline]
private predicate isDisambiguatingNonExtensionMethod0(NonExtensionMethod target, ValueOrRefType t) {
exists(Call c |
this.isArgument(c, target) |
t = c.(QualifiableExpr).getQualifier().getType()
or
not exists(c.(QualifiableExpr).getQualifier()) and
t = target.getDeclaringType()
)
}
/**
* Holds if this upcast may be used to affect call resolution in a non-extension
* method call.
*/
private predicate isDisambiguatingNonExtensionMethodCall() {
exists(NonExtensionMethod target, NonExtensionMethod other, ValueOrRefType t |
this.isDisambiguatingNonExtensionMethod0(target, t) |
hasCallable(t, other, target.getName()) and
other != target
)
}
/**
* Holds if this upcast may be used to affect call resolution in an extension
* method call.
*/
private predicate isDisambiguatingExtensionMethodCall() {
exists(Call c, ExtensionMethod target, ExtensionMethod other, ValueOrRefType t |
this.isArgument(c, target) |
t = c.getArgument(0).getType() and
hasExtensionMethod(t, other, target.getName()) and
other != target
)
}
/** Holds if this is a useful upcast. */
predicate isUseful() {
this.isDisambiguatingNonExtensionMethodCall()
or
this.isDisambiguatingExtensionMethodCall()
or
this = any(Call c).(QualifiableExpr).getQualifier() and
dest instanceof Interface
or
this = any(OperatorCall oc).getAnArgument()
or
this = any(Operation o |
not o instanceof Assignment and
not o instanceof UnaryBitwiseOperation and
not o instanceof SizeofExpr and
not o instanceof PointerIndirectionExpr and
not o instanceof AddressOfExpr and
not o instanceof UnaryLogicalOperation and
not o instanceof BinaryBitwiseOperation and
not o instanceof LogicalAndExpr and
not o instanceof LogicalOrExpr
).getAnOperand()
or
this = any(LocalVariableDeclAndInitExpr decl |
decl.isImplicitlyTyped()
).getInitializer()
or
exists(LambdaExpr c | c.canReturn(this))
}
}
from ExplicitUpcast u, ValueOrRefType src, ValueOrRefType dest
where src = u.getSourceType()
and dest = u.getTargetType()
and not u.isUseful()
select u, "There is no need to upcast from $@ to $@ - the conversion can be done implicitly.",
src, src.getName(),
dest, dest.getName()