diff --git a/change_notes/2025-03-26-deviations-suppression.md b/change_notes/2025-03-26-deviations-suppression.md new file mode 100644 index 000000000..5dcb5e8db --- /dev/null +++ b/change_notes/2025-03-26-deviations-suppression.md @@ -0,0 +1 @@ + - The `DeviationsSuppression.ql` query has been restored after being incorrectly deleted in a previous release. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index 310a2b678..4b2f03cf9 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -226,8 +226,8 @@ class DeviationAttribute extends StdAttribute { DeviationRecord getADeviationRecord() { result = record } - pragma[nomagic] - Element getASuppressedElement() { + /** Gets the element to which this attribute was applied. */ + Element getPrimarySuppressedElement() { result.(Type).getAnAttribute() = this or result.(Stmt).getAnAttribute() = this @@ -235,6 +235,11 @@ class DeviationAttribute extends StdAttribute { result.(Variable).getAnAttribute() = this or result.(Function).getAnAttribute() = this + } + + pragma[nomagic] + Element getASuppressedElement() { + result = this.getPrimarySuppressedElement() or result.(Expr).getEnclosingStmt() = this.getASuppressedElement() or @@ -336,26 +341,60 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { ) } + predicate hasLocationInfo( + string filepath, int suppressedLine, int suppressedColumn, int endline, int endcolumn + ) { + exists(Comment commentMarker | + this = TSingleLineDeviation(_, commentMarker, filepath, suppressedLine) and + suppressedColumn = 1 and + endline = suppressedLine + | + if commentMarker instanceof DeviationEndOfLineMarker + then endcolumn = commentMarker.(DeviationEndOfLineMarker).getLocation().getEndColumn() + else + // Find the last column for a location on the next line + endcolumn = + max(Location l | + l.hasLocationInfo(filepath, _, _, _, _) and + l.getEndLine() = suppressedLine + | + l.getEndColumn() + ) + ) + or + this = TMultiLineDeviation(_, _, _, filepath, suppressedLine, endline) and + suppressedColumn = 1 and + endcolumn = 1 + or + exists(DeviationAttribute attribute | + this = TCodeIdentifierDeviation(_, attribute) and + attribute + .getPrimarySuppressedElement() + .getLocation() + .hasLocationInfo(filepath, suppressedLine, suppressedColumn, endline, endcolumn) + ) + } + string toString() { exists(string filepath | exists(int suppressedLine | this = TSingleLineDeviation(_, _, filepath, suppressedLine) and result = - "Deviation record " + getADeviationRecord() + " applied to " + filepath + " Line " + + "Deviation of " + getADeviationRecord().getQuery() + " applied to " + filepath + " Line " + suppressedLine ) or exists(int suppressedStartLine, int suppressedEndLine | this = TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedEndLine) and result = - "Deviation record " + getADeviationRecord() + " applied to " + filepath + " Line" + + "Deviation of " + getADeviationRecord().getQuery() + " applied to " + filepath + " Line " + suppressedStartLine + ":" + suppressedEndLine ) ) or exists(DeviationAttribute attribute | this = TCodeIdentifierDeviation(_, attribute) and - result = "Deviation record " + getADeviationRecord() + " applied to " + attribute + result = "Deviation of " + getADeviationRecord().getQuery() + " applied to " + attribute ) } } diff --git a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.qhelp b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.qhelp new file mode 100644 index 000000000..0bf3a3a71 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.qhelp @@ -0,0 +1,12 @@ + + + +

This query generates suppression information for rules that have an associated deviation record.

+
+ +
  • + MISRA Compliance 2020 document: + Chapter 4.2 (page 12) - Deviations. +
  • +
    +
    \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql new file mode 100644 index 000000000..f29c06898 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql @@ -0,0 +1,125 @@ +/** + * @name Deviation suppression + * @description Generates information about files and locations where certain alerts should be considered suppressed by deviations. + * @kind alert-suppression + * @id cpp/coding-standards/deviation-suppression + */ + +import cpp +import Deviations + +/** Holds if `lineNumber` is an indexed line number in file `f`. */ +private predicate isLineNumber(File f, int lineNumber) { + exists(Location l | l.getFile() = f | + l.getStartLine() = lineNumber + or + l.getEndLine() = lineNumber + ) +} + +/** Gets the last line number in `f`. */ +private int getLastLineNumber(File f) { result = max(int lineNumber | isLineNumber(f, lineNumber)) } + +/** Gets the last column number on the last line of `f`. */ +int getLastColumnNumber(File f) { + result = + max(Location l | + l.getFile() = f and + l.getEndLine() = getLastLineNumber(f) + | + l.getEndColumn() + ) +} + +newtype TDeviationScope = + TDeviationRecordFileScope(DeviationRecord dr, File file) { + exists(string deviationPath | + dr.isDeviated(_, deviationPath) and + file.getRelativePath().prefix(deviationPath.length()) = deviationPath + ) + } or + TDeviationRecordCodeIdentiferDeviationScope(DeviationRecord dr, CodeIdentifierDeviation c) { + c = dr.getACodeIdentifierDeviation() + } + +/** A deviation scope. */ +class DeviationScope extends TDeviationScope { + /** Gets the location at which this deviation was defined. */ + abstract Locatable getDeviationDefinitionLocation(); + + /** Gets the Query being deviated. */ + abstract Query getQuery(); + + abstract string toString(); + + abstract predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ); +} + +/** A deviation scope derived from a "path" entry in a `DeviationRecord`. */ +class DeviationRecordFileScope extends DeviationScope, TDeviationRecordFileScope { + private DeviationRecord getDeviationRecord() { this = TDeviationRecordFileScope(result, _) } + + override Locatable getDeviationDefinitionLocation() { result = getDeviationRecord() } + + private File getFile() { this = TDeviationRecordFileScope(_, result) } + + override Query getQuery() { result = getDeviationRecord().getQuery() } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + // In an ideal world, we would produce a URL here that informed the AlertSuppression code that + // the whole file was suppressed. However, experimentation suggestions the alert suppression + // code only works with locations with lines and columns, so we generate a location that covers + // the whole "indexed" file, by finding the location indexed in the database with the latest + // line and column number. + exists(File f | f = getFile() | + f.getLocation().hasLocationInfo(filepath, _, _, _, _) and + startline = 1 and + startcolumn = 1 and + endline = getLastLineNumber(f) and + endcolumn = getLastColumnNumber(f) + ) + } + + override string toString() { + result = "Deviation of " + getDeviationRecord().getQuery() + " for " + getFile() + "." + } +} + +/** + * A deviation scope derived from a comment corresponding to a "code-identifier" entry for a + * `DeviationRecord`. + */ +class DeviationRecordCommentScope extends DeviationScope, + TDeviationRecordCodeIdentiferDeviationScope +{ + private DeviationRecord getDeviationRecord() { + this = TDeviationRecordCodeIdentiferDeviationScope(result, _) + } + + private CodeIdentifierDeviation getCodeIdentifierDeviation() { + this = TDeviationRecordCodeIdentiferDeviationScope(_, result) + } + + override Locatable getDeviationDefinitionLocation() { result = getDeviationRecord() } + + override Query getQuery() { result = getDeviationRecord().getQuery() } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + getCodeIdentifierDeviation() + .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + override string toString() { result = getCodeIdentifierDeviation().toString() } +} + +from DeviationScope deviationScope +select deviationScope.getDeviationDefinitionLocation(), // suppression comment + "// lgtm[" + deviationScope.getQuery().getQueryId() + "]", // text of suppression comment (excluding delimiters) + "lgtm[" + deviationScope.getQuery().getQueryId() + "]", // text of suppression annotation + deviationScope // scope of suppression diff --git a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected new file mode 100644 index 000000000..73f564c13 --- /dev/null +++ b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected @@ -0,0 +1,11 @@ +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:12:1:12:58 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 12 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:14:1:14:65 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 14 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:18:1:18:40 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 18 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:21:1:27:1 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 21:27 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:29:1:35:1 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 29:35 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/unused-return-value] | lgtm[cpp/autosar/unused-return-value] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/unused-return-value for nested/nested2/test2.h. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | coding-standards.xml:1:1:17:19 | Deviation of cpp/autosar/useless-assignment for coding-standards.xml. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | main.cpp:1:1:39:1 | Deviation of cpp/autosar/useless-assignment for main.cpp. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/coding-standards.xml:1:1:13:19 | Deviation of cpp/autosar/useless-assignment for nested/coding-standards.xml. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/nested2/test2.h. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/test.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/test.h. | diff --git a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.qlref b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.qlref new file mode 100644 index 000000000..6268ee734 --- /dev/null +++ b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.qlref @@ -0,0 +1 @@ +codingstandards/cpp/deviations/DeviationsSuppression.ql \ No newline at end of file diff --git a/cpp/common/test/deviations/deviations_report_deviated/main.cpp b/cpp/common/test/deviations/deviations_report_deviated/main.cpp index c59dea560..7891faea1 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/main.cpp +++ b/cpp/common/test/deviations/deviations_report_deviated/main.cpp @@ -10,5 +10,30 @@ int main(int argc, char **argv) { getX(); // NON_COMPLIANT long double d1; // NON_COMPLIANT (A0-4-2) long double d2; // a-0-4-2-deviation COMPLIANT[DEVIATED] + + long double d3; // codeql::autosar_deviation(a-0-4-2-deviation) + // COMPLIANT[DEVIATED] + long double d4; // NON_COMPLIANT (A0-4-2) + // codeql::autosar_deviation_next_line(a-0-4-2-deviation) + long double d5; // COMPLIANT[DEVIATED] + long double d6; // NON_COMPLIANT (A0-4-2) + + // codeql::autosar_deviation_begin(a-0-4-2-deviation) + long double d7; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d8; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d9; // COMPLIANT[DEVIATED] + // codeql::autosar_deviation_end(a-0-4-2-deviation) + long double d10; // NON_COMPLIANT (A0-4-2) + // codeql::autosar_deviation_begin(a-0-4-2-deviation) + long double d11; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d12; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d13; // COMPLIANT[DEVIATED] + // codeql::autosar_deviation_end(a-0-4-2-deviation) + long double d14; // NON_COMPLIANT (A0-4-2) + getX(); // NON_COMPLIANT (A0-1-2) return 0; } \ No newline at end of file