mirror of
https://github.com/github/codeql.git
synced 2025-12-17 09:13:20 +01:00
C++: Rework how qualified names are computed
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import semmle.code.cpp.Element
|
import semmle.code.cpp.Element
|
||||||
import semmle.code.cpp.Specifier
|
import semmle.code.cpp.Specifier
|
||||||
import semmle.code.cpp.Namespace
|
import semmle.code.cpp.Namespace
|
||||||
|
private import semmle.code.cpp.internal.QualifiedName as Q
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A C/C++ declaration: for example, a variable declaration, a type
|
* A C/C++ declaration: for example, a variable declaration, a type
|
||||||
@@ -30,16 +31,7 @@ abstract class Declaration extends Locatable, @declaration {
|
|||||||
* namespace of the structure.
|
* namespace of the structure.
|
||||||
*/
|
*/
|
||||||
Namespace getNamespace() {
|
Namespace getNamespace() {
|
||||||
// Top level declaration in a namespace ...
|
result = this.(Q::Declaration).getNamespace()
|
||||||
result.getADeclaration() = this
|
|
||||||
|
|
||||||
// ... or nested in another structure.
|
|
||||||
or
|
|
||||||
exists (Declaration m
|
|
||||||
| m = this and result = m.getDeclaringType().getNamespace())
|
|
||||||
or
|
|
||||||
exists (EnumConstant c
|
|
||||||
| c = this and result = c.getDeclaringEnum().getNamespace())
|
|
||||||
or
|
or
|
||||||
exists (Parameter p
|
exists (Parameter p
|
||||||
| p = this and result = p.getFunction().getNamespace())
|
| p = this and result = p.getFunction().getNamespace())
|
||||||
@@ -50,40 +42,56 @@ abstract class Declaration extends Locatable, @declaration {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name of the declaration, fully qualified with its
|
* Gets the name of the declaration, fully qualified with its
|
||||||
* namespace. For example: "A::B::C::myfcn".
|
* namespace and declaring type.
|
||||||
|
*
|
||||||
|
* For performance, prefer the multi-argument `hasQualifiedName` or
|
||||||
|
* `hasGlobalName` predicates since they don't construct so many intermediate
|
||||||
|
* strings. For debugging, the `semmle.code.cpp.Print` module produces more
|
||||||
|
* detailed output but are also more expensive to compute.
|
||||||
|
*
|
||||||
|
* Example: `getQualifiedName() =
|
||||||
|
* "namespace1::namespace2::TemplateClass1<int>::Class2::memberName"`.
|
||||||
*/
|
*/
|
||||||
string getQualifiedName() {
|
string getQualifiedName() {
|
||||||
// MemberFunction, MemberVariable, MemberType
|
result = this.(Q::Declaration).getQualifiedName()
|
||||||
exists (Declaration m
|
|
||||||
| m = this and
|
|
||||||
not m instanceof EnumConstant and
|
|
||||||
result = m.getDeclaringType().getQualifiedName() + "::" + m.getName())
|
|
||||||
or
|
|
||||||
exists (EnumConstant c
|
|
||||||
| c = this and
|
|
||||||
result = c.getDeclaringEnum().getQualifiedName() + "::" + c.getName())
|
|
||||||
or
|
|
||||||
exists (GlobalOrNamespaceVariable v, string s1, string s2
|
|
||||||
| v = this and
|
|
||||||
s2 = v.getNamespace().getQualifiedName() and
|
|
||||||
s1 = v.getName()
|
|
||||||
| (s2 != "" and result = s2 + "::" + s1) or (s2 = "" and result = s1))
|
|
||||||
or
|
|
||||||
exists (Function f, string s1, string s2
|
|
||||||
| f = this and f.isTopLevel() and
|
|
||||||
s2 = f.getNamespace().getQualifiedName() and
|
|
||||||
s1 = f.getName()
|
|
||||||
| (s2 != "" and result = s2 + "::" + s1) or (s2 = "" and result = s1))
|
|
||||||
or
|
|
||||||
exists (UserType t, string s1, string s2
|
|
||||||
| t = this and t.isTopLevel() and
|
|
||||||
s2 = t.getNamespace().getQualifiedName() and
|
|
||||||
s1 = t.getName()
|
|
||||||
| (s2 != "" and result = s2 + "::" + s1) or (s2 = "" and result = s1))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate hasQualifiedName(string name) {
|
/**
|
||||||
this.getQualifiedName() = name
|
* Holds if this declaration has the fully-qualified name `qualifiedName`.
|
||||||
|
* See `getQualifiedName`.
|
||||||
|
*/
|
||||||
|
predicate hasQualifiedName(string qualifiedName) {
|
||||||
|
this.getQualifiedName() = qualifiedName
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this declaration has a fully-qualified name with a name-space
|
||||||
|
* component of `namespaceQualifier`, a declaring type of `typeQualifier`,
|
||||||
|
* and a base name of `baseName`. Template parameters and arguments are
|
||||||
|
* stripped from all components. Missing components are `""`.
|
||||||
|
*
|
||||||
|
* Example: `hasQualifiedName("namespace1::namespace2",
|
||||||
|
* "TemplateClass1::Class2", "memberName")`.
|
||||||
|
*
|
||||||
|
* Example (the class `std::vector`): `hasQualifiedName("std", "", "vector")`
|
||||||
|
* or `hasQualifiedName("std", "vector")`.
|
||||||
|
*
|
||||||
|
* Example (the `size` member function of class `std::vector`):
|
||||||
|
* `hasQualifiedName("std", "vector", "size")`.
|
||||||
|
*/
|
||||||
|
predicate hasQualifiedName(string namespaceQualifier, string typeQualifier, string baseName) {
|
||||||
|
this.(Q::Declaration).hasQualifiedName(namespaceQualifier, typeQualifier, baseName)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this declaration has a fully-qualified name with a name-space
|
||||||
|
* component of `namespaceQualifier`, no declaring type, and a base name of
|
||||||
|
* `baseName`.
|
||||||
|
*
|
||||||
|
* See the 3-argument `hasQualifiedName` for more examples.
|
||||||
|
*/
|
||||||
|
predicate hasQualifiedName(string namespaceQualifier, string baseName) {
|
||||||
|
this.hasQualifiedName(namespaceQualifier, "", baseName)
|
||||||
}
|
}
|
||||||
|
|
||||||
override string toString() { result = this.getName() }
|
override string toString() { result = this.getName() }
|
||||||
@@ -93,22 +101,24 @@ abstract class Declaration extends Locatable, @declaration {
|
|||||||
*
|
*
|
||||||
* This name doesn't include a namespace or any argument types, so
|
* This name doesn't include a namespace or any argument types, so
|
||||||
* for example both functions `::open()` and `::std::ifstream::open(...)`
|
* for example both functions `::open()` and `::std::ifstream::open(...)`
|
||||||
* have the same name.
|
* have the same name. The name of a template _class_ includes a string
|
||||||
|
* representation of its parameters, and the names of its instantiations
|
||||||
|
* include string representations of their arguments. Template _functions_
|
||||||
|
* and their instantiations do not include template parameters or arguments.
|
||||||
*
|
*
|
||||||
* To get the name including the namespace, use `getQualifiedName` or
|
* To get the name including the namespace, use `hasQualifiedName`.
|
||||||
* `hasQualifiedName`.
|
|
||||||
*
|
*
|
||||||
* To test whether this declaration has a particular name in the global
|
* To test whether this declaration has a particular name in the global
|
||||||
* namespace, use `hasGlobalName`.
|
* namespace, use `hasGlobalName`.
|
||||||
*/
|
*/
|
||||||
abstract string getName();
|
string getName() { result = this.(Q::Declaration).getName() }
|
||||||
|
|
||||||
/** Holds if this declaration has the given name. */
|
/** Holds if this declaration has the given name. */
|
||||||
predicate hasName(string name) { name = this.getName() }
|
predicate hasName(string name) { name = this.getName() }
|
||||||
|
|
||||||
/** Holds if this declaration has the given name in the global namespace. */
|
/** Holds if this declaration has the given name in the global namespace. */
|
||||||
predicate hasGlobalName(string name) {
|
predicate hasGlobalName(string name) {
|
||||||
hasName(name)
|
this.hasQualifiedName("", "", name)
|
||||||
and getNamespace() instanceof GlobalNamespace
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a specifier of this declaration. */
|
/** Gets a specifier of this declaration. */
|
||||||
|
|||||||
@@ -100,11 +100,6 @@ class EnumConstant extends Declaration, @enumconstant {
|
|||||||
result = this.getDeclaringEnum().getDeclaringType()
|
result = this.getDeclaringEnum().getDeclaringType()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the name of this enumerator.
|
|
||||||
*/
|
|
||||||
override string getName() { enumconstants(underlyingElement(this),_,_,_,result,_) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value that this enumerator is initialized to, as a
|
* Gets the value that this enumerator is initialized to, as a
|
||||||
* string. This can be a value explicitly given to the enumerator, or an
|
* string. This can be a value explicitly given to the enumerator, or an
|
||||||
|
|||||||
@@ -35,11 +35,6 @@ class FriendDecl extends Declaration, @frienddecl {
|
|||||||
/** Gets the location of this friend declaration. */
|
/** Gets the location of this friend declaration. */
|
||||||
override Location getLocation() { frienddecls(underlyingElement(this),_,_,result) }
|
override Location getLocation() { frienddecls(underlyingElement(this),_,_,result) }
|
||||||
|
|
||||||
/** Gets a descriptive string for this friend declaration. */
|
|
||||||
override string getName() {
|
|
||||||
result = this.getDeclaringClass().getName() + "'s friend"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Friend declarations do not have specifiers. It makes no difference
|
* Friend declarations do not have specifiers. It makes no difference
|
||||||
* whether they are declared in a public, protected or private section of
|
* whether they are declared in a public, protected or private section of
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ private import semmle.code.cpp.internal.ResolveClass
|
|||||||
* in more detail in `Declaration.qll`.
|
* in more detail in `Declaration.qll`.
|
||||||
*/
|
*/
|
||||||
class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||||
override string getName() { functions(underlyingElement(this),result,_) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: Use `getIdentityString(Declaration)` from `semmle.code.cpp.Print` instead.
|
* DEPRECATED: Use `getIdentityString(Declaration)` from `semmle.code.cpp.Print` instead.
|
||||||
* Gets the full signature of this function, including return type, parameter
|
* Gets the full signature of this function, including return type, parameter
|
||||||
|
|||||||
@@ -148,9 +148,6 @@ deprecated class FinallyBlock extends Block {
|
|||||||
deprecated class Property extends Declaration {
|
deprecated class Property extends Declaration {
|
||||||
Property() { none() }
|
Property() { none() }
|
||||||
|
|
||||||
/** Gets the name of this property. */
|
|
||||||
override string getName() { none() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets nothing (provided for compatibility with Declaration).
|
* Gets nothing (provided for compatibility with Declaration).
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import semmle.code.cpp.Location
|
import semmle.code.cpp.Location
|
||||||
import semmle.code.cpp.Declaration
|
import semmle.code.cpp.Declaration
|
||||||
private import semmle.code.cpp.internal.ResolveClass
|
private import semmle.code.cpp.internal.ResolveClass
|
||||||
|
private import semmle.code.cpp.internal.QualifiedName as Q
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A C/C++ function parameter or catch block parameter.
|
* A C/C++ function parameter or catch block parameter.
|
||||||
@@ -13,26 +14,6 @@ private import semmle.code.cpp.internal.ResolveClass
|
|||||||
* have multiple declarations.
|
* have multiple declarations.
|
||||||
*/
|
*/
|
||||||
class Parameter extends LocalScopeVariable, @parameter {
|
class Parameter extends LocalScopeVariable, @parameter {
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the canonical name, or names, of this parameter.
|
|
||||||
*
|
|
||||||
* The canonical names are the first non-empty category from the
|
|
||||||
* following list:
|
|
||||||
* 1. The name given to the parameter at the function's definition or
|
|
||||||
* (for catch block parameters) at the catch block.
|
|
||||||
* 2. A name given to the parameter at a function declaration.
|
|
||||||
* 3. The name "p#i" where i is the index of the parameter.
|
|
||||||
*/
|
|
||||||
override string getName() {
|
|
||||||
exists (VariableDeclarationEntry vde
|
|
||||||
| vde = getANamedDeclarationEntry() and result = vde.getName()
|
|
||||||
| vde.isDefinition() or not getANamedDeclarationEntry().isDefinition())
|
|
||||||
or
|
|
||||||
(not exists(getANamedDeclarationEntry()) and
|
|
||||||
result = "p#" + this.getIndex().toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name of this parameter, including it's type.
|
* Gets the name of this parameter, including it's type.
|
||||||
*
|
*
|
||||||
@@ -53,27 +34,6 @@ class Parameter extends LocalScopeVariable, @parameter {
|
|||||||
else result = typeString + nameString))
|
else result = typeString + nameString))
|
||||||
}
|
}
|
||||||
|
|
||||||
private VariableDeclarationEntry getANamedDeclarationEntry() {
|
|
||||||
result = getAnEffectiveDeclarationEntry() and result.getName() != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a declaration entry corresponding to this declaration.
|
|
||||||
*
|
|
||||||
* This predicate is the same as getADeclarationEntry(), except that for
|
|
||||||
* parameters of instantiated function templates, gives the declaration
|
|
||||||
* entry of the prototype instantiation of the parameter (as
|
|
||||||
* non-prototype instantiations don't have declaration entries of their
|
|
||||||
* own).
|
|
||||||
*/
|
|
||||||
private VariableDeclarationEntry getAnEffectiveDeclarationEntry() {
|
|
||||||
if getFunction().isConstructedFrom(_)
|
|
||||||
then exists (Function prototypeInstantiation
|
|
||||||
| prototypeInstantiation.getParameter(getIndex()) = result.getVariable() and
|
|
||||||
getFunction().isConstructedFrom(prototypeInstantiation))
|
|
||||||
else result = getADeclarationEntry()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name of this parameter in the given block (which should be
|
* Gets the name of this parameter in the given block (which should be
|
||||||
* the body of a function with which the parameter is associated).
|
* the body of a function with which the parameter is associated).
|
||||||
@@ -95,7 +55,7 @@ class Parameter extends LocalScopeVariable, @parameter {
|
|||||||
* In other words, this predicate holds precisely when the result of
|
* In other words, this predicate holds precisely when the result of
|
||||||
* `getName()` is not "p#i" (where `i` is the index of the parameter).
|
* `getName()` is not "p#i" (where `i` is the index of the parameter).
|
||||||
*/
|
*/
|
||||||
predicate isNamed() { exists(getANamedDeclarationEntry()) }
|
predicate isNamed() { exists(this.(Q::Parameter).getANamedDeclarationEntry()) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the function to which this parameter belongs, if it is a function
|
* Gets the function to which this parameter belongs, if it is a function
|
||||||
@@ -135,8 +95,13 @@ class Parameter extends LocalScopeVariable, @parameter {
|
|||||||
* of the declaration locations.
|
* of the declaration locations.
|
||||||
*/
|
*/
|
||||||
override Location getLocation() {
|
override Location getLocation() {
|
||||||
exists(VariableDeclarationEntry vde | vde = getAnEffectiveDeclarationEntry() and result = vde.getLocation() |
|
exists(VariableDeclarationEntry vde |
|
||||||
vde.isDefinition() or not getAnEffectiveDeclarationEntry().isDefinition()
|
vde = this.(Q::Parameter).getAnEffectiveDeclarationEntry() and
|
||||||
|
result = vde.getLocation()
|
||||||
|
|
|
||||||
|
vde.isDefinition()
|
||||||
|
or
|
||||||
|
not this.(Q::Parameter).getAnEffectiveDeclarationEntry().isDefinition()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,9 @@ private import semmle.code.cpp.internal.ResolveClass
|
|||||||
* `Enum`, and `TypedefType`.
|
* `Enum`, and `TypedefType`.
|
||||||
*/
|
*/
|
||||||
class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @usertype {
|
class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @usertype {
|
||||||
/**
|
override string getName() {
|
||||||
* Gets the name of this type.
|
result = Declaration.super.getName()
|
||||||
*/
|
}
|
||||||
override string getName() { usertypes(underlyingElement(this),result,_) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the simple name of this type, without any template parameters. For example
|
* Gets the simple name of this type, without any template parameters. For example
|
||||||
|
|||||||
@@ -41,9 +41,6 @@ class Variable extends Declaration, @variable {
|
|||||||
/** Holds if this variable is `volatile`. */
|
/** Holds if this variable is `volatile`. */
|
||||||
predicate isVolatile() { this.getType().isVolatile() }
|
predicate isVolatile() { this.getType().isVolatile() }
|
||||||
|
|
||||||
/** Gets the name of this variable. */
|
|
||||||
override string getName() { none() }
|
|
||||||
|
|
||||||
/** Gets the type of this variable. */
|
/** Gets the type of this variable. */
|
||||||
Type getType() { none() }
|
Type getType() { none() }
|
||||||
|
|
||||||
@@ -291,8 +288,6 @@ deprecated class StackVariable extends Variable {
|
|||||||
* A local variable can be declared by a `DeclStmt` or a `ConditionDeclExpr`.
|
* A local variable can be declared by a `DeclStmt` or a `ConditionDeclExpr`.
|
||||||
*/
|
*/
|
||||||
class LocalVariable extends LocalScopeVariable, @localvariable {
|
class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||||
override string getName() { localvariables(underlyingElement(this),_,result) }
|
|
||||||
|
|
||||||
override Type getType() { localvariables(underlyingElement(this),unresolveElement(result),_) }
|
override Type getType() { localvariables(underlyingElement(this),unresolveElement(result),_) }
|
||||||
|
|
||||||
override Function getFunction() {
|
override Function getFunction() {
|
||||||
@@ -305,8 +300,6 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
|
|||||||
* A C/C++ variable which has global scope or namespace scope.
|
* A C/C++ variable which has global scope or namespace scope.
|
||||||
*/
|
*/
|
||||||
class GlobalOrNamespaceVariable extends Variable, @globalvariable {
|
class GlobalOrNamespaceVariable extends Variable, @globalvariable {
|
||||||
override string getName() { globalvariables(underlyingElement(this),_,result) }
|
|
||||||
|
|
||||||
override Type getType() { globalvariables(underlyingElement(this),unresolveElement(result),_) }
|
override Type getType() { globalvariables(underlyingElement(this),unresolveElement(result),_) }
|
||||||
|
|
||||||
override Element getEnclosingElement() { none() }
|
override Element getEnclosingElement() { none() }
|
||||||
@@ -354,8 +347,6 @@ class MemberVariable extends Variable, @membervariable {
|
|||||||
/** Holds if this member is public. */
|
/** Holds if this member is public. */
|
||||||
predicate isPublic() { this.hasSpecifier("public") }
|
predicate isPublic() { this.hasSpecifier("public") }
|
||||||
|
|
||||||
override string getName() { membervariables(underlyingElement(this),_,result) }
|
|
||||||
|
|
||||||
override Type getType() {
|
override Type getType() {
|
||||||
if (strictcount(this.getAType()) = 1) then (
|
if (strictcount(this.getAType()) = 1) then (
|
||||||
result = this.getAType()
|
result = this.getAType()
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
private import semmle.code.cpp.internal.ResolveClass as ResolveClass
|
|
||||||
|
|
||||||
class Namespace extends @namespace {
|
class Namespace extends @namespace {
|
||||||
string toString() { result = "QualifiedName Namespace" }
|
string toString() { result = "QualifiedName Namespace" }
|
||||||
|
|
||||||
@@ -26,61 +24,72 @@ abstract class Declaration extends @declaration {
|
|||||||
string toString() { result = "QualifiedName Declaration" }
|
string toString() { result = "QualifiedName Declaration" }
|
||||||
|
|
||||||
/** Gets the name of this declaration. */
|
/** Gets the name of this declaration. */
|
||||||
|
cached
|
||||||
abstract string getName();
|
abstract string getName();
|
||||||
|
|
||||||
// Note: This is not as full featured as the getNamespace in the AST,
|
string getTypeQualifierWithoutArgs() {
|
||||||
// but it covers the cases we need here.
|
exists(UserType declaringType |
|
||||||
|
declaringType = this.(EnumConstant).getDeclaringEnum()
|
||||||
|
or
|
||||||
|
declaringType = this.getDeclaringType()
|
||||||
|
|
|
||||||
|
result = getTypeQualifierForMembersWithoutArgs(declaringType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
string getTypeQualifierWithArgs() {
|
||||||
|
exists(UserType declaringType |
|
||||||
|
declaringType = this.(EnumConstant).getDeclaringEnum()
|
||||||
|
or
|
||||||
|
declaringType = this.getDeclaringType()
|
||||||
|
|
|
||||||
|
result = getTypeQualifierForMembersWithArgs(declaringType)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Namespace getNamespace() {
|
Namespace getNamespace() {
|
||||||
// Top level declaration in a namespace ...
|
// Top level declaration in a namespace ...
|
||||||
result.getADeclaration() = this
|
result.getADeclaration() = this
|
||||||
or
|
or
|
||||||
// ... or nested in another structure.
|
// ... or nested in another structure.
|
||||||
exists(Declaration m | m = this and result = m.getDeclaringType().getNamespace())
|
exists(Declaration m | m = this and result = m.getDeclaringType().getNamespace())
|
||||||
|
or
|
||||||
|
exists(EnumConstant c | c = this and result = c.getDeclaringEnum().getNamespace())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate hasQualifiedName(string namespaceQualifier, string typeQualifier, string baseName) {
|
||||||
|
declarationHasQualifiedName(baseName, typeQualifier, namespaceQualifier, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
string getQualifiedName() {
|
string getQualifiedName() {
|
||||||
// MemberFunction, MemberVariable, MemberType
|
exists(string ns, string name |
|
||||||
exists(Declaration m |
|
ns = this.getNamespace().getQualifiedName() and
|
||||||
m = this and
|
name = this.getName() and
|
||||||
result = m.getDeclaringType().getQualifiedName() + "::" + m.getName()
|
this.canHaveQualifiedName()
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(EnumConstant c |
|
|
||||||
c = this and
|
|
||||||
result = c.getDeclaringEnum().getQualifiedName() + "::" + c.getName()
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(GlobalOrNamespaceVariable v, string s1, string s2 |
|
|
||||||
v = this and
|
|
||||||
s2 = v.getNamespace().getQualifiedName() and
|
|
||||||
s1 = v.getName()
|
|
||||||
|
|
|
|
||||||
s2 != "" and result = s2 + "::" + s1
|
exists(string t | t = this.getTypeQualifierWithArgs() |
|
||||||
|
if ns != ""
|
||||||
|
then result = ns + "::" + t + "::" + name
|
||||||
|
else result = t + "::" + name
|
||||||
|
)
|
||||||
or
|
or
|
||||||
s2 = "" and result = s1
|
not hasTypeQualifier(this) and
|
||||||
|
if ns != ""
|
||||||
|
then result = ns + "::" + name
|
||||||
|
else result = name
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate canHaveQualifiedName() {
|
||||||
|
this.hasDeclaringType()
|
||||||
or
|
or
|
||||||
exists(Function f, string s1, string s2 |
|
this instanceof EnumConstant
|
||||||
f = this and
|
|
||||||
f.isTopLevel() and
|
|
||||||
s2 = f.getNamespace().getQualifiedName() and
|
|
||||||
s1 = f.getName()
|
|
||||||
|
|
|
||||||
s2 != "" and result = s2 + "::" + s1
|
|
||||||
or
|
|
||||||
s2 = "" and result = s1
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
exists(UserType t, string s1, string s2 |
|
this instanceof Function
|
||||||
t = this and
|
or
|
||||||
t.isTopLevel() and
|
this instanceof UserType
|
||||||
s2 = t.getNamespace().getQualifiedName() and
|
or
|
||||||
s1 = t.getName()
|
this instanceof GlobalOrNamespaceVariable
|
||||||
|
|
|
||||||
s2 != "" and result = s2 + "::" + s1
|
|
||||||
or
|
|
||||||
s2 = "" and result = s1
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isTopLevel() {
|
predicate isTopLevel() {
|
||||||
@@ -107,11 +116,13 @@ abstract class Declaration extends @declaration {
|
|||||||
* For templates, both the template itself and all instantiations of
|
* For templates, both the template itself and all instantiations of
|
||||||
* the template are considered to have the same declaring class.
|
* the template are considered to have the same declaring class.
|
||||||
*/
|
*/
|
||||||
Class getDeclaringType() { this = result.getAMember() }
|
UserType getDeclaringType() { this = result.getAMember() }
|
||||||
}
|
}
|
||||||
|
|
||||||
class Variable extends Declaration, @variable {
|
class Variable extends Declaration, @variable {
|
||||||
override string getName() { none() }
|
override string getName() { none() }
|
||||||
|
|
||||||
|
VariableDeclarationEntry getADeclarationEntry() { result.getDeclaration() = this }
|
||||||
}
|
}
|
||||||
|
|
||||||
class TemplateVariable extends Variable {
|
class TemplateVariable extends Variable {
|
||||||
@@ -126,9 +137,73 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
|
|||||||
override string getName() { localvariables(this, _, result) }
|
override string getName() { localvariables(this, _, result) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A particular declaration or definition of a C/C++ variable.
|
||||||
|
*/
|
||||||
|
class VariableDeclarationEntry extends @var_decl {
|
||||||
|
string toString() { result = "QualifiedName DeclarationEntry" }
|
||||||
|
|
||||||
|
Variable getDeclaration() { result = getVariable() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the variable which is being declared or defined.
|
||||||
|
*/
|
||||||
|
Variable getVariable() { var_decls(this, result, _, _, _) }
|
||||||
|
|
||||||
|
predicate isDefinition() { var_def(this) }
|
||||||
|
|
||||||
|
string getName() { var_decls(this, _, _, result, _) and result != "" }
|
||||||
|
}
|
||||||
|
|
||||||
class Parameter extends LocalScopeVariable, @parameter {
|
class Parameter extends LocalScopeVariable, @parameter {
|
||||||
|
@functionorblock function;
|
||||||
|
|
||||||
|
int index;
|
||||||
|
|
||||||
|
Parameter() { params(this, function, index, _) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the canonical name, or names, of this parameter.
|
||||||
|
*
|
||||||
|
* The canonical names are the first non-empty category from the
|
||||||
|
* following list:
|
||||||
|
* 1. The name given to the parameter at the function's definition or
|
||||||
|
* (for catch block parameters) at the catch block.
|
||||||
|
* 2. A name given to the parameter at a function declaration.
|
||||||
|
* 3. The name "p#i" where i is the index of the parameter.
|
||||||
|
*/
|
||||||
override string getName() {
|
override string getName() {
|
||||||
exists(int i | params(this, _, i, _) and result = "p#" + i.toString())
|
exists(VariableDeclarationEntry vde |
|
||||||
|
vde = getANamedDeclarationEntry() and result = vde.getName()
|
||||||
|
|
|
||||||
|
vde.isDefinition() or not getANamedDeclarationEntry().isDefinition()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
not exists(getANamedDeclarationEntry()) and
|
||||||
|
result = "p#" + index.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableDeclarationEntry getANamedDeclarationEntry() {
|
||||||
|
result = getAnEffectiveDeclarationEntry() and exists(result.getName())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a declaration entry corresponding to this declaration.
|
||||||
|
*
|
||||||
|
* This predicate is the same as getADeclarationEntry(), except that for
|
||||||
|
* parameters of instantiated function templates, gives the declaration
|
||||||
|
* entry of the prototype instantiation of the parameter (as
|
||||||
|
* non-prototype instantiations don't have declaration entries of their
|
||||||
|
* own).
|
||||||
|
*/
|
||||||
|
VariableDeclarationEntry getAnEffectiveDeclarationEntry() {
|
||||||
|
if function.(Function).isConstructedFrom(_)
|
||||||
|
then
|
||||||
|
exists(Function prototypeInstantiation |
|
||||||
|
prototypeInstantiation.getParameter(index) = result.getVariable() and
|
||||||
|
function.(Function).isConstructedFrom(prototypeInstantiation)
|
||||||
|
)
|
||||||
|
else result = getADeclarationEntry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,10 +221,15 @@ class EnumConstant extends Declaration, @enumconstant {
|
|||||||
override string getName() { enumconstants(this, _, _, _, result, _) }
|
override string getName() { enumconstants(this, _, _, _, result, _) }
|
||||||
|
|
||||||
UserType getDeclaringEnum() { enumconstants(this, result, _, _, _, _) }
|
UserType getDeclaringEnum() { enumconstants(this, result, _, _, _, _) }
|
||||||
|
// Unlike the usual `EnumConstant`, this one doesn't have a `getDeclaringType()`.
|
||||||
}
|
}
|
||||||
|
|
||||||
class Function extends Declaration, @function {
|
class Function extends Declaration, @function {
|
||||||
override string getName() { functions(this, result, _) }
|
override string getName() { functions(this, result, _) }
|
||||||
|
|
||||||
|
predicate isConstructedFrom(Function f) { function_instantiation(this, f) }
|
||||||
|
|
||||||
|
Parameter getParameter(int n) { params(result, this, n, _) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class TemplateFunction extends Function {
|
class TemplateFunction extends Function {
|
||||||
@@ -162,22 +242,11 @@ class TemplateFunction extends Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class UserType extends Declaration, @usertype {
|
class UserType extends Declaration, @usertype {
|
||||||
override string getName() { usertypes(this, result, _) }
|
override string getName() { result = getUserTypeNameWithArgs(this) }
|
||||||
|
|
||||||
predicate isLocal() { enclosingfunction(this, _) }
|
predicate isLocal() { enclosingfunction(this, _) }
|
||||||
}
|
|
||||||
|
|
||||||
class ProxyClass extends UserType {
|
|
||||||
ProxyClass() { usertypes(this, _, 9) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class TemplateParameter extends UserType {
|
|
||||||
TemplateParameter() { usertypes(this, _, 7) or usertypes(this, _, 8) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class Class extends UserType {
|
|
||||||
Class() { ResolveClass::isClass(this) }
|
|
||||||
|
|
||||||
|
// Gets a member of this class, if it's a class.
|
||||||
Declaration getAMember() {
|
Declaration getAMember() {
|
||||||
exists(Declaration d | member(this, _, d) |
|
exists(Declaration d | member(this, _, d) |
|
||||||
result = d or
|
result = d or
|
||||||
@@ -188,10 +257,18 @@ class Class extends UserType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TemplateClass extends Class {
|
class ProxyClass extends UserType {
|
||||||
|
ProxyClass() { usertypes(this, _, 9) }
|
||||||
|
}
|
||||||
|
|
||||||
|
class TemplateParameter extends UserType {
|
||||||
|
TemplateParameter() { usertypes(this, _, 7) or usertypes(this, _, 8) }
|
||||||
|
}
|
||||||
|
|
||||||
|
class TemplateClass extends UserType {
|
||||||
TemplateClass() { usertypes(this, _, 6) }
|
TemplateClass() { usertypes(this, _, 6) }
|
||||||
|
|
||||||
Class getAnInstantiation() {
|
UserType getAnInstantiation() {
|
||||||
class_instantiation(result, this) and
|
class_instantiation(result, this) and
|
||||||
class_template_argument(result, _, _)
|
class_template_argument(result, _, _)
|
||||||
}
|
}
|
||||||
@@ -204,7 +281,63 @@ deprecated class Property extends Declaration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FriendDecl extends Declaration, @frienddecl {
|
class FriendDecl extends Declaration, @frienddecl {
|
||||||
override string getName() { result = this.getDeclaringClass().getName() + "'s friend" }
|
override string getName() {
|
||||||
|
result = getUserTypeNameWithArgs(this.getDeclaringClass()) + "'s friend"
|
||||||
|
}
|
||||||
|
|
||||||
Class getDeclaringClass() { frienddecls(this, result, _, _) }
|
UserType getDeclaringClass() { frienddecls(this, result, _, _) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getUserTypeNameWithArgs(UserType t) { usertypes(t, result, _) }
|
||||||
|
|
||||||
|
private string getUserTypeNameWithoutArgs(UserType t) {
|
||||||
|
result = getUserTypeNameWithArgs(t).splitAt("<", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate hasTypeQualifier(Declaration d) {
|
||||||
|
d instanceof EnumConstant
|
||||||
|
or
|
||||||
|
d.hasDeclaringType()
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getTypeQualifierForMembersWithArgs(UserType t) {
|
||||||
|
result = t.getTypeQualifierWithArgs() + "::" + getUserTypeNameWithArgs(t)
|
||||||
|
or
|
||||||
|
not hasTypeQualifier(t) and
|
||||||
|
result = getUserTypeNameWithArgs(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getTypeQualifierForMembersWithoutArgs(UserType t) {
|
||||||
|
result = t.getTypeQualifierWithoutArgs() + "::" + getUserTypeNameWithoutArgs(t)
|
||||||
|
or
|
||||||
|
not hasTypeQualifier(t) and
|
||||||
|
result = getUserTypeNameWithoutArgs(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The order of parameters on this predicate is chosen to match the most common
|
||||||
|
// use case: finding a declaration that has a specific name. The declaration
|
||||||
|
// comes last because it's the output.
|
||||||
|
cached
|
||||||
|
private predicate declarationHasQualifiedName(
|
||||||
|
string baseName, string typeQualifier, string namespaceQualifier, Declaration d
|
||||||
|
) {
|
||||||
|
namespaceQualifier = d.getNamespace().getQualifiedName() and
|
||||||
|
(
|
||||||
|
if hasTypeQualifier(d)
|
||||||
|
then typeQualifier = d.getTypeQualifierWithoutArgs()
|
||||||
|
else typeQualifier = ""
|
||||||
|
) and
|
||||||
|
(
|
||||||
|
baseName = getUserTypeNameWithoutArgs(d)
|
||||||
|
or
|
||||||
|
// If a declaration isn't a `UserType`, there are two ways it can still
|
||||||
|
// contain `<`:
|
||||||
|
// 1. If it's `operator<` or `operator<<`.
|
||||||
|
// 2. If it's a conversion operator like `operator TemplateClass<Arg>`.
|
||||||
|
// Perhaps these names ought to be fixed up, but we don't do that
|
||||||
|
// currently.
|
||||||
|
not d instanceof UserType and
|
||||||
|
baseName = d.getName()
|
||||||
|
) and
|
||||||
|
d.canHaveQualifiedName()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user