-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Expand file tree
/
Copy pathGeneratedCode.qll
More file actions
196 lines (178 loc) · 5.9 KB
/
Copy pathGeneratedCode.qll
File metadata and controls
196 lines (178 loc) · 5.9 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
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
/**
* Provides classes for detecting generated code.
*/
import javascript
import semmle.javascript.frameworks.Bundling
import semmle.javascript.frameworks.Emscripten
import semmle.javascript.frameworks.GWT
import semmle.javascript.SourceMaps
/**
* A comment that marks generated code.
*/
abstract class GeneratedCodeMarkerComment extends Comment { }
/**
* A source mapping comment, viewed as a marker comment indicating generated code.
*/
private class SourceMappingCommentMarkerComment extends GeneratedCodeMarkerComment instanceof SourceMappingComment
{ }
/**
* A marker comment left by a known code generator.
*/
class CodeGeneratorMarkerComment extends GeneratedCodeMarkerComment {
CodeGeneratorMarkerComment() { codeGeneratorMarkerComment(this, _) }
/** Gets the name of the code generator that left this marker comment. */
string getGeneratorName() { codeGeneratorMarkerComment(this, result) }
}
/**
* Holds if `c` is a comment left by code generator `tool`.
*/
private predicate codeGeneratorMarkerComment(Comment c, string tool) {
exists(string toolPattern |
toolPattern =
"js_of_ocaml|CoffeeScript|LiveScript|dart2js|ANTLR|PEG\\.js|Opal|JSX|jison(?:-lex)?|(?:Microsoft \\(R\\) AutoRest Code Generator)|purs" and
tool =
c.getText()
.regexpCapture("(?s)[\\s*]*(?:parser |Code )?[gG]eneratedy? (?:from .*)?by (" +
toolPattern + ")\\b.*", 1)
)
}
/**
* A generic generated code marker comment.
*/
private class GenericGeneratedCodeMarkerComment extends GeneratedCodeMarkerComment {
GenericGeneratedCodeMarkerComment() {
exists(string entity, string was, string automatically |
entity = "code|file|class|interface|art[ei]fact|module|script" and
was = "was|is|has been" and
automatically = "automatically |mechanically |auto[- ]?" and
// Look for this pattern in each line of the comment.
this.getText()
.regexpMatch("(?im)^.*\\b(This|The following) (" + entity + ") (" + was + ") (" +
automatically + ")?gener(e?)ated\\b.*$")
)
}
}
/**
* A comment warning against modifications, viewed as a marker comment indicating generated code.
*/
private class DontModifyMarkerComment extends GeneratedCodeMarkerComment {
DontModifyMarkerComment() {
exists(string pattern |
// Look for these patterns in each line of the comment.
this.getText().regexpMatch(pattern) and
pattern =
[
"(?im)^.*\\bGenerated by\\b.*\\bDo not edit\\b.*$",
"(?im)^.*\\bAny modifications to this file will be lost\\b.*$"
]
)
}
}
/** A script that looks like it was generated by dart2js. */
private class DartGeneratedTopLevel extends TopLevel {
DartGeneratedTopLevel() {
exists(VarAccess deferredInit | deferredInit.getTopLevel() = this |
deferredInit.getName() = "$dart_deferred_initializers$" or
deferredInit.getName() = "$dart_deferred_initializers"
)
}
}
/**
* Holds if `tl` has unusually many or unusually complicated function invocations, which is
* often a sign of generated code.
*/
private predicate hasManyInvocations(TopLevel tl) {
// heuristic: more than 100 arguments per line means it's probably generated
exists(int nl, int na |
nl = tl.getNumberOfLines() and
nl > 0 and
na = sum(InvokeExpr invk | tl = invk.getTopLevel() | invk.getNumArgument()) and
na.(float) / nl > 100
)
}
/**
* Holds if `f` is side effect free, and full of primitive literals, which is often a sign of generated data code.
*/
private predicate isData(File f) {
// heuristic: `f` has more than 1000 primitive literal expressions ...
count(SyntacticConstants::PrimitiveLiteralConstant e | e.getFile() = f) > 1000 and
// ... but no expressions with side effects ...
not exists(Expr e |
e.getFile() = f and
e.isImpure() and
// ... except for variable initializers
not e instanceof VariableDeclarator
)
}
/**
* Holds if `f` is a single line that looks like a non-trivial amount of JSON data, which is often a sign of generated data code.
*/
private predicate isJsonLine(File f) {
f.getNumberOfLines() = 1 and
count(Expr e | e.getFile() = f) > 100 and
forall(Expr e | e.getFile() = f |
e instanceof ObjectExpr or
e instanceof ArrayExpr or
e instanceof NumberLiteral or
e instanceof StringLiteral or
e instanceof BooleanLiteral
)
}
/**
* Holds if `f` is a generated HTML file.
*/
private predicate isGeneratedHtml(File f) {
exists(HTML::Element e |
e.getFile() = f and
e.getName() = "meta" and
e.getAttributeByName("name").getValue() = "generator"
)
or
exists(HTML::CommentNode comment |
comment.getText().regexpMatch("\\s*Generated by [\\w-]+ \\d+\\.\\d+\\.\\d+\\s*") and
comment.getFile() = f
)
or
20 < countStartingHtmlElements(f, _)
}
/**
* Gets an element that starts at line `l` in file `f`.
*/
private HTML::Element getAStartingElement(File f, int l) {
result.getFile() = f and result.getLocation().getStartLine() = l
}
/**
* Gets the number of HTML elements that start at line `l` in file `f`.
*/
private int countStartingHtmlElements(File f, int l) {
result = strictcount(getAStartingElement(f, l))
}
/**
* Holds if the base name of `f` is a number followed by a single extension.
*/
predicate isGeneratedFileName(File f) {
f.getStem().regexpMatch("[0-9]+") and
not f.getExtension() = "vue"
}
/**
* Holds if `tl` looks like it contains generated code.
*/
predicate isGenerated(TopLevel tl) {
tl.isMinified() or
isBundle(tl) or
tl instanceof GwtGeneratedTopLevel or
tl instanceof DartGeneratedTopLevel or
exists(GeneratedCodeMarkerComment gcmc | tl = gcmc.getTopLevel()) or
hasManyInvocations(tl) or
isData(tl.getFile()) or
isJsonLine(tl.getFile()) or
isGeneratedHtml(tl.getFile()) or
isGeneratedFileName(tl.getFile())
}
/**
* Holds if `file` look like it contains generated code.
*/
predicate isGeneratedCode(File file) {
isGenerated(file.getATopLevel()) or
isGeneratedHtml(file)
}