@@ -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
@@ -200,8 +202,9 @@ private AstNode benign() {
200
202
result instanceof BlockComment or
201
203
not exists ( result .toString ( ) ) or // <- invalid code
202
204
// cached-stages pattern
203
- result .( Module ) .getAMember ( ) .( ClasslessPredicate ) .getName ( ) = "forceStage" or
204
- result .( ClasslessPredicate ) .getName ( ) = "forceStage" or
205
+ result .( Module ) .getAMember ( ) .( ClasslessPredicate ) .getName ( ) =
206
+ [ "forceStage" , "forceCachingInSameStageforceCachingInSameStage" ] or
207
+ result .( ClasslessPredicate ) .getName ( ) = [ "forceStage" , "forceCachingInSameStage" ] or
205
208
result .getLocation ( ) .getFile ( ) .getBaseName ( ) = "Caching.qll" or
206
209
// sometimes contains dead code - ignore
207
210
result .getLocation ( ) .getFile ( ) .getRelativePath ( ) .matches ( "%/tutorials/%" ) or
@@ -239,16 +242,46 @@ private AstNode queryable() {
239
242
result = aliveStep ( queryable ( ) )
240
243
}
241
244
245
+ // The benign cases are mostly
246
+ private AstNode benignUnqueryable ( ) {
247
+ result = benign ( ) or
248
+ // cached-stages pattern
249
+ // sometimes contains dead code - ignore
250
+ result .( Module ) .getName ( ) = "Debugging" or
251
+ result .getLocation ( ) .getFile ( ) = benignUnqueryableFile ( )
252
+ }
253
+
254
+ pragma [ noinline]
255
+ private File benignUnqueryableFile ( ) {
256
+ result .getAbsolutePath ( ) .matches ( "%/explore/%" ) or
257
+ result .getRelativePath ( ) .matches ( "%/tutorials/%" ) or
258
+ result .getBaseName ( ) =
259
+ [
260
+ "Expr.qll" , "TypeScript.qll" , "YAML.qll" , "Tokens.qll" , "Instruction.qll" , "Persistence.qll" ,
261
+ "ES2015Modules.qll"
262
+ ] or // lots of classes that exist for completeness
263
+ result .getBaseName ( ) = [ "CachedStages.qll" , "Caching.qll" , "tutorial.qll" ] or
264
+ result .getBaseName ( ) = "PrettyPrintAst.qll" or // it's dead code, but seems intentional
265
+ result .getBaseName ( ) = "SensitiveDataHeuristics.qll" or // not all langs use all the things
266
+ result .getAbsolutePath ( ) .matches ( "%/ql/ql/test%" ) // QL-for-QL tests contain plenty of unqueryable code on purpose
267
+ }
268
+
242
269
/**
243
270
* Gets an AstNode that does not affect any query result.
244
271
* Is interresting as an quick-eval target to investigate dead code.
245
272
* (It is intentional that this predicate is a result of this predicate).
246
273
*/
247
- AstNode unQueryable ( string msg ) {
274
+ AstNode unQueryable ( ) {
248
275
not result = queryable ( ) and
249
276
not result = deprecated ( ) and
250
- not result = benign ( ) and
251
- not result .getParent ( ) = any ( AstNode node | not node = queryable ( ) ) and
252
- msg = result .getLocation ( ) .getFile ( ) .getBaseName ( ) and
253
- result .getLocation ( ) .getFile ( ) .getAbsolutePath ( ) .matches ( "%/javascript/%" )
277
+ not result = benignUnqueryable ( ) and
278
+ not result .getParent ( ) = any ( AstNode node | not node = queryable ( ) )
279
+ }
280
+
281
+ AstNode unqueryableLang ( string lang ) {
282
+ lang = "/" + [ "cpp" , "csharp" , "java" , "javascript" , "python" , "ruby" ] + "/" and
283
+ result = unQueryable ( ) and
284
+ result .getLocation ( ) .getFile ( ) .getAbsolutePath ( ) .matches ( "%" + lang + "%" )
254
285
}
286
+
287
+ int countLang ( string lang ) { result = strictcount ( unqueryableLang ( lang ) ) }
0 commit comments