UNPKG

@abaplint/core

Version:
244 lines • 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.UncaughtException = exports.UncaughtExceptionConf = void 0; const issue_1 = require("../issue"); const _abap_rule_1 = require("./_abap_rule"); const _basic_rule_config_1 = require("./_basic_rule_config"); const Statements = require("../abap/2_statements/statements"); const Expressions = require("../abap/2_statements/expressions"); const Structures = require("../abap/3_structures/structures"); const _irule_1 = require("./_irule"); const nodes_1 = require("../abap/nodes"); const objects_1 = require("../objects"); const ddic_1 = require("../ddic"); const syntax_1 = require("../abap/5_syntax/syntax"); const _reference_1 = require("../abap/5_syntax/_reference"); const types_1 = require("../abap/types"); class UncaughtExceptionConf extends _basic_rule_config_1.BasicRuleConfig { constructor() { super(...arguments); this.reportDynamic = false; this.reportNoCheck = false; } } exports.UncaughtExceptionConf = UncaughtExceptionConf; class UncaughtException extends _abap_rule_1.ABAPRule { constructor() { super(...arguments); this.conf = new UncaughtExceptionConf(); this.issues = []; } getMetadata() { return { key: "uncaught_exception", title: "Uncaught Exception", shortDescription: `Checks for uncaught static exception`, extendedInformation: `Does not report any issues if the code contains syntax errors`, tags: [_irule_1.RuleTag.Syntax], }; } getConfig() { return this.conf; } initialize(reg) { super.initialize(reg); this.findGlobalExceptions(); return this; } setConfig(conf) { this.conf = conf; } runParsed(file, obj) { if (obj.getType() === "INTF") { // nothing can be raised in interfaces return []; } if (obj instanceof objects_1.Program && obj.isInclude() === true) { return []; } const stru = file.getStructure(); if (stru === undefined) { return []; } this.findLocalExceptions(obj); this.syntax = new syntax_1.SyntaxLogic(this.reg, obj).run(); if (this.syntax.issues.length > 0) { return []; } this.issues = []; this.sinked = undefined; for (const c of stru.getChildren()) { this.traverse(c, file); } return this.issues; } traverse(n, file) { var _a, _b, _c, _d, _e, _f; const get = n.get(); if (get instanceof Structures.ClassDefinition || get instanceof Structures.Interface) { return; // to optimize performance } if (n instanceof nodes_1.StructureNode) { if (get instanceof Structures.Try) { // note that TRY-CATCH might be arbitrarily nested const previous = this.sinked ? this.sinked.slice() : undefined; this.addFromTryStructure(n); for (const c of ((_a = n.findDirectStructure(Structures.Body)) === null || _a === void 0 ? void 0 : _a.getChildren()) || []) { this.traverse(c, file); } this.sinked = previous; for (const c of ((_b = n.findDirectStructure(Structures.Catch)) === null || _b === void 0 ? void 0 : _b.getChildren()) || []) { this.traverse(c, file); } for (const c of ((_c = n.findDirectStructure(Structures.Cleanup)) === null || _c === void 0 ? void 0 : _c.getChildren()) || []) { this.traverse(c, file); } return; } else { for (const c of n.getChildren()) { this.traverse(c, file); } } } else if (n instanceof nodes_1.StatementNode) { if (get instanceof Statements.MethodImplementation) { this.setSinkedFromMethod(n, file); } else if (get instanceof Statements.EndMethod) { this.sinked = undefined; // back to top level } else if (get instanceof Statements.Form) { this.sinked = []; const raising = n.findDirectExpression(Expressions.FormRaising); for (const c of (raising === null || raising === void 0 ? void 0 : raising.findAllExpressions(Expressions.ClassName)) || []) { this.sinked.push(c.concatTokens().toUpperCase()); } } else if (get instanceof Statements.EndForm) { this.sinked = undefined; // back to top level } else if (get instanceof Statements.Raise) { let name = undefined; const concat = n.concatTokens().toUpperCase(); if (concat.startsWith("RAISE EXCEPTION TYPE ")) { name = (_d = n.findFirstExpression(Expressions.ClassName)) === null || _d === void 0 ? void 0 : _d.getFirstToken().getStr().toUpperCase(); } else if (concat.startsWith("RAISE EXCEPTION NEW ")) { name = (_f = (_e = n.findFirstExpression(Expressions.NewObject)) === null || _e === void 0 ? void 0 : _e.findFirstExpression(Expressions.TypeNameOrInfer)) === null || _f === void 0 ? void 0 : _f.getFirstToken().getStr().toUpperCase(); // todo: else its a normal Source, infer the type from it } this.check(name, n, file); } else if (get instanceof Statements.Perform) { // todo, PERFORM, or is this not statically checked? } else { this.checkForMethodCalls(n, file); } } } //////////////////////////////// check(name, n, file) { if (this.isSinked(name) === false) { const issue = issue_1.Issue.atStatement(file, n, "Uncaught exception " + name, this.getMetadata().key, this.getConfig().severity); this.issues.push(issue); } } checkForMethodCalls(n, file) { const start = n.getFirstToken().getStart(); const end = n.getLastToken().getEnd(); const scope = this.syntax.spaghetti.lookupPosition(start, file.getFilename()); for (const r of (scope === null || scope === void 0 ? void 0 : scope.getData().references) || []) { if (r.referenceType === _reference_1.ReferenceType.MethodReference && r.position.getStart().isAfter(start) && r.position.getEnd().isBefore(end) && r.resolved instanceof types_1.MethodDefinition) { for (const name of r.resolved.getRaising()) { this.check(name, n, file); } } } } addFromTryStructure(s) { if (this.sinked === undefined) { return; } for (const structure of s.findDirectStructures(Structures.Catch)) { const c = structure.findDirectStatement(Statements.Catch); if (c === undefined) { continue; } for (const cn of c.findDirectExpressions(Expressions.ClassName)) { this.sinked.push(cn.concatTokens()); } } } setSinkedFromMethod(s, file) { this.sinked = []; const scope = this.syntax.spaghetti.lookupPosition(s.getLastToken().getEnd(), file.getFilename()); let def = undefined; for (const r of (scope === null || scope === void 0 ? void 0 : scope.getData().references) || []) { // there should be only one, so the first is okay if (r.referenceType === _reference_1.ReferenceType.MethodImplementationReference && r.resolved instanceof types_1.MethodDefinition) { def = r.resolved; break; } } if (def === undefined) { return; // this should not occur, so just report everything as errors } def.getRaising().forEach(r => { var _a; return (_a = this.sinked) === null || _a === void 0 ? void 0 : _a.push(r); }); } isSinked(name) { if (this.sinked === undefined || name === undefined) { return true; } const sup = this.globalExceptions[name.toUpperCase()]; if (sup === "CX_DYNAMIC_CHECK" && this.getConfig().reportDynamic !== true) { return true; } if (sup === "CX_NO_CHECK" && this.getConfig().reportNoCheck !== true) { return true; } const lsup = this.localExceptions[name.toUpperCase()]; if (lsup === "CX_DYNAMIC_CHECK" && this.getConfig().reportDynamic !== true) { return true; } if (lsup === "CX_NO_CHECK" && this.getConfig().reportNoCheck !== true) { return true; } return this.sinked.some(a => a.toUpperCase() === name.toUpperCase()) || (sup !== undefined && this.isSinked(sup) === true) || (lsup !== undefined && this.isSinked(lsup) === true); } findGlobalExceptions() { var _a, _b; this.globalExceptions = {}; const ddic = new ddic_1.DDIC(this.reg); for (const o of this.reg.getObjects()) { if (!(o instanceof objects_1.Class)) { continue; } const def = (_a = o.getMainABAPFile()) === null || _a === void 0 ? void 0 : _a.getInfo().getClassDefinitionByName(o.getName()); if (def === undefined || ddic.isException(def, o) === false) { continue; } this.globalExceptions[o.getName().toUpperCase()] = (_b = def.superClassName) === null || _b === void 0 ? void 0 : _b.toUpperCase(); } } findLocalExceptions(obj) { var _a; this.localExceptions = {}; for (const file of obj.getABAPFiles()) { for (const def of file.getInfo().listClassDefinitions()) { if (def.isLocal === true && def.superClassName !== undefined) { this.localExceptions[def.name.toUpperCase()] = (_a = def.superClassName) === null || _a === void 0 ? void 0 : _a.toUpperCase(); } } } } } exports.UncaughtException = UncaughtException; //# sourceMappingURL=uncaught_exception.js.map