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 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 23134x 23134x 23134x 23134x 1x 11568x 11568x 11568x 11568x 11568x 34550x 34550x 34550x 34550x 34550x 34550x 34550x 34550x 34550x 34550x 34550x 11568x 11568x 11065x 11065x 11568x 11568x 236x 236x 11568x 11568x 262x 262x 262x 262x 262x 1417x 1417x 1417x 1417x 1417x 1417x 8x 1417x 1409x 1409x 1409x 8x 1409x 5x 5x 5x 5x 5x 5x 5x 5x 1401x 2x 2x 2x 2x 2x 1417x 262x 262x 262x 11568x 11568x | import {Issue} from "../issue";
import * as Statements from "../abap/2_statements/statements";
import {ABAPRule} from "./_abap_rule";
import {StatementNode} from "../abap/nodes";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IRuleMetadata, RuleTag} from "./_irule";
import {ABAPFile} from "../abap/abap_file";
import {EditHelper} from "../edit_helper";
export class ExitOrCheckConf extends BasicRuleConfig {
public allowExit: boolean = false;
public allowCheck: boolean = false;
}
export class ExitOrCheck extends ABAPRule {
private conf = new ExitOrCheckConf();
public getMetadata(): IRuleMetadata {
return {
key: "exit_or_check",
title: "Find EXIT or CHECK outside loops",
shortDescription: `Detects usages of EXIT or CHECK statements outside of loops.
Use RETURN to leave procesing blocks instead.`,
extendedInformation: `https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abenleave_processing_blocks.htm
https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abapcheck_processing_blocks.htm
https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#check-vs-return`,
tags: [RuleTag.Styleguide, RuleTag.SingleFile, RuleTag.Quickfix],
};
}
public getConfig() {
return this.conf;
}
public setConfig(conf: ExitOrCheckConf) {
this.conf = conf;
}
public runParsed(file: ABAPFile) {
const issues: Issue[] = [];
const stack: StatementNode[] = [];
for (const statement of file.getStatements()) {
const get = statement.get();
if (get instanceof Statements.Loop
|| get instanceof Statements.While
|| get instanceof Statements.LoopAtScreen
|| get instanceof Statements.SelectLoop
|| get instanceof Statements.Do) {
stack.push(statement);
} else if (get instanceof Statements.EndLoop
|| get instanceof Statements.EndWhile
|| get instanceof Statements.EndSelect
|| get instanceof Statements.EndDo) {
stack.pop();
} else if (this.conf.allowCheck === false && get instanceof Statements.Check && stack.length === 0) {
const message = "CHECK is not allowed outside of loops";
let tokensString = statement.concatTokens();
tokensString = tokensString.replace(/^check /i, "CHECK ");
tokensString = tokensString.split("CHECK")[1].trim();
const replacement = "IF NOT " + tokensString + "\n RETURN.\nENDIF.";
const fix = EditHelper.replaceRange(file, statement.getFirstToken().getStart(), statement.getLastToken().getEnd(), replacement);
const issue = Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity, fix);
issues.push(issue);
} else if (this.conf.allowExit === false && get instanceof Statements.Exit && stack.length === 0) {
const message = "EXIT is not allowed outside of loops";
const fix = EditHelper.replaceToken(file, statement.getFirstToken(), "RETURN");
const issue = Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity, fix);
issues.push(issue);
}
}
return issues;
}
} |