|
15 | 15 |
|
16 | 16 | import cpp
|
17 | 17 | import codingstandards.c.misra
|
18 |
| -import codingstandards.cpp.rules.deadcode.DeadCode |
| 18 | +import codingstandards.cpp.alertreporting.HoldsForAllCopies |
| 19 | +import codingstandards.cpp.deadcode.UselessAssignments |
19 | 20 |
|
20 |
| -class MisraCDeadCodeQuery extends DeadCodeSharedQuery { |
21 |
| - MisraCDeadCodeQuery() { this = DeadCodePackage::deadCodeQuery() } |
| 21 | +/** |
| 22 | + * Gets an explicit cast from `e` if one exists. |
| 23 | + */ |
| 24 | +Cast getExplicitCast(Expr e) { |
| 25 | + exists(Conversion c | c = e.getExplicitlyConverted() | |
| 26 | + result = c |
| 27 | + or |
| 28 | + result = c.(ParenthesisExpr).getExpr() |
| 29 | + ) |
| 30 | +} |
| 31 | + |
| 32 | +class ExprStmtExpr extends Expr { |
| 33 | + ExprStmtExpr() { exists(ExprStmt es | es.getExpr() = this) } |
| 34 | +} |
| 35 | + |
| 36 | +/** |
| 37 | + * An "operation" as defined by MISRA C Rule 2.2 that is dead, i.e. it's removal has no effect on |
| 38 | + * the behaviour of the program. |
| 39 | + */ |
| 40 | +class DeadOperationInstance extends Expr { |
| 41 | + string description; |
| 42 | + |
| 43 | + DeadOperationInstance() { |
| 44 | + // Exclude cases nested within macro expansions, because the code may be "live" in other |
| 45 | + // expansions |
| 46 | + isNotWithinMacroExpansion(this) and |
| 47 | + exists(ExprStmtExpr e | |
| 48 | + if exists(getExplicitCast(e)) |
| 49 | + then |
| 50 | + this = getExplicitCast(e) and |
| 51 | + // void conversions are permitted |
| 52 | + not getExplicitCast(e) instanceof VoidConversion and |
| 53 | + description = "Cast operation is unused" |
| 54 | + else ( |
| 55 | + this = e and |
| 56 | + ( |
| 57 | + if e instanceof Assignment |
| 58 | + then |
| 59 | + exists(SsaDefinition sd, LocalScopeVariable v | |
| 60 | + e = sd.getDefinition() and |
| 61 | + sd.getDefiningValue(v).isPure() and |
| 62 | + // The definition is useless |
| 63 | + isUselessSsaDefinition(sd, v) and |
| 64 | + description = "Assignment to " + v.getName() + " is unused and has no side effects" |
| 65 | + ) |
| 66 | + else ( |
| 67 | + e.isPure() and |
| 68 | + description = "Result of operation is unused and has no side effects" |
| 69 | + ) |
| 70 | + ) |
| 71 | + ) |
| 72 | + ) |
| 73 | + } |
| 74 | + |
| 75 | + string getDescription() { result = description } |
22 | 76 | }
|
| 77 | + |
| 78 | +class DeadOperation = HoldsForAllCopies<DeadOperationInstance, Expr>::LogicalResultElement; |
| 79 | + |
| 80 | +from |
| 81 | + DeadOperation deadOperation, DeadOperationInstance instance, string message, Element explainer, |
| 82 | + string explainerDescription |
| 83 | +where |
| 84 | + not isExcluded(instance, DeadCodePackage::deadCodeQuery()) and |
| 85 | + instance = deadOperation.getAnElementInstance() and |
| 86 | + if instance instanceof FunctionCall |
| 87 | + then |
| 88 | + message = instance.getDescription() + " from call to function $@" and |
| 89 | + explainer = instance.(FunctionCall).getTarget() and |
| 90 | + explainerDescription = explainer.(Function).getName() |
| 91 | + else ( |
| 92 | + message = instance.getDescription() and |
| 93 | + // Ignore the explainer |
| 94 | + explainer = instance and |
| 95 | + explainerDescription = "" |
| 96 | + ) |
| 97 | +select deadOperation, message + ".", explainer, explainerDescription |
0 commit comments