Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 10339x 10339x 1x 1x 10339x 10339x 10335x 10335x 4x 4x 4x 10339x 10339x 10339x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 4x 4x 4x 5x 4x 1x 1x 1x 1x 10339x 10339x 10822x 10788x 10788x 34x 34x 5x 5x 5x 34x 34x 10339x 10339x 1x 1x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 1x 1x 5x 5x 8x 5x 5x 4x 4x 5x 8x 1x 1x 1x 1x 1x | import {IRegistry} from "../_iregistry";
import {ABAPObject} from "../objects/_abap_object";
import {Program} from "../objects/program";
import {Unknown} from "./2_statements/statements/_statement";
import {ExpandMacros} from "./2_statements/expand_macros";
import {IncludeGraph} from "../utils/include_graph";
// Macros can be defined in one include and used in a sibling include, connected
// via the main program. Objects are parsed in isolation, so the sibling include
// initially ends up with Unknown statements. This second pass finds the main
// program(s) for such includes, collects the macro definitions visible there,
// and re-parses the include with the macro names as extra global macros.
export class CrossIncludeMacros {
private readonly reg: IRegistry;
public constructor(reg: IRegistry) {
this.reg = reg;
}
public run(): void {
const candidates = this.findCandidates();
if (candidates.length === 0) {
return;
}
const graph = new IncludeGraph(this.reg);
const config = this.reg.getConfig();
const globalMacros = config.getSyntaxSetttings().globalMacros || [];
for (const prog of candidates) {
const mains = this.findMains(graph, prog);
if (mains.size === 0) {
continue;
}
const expand = new ExpandMacros(globalMacros, config.getRelease(), this.reg, config.getLanguageVersion());
for (const main of mains) {
for (const file of main.getABAPFiles()) {
// find() follows INCLUDE statements, so this collects macros from the full include chain
expand.find([...file.getStatements()], file, false);
}
}
const macroNames = expand.listMacroNames();
if (this.matchesUnknown(prog, new Set(macroNames))) {
prog.setDirty();
prog.parse(config.getRelease(), macroNames, this.reg, config.getLanguageVersion());
}
}
}
//////////////////////////////
private findCandidates(): Program[] {
const ret: Program[] = [];
for (const obj of this.reg.getObjects()) {
if (!(obj instanceof Program) || obj.isInclude() === false) {
continue;
}
for (const file of obj.getABAPFiles()) {
if (file.getStatements().some(s => s.get() instanceof Unknown)) {
ret.push(obj);
break;
}
}
}
return ret;
}
private findMains(graph: IncludeGraph, prog: Program): Set<ABAPObject> {
const ret = new Set<ABAPObject>();
const filename = prog.getMainABAPFile()?.getFilename();
for (const mainFilename of graph.listMainForInclude(filename)) {
const file = this.reg.getFileByName(mainFilename);
const obj = file ? this.reg.findObjectForFile(file) : undefined;
if (obj instanceof ABAPObject) {
ret.add(obj);
}
}
return ret;
}
private matchesUnknown(prog: Program, macroNames: Set<string>): boolean {
for (const file of prog.getABAPFiles()) {
for (const s of file.getStatements()) {
if (s.get() instanceof Unknown) {
const name = ExpandMacros.findName(s.getTokens());
if (name !== undefined && macroNames.has(name.toUpperCase())) {
return true;
}
}
}
}
return false;
}
}
|