This commit is contained in:
Calum Grant
2024-06-10 11:33:09 +01:00
parent c92be9fcd7
commit 62a6a2479b
5 changed files with 127 additions and 65 deletions

View File

@@ -26,6 +26,7 @@ signature module BuildlessASTSig
predicate functionReturn(Node fn, Node returnType);
predicate functionName(Node fn, string name);
predicate functionParameter(Node fn, int i, Node parameterDecl);
predicate functionDefinition(Node fn); // If a definition as opposed to a declaration
// Statements
predicate stmt(Node node);
@@ -51,6 +52,7 @@ signature module BuildlessASTSig
predicate arrayType(Node type, Node element);
predicate typename(Node node, string name); // Any named type, including built-in types
predicate templated(Node node);
predicate typeDefinition(Node node); // If a definition as opposed to a declaration
predicate classOrStructDefinition(Node node);
predicate classMember(Node classOrStruct, int child, Node member);

View File

@@ -1,5 +1,5 @@
import cpp
import ast_sig
import ASTSig
module CompiledAST implements BuildlessASTSig {
private class SourceLocation extends Location {
@@ -13,20 +13,24 @@ module CompiledAST implements BuildlessASTSig {
result = reachableType(type).(ReferenceType).getBaseType()
}
private class SourceDeclEntry extends DeclarationEntry {
SourceDeclEntry() {
not this.isAffectedByMacro() and
not this.isFromTemplateInstantiation(_) and
not this.isInMacroExpansion() and
not this.getDeclaration().isInMacroExpansion() and
this.getLocation() instanceof SourceLocation and
not this.(FunctionDeclarationEntry).getDeclaration().isCompilerGenerated()
}
}
private newtype TNode =
// TFunction(SourceLocation loc) { exists(Function f | f.getLocation() = loc) } or
TStatement(SourceLocation loc) { exists(Stmt s | s.getLocation() = loc) } or
TDeclaration(SourceLocation loc) { exists(DeclarationEntry decl | decl.getLocation() = loc) } or
TDeclaration(SourceDeclEntry decl) or
TExpression(SourceLocation loc) { exists(Expr e | e.getLocation() = loc) } or
TFunctionCallName(SourceLocation loc) { exists(FunctionCall c | c.getLocation() = loc) } or
TDeclarationType(SourceLocation loc, Type type) {
// TODO: Avoid template instantiation here
exists(DeclarationEntry decl |
decl.getLocation() = loc and not decl.isFromTemplateInstantiation(_)
|
type = reachableType(decl.getType())
)
} or
TDeclarationType(SourceDeclEntry decl, Type type) { type = reachableType(decl.getType()) } or
TNamespaceDeclaration(NamespaceDeclarationEntry ns) { any() }
class Node extends TNode {
@@ -34,29 +38,28 @@ module CompiledAST implements BuildlessASTSig {
SourceLocation getLocation() {
this = TStatement(result) or
this = TDeclaration(result) or
result = this.getDeclaration().getLocation() or
this = TExpression(result) or
this = TFunctionCallName(result) or
this = TDeclarationType(result, _) or
result = this.getVariableDeclaration().getLocation() or
result = this.getNamespaceDeclaration().getLocation()
}
Stmt getStmt() { this = TStatement(result.getLocation()) }
Function getFunction() { this = TDeclaration(result.getLocation()) and not result.isFromTemplateInstantiation(_) and not result.isCompilerGenerated()}
DeclarationEntry getDeclaration() {
this = TDeclaration(result.getLocation()) and
not result.isFromTemplateInstantiation(_)
and not result.getDeclaration().(Function).isCompilerGenerated()
/* or this = TDeclarationType(result.getLocation(), _) */
Function getFunction() {
result = this.getDeclaration().getDeclaration() and
not result.isFromTemplateInstantiation(_) and
not result.isCompilerGenerated()
}
SourceDeclEntry getDeclaration() { this = TDeclaration(result) }
NamespaceDeclarationEntry getNamespaceDeclaration() { this = TNamespaceDeclaration(result) }
Type getType() { this = TDeclarationType(_, result) }
DeclarationEntry getVariableDeclaration() { this = TDeclarationType(result.getLocation(), _) }
SourceDeclEntry getVariableDeclaration() { this = TDeclarationType(result, _) }
Expr getExpr() { this = TExpression(result.getLocation()) }
@@ -124,16 +127,16 @@ module CompiledAST implements BuildlessASTSig {
// etc
// Types
predicate ptrType(Node node, Node element) {
exists(PointerType type, Location loc |
node = TDeclarationType(loc, type) and
element = TDeclarationType(loc, type.getBaseType())
exists(PointerType type, SourceDeclEntry e |
node = TDeclarationType(e, type) and
element = TDeclarationType(e, type.getBaseType())
)
}
predicate refType(Node node, Node element) {
exists(ReferenceType type, Location loc |
node = TDeclarationType(loc, type) and
element = TDeclarationType(loc, type.getBaseType())
exists(ReferenceType type, SourceDeclEntry e |
node = TDeclarationType(e, type) and
element = TDeclarationType(e, type.getBaseType())
)
}
@@ -159,6 +162,7 @@ module CompiledAST implements BuildlessASTSig {
member.getDeclaration().getDeclaration() and
child = 0 and
classOrStruct.getLocation().getFile() = member.getLocation().getFile() // TODO: Disambiguate
// and not member.getDeclaration().getDeclaration() instanceof FriendDecl
}
// Templates
@@ -234,9 +238,9 @@ module CompiledAST implements BuildlessASTSig {
predicate type(Node node) { node = TDeclarationType(_, _) }
predicate constType(Node node, Node element) {
exists(SpecifiedType type, Location loc |
node = TDeclarationType(loc, type) and
element = TDeclarationType(loc, type.getBaseType()) and
exists(SpecifiedType type, SourceDeclEntry e |
node = TDeclarationType(e, type) and
element = TDeclarationType(e, type.getBaseType()) and
type.isConst()
)
}
@@ -247,15 +251,25 @@ module CompiledAST implements BuildlessASTSig {
ns.getNamespaceDeclaration().getNamespace().getName() = name
}
pragma[nomagic]
private predicate namespaceNamespace(Node ns, Node child) {
ns.getNamespaceDeclaration().getNamespace().getAChildNamespace() =
child.getNamespaceDeclaration().getNamespace() and
ns.getLocation().getFile() = child.getLocation().getFile()
}
pragma[nomagic]
private predicate namespaceDecl(Node ns, Node child) {
child.getDeclaration().getDeclaration() =
ns.getNamespaceDeclaration().getNamespace().getADeclaration()
and
ns.getLocation().getFile() = child.getLocation().getFile() and
ns.getLocation().getStartLine() <= child.getLocation().getStartLine()
}
predicate namespaceMember(Node ns, Node member) {
(
member.getDeclaration().getDeclaration() =
ns.getNamespaceDeclaration().getNamespace().getADeclaration()
or
ns.getNamespaceDeclaration().getNamespace().getAChildNamespace() =
member.getNamespaceDeclaration().getNamespace()
) and
ns.getLocation().getFile() = member.getLocation().getFile()
namespaceNamespace(ns, member) or
namespaceDecl(ns, member)
}
predicate edge(Node parent, int index, Node child) {
@@ -265,4 +279,8 @@ module CompiledAST implements BuildlessASTSig {
or
blockMember(parent, index, child)
}
predicate typeDefinition(Node node) { node.getDeclaration().(TypeDeclarationEntry).isDefinition() }
predicate functionDefinition(Node fn) { fn.getDeclaration().(FunctionDeclarationEntry).isDefinition() }
}

View File

@@ -1,4 +1,4 @@
import ast
import AST
module BuildlessModel<BuildlessASTSig Sig> {
module AST = BuildlessAST<Sig>;
@@ -13,7 +13,18 @@ module BuildlessModel<BuildlessASTSig Sig> {
private newtype TElement =
TNamespace(string fqn) { fqn = getQualifiedName(_) } or
TASTNode(AST::SourceElement node) { any() }
TASTNode(AST::SourceElement node) { any() }
class Type extends string
{
Type() { exists(SourceTypeDeclaration t | t.getMangledName() = this) }
// string toString() { result = "i am a type" }
SourceTypeDeclaration getADeclaration() { result.getMangledName() = this }
SourceTypeDefinition getADefinition() { result.getMangledName() = this }
}
class Element extends TElement {
string toString() { result = "element" }
@@ -25,25 +36,31 @@ module BuildlessModel<BuildlessASTSig Sig> {
override string toString() { result = "namespace " + this.getFullyQualifiedName() }
}
class SourceElement extends Element, TASTNode
{
class SourceElement extends Element, TASTNode {
AST::SourceElement node;
SourceElement() { this = TASTNode(node) }
Location getLocation() { result = node.getLocation() }
AST::SourceElement getSourceNode() { result = node }
}
class SourceDeclaration extends SourceElement, TASTNode
{
class SourceDeclaration extends SourceElement, TASTNode {
abstract SourceDeclaration getParent();
abstract string getName();
abstract string getMangledName();
abstract predicate isDefinition();
}
abstract class SourceDefinition extends SourceDeclaration
{
}
class NamespaceDeclaration extends SourceDeclaration {
AST::SourceNamespace ns;
NamespaceDeclaration() { ns = node }
@@ -63,6 +80,8 @@ module BuildlessModel<BuildlessASTSig Sig> {
}
override string getMangledName() { result = this.getFullyQualifiedName() }
override predicate isDefinition() { any() }
}
class SourceTypeDeclaration extends SourceDeclaration {
@@ -74,37 +93,42 @@ module BuildlessModel<BuildlessASTSig Sig> {
override string toString() { result = "typename " + def.getName() }
NamespaceDeclaration getParentNamespace() {
result.getSourceNode() = def.getParent()
}
NamespaceDeclaration getParentNamespace() { result.getSourceNode() = def.getParent() }
SourceTypeDeclaration getParentType() {
result.getSourceNode() = def.getParent()
}
SourceTypeDeclaration getParentType() { result.getSourceNode() = def.getParent() }
override SourceDeclaration getParent() {
result = this.getParentNamespace() or result = this.getParentType()
override SourceDeclaration getParent() {
result = this.getParentNamespace() or result = this.getParentType()
}
override string getName() { result = def.getName() }
// Mangled name
override string getMangledName() {
if exists(this.getParent()) then result = this.getParent().getMangledName() +
"." + this.getName() else result = this.getName() }
override string getMangledName() {
if exists(this.getParent())
then result = this.getParent().getMangledName() + "." + this.getName()
else result = this.getName()
}
override predicate isDefinition() { def.isDefinition() }
}
class SourceFunctionDeclaration extends SourceDeclaration
class SourceTypeDefinition extends SourceTypeDeclaration, SourceDefinition
{
SourceTypeDefinition() { this.isDefinition() }
}
class SourceFunctionDeclaration extends SourceDeclaration {
AST::SourceFunction fn;
SourceFunctionDeclaration() { fn=node }
SourceFunctionDeclaration() { fn = node }
SourceTypeDeclaration getParentType() { result.getSourceNode() = fn.getParent() }
NamespaceDeclaration getParentNamespace() { result.getSourceNode() = fn.getParent() }
override SourceDeclaration getParent() {
result = this.getParentType() or result = this.getParentNamespace()
override SourceDeclaration getParent() {
result = this.getParentType() or result = this.getParentNamespace()
}
override string toString() { result = fn.getName() + "()" }
@@ -113,10 +137,21 @@ module BuildlessModel<BuildlessASTSig Sig> {
override string getName() { result = fn.getName() }
override string getMangledName() {
if exists(this.getParent()) then result = this.getParent().getMangledName() +
"." + this.getName()+"()" else result = this.getName()+"()" }
}
override string getMangledName() {
if exists(this.getParent())
then result = this.getParent().getMangledName() + "." + this.getName() + "()"
else result = this.getName() + "()"
}
override predicate isDefinition() { fn.isDefinition() }
}
class SourceFunctionDefinition extends SourceFunctionDeclaration, SourceDefinition
{
SourceFunctionDefinition() { this.isDefinition() }
}
predicate invalidParent(SourceDeclaration decl) { decl.getParent+() = decl }
}
// For debugging in context

View File

@@ -1,5 +1,5 @@
import compiled_ast
import ast_sig
import CompiledAST
import ASTSig
module BuildlessAST<BuildlessASTSig AST> {
final class Node = AST::Node;
@@ -49,6 +49,8 @@ module BuildlessAST<BuildlessASTSig AST> {
SourceParameter getParameter(int i) { AST::functionParameter(this, i, result) }
SourceType getReturnType() { AST::functionReturn(this, result) }
predicate isDefinition() { AST::functionDefinition(this) }
}
// A syntax node that declares a variable (including fields and parameters)
@@ -136,6 +138,8 @@ module BuildlessAST<BuildlessASTSig AST> {
override string toString() { result = this.getName() }
SourceElement getAMember() { AST::classMember(this, _, result) }
predicate isDefinition() { AST::typeDefinition(this) }
}
// A node that contains a type of some kind

View File

@@ -0,0 +1,3 @@
import Model
select 1