Move `View CFG` implementation from Ruby/Swift into shared library

This commit is contained in:
Tom Hvitved 2024-02-26 10:32:26 +01:00
Родитель 8fbe62ccae
Коммит 5b6e76c030
6 изменённых файлов: 141 добавлений и 82 удалений

Просмотреть файл

@ -4,6 +4,9 @@
import csharp
import Common
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl::TestOutput
private class MyRelevantNode extends RelevantNode, SourceControlFlowNode { }
private class MyRelevantNode extends SourceControlFlowNode {
string getOrderDisambiguation() { result = "" }
}
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl::TestOutput<MyRelevantNode>

Просмотреть файл

@ -7,47 +7,35 @@
* @tags ide-contextual-queries/print-cfg
*/
private import codeql.ruby.controlflow.internal.ControlFlowGraphImpl::TestOutput
private import codeql.IDEContextual
private import codeql.Locations
private import codeql.ruby.controlflow.internal.ControlFlowGraphImpl
private import codeql.ruby.controlflow.ControlFlowGraph
/**
* Gets the source file to generate a CFG from.
*/
external string selectedSourceFile();
external string selectedSourceLine();
private predicate selectedSourceFileAlias = selectedSourceFile/0;
external string selectedSourceColumn();
external int selectedSourceLine();
bindingset[file, line, column]
private CfgScope smallestEnclosingScope(File file, int line, int column) {
result =
min(Location loc, CfgScope scope |
loc = scope.getLocation() and
(
loc.getStartLine() < line
or
loc.getStartLine() = line and loc.getStartColumn() <= column
) and
(
loc.getEndLine() > line
or
loc.getEndLine() = line and loc.getEndColumn() >= column
) and
loc.getFile() = file
|
scope
order by
loc.getStartLine() desc, loc.getStartColumn() desc, loc.getEndLine(), loc.getEndColumn()
)
}
private predicate selectedSourceLineAlias = selectedSourceLine/0;
class MyRelevantNode extends RelevantNode {
MyRelevantNode() {
this.getScope() =
smallestEnclosingScope(getFileBySourceArchiveName(selectedSourceFile()),
selectedSourceLine().toInt(), selectedSourceColumn().toInt())
external int selectedSourceColumn();
private predicate selectedSourceColumnAlias = selectedSourceColumn/0;
module ViewCfgQueryInput implements ViewCfgQueryInputSig<File> {
predicate selectedSourceFile = selectedSourceFileAlias/0;
predicate selectedSourceLine = selectedSourceLineAlias/0;
predicate selectedSourceColumn = selectedSourceColumnAlias/0;
predicate cfgScopeSpan(
CfgScope scope, File file, int startLine, int startColumn, int endLine, int endColumn
) {
file = scope.getFile() and
scope.getLocation().hasLocationInfo(_, startLine, startColumn, endLine, endColumn)
}
}
import ViewCfgQuery<File, ViewCfgQueryInput>

Просмотреть файл

@ -3,8 +3,9 @@
*/
import codeql.ruby.CFG
import codeql.ruby.controlflow.internal.ControlFlowGraphImpl::TestOutput
class MyRelevantNode extends RelevantNode {
MyRelevantNode() { exists(this) }
class MyRelevantNode extends CfgNode {
string getOrderDisambiguation() { result = "" }
}
import codeql.ruby.controlflow.internal.ControlFlowGraphImpl::TestOutput<MyRelevantNode>

Просмотреть файл

@ -4,6 +4,7 @@
*/
private import codeql.util.Location
private import codeql.util.FileSystem
/** Provides the language-specific input specification. */
signature module InputSig<LocationSig Location> {
@ -1132,19 +1133,19 @@ module Make<LocationSig Location, InputSig<Location> Input> {
final class AstCfgNode = AstCfgNodeImpl;
/** A node to be included in the output of `TestOutput`. */
signature class RelevantNodeSig extends Node {
/**
* Gets a string used to resolve ties in node and edge ordering.
*/
string getOrderDisambiguation();
}
/**
* Import this module into a `.ql` file of `@kind graph` to render a CFG. The
* graph is restricted to nodes from `RelevantNode`.
*/
module TestOutput {
/** A CFG node to include in the output. */
abstract class RelevantNode extends Node {
/**
* Gets a string used to resolve ties in node and edge ordering.
*/
string getOrderDisambiguation() { result = "" }
}
module TestOutput<RelevantNodeSig RelevantNode> {
/** Holds if `n` is a relevant node in the CFG. */
query predicate nodes(RelevantNode n, string attr, string val) {
attr = "semmle.order" and
@ -1192,6 +1193,78 @@ module Make<LocationSig Location, InputSig<Location> Input> {
}
}
/** Provides the input to `ViewCfgQuery`. */
signature module ViewCfgQueryInputSig<FileSig File> {
/** The source file selected in the IDE. Should be an `external` predicate. */
string selectedSourceFile();
/** The source line selected in the IDE. Should be an `external` predicate. */
int selectedSourceLine();
/** The source column selected in the IDE. Should be an `external` predicate. */
int selectedSourceColumn();
/**
* Holds if CFG scope `scope` spans column `startColumn` of line `startLine` to
* column `endColumn` of line `endLine` in `file`.
*/
predicate cfgScopeSpan(
CfgScope scope, File file, int startLine, int startColumn, int endLine, int endColumn
);
}
/**
* Provides an implementation for a `View CFG` query.
*
* Import this module into a `.ql` that looks like
*
* ```ql
* @name Print CFG
* @description Produces a representation of a file's Control Flow Graph.
* This query is used by the VS Code extension.
* @id <lang>/print-cfg
* @kind graph
* @tags ide-contextual-queries/print-cfg
* ```
*/
module ViewCfgQuery<FileSig File, ViewCfgQueryInputSig<File> ViewCfgQueryInput> {
private import ViewCfgQueryInput
bindingset[file, line, column]
private CfgScope smallestEnclosingScope(File file, int line, int column) {
result =
min(CfgScope scope, int startLine, int startColumn, int endLine, int endColumn |
cfgScopeSpan(scope, file, startLine, startColumn, endLine, endColumn) and
(
startLine < line
or
startLine = line and startColumn <= column
) and
(
endLine > line
or
endLine = line and endColumn >= column
)
|
scope order by startLine desc, startColumn desc, endLine, endColumn
)
}
private import IdeContextual<File>
private class RelevantNode extends Node {
RelevantNode() {
this.getScope() =
smallestEnclosingScope(getFileBySourceArchiveName(selectedSourceFile()),
selectedSourceLine(), selectedSourceColumn())
}
string getOrderDisambiguation() { result = "" }
}
import TestOutput<RelevantNode>
}
/** Provides a set of consistency queries. */
module Consistency {
/** Holds if `s1` and `s2` are distinct representations of the same set. */

Просмотреть файл

@ -7,52 +7,45 @@
* @tags ide-contextual-queries/print-cfg
*/
private import codeql.IDEContextual
private import codeql.swift.elements.File
private import codeql.swift.controlflow.ControlFlowGraph
private import codeql.swift.controlflow.internal.ControlFlowGraphImpl::TestOutput
private import codeql.swift.controlflow.internal.ControlFlowGraphImpl as Impl
private import codeql.swift.controlflow.internal.ControlFlowGraphImplSpecific
/**
* Gets the source file to generate a CFG from.
*/
external string selectedSourceFile();
private predicate selectedSourceFileAlias = selectedSourceFile/0;
/**
* Gets the source line to generate a CFG from.
*/
external string selectedSourceLine();
external int selectedSourceLine();
private predicate selectedSourceLineAlias = selectedSourceLine/0;
/**
* Gets the source column to generate a CFG from.
*/
external string selectedSourceColumn();
external int selectedSourceColumn();
bindingset[file, line, column]
private CfgScope smallestEnclosingScope(File file, int line, int column) {
result =
min(Location loc, CfgScope scope |
loc = scope.getLocation() and
(
loc.getStartLine() < line
or
loc.getStartLine() = line and loc.getStartColumn() <= column
) and
(
loc.getEndLine() > line
or
loc.getEndLine() = line and loc.getEndColumn() >= column
) and
loc.getFile() = file
|
scope
order by
loc.getStartLine() desc, loc.getStartColumn() desc, loc.getEndLine(), loc.getEndColumn()
)
}
private predicate selectedSourceColumnAlias = selectedSourceColumn/0;
class MyRelevantNode extends RelevantNode {
MyRelevantNode() {
this.getScope() =
smallestEnclosingScope(getFileBySourceArchiveName(selectedSourceFile()),
selectedSourceLine().toInt(), selectedSourceColumn().toInt())
module ViewCfgQueryInput implements Impl::ViewCfgQueryInputSig<File> {
predicate selectedSourceFile = selectedSourceFileAlias/0;
predicate selectedSourceLine = selectedSourceLineAlias/0;
predicate selectedSourceColumn = selectedSourceColumnAlias/0;
predicate cfgScopeSpan(
CfgInput::CfgScope scope, File file, int startLine, int startColumn, int endLine, int endColumn
) {
file = scope.getFile() and
scope.getLocation().hasLocationInfo(_, startLine, startColumn, endLine, endColumn)
}
}
import Impl::ViewCfgQuery<File, ViewCfgQueryInput>

Просмотреть файл

@ -4,16 +4,17 @@
import swift
import codeql.swift.controlflow.ControlFlowGraph
import codeql.swift.controlflow.internal.ControlFlowGraphImpl::TestOutput
class MyRelevantNode extends RelevantNode {
class MyRelevantNode extends ControlFlowNode {
MyRelevantNode() { this.getScope().getLocation().getFile().getName().matches("%swift/ql/test%") }
private AstNode asAstNode() { result = this.getAstNode().asAstNode() }
override string getOrderDisambiguation() {
string getOrderDisambiguation() {
result = this.asAstNode().getPrimaryQlClasses()
or
not exists(this.asAstNode()) and result = ""
}
}
import codeql.swift.controlflow.internal.ControlFlowGraphImpl::TestOutput<MyRelevantNode>