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 | 461x 461x 447x 447x 3x 3x 450x 4x 4x 461x 461x 461x | /**
* ADR-049 declaration modifiers: E0889.
*
* #1322. One throw in `VariableModifierBuilder`, reported as `1:0` with its
* position built into the message text.
*
* `atomic` already implies `volatile` -- it is `volatile` plus the guarantee
* that a read or write cannot be torn -- so writing both says one of two
* things, and the author has to be asked which. The rule is entirely
* syntactic: two modifier tokens on one declaration, which is why it needs no
* type, no frame and no symbols.
*
* Every declaration form is checked. Codegen's copy sat in the builder that
* file-scope and block declarations share, so it saw both; a `for` header's
* declaration and a parameter carry the same modifiers in the grammar and are
* asked here too rather than being assumed unreachable.
*/
import { ParserRuleContext, ParseTreeWalker } from "antlr4ng";
import { CNextListener } from "../../PARSE/2-Parse/grammar/CNextListener";
import * as Parser from "../../PARSE/2-Parse/grammar/CNextParser";
import ParserUtils from "../../utils/ParserUtils";
import IDeclarationModifierError from "./types/IDeclarationModifierError";
class DeclarationModifierListener extends CNextListener {
private readonly found: IDeclarationModifierError[] = [];
public errors(): IDeclarationModifierError[] {
return this.found;
}
override enterVariableDeclaration = (
ctx: Parser.VariableDeclarationContext,
): void => {
this.check(ctx, ctx.atomicModifier(), ctx.volatileModifier());
};
override enterForVarDecl = (ctx: Parser.ForVarDeclContext): void => {
this.check(ctx, ctx.atomicModifier(), ctx.volatileModifier());
};
private check(
at: ParserRuleContext,
atomic: Parser.AtomicModifierContext | null,
volatileMod: Parser.VolatileModifierContext | null,
): void {
if (atomic === null || volatileMod === null) return;
const { line, column } = ParserUtils.getPosition(at);
this.found.push({
code: "E0889",
line,
column,
message: "Cannot use both 'atomic' and 'volatile' on one declaration",
helpText:
"`atomic` already implies `volatile`, and adds that a read or write cannot be torn. Use `atomic` for a variable an ISR shares, or `volatile` alone for a hardware register or a delay loop (ADR-049).",
});
}
}
class DeclarationModifierAnalyzer {
public analyze(tree: Parser.ProgramContext): IDeclarationModifierError[] {
const listener = new DeclarationModifierListener();
ParseTreeWalker.DEFAULT.walk(listener, tree);
return listener.errors();
}
}
export default DeclarationModifierAnalyzer;
|