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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 11832x 11832x 11832x 11832x 11832x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 46596x 11832x 11832x 11279x 11279x 11832x 11832x 253x 253x 11832x 11832x 288x 288x 288x 288x 288x 1700x 1700x 1700x 1700x 206x 206x 1700x 350x 350x 1494x 1130x 1144x 14x 1x 1x 13x 13x 1700x 14x 1x 1x 13x 13x 13x 1700x 13x 13x 1700x 9x 9x 1700x 288x 288x 288x 11832x 11832x 474x 474x 474x 11832x 11832x 13x 13x 13x 13x 13x 13x 3x 3x 10x 10x 10x 13x 2x 1x 1x 1x 1x 8x 13x 4x 4x 4x 4x 13x 1x 1x 3x 3x 3x 11832x 11832x | import * as Statements from "../abap/2_statements/statements";
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IRuleMetadata, RuleTag} from "./_irule";
import {ABAPFile} from "../abap/abap_file";
import {Comment} from "../abap/2_statements/statements/_statement";
import {StatementNode} from "../abap/nodes";
export class WrongAbapdocPositionConf extends BasicRuleConfig {
}
export class WrongAbapdocPosition extends ABAPRule {
private conf = new WrongAbapdocPositionConf();
public getMetadata(): IRuleMetadata {
return {
key: "wrong_abapdoc_position",
title: "Wrong ABAP Doc position",
shortDescription: `ABAP Doc must be placed directly in front of the declaration it documents.`,
extendedInformation: `ABAP Doc documents the single declaration following it, an ABAP Doc block placed
elsewhere is silently ignored, leaving the declaration undocumented.
The following positions are reported,
* in front of a chained keyword, ie. before "CONSTANTS:" instead of after the colon,
* in the middle of a statement, ie. between the parameters of a METHODS definition,
* directly in front of ENDCLASS, ENDINTERFACE or a SECTION statement.
Only checks ABAP Doc inside class definitions and interfaces.`,
tags: [RuleTag.SingleFile],
badExample: `CLASS zcl_foo DEFINITION PUBLIC.
PUBLIC SECTION.
"! Navigation modes
CONSTANTS:
BEGIN OF cs_nav_mode,
back TYPE i VALUE 1,
END OF cs_nav_mode.
ENDCLASS.`,
goodExample: `CLASS zcl_foo DEFINITION PUBLIC.
PUBLIC SECTION.
CONSTANTS:
"! Navigation modes
BEGIN OF cs_nav_mode,
back TYPE i VALUE 1,
END OF cs_nav_mode.
ENDCLASS.`,
};
}
public getConfig() {
return this.conf;
}
public setConfig(conf: WrongAbapdocPositionConf) {
this.conf = conf;
}
public runParsed(file: ABAPFile): Issue[] {
const issues: Issue[] = [];
const statements = file.getStatements();
let definition = false;
for (let i = 0; i < statements.length; i++) {
const statement = statements[i];
const type = statement.get();
if (type instanceof Statements.ClassDefinition || type instanceof Statements.Interface) {
definition = true;
continue;
} else if (type instanceof Statements.EndClass || type instanceof Statements.EndInterface) {
definition = false;
continue;
} else if (definition === false || this.isAbapdoc(statement) === false) {
continue;
} else if (this.isAbapdoc(statements[i - 1]) === true
&& statements[i - 1].getStart().getRow() + 1 === statement.getStart().getRow()) {
continue; // only report the first row of each block
}
let next: StatementNode | undefined = undefined;
for (let j = i + 1; j < statements.length; j++) {
if (statements[j].get() instanceof Comment) {
continue;
}
next = statements[j];
break;
}
if (next === undefined) {
continue;
}
const message = this.check(statement, next);
if (message !== undefined) {
issues.push(Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity));
}
}
return issues;
}
private isAbapdoc(statement: StatementNode | undefined): boolean {
return statement?.get() instanceof Comment
&& statement.getFirstToken().getStr().startsWith(`"!`);
}
private check(abapdoc: StatementNode, next: StatementNode): string | undefined {
const type = next.get();
if (type instanceof Statements.EndClass
|| type instanceof Statements.EndInterface
|| type instanceof Statements.Public
|| type instanceof Statements.Protected
|| type instanceof Statements.Private) {
return "ABAP Doc does not document anything, move or delete it";
}
const position = abapdoc.getStart();
const colon = next.getColon();
if (colon === undefined) {
if (position.isAfter(next.getStart()) === true) {
return "ABAP Doc inside statement, move it in front of the statement";
}
return undefined;
}
if (position.isBefore(colon.getStart()) === true) {
return "ABAP Doc in front of chained statement, move it after the colon";
}
const member = next.getTokens().find(t => t.getStart().isAfter(colon.getStart()));
if (member !== undefined && position.isAfter(member.getStart()) === true) {
return "ABAP Doc inside statement, move it in front of the chained declaration";
}
return undefined;
}
}
|