mirror of
https://github.com/github/codeql.git
synced 2026-05-25 16:47:07 +02:00
Types
This commit is contained in:
@@ -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);
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
3
cpp/ql/lib/experimental/buildless/checks.ql
Normal file
3
cpp/ql/lib/experimental/buildless/checks.ql
Normal file
@@ -0,0 +1,3 @@
|
||||
import Model
|
||||
|
||||
select 1
|
||||
Reference in New Issue
Block a user