diff --git a/cpp/ql/lib/change-notes/2025-05-28-using-template.md b/cpp/ql/lib/change-notes/2025-05-28-using-template.md new file mode 100644 index 000000000000..7c13e1ae0ee1 --- /dev/null +++ b/cpp/ql/lib/change-notes/2025-05-28-using-template.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* Added a predicate `getReferencedMember` to `UsingDeclarationEntry`, which yields a member depending on a type template parameter. diff --git a/cpp/ql/lib/semmle/code/cpp/Namespace.qll b/cpp/ql/lib/semmle/code/cpp/Namespace.qll index 2e75a783c14f..dc138f67524b 100644 --- a/cpp/ql/lib/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/lib/semmle/code/cpp/Namespace.qll @@ -174,7 +174,27 @@ class UsingDeclarationEntry extends UsingEntry { */ Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _, _) } - override string toString() { result = "using " + this.getDeclaration().getDescription() } + /** + * Gets the member that is referenced by this using declaration, where the member depends on a + * type template parameter. + * + * For example: + * ``` + * template + * class A { + * using T::m; + * }; + * ``` + * Here, `getReferencedMember()` yields the member `m` of `T`. Observe that, + * as `T` is not instantiated, `m` is represented by a `Literal` and not + * a `Declaration`. + */ + Literal getReferencedMember() { usings(underlyingElement(this), unresolveElement(result), _, _) } + + override string toString() { + result = "using " + this.getDeclaration().getDescription() or + result = "using " + this.getReferencedMember() + } } /** diff --git a/cpp/ql/test/library-tests/comments/binding/commentBinding.expected b/cpp/ql/test/library-tests/comments/binding/commentBinding.expected index be0290274f06..e2418f7707cf 100644 --- a/cpp/ql/test/library-tests/comments/binding/commentBinding.expected +++ b/cpp/ql/test/library-tests/comments/binding/commentBinding.expected @@ -9,3 +9,6 @@ | multi.c:5:27:5:36 | // Multi 3 | declaration of multi3 | | templates.cpp:3:3:3:8 | // Foo | declaration of foo | | templates.cpp:7:3:7:8 | // Bar | definition of bar | +| templates.cpp:16:3:16:20 | // using T::member | using member | +| templates.cpp:19:3:19:28 | // using T::nested::member | using member | +| templates.cpp:25:3:25:20 | // using T::member | using member | diff --git a/cpp/ql/test/library-tests/comments/binding/templates.cpp b/cpp/ql/test/library-tests/comments/binding/templates.cpp index 2c76db6a915f..83d2947d952f 100644 --- a/cpp/ql/test/library-tests/comments/binding/templates.cpp +++ b/cpp/ql/test/library-tests/comments/binding/templates.cpp @@ -10,3 +10,18 @@ class Cl { } }; + +template +class Derived : public T { + // using T::member + using T::member; + + // using T::nested::member + using T::nested::member; +}; + +template +class Base { + // using T::member + using T::member; +}; \ No newline at end of file