Skip to content

Commit 1a24541

Browse files
committed
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.
1 parent 6e68fb8 commit 1a24541

File tree

5 files changed

+151
-5
lines changed

5 files changed

+151
-5
lines changed

cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,40 @@ private predicate isDeviationRangePaired(
177177
)
178178
}
179179

180+
/**
181+
* A standard attribute that either deviates a result.
182+
*/
183+
class DeviationAttribute extends StdAttribute {
184+
DeviationRecord record;
185+
186+
DeviationAttribute() {
187+
this.hasQualifiedName("codingstandards", "deviation") and
188+
// Support multiple argument deviations
189+
"\"" + record.getCodeIdentifier() + "\"" = this.getAnArgument().getValueText()
190+
}
191+
192+
DeviationRecord getDeviationRecord() { result = record }
193+
194+
pragma[nomagic]
195+
Element getASuppressedElement() {
196+
result.(Type).getAnAttribute() = this
197+
or
198+
result.(Stmt).getAnAttribute() = this
199+
or
200+
result.(Variable).getAnAttribute() = this
201+
or
202+
result.(Function).getAnAttribute() = this
203+
or
204+
result.(Expr).getEnclosingStmt() = this.getASuppressedElement()
205+
or
206+
result.(Stmt).getParentStmt() = this.getASuppressedElement()
207+
or
208+
result.(Stmt).getEnclosingFunction() = this.getASuppressedElement()
209+
or
210+
result.(LocalVariable) = this.getASuppressedElement().(DeclStmt).getADeclaration()
211+
}
212+
}
213+
180214
newtype TCodeIndentifierDeviation =
181215
TSingleLineDeviation(DeviationRecord record, Comment comment, string filepath, int suppressedLine) {
182216
(
@@ -195,6 +229,9 @@ newtype TCodeIndentifierDeviation =
195229
isDeviationRangePaired(record, beginComment, endComment) and
196230
beginComment.getLocation().hasLocationInfo(filepath, suppressedStartLine, _, _, _) and
197231
endComment.getLocation().hasLocationInfo(filepath, suppressedEndLine, _, _, _)
232+
} or
233+
TCodeIdentifierDeviation(DeviationRecord record, DeviationAttribute attribute) {
234+
attribute.getDeviationRecord() = record
198235
}
199236

200237
class CodeIdentifierDeviation extends TCodeIndentifierDeviation {
@@ -203,6 +240,8 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation {
203240
this = TSingleLineDeviation(result, _, _, _)
204241
or
205242
this = TMultiLineDeviation(result, _, _, _, _, _)
243+
or
244+
this = TCodeIdentifierDeviation(result, _)
206245
}
207246

208247
/**
@@ -225,6 +264,11 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation {
225264
suppressedEndLine > elementLocationStart
226265
)
227266
)
267+
or
268+
exists(DeviationAttribute attribute |
269+
this = TCodeIdentifierDeviation(_, attribute) and
270+
attribute.getASuppressedElement() = e
271+
)
228272
}
229273

230274
string toString() {
@@ -243,5 +287,10 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation {
243287
suppressedStartLine + ":" + suppressedEndLine
244288
)
245289
)
290+
or
291+
exists(DeviationAttribute attribute |
292+
this = TCodeIdentifierDeviation(_, attribute) and
293+
result = "Deviation record " + getDeviationRecord() + " applied to " + attribute
294+
)
246295
}
247296
}

cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
| attribute_syntax.cpp:6:15:6:17 | dd1 | Use of long double type. |
2+
| attribute_syntax.cpp:22:15:22:17 | d10 | Use of long double type. |
3+
| attribute_syntax.cpp:30:15:30:17 | d14 | Use of long double type. |
4+
| attribute_syntax.cpp:34:20:34:22 | d16 | Use of long double type. |
15
| main.cpp:13:15:13:16 | d1 | Use of long double type. |
26
| main.cpp:18:15:18:16 | d4 | Use of long double type. |
37
| main.cpp:21:15:21:16 | d6 | Use of long double type. |
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
| 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 |
2+
| 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 |
3+
| 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 |
4+
| 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 |
5+
| 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 |
6+
| 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 |
7+
| 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 |
18
| main.cpp:12:3:12:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
9+
| main.cpp:25:3:25:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
10+
| main.cpp:27:3:27:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
11+
| main.cpp:33:3:33:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
12+
| main.cpp:35:3:35:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
13+
| main.cpp:39:3:39:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX |
214
| 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 |
315
| 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 |
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
int getZ() { return 5; }
2+
3+
int alt() {
4+
int x = 0; // COMPLIANT[DEVIATED]
5+
getZ(); // NON_COMPLIANT
6+
long double dd1; // NON_COMPLIANT (A0-4-2)
7+
8+
long double [[codingstandards::deviation(
9+
"a-0-4-2-deviation")]] dd3; // COMPLIANT[DEVIATED]
10+
long double [[codingstandards::deviation("a")]] dd3a; // NON_COMPLIAT
11+
12+
[[codingstandards::deviation(
13+
"a-0-4-2-deviation")]] long double dd4; // COMPLIANT[DEVIATED]
14+
15+
[[codingstandards::deviation("a-0-4-2-deviation")]] {
16+
long double d7; // COMPLIANT[DEVIATED]
17+
getZ(); // NON_COMPLIANT (A0-1-2)
18+
long double d8; // COMPLIANT[DEVIATED]
19+
getZ(); // NON_COMPLIANT (A0-1-2)
20+
long double d9; // COMPLIANT[DEVIATED]
21+
}
22+
long double d10; // NON_COMPLIANT (A0-4-2)
23+
[[codingstandards::deviation("a-0-4-2-deviation")]] {
24+
long double d11; // COMPLIANT[DEVIATED]
25+
getZ(); // NON_COMPLIANT (A0-1-2)
26+
long double d12; // COMPLIANT[DEVIATED]
27+
getZ(); // NON_COMPLIANT (A0-1-2)
28+
long double d13; // COMPLIANT[DEVIATED]
29+
}
30+
long double d14; // NON_COMPLIANT (A0-4-2)
31+
getZ(); // NON_COMPLIANT (A0-1-2)
32+
[[codingstandards::deviation("a-0-4-2-deviation")]]
33+
for (long double d15 = 0.0; true;) {} // COMPLIANT[DEVIATED]
34+
for (long double d16 = 0.0; true;) { // NON_COMPLIANT (A0-4-2)
35+
}
36+
return 0;
37+
}
38+
39+
[[codingstandards::deviation("a-0-4-2-deviation")]]
40+
int alt2() {
41+
int x = 0; // COMPLIANT[DEVIATED]
42+
getZ(); // NON_COMPLIANT
43+
long double dd1; // COMPLIANT[DEVIATED]
44+
}

docs/user_manual.md

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,15 +421,50 @@ The `process_coding_standards_config.py` has a dependency on the package `pyyaml
421421

422422
`pip3 install -r path/to/codeql-coding-standards/scripts/configuration/requirements.txt`
423423

424-
##### Deviation code identifiers
424+
##### Deviation code identifier attributes
425425

426-
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:
426+
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:
427+
428+
```
429+
[[codingstandards::deviation("code-identifier")]]
430+
```
431+
432+
This attribute may be added to the following program elements:
433+
* Functions
434+
* Statements
435+
* Variables
436+
* Type declarations
437+
438+
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.
439+
440+
Multiple code identifiers may be passed in a single attribute to apply multiple deviations, for example:
441+
442+
```
443+
[[codingstandards::deviation("code-identifier-1", "code-identifier-2")]]
444+
```
445+
446+
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.
447+
448+
**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:
449+
* Confirm that your compiler supports attributes for your chosen compiler configuration, if necessary as a language extension.
450+
* Confirm that unknown attributes are ignored by the compiler.
451+
* 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.
452+
453+
**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:
454+
* If using C++14, confirm that your compiler ignores unknown attributes.
455+
* 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`.
456+
457+
If you cannot satisfy these condition, please use the deviation code identifier comment format instead.
458+
459+
##### Deviation code identifier comments
460+
461+
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:
427462

428463
- `<code-identifier>` - the deviation applies to results on the current line.
429464
- `codingstandards::deviation(<code-identifier>)` - the deviation applies to results on the current line.
430465
- `codingstandards::deviation_next_line(<code-identifier>)` - this deviation applies to results on the next line.
431-
- `DEVIATION_BEGIN(<code-identifier>)` - marks the beginning of a range of lines where the deviation applies.
432-
- `DEVIATION_END(<code-identifier>)` - marks the end of a range of lines where the deviation applies.
466+
- `codingstandards::deviation_begin(<code-identifier>)` - marks the beginning of a range of lines where the deviation applies.
467+
- `codingstandards::deviation_end(<code-identifier>)` - marks the end of a range of lines where the deviation applies.
433468

434469
Here are some examples, using the deviation record with the `a-0-4-2-deviation` code-identifier specified above:
435470
```cpp
@@ -465,7 +500,9 @@ A `codingstandards::deviation_end` without a matching `codingstandards::deviatio
465500

466501
`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.
467502

468-
##### Deviation permit
503+
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.
504+
505+
##### Deviation permits
469506

470507
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_.
471508

0 commit comments

Comments
 (0)