@@ -76,7 +76,7 @@ private TypeExpr getABaseType(Class cls, boolean abstractExtension) {
76
76
}
77
77
78
78
pragma [ nomagic]
79
- predicate rawEdge ( PathNode pred , PathNode succ ) {
79
+ private predicate basicEdge ( PathNode pred , PathNode succ ) {
80
80
exists ( Predicate predicat | pred .asAstNode ( ) = predicat |
81
81
succ .asAstNode ( ) .getEnclosingPredicate ( ) = predicat
82
82
or
@@ -138,11 +138,36 @@ predicate rawEdge(PathNode pred, PathNode succ) {
138
138
pred .asAstNode ( ) = top and
139
139
succ .asAstNode ( ) .getFile ( ) = top .getFile ( )
140
140
)
141
+ or
142
+ // Add bidirectional edges between a class declaration and its type.
143
+ exists ( Class cls |
144
+ pred .asAstNode ( ) = cls and succ .asType ( ) = cls .getType ( )
145
+ or
146
+ succ .asAstNode ( ) = cls and pred .asType ( ) = cls .getType ( )
147
+ )
141
148
}
142
149
143
- private PathNode getAPredecessor ( PathNode node ) { rawEdge ( result , node ) }
144
-
145
- private PathNode getASuccessor ( PathNode node ) { rawEdge ( node , result ) }
150
+ private predicate cacheEdge ( PathNode pred , PathNode succ ) {
151
+ // At a cached module, add bidirectional edges to every cached member
152
+ exists ( Module mod , Declaration decl |
153
+ mod .hasAnnotation ( "cached" ) and
154
+ decl = mod .getAChild ( ) and
155
+ decl .hasAnnotation ( "cached" )
156
+ |
157
+ pred .asAstNode ( ) = mod and succ .asAstNode ( ) = decl
158
+ or
159
+ succ .asAstNode ( ) = mod and pred .asAstNode ( ) = decl
160
+ )
161
+ or
162
+ // At a cached class, add edges from the class to its cached member predicates
163
+ exists ( Class cls , Predicate member |
164
+ cls .hasAnnotation ( "cached" ) and
165
+ member = cls .getAClassPredicate ( ) and
166
+ member .hasAnnotation ( "cached" ) and
167
+ pred .asAstNode ( ) = cls and
168
+ succ .asAstNode ( ) = member
169
+ )
170
+ }
146
171
147
172
signature module DependencyConfig {
148
173
/**
@@ -154,9 +179,30 @@ signature module DependencyConfig {
154
179
* Holds if a transitive dependency from a source to `sink` should be reported.
155
180
*/
156
181
predicate isSink ( PathNode sink ) ;
182
+
183
+ /**
184
+ * Holds if the `cached` members of a `cached` module or class should be unified.
185
+ *
186
+ * Whether to set this depends on your use-case:
187
+ * - If you wish to know why one predicate causes another predicate to be evaluated, this should be `any()`.
188
+ * - If you wish to investigate recursion patterns or understand why the value of one predicate
189
+ * is influenced by another predicate, it should be `none()`.
190
+ */
191
+ predicate followCacheDependencies ( ) ;
157
192
}
158
193
159
194
module PathGraph< DependencyConfig C> {
195
+ private predicate rawEdge ( PathNode pred , PathNode succ ) {
196
+ basicEdge ( pred , succ )
197
+ or
198
+ C:: followCacheDependencies ( ) and
199
+ cacheEdge ( pred , succ )
200
+ }
201
+
202
+ private PathNode getAPredecessor ( PathNode node ) { rawEdge ( result , node ) }
203
+
204
+ private PathNode getASuccessor ( PathNode node ) { rawEdge ( node , result ) }
205
+
160
206
private PathNode reachableFromSource ( ) {
161
207
C:: isSource ( result )
162
208
or
0 commit comments