diff --git a/java/ql/lib/utils/test/BasicBlock.qll b/java/ql/lib/utils/test/BasicBlock.qll new file mode 100644 index 00000000000..c1f31f79182 --- /dev/null +++ b/java/ql/lib/utils/test/BasicBlock.qll @@ -0,0 +1,40 @@ +/** + * Provides utilities for working with basic blocks in tests. + */ +overlay[local?] +module; + +import java +import codeql.util.Boolean + +private predicate entryOrExit(ControlFlowNode n) { + n instanceof ControlFlow::EntryNode or + n instanceof ControlFlow::AnnotatedExitNode or + n instanceof ControlFlow::ExitNode +} + +/** Gets the first AST node in the basic block `bb`, if any. */ +ControlFlowNode getFirstAstNode(BasicBlock bb) { result = getFirstAstNode(bb, false) } + +/** + * Gets the first AST node in the basic block `bb`, if any. Otherwise, gets + * the first synthetic node. + */ +ControlFlowNode getFirstAstNodeOrSynth(BasicBlock bb) { result = getFirstAstNode(bb, true) } + +private ControlFlowNode getFirstAstNode(BasicBlock bb, Boolean allowSynthetic) { + result = + min(ControlFlowNode n, int i, int astOrder | + bb.getNode(i) = n and + if n.injects(_) + then astOrder = 0 + else + if entryOrExit(n) + then astOrder = 1 + else ( + allowSynthetic = true and astOrder = 2 + ) + | + n order by astOrder, i + ) +} diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.ql b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.ql index de1e23b649c..72de0cc435d 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.ql +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.ql @@ -1,6 +1,7 @@ import java import semmle.code.java.controlflow.Dominance +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.strictlyDominates(b2) -select b, b2 +select getFirstAstNode(b), getFirstAstNode(b2) diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.ql b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.ql index ae2d8a393b4..ae8dc5d188d 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.ql +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.ql @@ -1,5 +1,6 @@ import java +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.getASuccessor() = b2 -select b, b2 +select getFirstAstNodeOrSynth(b), getFirstAstNodeOrSynth(b2) diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.ql b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.ql index de1e23b649c..72de0cc435d 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.ql +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.ql @@ -1,6 +1,7 @@ import java import semmle.code.java.controlflow.Dominance +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.strictlyDominates(b2) -select b, b2 +select getFirstAstNode(b), getFirstAstNode(b2) diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.ql b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.ql index ae2d8a393b4..ae8dc5d188d 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.ql +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.ql @@ -1,5 +1,6 @@ import java +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.getASuccessor() = b2 -select b, b2 +select getFirstAstNodeOrSynth(b), getFirstAstNodeOrSynth(b2) diff --git a/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.ql b/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.ql index de1e23b649c..72de0cc435d 100644 --- a/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.ql +++ b/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.ql @@ -1,6 +1,7 @@ import java import semmle.code.java.controlflow.Dominance +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.strictlyDominates(b2) -select b, b2 +select getFirstAstNode(b), getFirstAstNode(b2) diff --git a/java/ql/test/library-tests/controlflow/basic/bbSuccessor.ql b/java/ql/test/library-tests/controlflow/basic/bbSuccessor.ql index ae2d8a393b4..ae8dc5d188d 100644 --- a/java/ql/test/library-tests/controlflow/basic/bbSuccessor.ql +++ b/java/ql/test/library-tests/controlflow/basic/bbSuccessor.ql @@ -1,5 +1,6 @@ import java +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.getASuccessor() = b2 -select b, b2 +select getFirstAstNodeOrSynth(b), getFirstAstNodeOrSynth(b2) diff --git a/java/ql/test/library-tests/guards/guards.ql b/java/ql/test/library-tests/guards/guards.ql index e2d80a4e738..21a23534ed6 100644 --- a/java/ql/test/library-tests/guards/guards.ql +++ b/java/ql/test/library-tests/guards/guards.ql @@ -1,8 +1,9 @@ import java import semmle.code.java.controlflow.Guards +import utils.test.BasicBlock from ConditionBlock cb, boolean testIsTrue, BasicBlock controlled where cb.controls(controlled, testIsTrue) and cb.getEnclosingCallable().getDeclaringType().hasName("Test") -select cb.getCondition(), testIsTrue, controlled +select cb.getCondition(), testIsTrue, getFirstAstNode(controlled) diff --git a/java/ql/test/library-tests/guards/guardslogic.ql b/java/ql/test/library-tests/guards/guardslogic.ql index f2ce9fdaa36..e68be505ff7 100644 --- a/java/ql/test/library-tests/guards/guardslogic.ql +++ b/java/ql/test/library-tests/guards/guardslogic.ql @@ -1,9 +1,10 @@ import java import semmle.code.java.controlflow.Guards +import utils.test.BasicBlock from Guard g, BasicBlock bb, GuardValue gv where g.valueControls(bb, gv) and g.getEnclosingCallable().getDeclaringType().hasName("Logic") and (exists(gv.asBooleanValue()) or gv.isThrowsException() or gv.getDualValue().isThrowsException()) -select g, gv, bb +select g, gv, getFirstAstNode(bb) diff --git a/java/ql/test/library-tests/guards/guardspreconditions.ql b/java/ql/test/library-tests/guards/guardspreconditions.ql index 77e4a4e48c0..849ee6087bf 100644 --- a/java/ql/test/library-tests/guards/guardspreconditions.ql +++ b/java/ql/test/library-tests/guards/guardspreconditions.ql @@ -1,9 +1,10 @@ import java import semmle.code.java.controlflow.Guards +import utils.test.BasicBlock from Guard g, BasicBlock bb, GuardValue gv where g.valueControls(bb, gv) and g.getEnclosingCallable().getDeclaringType().hasName("Preconditions") and (gv.isThrowsException() or gv.getDualValue().isThrowsException()) -select g, gv, bb +select g, gv, getFirstAstNode(bb)