@abaplint/core
Version:
abaplint - Core API
222 lines (218 loc) • 10.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CheckSubrc = exports.CheckSubrcConf = void 0;
const Statements = require("../abap/2_statements/statements");
const Expressions = require("../abap/2_statements/expressions");
const issue_1 = require("../issue");
const _basic_rule_config_1 = require("./_basic_rule_config");
const _abap_rule_1 = require("./_abap_rule");
const _irule_1 = require("./_irule");
const _statement_1 = require("../abap/2_statements/statements/_statement");
const edit_helper_1 = require("../edit_helper");
class CheckSubrcConf extends _basic_rule_config_1.BasicRuleConfig {
constructor() {
super(...arguments);
this.openDataset = true;
this.authorityCheck = true;
this.selectSingle = true;
this.selectTable = true;
this.updateDatabase = true;
this.insertDatabase = true;
this.modifyDatabase = true;
this.readTable = true;
this.assign = true;
this.find = true;
}
}
exports.CheckSubrcConf = CheckSubrcConf;
class CheckSubrc extends _abap_rule_1.ABAPRule {
constructor() {
super(...arguments);
this.conf = new CheckSubrcConf();
}
getMetadata() {
return {
key: "check_subrc",
title: "Check sy-subrc",
shortDescription: `Check sy-subrc`,
extendedInformation: `Pseudo comment "#EC CI_SUBRC can be added to suppress findings
If sy-dbcnt is checked after database statements, it is considered okay.
"SELECT SINGLE @abap_true FROM " is considered as an existence check, also "SELECT COUNT( * )" is considered okay
If IS ASSIGNED is checked after assigning, it is considered okay.
FIND statement with MATCH COUNT is considered okay if subrc is not checked`,
tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Quickfix],
pseudoComment: "EC CI_SUBRC",
pragma: "##SUBRC_OK",
};
}
getConfig() {
return this.conf;
}
setConfig(conf) {
this.conf = conf;
}
buildFix(file, statement) {
return {
description: "Add ##SUBRC_OK",
edit: edit_helper_1.EditHelper.insertAt(file, statement.getLastToken().getStart(), " ##SUBRC_OK"),
};
}
runParsed(file) {
const issues = [];
const statements = file.getStatements();
const message = "Check sy-subrc";
const config = this.getConfig();
for (let i = 0; i < statements.length; i++) {
const statement = statements[i];
// todo: CALL FUNCTION
if (statement.getPragmas().some(t => t.getStr() === this.getMetadata().pragma)) {
continue;
}
if (config.openDataset === true
&& statement.get() instanceof Statements.OpenDataset
&& this.isChecked(i, statements) === false) {
// it doesnt make sense to ignore the subrc for open dataset, so no quick fix
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity));
}
else if (config.authorityCheck === true
&& statement.get() instanceof Statements.AuthorityCheck
&& this.isChecked(i, statements) === false) {
// it doesnt make sense to ignore the subrc for authority checks, so no quick fix
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity));
}
else if (config.selectSingle === true
&& statement.get() instanceof Statements.Select
&& statement.concatTokens().toUpperCase().startsWith("SELECT SINGLE ")
&& this.isChecked(i, statements) === false
&& this.checksDbcnt(i, statements) === false) {
const concat = statement.concatTokens().toUpperCase();
if (concat.startsWith("SELECT SINGLE @ABAP_TRUE FROM ")) {
continue;
}
const fix = this.buildFix(file, statement);
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity, undefined, [fix]));
}
else if (config.selectTable === true
&& statement.get() instanceof Statements.Select
&& statement.concatTokens().toUpperCase().startsWith("SELECT SINGLE ") === false
&& statement.concatTokens().toUpperCase().startsWith("SELECT COUNT( * ) ") === false
&& statement.concatTokens().toUpperCase().startsWith("SELECT COUNT(*) ") === false
&& this.isChecked(i, statements) === false
&& this.checksDbcnt(i, statements) === false) {
const fix = this.buildFix(file, statement);
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity, undefined, [fix]));
}
else if (config.updateDatabase === true
&& statement.get() instanceof Statements.UpdateDatabase
&& this.isChecked(i, statements) === false
&& this.checksDbcnt(i, statements) === false) {
const fix = this.buildFix(file, statement);
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity, undefined, [fix]));
}
else if (config.insertDatabase === true
&& statement.get() instanceof Statements.InsertDatabase
&& this.isChecked(i, statements) === false
&& this.checksDbcnt(i, statements) === false) {
const fix = this.buildFix(file, statement);
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity, undefined, [fix]));
}
else if (config.modifyDatabase === true
&& statement.get() instanceof Statements.ModifyDatabase
&& this.isChecked(i, statements) === false
&& this.checksDbcnt(i, statements) === false) {
const fix = this.buildFix(file, statement);
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity, undefined, [fix]));
}
else if (config.readTable === true
&& statement.get() instanceof Statements.ReadTable
&& this.isChecked(i, statements) === false) {
const fix = this.buildFix(file, statement);
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity, undefined, [fix]));
}
else if (config.assign === true
&& statement.get() instanceof Statements.Assign
&& this.isSimpleAssign(statement) === false
&& this.isChecked(i, statements) === false) {
const fix = this.buildFix(file, statement);
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity, undefined, [fix]));
}
else if (config.find === true
&& statement.get() instanceof Statements.Find
&& this.isExemptedFind(statement) === false
&& this.isChecked(i, statements) === false) {
const fix = this.buildFix(file, statement);
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity, undefined, [fix]));
}
}
return issues;
}
////////////////
isSimpleAssign(statement) {
if (statement.getChildren().length === 5) {
const source = statement.findDirectExpression(Expressions.AssignSource);
if ((source === null || source === void 0 ? void 0 : source.getChildren().length) === 1
&& source.findDirectExpression(Expressions.Source) !== undefined) {
return true;
}
}
return false;
}
isExemptedFind(s) {
// see https://github.com/abaplint/abaplint/issues/2130
return s.concatTokens().toUpperCase().includes(" MATCH COUNT ") === true;
}
checksDbcnt(index, statements) {
for (let i = index + 1; i < statements.length; i++) {
const statement = statements[i];
const concat = statement.concatTokens().toUpperCase();
if (statement.get() instanceof _statement_1.Comment) {
continue;
}
else if (statement.get() instanceof Statements.EndIf
|| statement.get() instanceof Statements.EndTestSeam) {
continue;
}
else {
return concat.includes("SY-DBCNT");
}
}
return false;
}
isChecked(index, statements) {
var _a, _b;
let assigned = undefined;
let assignedn = undefined;
if (statements[index].get() instanceof Statements.Assign
|| statements[index].get() instanceof Statements.ReadTable) {
const fs = (_b = (_a = statements[index].findFirstExpression(Expressions.FSTarget)) === null || _a === void 0 ? void 0 : _a.findFirstExpression(Expressions.FieldSymbol)) === null || _b === void 0 ? void 0 : _b.getFirstToken().getStr();
assigned = (fs === null || fs === void 0 ? void 0 : fs.toUpperCase()) + " IS ASSIGNED";
assignedn = (fs === null || fs === void 0 ? void 0 : fs.toUpperCase()) + " IS NOT ASSIGNED";
}
for (let i = index + 1; i < statements.length; i++) {
const statement = statements[i];
const concat = statement.concatTokens().toUpperCase();
if (statement.get() instanceof _statement_1.Comment) {
if (concat.includes("" + this.getMetadata().pseudoComment)) {
return true;
}
}
else if (statement.get() instanceof Statements.EndIf
|| statement.get() instanceof Statements.EndTestSeam) {
continue;
}
else {
if (assigned && concat.includes(assigned)) {
return true;
}
if (assignedn && concat.includes(assignedn)) {
return true;
}
return concat.includes(" SY-SUBRC")
|| concat.includes("CL_ABAP_UNIT_ASSERT=>ASSERT_SUBRC");
}
}
return false;
}
}
exports.CheckSubrc = CheckSubrc;
//# sourceMappingURL=check_subrc.js.map