@abaplint/core
Version:
abaplint - Core API
244 lines • 10.5 kB
JavaScript
"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