Skip to content

Commit 5b6e76c

Browse files
committed
Move View CFG implementation from Ruby/Swift into shared library
1 parent 8fbe62c commit 5b6e76c

File tree

6 files changed

+144
-85
lines changed
  • csharp/ql/test/library-tests/controlflow/graph
  • ruby/ql
  • shared/controlflow/codeql/controlflow
  • swift/ql
    • lib/codeql/swift/controlflow/internal
    • test/library-tests/controlflow/graph

6 files changed

+144
-85
lines changed

csharp/ql/test/library-tests/controlflow/graph/NodeGraph.ql

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
import csharp
66
import Common
7-
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl::TestOutput
87

9-
private class MyRelevantNode extends RelevantNode, SourceControlFlowNode { }
8+
private class MyRelevantNode extends SourceControlFlowNode {
9+
string getOrderDisambiguation() { result = "" }
10+
}
11+
12+
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl::TestOutput<MyRelevantNode>

ruby/ql/lib/ide-contextual-queries/printCfg.ql

Lines changed: 24 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,47 +7,35 @@
77
* @tags ide-contextual-queries/print-cfg
88
*/
99

10-
private import codeql.ruby.controlflow.internal.ControlFlowGraphImpl::TestOutput
11-
private import codeql.IDEContextual
1210
private import codeql.Locations
11+
private import codeql.ruby.controlflow.internal.ControlFlowGraphImpl
1312
private import codeql.ruby.controlflow.ControlFlowGraph
1413

15-
/**
16-
* Gets the source file to generate a CFG from.
17-
*/
1814
external string selectedSourceFile();
1915

20-
external string selectedSourceLine();
21-
22-
external string selectedSourceColumn();
23-
24-
bindingset[file, line, column]
25-
private CfgScope smallestEnclosingScope(File file, int line, int column) {
26-
result =
27-
min(Location loc, CfgScope scope |
28-
loc = scope.getLocation() and
29-
(
30-
loc.getStartLine() < line
31-
or
32-
loc.getStartLine() = line and loc.getStartColumn() <= column
33-
) and
34-
(
35-
loc.getEndLine() > line
36-
or
37-
loc.getEndLine() = line and loc.getEndColumn() >= column
38-
) and
39-
loc.getFile() = file
40-
|
41-
scope
42-
order by
43-
loc.getStartLine() desc, loc.getStartColumn() desc, loc.getEndLine(), loc.getEndColumn()
44-
)
45-
}
16+
private predicate selectedSourceFileAlias = selectedSourceFile/0;
17+
18+
external int selectedSourceLine();
19+
20+
private predicate selectedSourceLineAlias = selectedSourceLine/0;
21+
22+
external int selectedSourceColumn();
4623

47-
class MyRelevantNode extends RelevantNode {
48-
MyRelevantNode() {
49-
this.getScope() =
50-
smallestEnclosingScope(getFileBySourceArchiveName(selectedSourceFile()),
51-
selectedSourceLine().toInt(), selectedSourceColumn().toInt())
24+
private predicate selectedSourceColumnAlias = selectedSourceColumn/0;
25+
26+
module ViewCfgQueryInput implements ViewCfgQueryInputSig<File> {
27+
predicate selectedSourceFile = selectedSourceFileAlias/0;
28+
29+
predicate selectedSourceLine = selectedSourceLineAlias/0;
30+
31+
predicate selectedSourceColumn = selectedSourceColumnAlias/0;
32+
33+
predicate cfgScopeSpan(
34+
CfgScope scope, File file, int startLine, int startColumn, int endLine, int endColumn
35+
) {
36+
file = scope.getFile() and
37+
scope.getLocation().hasLocationInfo(_, startLine, startColumn, endLine, endColumn)
5238
}
5339
}
40+
41+
import ViewCfgQuery<File, ViewCfgQueryInput>

ruby/ql/test/library-tests/controlflow/graph/Cfg.ql

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
*/
44

55
import codeql.ruby.CFG
6-
import codeql.ruby.controlflow.internal.ControlFlowGraphImpl::TestOutput
76

8-
class MyRelevantNode extends RelevantNode {
9-
MyRelevantNode() { exists(this) }
7+
class MyRelevantNode extends CfgNode {
8+
string getOrderDisambiguation() { result = "" }
109
}
10+
11+
import codeql.ruby.controlflow.internal.ControlFlowGraphImpl::TestOutput<MyRelevantNode>

shared/controlflow/codeql/controlflow/Cfg.qll

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
private import codeql.util.Location
7+
private import codeql.util.FileSystem
78

89
/** Provides the language-specific input specification. */
910
signature module InputSig<LocationSig Location> {
@@ -1132,19 +1133,19 @@ module Make<LocationSig Location, InputSig<Location> Input> {
11321133

11331134
final class AstCfgNode = AstCfgNodeImpl;
11341135

1136+
/** A node to be included in the output of `TestOutput`. */
1137+
signature class RelevantNodeSig extends Node {
1138+
/**
1139+
* Gets a string used to resolve ties in node and edge ordering.
1140+
*/
1141+
string getOrderDisambiguation();
1142+
}
1143+
11351144
/**
11361145
* Import this module into a `.ql` file of `@kind graph` to render a CFG. The
11371146
* graph is restricted to nodes from `RelevantNode`.
11381147
*/
1139-
module TestOutput {
1140-
/** A CFG node to include in the output. */
1141-
abstract class RelevantNode extends Node {
1142-
/**
1143-
* Gets a string used to resolve ties in node and edge ordering.
1144-
*/
1145-
string getOrderDisambiguation() { result = "" }
1146-
}
1147-
1148+
module TestOutput<RelevantNodeSig RelevantNode> {
11481149
/** Holds if `n` is a relevant node in the CFG. */
11491150
query predicate nodes(RelevantNode n, string attr, string val) {
11501151
attr = "semmle.order" and
@@ -1192,6 +1193,78 @@ module Make<LocationSig Location, InputSig<Location> Input> {
11921193
}
11931194
}
11941195

1196+
/** Provides the input to `ViewCfgQuery`. */
1197+
signature module ViewCfgQueryInputSig<FileSig File> {
1198+
/** The source file selected in the IDE. Should be an `external` predicate. */
1199+
string selectedSourceFile();
1200+
1201+
/** The source line selected in the IDE. Should be an `external` predicate. */
1202+
int selectedSourceLine();
1203+
1204+
/** The source column selected in the IDE. Should be an `external` predicate. */
1205+
int selectedSourceColumn();
1206+
1207+
/**
1208+
* Holds if CFG scope `scope` spans column `startColumn` of line `startLine` to
1209+
* column `endColumn` of line `endLine` in `file`.
1210+
*/
1211+
predicate cfgScopeSpan(
1212+
CfgScope scope, File file, int startLine, int startColumn, int endLine, int endColumn
1213+
);
1214+
}
1215+
1216+
/**
1217+
* Provides an implementation for a `View CFG` query.
1218+
*
1219+
* Import this module into a `.ql` that looks like
1220+
*
1221+
* ```ql
1222+
* @name Print CFG
1223+
* @description Produces a representation of a file's Control Flow Graph.
1224+
* This query is used by the VS Code extension.
1225+
* @id <lang>/print-cfg
1226+
* @kind graph
1227+
* @tags ide-contextual-queries/print-cfg
1228+
* ```
1229+
*/
1230+
module ViewCfgQuery<FileSig File, ViewCfgQueryInputSig<File> ViewCfgQueryInput> {
1231+
private import ViewCfgQueryInput
1232+
1233+
bindingset[file, line, column]
1234+
private CfgScope smallestEnclosingScope(File file, int line, int column) {
1235+
result =
1236+
min(CfgScope scope, int startLine, int startColumn, int endLine, int endColumn |
1237+
cfgScopeSpan(scope, file, startLine, startColumn, endLine, endColumn) and
1238+
(
1239+
startLine < line
1240+
or
1241+
startLine = line and startColumn <= column
1242+
) and
1243+
(
1244+
endLine > line
1245+
or
1246+
endLine = line and endColumn >= column
1247+
)
1248+
|
1249+
scope order by startLine desc, startColumn desc, endLine, endColumn
1250+
)
1251+
}
1252+
1253+
private import IdeContextual<File>
1254+
1255+
private class RelevantNode extends Node {
1256+
RelevantNode() {
1257+
this.getScope() =
1258+
smallestEnclosingScope(getFileBySourceArchiveName(selectedSourceFile()),
1259+
selectedSourceLine(), selectedSourceColumn())
1260+
}
1261+
1262+
string getOrderDisambiguation() { result = "" }
1263+
}
1264+
1265+
import TestOutput<RelevantNode>
1266+
}
1267+
11951268
/** Provides a set of consistency queries. */
11961269
module Consistency {
11971270
/** Holds if `s1` and `s2` are distinct representations of the same set. */

swift/ql/lib/codeql/swift/controlflow/internal/PrintCFG.ql

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,52 +7,45 @@
77
* @tags ide-contextual-queries/print-cfg
88
*/
99

10-
private import codeql.IDEContextual
10+
private import codeql.swift.elements.File
1111
private import codeql.swift.controlflow.ControlFlowGraph
12-
private import codeql.swift.controlflow.internal.ControlFlowGraphImpl::TestOutput
12+
private import codeql.swift.controlflow.internal.ControlFlowGraphImpl as Impl
13+
private import codeql.swift.controlflow.internal.ControlFlowGraphImplSpecific
1314

1415
/**
1516
* Gets the source file to generate a CFG from.
1617
*/
1718
external string selectedSourceFile();
1819

20+
private predicate selectedSourceFileAlias = selectedSourceFile/0;
21+
1922
/**
2023
* Gets the source line to generate a CFG from.
2124
*/
22-
external string selectedSourceLine();
25+
external int selectedSourceLine();
26+
27+
private predicate selectedSourceLineAlias = selectedSourceLine/0;
2328

2429
/**
2530
* Gets the source column to generate a CFG from.
2631
*/
27-
external string selectedSourceColumn();
28-
29-
bindingset[file, line, column]
30-
private CfgScope smallestEnclosingScope(File file, int line, int column) {
31-
result =
32-
min(Location loc, CfgScope scope |
33-
loc = scope.getLocation() and
34-
(
35-
loc.getStartLine() < line
36-
or
37-
loc.getStartLine() = line and loc.getStartColumn() <= column
38-
) and
39-
(
40-
loc.getEndLine() > line
41-
or
42-
loc.getEndLine() = line and loc.getEndColumn() >= column
43-
) and
44-
loc.getFile() = file
45-
|
46-
scope
47-
order by
48-
loc.getStartLine() desc, loc.getStartColumn() desc, loc.getEndLine(), loc.getEndColumn()
49-
)
50-
}
32+
external int selectedSourceColumn();
33+
34+
private predicate selectedSourceColumnAlias = selectedSourceColumn/0;
5135

52-
class MyRelevantNode extends RelevantNode {
53-
MyRelevantNode() {
54-
this.getScope() =
55-
smallestEnclosingScope(getFileBySourceArchiveName(selectedSourceFile()),
56-
selectedSourceLine().toInt(), selectedSourceColumn().toInt())
36+
module ViewCfgQueryInput implements Impl::ViewCfgQueryInputSig<File> {
37+
predicate selectedSourceFile = selectedSourceFileAlias/0;
38+
39+
predicate selectedSourceLine = selectedSourceLineAlias/0;
40+
41+
predicate selectedSourceColumn = selectedSourceColumnAlias/0;
42+
43+
predicate cfgScopeSpan(
44+
CfgInput::CfgScope scope, File file, int startLine, int startColumn, int endLine, int endColumn
45+
) {
46+
file = scope.getFile() and
47+
scope.getLocation().hasLocationInfo(_, startLine, startColumn, endLine, endColumn)
5748
}
5849
}
50+
51+
import Impl::ViewCfgQuery<File, ViewCfgQueryInput>

swift/ql/test/library-tests/controlflow/graph/Cfg.ql

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@
44

55
import swift
66
import codeql.swift.controlflow.ControlFlowGraph
7-
import codeql.swift.controlflow.internal.ControlFlowGraphImpl::TestOutput
87

9-
class MyRelevantNode extends RelevantNode {
8+
class MyRelevantNode extends ControlFlowNode {
109
MyRelevantNode() { this.getScope().getLocation().getFile().getName().matches("%swift/ql/test%") }
1110

1211
private AstNode asAstNode() { result = this.getAstNode().asAstNode() }
1312

14-
override string getOrderDisambiguation() {
13+
string getOrderDisambiguation() {
1514
result = this.asAstNode().getPrimaryQlClasses()
1615
or
1716
not exists(this.asAstNode()) and result = ""
1817
}
1918
}
19+
20+
import codeql.swift.controlflow.internal.ControlFlowGraphImpl::TestOutput<MyRelevantNode>

0 commit comments

Comments
 (0)