|
4 | 4 | */ |
5 | 5 |
|
6 | 6 | private import codeql.util.Location |
| 7 | +private import codeql.util.FileSystem |
7 | 8 |
|
8 | 9 | /** Provides the language-specific input specification. */ |
9 | 10 | signature module InputSig<LocationSig Location> { |
@@ -1132,19 +1133,19 @@ module Make<LocationSig Location, InputSig<Location> Input> { |
1132 | 1133 |
|
1133 | 1134 | final class AstCfgNode = AstCfgNodeImpl; |
1134 | 1135 |
|
| 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 | + |
1135 | 1144 | /** |
1136 | 1145 | * Import this module into a `.ql` file of `@kind graph` to render a CFG. The |
1137 | 1146 | * graph is restricted to nodes from `RelevantNode`. |
1138 | 1147 | */ |
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> { |
1148 | 1149 | /** Holds if `n` is a relevant node in the CFG. */ |
1149 | 1150 | query predicate nodes(RelevantNode n, string attr, string val) { |
1150 | 1151 | attr = "semmle.order" and |
@@ -1192,6 +1193,78 @@ module Make<LocationSig Location, InputSig<Location> Input> { |
1192 | 1193 | } |
1193 | 1194 | } |
1194 | 1195 |
|
| 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 | + |
1195 | 1268 | /** Provides a set of consistency queries. */ |
1196 | 1269 | module Consistency { |
1197 | 1270 | /** Holds if `s1` and `s2` are distinct representations of the same set. */ |
|
0 commit comments