Skip to content

Commit e76dc4a

Browse files
committed
C++: Support printing of global and namespace variables in PrintAST
1 parent 2a63116 commit e76dc4a

File tree

5 files changed

+183
-44
lines changed

5 files changed

+183
-44
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: majorAnalysis
3+
---
4+
* The `PrintAST` library now also prints global and namespace variables and their initializers.

cpp/ql/lib/semmle/code/cpp/Print.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ private import PrintAST
66
* that requests that function, or no `PrintASTConfiguration` exists.
77
*/
88
private predicate shouldPrintDeclaration(Declaration decl) {
9-
not decl instanceof Function
9+
not (decl instanceof Function or decl instanceof GlobalOrNamespaceVariable)
1010
or
1111
not exists(PrintAstConfiguration c)
1212
or

cpp/ql/lib/semmle/code/cpp/PrintAST.qll

Lines changed: 67 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/**
22
* Provides queries to pretty-print a C++ AST as a graph.
33
*
4-
* By default, this will print the AST for all functions in the database. To change this behavior,
5-
* extend `PrintASTConfiguration` and override `shouldPrintDeclaration` to hold for only the
6-
* declarations you wish to view the AST for.
4+
* By default, this will print the AST for all functions and global and namespace variables in
5+
* the database. To change this behavior, extend `PrintASTConfiguration` and override
6+
* `shouldPrintDeclaration` to hold for only the declarations you wish to view the AST for.
77
*/
88

99
import cpp
@@ -22,16 +22,15 @@ class PrintAstConfiguration extends TPrintAstConfiguration {
2222

2323
/**
2424
* Holds if the AST for `decl` should be printed. By default, holds for all
25-
* functions. Currently, does not support any other declaration types.
25+
* functions and global and namespace variables. Currently, does not support any
26+
* other declaration types.
2627
*/
2728
predicate shouldPrintDeclaration(Declaration decl) { any() }
2829
}
2930

3031
private predicate shouldPrintDeclaration(Declaration decl) {
31-
exists(PrintAstConfiguration config |
32-
config.shouldPrintDeclaration(decl) and
33-
decl instanceof Function
34-
)
32+
exists(PrintAstConfiguration config | config.shouldPrintDeclaration(decl)) and
33+
(decl instanceof Function or decl instanceof GlobalOrNamespaceVariable)
3534
}
3635

3736
bindingset[s]
@@ -72,7 +71,7 @@ private predicate locationSortKeys(Locatable ast, string file, int line, int col
7271
)
7372
}
7473

75-
private Function getEnclosingFunction(Locatable ast) {
74+
private Declaration getEnclosingDeclaration(Locatable ast) {
7675
result = ast.(Expr).getEnclosingFunction()
7776
or
7877
result = ast.(Stmt).getEnclosingFunction()
@@ -81,6 +80,10 @@ private Function getEnclosingFunction(Locatable ast) {
8180
or
8281
result = ast.(Parameter).getFunction()
8382
or
83+
result = ast.(Expr).getEnclosingDeclaration()
84+
or
85+
result = ast.(Initializer).getDeclaration()
86+
or
8487
result = ast
8588
}
8689

@@ -89,7 +92,7 @@ private Function getEnclosingFunction(Locatable ast) {
8992
* nodes for things like parameter lists and constructor init lists.
9093
*/
9194
private newtype TPrintAstNode =
92-
TAstNode(Locatable ast) { shouldPrintDeclaration(getEnclosingFunction(ast)) } or
95+
TAstNode(Locatable ast) { shouldPrintDeclaration(getEnclosingDeclaration(ast)) } or
9396
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
9497
// We create a unique node for each pair of (stmt, entry), to avoid having one node with
9598
// multiple parents due to extractor bug CPP-413.
@@ -161,10 +164,10 @@ class PrintAstNode extends TPrintAstNode {
161164

162165
/**
163166
* Holds if this node should be printed in the output. By default, all nodes
164-
* within a function are printed, but the query can override
165-
* `PrintASTConfiguration.shouldPrintDeclaration` to filter the output.
167+
* within functions and global and namespace variables are printed, but the query
168+
* can override `PrintASTConfiguration.shouldPrintDeclaration` to filter the output.
166169
*/
167-
final predicate shouldPrint() { shouldPrintDeclaration(this.getEnclosingFunction()) }
170+
final predicate shouldPrint() { shouldPrintDeclaration(this.getEnclosingDeclaration()) }
168171

169172
/**
170173
* Gets the children of this node.
@@ -232,10 +235,15 @@ class PrintAstNode extends TPrintAstNode {
232235
abstract string getChildAccessorPredicateInternal(int childIndex);
233236

234237
/**
235-
* Gets the `Function` that contains this node.
238+
* Gets the `Declaration` that contains this node.
236239
*/
237-
private Function getEnclosingFunction() {
238-
result = this.getParent*().(FunctionNode).getFunction()
240+
private Declaration getEnclosingDeclaration() { result = this.getParent*().getDeclaration() }
241+
242+
/**
243+
* Gets the `Declaration` this node represents.
244+
*/
245+
private Declaration getDeclaration() {
246+
result = this.(AstNode).getAst() and shouldPrintDeclaration(result)
239247
}
240248
}
241249

@@ -574,16 +582,53 @@ class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNo
574582
final Destructor getDestructor() { result = dtor }
575583
}
576584

585+
abstract private class FunctionOrGlobalOrNamespaceVariableNode extends AstNode {
586+
override string toString() { result = qlClass(ast) + getIdentityString(ast) }
587+
588+
private int getOrder() {
589+
this =
590+
rank[result](FunctionOrGlobalOrNamespaceVariableNode node, Declaration decl, string file,
591+
int line, int column |
592+
node.getAst() = decl and
593+
locationSortKeys(decl, file, line, column)
594+
|
595+
node order by file, line, column, getIdentityString(decl)
596+
)
597+
}
598+
599+
override string getProperty(string key) {
600+
result = super.getProperty(key)
601+
or
602+
key = "semmle.order" and result = this.getOrder().toString()
603+
}
604+
}
605+
606+
/**
607+
* A node representing a `GlobalOrNamespaceVariable`.
608+
*/
609+
class GlobalOrNamespaceVariableNode extends FunctionOrGlobalOrNamespaceVariableNode {
610+
GlobalOrNamespaceVariable var;
611+
612+
GlobalOrNamespaceVariableNode() { var = ast }
613+
614+
override PrintAstNode getChildInternal(int childIndex) {
615+
childIndex = 0 and
616+
result.(AstNode).getAst() = var.getInitializer()
617+
}
618+
619+
override string getChildAccessorPredicateInternal(int childIndex) {
620+
childIndex = 0 and result = "getInitializer()"
621+
}
622+
}
623+
577624
/**
578625
* A node representing a `Function`.
579626
*/
580-
class FunctionNode extends AstNode {
627+
class FunctionNode extends FunctionOrGlobalOrNamespaceVariableNode {
581628
Function func;
582629

583630
FunctionNode() { func = ast }
584631

585-
override string toString() { result = qlClass(func) + getIdentityString(func) }
586-
587632
override PrintAstNode getChildInternal(int childIndex) {
588633
childIndex = 0 and
589634
result.(ParametersNode).getFunction() = func
@@ -607,31 +652,10 @@ class FunctionNode extends AstNode {
607652
or
608653
childIndex = 3 and result = "<destructions>"
609654
}
610-
611-
private int getOrder() {
612-
this =
613-
rank[result](FunctionNode node, Function function, string file, int line, int column |
614-
node.getAst() = function and
615-
locationSortKeys(function, file, line, column)
616-
|
617-
node order by file, line, column, getIdentityString(function)
618-
)
619-
}
620-
621-
override string getProperty(string key) {
622-
result = super.getProperty(key)
623-
or
624-
key = "semmle.order" and result = this.getOrder().toString()
625-
}
626-
627-
/**
628-
* Gets the `Function` this node represents.
629-
*/
630-
final Function getFunction() { result = func }
631655
}
632656

633657
private string getChildAccessorWithoutConversions(Locatable parent, Element child) {
634-
shouldPrintDeclaration(getEnclosingFunction(parent)) and
658+
shouldPrintDeclaration(getEnclosingDeclaration(parent)) and
635659
(
636660
exists(Stmt s | s = parent |
637661
namedStmtChildPredicates(s, child, result)
@@ -650,7 +674,7 @@ private string getChildAccessorWithoutConversions(Locatable parent, Element chil
650674
}
651675

652676
private predicate namedStmtChildPredicates(Locatable s, Element e, string pred) {
653-
shouldPrintDeclaration(getEnclosingFunction(s)) and
677+
shouldPrintDeclaration(getEnclosingDeclaration(s)) and
654678
(
655679
exists(int n | s.(BlockStmt).getStmt(n) = e and pred = "getStmt(" + n + ")")
656680
or
@@ -738,7 +762,7 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
738762
}
739763

740764
private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) {
741-
shouldPrintDeclaration(expr.getEnclosingFunction()) and
765+
shouldPrintDeclaration(expr.getEnclosingDeclaration()) and
742766
(
743767
expr.(Access).getTarget() = ele and pred = "getTarget()"
744768
or

cpp/ql/test/examples/expressions/PrintAST.expected

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,6 +1308,11 @@ union_etc.cpp:
13081308
# 6| Type = [IntType] int
13091309
# 6| ValueCategory = prvalue(load)
13101310
# 6| getStmt(1): [ReturnStmt] return ...
1311+
# 7| [GlobalVariable] S s
1312+
# 7| getInitializer(): [Initializer] initializer for s
1313+
# 7| getExpr(): [ConstructorCall] call to S
1314+
# 7| Type = [VoidType] void
1315+
# 7| ValueCategory = prvalue
13111316
# 9| [CopyAssignmentOperator] C& C::operator=(C const&)
13121317
# 9| <params>:
13131318
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -1332,6 +1337,7 @@ union_etc.cpp:
13321337
# 12| <params>:
13331338
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
13341339
#-----| Type = [RValueReferenceType] U &&
1340+
# 14| [GlobalVariable] C c
13351341
# 16| [CopyAssignmentOperator] U& U::operator=(U const&)
13361342
# 16| <params>:
13371343
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -1356,6 +1362,7 @@ union_etc.cpp:
13561362
# 18| <params>:
13571363
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
13581364
#-----| Type = [RValueReferenceType] C &&
1365+
# 20| [GlobalVariable] U u
13591366
# 22| [TopLevelFunction] int foo()
13601367
# 22| <params>:
13611368
# 22| getEntryPoint(): [BlockStmt] { ... }

cpp/ql/test/library-tests/ir/ir/PrintAST.expected

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8529,6 +8529,11 @@ ir.cpp:
85298529
# 1035| Type = [Struct] EmptyStruct
85308530
# 1035| ValueCategory = prvalue
85318531
# 1036| getStmt(1): [ReturnStmt] return ...
8532+
# 1038| [GlobalVariable] (lambda [] type at line 1038, col. 12) lam
8533+
# 1038| getInitializer(): [Initializer] initializer for lam
8534+
# 1038| getExpr(): [LambdaExpression] [...](...){...}
8535+
# 1038| Type = [Closure] decltype([...](...){...})
8536+
# 1038| ValueCategory = prvalue
85328537
# 1038| [CopyAssignmentOperator] (lambda [] type at line 1038, col. 12)& (lambda [] type at line 1038, col. 12)::operator=((lambda [] type at line 1038, col. 12) const&)
85338538
# 1038| <params>:
85348539
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -13976,6 +13981,54 @@ ir.cpp:
1397613981
# 1815| Type = [IntType] int
1397713982
# 1815| ValueCategory = prvalue(load)
1397813983
# 1817| getStmt(8): [ReturnStmt] return ...
13984+
# 1821| [GlobalVariable] int global_2
13985+
# 1821| getInitializer(): [Initializer] initializer for global_2
13986+
# 1821| getExpr(): [Literal] 1
13987+
# 1821| Type = [IntType] int
13988+
# 1821| Value = [Literal] 1
13989+
# 1821| ValueCategory = prvalue
13990+
# 1823| [GlobalVariable] int const global_3
13991+
# 1823| getInitializer(): [Initializer] initializer for global_3
13992+
# 1823| getExpr(): [Literal] 2
13993+
# 1823| Type = [IntType] int
13994+
# 1823| Value = [Literal] 2
13995+
# 1823| ValueCategory = prvalue
13996+
# 1825| [GlobalVariable] constructor_only global_4
13997+
# 1825| getInitializer(): [Initializer] initializer for global_4
13998+
# 1825| getExpr(): [ConstructorCall] call to constructor_only
13999+
# 1825| Type = [VoidType] void
14000+
# 1825| ValueCategory = prvalue
14001+
# 1825| getArgument(0): [Literal] 1
14002+
# 1825| Type = [IntType] int
14003+
# 1825| Value = [Literal] 1
14004+
# 1825| ValueCategory = prvalue
14005+
# 1827| [GlobalVariable] constructor_only global_5
14006+
# 1827| getInitializer(): [Initializer] initializer for global_5
14007+
# 1827| getExpr(): [ConstructorCall] call to constructor_only
14008+
# 1827| Type = [VoidType] void
14009+
# 1827| ValueCategory = prvalue
14010+
# 1827| getArgument(0): [Literal] 2
14011+
# 1827| Type = [IntType] int
14012+
# 1827| Value = [Literal] 2
14013+
# 1827| ValueCategory = prvalue
14014+
# 1829| [GlobalVariable] char* global_string
14015+
# 1829| getInitializer(): [Initializer] initializer for global_string
14016+
# 1829| getExpr(): global string
14017+
# 1829| Type = [ArrayType] const char[14]
14018+
# 1829| Value = [StringLiteral] "global string"
14019+
# 1829| ValueCategory = lvalue
14020+
# 1829| getExpr().getFullyConverted(): [CStyleCast] (char *)...
14021+
# 1829| Conversion = [PointerConversion] pointer conversion
14022+
# 1829| Type = [CharPointerType] char *
14023+
# 1829| ValueCategory = prvalue
14024+
# 1829| getExpr(): [ArrayToPointerConversion] array to pointer conversion
14025+
# 1829| Type = [PointerType] const char *
14026+
# 1829| ValueCategory = prvalue
14027+
# 1831| [GlobalVariable] int global_6
14028+
# 1831| getInitializer(): [Initializer] initializer for global_6
14029+
# 1831| getExpr(): [VariableAccess] global_2
14030+
# 1831| Type = [IntType] int
14031+
# 1831| ValueCategory = prvalue(load)
1397914032
# 1834| [CopyAssignmentOperator] block_assignment::A& block_assignment::A::operator=(block_assignment::A const&)
1398014033
# 1834| <params>:
1398114034
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -14377,6 +14430,23 @@ ir.cpp:
1437714430
# 1885| Type = [ClassTemplateInstantiation,Struct] Bar2<int>
1437814431
# 1885| ValueCategory = lvalue
1437914432
# 1886| getStmt(2): [ReturnStmt] return ...
14433+
# 1889| [GlobalVariable] char global_template<char>
14434+
# 1889| getInitializer(): [Initializer] initializer for global_template
14435+
# 1889| getExpr(): [Literal] 42
14436+
# 1889| Type = [IntType] int
14437+
# 1889| Value = [Literal] 42
14438+
# 1889| ValueCategory = prvalue
14439+
# 1889| getExpr().getFullyConverted(): [CStyleCast] (char)...
14440+
# 1889| Conversion = [IntegralConversion] integral conversion
14441+
# 1889| Type = [PlainCharType] char
14442+
# 1889| Value = [CStyleCast] 42
14443+
# 1889| ValueCategory = prvalue
14444+
# 1889| [GlobalVariable] int global_template<int>
14445+
# 1889| getInitializer(): [Initializer] initializer for global_template
14446+
# 1889| getExpr(): [Literal] 42
14447+
# 1889| Type = [IntType] int
14448+
# 1889| Value = [Literal] 42
14449+
# 1889| ValueCategory = prvalue
1438014450
# 1891| [TopLevelFunction] int test_global_template_int()
1438114451
# 1891| <params>:
1438214452
# 1891| getEntryPoint(): [BlockStmt] { ... }
@@ -15170,6 +15240,40 @@ struct_init.cpp:
1517015240
# 4| <params>:
1517115241
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
1517215242
#-----| Type = [RValueReferenceType] Info &&
15243+
# 9| [GlobalVariable] Info infos_in_file[]
15244+
# 9| getInitializer(): [Initializer] initializer for infos_in_file
15245+
# 9| getExpr(): [ArrayAggregateLiteral] {...}
15246+
# 9| Type = [ArrayType] Info[2]
15247+
# 9| ValueCategory = prvalue
15248+
# 10| getAnElementExpr(0): [ClassAggregateLiteral] {...}
15249+
# 10| Type = [Struct] Info
15250+
# 10| ValueCategory = prvalue
15251+
# 10| getAFieldExpr(name): 1
15252+
# 10| Type = [ArrayType] const char[2]
15253+
# 10| Value = [StringLiteral] "1"
15254+
# 10| ValueCategory = lvalue
15255+
# 10| getAFieldExpr(handler): [FunctionAccess] handler1
15256+
# 10| Type = [FunctionPointerType] ..(*)(..)
15257+
# 10| ValueCategory = prvalue(load)
15258+
# 10| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
15259+
# 10| Type = [PointerType] const char *
15260+
# 10| ValueCategory = prvalue
15261+
# 11| getAnElementExpr(1): [ClassAggregateLiteral] {...}
15262+
# 11| Type = [Struct] Info
15263+
# 11| ValueCategory = prvalue
15264+
# 11| getAFieldExpr(name): 3
15265+
# 11| Type = [ArrayType] const char[2]
15266+
# 11| Value = [StringLiteral] "3"
15267+
# 11| ValueCategory = lvalue
15268+
# 11| getAFieldExpr(handler): [AddressOfExpr] & ...
15269+
# 11| Type = [FunctionPointerType] ..(*)(..)
15270+
# 11| ValueCategory = prvalue
15271+
# 11| getOperand(): [FunctionAccess] handler2
15272+
# 11| Type = [RoutineType] ..()(..)
15273+
# 11| ValueCategory = lvalue
15274+
# 11| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
15275+
# 11| Type = [PointerType] const char *
15276+
# 11| ValueCategory = prvalue
1517315277
# 16| [TopLevelFunction] void let_info_escape(Info*)
1517415278
# 16| <params>:
1517515279
# 16| getParameter(0): [Parameter] info

0 commit comments

Comments
 (0)