|
| 1 | +/** |
| 2 | + * @name Deviation suppression |
| 3 | + * @description Generates information about files and locations where certain alerts should be considered suppressed by deviations. |
| 4 | + * @kind alert-suppression |
| 5 | + * @id cpp/coding-standards/deviation-suppression |
| 6 | + */ |
| 7 | + |
| 8 | +import cpp |
| 9 | +import Deviations |
| 10 | + |
| 11 | +/** Holds if `lineNumber` is an indexed line number in file `f`. */ |
| 12 | +private predicate isLineNumber(File f, int lineNumber) { |
| 13 | + exists(Location l | l.getFile() = f | |
| 14 | + l.getStartLine() = lineNumber |
| 15 | + or |
| 16 | + l.getEndLine() = lineNumber |
| 17 | + ) |
| 18 | +} |
| 19 | + |
| 20 | +/** Gets the last line number in `f`. */ |
| 21 | +private int getLastLineNumber(File f) { result = max(int lineNumber | isLineNumber(f, lineNumber)) } |
| 22 | + |
| 23 | +/** Gets the last column number on the last line of `f`. */ |
| 24 | +int getLastColumnNumber(File f) { |
| 25 | + result = |
| 26 | + max(Location l | |
| 27 | + l.getFile() = f and |
| 28 | + l.getEndLine() = getLastLineNumber(f) |
| 29 | + | |
| 30 | + l.getEndColumn() |
| 31 | + ) |
| 32 | +} |
| 33 | + |
| 34 | +newtype TDeviationScope = |
| 35 | + TDeviationRecordFileScope(DeviationRecord dr, File file) { |
| 36 | + exists(string deviationPath | |
| 37 | + dr.isDeviated(_, deviationPath) and |
| 38 | + file.getRelativePath().prefix(deviationPath.length()) = deviationPath |
| 39 | + ) |
| 40 | + } or |
| 41 | + TDeviationRecordCommentScope(DeviationRecord dr, Comment c) { c = dr.getACodeIdentifierComment() } |
| 42 | + |
| 43 | +/** A deviation scope. */ |
| 44 | +class DeviationScope extends TDeviationScope { |
| 45 | + /** Gets the location at which this deviation was defined. */ |
| 46 | + abstract Locatable getDeviationDefinitionLocation(); |
| 47 | + |
| 48 | + /** Gets the Query being deviated. */ |
| 49 | + abstract Query getQuery(); |
| 50 | + |
| 51 | + abstract string toString(); |
| 52 | + |
| 53 | + abstract predicate hasLocationInfo( |
| 54 | + string filepath, int startline, int startcolumn, int endline, int endcolumn |
| 55 | + ); |
| 56 | +} |
| 57 | + |
| 58 | +/** A deviation scope derived from a "path" entry in a `DeviationRecord`. */ |
| 59 | +class DeviationRecordFileScope extends DeviationScope, TDeviationRecordFileScope { |
| 60 | + private DeviationRecord getDeviationRecord() { this = TDeviationRecordFileScope(result, _) } |
| 61 | + |
| 62 | + override Locatable getDeviationDefinitionLocation() { result = getDeviationRecord() } |
| 63 | + |
| 64 | + private File getFile() { this = TDeviationRecordFileScope(_, result) } |
| 65 | + |
| 66 | + override Query getQuery() { result = getDeviationRecord().getQuery() } |
| 67 | + |
| 68 | + override predicate hasLocationInfo( |
| 69 | + string filepath, int startline, int startcolumn, int endline, int endcolumn |
| 70 | + ) { |
| 71 | + // In an ideal world, we would produce a URL here that informed the AlertSuppression code that |
| 72 | + // the whole file was suppressed. However, experimentation suggestions the alert suppression |
| 73 | + // code only works with locations with lines and columns, so we generate a location that covers |
| 74 | + // the whole "indexed" file, by finding the location indexed in the database with the latest |
| 75 | + // line and column number. |
| 76 | + exists(File f | f = getFile() | |
| 77 | + f.getLocation().hasLocationInfo(filepath, _, _, _, _) and |
| 78 | + startline = 1 and |
| 79 | + startcolumn = 1 and |
| 80 | + endline = getLastLineNumber(f) and |
| 81 | + endcolumn = getLastColumnNumber(f) |
| 82 | + ) |
| 83 | + } |
| 84 | + |
| 85 | + override string toString() { |
| 86 | + result = "Deviation of " + getDeviationRecord().getQuery() + " for " + getFile() + "." |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +/** |
| 91 | + * A deviation scope derived from a comment corresponding to a "code-identifier" entry for a |
| 92 | + * `DeviationRecord`. |
| 93 | + */ |
| 94 | +class DeviationRecordCommentScope extends DeviationScope, TDeviationRecordCommentScope { |
| 95 | + private DeviationRecord getDeviationRecord() { this = TDeviationRecordCommentScope(result, _) } |
| 96 | + |
| 97 | + private Comment getComment() { this = TDeviationRecordCommentScope(_, result) } |
| 98 | + |
| 99 | + override Locatable getDeviationDefinitionLocation() { result = getDeviationRecord() } |
| 100 | + |
| 101 | + override Query getQuery() { result = getDeviationRecord().getQuery() } |
| 102 | + |
| 103 | + override predicate hasLocationInfo( |
| 104 | + string filepath, int startline, int startcolumn, int endline, int endcolumn |
| 105 | + ) { |
| 106 | + getComment().getLocation().hasLocationInfo(filepath, startline, _, endline, endcolumn) and |
| 107 | + startcolumn = 1 |
| 108 | + } |
| 109 | + |
| 110 | + override string toString() { |
| 111 | + result = |
| 112 | + "Deviation of " + getDeviationRecord().getQuery() + " for comment " + getComment() + "." |
| 113 | + } |
| 114 | +} |
| 115 | + |
| 116 | +from DeviationScope deviationScope |
| 117 | +select deviationScope.getDeviationDefinitionLocation(), // suppression comment |
| 118 | + "// lgtm[" + deviationScope.getQuery().getQueryId() + "]", // text of suppression comment (excluding delimiters) |
| 119 | + "lgtm[" + deviationScope.getQuery().getQueryId() + "]", // text of suppression annotation |
| 120 | + deviationScope // scope of suppression |
0 commit comments