@abaplint/core
Version:
abaplint - Core API
199 lines • 7.29 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.IncludeGraph = void 0;
const statements_1 = require("../abap/2_statements/statements");
const expressions_1 = require("../abap/2_statements/expressions");
const objects_1 = require("../objects");
const check_include_1 = require("../rules/check_include");
const position_1 = require("../position");
const issue_1 = require("../issue");
const _abap_object_1 = require("../objects/_abap_object");
const severity_1 = require("../severity");
// todo, check for cycles/circular dependencies, method findTop
// todo, add configurable error for multiple use includes
function getABAPObjects(reg) {
const ret = [];
for (const o of reg.getObjects()) {
if (o instanceof _abap_object_1.ABAPObject) {
ret.push(o);
}
}
return ret;
}
class Graph {
constructor() {
this.vertices = [];
this.edges = [];
}
addVertex(vertex) {
this.vertices.push(vertex);
}
findInclude(includeName) {
for (const v of this.vertices) {
if (v.includeName.toUpperCase() === includeName.toUpperCase()) {
return v;
}
}
return undefined;
}
findVertex(filename) {
for (const v of this.vertices) {
if (v.filename.toUpperCase() === filename.toUpperCase()) {
return v;
}
}
return undefined;
}
addEdge(from, toFilename) {
this.edges.push({ from: from.filename, to: toFilename });
}
findTop(filename) {
const ret = [];
for (const e of this.edges) {
if (e.from === filename) {
ret.push(...this.findTop(e.to));
}
}
if (ret.length === 0) {
const found = this.findVertex(filename);
if (found !== undefined) {
ret.push(found);
}
}
return ret;
}
}
class IncludeGraph {
constructor(reg) {
this.reg = reg;
this.issues = [];
this.graph = new Graph();
this.build();
}
getIssues() {
return this.issues;
}
listMainForInclude(filename) {
const ret = [];
if (filename === undefined) {
return [];
}
for (const f of this.graph.findTop(filename)) {
if (f.include === false) {
ret.push(f.filename);
}
}
return ret;
}
getIssuesFile(file) {
const ret = [];
for (const i of this.issues) {
if (i.getFilename() === file.getFilename()) {
ret.push(i);
}
}
return ret;
}
///////////////////////////////
build() {
this.addVertices();
for (const o of getABAPObjects(this.reg)) {
for (const f of o.getABAPFiles()) {
for (const s of f.getStatements()) {
if (s.get() instanceof statements_1.Include) {
const ifFound = s.concatTokens().toUpperCase().includes("IF FOUND");
const iexp = s.findFirstExpression(expressions_1.IncludeName);
if (iexp === undefined) {
throw new Error("unexpected Include node");
}
const name = iexp.getFirstToken().getStr().toUpperCase();
if (name.match(/^(\/\w+\/)?L.+XX$/)) { // function module XX includes, possibily namespaced
continue;
}
const found = this.graph.findInclude(name);
if (found === undefined) {
if (ifFound === false) {
const issue = issue_1.Issue.atStatement(f, s, "Include " + name + " not found", new check_include_1.CheckInclude().getMetadata().key, severity_1.Severity.Error);
this.issues.push(issue);
}
}
else if (found.include === false) {
const issue = issue_1.Issue.atStatement(f, s, "Not possible to INCLUDE a main program, " + name, new check_include_1.CheckInclude().getMetadata().key, severity_1.Severity.Error);
this.issues.push(issue);
}
else {
this.graph.addEdge(found, f.getFilename());
}
}
}
}
}
this.findUnusedIncludes();
}
findUnusedIncludes() {
for (const v of this.graph.vertices) {
if (v.include === true) {
if (this.listMainForInclude(v.filename).length === 0) {
const f = this.reg.getFileByName(v.filename);
if (f === undefined) {
throw new Error("findUnusedIncludes internal error");
}
const issue = issue_1.Issue.atPosition(f, new position_1.Position(1, 1), "INCLUDE not used anywhere", new check_include_1.CheckInclude().getMetadata().key, severity_1.Severity.Error);
this.issues.push(issue);
}
}
}
}
addVertices() {
for (const o of getABAPObjects(this.reg)) {
if (o instanceof objects_1.Program) {
const file = o.getMainABAPFile();
if (file) {
this.graph.addVertex({
filename: file.getFilename(),
includeName: o.getName(),
include: o.isInclude()
});
}
}
else if (o instanceof objects_1.TypePool) {
const file = o.getMainABAPFile();
if (file) {
this.graph.addVertex({
filename: file.getFilename(),
includeName: o.getName(),
include: false
});
}
}
else if (o instanceof objects_1.Class) {
for (const f of o.getSequencedFiles()) {
this.graph.addVertex({
filename: f.getFilename(),
includeName: o.getName(),
include: false
});
}
}
else if (o instanceof objects_1.FunctionGroup) {
for (const i of o.getIncludeFiles()) {
this.graph.addVertex({
filename: i.file.getFilename(),
includeName: i.name,
include: true
});
}
const file = o.getMainABAPFile();
if (file) {
this.graph.addVertex({
filename: file.getFilename(),
includeName: o.getName(),
include: false
});
}
}
}
}
}
exports.IncludeGraph = IncludeGraph;
//# sourceMappingURL=include_graph.js.map