Skip to content

Commit

Permalink
Implement RULE-2-8, project should not contain unused object definiti…
Browse files Browse the repository at this point in the history
…ons.

Also add a new AlertReporting shared query library for deduplicating results
across macro definitions/invocations/etc.

Split __attribute__((unused)) variables (and similar) to a Strict pair of queries.
  • Loading branch information
MichaelRFairhurst committed Oct 25, 2024
1 parent 2a805c0 commit 1340cdb
Show file tree
Hide file tree
Showing 22 changed files with 1,050 additions and 3 deletions.
24 changes: 24 additions & 0 deletions c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @id c/misra/unused-object-definition
* @name RULE-2-8: A project should not contain unused object definitions
* @description Object definitions which are unused should be removed.
* @kind problem
* @precision very-high
* @problem.severity recommendation
* @tags external/misra/id/rule-2-8
* maintainability
* performance
* external/misra/c/2012/amendment4
* external/misra/obligation/advisory
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.deadcode.UnusedObjects

from ReportDeadObjectAtDefinition report
where
not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionQuery()) and
not report.hasAttrUnused()
select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(),
report.getOptionalPlaceholderMessage()
24 changes: 24 additions & 0 deletions c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @id c/misra/unused-object-definition-in-macro
* @name RULE-2-8: Project macros should not include unused object definitions
* @description Macros should not have unused object definitions.
* @kind problem
* @precision very-high
* @problem.severity recommendation
* @tags external/misra/id/rule-2-8
* maintainability
* performance
* external/misra/c/2012/amendment4
* external/misra/obligation/advisory
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.deadcode.UnusedObjects

from ReportDeadObjectInMacro report
where
not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionInMacroQuery()) and
not report.hasAttrUnused()
select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(),
report.getOptionalPlaceholderMessage()
27 changes: 27 additions & 0 deletions c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @id c/misra/unused-object-definition-in-macro-strict
* @name RULE-2-8: Project macros should not include '__attribute__((unused))' object definitions
* @description A strict query which reports all unused object definitions in macros with
* '__attribute__((unused))'.
* @kind problem
* @precision very-high
* @problem.severity recommendation
* @tags external/misra/id/rule-2-8
* maintainability
* performance
* external/misra/c/2012/amendment4
* external/misra/c/strict
* external/misra/obligation/advisory
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.deadcode.UnusedObjects

from ReportDeadObjectInMacro report
where
not isExcluded(report.getPrimaryElement(),
DeadCode2Package::unusedObjectDefinitionInMacroStrictQuery()) and
report.hasAttrUnused()
select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(),
report.getOptionalPlaceholderMessage()
26 changes: 26 additions & 0 deletions c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* @id c/misra/unused-object-definition-strict
* @name RULE-2-8: A project should not contain '__attribute__((unused))' object definitions
* @description A strict query which reports all unused object definitions with
* '__attribute__((unused))'.
* @kind problem
* @precision very-high
* @problem.severity recommendation
* @tags external/misra/id/rule-2-8
* maintainability
* performance
* external/misra/c/2012/amendment4
* external/misra/c/strict
* external/misra/obligation/advisory
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.deadcode.UnusedObjects

from ReportDeadObjectAtDefinition report
where
not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionStrictQuery()) and
report.hasAttrUnused()
select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(),
report.getOptionalPlaceholderMessage()
8 changes: 8 additions & 0 deletions c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
| test.c:6:5:6:6 | definition of g2 | Unused object definition 'g2'. | test.c:6:5:6:6 | test.c:6:5:6:6 | |
| test.c:9:5:9:6 | definition of g3 | Unused object definition 'g3'. | test.c:9:5:9:6 | test.c:9:5:9:6 | |
| test.c:20:7:20:8 | definition of l2 | Unused object definition 'l2'. | test.c:20:7:20:8 | test.c:20:7:20:8 | |
| test.c:27:7:27:8 | definition of l5 | Unused object definition 'l5'. | test.c:27:7:27:8 | test.c:27:7:27:8 | |
| test.c:37:10:37:11 | definition of g5 | Unused object definition 'g5'. | test.c:37:10:37:11 | test.c:37:10:37:11 | |
| test.c:45:9:45:10 | definition of g6 | Unused object definition 'g6'. | test.c:45:9:45:10 | test.c:45:9:45:10 | |
| test.c:51:5:51:6 | definition of g7 | Unused object definition 'g7'. | test.c:51:5:51:6 | test.c:51:5:51:6 | |
| test.c:64:3:64:18 | ONLY_DEF_VAR(x) | Unused object definition 'l2' from macro '$@'. | test.c:60:1:60:34 | test.c:60:1:60:34 | ONLY_DEF_VAR |
1 change: 1 addition & 0 deletions c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.qlref
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-2-8/UnusedObjectDefinition.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
| test.c:68:1:71:5 | #define ALSO_DEF_VAR(x) int x = 0; while (1) ; | Macro 'ALSO_DEF_VAR' defines unused object of varied names, for example, '$@'. | test.c:73:16:73:17 | test.c:73:16:73:17 | l1 |
| test.c:77:1:82:3 | #define DEF_UNUSED_INNER_VAR() { int _v = 0; while (1) ; } | Macro 'DEF_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:77:1:82:3 | test.c:77:1:82:3 | (ignored) |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
| test.c:94:1:97:5 | #define ALSO_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; while (1) ; | Macro 'ALSO_DEF_ATTR_UNUSED_VAR' defines unused object of varied names, for example, '$@'. | test.c:99:28:99:29 | test.c:99:28:99:29 | l1 |
| test.c:104:1:109:3 | #define DEF_ATTR_UNUSED_INNER_VAR() { __attribute__((unused)) int _v = 0; while (1) ; } | Macro 'DEF_ATTR_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:104:1:109:3 | test.c:104:1:109:3 | (ignored) |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
| test.c:87:29:87:30 | definition of g8 | Unused object definition 'g8'. | test.c:87:29:87:30 | test.c:87:29:87:30 | |
| test.c:90:3:90:30 | ONLY_DEF_ATTR_UNUSED_VAR(x) | Unused object definition 'l2' from macro '$@'. | test.c:88:1:88:70 | test.c:88:1:88:70 | ONLY_DEF_ATTR_UNUSED_VAR |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-2-8/UnusedObjectDefinitionStrict.ql
113 changes: 113 additions & 0 deletions c/misra/test/rules/RULE-2-8/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Not a definition, only a declaration:
extern int g1; // COMPLIANT

// Both declared + defined:
extern int g2; // COMPLIANT
int g2 = 1; // NON_COMPLIANT

// Definition is only declaration:
int g3 = 1; // NON_COMPLIANT

// Definition, but value is required for program to compile:
int g4 = 1; // COMPLIANT
void f1() { g4; }

// Local variables:
void f2() {
int l1; // COMPLIANT
l1;

int l2; // NON-COMPLIANT

// Value is required for the program to compile:
int l3; // COMPLIANT
sizeof(l3);

int l4, // COMPLIANT
l5; // NON-COMPLIANT
l4;
}

// Struct fields are not objects:
struct s {
int x; // COMPLIANT
};

// Declaration of type struct is an object:
struct s g5; // NON-COMPLIANT

// Struct fields are not objects:
union u {
int x; // COMPLIANT
};

// Declaration of type union is an object:
union u g6; // NON-COMPLIANT

// Typedefs are not objects:
typedef int td1; // COMPLIANT

// Declaration of typedef type object:
td1 g7; // NON-COMPLIANT

// Function parameters are not objects:
void f3(int p) {} // COMPLIANT

// Function type parameters are not objects:
typedef int td2(int x); // COMPLIANT

// Macros that define unused vars tests:
#define ONLY_DEF_VAR(x) int x = 0;
void f4() {
ONLY_DEF_VAR(l1); // COMPLIANT
l1;
ONLY_DEF_VAR(l2); // NON-COMPLIANT
}

// NON-COMPLIANT
#define ALSO_DEF_VAR(x) \
int x = 0; \
while (1) \
;
void f5() {
ALSO_DEF_VAR(l1); // COMPLIANT
ALSO_DEF_VAR(l2); // COMPLIANT
}

#define DEF_UNUSED_INNER_VAR() \
{ \
int _v = 0; \
while (1) \
; \
} // NON-COMPLIANT
void f6() {
DEF_UNUSED_INNER_VAR(); // COMPLIANT
}

__attribute__((unused)) int g8 = 1; // NON-COMPLIANT
#define ONLY_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0;
void f7() {
ONLY_DEF_ATTR_UNUSED_VAR(l2); // NON-COMPLIANT
}

// NON-COMPLIANT
#define ALSO_DEF_ATTR_UNUSED_VAR(x) \
__attribute__((unused)) int x = 0; \
while (1) \
;
void f8() {
ALSO_DEF_ATTR_UNUSED_VAR(l1); // COMPLIANT
ALSO_DEF_ATTR_UNUSED_VAR(l2); // COMPLIANT
}

// NON-COMPLIANT
#define DEF_ATTR_UNUSED_INNER_VAR() \
{ \
__attribute__((unused)) int _v = 0; \
while (1) \
; \
}

void f9() {
DEF_ATTR_UNUSED_INNER_VAR(); // COMPLIANT
}
28 changes: 25 additions & 3 deletions cpp/common/src/codingstandards/cpp/AlertReporting.qll
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,46 @@ module MacroUnwrapper<ResultType ResultElement> {
}

/**
* Gets the primary macro that generated the result element.
* Gets the primary macro invocation that generated the result element.
*/
Macro getPrimaryMacro(ResultElement re) {
MacroInvocation getPrimaryMacroInvocation(ResultElement re) {
exists(MacroInvocation mi |
mi = getAMacroInvocation(re) and
// No other more specific macro that expands to element
not exists(MacroInvocation otherMi |
otherMi = getAMacroInvocation(re) and otherMi.getParentInvocation() = mi
) and
result = mi.getMacro()
result = mi
)
}

/**
* Gets the primary macro that generated the result element.
*/
Macro getPrimaryMacro(ResultElement re) { result = getPrimaryMacroInvocation(re).getMacro() }

/**
* If a result element is expanded from a macro invocation, then return the "primary" macro that
* generated the element, otherwise return the element itself.
*/
Element unwrapElement(ResultElement re) {
if exists(getPrimaryMacro(re)) then result = getPrimaryMacro(re) else result = re
}

/* Final class so we can extend it */
final private class FinalMacroInvocation = MacroInvocation;

/* A macro invocation that expands to create a `ResultElement` */
class ResultMacroExpansion extends FinalMacroInvocation {
ResultElement re;

ResultMacroExpansion() { re = getAnExpandedElement() }

ResultElement getResultElement() { result = re }
}

/* The most specific macro invocation that expands to create this `ResultElement`. */
class PrimaryMacroExpansion extends ResultMacroExpansion {
PrimaryMacroExpansion() { this = getPrimaryMacroInvocation(re) }
}
}
Loading

0 comments on commit 1340cdb

Please sign in to comment.