Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | 463x 463x 462x 462x 477x 477x 462x 2x 477x 477x 477x 5x 477x 477x 478x 478x 2x 478x 1x 1x 1x 477x 468x 468x 4x | import ECommentType from "../../types/ECommentType";
import CommentScanner from "../../PARSE/2-Parse/CommentScanner";
import IComment from "../../types/IComment";
import ICommentError from "./types/ICommentError";
/**
* Validates comments against MISRA C:2012 Rules 3.1 and 3.2 (ADR-043).
*
* #1322: the extraction half is `CommentScanner`, in the parser. This is the
* rejection half, and a rejection is 2.1's to author. The split is what lets
* codegen read comments -- which it must, to re-attach them -- without
* importing an analyzer.
*
* #1445: it takes the comments rather than the token stream they came off.
* Scanning was 2.1 re-deriving a fact about the PARSE, which is what the
* lifetime axis forbids -- so 1.2 now carries them on `IParsedFile` and this
* class names no parse type at all. `CommentScanner` remains imported for
* `markerLength`, a pure function of the comment kind; the confinement rule is
* direct rather than reachable, because its claim is about what a pass's
* source NAMES.
*/
class CommentExtractor {
private readonly comments: readonly IComment[];
private errors: ICommentError[] = [];
constructor(comments: readonly IComment[]) {
this.comments = comments;
}
/**
* Validate all comments against MISRA C:2012 Rules 3.1 and 3.2
*/
validate(): ICommentError[] {
this.errors = [];
for (const comment of this.comments) {
this.validateMisra31(comment);
this.validateMisra32(comment);
}
return this.errors;
}
/**
* Get validation errors
*/
getErrors(): ICommentError[] {
return this.errors;
}
/**
* MISRA C:2012 Rule 3.1: No nested comment markers
* The character sequences /* and // shall not appear within a comment.
* Exception: :// (URI pattern) is allowed per Amendment 4
*/
private validateMisra31(comment: IComment): void {
const content = comment.content;
// Check for nested /* (not part of a URI)
const nestedBlockStart = content.indexOf("/*");
if (nestedBlockStart !== -1) {
this.errors.push({
rule: "3.1",
message:
"Nested comment marker '/*' found inside comment (MISRA C:2012 Rule 3.1)",
line: comment.line,
column:
comment.column +
CommentScanner.markerLength(comment.type) +
nestedBlockStart,
});
}
// Check for nested // (not part of a URI like ://)
// Find all // occurrences and check if preceded by :
let searchStart = 0;
while (true) {
const slashSlash = content.indexOf("//", searchStart);
if (slashSlash === -1) break;
// Check if this is part of a URI (preceded by :)
const isUri = slashSlash > 0 && content[slashSlash - 1] === ":";
if (!isUri) {
this.errors.push({
rule: "3.1",
message:
"Nested comment marker '//' found inside comment (MISRA C:2012 Rule 3.1)",
line: comment.line,
column:
comment.column +
CommentScanner.markerLength(comment.type) +
slashSlash,
});
break; // Only report first occurrence
}
searchStart = slashSlash + 2;
}
}
/**
* MISRA C:2012 Rule 3.2: No line-splice in line comments
* Line comments ending with \ cause undefined behavior
*/
private validateMisra32(comment: IComment): void {
// Only applies to line comments (// and ///)
if (comment.type === ECommentType.Block) return;
const content = comment.content;
if (content.endsWith("\\")) {
this.errors.push({
rule: "3.2",
message: String.raw`Line comment ends with '\' which causes line-splice (MISRA C:2012 Rule 3.2)`,
line: comment.line,
column: comment.column,
});
}
}
}
export default CommentExtractor;
|