From 0fef17c85539f69a549ff29ab549403baa0fa316 Mon Sep 17 00:00:00 2001 From: "rakesh.pothengil" Date: Thu, 19 Sep 2024 11:10:57 +0900 Subject: [PATCH] Fix #665 --- change_notes/2024-09-19-fix-fp-665-M3-4-1.md | 2 + ...saryExposedIdentifierDeclarationShared.qll | 21 ++++- .../test.cpp | 94 ++++++++++++++++++- 3 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 change_notes/2024-09-19-fix-fp-665-M3-4-1.md diff --git a/change_notes/2024-09-19-fix-fp-665-M3-4-1.md b/change_notes/2024-09-19-fix-fp-665-M3-4-1.md new file mode 100644 index 0000000000..63c5f91b56 --- /dev/null +++ b/change_notes/2024-09-19-fix-fp-665-M3-4-1.md @@ -0,0 +1,2 @@ +- `M3-4-1` - `UnnecessaryExposedIdentifierDeclarationShared.qll`: + - Fixes #665. Exclude variables that are constexpr and coming from template instantiations. diff --git a/cpp/common/src/codingstandards/cpp/rules/unnecessaryexposedidentifierdeclarationshared/UnnecessaryExposedIdentifierDeclarationShared.qll b/cpp/common/src/codingstandards/cpp/rules/unnecessaryexposedidentifierdeclarationshared/UnnecessaryExposedIdentifierDeclarationShared.qll index a18ab593bb..695a8740b6 100644 --- a/cpp/common/src/codingstandards/cpp/rules/unnecessaryexposedidentifierdeclarationshared/UnnecessaryExposedIdentifierDeclarationShared.qll +++ b/cpp/common/src/codingstandards/cpp/rules/unnecessaryexposedidentifierdeclarationshared/UnnecessaryExposedIdentifierDeclarationShared.qll @@ -120,7 +120,10 @@ private predicate isTypeUse(Type t1, Type t2) { } newtype TDeclarationAccess = - ObjectAccess(Variable v, VariableAccess va) { va = v.getAnAccess() } or + ObjectAccess(Variable v, VariableAccess va) { + va = v.getAnAccess() or + v.(TemplateVariable).getAnInstantiation().getAnAccess() = va + } or /* Type access can be done in a declaration or an expression (e.g., static member function call) */ TypeAccess(Type t, Element access) { isTypeUse(access.(Variable).getUnspecifiedType(), t) @@ -205,9 +208,13 @@ class DeclarationAccess extends TDeclarationAccess { class CandidateDeclaration extends Declaration { CandidateDeclaration() { - this instanceof LocalVariable + this instanceof LocalVariable and + not this.(LocalVariable).isConstexpr() and + not this.isFromTemplateInstantiation(_) or - this instanceof GlobalOrNamespaceVariable + this instanceof GlobalOrNamespaceVariable and + not this.isFromTemplateInstantiation(_) and + not this.(GlobalOrNamespaceVariable).isConstexpr() or this instanceof Type and not this instanceof ClassTemplateInstantiation and @@ -229,7 +236,13 @@ Scope possibleScopesForDeclaration(CandidateDeclaration d) { result = scope.getStrictParent*() ) and // Limit the best scope to block statements and namespaces or control structures - (result instanceof BlockStmt or result instanceof Namespace) + ( + result instanceof BlockStmt and + // Template variables cannot be in block scope + not d instanceof TemplateVariable + or + result instanceof Namespace + ) } /* Gets the smallest scope that includes all the declaration accesses of declaration `d`. */ diff --git a/cpp/common/test/rules/unnecessaryexposedidentifierdeclarationshared/test.cpp b/cpp/common/test/rules/unnecessaryexposedidentifierdeclarationshared/test.cpp index ae3bb7b887..c4e01b8224 100644 --- a/cpp/common/test/rules/unnecessaryexposedidentifierdeclarationshared/test.cpp +++ b/cpp/common/test/rules/unnecessaryexposedidentifierdeclarationshared/test.cpp @@ -136,4 +136,96 @@ void f17() { ptr = &i; } *ptr = 1; -} \ No newline at end of file +} + +namespace a_namespace { + +constexpr static unsigned int a_constexpr_var{ + 10U}; // COMPLIANT; used in + // a_namespace and + // another_namespace_function +static unsigned int + a_namespace_var[a_constexpr_var]{}; // COMPLIANT; used in + // a_namespace_function and + // another_namespace_function + +constexpr static unsigned int a_namespace_function(void) noexcept { + unsigned int a_return_value{0U}; + + for (auto loop_var : a_namespace_var) { // usage of a_namespace_var + a_return_value += loop_var; + } + return a_return_value; +} + +constexpr static unsigned int another_namespace_function(void) noexcept { + unsigned int a_return_value{0U}; + + for (unsigned int i{0U}; i < a_constexpr_var; + i++) { // usage of a_constexpr_var + a_return_value += a_namespace_var[i]; // usage of a_namespace_var + } + return a_return_value; +} +} // namespace a_namespace + +namespace parent_namespace { +namespace child_namespace { +template class a_class_in_child_namespace { +public: + template constexpr auto &&operator()(To &&val) const noexcept { + return static_cast(val); + } +}; // a_class_in_child_namespace end + +template +extern constexpr a_class_in_child_namespace + a_class_in_child_namespace_impl{}; + +} // namespace child_namespace + +template +static constexpr auto const &a_parent_namespace_variable = + child_namespace::a_class_in_child_namespace_impl< + From>; // COMPLIANT; used in child_namespace2::a_class::bar() and + // parent_namespace::another_class::foo() + +namespace child_namespace2 { +class a_class { +public: + int func(...) { return 0; } + void foo(int x) { x++; } + template constexpr auto bar(F(*func), int b) { + foo(func(a_parent_namespace_variable( + b))); // usage of a_parent_namespace_variable + } +}; // a_class +} // namespace child_namespace2 + +class another_class { + int a; + int b; + void bar(int param) { param++; } + + bool has_value() { return a == b; } + +public: + template int foo(F(*func), int b) { + if (has_value()) { + bar(func(a_parent_namespace_variable( + b))); // usage of a_parent_namespace_variable + } + return 0; + } +}; // another_class +} // namespace parent_namespace + +template T a_func(T v) { return v++; } + +int main() { + parent_namespace::child_namespace2::a_class a_class_obj; + a_class_obj.bar(a_func, 10); + parent_namespace::another_class another_class_obj; + another_class_obj.foo(a_func, 10); + return 0; +}