Skip to content

Commit 3851261

Browse files
authored
Merge pull request #1378 from jbj/hasQualifiedName-inline-namespace
Approved by dave-bartolomeo
2 parents c0440cf + 2b424bf commit 3851261

File tree

4 files changed

+65
-2
lines changed

4 files changed

+65
-2
lines changed

change-notes/1.21/analysis-cpp.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
## Changes to QL libraries
3636
- The predicate `Declaration.hasGlobalName` now only holds for declarations that are not nested in a class. For example, it no longer holds for a member function `MyClass::myFunction` or a constructor `MyClass::MyClass`, whereas previously it would classify those two declarations as global names.
37-
- In class `Declaration`, predicates `getQualifiedName/0` and `hasQualifiedName/1` are no longer recommended for finding functions by name. Instead, use `hasGlobalName/1` and the new `hasQualifiedName/2` and `hasQualifiedName/3` predicates. This improves performance and makes it more reliable to identify names involving templates.
37+
- In class `Declaration`, predicates `getQualifiedName/0` and `hasQualifiedName/1` are no longer recommended for finding functions by name. Instead, use `hasGlobalName/1` and the new `hasQualifiedName/2` and `hasQualifiedName/3` predicates. This improves performance and makes it more reliable to identify names involving templates and inline namespaces.
3838
- Additional support for definition by reference has been added to the `semmle.code.cpp.dataflow.TaintTracking` library.
3939
- The taint tracking library now includes taint-specific edges for functions modeled in `semmle.code.cpp.models.interfaces.DataFlow`.
4040
- The taint tracking library adds flow through library functions that are modeled in `semmle.code.cpp.models.interfaces.Taint`. Queries can add subclasses of `TaintFunction` to specify additional flow.

cpp/ql/src/semmle/code/cpp/internal/QualifiedName.qll

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,32 @@ class Namespace extends @namespace {
2727
else result = this.getName()
2828
}
2929

30+
/**
31+
* Gets a namespace qualifier, like `"namespace1::namespace2"`, through which
32+
* the members of this namespace can be named. When `inline namespace` is
33+
* used, this predicate may have multiple results.
34+
*
35+
* This predicate does not take namespace aliases into account. Unlike inline
36+
* namespaces, specialization of templates cannot happen through an alias.
37+
* Aliases are also local to the compilation unit, while inline namespaces
38+
* affect the whole program.
39+
*/
40+
string getAQualifierForMembers() {
41+
if namespacembrs(_, this)
42+
then
43+
exists(Namespace ns |
44+
namespacembrs(ns, this)
45+
|
46+
result = ns.getAQualifierForMembers() + "::" + this.getName()
47+
or
48+
// If this is an inline namespace, its members are also visible in any
49+
// namespace where the members of the parent are visible.
50+
namespace_inline(this) and
51+
result = ns.getAQualifierForMembers()
52+
)
53+
else result = this.getName()
54+
}
55+
3056
Declaration getADeclaration() {
3157
if this.getName() = ""
3258
then result.isTopLevel() and not namespacembrs(_, result)
@@ -267,7 +293,7 @@ cached
267293
private predicate declarationHasQualifiedName(
268294
string baseName, string typeQualifier, string namespaceQualifier, Declaration d
269295
) {
270-
namespaceQualifier = d.getNamespace().getQualifiedName() and
296+
namespaceQualifier = d.getNamespace().getAQualifierForMembers() and
271297
(
272298
if hasTypeQualifier(d)
273299
then typeQualifier = d.getTypeQualifierWithoutArgs()

cpp/ql/test/library-tests/identifiers/qualified_names/qualifiedNames.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,26 @@ namespace templates {
5959
return getMember(tc, typedefC());
6060
}
6161
}
62+
63+
namespace std {
64+
inline namespace cpp17 {
65+
void functionInTwoNamespaces();
66+
class classInTwoNameSpaces {
67+
};
68+
inline namespace implementation {
69+
namespace ns {
70+
void functionInFourNamespaces();
71+
}
72+
}
73+
}
74+
}
75+
76+
// This code demonstrates that `functionInFourNamespaces` is indeed visible in
77+
// four name spaces.
78+
using void_fptr = void(*)();
79+
void_fptr ptrs[] = {
80+
std::ns::functionInFourNamespaces,
81+
std::cpp17::ns::functionInFourNamespaces,
82+
std::implementation::ns::functionInFourNamespaces,
83+
std::cpp17::implementation::ns::functionInFourNamespaces,
84+
};

cpp/ql/test/library-tests/identifiers/qualified_names/qualifiedNames.expected

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,17 @@
5252
| qualifiedNames.cpp:53:12:53:12 | getMember | templates::getMember | templates | | getMember | (not global) |
5353
| qualifiedNames.cpp:53:12:53:20 | getMember | templates::getMember | templates | | getMember | (not global) |
5454
| qualifiedNames.cpp:57:8:57:10 | use | templates::use | templates | | use | (not global) |
55+
| qualifiedNames.cpp:65:10:65:32 | functionInTwoNamespaces | std::cpp17::functionInTwoNamespaces | std | | functionInTwoNamespaces | (not global) |
56+
| qualifiedNames.cpp:65:10:65:32 | functionInTwoNamespaces | std::cpp17::functionInTwoNamespaces | std::cpp17 | | functionInTwoNamespaces | (not global) |
57+
| qualifiedNames.cpp:66:11:66:11 | operator= | std::cpp17::classInTwoNameSpaces::operator= | std | classInTwoNameSpaces | operator= | (not global) |
58+
| qualifiedNames.cpp:66:11:66:11 | operator= | std::cpp17::classInTwoNameSpaces::operator= | std | classInTwoNameSpaces | operator= | (not global) |
59+
| qualifiedNames.cpp:66:11:66:11 | operator= | std::cpp17::classInTwoNameSpaces::operator= | std::cpp17 | classInTwoNameSpaces | operator= | (not global) |
60+
| qualifiedNames.cpp:66:11:66:11 | operator= | std::cpp17::classInTwoNameSpaces::operator= | std::cpp17 | classInTwoNameSpaces | operator= | (not global) |
61+
| qualifiedNames.cpp:66:11:66:30 | classInTwoNameSpaces | std::cpp17::classInTwoNameSpaces | std | | classInTwoNameSpaces | (not global) |
62+
| qualifiedNames.cpp:66:11:66:30 | classInTwoNameSpaces | std::cpp17::classInTwoNameSpaces | std::cpp17 | | classInTwoNameSpaces | (not global) |
63+
| qualifiedNames.cpp:70:14:70:37 | functionInFourNamespaces | std::cpp17::implementation::ns::functionInFourNamespaces | std::cpp17::implementation::ns | | functionInFourNamespaces | (not global) |
64+
| qualifiedNames.cpp:70:14:70:37 | functionInFourNamespaces | std::cpp17::implementation::ns::functionInFourNamespaces | std::cpp17::ns | | functionInFourNamespaces | (not global) |
65+
| qualifiedNames.cpp:70:14:70:37 | functionInFourNamespaces | std::cpp17::implementation::ns::functionInFourNamespaces | std::implementation::ns | | functionInFourNamespaces | (not global) |
66+
| qualifiedNames.cpp:70:14:70:37 | functionInFourNamespaces | std::cpp17::implementation::ns::functionInFourNamespaces | std::ns | | functionInFourNamespaces | (not global) |
67+
| qualifiedNames.cpp:78:7:78:15 | void_fptr | void_fptr | | | void_fptr | void_fptr |
68+
| qualifiedNames.cpp:79:11:79:14 | ptrs | ptrs | | | ptrs | ptrs |

0 commit comments

Comments
 (0)