@abaplint/core
Version:
abaplint - Core API
192 lines • 7.48 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
const FMXXINCLUDE = /^(\/\w+\/)?L.+XX$/;
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.verticesIncludenameIndex = {};
this.verticesFilenameIndex = {};
this.edges = {};
}
addVertex(vertex) {
if (vertex.includeName !== undefined) {
this.verticesIncludenameIndex[vertex.includeName.toUpperCase()] = vertex;
}
this.verticesFilenameIndex[vertex.filename.toUpperCase()] = vertex;
}
findVertexViaIncludename(includeName) {
return this.verticesIncludenameIndex[includeName.toUpperCase()];
}
findVertexByFilename(filename) {
return this.verticesFilenameIndex[filename.toUpperCase()];
}
addEdge(from, toFilename) {
if (this.edges[from.filename] === undefined) {
this.edges[from.filename] = [];
}
this.edges[from.filename].push(toFilename);
}
findTop(filename) {
const ret = [];
for (const to of this.edges[filename] || []) {
ret.push(...this.findTop(to));
}
if (ret.length === 0) {
const found = this.findVertexByFilename(filename);
if (found !== undefined) {
ret.push(found);
}
}
return ret;
}
}
class IncludeGraph {
constructor(reg) {
this.reg = reg;
this.issues = [];
this.graph = new Graph();
this.build();
}
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);
}
}
const v = this.graph.findVertexByFilename(file.getFilename());
if (v !== undefined
&& v.include === true
&& 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);
ret.push(issue);
}
return ret;
}
///////////////////////////////
build() {
this.addVertices();
for (const o of getABAPObjects(this.reg)) {
for (const f of o.getABAPFiles()) {
if (f.getFilename().includes(".prog.screen_") || f.getFilename().includes(".fugr.screen_")) {
// skip dynpro files
continue;
}
for (const s of f.getStatements()) {
if (s.get() instanceof statements_1.Include) {
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(FMXXINCLUDE)) { // function module XX includes, possibily namespaced
continue;
}
const found = this.graph.findVertexViaIncludename(name);
if (found === undefined) {
const ifFound = s.concatTokens().toUpperCase().includes("IF FOUND");
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());
}
}
}
}
}
}
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: undefined,
include: false
});
}
}
else if (o instanceof objects_1.Class) {
for (const f of o.getSequencedFiles()) {
this.graph.addVertex({
filename: f.getFilename(),
includeName: undefined,
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: undefined, // this is the SAPL program
include: false
});
}
}
}
}
}
exports.IncludeGraph = IncludeGraph;
//# sourceMappingURL=include_graph.js.map