-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathDefaultToString.ql
More file actions
91 lines (82 loc) · 2.72 KB
/
DefaultToString.ql
File metadata and controls
91 lines (82 loc) · 2.72 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
/**
* @name Use of default ToString()
* @description Calling the default implementation of 'ToString' returns a value
* that is unlikely to be what you expect.
* @kind problem
* @problem.severity warning
* @precision very-high
* @id cs/call-to-object-tostring
* @tags reliability
* maintainability
*/
import csharp
import semmle.code.csharp.commons.Strings
import semmle.code.csharp.frameworks.System
/**
* Holds if expression `e`, of type `t`, invokes `ToString()` either explicitly
* or implicitly.
*/
predicate invokesToString(Expr e, ValueOrRefType t) {
// Explicit invocation
exists(MethodCall mc |
mc.getQualifier() = e |
mc.getTarget() instanceof ToStringMethod and
t = mc.getQualifier().getType()
)
or
// Explicit or implicit invocation
e instanceof ImplicitToStringExpr and
t = e.stripCasts().getType()
or
// Implicit invocation via forwarder method
t = e.stripCasts().getType() and
not t instanceof StringType and
exists(AssignableDefinitions::ImplicitParameterDefinition def, Parameter p, ParameterRead pr |
e = p.getAnAssignedArgument() |
def.getParameter() = p and
pr = def.getAReachableRead() and
pr.getAControlFlowNode().postDominates(p.getCallable().getEntryPoint()) and
invokesToString(pr, _)
)
}
/**
* Holds if `t`, or any sub type of `t`, inherits the default `ToString()`
* method from `System.Object` or `System.ValueType`.
*/
predicate alwaysDefaultToString(ValueOrRefType t) {
exists(ToStringMethod m |
t.hasMethod(m) |
m.getDeclaringType() instanceof SystemObjectClass or
m.getDeclaringType() instanceof SystemValueTypeClass
)
and
not exists(RefType overriding |
overriding.getAMethod() instanceof ToStringMethod and
overriding.getABaseType+() = t
)
}
newtype TDefaultToStringType =
TDefaultToStringType0(ValueOrRefType t) { alwaysDefaultToString(t) }
class DefaultToStringType extends TDefaultToStringType {
ValueOrRefType t;
DefaultToStringType() { this = TDefaultToStringType0(t) }
ValueOrRefType getType() { result = t }
string toString() { result = t.toString() }
// A workaround for generating empty URLs for non-source locations, because qltest
// does not support non-source locations
string getURL() {
exists(Location l |
l = t.getLocation() |
if l instanceof SourceLocation then
exists(string path, int a, int b, int c, int d |
l.hasLocationInfo(path, a, b, c, d) |
toUrl(path, a, b, c, d, result)
)
else
result = ""
)
}
}
from Expr e, DefaultToStringType t
where invokesToString(e, t.getType())
select e, "Default 'ToString()': $@ inherits 'ToString()' from 'Object', and so is not suitable for printing.", t, t.getType().getName()