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 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 30962x 30962x 30962x 30962x 1x 15489x 15489x 15489x 15489x 15489x 150635x 150635x 150635x 150635x 150635x 150635x 150635x 150635x 150635x 150635x 150635x 150635x 150635x 150635x 150635x 15489x 15489x 14908x 14908x 15489x 15489x 268x 268x 15489x 15489x 311x 311x 311x 311x 1667x 1648x 1648x 19x 1667x 1x 1667x 3x 3x 15x 15x 15x 15x 15x 1667x 1667x 4x 4x 1667x 11x 11x 11x 15x 1667x 3x 3x 12x 1667x 10x 1667x 1667x 8x 8x 8x 1667x 311x 311x 311x 15489x | 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 {ExpressionNode} from "../abap/nodes/expression_node";
import * as Statements from "../abap/2_statements/statements";
import * as Expressions from "../abap/2_statements/expressions";
export class PreferRaiseMessageConf extends BasicRuleConfig {
/** List of exception class names to ignore, case insensitive */
public ignoreExceptionClasses: string[] = [];
}
export class PreferRaiseMessage extends ABAPRule {
private conf = new PreferRaiseMessageConf();
public getMetadata(): IRuleMetadata {
return {
key: "prefer_raise_message",
title: "Prefer RAISE EXCEPTION with MESSAGE",
shortDescription: `Prefer RAISE EXCEPTION with MESSAGE instead of supplying parameter TEXT or TEXTID`,
extendedInformation: `Reports RAISE EXCEPTION statements where parameter TEXT or TEXTID is supplied.
Use a message class instead, so the text is translatable and can be found via where-used.
Exception classes can be excluded via configuration "ignoreExceptionClasses".`,
tags: [RuleTag.SingleFile],
goodExample: `RAISE EXCEPTION TYPE zcx_error MESSAGE e001(zclass).`,
badExample: `RAISE EXCEPTION TYPE zcx_error
EXPORTING text = 'hello world'.`,
};
}
public getConfig() {
return this.conf;
}
public setConfig(conf: PreferRaiseMessageConf) {
this.conf = conf;
}
public runParsed(file: ABAPFile): Issue[] {
const issues: Issue[] = [];
const ignore = (this.conf.ignoreExceptionClasses ?? []).map(c => c.toUpperCase());
for (const statement of file.getStatements()) {
if (!(statement.get() instanceof Statements.Raise)) {
continue;
}
const concat = statement.concatTokens().toUpperCase();
if (!concat.startsWith("RAISE EXCEPTION ") && !concat.startsWith("RAISE RESUMABLE EXCEPTION ")) {
continue;
} else if (concat.includes(" MESSAGE")) {
continue;
}
let className: string | undefined;
let parameters: ExpressionNode | undefined;
const newObject = statement.findDirectExpression(Expressions.Source)
?.findDirectExpression(Expressions.MethodCallChain)?.findDirectExpression(Expressions.NewObject);
if (newObject) {
className = newObject.findDirectExpression(Expressions.TypeNameOrInfer)?.concatTokens();
parameters = newObject.findDirectExpression(Expressions.ParameterListS);
} else {
className = statement.findDirectExpression(Expressions.ClassName)?.concatTokens();
parameters = statement.findDirectExpression(Expressions.ParameterListS);
}
if (className === undefined || ignore.includes(className.toUpperCase())) {
continue;
}
const name = parameters?.findDirectExpressions(Expressions.ParameterS)
.map(p => p.findDirectExpression(Expressions.ParameterName)?.concatTokens().toUpperCase())
.find(n => n === "TEXT" || n === "TEXTID");
if (name) {
const message = "Prefer RAISE EXCEPTION with MESSAGE, " + className + " raised with parameter " + name;
issues.push(Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity));
}
}
return issues;
}
}
|