@@ -30,7 +30,9 @@ private AstNode publicApi() {
30
30
*/
31
31
private AstNode queryPredicate ( ) {
32
32
// result = query relation that is "transitively" imported by a .ql file.
33
- PathProblemQuery:: importsQueryRelation ( result ) .asFile ( ) .getExtension ( ) = "ql"
33
+ // PathProblemQuery::importsQueryRelation(result).asFile().getExtension() = "ql"
34
+ // any query predicate. Query predicates are usually meant to be used.
35
+ result .( Predicate ) .hasAnnotation ( "query" )
34
36
or
35
37
// the from-where-select
36
38
result instanceof Select
@@ -208,8 +210,9 @@ private AstNode benign() {
208
210
result instanceof Comment or
209
211
not exists ( result .toString ( ) ) or // <- invalid code
210
212
// cached-stages pattern
211
- result .( Module ) .getAMember ( ) .( ClasslessPredicate ) .getName ( ) = "forceStage" or
212
- result .( ClasslessPredicate ) .getName ( ) = "forceStage" or
213
+ result .( Module ) .getAMember ( ) .( ClasslessPredicate ) .getName ( ) =
214
+ [ "forceStage" , "forceCachingInSameStageforceCachingInSameStage" ] or
215
+ result .( ClasslessPredicate ) .getName ( ) = [ "forceStage" , "forceCachingInSameStage" ] or
213
216
result .getLocation ( ) .getFile ( ) .getBaseName ( ) = "Caching.qll" or
214
217
// sometimes contains dead code - ignore
215
218
result .getLocation ( ) .getFile ( ) .getRelativePath ( ) .matches ( "%/tutorials/%" ) or
@@ -243,20 +246,74 @@ private AstNode queryable() {
243
246
or
244
247
result instanceof TopLevel // toplevel is always alive.
245
248
or
249
+ result = hackyShouldBeTreatedAsAlive ( )
250
+ or
251
+ // The below prevents the query from being too loud. The files below contain a lot of unqueryable code.
252
+ // I think some of it is from some languages not using all features of a shared library, but I'm not sure (haven't look much into it).
253
+ result
254
+ .getLocation ( )
255
+ .getFile ( )
256
+ .getBaseName ( )
257
+ .matches ( [ "DataFlowImpl" , "SsaImplCommon" , "FlowSummary" ] + "%" )
258
+ or
246
259
// recurisve cases
247
260
result = aliveStep ( queryable ( ) )
248
261
}
249
262
263
+ // The benign cases are mostly
264
+ private AstNode benignUnqueryable ( ) {
265
+ result = benign ( ) or
266
+ // cached-stages pattern
267
+ // sometimes contains dead code - ignore
268
+ result .( Module ) .getName ( ) = "Debugging" or
269
+ result .getLocation ( ) .getFile ( ) = benignUnqueryableFile ( )
270
+ }
271
+
272
+ pragma [ noinline]
273
+ private File benignUnqueryableFile ( ) {
274
+ result .getAbsolutePath ( ) .matches ( "%/explore/%" ) or
275
+ result .getRelativePath ( ) .matches ( "%/tutorials/%" ) or
276
+ result .getRelativePath ( ) .matches ( "%/experimental/%" ) or
277
+ result .getRelativePath ( ) .matches ( "%/frameworks/%" ) or // the frameworks have a lot of code that only exists for completeness.
278
+ result .getBaseName ( ) =
279
+ [
280
+ "Expr.qll" , "TypeScript.qll" , "YAML.qll" , "Tokens.qll" , "Instruction.qll" , "Persistence.qll" ,
281
+ "ES2015Modules.qll" , "TaintTrackingPublic.qll" , "TaintTrackingUtil.qll" ,
282
+ ] or // lots of classes that exist for completeness
283
+ result .getBaseName ( ) = [ "CachedStages.qll" , "Caching.qll" , "tutorial.qll" ] or
284
+ result .getBaseName ( ) = "PrettyPrintAst.qll" or // it's dead code, but seems intentional
285
+ result .getBaseName ( ) = [ "CryptoAlgorithmNames.qll" , "SensitiveDataHeuristics.qll" ] or // not all langs use all the things
286
+ // some more identical files
287
+ result .getBaseName ( ) = "ReachableBlock.qll" or
288
+ // QL-for-QL tests contain plenty of unqueryable code on purpose
289
+ result .getAbsolutePath ( ) .matches ( "%/ql/ql/test%" )
290
+ }
291
+
292
+ import NodeName
293
+
250
294
/**
251
295
* Gets an AstNode that does not affect any query result.
252
296
* Is interresting as an quick-eval target to investigate dead code.
253
297
* (It is intentional that this predicate is a result of this predicate).
254
298
*/
255
- AstNode unQueryable ( string msg ) {
299
+ AstNode unQueryable ( ) {
256
300
not result = queryable ( ) and
257
301
not result = deprecated ( ) and
258
- not result = benign ( ) and
302
+ not result = benignUnqueryable ( ) and
259
303
not result .getParent ( ) = any ( AstNode node | not node = queryable ( ) ) and
260
- msg = result .getLocation ( ) .getFile ( ) .getBaseName ( ) and
261
- result .getLocation ( ) .getFile ( ) .getAbsolutePath ( ) .matches ( "%/javascript/%" )
304
+ // remove where a queryable feature with the "same" name exists.
305
+ not exists ( AstNode other , string name |
306
+ name = getName ( result , _) and
307
+ name = oppositeFirstLetter ( getName ( other , _) ) and
308
+ other .getParent ( ) = result .getParent ( )
309
+ )
310
+ }
311
+
312
+ bindingset [ name]
313
+ string oppositeFirstLetter ( string name ) {
314
+ exists ( string first | first = name .prefix ( 1 ) |
315
+ if first .toUpperCase ( ) = first
316
+ then result = first .toLowerCase ( ) + name .suffix ( 1 )
317
+ else result = first .toUpperCase ( ) + name .suffix ( 1 )
318
+ )
262
319
}
0 commit comments