Skip to content

Commit 47b905b

Browse files
committed
Swift: add PrintAst
1 parent 6914c44 commit 47b905b

21 files changed

+1908
-6
lines changed

config/identical-files.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -584,19 +584,19 @@
584584
],
585585
"Swift declarations test file": [
586586
"swift/ql/test/extractor-tests/declarations/declarations.swift",
587-
"swift/ql/test/library-tests/parent/declarations.swift"
587+
"swift/ql/test/library-tests/ast/declarations.swift"
588588
],
589589
"Swift statements test file": [
590590
"swift/ql/test/extractor-tests/statements/statements.swift",
591-
"swift/ql/test/library-tests/parent/statements.swift"
591+
"swift/ql/test/library-tests/ast/statements.swift"
592592
],
593593
"Swift expressions test file": [
594594
"swift/ql/test/extractor-tests/expressions/expressions.swift",
595-
"swift/ql/test/library-tests/parent/expressions.swift"
595+
"swift/ql/test/library-tests/ast/expressions.swift"
596596
],
597597
"Swift patterns test file": [
598598
"swift/ql/test/extractor-tests/patterns/patterns.swift",
599-
"swift/ql/test/library-tests/parent/patterns.swift"
599+
"swift/ql/test/library-tests/ast/patterns.swift"
600600
],
601601
"IncompleteMultiCharacterSanitization JS/Ruby": [
602602
"javascript/ql/lib/semmle/javascript/security/IncompleteMultiCharacterSanitizationQuery.qll",
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
21
private import codeql.swift.generated.Raw
32

4-
predicate constructArgument(Raw::Argument id) { any() }
3+
predicate constructArgument(Raw::Argument id) {
4+
// exclude an argument that will be part of a DotSyntaxCallExpr
5+
// that will be transformed into a MethodRefCallExpr
6+
not exists(Raw::DotSyntaxCallExpr c |
7+
c.getFunction() instanceof Raw::DeclRefExpr and id = c.getArgument(0)
8+
)
9+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/**
2+
* Provides queries to pretty-print a Go AST as a graph.
3+
*/
4+
5+
import swift
6+
import codeql.swift.generated.ParentChild
7+
8+
/**
9+
* Hook to customize the files and functions printed by this module.
10+
*
11+
* For an AstNode to be printed, it always requires `shouldPrintFile(f)` to hold
12+
* for its containing file `f`, and additionally requires `shouldPrintFunction(fun)`
13+
* to hold if it is, or is a child of, function `fun`.
14+
*/
15+
class PrintAstConfiguration extends string {
16+
/**
17+
* Restrict to a single string, making this a singleton type.
18+
*/
19+
PrintAstConfiguration() { this = "PrintAstConfiguration" }
20+
21+
/**
22+
* Holds if the AST for `e` should be printed. By default, holds for all.
23+
*/
24+
predicate shouldPrint(Locatable e) { any() }
25+
}
26+
27+
private predicate shouldPrint(Locatable e) { any(PrintAstConfiguration config).shouldPrint(e) }
28+
29+
/**
30+
* An AST node that should be printed.
31+
*/
32+
private newtype TPrintAstNode =
33+
TLocatable(Locatable ast) {
34+
// Only consider resolved nodes (that is not within the hidden conversion AST)
35+
ast = ast.resolve()
36+
}
37+
38+
/**
39+
* A node in the output tree.
40+
*/
41+
class PrintAstNode extends TPrintAstNode {
42+
/**
43+
* Gets a textual representation of this node.
44+
*/
45+
abstract string toString();
46+
47+
/**
48+
* Gets the child node at index `index`. Child indices must be unique,
49+
* but need not be contiguous.
50+
*/
51+
abstract predicate hasChild(PrintAstNode child, int index, string accessor);
52+
53+
/**
54+
* Holds if this node should be printed in the output.
55+
*/
56+
abstract predicate shouldBePrinted();
57+
58+
/**
59+
* Gets the location of this node in the source code.
60+
*/
61+
abstract Location getLocation();
62+
63+
/**
64+
* Gets the value of an additional property of this node, where the name of
65+
* the property is `key`.
66+
*/
67+
string getProperty(string key) { none() }
68+
}
69+
70+
/**
71+
* A graph node representing a real Locatable node.
72+
*/
73+
class PrintLocatable extends PrintAstNode, TLocatable {
74+
Locatable ast;
75+
76+
PrintLocatable() { this = TLocatable(ast) }
77+
78+
final override predicate shouldBePrinted() { shouldPrint(ast) }
79+
80+
override predicate hasChild(PrintAstNode child, int index, string accessor) {
81+
child = TLocatable(getChildAndAccessor(ast, index, accessor))
82+
}
83+
84+
override string toString() { result = "[" + concat(ast.getPrimaryQlClasses(), ", ") + "] " + ast }
85+
86+
final override Location getLocation() { result = ast.getLocation() }
87+
}
88+
89+
cached
90+
private int getOrder(PrintAstNode node) {
91+
node =
92+
rank[result](PrintAstNode n, Location loc |
93+
loc = n.getLocation()
94+
|
95+
n
96+
order by
97+
loc.getFile().getName(), loc.getStartLine(), loc.getStartColumn(), loc.getEndLine(),
98+
loc.getEndColumn()
99+
)
100+
}
101+
102+
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
103+
query predicate nodes(PrintAstNode node, string key, string value) {
104+
node.shouldBePrinted() and
105+
(
106+
key = "semmle.label" and value = node.toString()
107+
or
108+
key = "semmle.order" and value = getOrder(node).toString()
109+
or
110+
value = node.getProperty(key)
111+
)
112+
}
113+
114+
/**
115+
* Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the
116+
* given `value`.
117+
*/
118+
query predicate edges(PrintAstNode source, PrintAstNode target, string key, string value) {
119+
source.shouldBePrinted() and
120+
target.shouldBePrinted() and
121+
exists(int index, string accessor | source.hasChild(target, index, accessor) |
122+
key = "semmle.label" and value = accessor
123+
or
124+
key = "semmle.order" and value = index.toString()
125+
)
126+
}
127+
128+
/** Holds if property `key` of the graph has the given `value`. */
129+
query predicate graphProperties(string key, string value) {
130+
key = "semmle.graphKind" and value = "tree"
131+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Provides shared predicates related to contextual queries in the code viewer.
3+
*/
4+
5+
import swift
6+
7+
/**
8+
* Returns the `File` matching the given source file name as encoded by the VS
9+
* Code extension.
10+
*/
11+
cached
12+
File getFileBySourceArchiveName(string name) {
13+
// The name provided for a file in the source archive by the VS Code extension
14+
// has some differences from the absolute path in the database:
15+
// 1. colons are replaced by underscores
16+
// 2. there's a leading slash, even for Windows paths: "C:/foo/bar" ->
17+
// "/C_/foo/bar"
18+
// 3. double slashes in UNC prefixes are replaced with a single slash
19+
// We can handle 2 and 3 together by unconditionally adding a leading slash
20+
// before replacing double slashes.
21+
name = ("/" + result.getAbsolutePath().replaceAll(":", "_")).replaceAll("//", "/")
22+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* @name Print AST
3+
* @description Outputs a representation of a file's Abstract Syntax Tree. This
4+
* query is used by the VS Code extension.
5+
* @id swift/print-ast
6+
* @kind graph
7+
* @tags ide-contextual-queries/print-ast
8+
*/
9+
10+
import swift
11+
import codeql.swift.printast.PrintAst
12+
import IDEContextual
13+
14+
/**
15+
* The source file to generate an AST from.
16+
*/
17+
external string selectedSourceFile();
18+
19+
class PrintAstConfigurationOverride extends PrintAstConfiguration {
20+
/**
21+
* Holds if the location matches the selected file in the VS Code extension and
22+
* the element is `fromSource`.
23+
*/
24+
override predicate shouldPrint(Locatable e) {
25+
super.shouldPrint(e) and
26+
e.getFile() = getFileBySourceArchiveName(selectedSourceFile())
27+
}
28+
}

0 commit comments

Comments
 (0)