C++: Support printing of global and namespace variables in PrintAST

This commit is contained in:
Jeroen Ketema
2023-07-19 17:41:27 +02:00
parent 2a63116fc2
commit e76dc4a1f9
5 changed files with 183 additions and 44 deletions

View File

@@ -0,0 +1,4 @@
---
category: majorAnalysis
---
* The `PrintAST` library now also prints global and namespace variables and their initializers.

View File

@@ -6,7 +6,7 @@ private import PrintAST
* that requests that function, or no `PrintASTConfiguration` exists.
*/
private predicate shouldPrintDeclaration(Declaration decl) {
not decl instanceof Function
not (decl instanceof Function or decl instanceof GlobalOrNamespaceVariable)
or
not exists(PrintAstConfiguration c)
or

View File

@@ -1,9 +1,9 @@
/**
* Provides queries to pretty-print a C++ AST as a graph.
*
* By default, this will print the AST for all functions in the database. To change this behavior,
* extend `PrintASTConfiguration` and override `shouldPrintDeclaration` to hold for only the
* declarations you wish to view the AST for.
* By default, this will print the AST for all functions and global and namespace variables in
* the database. To change this behavior, extend `PrintASTConfiguration` and override
* `shouldPrintDeclaration` to hold for only the declarations you wish to view the AST for.
*/
import cpp
@@ -22,16 +22,15 @@ class PrintAstConfiguration extends TPrintAstConfiguration {
/**
* Holds if the AST for `decl` should be printed. By default, holds for all
* functions. Currently, does not support any other declaration types.
* functions and global and namespace variables. Currently, does not support any
* other declaration types.
*/
predicate shouldPrintDeclaration(Declaration decl) { any() }
}
private predicate shouldPrintDeclaration(Declaration decl) {
exists(PrintAstConfiguration config |
config.shouldPrintDeclaration(decl) and
decl instanceof Function
)
exists(PrintAstConfiguration config | config.shouldPrintDeclaration(decl)) and
(decl instanceof Function or decl instanceof GlobalOrNamespaceVariable)
}
bindingset[s]
@@ -72,7 +71,7 @@ private predicate locationSortKeys(Locatable ast, string file, int line, int col
)
}
private Function getEnclosingFunction(Locatable ast) {
private Declaration getEnclosingDeclaration(Locatable ast) {
result = ast.(Expr).getEnclosingFunction()
or
result = ast.(Stmt).getEnclosingFunction()
@@ -81,6 +80,10 @@ private Function getEnclosingFunction(Locatable ast) {
or
result = ast.(Parameter).getFunction()
or
result = ast.(Expr).getEnclosingDeclaration()
or
result = ast.(Initializer).getDeclaration()
or
result = ast
}
@@ -89,7 +92,7 @@ private Function getEnclosingFunction(Locatable ast) {
* nodes for things like parameter lists and constructor init lists.
*/
private newtype TPrintAstNode =
TAstNode(Locatable ast) { shouldPrintDeclaration(getEnclosingFunction(ast)) } or
TAstNode(Locatable ast) { shouldPrintDeclaration(getEnclosingDeclaration(ast)) } or
TDeclarationEntryNode(DeclStmt stmt, DeclarationEntry entry) {
// We create a unique node for each pair of (stmt, entry), to avoid having one node with
// multiple parents due to extractor bug CPP-413.
@@ -161,10 +164,10 @@ class PrintAstNode extends TPrintAstNode {
/**
* Holds if this node should be printed in the output. By default, all nodes
* within a function are printed, but the query can override
* `PrintASTConfiguration.shouldPrintDeclaration` to filter the output.
* within functions and global and namespace variables are printed, but the query
* can override `PrintASTConfiguration.shouldPrintDeclaration` to filter the output.
*/
final predicate shouldPrint() { shouldPrintDeclaration(this.getEnclosingFunction()) }
final predicate shouldPrint() { shouldPrintDeclaration(this.getEnclosingDeclaration()) }
/**
* Gets the children of this node.
@@ -232,10 +235,15 @@ class PrintAstNode extends TPrintAstNode {
abstract string getChildAccessorPredicateInternal(int childIndex);
/**
* Gets the `Function` that contains this node.
* Gets the `Declaration` that contains this node.
*/
private Function getEnclosingFunction() {
result = this.getParent*().(FunctionNode).getFunction()
private Declaration getEnclosingDeclaration() { result = this.getParent*().getDeclaration() }
/**
* Gets the `Declaration` this node represents.
*/
private Declaration getDeclaration() {
result = this.(AstNode).getAst() and shouldPrintDeclaration(result)
}
}
@@ -574,16 +582,53 @@ class DestructorDestructionsNode extends PrintAstNode, TDestructorDestructionsNo
final Destructor getDestructor() { result = dtor }
}
abstract private class FunctionOrGlobalOrNamespaceVariableNode extends AstNode {
override string toString() { result = qlClass(ast) + getIdentityString(ast) }
private int getOrder() {
this =
rank[result](FunctionOrGlobalOrNamespaceVariableNode node, Declaration decl, string file,
int line, int column |
node.getAst() = decl and
locationSortKeys(decl, file, line, column)
|
node order by file, line, column, getIdentityString(decl)
)
}
override string getProperty(string key) {
result = super.getProperty(key)
or
key = "semmle.order" and result = this.getOrder().toString()
}
}
/**
* A node representing a `GlobalOrNamespaceVariable`.
*/
class GlobalOrNamespaceVariableNode extends FunctionOrGlobalOrNamespaceVariableNode {
GlobalOrNamespaceVariable var;
GlobalOrNamespaceVariableNode() { var = ast }
override PrintAstNode getChildInternal(int childIndex) {
childIndex = 0 and
result.(AstNode).getAst() = var.getInitializer()
}
override string getChildAccessorPredicateInternal(int childIndex) {
childIndex = 0 and result = "getInitializer()"
}
}
/**
* A node representing a `Function`.
*/
class FunctionNode extends AstNode {
class FunctionNode extends FunctionOrGlobalOrNamespaceVariableNode {
Function func;
FunctionNode() { func = ast }
override string toString() { result = qlClass(func) + getIdentityString(func) }
override PrintAstNode getChildInternal(int childIndex) {
childIndex = 0 and
result.(ParametersNode).getFunction() = func
@@ -607,31 +652,10 @@ class FunctionNode extends AstNode {
or
childIndex = 3 and result = "<destructions>"
}
private int getOrder() {
this =
rank[result](FunctionNode node, Function function, string file, int line, int column |
node.getAst() = function and
locationSortKeys(function, file, line, column)
|
node order by file, line, column, getIdentityString(function)
)
}
override string getProperty(string key) {
result = super.getProperty(key)
or
key = "semmle.order" and result = this.getOrder().toString()
}
/**
* Gets the `Function` this node represents.
*/
final Function getFunction() { result = func }
}
private string getChildAccessorWithoutConversions(Locatable parent, Element child) {
shouldPrintDeclaration(getEnclosingFunction(parent)) and
shouldPrintDeclaration(getEnclosingDeclaration(parent)) and
(
exists(Stmt s | s = parent |
namedStmtChildPredicates(s, child, result)
@@ -650,7 +674,7 @@ private string getChildAccessorWithoutConversions(Locatable parent, Element chil
}
private predicate namedStmtChildPredicates(Locatable s, Element e, string pred) {
shouldPrintDeclaration(getEnclosingFunction(s)) and
shouldPrintDeclaration(getEnclosingDeclaration(s)) and
(
exists(int n | s.(BlockStmt).getStmt(n) = e and pred = "getStmt(" + n + ")")
or
@@ -738,7 +762,7 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
}
private predicate namedExprChildPredicates(Expr expr, Element ele, string pred) {
shouldPrintDeclaration(expr.getEnclosingFunction()) and
shouldPrintDeclaration(expr.getEnclosingDeclaration()) and
(
expr.(Access).getTarget() = ele and pred = "getTarget()"
or

View File

@@ -1308,6 +1308,11 @@ union_etc.cpp:
# 6| Type = [IntType] int
# 6| ValueCategory = prvalue(load)
# 6| getStmt(1): [ReturnStmt] return ...
# 7| [GlobalVariable] S s
# 7| getInitializer(): [Initializer] initializer for s
# 7| getExpr(): [ConstructorCall] call to S
# 7| Type = [VoidType] void
# 7| ValueCategory = prvalue
# 9| [CopyAssignmentOperator] C& C::operator=(C const&)
# 9| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -1332,6 +1337,7 @@ union_etc.cpp:
# 12| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] U &&
# 14| [GlobalVariable] C c
# 16| [CopyAssignmentOperator] U& U::operator=(U const&)
# 16| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -1356,6 +1362,7 @@ union_etc.cpp:
# 18| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] C &&
# 20| [GlobalVariable] U u
# 22| [TopLevelFunction] int foo()
# 22| <params>:
# 22| getEntryPoint(): [BlockStmt] { ... }

View File

@@ -8529,6 +8529,11 @@ ir.cpp:
# 1035| Type = [Struct] EmptyStruct
# 1035| ValueCategory = prvalue
# 1036| getStmt(1): [ReturnStmt] return ...
# 1038| [GlobalVariable] (lambda [] type at line 1038, col. 12) lam
# 1038| getInitializer(): [Initializer] initializer for lam
# 1038| getExpr(): [LambdaExpression] [...](...){...}
# 1038| Type = [Closure] decltype([...](...){...})
# 1038| ValueCategory = prvalue
# 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&)
# 1038| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -13976,6 +13981,54 @@ ir.cpp:
# 1815| Type = [IntType] int
# 1815| ValueCategory = prvalue(load)
# 1817| getStmt(8): [ReturnStmt] return ...
# 1821| [GlobalVariable] int global_2
# 1821| getInitializer(): [Initializer] initializer for global_2
# 1821| getExpr(): [Literal] 1
# 1821| Type = [IntType] int
# 1821| Value = [Literal] 1
# 1821| ValueCategory = prvalue
# 1823| [GlobalVariable] int const global_3
# 1823| getInitializer(): [Initializer] initializer for global_3
# 1823| getExpr(): [Literal] 2
# 1823| Type = [IntType] int
# 1823| Value = [Literal] 2
# 1823| ValueCategory = prvalue
# 1825| [GlobalVariable] constructor_only global_4
# 1825| getInitializer(): [Initializer] initializer for global_4
# 1825| getExpr(): [ConstructorCall] call to constructor_only
# 1825| Type = [VoidType] void
# 1825| ValueCategory = prvalue
# 1825| getArgument(0): [Literal] 1
# 1825| Type = [IntType] int
# 1825| Value = [Literal] 1
# 1825| ValueCategory = prvalue
# 1827| [GlobalVariable] constructor_only global_5
# 1827| getInitializer(): [Initializer] initializer for global_5
# 1827| getExpr(): [ConstructorCall] call to constructor_only
# 1827| Type = [VoidType] void
# 1827| ValueCategory = prvalue
# 1827| getArgument(0): [Literal] 2
# 1827| Type = [IntType] int
# 1827| Value = [Literal] 2
# 1827| ValueCategory = prvalue
# 1829| [GlobalVariable] char* global_string
# 1829| getInitializer(): [Initializer] initializer for global_string
# 1829| getExpr(): global string
# 1829| Type = [ArrayType] const char[14]
# 1829| Value = [StringLiteral] "global string"
# 1829| ValueCategory = lvalue
# 1829| getExpr().getFullyConverted(): [CStyleCast] (char *)...
# 1829| Conversion = [PointerConversion] pointer conversion
# 1829| Type = [CharPointerType] char *
# 1829| ValueCategory = prvalue
# 1829| getExpr(): [ArrayToPointerConversion] array to pointer conversion
# 1829| Type = [PointerType] const char *
# 1829| ValueCategory = prvalue
# 1831| [GlobalVariable] int global_6
# 1831| getInitializer(): [Initializer] initializer for global_6
# 1831| getExpr(): [VariableAccess] global_2
# 1831| Type = [IntType] int
# 1831| ValueCategory = prvalue(load)
# 1834| [CopyAssignmentOperator] block_assignment::A& block_assignment::A::operator=(block_assignment::A const&)
# 1834| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
@@ -14377,6 +14430,23 @@ ir.cpp:
# 1885| Type = [ClassTemplateInstantiation,Struct] Bar2<int>
# 1885| ValueCategory = lvalue
# 1886| getStmt(2): [ReturnStmt] return ...
# 1889| [GlobalVariable] char global_template<char>
# 1889| getInitializer(): [Initializer] initializer for global_template
# 1889| getExpr(): [Literal] 42
# 1889| Type = [IntType] int
# 1889| Value = [Literal] 42
# 1889| ValueCategory = prvalue
# 1889| getExpr().getFullyConverted(): [CStyleCast] (char)...
# 1889| Conversion = [IntegralConversion] integral conversion
# 1889| Type = [PlainCharType] char
# 1889| Value = [CStyleCast] 42
# 1889| ValueCategory = prvalue
# 1889| [GlobalVariable] int global_template<int>
# 1889| getInitializer(): [Initializer] initializer for global_template
# 1889| getExpr(): [Literal] 42
# 1889| Type = [IntType] int
# 1889| Value = [Literal] 42
# 1889| ValueCategory = prvalue
# 1891| [TopLevelFunction] int test_global_template_int()
# 1891| <params>:
# 1891| getEntryPoint(): [BlockStmt] { ... }
@@ -15170,6 +15240,40 @@ struct_init.cpp:
# 4| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] Info &&
# 9| [GlobalVariable] Info infos_in_file[]
# 9| getInitializer(): [Initializer] initializer for infos_in_file
# 9| getExpr(): [ArrayAggregateLiteral] {...}
# 9| Type = [ArrayType] Info[2]
# 9| ValueCategory = prvalue
# 10| getAnElementExpr(0): [ClassAggregateLiteral] {...}
# 10| Type = [Struct] Info
# 10| ValueCategory = prvalue
# 10| getAFieldExpr(name): 1
# 10| Type = [ArrayType] const char[2]
# 10| Value = [StringLiteral] "1"
# 10| ValueCategory = lvalue
# 10| getAFieldExpr(handler): [FunctionAccess] handler1
# 10| Type = [FunctionPointerType] ..(*)(..)
# 10| ValueCategory = prvalue(load)
# 10| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 10| Type = [PointerType] const char *
# 10| ValueCategory = prvalue
# 11| getAnElementExpr(1): [ClassAggregateLiteral] {...}
# 11| Type = [Struct] Info
# 11| ValueCategory = prvalue
# 11| getAFieldExpr(name): 3
# 11| Type = [ArrayType] const char[2]
# 11| Value = [StringLiteral] "3"
# 11| ValueCategory = lvalue
# 11| getAFieldExpr(handler): [AddressOfExpr] & ...
# 11| Type = [FunctionPointerType] ..(*)(..)
# 11| ValueCategory = prvalue
# 11| getOperand(): [FunctionAccess] handler2
# 11| Type = [RoutineType] ..()(..)
# 11| ValueCategory = lvalue
# 11| getAFieldExpr(name).getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
# 11| Type = [PointerType] const char *
# 11| ValueCategory = prvalue
# 16| [TopLevelFunction] void let_info_escape(Info*)
# 16| <params>:
# 16| getParameter(0): [Parameter] info