Deviations: Support C/C++ attributes

This commit adds support for C/C++ attributes to specify deviations
with code identifiers in the code.

Attributes are inherited from parents, and support multiple code
identifiers in a single definition.
This commit is contained in:
Luke Cartey 2025-01-28 13:17:02 +00:00
Родитель 6e68fb8645
Коммит 1a2454165d
Не найден ключ, соответствующий данной подписи
5 изменённых файлов: 151 добавлений и 5 удалений

Просмотреть файл

@ -177,6 +177,40 @@ private predicate isDeviationRangePaired(
)
}
/**
* A standard attribute that either deviates a result.
*/
class DeviationAttribute extends StdAttribute {
DeviationRecord record;
DeviationAttribute() {
this.hasQualifiedName("codingstandards", "deviation") and
// Support multiple argument deviations
"\"" + record.getCodeIdentifier() + "\"" = this.getAnArgument().getValueText()
}
DeviationRecord getDeviationRecord() { result = record }
pragma[nomagic]
Element getASuppressedElement() {
result.(Type).getAnAttribute() = this
or
result.(Stmt).getAnAttribute() = this
or
result.(Variable).getAnAttribute() = this
or
result.(Function).getAnAttribute() = this
or
result.(Expr).getEnclosingStmt() = this.getASuppressedElement()
or
result.(Stmt).getParentStmt() = this.getASuppressedElement()
or
result.(Stmt).getEnclosingFunction() = this.getASuppressedElement()
or
result.(LocalVariable) = this.getASuppressedElement().(DeclStmt).getADeclaration()
}
}
newtype TCodeIndentifierDeviation =
TSingleLineDeviation(DeviationRecord record, Comment comment, string filepath, int suppressedLine) {
(
@ -195,6 +229,9 @@ newtype TCodeIndentifierDeviation =
isDeviationRangePaired(record, beginComment, endComment) and
beginComment.getLocation().hasLocationInfo(filepath, suppressedStartLine, _, _, _) and
endComment.getLocation().hasLocationInfo(filepath, suppressedEndLine, _, _, _)
} or
TCodeIdentifierDeviation(DeviationRecord record, DeviationAttribute attribute) {
attribute.getDeviationRecord() = record
}
class CodeIdentifierDeviation extends TCodeIndentifierDeviation {
@ -203,6 +240,8 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation {
this = TSingleLineDeviation(result, _, _, _)
or
this = TMultiLineDeviation(result, _, _, _, _, _)
or
this = TCodeIdentifierDeviation(result, _)
}
/**
@ -225,6 +264,11 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation {
suppressedEndLine > elementLocationStart
)
)
or
exists(DeviationAttribute attribute |
this = TCodeIdentifierDeviation(_, attribute) and
attribute.getASuppressedElement() = e
)
}
string toString() {
@ -243,5 +287,10 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation {
suppressedStartLine + ":" + suppressedEndLine
)
)
or
exists(DeviationAttribute attribute |
this = TCodeIdentifierDeviation(_, attribute) and
result = "Deviation record " + getDeviationRecord() + " applied to " + attribute
)
}
}

Просмотреть файл

@ -1,3 +1,7 @@
| attribute_syntax.cpp:6:15:6:17 | dd1 | Use of long double type. |
| attribute_syntax.cpp:22:15:22:17 | d10 | Use of long double type. |
| attribute_syntax.cpp:30:15:30:17 | d14 | Use of long double type. |
| attribute_syntax.cpp:34:20:34:22 | d16 | Use of long double type. |
| main.cpp:13:15:13:16 | d1 | Use of long double type. |
| main.cpp:18:15:18:16 | d4 | Use of long double type. |
| main.cpp:21:15:21:16 | d6 | Use of long double type. |

Просмотреть файл

@ -1,3 +1,15 @@
| attribute_syntax.cpp:5:3:5:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ |
| attribute_syntax.cpp:17:5:17:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ |
| attribute_syntax.cpp:19:5:19:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ |
| attribute_syntax.cpp:25:5:25:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ |
| attribute_syntax.cpp:27:5:27:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ |
| attribute_syntax.cpp:31:3:31:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ |
| attribute_syntax.cpp:42:3:42:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ |
| main.cpp:12:3:12:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
| main.cpp:25:3:25:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
| main.cpp:27:3:27:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
| main.cpp:33:3:33:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
| main.cpp:35:3:35:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
| main.cpp:39:3:39:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
| nested/nested3/test3.h:5:3:5:7 | call to getZ3 | Return value from call to $@ is unused. | nested/nested3/test3.h:1:5:1:9 | getZ3 | getZ3 |
| nested/test.h:5:3:5:6 | call to getY | Return value from call to $@ is unused. | nested/test.h:1:5:1:8 | getY | getY |

Просмотреть файл

@ -0,0 +1,44 @@
int getZ() { return 5; }
int alt() {
int x = 0; // COMPLIANT[DEVIATED]
getZ(); // NON_COMPLIANT
long double dd1; // NON_COMPLIANT (A0-4-2)
long double [[codingstandards::deviation(
"a-0-4-2-deviation")]] dd3; // COMPLIANT[DEVIATED]
long double [[codingstandards::deviation("a")]] dd3a; // NON_COMPLIAT
[[codingstandards::deviation(
"a-0-4-2-deviation")]] long double dd4; // COMPLIANT[DEVIATED]
[[codingstandards::deviation("a-0-4-2-deviation")]] {
long double d7; // COMPLIANT[DEVIATED]
getZ(); // NON_COMPLIANT (A0-1-2)
long double d8; // COMPLIANT[DEVIATED]
getZ(); // NON_COMPLIANT (A0-1-2)
long double d9; // COMPLIANT[DEVIATED]
}
long double d10; // NON_COMPLIANT (A0-4-2)
[[codingstandards::deviation("a-0-4-2-deviation")]] {
long double d11; // COMPLIANT[DEVIATED]
getZ(); // NON_COMPLIANT (A0-1-2)
long double d12; // COMPLIANT[DEVIATED]
getZ(); // NON_COMPLIANT (A0-1-2)
long double d13; // COMPLIANT[DEVIATED]
}
long double d14; // NON_COMPLIANT (A0-4-2)
getZ(); // NON_COMPLIANT (A0-1-2)
[[codingstandards::deviation("a-0-4-2-deviation")]]
for (long double d15 = 0.0; true;) {} // COMPLIANT[DEVIATED]
for (long double d16 = 0.0; true;) { // NON_COMPLIANT (A0-4-2)
}
return 0;
}
[[codingstandards::deviation("a-0-4-2-deviation")]]
int alt2() {
int x = 0; // COMPLIANT[DEVIATED]
getZ(); // NON_COMPLIANT
long double dd1; // COMPLIANT[DEVIATED]
}

Просмотреть файл

@ -421,15 +421,50 @@ The `process_coding_standards_config.py` has a dependency on the package `pyyaml
`pip3 install -r path/to/codeql-coding-standards/scripts/configuration/requirements.txt`
##### Deviation code identifiers
##### Deviation code identifier attributes
A code identifier specified in a deviation record can be applied to certain results in the code by adding a comment marker consisting of a `code-identifier` with some optional annotations. The supported marker annotation formats are:
A code identifier specified in a deviation record can be applied to certain results in the code by adding a C or C++ attribute of the following format:
```
[[codingstandards::deviation("code-identifier")]]
```
This attribute may be added to the following program elements:
* Functions
* Statements
* Variables
* Type declarations
Deviation attributes are inherited from parents in the code structure. For example, a deviation attribute applied to a function will apply the deviation to all code within the function. Note: deviations are not inherited by lambda expressions.
Multiple code identifiers may be passed in a single attribute to apply multiple deviations, for example:
```
[[codingstandards::deviation("code-identifier-1", "code-identifier-2")]]
```
Note - considation should be taken to ensure the use of custom attributes for deviations is compatible with your chosen language version, compiler, compiler configuration and coding standard.
**Use of attributes in C Coding Standards**: The C Standard introduces attributes in C23, however some compilers support attributes as a language extension in prior versions. You should:
* Confirm that your compiler supports attributes for your chosen compiler configuration, if necessary as a language extension.
* Confirm that unknown attributes are ignored by the compiler.
* For MISRA C, add a project deviation against "Rule 1.2: Language extensions should not be used", if attribute support is a language extension in your language version.
**Use of attributes in C++ Coding Standards**: The C++ Standard supports attributes in C++14, however the handling of unknown attributes is implementation defined. From C++17 onwards, unknown attributes are mandated to be ignored. Unknown attributes will usually raise an "unknown attribute" warning. You should:
* If using C++14, confirm that your compiler ignores unknown attributes.
* If using AUTOSAR and a compiler which produces warnings on unknown attributes, the compiler warning should be disabled (as per `A1-1-2: A warning level of the compilation process shall be set in compliance with project policies`), to ensure compliance with `A1-4-3: All code should compiler free of compiler warnings`.
If you cannot satisfy these condition, please use the deviation code identifier comment format instead.
##### Deviation code identifier comments
As an alternative to attributes, a code identifier specified in a deviation record can be applied to certain results in the code by adding a comment marker consisting of a `code-identifier` with some optional annotations. The supported marker annotation formats are:
- `<code-identifier>` - the deviation applies to results on the current line.
- `codingstandards::deviation(<code-identifier>)` - the deviation applies to results on the current line.
- `codingstandards::deviation_next_line(<code-identifier>)` - this deviation applies to results on the next line.
- `DEVIATION_BEGIN(<code-identifier>)` - marks the beginning of a range of lines where the deviation applies.
- `DEVIATION_END(<code-identifier>)` - marks the end of a range of lines where the deviation applies.
- `codingstandards::deviation_begin(<code-identifier>)` - marks the beginning of a range of lines where the deviation applies.
- `codingstandards::deviation_end(<code-identifier>)` - marks the end of a range of lines where the deviation applies.
Here are some examples, using the deviation record with the `a-0-4-2-deviation` code-identifier specified above:
```cpp
@ -465,7 +500,9 @@ A `codingstandards::deviation_end` without a matching `codingstandards::deviatio
`codingstandards::deviation_begin` and `codingstandards::deviation_end` markers only apply within a single file. Markers cannot be paired across files, and deviations do not apply to included files.
##### Deviation permit
Note: deviation markers cannot be applied to the body of a macro. Please apply the deviation to macro expansion, or use the attribute deviation format.
##### Deviation permits
The current implementation supports _deviation permits_ as described in the [MISRA Compliance:2020](https://www.misra.org.uk/app/uploads/2021/06/MISRA-Compliance-2020.pdf) section _4.3 Deviation permits_.