diff --git a/change_notes/2024-08-06-fix-fp-658-M0-1-3.md b/change_notes/2024-08-06-fix-fp-658-M0-1-3.md new file mode 100644 index 000000000..47a26705a --- /dev/null +++ b/change_notes/2024-08-06-fix-fp-658-M0-1-3.md @@ -0,0 +1,2 @@ +- `M0-1-3` - `UnusedLocalVariable.ql`: + - Fixes #658. Considers usage of const/constexpr variables in array size and function parameters that are used in arguments of template functions. diff --git a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql index f088bb1b7..5956515e5 100644 --- a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql +++ b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql @@ -18,10 +18,10 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.deadcode.UnusedVariables -/** Gets the constant value of a constexpr variable. */ +/** Gets the constant value of a constexpr/const variable. */ private string getConstExprValue(Variable v) { result = v.getInitializer().getExpr().getValue() and - v.isConstexpr() + (v.isConst() or v.isConstexpr()) } // This predicate is similar to getUseCount for M0-1-4 except that it also @@ -41,7 +41,14 @@ int getUseCountConservatively(Variable 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)) + count(StaticAssert s | s.getCondition().getAChild*().getValue() = getConstExprValue(v)) + + // In case an array type uses a constant in the same scope as the constexpr variable, + // consider it as used. + count(ArrayType at, LocalVariable arrayVariable | + arrayVariable.getType().resolveTypedefs() = at and + v.(PotentiallyUnusedLocalVariable).getFunction() = arrayVariable.getFunction() and + at.getArraySize().toString() = getConstExprValue(v) + ) } from PotentiallyUnusedLocalVariable v @@ -49,5 +56,13 @@ where not isExcluded(v, DeadCodePackage::unusedLocalVariableQuery()) and // Local variable is never accessed not exists(v.getAnAccess()) and + // Sometimes multiple objects representing the same entities are created in + // the AST. Check if those are not accessed as well. Refer issue #658 + not exists(LocalScopeVariable another | + another.getDefinitionLocation() = v.getDefinitionLocation() and + another.hasName(v.getName()) and + exists(another.getAnAccess()) and + another != v + ) 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/UnusedLocalVariable.expected b/cpp/autosar/test/rules/M0-1-3/UnusedLocalVariable.expected index d6f398369..19317d1d0 100644 --- a/cpp/autosar/test/rules/M0-1-3/UnusedLocalVariable.expected +++ b/cpp/autosar/test/rules/M0-1-3/UnusedLocalVariable.expected @@ -1,7 +1,6 @@ | test.cpp:7:7:7:7 | y | Local variable 'y' in 'test_simple' is not used. | -| test.cpp:14:13:14:13 | y | Local variable 'y' in 'test_const' is not used. | -| test.cpp:17:7:17:7 | z | Local variable 'z' in 'test_const' is not used. | -| test.cpp:23:5:23:5 | t | Local variable 't' in 'f1' is not used. | -| test.cpp:23:5:23:5 | t | Local variable 't' in 'f1' is not used. | -| test.cpp:44:6:44:6 | a | Local variable 'a' in 'test_side_effect_init' is not used. | -| test.cpp:91:5:91:5 | t | Local variable 't' in 'template_function' is not used. | +| test.cpp:15:7:15:7 | z | Local variable 'z' in 'test_const' is not used. | +| test.cpp:21:5:21:5 | t | Local variable 't' in 'f1' is not used. | +| test.cpp:21:5:21:5 | t | Local variable 't' in 'f1' is not used. | +| test.cpp:42:6:42:6 | a | Local variable 'a' in 'test_side_effect_init' is not used. | +| test.cpp:89:5:89:5 | t | Local variable 't' in 'template_function' 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 a591c7e82..5c9c4a341 100644 --- a/cpp/autosar/test/rules/M0-1-3/test.cpp +++ b/cpp/autosar/test/rules/M0-1-3/test.cpp @@ -11,9 +11,7 @@ int test_simple() { int test_const() { const int x = 1; // COMPLIANT - used below - const int y = 2; // COMPLIANT[FALSE_POSITIVE] - used in array initialization, - // but the database does not contain sufficient information - // for this case + const int y = 2; // COMPLIANT - used in array initialization, int z[y]; // NON_COMPLIANT - never used return x; } @@ -98,4 +96,20 @@ class ClassT { void test() {} }; -void test_template_function() { template_function(); } \ No newline at end of file +void test_template_function() { template_function(); } + +int foo() { + constexpr int arrayDim = 10; // COMPLIANT - used in array size below + static int array[arrayDim]{}; + return array[4]; +} + +template static T another_templ_function() { return T(); } + +template +static T another_templ_function(const First &first, const Rest &...rest) { + return first + + another_templ_function(rest...); // COMPLIANT - 'rest' is used here +} + +static int templ_fnc2() { return another_templ_function(1, 2, 3, 4, 5); }