diff --git a/change_notes/2023-07-26-unused-local-variable.md b/change_notes/2023-07-26-unused-local-variable.md new file mode 100644 index 0000000000..1f71a5b67f --- /dev/null +++ b/change_notes/2023-07-26-unused-local-variable.md @@ -0,0 +1 @@ + - `M0-1-3` - Consider constexpr variables used in template instantiations as "used". diff --git a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql index 50aa5ea919..3b93402261 100644 --- a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql +++ b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql @@ -18,9 +18,37 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.deadcode.UnusedVariables +/** Gets the constant value of a constexpr variable. */ +private string getConstExprValue(Variable v) { + result = v.getInitializer().getExpr().getValue() and + v.isConstexpr() +} + +// This predicate is similar to getUseCount for M0-1-4 except that it also +// considers static_asserts. This was created to cater for M0-1-3 specifically +// and hence, doesn't attempt to reuse the M0-1-4 specific predicate +// - getUseCount() +int getUseCountConservatively(Variable v) { + result = + count(VariableAccess access | access = v.getAnAccess()) + + count(UserProvidedConstructorFieldInit cfi | cfi.getTarget() = v) + + // For constexpr variables used as template arguments, we don't see accesses (just the + // appropriate literals). We therefore take a conservative approach and count the number of + // template instantiations that use the given constant, and consider each one to be a use + // of the variable + count(ClassTemplateInstantiation cti | + cti.getTemplateArgument(_).(Expr).getValue() = getConstExprValue(v) + ) + // For static asserts too, check if there is a child which has the same value + // as the constexpr variable. + + count(StaticAssert s | + s.getCondition().getAChild*().getValue() = getConstExprValue(v)) +} + from PotentiallyUnusedLocalVariable v where not isExcluded(v, DeadCodePackage::unusedLocalVariableQuery()) and // Local variable is never accessed not exists(v.getAnAccess()) + and getUseCountConservatively(v) = 0 select v, "Local variable " + v.getName() + " in " + v.getFunction().getName() + " is not used." diff --git a/cpp/autosar/test/rules/M0-1-3/test.cpp b/cpp/autosar/test/rules/M0-1-3/test.cpp index 7729371e5e..9dbe9692cd 100644 --- a/cpp/autosar/test/rules/M0-1-3/test.cpp +++ b/cpp/autosar/test/rules/M0-1-3/test.cpp @@ -44,4 +44,37 @@ void test_side_effect_init() { LA a; // NON_COMPLIANT - no constructor called LC c; // COMPLIANT - constructor called which is considered to potentially // have side effects -} \ No newline at end of file +} + +#include +#include +template class CharBuffer { +public: + int member[t]; + CharBuffer() : member{0} {} +}; + +int test_constexpr_in_template_inst() { + constexpr int line_length = 1024U; // COMPLIANT - used in template inst. + // of buffer. + CharBuffer buffer{}; + return buffer.member[0]; +} + +enum DataType : unsigned char { + int8, + int16, +}; + +template int test_constexpr_in_static_assert() { + const std::array lldts{int8}; + const std::array llams{int16}; + constexpr std::size_t mssu = 64 * 1024; // COMPLIANT - used in static assert. + static_assert((sizeof(lldts) + sizeof(llams)) <= mssu, "assert"); + return 0; +} + +int baz() { + test_constexpr_in_static_assert(); + return 0; +} diff --git a/rule_packages/cpp/DeadCode.json b/rule_packages/cpp/DeadCode.json index f322f5b0a7..53d6b41aa5 100644 --- a/rule_packages/cpp/DeadCode.json +++ b/rule_packages/cpp/DeadCode.json @@ -238,7 +238,10 @@ "tags": [ "readability", "maintainability" - ] + ], + "implementation_scope": { + "description": "In limited cases, this query can raise false-positives for variables that are defined as constexpr and used in an expression to instantiate a template." + } }, { "description": "Unused variables complicate the program and can indicate a possible mistake on the part of the programmer.", @@ -344,4 +347,4 @@ "title": "There shall be no dead code." } } -} \ No newline at end of file +} diff --git a/rule_packages/cpp/Templates.json b/rule_packages/cpp/Templates.json index faf3c67155..006f81bda6 100644 --- a/rule_packages/cpp/Templates.json +++ b/rule_packages/cpp/Templates.json @@ -192,4 +192,4 @@ "title": "In a class template with a dependent base, any name that may be found in that dependent base shall be referred to using a qualified-id or this->." } } -} \ No newline at end of file +}