mirror of
https://github.com/github/codeql.git
synced 2025-12-17 17:23:36 +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.Specifier
|
||||
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
|
||||
@@ -30,16 +31,7 @@ abstract class Declaration extends Locatable, @declaration {
|
||||
* namespace of the structure.
|
||||
*/
|
||||
Namespace getNamespace() {
|
||||
// Top level declaration in a namespace ...
|
||||
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())
|
||||
result = this.(Q::Declaration).getNamespace()
|
||||
or
|
||||
exists (Parameter p
|
||||
| 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
|
||||
* 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() {
|
||||
// MemberFunction, MemberVariable, MemberType
|
||||
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))
|
||||
result = this.(Q::Declaration).getQualifiedName()
|
||||
}
|
||||
|
||||
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() }
|
||||
@@ -93,22 +101,24 @@ abstract class Declaration extends Locatable, @declaration {
|
||||
*
|
||||
* This name doesn't include a namespace or any argument types, so
|
||||
* 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
|
||||
* `hasQualifiedName`.
|
||||
* To get the name including the namespace, use `hasQualifiedName`.
|
||||
*
|
||||
* To test whether this declaration has a particular name in the global
|
||||
* namespace, use `hasGlobalName`.
|
||||
*/
|
||||
abstract string getName();
|
||||
string getName() { result = this.(Q::Declaration).getName() }
|
||||
|
||||
/** Holds if this declaration has the given name. */
|
||||
predicate hasName(string name) { name = this.getName() }
|
||||
|
||||
/** Holds if this declaration has the given name in the global namespace. */
|
||||
predicate hasGlobalName(string name) {
|
||||
hasName(name)
|
||||
and getNamespace() instanceof GlobalNamespace
|
||||
this.hasQualifiedName("", "", name)
|
||||
}
|
||||
|
||||
/** Gets a specifier of this declaration. */
|
||||
|
||||
@@ -100,11 +100,6 @@ class EnumConstant extends Declaration, @enumconstant {
|
||||
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
|
||||
* 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. */
|
||||
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
|
||||
* 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`.
|
||||
*/
|
||||
class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
override string getName() { functions(underlyingElement(this),result,_) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getIdentityString(Declaration)` from `semmle.code.cpp.Print` instead.
|
||||
* 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 {
|
||||
Property() { none() }
|
||||
|
||||
/** Gets the name of this property. */
|
||||
override string getName() { none() }
|
||||
|
||||
/**
|
||||
* Gets nothing (provided for compatibility with Declaration).
|
||||
*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import semmle.code.cpp.Location
|
||||
import semmle.code.cpp.Declaration
|
||||
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.
|
||||
@@ -13,26 +14,6 @@ private import semmle.code.cpp.internal.ResolveClass
|
||||
* have multiple declarations.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -53,27 +34,6 @@ class Parameter extends LocalScopeVariable, @parameter {
|
||||
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
|
||||
* 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
|
||||
* `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
|
||||
@@ -135,8 +95,13 @@ class Parameter extends LocalScopeVariable, @parameter {
|
||||
* of the declaration locations.
|
||||
*/
|
||||
override Location getLocation() {
|
||||
exists(VariableDeclarationEntry vde | vde = getAnEffectiveDeclarationEntry() and result = vde.getLocation() |
|
||||
vde.isDefinition() or not getAnEffectiveDeclarationEntry().isDefinition()
|
||||
exists(VariableDeclarationEntry vde |
|
||||
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`.
|
||||
*/
|
||||
class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @usertype {
|
||||
/**
|
||||
* Gets the name of this type.
|
||||
*/
|
||||
override string getName() { usertypes(underlyingElement(this),result,_) }
|
||||
override string getName() {
|
||||
result = Declaration.super.getName()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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`. */
|
||||
predicate isVolatile() { this.getType().isVolatile() }
|
||||
|
||||
/** Gets the name of this variable. */
|
||||
override string getName() { none() }
|
||||
|
||||
/** Gets the type of this variable. */
|
||||
Type getType() { none() }
|
||||
|
||||
@@ -291,8 +288,6 @@ deprecated class StackVariable extends Variable {
|
||||
* A local variable can be declared by a `DeclStmt` or a `ConditionDeclExpr`.
|
||||
*/
|
||||
class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
override string getName() { localvariables(underlyingElement(this),_,result) }
|
||||
|
||||
override Type getType() { localvariables(underlyingElement(this),unresolveElement(result),_) }
|
||||
|
||||
override Function getFunction() {
|
||||
@@ -305,8 +300,6 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
* A C/C++ variable which has global scope or namespace scope.
|
||||
*/
|
||||
class GlobalOrNamespaceVariable extends Variable, @globalvariable {
|
||||
override string getName() { globalvariables(underlyingElement(this),_,result) }
|
||||
|
||||
override Type getType() { globalvariables(underlyingElement(this),unresolveElement(result),_) }
|
||||
|
||||
override Element getEnclosingElement() { none() }
|
||||
@@ -354,8 +347,6 @@ class MemberVariable extends Variable, @membervariable {
|
||||
/** Holds if this member is public. */
|
||||
predicate isPublic() { this.hasSpecifier("public") }
|
||||
|
||||
override string getName() { membervariables(underlyingElement(this),_,result) }
|
||||
|
||||
override Type getType() {
|
||||
if (strictcount(this.getAType()) = 1) then (
|
||||
result = this.getAType()
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
private import semmle.code.cpp.internal.ResolveClass as ResolveClass
|
||||
|
||||
class Namespace extends @namespace {
|
||||
string toString() { result = "QualifiedName Namespace" }
|
||||
|
||||
@@ -26,61 +24,72 @@ abstract class Declaration extends @declaration {
|
||||
string toString() { result = "QualifiedName Declaration" }
|
||||
|
||||
/** Gets the name of this declaration. */
|
||||
cached
|
||||
abstract string getName();
|
||||
|
||||
// Note: This is not as full featured as the getNamespace in the AST,
|
||||
// but it covers the cases we need here.
|
||||
string getTypeQualifierWithoutArgs() {
|
||||
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() {
|
||||
// Top level declaration in a namespace ...
|
||||
result.getADeclaration() = this
|
||||
or
|
||||
// ... or nested in another structure.
|
||||
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() {
|
||||
// MemberFunction, MemberVariable, MemberType
|
||||
exists(Declaration m |
|
||||
m = this 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()
|
||||
exists(string ns, string name |
|
||||
ns = this.getNamespace().getQualifiedName() and
|
||||
name = this.getName() and
|
||||
this.canHaveQualifiedName()
|
||||
|
|
||||
s2 != "" and result = s2 + "::" + s1
|
||||
or
|
||||
s2 = "" and result = s1
|
||||
exists(string t | t = this.getTypeQualifierWithArgs() |
|
||||
if ns != ""
|
||||
then result = ns + "::" + t + "::" + name
|
||||
else result = t + "::" + name
|
||||
)
|
||||
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
|
||||
not hasTypeQualifier(this) and
|
||||
if ns != ""
|
||||
then result = ns + "::" + name
|
||||
else result = name
|
||||
)
|
||||
}
|
||||
|
||||
predicate canHaveQualifiedName() {
|
||||
this.hasDeclaringType()
|
||||
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
|
||||
this instanceof EnumConstant
|
||||
or
|
||||
s2 = "" and result = s1
|
||||
)
|
||||
this instanceof Function
|
||||
or
|
||||
this instanceof UserType
|
||||
or
|
||||
this instanceof GlobalOrNamespaceVariable
|
||||
}
|
||||
|
||||
predicate isTopLevel() {
|
||||
@@ -107,11 +116,13 @@ abstract class Declaration extends @declaration {
|
||||
* For templates, both the template itself and all instantiations of
|
||||
* 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 {
|
||||
override string getName() { none() }
|
||||
|
||||
VariableDeclarationEntry getADeclarationEntry() { result.getDeclaration() = this }
|
||||
}
|
||||
|
||||
class TemplateVariable extends Variable {
|
||||
@@ -126,9 +137,73 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
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 {
|
||||
@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() {
|
||||
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, _) }
|
||||
|
||||
UserType getDeclaringEnum() { enumconstants(this, result, _, _, _, _) }
|
||||
// Unlike the usual `EnumConstant`, this one doesn't have a `getDeclaringType()`.
|
||||
}
|
||||
|
||||
class Function extends Declaration, @function {
|
||||
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 {
|
||||
@@ -162,22 +242,11 @@ class TemplateFunction extends Function {
|
||||
}
|
||||
|
||||
class UserType extends Declaration, @usertype {
|
||||
override string getName() { usertypes(this, result, _) }
|
||||
override string getName() { result = getUserTypeNameWithArgs(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() {
|
||||
exists(Declaration d | member(this, _, d) |
|
||||
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) }
|
||||
|
||||
Class getAnInstantiation() {
|
||||
UserType getAnInstantiation() {
|
||||
class_instantiation(result, this) and
|
||||
class_template_argument(result, _, _)
|
||||
}
|
||||
@@ -204,7 +281,63 @@ deprecated class Property extends Declaration {
|
||||
}
|
||||
|
||||
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