-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathModelEditor.qll
More file actions
147 lines (125 loc) · 4.4 KB
/
ModelEditor.qll
File metadata and controls
147 lines (125 loc) · 4.4 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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/** Provides classes and predicates related to handling APIs for the VS Code extension. */
private import csharp
private import semmle.code.csharp.dataflow.FlowSummary
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.dataflow.internal.ExternalFlow
private import semmle.code.csharp.frameworks.Test
private import semmle.code.csharp.telemetry.TestLibrary
/** Holds if the given callable is not worth supporting. */
private predicate isUninteresting(Callable c) {
c.getDeclaringType() instanceof TestLibrary
or
c.(Constructor).isParameterless()
or
c.getDeclaringType() instanceof AnonymousClass
or
// The data flow library uses read/store steps for properties, so we don't need to model them,
// if both a getter and a setter exist.
c.(Accessor).getDeclaration().(Property).isReadWrite()
}
/**
* A callable method or accessor from either the C# Standard Library, a 3rd party library, or from the source.
*/
class Endpoint extends Callable {
Endpoint() {
[this.(Modifiable), this.(Accessor).getDeclaration()].isEffectivelyPublic() and
not isUninteresting(this) and
this.isUnboundDeclaration()
}
/**
* Gets the namespace of this endpoint.
*/
bindingset[this]
string getNamespace() { this.getDeclaringType().hasFullyQualifiedName(result, _) }
/**
* Gets the unbound type name of this endpoint.
*/
bindingset[this]
string getTypeName() {
result = qualifiedTypeName(this.getNamespace(), this.getDeclaringType().getUnboundDeclaration())
}
/**
* Gets the qualified name of this endpoint.
*/
bindingset[this]
string getEndpointName() {
result = qualifiedCallableName(this.getNamespace(), this.getTypeName(), this)
}
/**
* Gets the parameter types of this endpoint.
*/
bindingset[this]
string getParameterTypes() { result = "(" + parameterQualifiedTypeNamesToString(this) + ")" }
private string getDllName() { result = this.getLocation().(Assembly).getName() }
private string getDllVersion() { result = this.getLocation().(Assembly).getVersion().toString() }
string dllName() {
result = this.getDllName()
or
not exists(this.getDllName()) and result = this.getFile().getBaseName()
}
string dllVersion() {
result = this.getDllVersion()
or
not exists(this.getDllVersion()) and result = ""
}
/** Holds if this API has a supported summary. */
pragma[nomagic]
predicate hasSummary() { this instanceof SummarizedCallable }
/** Holds if this API is a known source. */
pragma[nomagic]
abstract predicate isSource();
/** Holds if this API is a known sink. */
pragma[nomagic]
abstract predicate isSink();
/** Holds if this API is a known neutral. */
pragma[nomagic]
predicate isNeutral() { this instanceof FlowSummaryImpl::Public::NeutralCallable }
/**
* Holds if this API is supported by existing CodeQL libraries, that is, it is either a
* recognized source, sink or neutral or it has a flow summary.
*/
predicate isSupported() {
this.hasSummary() or this.isSource() or this.isSink() or this.isNeutral()
}
}
boolean isSupported(Endpoint endpoint) {
if endpoint.isSupported() then result = true else result = false
}
string supportedType(Endpoint endpoint) {
endpoint.isSink() and result = "sink"
or
endpoint.isSource() and result = "source"
or
endpoint.hasSummary() and result = "summary"
or
endpoint.isNeutral() and result = "neutral"
or
not endpoint.isSupported() and result = ""
}
string methodClassification(Call method) {
method.getFile() instanceof TestRelatedFile and result = "test"
or
not method.getFile() instanceof TestRelatedFile and
result = "source"
}
/**
* Gets the fully qualified name of the type `t`.
*/
private string qualifiedTypeName(string namespace, Type t) {
exists(string type | hasQualifiedTypeName(t, namespace, type) | result = type)
}
/**
* Gets the fully qualified name of the callable `c`.
*/
private string qualifiedCallableName(string namespace, string type, Callable c) {
exists(string name | hasQualifiedMethodName(c, namespace, type, name) | result = name)
}
/** A file that is either a test file or is only used in tests. */
class TestRelatedFile extends File {
TestRelatedFile() {
this instanceof TestFile
or
this.getAbsolutePath().matches(["%/test/%", "%/tests/%"]) and
not this.getAbsolutePath().matches("%/ql/test/%") // allows our test cases to work
}
}