UNPKG

@abaplint/core

Version:
164 lines (162 loc) 5.91 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CyclicOO = exports.CyclicOOConf = void 0; const issue_1 = require("../issue"); const _basic_rule_config_1 = require("./_basic_rule_config"); const objects_1 = require("../objects"); const syntax_1 = require("../abap/5_syntax/syntax"); const _reference_1 = require("../abap/5_syntax/_reference"); const _builtin_1 = require("../abap/5_syntax/_builtin"); const _abap_object_1 = require("../objects/_abap_object"); class CyclicOOConf extends _basic_rule_config_1.BasicRuleConfig { constructor() { super(...arguments); /** List of object names to skip, must be full upper case name * @uniqueItems true */ this.skip = []; /** Skips shared memory enabled classes */ this.skipSharedMemory = true; /** Skip testclass inclues */ this.skipTestclasses = true; } } exports.CyclicOOConf = CyclicOOConf; class CyclicOO { constructor() { this.conf = new CyclicOOConf(); this.edges = {}; } getMetadata() { return { key: "cyclic_oo", title: "Cyclic OO", shortDescription: `Finds cyclic/circular OO references`, extendedInformation: `Runs for global INTF + CLAS objects Objects must be without syntax errors for this rule to take effect References in testclass includes are ignored`, }; } getConfig() { return this.conf; } setConfig(conf) { this.conf = conf; if (this.conf.skip === undefined) { this.conf.skip = []; } } initialize(reg) { var _a; this.reg = reg; this.edges = {}; for (const obj of this.reg.getObjectsByType("CLAS")) { if (this.reg.isDependency(obj)) { continue; } const name = obj.getName().toUpperCase(); if (!(obj instanceof objects_1.Class)) { continue; } else if (this.conf.skip.indexOf(name) >= 0) { continue; } else if (this.conf.skipSharedMemory === true && ((_a = obj.getClassDefinition()) === null || _a === void 0 ? void 0 : _a.isSharedMemory) === true) { continue; } const run = new syntax_1.SyntaxLogic(this.reg, obj).run(); if (run.issues.length > 0) { continue; } this.buildEdges(name, run.spaghetti.getTop()); } for (const obj of this.reg.getObjectsByType("INTF")) { if (this.reg.isDependency(obj)) { continue; } const name = obj.getName().toUpperCase(); if (!(obj instanceof _abap_object_1.ABAPObject)) { continue; } else if (this.conf.skip.indexOf(name) >= 0) { continue; } const run = new syntax_1.SyntaxLogic(this.reg, obj).run(); if (run.issues.length > 0) { continue; } this.buildEdges(name, run.spaghetti.getTop()); } return this; } run(obj) { if (!(obj instanceof objects_1.Interface) && !(obj instanceof objects_1.Class)) { return []; } const id = obj.getIdentifier(); if (id === undefined) { return []; } const previous = {}; previous[obj.getName()] = true; const path = this.findCycle(obj.getName(), obj.getName(), previous); if (path) { const message = "Cyclic definition/usage: " + obj.getName() + " -> " + path; return [issue_1.Issue.atIdentifier(id, message, this.getMetadata().key, this.conf.severity)]; } return []; } ///////////////////////////// findCycle(source, current, previous) { if (this.edges[current] === undefined) { return undefined; } for (const e of this.edges[current]) { if (e === source) { return e; } if (previous[e] === undefined) { // dont revisit vertices previous[e] = true; const found = this.findCycle(source, e, previous); if (found) { return e + " -> " + found; } } } return undefined; } buildEdges(from, node) { var _a; for (const r of node.getData().references) { if (r.resolved === undefined || node.getIdentifier().filename === r.resolved.getFilename() || r.resolved.getFilename() === _builtin_1.BuiltIn.filename) { continue; } if (this.conf.skipTestclasses === true && (r.position.getFilename().includes(".testclasses.") || r.resolved.getFilename().includes(".testclasses."))) { continue; } if (r.referenceType === _reference_1.ReferenceType.ObjectOrientedReference && ((_a = r.extra) === null || _a === void 0 ? void 0 : _a.ooName)) { if (this.edges[from] === undefined) { this.edges[from] = []; } const name = r.extra.ooName.toUpperCase(); if (name !== from && this.edges[from].indexOf(name) < 0) { const obj = this.reg.getObject("INTF", name) || this.reg.getObject("CLAS", name); if (obj && this.reg.isDependency(obj)) { continue; } this.edges[from].push(name); } } } for (const c of node.getChildren()) { this.buildEdges(from, c); } } } exports.CyclicOO = CyclicOO; //# sourceMappingURL=cyclic_oo.js.map