-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathLocation.qll
221 lines (197 loc) · 7.18 KB
/
Location.qll
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/**
* Provides classes and predicates for working with locations.
*
* Locations represent parts of files and are used to map elements to their source location.
*/
import FileSystem
import semmle.code.java.Element
private import semmle.code.SMAP
/** Holds if element `e` has name `name`. */
predicate hasName(Element e, string name) {
classes_or_interfaces(e, name, _, _)
or
primitives(e, name)
or
constrs(e, name, _, _, _, _)
or
methods(e, name, _, _, _, _)
or
fields(e, name, _, _)
or
packages(e, name)
or
name = e.(File).getStem()
or
paramName(e, name)
or
exists(int pos |
params(e, _, pos, _, _) and
not paramName(e, _) and
name = "p" + pos
)
or
localvars(e, name, _, _)
or
typeVars(e, name, _, _)
or
wildcards(e, name, _)
or
arrays(e, name, _, _, _)
or
modifiers(e, name)
or
kt_type_alias(e, name, _)
or
ktProperties(e, name)
or
e instanceof ErrorType and name = "<CodeQL error type>"
}
/**
* Top is the root of the QL type hierarchy; it defines some default
* methods for obtaining locations and a standard `toString()` method.
*/
class Top extends @top {
/** Gets the source location for this element. */
Location getLocation() { fixedHasLocation(this, result, _) }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.hasLocationInfoAux(filepath, startline, startcolumn, endline, endcolumn)
or
exists(string outFilepath, int outStartline, int outEndline |
this.hasLocationInfoAux(outFilepath, outStartline, _, outEndline, _) and
hasSmapLocationInfo(filepath, startline, startcolumn, endline, endcolumn, outFilepath,
outStartline, outEndline)
)
}
private predicate hasLocationInfoAux(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f, Location l | fixedHasLocation(this, l, f) |
locations_default(l, f, startline, startcolumn, endline, endcolumn) and
filepath = f.getAbsolutePath()
)
}
/** Gets the file associated with this element. */
File getFile() { fixedHasLocation(this, _, result) }
/**
* Gets the total number of lines that this element ranges over,
* including lines of code, comment and whitespace-only lines.
*/
int getTotalNumberOfLines() { numlines(this, result, _, _) }
/** Gets the number of lines of code that this element ranges over. */
int getNumberOfLinesOfCode() { numlines(this, _, result, _) }
/** Gets the number of comment lines that this element ranges over. */
int getNumberOfCommentLines() { numlines(this, _, _, result) }
/** Gets a textual representation of this element. */
cached
string toString() { hasName(this, result) }
/**
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
*/
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
/**
* Gets the name of a primary CodeQL class to which this element belongs.
*
* For most elements, this is simply the most precise syntactic category to
* which they belong; for example, `AddExpr` is a primary class, but
* `BinaryExpr` is not.
*
* This predicate always has a result. If no primary class can be
* determined, the result is `"???"`. If multiple primary classes match,
* this predicate can have multiple results.
*/
string getAPrimaryQlClass() { result = "???" }
}
/** A location maps language elements to positions in source files. */
class Location extends @location {
/** Gets the 1-based line number (inclusive) where this location starts. */
int getStartLine() { locations_default(this, _, result, _, _, _) }
/** Gets the 1-based column number (inclusive) where this location starts. */
int getStartColumn() { locations_default(this, _, _, result, _, _) }
/** Gets the 1-based line number (inclusive) where this location ends. */
int getEndLine() { locations_default(this, _, _, _, result, _) }
/** Gets the 1-based column number (inclusive) where this location ends. */
int getEndColumn() { locations_default(this, _, _, _, _, result) }
/**
* Gets the total number of lines that this location ranges over,
* including lines of code, comment and whitespace-only lines.
*/
int getNumberOfLines() {
exists(@sourceline s | hasLocation(s, this) |
numlines(s, result, _, _)
or
not numlines(s, _, _, _) and result = 0
)
}
/** Gets the number of lines of code that this location ranges over. */
int getNumberOfLinesOfCode() {
exists(@sourceline s | hasLocation(s, this) |
numlines(s, _, result, _)
or
not numlines(s, _, _, _) and result = 0
)
}
/** Gets the number of comment lines that this location ranges over. */
int getNumberOfCommentLines() {
exists(@sourceline s | hasLocation(s, this) |
numlines(s, _, _, result)
or
not numlines(s, _, _, _) and result = 0
)
}
/** Gets the file containing this location. */
File getFile() { locations_default(this, result, _, _, _, _) }
/** Gets a string representation containing the file and range for this location. */
string toString() {
exists(string filepath, int startLine, int startCol, int endLine, int endCol |
this.hasLocationInfo(filepath, startLine, startCol, endLine, endCol)
|
toUrl(filepath, startLine, startCol, endLine, endCol, result)
)
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f | locations_default(this, f, startline, startcolumn, endline, endcolumn) |
filepath = f.getAbsolutePath()
)
}
}
private predicate hasSourceLocation(Top l, Location loc, File f) {
hasLocation(l, loc) and f = loc.getFile() and f.isSourceFile()
}
cached
private predicate fixedHasLocation(Top l, Location loc, File f) {
hasSourceLocation(l, loc, f)
or
// When an entity has more than one location, as it might due to
// e.g. a parameterized generic being seen and extracted in several
// different directories or JAR files, select an arbitrary representative
// location to avoid needlessly duplicating alerts.
//
// Don't do this when the relevant location is in a source file, because
// that is much more unusual and we would rather notice the bug than mask it here.
loc =
min(Location candidateLoc |
hasLocation(l, candidateLoc)
|
candidateLoc order by candidateLoc.getFile().getAbsolutePath()
) and
not hasSourceLocation(l, _, _) and
locations_default(loc, f, _, _, _, _)
}