11import semmle.code.cpp.Element
22import semmle.code.cpp.Specifier
33import semmle.code.cpp.Namespace
4+ private import semmle.code.cpp.internal.QualifiedName as Q
45
56/**
67 * A C/C++ declaration: for example, a variable declaration, a type
@@ -30,16 +31,7 @@ abstract class Declaration extends Locatable, @declaration {
3031 * namespace of the structure.
3132 */
3233 Namespace getNamespace ( ) {
33- // Top level declaration in a namespace ...
34- result .getADeclaration ( ) = this
35-
36- // ... or nested in another structure.
37- or
38- exists ( Declaration m
39- | m = this and result = m .getDeclaringType ( ) .getNamespace ( ) )
40- or
41- exists ( EnumConstant c
42- | c = this and result = c .getDeclaringEnum ( ) .getNamespace ( ) )
34+ result = this .( Q:: Declaration ) .getNamespace ( )
4335 or
4436 exists ( Parameter p
4537 | p = this and result = p .getFunction ( ) .getNamespace ( ) )
@@ -50,40 +42,56 @@ abstract class Declaration extends Locatable, @declaration {
5042
5143 /**
5244 * Gets the name of the declaration, fully qualified with its
53- * namespace. For example: "A::B::C::myfcn".
45+ * namespace and declaring type.
46+ *
47+ * For performance, prefer the multi-argument `hasQualifiedName` or
48+ * `hasGlobalName` predicates since they don't construct so many intermediate
49+ * strings. For debugging, the `semmle.code.cpp.Print` module produces more
50+ * detailed output but are also more expensive to compute.
51+ *
52+ * Example: `getQualifiedName() =
53+ * "namespace1::namespace2::TemplateClass1<int>::Class2::memberName"`.
5454 */
5555 string getQualifiedName ( ) {
56- // MemberFunction, MemberVariable, MemberType
57- exists ( Declaration m
58- | m = this and
59- not m instanceof EnumConstant and
60- result = m .getDeclaringType ( ) .getQualifiedName ( ) + "::" + m .getName ( ) )
61- or
62- exists ( EnumConstant c
63- | c = this and
64- result = c .getDeclaringEnum ( ) .getQualifiedName ( ) + "::" + c .getName ( ) )
65- or
66- exists ( GlobalOrNamespaceVariable v , string s1 , string s2
67- | v = this and
68- s2 = v .getNamespace ( ) .getQualifiedName ( ) and
69- s1 = v .getName ( )
70- | ( s2 != "" and result = s2 + "::" + s1 ) or ( s2 = "" and result = s1 ) )
71- or
72- exists ( Function f , string s1 , string s2
73- | f = this and f .isTopLevel ( ) and
74- s2 = f .getNamespace ( ) .getQualifiedName ( ) and
75- s1 = f .getName ( )
76- | ( s2 != "" and result = s2 + "::" + s1 ) or ( s2 = "" and result = s1 ) )
77- or
78- exists ( UserType t , string s1 , string s2
79- | t = this and t .isTopLevel ( ) and
80- s2 = t .getNamespace ( ) .getQualifiedName ( ) and
81- s1 = t .getName ( )
82- | ( s2 != "" and result = s2 + "::" + s1 ) or ( s2 = "" and result = s1 ) )
56+ result = this .( Q:: Declaration ) .getQualifiedName ( )
8357 }
8458
85- predicate hasQualifiedName ( string name ) {
86- this .getQualifiedName ( ) = name
59+ /**
60+ * Holds if this declaration has the fully-qualified name `qualifiedName`.
61+ * See `getQualifiedName`.
62+ */
63+ predicate hasQualifiedName ( string qualifiedName ) {
64+ this .getQualifiedName ( ) = qualifiedName
65+ }
66+
67+ /**
68+ * Holds if this declaration has a fully-qualified name with a name-space
69+ * component of `namespaceQualifier`, a declaring type of `typeQualifier`,
70+ * and a base name of `baseName`. Template parameters and arguments are
71+ * stripped from all components. Missing components are `""`.
72+ *
73+ * Example: `hasQualifiedName("namespace1::namespace2",
74+ * "TemplateClass1::Class2", "memberName")`.
75+ *
76+ * Example (the class `std::vector`): `hasQualifiedName("std", "", "vector")`
77+ * or `hasQualifiedName("std", "vector")`.
78+ *
79+ * Example (the `size` member function of class `std::vector`):
80+ * `hasQualifiedName("std", "vector", "size")`.
81+ */
82+ predicate hasQualifiedName ( string namespaceQualifier , string typeQualifier , string baseName ) {
83+ this .( Q:: Declaration ) .hasQualifiedName ( namespaceQualifier , typeQualifier , baseName )
84+ }
85+
86+ /**
87+ * Holds if this declaration has a fully-qualified name with a name-space
88+ * component of `namespaceQualifier`, no declaring type, and a base name of
89+ * `baseName`.
90+ *
91+ * See the 3-argument `hasQualifiedName` for more examples.
92+ */
93+ predicate hasQualifiedName ( string namespaceQualifier , string baseName ) {
94+ this .hasQualifiedName ( namespaceQualifier , "" , baseName )
8795 }
8896
8997 override string toString ( ) { result = this .getName ( ) }
@@ -93,22 +101,24 @@ abstract class Declaration extends Locatable, @declaration {
93101 *
94102 * This name doesn't include a namespace or any argument types, so
95103 * for example both functions `::open()` and `::std::ifstream::open(...)`
96- * have the same name.
104+ * have the same name. The name of a template _class_ includes a string
105+ * representation of its parameters, and the names of its instantiations
106+ * include string representations of their arguments. Template _functions_
107+ * and their instantiations do not include template parameters or arguments.
97108 *
98- * To get the name including the namespace, use `getQualifiedName` or
99- * `hasQualifiedName`.
109+ * To get the name including the namespace, use `hasQualifiedName`.
100110 *
101111 * To test whether this declaration has a particular name in the global
102112 * namespace, use `hasGlobalName`.
103113 */
104- abstract string getName ( ) ;
114+ string getName ( ) { result = this .( Q:: Declaration ) .getName ( ) }
115+
105116 /** Holds if this declaration has the given name. */
106117 predicate hasName ( string name ) { name = this .getName ( ) }
107118
108119 /** Holds if this declaration has the given name in the global namespace. */
109120 predicate hasGlobalName ( string name ) {
110- hasName ( name )
111- and getNamespace ( ) instanceof GlobalNamespace
121+ this .hasQualifiedName ( "" , "" , name )
112122 }
113123
114124 /** Gets a specifier of this declaration. */
0 commit comments