Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions change_notes/2025-03-26-deviations-suppression.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- The `DeviationsSuppression.ql` query has been restored after being incorrectly deleted in a previous release.
Original file line number Diff line number Diff line change
Expand Up @@ -226,15 +226,20 @@ 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
or
result.(Variable).getAnAttribute() = this
or
result.(Function).getAnAttribute() = this
}

pragma[nomagic]
Element getASuppressedElement() {
result = this.getPrimarySuppressedElement()
or
result.(Expr).getEnclosingStmt() = this.getASuppressedElement()
or
Expand Down Expand Up @@ -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
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>This query generates suppression information for rules that have an associated deviation record.</p>
</overview>
<references>
<li>
MISRA Compliance 2020 document:
<a href="https://www.misra.org.uk/app/uploads/2021/06/MISRA-Compliance-2020.pdf">Chapter 4.2 (page 12) - Deviations.</a>
</li>
</references>
</qhelp>
125 changes: 125 additions & 0 deletions cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
codingstandards/cpp/deviations/DeviationsSuppression.ql
25 changes: 25 additions & 0 deletions cpp/common/test/deviations/deviations_report_deviated/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Loading