forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDependencyCounts.qll
More file actions
165 lines (159 loc) · 5.48 KB
/
DependencyCounts.qll
File metadata and controls
165 lines (159 loc) · 5.48 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
/**
* This library provides utility predicates for representing the number of dependencies between types.
*/
import Type
import Generics
import Expr
/**
* The number of dependencies from type `t` on type `dep`.
*
* Dependencies are restricted to generic and non-generic reference types.
*
* Dependencies on parameterized or raw types are decomposed into
* a dependency on the corresponding generic type and separate
* dependencies on (source declarations of) any type arguments.
*
* For example, a dependency on type `List<Set<String>>` is represented by
* dependencies on the generic types `List` and `Set` as well as a dependency
* on the type `String` but not on the parameterized types `List<Set<String>>`
* or `Set<String>`.
*/
pragma[nomagic]
predicate numDepends(RefType t, RefType dep, int value) {
// Type `t` is neither a parameterized nor a raw type and is distinct from `dep`.
not isParameterized(t) and
not isRaw(t) and
not t = dep and
// Type `t` depends on:
value =
strictcount(Element elem |
// its supertypes,
exists(RefType s | elem = s and t.hasSupertype(s) | usesType(s, dep))
or
// its enclosing types,
exists(RefType s | elem = s and t.getEnclosingType() = s | usesType(s, dep))
or
// the type of any field declared in `t`,
exists(Field f | elem = f and f.getDeclaringType() = t | usesType(f.getType(), dep))
or
// the return type of any method declared in `t`,
exists(Method m | elem = m and m.getDeclaringType() = t | usesType(m.getReturnType(), dep))
or
// the type of any parameter of a callable in `t`,
exists(Parameter p | elem = p and p.getCallable().getDeclaringType() = t |
usesType(p.getType(), dep)
)
or
// the type of any exception in the `throws` clause of a callable declared in `t`,
exists(Exception e | elem = e and e.getCallable().getDeclaringType() = t |
usesType(e.getType(), dep)
)
or
// the declaring type of a callable accessed in `t`,
exists(Call c |
elem = c and
c.getEnclosingCallable().getDeclaringType() = t
|
usesType(c.getCallee().getSourceDeclaration().getDeclaringType(), dep)
)
or
// the declaring type of a field accessed in `t`,
exists(FieldAccess fa |
elem = fa and
fa.getEnclosingCallable().getDeclaringType() = t
|
usesType(fa.getField().getSourceDeclaration().getDeclaringType(), dep)
)
or
// the type of a local variable declared in `t`,
exists(LocalVariableDeclExpr decl |
elem = decl and
decl.getEnclosingCallable().getDeclaringType() = t
|
usesType(decl.getType(), dep)
)
or
// the type of a type literal accessed in `t`,
exists(TypeLiteral l |
elem = l and
l.getEnclosingCallable().getDeclaringType() = t
|
usesType(l.getTypeName().getType(), dep)
)
or
// the type of an annotation (or one of its element values) that annotates `t` or one of its members,
exists(Annotation a |
a.getAnnotatedElement() = t or
a.getAnnotatedElement().(Member).getDeclaringType() = t
|
elem = a and usesType(a.getType(), dep)
or
elem = a.getAValue() and
elem.getFile().getExtension() = "java" and
usesType(elem.(Expr).getType(), dep)
)
or
// the type accessed in an `instanceof` expression in `t`.
exists(InstanceOfExpr ioe |
elem = ioe and
t = ioe.getEnclosingCallable().getDeclaringType()
|
usesType(ioe.getTypeName().getType(), dep)
)
)
}
predicate filePackageDependencyCount(File sourceFile, int total, string entity) {
exists(Package targetPackage |
total =
strictsum(RefType sourceType, RefType targetType, int num |
sourceType.getFile() = sourceFile and
sourceType.fromSource() and
sourceType.getPackage() != targetPackage and
targetType.getPackage() = targetPackage and
numDepends(sourceType, targetType, num)
|
num
) and
entity = "/" + sourceFile.getRelativePath() + "<|>" + targetPackage + "<|>N/A"
)
}
private string nameVersionRegex() { result = "([_.A-Za-z0-9-]*)-([0-9][A-Za-z0-9.+_-]*)" }
/**
* Given a JAR filename, try to split it into a name and version.
* This is a heuristic approach assuming that the a dash is used to
* separate the library name from a largely numeric version such as
* `commons-io-2.4`.
*/
bindingset[target]
predicate hasDashedVersion(string target, string name, string version) {
exists(string regex | regex = nameVersionRegex() |
name = target.regexpCapture(regex, 1) and
version = target.regexpCapture(regex, 2)
)
}
predicate fileJarDependencyCount(File sourceFile, int total, string entity) {
exists(Container targetJar, string jarStem |
jarStem = targetJar.getStem() and
targetJar.(File).getExtension() = "jar" and
jarStem != "rt"
|
total =
strictsum(RefType r, RefType dep, int num |
r.getFile() = sourceFile and
r.fromSource() and
dep.getFile().getParentContainer*() = targetJar and
numDepends(r, dep, num)
|
num
) and
exists(string name, string version |
if hasDashedVersion(jarStem, _, _)
then hasDashedVersion(jarStem, name, version)
else (
name = jarStem and version = "unknown"
)
|
entity = "/" + sourceFile.getRelativePath() + "<|>" + name + "<|>" + version
)
)
}