Skip to content

Implement "Statements" package #938

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import SideEffects1
import SideEffects2
import SmartPointers1
import SmartPointers2
import Statements
import Strings
import Templates
import Toolchain
Expand Down Expand Up @@ -102,6 +103,7 @@ newtype TCPPQuery =
TSideEffects2PackageQuery(SideEffects2Query q) or
TSmartPointers1PackageQuery(SmartPointers1Query q) or
TSmartPointers2PackageQuery(SmartPointers2Query q) or
TStatementsPackageQuery(StatementsQuery q) or
TStringsPackageQuery(StringsQuery q) or
TTemplatesPackageQuery(TemplatesQuery q) or
TToolchainPackageQuery(ToolchainQuery q) or
Expand Down Expand Up @@ -157,6 +159,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
isSideEffects2QueryMetadata(query, queryId, ruleId, category) or
isSmartPointers1QueryMetadata(query, queryId, ruleId, category) or
isSmartPointers2QueryMetadata(query, queryId, ruleId, category) or
isStatementsQueryMetadata(query, queryId, ruleId, category) or
isStringsQueryMetadata(query, queryId, ruleId, category) or
isTemplatesQueryMetadata(query, queryId, ruleId, category) or
isToolchainQueryMetadata(query, queryId, ruleId, category) or
Expand Down
61 changes: 61 additions & 0 deletions cpp/common/src/codingstandards/cpp/exclusions/cpp/Statements.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
import cpp
import RuleMetadata
import codingstandards.cpp.exclusions.RuleMetadata

newtype StatementsQuery =
TAppropriateStructureOfSwitchStatementQuery() or
TLegacyForStatementsShouldBeSimpleQuery() or
TForRangeInitializerAtMostOneFunctionCallQuery()

predicate isStatementsQueryMetadata(Query query, string queryId, string ruleId, string category) {
query =
// `Query` instance for the `appropriateStructureOfSwitchStatement` query
StatementsPackage::appropriateStructureOfSwitchStatementQuery() and
queryId =
// `@id` for the `appropriateStructureOfSwitchStatement` query
"cpp/misra/appropriate-structure-of-switch-statement" and
ruleId = "RULE-9-4-2" and
category = "required"
or
query =
// `Query` instance for the `legacyForStatementsShouldBeSimple` query
StatementsPackage::legacyForStatementsShouldBeSimpleQuery() and
queryId =
// `@id` for the `legacyForStatementsShouldBeSimple` query
"cpp/misra/legacy-for-statements-should-be-simple" and
ruleId = "RULE-9-5-1" and
category = "advisory"
or
query =
// `Query` instance for the `forRangeInitializerAtMostOneFunctionCall` query
StatementsPackage::forRangeInitializerAtMostOneFunctionCallQuery() and
queryId =
// `@id` for the `forRangeInitializerAtMostOneFunctionCall` query
"cpp/misra/for-range-initializer-at-most-one-function-call" and
ruleId = "RULE-9-5-2" and
category = "required"
}

module StatementsPackage {
Query appropriateStructureOfSwitchStatementQuery() {
//autogenerate `Query` type
result =
// `Query` type for `appropriateStructureOfSwitchStatement` query
TQueryCPP(TStatementsPackageQuery(TAppropriateStructureOfSwitchStatementQuery()))
}

Query legacyForStatementsShouldBeSimpleQuery() {
//autogenerate `Query` type
result =
// `Query` type for `legacyForStatementsShouldBeSimple` query
TQueryCPP(TStatementsPackageQuery(TLegacyForStatementsShouldBeSimpleQuery()))
}

Query forRangeInitializerAtMostOneFunctionCallQuery() {
//autogenerate `Query` type
result =
// `Query` type for `forRangeInitializerAtMostOneFunctionCall` query
TQueryCPP(TStatementsPackageQuery(TForRangeInitializerAtMostOneFunctionCallQuery()))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* @id cpp/misra/appropriate-structure-of-switch-statement
* @name RULE-9-4-2: The structure of a switch statement shall be appropriate
* @description A switch statement should have an appropriate structure with proper cases, default
* labels, and break statements to ensure clear control flow and prevent unintended
* fall-through behavior.
* @kind problem
* @precision very-high
* @problem.severity error
* @tags external/misra/id/rule-9-4-2
* correctness
* maintainability
* readability
* external/misra/allocated-target/single-translation-unit
* external/misra/enforcement/decidable
* external/misra/obligation/required
*/

import cpp
import codingstandards.cpp.misra
import codingstandards.cpp.SwitchStatement
import codingstandards.cpp.Noreturn

from SwitchStmt switch, string message
where
not isExcluded(switch, StatementsPackage::appropriateStructureOfSwitchStatementQuery()) and
/* 1. There is a statement that appears as an initializer and is not a declaration statement. */
exists(Stmt initializer | initializer = switch.getInitialization() |
not initializer instanceof DeclStmt
) and
message = "contains a statement that that is not a simple declaration"
or
/* 2. There is a switch case label that does not lead a branch (i.e. a switch case label is nested). */
exists(SwitchCase case | case = switch.getASwitchCase() | case instanceof NestedSwitchCase) and
message = "contains a switch label that is not directly within the switch body"
or
/* 3. There is a non-case label in a label group. */
exists(SwitchCase case | case = switch.getASwitchCase() |
case.getAStmt().getChildStmt*() instanceof LabelStmt
) and
message = "contains a statement label that is not a case label"
or
/* 4. There is a statement before the first case label. */
exists(Stmt switchBody | switchBody = switch.getStmt() |
not switchBody.getChild(0) instanceof SwitchCase
) and
message = "has a statement that is not a case label as its first element"
or
/* 5. There is a switch case whose terminator is not one of the allowed kinds. */
exists(SwitchCase case, Stmt lastStmt |
case = switch.getASwitchCase() and lastStmt = case.getLastStmt()
|
not (
lastStmt instanceof BreakStmt or
lastStmt instanceof ReturnStmt or
lastStmt instanceof GotoStmt or
lastStmt instanceof ContinueStmt or
lastStmt.(ExprStmt).getExpr() instanceof ThrowExpr or
lastStmt.(ExprStmt).getExpr().(Call).getTarget() instanceof NoreturnFunction or
lastStmt.getAnAttribute().getName().matches("%fallthrough") // We'd like to consider compiler variants such as `clang::fallthrough`.
)
) and
message = "is missing a terminator that moves the control out of its body"
or
/* 6. The switch statement does not have more than two unique branches. */
count(SwitchCase case |
case = switch.getASwitchCase() and
/*
* If the next switch case is the following statement of this switch case, then the two
* switch cases are consecutive and should be considered as constituting one branch
* together.
*/

not case.getNextSwitchCase() = case.getFollowingStmt()
|
case
) < 2 and
message = "contains less than two branches"
or
/* 7-1. The switch statement is not an enum switch statement and is missing a default case. */
not switch instanceof EnumSwitch and
not switch.hasDefaultCase() and
message = "lacks a default case"
or
/*
* 7-2. The switch statement is an enum switch statement and is missing a branch for a
* variant.
*/

exists(switch.(EnumSwitch).getAMissingCase()) and
message = "lacks a case for one of its variants"
select switch, "Switch statement " + message + "."
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @id cpp/misra/legacy-for-statements-should-be-simple
* @name RULE-9-5-1: Legacy for statements should be simple
* @description Legacy for statements with complex initialization, condition, and increment
* expressions can be difficult to understand and maintain. Simple for loops are more
* readable.
* @kind problem
* @precision high
* @problem.severity recommendation
* @tags external/misra/id/rule-9-5-1
* maintainability
* readability
* external/misra/allocated-target/single-translation-unit
* external/misra/enforcement/decidable
* external/misra/obligation/advisory
*/

import cpp
import codingstandards.cpp.misra

from
where
not isExcluded(x, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and
select
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @id cpp/misra/for-range-initializer-at-most-one-function-call
* @name RULE-9-5-2: A for-range-initializer shall contain at most one function call
* @description Multiple function calls in a for-range-initializer can lead to unclear iteration
* behavior and potential side effects that make the code harder to understand and
* debug.
* @kind problem
* @precision very-high
* @problem.severity error
* @tags external/misra/id/rule-9-5-2
* correctness
* maintainability
* readability
* external/misra/allocated-target/single-translation-unit
* external/misra/enforcement/decidable
* external/misra/obligation/required
*/

import cpp
import codingstandards.cpp.misra

from RangeBasedForStmt foreach, string message
where
not isExcluded(foreach, StatementsPackage::forRangeInitializerAtMostOneFunctionCallQuery()) and
count(Call call | call = foreach.getRange().getAChild*() | call) >= 2 and
message = "has nested call expression in its initializer"
select foreach, "Range-based for loop " + message + "."
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
| test.cpp:28:3:37:3 | switch (...) ... | Switch statement contains a statement that that is not a simple declaration. |
| test.cpp:51:3:60:3 | switch (...) ... | Switch statement contains a switch label that is not directly within the switch body. |
| test.cpp:62:3:71:3 | switch (...) ... | Switch statement contains a switch label that is not directly within the switch body. |
| test.cpp:75:3:85:3 | switch (...) ... | Switch statement contains a statement label that is not a case label. |
| test.cpp:89:3:97:3 | switch (...) ... | Switch statement has a statement that is not a case label as its first element. |
| test.cpp:147:3:154:3 | switch (...) ... | Switch statement is missing a terminator that moves the control out of its body. |
| test.cpp:188:3:192:3 | switch (...) ... | Switch statement contains less than two branches. |
| test.cpp:194:3:200:3 | switch (...) ... | Switch statement contains less than two branches. |
| test.cpp:215:3:219:3 | switch (...) ... | Switch statement contains less than two branches. |
| test.cpp:215:3:219:3 | switch (...) ... | Switch statement lacks a default case. |
| test.cpp:223:3:229:3 | switch (...) ... | Switch statement lacks a case for one of its variants. |
| test.cpp:231:3:239:3 | switch (...) ... | Switch statement lacks a case for one of its variants. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql
Loading
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy