UNPKG

@abaplint/core

Version:
192 lines 7.48 kB
"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