Skip to content

Commit 5d8e899

Browse files
authored
Merge branch 'main' into michaelrfairhurst/package-deadcode-9-rule-0-2-3
2 parents 4e4c11d + 4e60680 commit 5d8e899

File tree

73 files changed

+3696
-449
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+3696
-449
lines changed

c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import cpp
1717
import codingstandards.c.misra
1818
import codingstandards.c.Objects
19+
import codingstandards.cpp.Expr
1920

2021
/**
2122
* Holds if the value of an expression is used or stored.
@@ -37,32 +38,14 @@ predicate isUsedOrStored(Expr e) {
3738
e = any(ClassAggregateLiteral l).getAFieldExpr(_)
3839
}
3940

40-
/**
41-
* Find expressions that defer their value directly to an inner expression
42-
* value.
43-
*
44-
* When an array is on the rhs of a comma expr, or in the then/else branch of a
45-
* ternary expr, and the result us used as a pointer, then the ArrayToPointer
46-
* conversion is marked inside comma expr/ternary expr, on the operands. These
47-
* conversions are only non-compliant if they flow into an operation or store.
48-
*
49-
* Full flow analysis with localFlowStep should not be necessary, and may cast a
50-
* wider net than needed for some queries, potentially resulting in false
51-
* positives.
52-
*/
53-
Expr temporaryObjectFlowStep(Expr e) {
54-
e = result.(CommaExpr).getRightOperand()
55-
or
56-
e = result.(ConditionalExpr).getThen()
57-
or
58-
e = result.(ConditionalExpr).getElse()
59-
}
60-
6141
from FieldAccess fa, TemporaryObjectIdentity temporary, ArrayToPointerConversion conversion
6242
where
6343
not isExcluded(conversion, InvalidMemory3Package::arrayToPointerConversionOfTemporaryObjectQuery()) and
6444
fa = temporary.getASubobjectAccess() and
6545
conversion.getExpr() = fa and
66-
isUsedOrStored(temporaryObjectFlowStep*(conversion.getExpr()))
46+
exists(Expr useOrStore |
47+
temporaryObjectFlowStep*(conversion.getExpr(), useOrStore) and
48+
isUsedOrStored(useOrStore)
49+
)
6750
select conversion, "Array to pointer conversion of array $@ from temporary object $@.",
6851
fa.getTarget(), fa.getTarget().getName(), temporary, temporary.toString()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- All queries related to integer suffixes:
2+
- No visible changes expected: the regex for parsing integer suffixes, and how they are treated after lexing, has been refactored.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- `RULE-18-9` - `ArraytoPointerConversionOfTemporaryObject.ql`
2+
- The behavior for finding flow steps of temporary objects (for example, from ternary branches to the ternary expr result) has been extracted for reuse in other rules, no visible changes expected.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
- All rules using `Linkage.qll`:
2+
- `extern const` global variables are now properly analyzed as having external linkage, rather than internal linkage.
3+
- Linkage analysis has been fixed to properly handle nested classes, including anonymous and typedefs of anonymous classes.
4+
- Linkage for names within classes with internal linkage is now properly inherited as internal, rather than external.
5+
- `M0-1-3`, `RULE-2-8` - `UnusedLocalVariable.ql`, `UnusedMemberVariable.ql`, `UnusedGlobalOrNamespaceVariable.ql`, `UnusedObjectDefinition.ql`, `UnusedObjectDefinitionStrict.ql`:
6+
- The organization of unused variable analysis has been reorganized to be usable in MISRA C++ rule 0.2.1, with no expected noticeable change in results.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `A3-3-2` - `StaticOrThreadLocalObjectsNonConstantInit`:
2+
- The checks for non-constant initialization have been moved to be usable in other queries, such as MISRA C++23 Rule 6.7.2.
3+
- No visible changes in query results expected.

cpp/autosar/src/rules/A3-3-2/StaticOrThreadLocalObjectsNonConstantInit.ql

Lines changed: 1 addition & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -15,100 +15,7 @@
1515

1616
import cpp
1717
import codingstandards.cpp.autosar
18-
19-
/**
20-
* Holds if `e` is a full expression or `AggregateLiteral` in the initializer of a
21-
* `StaticStorageDurationVariable`.
22-
*
23-
* Although `AggregateLiteral`s are expressions according to our model, they are not considered
24-
* expressions from the perspective of the standard. Therefore, we should consider components of
25-
* aggregate literals within static initializers to also be full expressions.
26-
*/
27-
private predicate isFullExprOrAggregateInStaticInitializer(Expr e) {
28-
exists(StaticStorageDurationVariable var | e = var.getInitializer().getExpr())
29-
or
30-
isFullExprOrAggregateInStaticInitializer(e.getParent().(AggregateLiteral))
31-
}
32-
33-
/**
34-
* Holds if `e` is a non-constant full expression in a static initializer, for the given `reason`
35-
* and `reasonElement`.
36-
*/
37-
private predicate nonConstantFullExprInStaticInitializer(
38-
Expr e, Element reasonElement, string reason
39-
) {
40-
isFullExprOrAggregateInStaticInitializer(e) and
41-
if e instanceof AggregateLiteral
42-
then
43-
// If this is an aggregate literal, we apply this recursively
44-
nonConstantFullExprInStaticInitializer(e.getAChild(), reasonElement, reason)
45-
else (
46-
// Otherwise we check this component to determine if it is constant
47-
not (
48-
e.getFullyConverted().isConstant() or
49-
e.(Call).getTarget().isConstexpr() or
50-
e.(VariableAccess).getTarget().isConstexpr()
51-
) and
52-
reason = "uses a non-constant element in the initialization" and
53-
reasonElement = e
54-
)
55-
}
56-
57-
/**
58-
* A `ConstructorCall` that does not represent a constant initializer for an object according to
59-
* `[basic.start.init]`.
60-
*
61-
* In addition to identifying `ConstructorCall`s which are not constant initializers, this also
62-
* provides an explanatory "reason" for why this constructor is not considered to be a constant
63-
* initializer.
64-
*/
65-
predicate isNotConstantInitializer(ConstructorCall cc, Element reasonElement, string reason) {
66-
// Must call a constexpr constructor
67-
not cc.getTarget().isConstexpr() and
68-
reason =
69-
"calls the " + cc.getTarget().getName() + "(..) constructor which is not marked as constexpr" and
70-
reasonElement = cc
71-
or
72-
// And all arguments must either be constant, or themselves call constexpr constructors
73-
cc.getTarget().isConstexpr() and
74-
exists(Expr arg | arg = cc.getAnArgument() |
75-
isNotConstantInitializer(arg, reasonElement, reason)
76-
or
77-
not arg instanceof ConstructorCall and
78-
not arg.getFullyConverted().isConstant() and
79-
not arg.(Call).getTarget().isConstexpr() and
80-
not arg.(VariableAccess).getTarget().isConstexpr() and
81-
reason = "includes a non constant " + arg.getType() + " argument to a constexpr constructor" and
82-
reasonElement = arg
83-
)
84-
}
85-
86-
/**
87-
* Identifies if a `StaticStorageDurationVariable` is not constant initialized according to
88-
* `[basic.start.init]`.
89-
*/
90-
predicate isNotConstantInitialized(
91-
StaticStorageDurationVariable v, string reason, Element reasonElement
92-
) {
93-
if v.getInitializer().getExpr() instanceof ConstructorCall
94-
then
95-
// (2.2) if initialized by a constructor call, then that constructor call must be a constant
96-
// initializer for the variable to be constant initialized
97-
isNotConstantInitializer(v.getInitializer().getExpr(), reasonElement, reason)
98-
else
99-
// (2.3) If it is not initialized by a constructor call, then it must be the case that every full
100-
// expr in the initializer is a constant expression or that the object was "value initialized"
101-
// but without a constructor call. For value initialization, there are two non-constructor call
102-
// cases to consider:
103-
//
104-
// 1. The object was zero initialized - in which case, the extractor does not include a
105-
// constructor call - instead, it has a blank aggregate literal, or no initializer.
106-
// 2. The object is an array, which will be initialized by an aggregate literal.
107-
//
108-
// In both cases it is sufficient for us to find a non-constant full expression in the static
109-
// initializer
110-
nonConstantFullExprInStaticInitializer(v.getInitializer().getExpr(), reasonElement, reason)
111-
}
18+
import codingstandards.cpp.orderofevaluation.Initialization
11219

11320
from StaticStorageDurationVariable staticOrThreadLocalVar, string reason, Element reasonElement
11421
where

cpp/autosar/src/rules/M0-1-3/UnusedGlobalOrNamespaceVariable.ql

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ import cpp
1818
import codingstandards.cpp.autosar
1919
import codingstandards.cpp.deadcode.UnusedVariables
2020

21-
from PotentiallyUnusedGlobalOrNamespaceVariable v
22-
where
23-
not isExcluded(v, DeadCodePackage::unusedGlobalOrNamespaceVariableQuery()) and
24-
// No variable access
25-
not exists(v.getAnAccess()) and
26-
// Exclude members whose value is compile time and is potentially used to inintialize a template
27-
not maybeACompileTimeTemplateArgument(v)
21+
from FullyUnusedGlobalOrNamespaceVariable v
22+
where not isExcluded(v, DeadCodePackage::unusedGlobalOrNamespaceVariableQuery())
2823
select v, "Variable '" + v.getQualifiedName() + "' is unused."

cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -18,58 +18,6 @@ import cpp
1818
import codingstandards.cpp.autosar
1919
import codingstandards.cpp.deadcode.UnusedVariables
2020

21-
// Collect constant values that we should use to exclude otherwise unused constexpr variables.
22-
//
23-
// For constexpr variables used as template arguments or in static_asserts, we don't see accesses
24-
// (just the appropriate literals). We therefore take a conservative approach and do not report
25-
// constexpr variables whose values are used in such contexts.
26-
//
27-
// For performance reasons, these special values should be collected in a single pass.
28-
predicate excludedConstantValue(string value) {
29-
value = any(ClassTemplateInstantiation cti).getTemplateArgument(_).(Expr).getValue()
30-
or
31-
value = any(StaticAssert sa).getCondition().getAChild*().getValue()
32-
}
33-
34-
/**
35-
* Defines the local variables that should be excluded from the unused variable analysis based
36-
* on their constant value.
37-
*
38-
* See `excludedConstantValue` for more details.
39-
*/
40-
predicate excludeVariableByValue(Variable variable) {
41-
variable.isConstexpr() and
42-
excludedConstantValue(getConstExprValue(variable))
43-
}
44-
45-
// TODO: This predicate may be possible to merge with M0-1-4's getUseCount(). These two rules
46-
// diverged to handle `excludeVariableByValue`, but may be possible to merge.
47-
int getUseCountConservatively(Variable v) {
48-
result =
49-
count(VariableAccess access | access = v.getAnAccess()) +
50-
count(UserProvidedConstructorFieldInit cfi | cfi.getTarget() = v) +
51-
// In case an array type uses a constant in the same scope as the constexpr variable,
52-
// consider it as used.
53-
countUsesInLocalArraySize(v)
54-
}
55-
56-
predicate isConservativelyUnused(Variable v) {
57-
getUseCountConservatively(v) = 0 and
58-
not excludeVariableByValue(v)
59-
}
60-
61-
from PotentiallyUnusedLocalVariable v
62-
where
63-
not isExcluded(v, DeadCodePackage::unusedLocalVariableQuery()) and
64-
// Local variable is never accessed
65-
not exists(v.getAnAccess()) and
66-
// Sometimes multiple objects representing the same entities are created in
67-
// the AST. Check if those are not accessed as well. Refer issue #658
68-
not exists(LocalScopeVariable another |
69-
another.getDefinitionLocation() = v.getDefinitionLocation() and
70-
another.hasName(v.getName()) and
71-
exists(another.getAnAccess()) and
72-
another != v
73-
) and
74-
isConservativelyUnused(v)
21+
from FullyUnusedLocalVariable v
22+
where not isExcluded(v, DeadCodePackage::unusedLocalVariableQuery())
7523
select v, "Local variable '" + v.getName() + "' in '" + v.getFunction().getName() + "' is not used."

cpp/autosar/src/rules/M0-1-3/UnusedMemberVariable.ql

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,6 @@ import codingstandards.cpp.autosar
1919
import codingstandards.cpp.FunctionEquivalence
2020
import codingstandards.cpp.deadcode.UnusedVariables
2121

22-
from PotentiallyUnusedMemberVariable v
23-
where
24-
not isExcluded(v, DeadCodePackage::unusedMemberVariableQuery()) and
25-
// No variable access
26-
not exists(v.getAnAccess()) and
27-
// No explicit initialization in a constructor
28-
not exists(UserProvidedConstructorFieldInit cfi | cfi.getTarget() = v) and
29-
// Exclude members whose value is compile time and is potentially used to inintialize a template
30-
not maybeACompileTimeTemplateArgument(v)
22+
from FullyUnusedMemberVariable v
23+
where not isExcluded(v, DeadCodePackage::unusedMemberVariableQuery())
3124
select v, "Member variable '" + v.getName() + "' is unused."

cpp/autosar/src/rules/M0-1-4/SingleUseGlobalOrNamespacePODVariable.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import codingstandards.cpp.autosar
1919
import codingstandards.cpp.deadcode.UnusedVariables
2020
import SingleUsePODVariable
2121

22-
from PotentiallyUnusedGlobalOrNamespaceVariable v
22+
from SecondPass::UnusedGlobalOrNamespaceVariable v
2323
where
2424
not isExcluded(v, DeadCodePackage::singleUseGlobalOrNamespacePODVariableQuery()) and
2525
isSingleUseNonVolatilePODVariable(v)

0 commit comments

Comments
 (0)