77 */
88
99import go
10- import semmle.go.PrintAst
1110
1211/**
1312 * Gets the source files to generate AST from.
@@ -34,25 +33,142 @@ File getSelectedFile() {
3433 // Match by file name if no path separators
3534 ( not selectedFile .matches ( "%/%" ) and result .getBaseName ( ) = selectedFile ) or
3635 // Match by ending path component
37- result .getAbsolutePath ( ) .suffix ( result .getAbsolutePath ( ) .length ( ) - selectedFile .length ( ) ) = selectedFile
36+ result .getAbsolutePath ( ) .suffix ( result .getAbsolutePath ( ) .length ( ) - selectedFile .length ( ) ) =
37+ selectedFile
3838 )
3939 )
4040}
4141
4242/**
43- * Configuration for PrintAST that uses external predicates to specify source files .
44- * Falls back to test file selection when external predicates are not available .
43+ * Holds if the given file should be printed .
44+ * Uses the external predicate if available, otherwise falls back to test files .
4545 */
46- class Cfg extends PrintAstConfiguration {
47- override predicate shouldPrintFunction ( FuncDecl func ) { this .shouldPrintFile ( func .getFile ( ) ) }
46+ private predicate isSelectedFile ( File file ) {
47+ file = getSelectedFile ( )
48+ or
49+ not exists ( getSelectedFile ( ) ) and file .getBaseName ( ) = "Example1.go"
50+ }
51+
52+ // Standalone PrintAST implementation for Go.
53+ //
54+ // This avoids extending the library's `PrintAstConfiguration` (which is inside
55+ // an `overlay[local]` module in `go-all`) by directly using the Go AST API.
56+ // File filtering is applied at the source level for efficiency.
57+
58+ /** Gets the enclosing function declaration for `n`, if any. */
59+ private FuncDecl getEnclosingFunctionDecl ( AstNode n ) { result = n .getParent * ( ) }
60+
61+ /**
62+ * Holds if `ast` should be included in the printed AST.
63+ * Restricts to selected files and excludes comments for deterministic output.
64+ */
65+ private predicate shouldPrint ( AstNode ast ) {
66+ isSelectedFile ( ast .getFile ( ) ) and
67+ // Print nodes without an enclosing function (e.g. file headers)
68+ forall ( FuncDecl f | f = getEnclosingFunctionDecl ( ast ) | isSelectedFile ( f .getFile ( ) ) ) and
69+ // Exclude comments for deterministic output
70+ not ast instanceof Comment and
71+ not ast instanceof CommentGroup and
72+ exists ( ast .getLocation ( ) )
73+ }
4874
49- override predicate shouldPrintFile ( File file ) {
50- // Use external predicate if available
51- file = getSelectedFile ( )
75+ /** Gets the QL class label for an AST node. */
76+ private string qlClass ( AstNode el ) {
77+ result = "[" + concat ( el .getAPrimaryQlClass ( ) , ", " ) + "] "
78+ }
79+
80+ /** Gets the default string representation for an AST node. */
81+ private string nodeToString ( AstNode ast ) {
82+ if ast instanceof File
83+ then result = qlClass ( ast ) + ast .( File ) .getRelativePath ( )
84+ else result = qlClass ( ast ) + ast .toString ( )
85+ }
86+
87+ /**
88+ * Gets the child at `childIndex` for `ast`, with special handling
89+ * for `File` nodes (package name expression is moved to index 0).
90+ * Comments are excluded from the child list.
91+ */
92+ private AstNode getChild ( AstNode ast , int childIndex ) {
93+ if ast instanceof File and exists ( ast .( File ) .getPackageNameExpr ( ) )
94+ then
95+ exists ( AstNode packageNode , int oldPackageIndex |
96+ ast .getUniquelyNumberedChild ( oldPackageIndex ) = packageNode and
97+ packageNode = ast .( File ) .getPackageNameExpr ( ) and
98+ (
99+ childIndex = 0 and result = packageNode
100+ or
101+ result =
102+ rank [ childIndex ] ( AstNode node , int i |
103+ node = ast .getUniquelyNumberedChild ( i ) and
104+ i != oldPackageIndex and
105+ not node instanceof Comment and
106+ not node instanceof CommentGroup
107+ |
108+ node order by i
109+ )
110+ )
111+ )
112+ else (
113+ result =
114+ rank [ childIndex ] ( AstNode node , int i |
115+ node = ast .getUniquelyNumberedChild ( i ) and
116+ not node instanceof Comment and
117+ not node instanceof CommentGroup
118+ |
119+ node order by i
120+ )
121+ )
122+ }
123+
124+ /** Gets the edge label from `ast` to its child at `childIndex`. */
125+ private string getChildEdgeLabel ( AstNode ast , int childIndex ) {
126+ exists ( getChild ( ast , childIndex ) ) and
127+ if
128+ ast instanceof File and
129+ exists ( ast .( File ) .getPackageNameExpr ( ) ) and
130+ getChild ( ast , childIndex ) = ast .( File ) .getPackageNameExpr ( )
131+ then result = "package"
132+ else result = childIndex .toString ( )
133+ }
134+
135+ /** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
136+ query predicate nodes ( AstNode node , string key , string value ) {
137+ shouldPrint ( node ) and
138+ (
139+ key = "semmle.label" and value = nodeToString ( node )
140+ or
141+ node instanceof Expr and
142+ (
143+ key = "Value" and
144+ value = qlClass ( node ) + node .( Expr ) .getExactValue ( )
145+ or
146+ key = "Type" and
147+ not node .( Expr ) .getType ( ) instanceof InvalidType and
148+ value = node .( Expr ) .getType ( ) .pp ( )
149+ )
52150 or
53- // Fallback for unit tests: include specific test files
54- ( not exists ( getSelectedFile ( ) ) and file .getBaseName ( ) = "Example1.go" )
55- }
151+ node instanceof File and
152+ key = "semmle.order" and
153+ value = any ( int i | node = rank [ i ] ( File fn | isSelectedFile ( fn ) | fn order by fn .getRelativePath ( ) ) | i ) .toString ( )
154+ )
155+ }
156+
157+ /** Holds if `target` is a child of `source` in the AST. */
158+ query predicate edges ( AstNode source , AstNode target , string key , string value ) {
159+ shouldPrint ( source ) and
160+ shouldPrint ( target ) and
161+ exists ( int childIndex |
162+ target = getChild ( source , childIndex ) and
163+ (
164+ key = "semmle.label" and value = getChildEdgeLabel ( source , childIndex )
165+ or
166+ key = "semmle.order" and value = childIndex .toString ( )
167+ )
168+ )
169+ }
56170
57- override predicate shouldPrintComments ( File file ) { none ( ) }
171+ /** Holds if property `key` of the graph has the given `value`. */
172+ query predicate graphProperties ( string key , string value ) {
173+ key = "semmle.graphKind" and value = "tree"
58174}
0 commit comments