From db5b3bca6fafd92908a640ad73f811b19be193c8 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 19 Nov 2025 18:01:18 -0800 Subject: [PATCH 1/3] Test improvement --- .../src/rules/M0-1-3/UnusedLocalVariable.ql | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql index e89e9ec135..f1041b8188 100644 --- a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql +++ b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql @@ -18,6 +18,25 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.deadcode.UnusedVariables +predicate excludedConstantValue(string value) { + // 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 + value = any(ClassTemplateInstantiation cti).getTemplateArgument(_).(Expr).getValue() + or + // For static asserts too, check if there is a child which has the same value + // as the constexpr variable. + value = any(StaticAssert sa).getCondition().getAChild*().getValue() +} + +pragma[inline_late] +bindingset[variable] +predicate excludeVariableByValue(Variable variable) { + variable.isConstexpr() and + excludedConstantValue(getConstExprValue(variable)) +} + // 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 @@ -26,21 +45,31 @@ 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)) + + //count(ClassTemplateInstantiation cti | + // cti.getTemplateArgument(_).(Expr).getValue() = getConstExprValue(v) + //) + // In case an array type uses a constant in the same scope as the constexpr variable, // consider it as used. countUsesInLocalArraySize(v) } +predicate isConservativelyUnused(Variable v) { + getUseCountConservatively(v) = 0 + and + not excludeVariableByValue(v) +} + +pragma[inline_late] +bindingset[v] +predicate mayAppearInStaticAssert(Variable v) { + // For static asserts too, check if there is a child which has the same value + // as the constexpr variable. + v.isConstexpr() and + exists(StaticAssert sa | + sa.getCondition().getAChild*().getValue() = getConstExprValue(v) + ) +} + from PotentiallyUnusedLocalVariable v where not isExcluded(v, DeadCodePackage::unusedLocalVariableQuery()) and @@ -54,5 +83,5 @@ where exists(another.getAnAccess()) and another != v ) and - getUseCountConservatively(v) = 0 + isConservativelyUnused(v) select v, "Local variable '" + v.getName() + "' in '" + v.getFunction().getName() + "' is not used." From d5dacfddabbc00a6d7180119b0ec5d867e531dad Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 19 Nov 2025 18:25:56 -0800 Subject: [PATCH 2/3] Improve performance of M0-1-3's unused local variable query. --- ...rformance-m0-1-3-unused-local-variables.md | 2 + .../src/rules/M0-1-3/UnusedLocalVariable.ql | 38 ++++++++----------- 2 files changed, 18 insertions(+), 22 deletions(-) create mode 100644 change_notes/2025-11-19-improve-performance-m0-1-3-unused-local-variables.md diff --git a/change_notes/2025-11-19-improve-performance-m0-1-3-unused-local-variables.md b/change_notes/2025-11-19-improve-performance-m0-1-3-unused-local-variables.md new file mode 100644 index 0000000000..373a23e602 --- /dev/null +++ b/change_notes/2025-11-19-improve-performance-m0-1-3-unused-local-variables.md @@ -0,0 +1,2 @@ + - `M0-1-3` - `UnusedLocalVariable.ql`: + - Improved performance of the unused local variable analysis by moving constant expression value extraction to a separate pass, eliminating certain expensive joins. \ No newline at end of file diff --git a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql index f1041b8188..f51ce0cfc3 100644 --- a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql +++ b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql @@ -18,6 +18,13 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.deadcode.UnusedVariables +// Collect constant values that we should use to exclude otherwise unused constexpr variables. +// +// For constexpr variables used as template arguments or in static_asserts, we don't see accesses +// (just the appropriate literals). We therefore take a conservative approach and do not report +// constexpr variables whose values are used in such contexts. +// +// For performance reasons, these special values should be collected in a single pass. predicate excludedConstantValue(string value) { // 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 @@ -30,46 +37,33 @@ predicate excludedConstantValue(string value) { value = any(StaticAssert sa).getCondition().getAChild*().getValue() } -pragma[inline_late] -bindingset[variable] +/** + * Defines the local variables that should be excluded from the unused variable analysis based + * on their constant value. + * + * See `excludedConstantValue` for more details. + */ predicate excludeVariableByValue(Variable variable) { variable.isConstexpr() and excludedConstantValue(getConstExprValue(variable)) } -// 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() +// TODO: This predicate may be possible to merge with M0-1-4's getUseCount(). These two rules +// diverged to handle `excludeVariableByValue`, but may be possible to merge. int getUseCountConservatively(Variable v) { result = count(VariableAccess access | access = v.getAnAccess()) + count(UserProvidedConstructorFieldInit cfi | cfi.getTarget() = v) + - //count(ClassTemplateInstantiation cti | - // cti.getTemplateArgument(_).(Expr).getValue() = getConstExprValue(v) - //) + // In case an array type uses a constant in the same scope as the constexpr variable, // consider it as used. countUsesInLocalArraySize(v) } predicate isConservativelyUnused(Variable v) { - getUseCountConservatively(v) = 0 - and + getUseCountConservatively(v) = 0 and not excludeVariableByValue(v) } -pragma[inline_late] -bindingset[v] -predicate mayAppearInStaticAssert(Variable v) { - // For static asserts too, check if there is a child which has the same value - // as the constexpr variable. - v.isConstexpr() and - exists(StaticAssert sa | - sa.getCondition().getAChild*().getValue() = getConstExprValue(v) - ) -} - from PotentiallyUnusedLocalVariable v where not isExcluded(v, DeadCodePackage::unusedLocalVariableQuery()) and From 0e9fc0415c524c0f3471891ffd3f01ee8dfddc20 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 20 Nov 2025 13:49:04 -0800 Subject: [PATCH 3/3] Remove outdated comment. --- cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql index f51ce0cfc3..8a9090e71b 100644 --- a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql +++ b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql @@ -26,14 +26,8 @@ import codingstandards.cpp.deadcode.UnusedVariables // // For performance reasons, these special values should be collected in a single pass. predicate excludedConstantValue(string value) { - // 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 value = any(ClassTemplateInstantiation cti).getTemplateArgument(_).(Expr).getValue() or - // For static asserts too, check if there is a child which has the same value - // as the constexpr variable. value = any(StaticAssert sa).getCondition().getAChild*().getValue() }