@abaplint/core 2.80.1 → 2.80.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/src/abap/2_statements/statements/replace.js +1 -1
- package/build/src/abap/5_syntax/basic_types.js +1 -0
- package/build/src/abap/flow/flow_graph.js +134 -0
- package/build/src/abap/flow/statement_flow.js +147 -175
- package/build/src/lsp/language_server.js +3 -1
- package/build/src/registry.js +1 -1
- package/build/src/rules/align_parameters.js +82 -8
- package/package.json +2 -2
|
@@ -7,7 +7,7 @@ class Replace {
|
|
|
7
7
|
getMatcher() {
|
|
8
8
|
const length = (0, combi_1.seq)("LENGTH", expressions_1.Source);
|
|
9
9
|
const offset = (0, combi_1.seq)("OFFSET", expressions_1.Source);
|
|
10
|
-
const section = (0, combi_1.seq)((0, combi_1.opt)("IN"), "SECTION", (0, combi_1.per)(offset, length), "OF", expressions_1.
|
|
10
|
+
const section = (0, combi_1.seq)((0, combi_1.opt)("IN"), "SECTION", (0, combi_1.per)(offset, length), "OF", expressions_1.Target);
|
|
11
11
|
const source = (0, combi_1.seq)((0, combi_1.opt)("OF"), expressions_1.FindType, expressions_1.Source);
|
|
12
12
|
const cas = (0, combi_1.alt)("IGNORING CASE", "RESPECTING CASE");
|
|
13
13
|
const repl = (0, combi_1.seq)("REPLACEMENT COUNT", expressions_1.Target);
|
|
@@ -455,6 +455,7 @@ class BasicTypes {
|
|
|
455
455
|
// lookup in local and global scope
|
|
456
456
|
const obj = this.scope.findObjectDefinition(className);
|
|
457
457
|
if (obj === undefined && this.scope.getDDIC().inErrorNamespace(className) === false) {
|
|
458
|
+
this.scope.addReference(expr.getFirstToken(), undefined, _reference_1.ReferenceType.ObjectOrientedVoidReference, this.filename, { ooName: className.toUpperCase() });
|
|
458
459
|
return new Types.VoidType(className);
|
|
459
460
|
}
|
|
460
461
|
else if (obj === undefined) {
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FlowGraph = void 0;
|
|
4
|
+
class FlowGraph {
|
|
5
|
+
constructor(counter) {
|
|
6
|
+
this.label = "undefined";
|
|
7
|
+
this.edges = {};
|
|
8
|
+
this.start = "start#" + counter;
|
|
9
|
+
this.end = "end#" + counter;
|
|
10
|
+
}
|
|
11
|
+
getStart() {
|
|
12
|
+
return this.start;
|
|
13
|
+
}
|
|
14
|
+
getEnd() {
|
|
15
|
+
return this.end;
|
|
16
|
+
}
|
|
17
|
+
addEdge(from, to) {
|
|
18
|
+
if (this.edges[from] === undefined) {
|
|
19
|
+
this.edges[from] = {};
|
|
20
|
+
}
|
|
21
|
+
this.edges[from][to] = true;
|
|
22
|
+
}
|
|
23
|
+
removeEdge(from, to) {
|
|
24
|
+
if (this.edges[from] === undefined) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
delete this.edges[from][to];
|
|
28
|
+
if (Object.keys(this.edges[from]).length === 0) {
|
|
29
|
+
delete this.edges[from];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
listEdges() {
|
|
33
|
+
const list = [];
|
|
34
|
+
for (const from of Object.keys(this.edges)) {
|
|
35
|
+
for (const to of Object.keys(this.edges[from])) {
|
|
36
|
+
list.push({ from, to });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return list;
|
|
40
|
+
}
|
|
41
|
+
listNodes() {
|
|
42
|
+
const set = new Set();
|
|
43
|
+
for (const l of this.listEdges()) {
|
|
44
|
+
set.add(l.from);
|
|
45
|
+
set.add(l.to);
|
|
46
|
+
}
|
|
47
|
+
return Array.from(set.values());
|
|
48
|
+
}
|
|
49
|
+
hasEdges() {
|
|
50
|
+
return Object.keys(this.edges).length > 0;
|
|
51
|
+
}
|
|
52
|
+
/** return value: end node of to graph */
|
|
53
|
+
addGraph(from, to) {
|
|
54
|
+
if (to.hasEdges() === false) {
|
|
55
|
+
return from;
|
|
56
|
+
}
|
|
57
|
+
this.addEdge(from, to.getStart());
|
|
58
|
+
to.listEdges().forEach(e => this.addEdge(e.from, e.to));
|
|
59
|
+
return to.getEnd();
|
|
60
|
+
}
|
|
61
|
+
toJSON() {
|
|
62
|
+
return JSON.stringify(this.edges);
|
|
63
|
+
}
|
|
64
|
+
toTextEdges() {
|
|
65
|
+
let graph = "";
|
|
66
|
+
for (const l of this.listEdges()) {
|
|
67
|
+
graph += `"${l.from}" -> "${l.to}";\n`;
|
|
68
|
+
}
|
|
69
|
+
return graph.trim();
|
|
70
|
+
}
|
|
71
|
+
setLabel(label) {
|
|
72
|
+
this.label = label;
|
|
73
|
+
}
|
|
74
|
+
toDigraph() {
|
|
75
|
+
return `digraph G {
|
|
76
|
+
labelloc="t";
|
|
77
|
+
label="${this.label}";
|
|
78
|
+
graph [fontname = "helvetica"];
|
|
79
|
+
node [fontname = "helvetica"];
|
|
80
|
+
edge [fontname = "helvetica"];
|
|
81
|
+
${this.toTextEdges()}
|
|
82
|
+
}`;
|
|
83
|
+
}
|
|
84
|
+
listSources(node) {
|
|
85
|
+
const set = new Set();
|
|
86
|
+
for (const l of this.listEdges()) {
|
|
87
|
+
if (node === l.to) {
|
|
88
|
+
set.add(l.from);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return Array.from(set.values());
|
|
92
|
+
}
|
|
93
|
+
listTargets(node) {
|
|
94
|
+
const set = new Set();
|
|
95
|
+
for (const l of this.listEdges()) {
|
|
96
|
+
if (node === l.from) {
|
|
97
|
+
set.add(l.to);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return Array.from(set.values());
|
|
101
|
+
}
|
|
102
|
+
/** removes all nodes containing "#" that have one ingoing and one outgoing edge */
|
|
103
|
+
reduce() {
|
|
104
|
+
for (const node of this.listNodes()) {
|
|
105
|
+
if (node.includes("#") === false) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const sources = this.listSources(node);
|
|
109
|
+
const targets = this.listTargets(node);
|
|
110
|
+
if (sources.length > 0 && targets.length > 0) {
|
|
111
|
+
// hash node in the middle of the graph
|
|
112
|
+
for (const s of sources) {
|
|
113
|
+
this.removeEdge(s, node);
|
|
114
|
+
}
|
|
115
|
+
for (const t of targets) {
|
|
116
|
+
this.removeEdge(node, t);
|
|
117
|
+
}
|
|
118
|
+
for (const s of sources) {
|
|
119
|
+
for (const t of targets) {
|
|
120
|
+
this.addEdge(s, t);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (node.startsWith("end#") && sources.length === 0) {
|
|
125
|
+
for (const t of targets) {
|
|
126
|
+
this.removeEdge(node, t);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.FlowGraph = FlowGraph;
|
|
134
|
+
//# sourceMappingURL=flow_graph.js.map
|
|
@@ -1,195 +1,184 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.StatementFlow =
|
|
3
|
+
exports.StatementFlow = void 0;
|
|
4
4
|
const nodes_1 = require("../nodes");
|
|
5
5
|
const Structures = require("../3_structures/structures");
|
|
6
6
|
const Statements = require("../2_statements/statements");
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
duplicate = true;
|
|
25
|
-
for (let index = 0; index < f.statements.length; index++) {
|
|
26
|
-
if (f.statements[index] !== r.statements[index]) {
|
|
27
|
-
duplicate = false;
|
|
28
|
-
break;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
if (duplicate === false) {
|
|
33
|
-
result.push(f);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return result;
|
|
37
|
-
}
|
|
38
|
-
function pruneByStatement(flows, type) {
|
|
39
|
-
const result = [];
|
|
40
|
-
for (const f of flows) {
|
|
41
|
-
const nodes = [];
|
|
42
|
-
for (const n of f.statements) {
|
|
43
|
-
nodes.push(n);
|
|
44
|
-
if (n.get() instanceof type) {
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
result.push({ statements: nodes });
|
|
49
|
-
}
|
|
50
|
-
return removeDuplicates(result);
|
|
51
|
-
}
|
|
52
|
-
////////////////////////////////////////////////////////////////
|
|
7
|
+
const Expressions = require("../2_statements/expressions");
|
|
8
|
+
const flow_graph_1 = require("./flow_graph");
|
|
9
|
+
// Levels: top, FORM, METHOD, FUNCTION-MODULE, (MODULE, AT, END-OF-*, GET, START-OF-SELECTION, TOP-OF-PAGE)
|
|
10
|
+
//
|
|
11
|
+
// Loop branching: LOOP, DO, WHILE,SELECT(loop), WITH, PROVIDE
|
|
12
|
+
//
|
|
13
|
+
// Branching: IF, CASE, CASE TYPE OF, TRY, ON, CATCH SYSTEM-EXCEPTIONS, AT
|
|
14
|
+
//
|
|
15
|
+
// Conditional exits: CHECK, ASSERT
|
|
16
|
+
//
|
|
17
|
+
// Exits: RETURN, EXIT, RAISE(not RESUMABLE), MESSAGE(type E and A?), CONTINUE, REJECT, RESUME, STOP
|
|
18
|
+
//
|
|
19
|
+
// Not handled? INCLUDE + malplaced macro calls
|
|
20
|
+
/////////////////////////////////////
|
|
21
|
+
// TODO: handling static exceptions(only static), refactor some logic from UncaughtException to common file
|
|
22
|
+
// TODO: RAISE
|
|
53
23
|
class StatementFlow {
|
|
24
|
+
constructor() {
|
|
25
|
+
this.counter = 0;
|
|
26
|
+
}
|
|
54
27
|
build(stru) {
|
|
28
|
+
var _a, _b;
|
|
55
29
|
const ret = [];
|
|
56
30
|
const forms = stru.findAllStructures(Structures.Form);
|
|
57
31
|
for (const f of forms) {
|
|
58
|
-
|
|
32
|
+
const formName = "FORM " + ((_a = f.findFirstExpression(Expressions.FormName)) === null || _a === void 0 ? void 0 : _a.concatTokens());
|
|
33
|
+
this.counter = 1;
|
|
34
|
+
const graph = this.traverseBody(this.findBody(f), "end#1", undefined);
|
|
35
|
+
graph.setLabel(formName);
|
|
36
|
+
ret.push(graph);
|
|
59
37
|
}
|
|
60
38
|
const methods = stru.findAllStructures(Structures.Method);
|
|
61
39
|
for (const f of methods) {
|
|
62
|
-
|
|
40
|
+
const methodName = "METHOD " + ((_b = f.findFirstExpression(Expressions.MethodName)) === null || _b === void 0 ? void 0 : _b.concatTokens());
|
|
41
|
+
this.counter = 1;
|
|
42
|
+
const graph = this.traverseBody(this.findBody(f), "end#1", undefined);
|
|
43
|
+
graph.setLabel(methodName);
|
|
44
|
+
ret.push(graph);
|
|
63
45
|
}
|
|
64
|
-
return ret;
|
|
46
|
+
return ret.map(f => f.reduce());
|
|
47
|
+
}
|
|
48
|
+
findBody(f) {
|
|
49
|
+
var _a;
|
|
50
|
+
return ((_a = f.findDirectStructure(Structures.Body)) === null || _a === void 0 ? void 0 : _a.getChildren()) || [];
|
|
65
51
|
}
|
|
66
|
-
|
|
67
|
-
|
|
52
|
+
buildName(statement) {
|
|
53
|
+
// note: there might be multiple statements on the same line
|
|
54
|
+
return statement.get().constructor.name +
|
|
55
|
+
":" + statement.getFirstToken().getRow() +
|
|
56
|
+
"," + statement.getFirstToken().getCol();
|
|
57
|
+
}
|
|
58
|
+
traverseBody(children, procedureEnd, loopStart) {
|
|
59
|
+
const graph = new flow_graph_1.FlowGraph(this.counter++);
|
|
68
60
|
if (children.length === 0) {
|
|
69
|
-
|
|
61
|
+
graph.addEdge(graph.getStart(), graph.getEnd());
|
|
62
|
+
return graph;
|
|
70
63
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// console.dir(c);
|
|
64
|
+
let current = graph.getStart();
|
|
65
|
+
for (const c of children) {
|
|
74
66
|
if (c.get() instanceof Structures.Normal) {
|
|
75
67
|
const firstChild = c.getFirstChild(); // "Normal" only has one child
|
|
76
68
|
if (firstChild instanceof nodes_1.StatementNode) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (firstChild.get() instanceof Statements.Check
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
69
|
+
const name = this.buildName(firstChild);
|
|
70
|
+
graph.addEdge(current, name);
|
|
71
|
+
current = name;
|
|
72
|
+
if (firstChild.get() instanceof Statements.Check) {
|
|
73
|
+
if (loopStart) {
|
|
74
|
+
graph.addEdge(name, loopStart);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
graph.addEdge(name, procedureEnd);
|
|
87
78
|
}
|
|
88
|
-
|
|
79
|
+
}
|
|
80
|
+
else if (firstChild.get() instanceof Statements.Assert) {
|
|
81
|
+
graph.addEdge(name, procedureEnd);
|
|
82
|
+
}
|
|
83
|
+
else if (firstChild.get() instanceof Statements.Continue && loopStart) {
|
|
84
|
+
graph.addEdge(name, loopStart);
|
|
85
|
+
return graph;
|
|
89
86
|
}
|
|
90
87
|
else if (firstChild.get() instanceof Statements.Exit) {
|
|
91
|
-
|
|
88
|
+
if (loopStart) {
|
|
89
|
+
// hmm, perhaps this should hit loop end instead?
|
|
90
|
+
graph.addEdge(name, loopStart);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
graph.addEdge(name, procedureEnd);
|
|
94
|
+
}
|
|
95
|
+
return graph;
|
|
92
96
|
}
|
|
93
97
|
else if (firstChild.get() instanceof Statements.Return) {
|
|
94
|
-
|
|
98
|
+
graph.addEdge(name, procedureEnd);
|
|
99
|
+
return graph;
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
else if (firstChild instanceof nodes_1.StructureNode) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
// console.dir("found: " + dump(found));
|
|
101
|
-
const n = [];
|
|
102
|
-
for (const existing of flows) {
|
|
103
|
-
for (const fo of found) {
|
|
104
|
-
const add = { statements: [...existing.statements, ...fo.statements] };
|
|
105
|
-
n.push(add);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// console.dir(dump(n));
|
|
109
|
-
flows = n;
|
|
103
|
+
const sub = this.traverseStructure(firstChild, procedureEnd, loopStart);
|
|
104
|
+
current = graph.addGraph(current, sub);
|
|
110
105
|
}
|
|
111
106
|
}
|
|
112
107
|
}
|
|
113
|
-
|
|
108
|
+
graph.addEdge(current, graph.getEnd());
|
|
109
|
+
return graph;
|
|
114
110
|
}
|
|
115
|
-
traverseStructure(n) {
|
|
116
|
-
|
|
111
|
+
traverseStructure(n, procedureEnd, loopStart) {
|
|
112
|
+
const graph = new flow_graph_1.FlowGraph(this.counter++);
|
|
117
113
|
if (n === undefined) {
|
|
118
|
-
return
|
|
114
|
+
return graph;
|
|
119
115
|
}
|
|
116
|
+
let current = graph.getStart();
|
|
120
117
|
const type = n.get();
|
|
121
|
-
if (type instanceof Structures.
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
else if (type instanceof Structures.Any) {
|
|
129
|
-
for (const c of n.getChildren()) {
|
|
130
|
-
// console.dir("yep");
|
|
131
|
-
if (c instanceof nodes_1.StructureNode && c.get() instanceof Structures.Form) {
|
|
132
|
-
flows.push(...this.traverseStructure(c));
|
|
133
|
-
}
|
|
134
|
-
else if (c instanceof nodes_1.StructureNode && c.get() instanceof Structures.If) {
|
|
135
|
-
flows.push(...this.traverseStructure(c));
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
console.dir("any, todo, " + c.constructor.name + ", " + c.get().constructor.name);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
else if (type instanceof Structures.Try) {
|
|
143
|
-
// TODO: this does not take exceptions into account
|
|
144
|
-
const firstTry = n.getFirstStatement();
|
|
145
|
-
let allPossibleBody = this.traverseBody(findBody(n));
|
|
146
|
-
allPossibleBody = allPossibleBody.map(b => { return { statements: [firstTry, ...b.statements] }; });
|
|
147
|
-
if (allPossibleBody.length === 0) {
|
|
148
|
-
allPossibleBody.push({ statements: [firstTry] });
|
|
149
|
-
}
|
|
150
|
-
flows.push(...allPossibleBody);
|
|
151
|
-
for (const c of n.findDirectStructures(Structures.Catch)) {
|
|
152
|
-
const firstCatch = c.getFirstStatement();
|
|
153
|
-
const catchBodies = this.traverseBody(findBody(c));
|
|
154
|
-
for (const bodyFlow of allPossibleBody) {
|
|
155
|
-
for (const catchFlow of catchBodies) {
|
|
156
|
-
flows.push({ statements: [...bodyFlow.statements, firstCatch, ...catchFlow.statements] });
|
|
157
|
-
}
|
|
158
|
-
if (catchBodies.length === 0) {
|
|
159
|
-
flows.push({ statements: [...bodyFlow.statements, firstCatch] });
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
// TODO, handle CLEANUP
|
|
164
|
-
}
|
|
165
|
-
else if (type instanceof Structures.If) {
|
|
166
|
-
const collect = [n.findDirectStatement(Statements.If)];
|
|
167
|
-
let bodyFlows = this.traverseBody(findBody(n));
|
|
168
|
-
bodyFlows = bodyFlows.map(b => { return { statements: [...collect, ...b.statements] }; });
|
|
169
|
-
flows.push(...bodyFlows);
|
|
118
|
+
if (type instanceof Structures.If) {
|
|
119
|
+
const ifName = this.buildName(n.findDirectStatement(Statements.If));
|
|
120
|
+
const sub = this.traverseBody(this.findBody(n), procedureEnd, loopStart);
|
|
121
|
+
graph.addEdge(current, ifName);
|
|
122
|
+
graph.addGraph(ifName, sub);
|
|
123
|
+
graph.addEdge(sub.getEnd(), graph.getEnd());
|
|
124
|
+
current = ifName;
|
|
170
125
|
for (const e of n.findDirectStructures(Structures.ElseIf)) {
|
|
171
126
|
const elseifst = e.findDirectStatement(Statements.ElseIf);
|
|
172
127
|
if (elseifst === undefined) {
|
|
173
128
|
continue;
|
|
174
129
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
130
|
+
const elseIfName = this.buildName(elseifst);
|
|
131
|
+
const sub = this.traverseBody(this.findBody(e), procedureEnd, loopStart);
|
|
132
|
+
graph.addEdge(current, elseIfName);
|
|
133
|
+
graph.addGraph(elseIfName, sub);
|
|
134
|
+
graph.addEdge(sub.getEnd(), graph.getEnd());
|
|
135
|
+
current = elseIfName;
|
|
179
136
|
}
|
|
180
137
|
const els = n.findDirectStructure(Structures.Else);
|
|
181
138
|
const elsest = els === null || els === void 0 ? void 0 : els.findDirectStatement(Statements.Else);
|
|
182
139
|
if (els && elsest) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
140
|
+
const elseName = this.buildName(elsest);
|
|
141
|
+
const sub = this.traverseBody(this.findBody(els), procedureEnd, loopStart);
|
|
142
|
+
graph.addEdge(current, elseName);
|
|
143
|
+
graph.addGraph(elseName, sub);
|
|
144
|
+
graph.addEdge(sub.getEnd(), graph.getEnd());
|
|
186
145
|
}
|
|
187
146
|
else {
|
|
188
|
-
|
|
147
|
+
graph.addEdge(ifName, graph.getEnd());
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else if (type instanceof Structures.Loop
|
|
151
|
+
|| type instanceof Structures.While
|
|
152
|
+
|| type instanceof Structures.With
|
|
153
|
+
|| type instanceof Structures.Provide
|
|
154
|
+
|| type instanceof Structures.Select
|
|
155
|
+
|| type instanceof Structures.Do) {
|
|
156
|
+
const loopName = this.buildName(n.getFirstStatement());
|
|
157
|
+
const sub = this.traverseBody(this.findBody(n), procedureEnd, loopName);
|
|
158
|
+
graph.addEdge(current, loopName);
|
|
159
|
+
graph.addGraph(loopName, sub);
|
|
160
|
+
graph.addEdge(sub.getEnd(), loopName);
|
|
161
|
+
graph.addEdge(loopName, graph.getEnd());
|
|
162
|
+
}
|
|
163
|
+
else if (type instanceof Structures.Try) {
|
|
164
|
+
const tryName = this.buildName(n.getFirstStatement());
|
|
165
|
+
const body = this.traverseBody(this.findBody(n), procedureEnd, loopStart);
|
|
166
|
+
graph.addEdge(current, tryName);
|
|
167
|
+
graph.addGraph(tryName, body);
|
|
168
|
+
graph.addEdge(body.getEnd(), graph.getEnd());
|
|
169
|
+
for (const c of n.findDirectStructures(Structures.Catch)) {
|
|
170
|
+
const catchName = this.buildName(c.getFirstStatement());
|
|
171
|
+
const catchBody = this.traverseBody(this.findBody(c), procedureEnd, loopStart);
|
|
172
|
+
// TODO: this does not take exceptions into account
|
|
173
|
+
graph.addEdge(body.getEnd(), catchName);
|
|
174
|
+
graph.addGraph(catchName, catchBody);
|
|
175
|
+
graph.addEdge(catchBody.getEnd(), graph.getEnd());
|
|
189
176
|
}
|
|
177
|
+
// TODO, handle CLEANUP
|
|
190
178
|
}
|
|
191
179
|
else if (type instanceof Structures.Case) {
|
|
192
|
-
const
|
|
180
|
+
const caseName = this.buildName(n.getFirstStatement());
|
|
181
|
+
graph.addEdge(current, caseName);
|
|
193
182
|
let othersFound = false;
|
|
194
183
|
for (const w of n.findDirectStructures(Structures.When)) {
|
|
195
184
|
const first = w.getFirstStatement();
|
|
@@ -199,16 +188,19 @@ class StatementFlow {
|
|
|
199
188
|
if (first.get() instanceof Statements.WhenOthers) {
|
|
200
189
|
othersFound = true;
|
|
201
190
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
191
|
+
const firstName = this.buildName(first);
|
|
192
|
+
const sub = this.traverseBody(this.findBody(w), procedureEnd, loopStart);
|
|
193
|
+
graph.addEdge(caseName, firstName);
|
|
194
|
+
graph.addGraph(firstName, sub);
|
|
195
|
+
graph.addEdge(sub.getEnd(), graph.getEnd());
|
|
205
196
|
}
|
|
206
197
|
if (othersFound === false) {
|
|
207
|
-
|
|
198
|
+
graph.addEdge(caseName, graph.getEnd());
|
|
208
199
|
}
|
|
209
200
|
}
|
|
210
201
|
else if (type instanceof Structures.CaseType) {
|
|
211
|
-
const
|
|
202
|
+
const caseName = this.buildName(n.getFirstStatement());
|
|
203
|
+
graph.addEdge(current, caseName);
|
|
212
204
|
let othersFound = false;
|
|
213
205
|
for (const w of n.findDirectStructures(Structures.WhenType)) {
|
|
214
206
|
const first = w.getFirstStatement();
|
|
@@ -218,40 +210,20 @@ class StatementFlow {
|
|
|
218
210
|
if (first.get() instanceof Statements.WhenOthers) {
|
|
219
211
|
othersFound = true;
|
|
220
212
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
213
|
+
const firstName = this.buildName(first);
|
|
214
|
+
const sub = this.traverseBody(this.findBody(w), procedureEnd, loopStart);
|
|
215
|
+
graph.addEdge(caseName, firstName);
|
|
216
|
+
graph.addGraph(firstName, sub);
|
|
217
|
+
graph.addEdge(sub.getEnd(), graph.getEnd());
|
|
224
218
|
}
|
|
225
219
|
if (othersFound === false) {
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
else if (type instanceof Structures.Loop
|
|
230
|
-
|| type instanceof Structures.While
|
|
231
|
-
|| type instanceof Structures.With
|
|
232
|
-
|| type instanceof Structures.Provide
|
|
233
|
-
|| type instanceof Structures.Select
|
|
234
|
-
|| type instanceof Structures.Do) {
|
|
235
|
-
const loop = n.getFirstStatement();
|
|
236
|
-
const bodyFlows = this.traverseBody(findBody(n));
|
|
237
|
-
for (const b of bodyFlows) {
|
|
238
|
-
flows.push({ statements: [loop, ...b.statements] });
|
|
239
|
-
}
|
|
240
|
-
for (const b1 of bodyFlows) {
|
|
241
|
-
for (const b2 of bodyFlows) {
|
|
242
|
-
const add = [loop, ...b1.statements, ...b2.statements];
|
|
243
|
-
flows.push({ statements: add });
|
|
244
|
-
}
|
|
220
|
+
graph.addEdge(caseName, graph.getEnd());
|
|
245
221
|
}
|
|
246
|
-
flows.push({ statements: [loop] });
|
|
247
|
-
flows = pruneByStatement(flows, Statements.Exit);
|
|
248
|
-
flows = pruneByStatement(flows, Statements.Continue);
|
|
249
|
-
flows = pruneByStatement(flows, Statements.Return);
|
|
250
222
|
}
|
|
251
223
|
else {
|
|
252
224
|
console.dir("todo, " + n.get().constructor.name);
|
|
253
225
|
}
|
|
254
|
-
return
|
|
226
|
+
return graph;
|
|
255
227
|
}
|
|
256
228
|
}
|
|
257
229
|
exports.StatementFlow = StatementFlow;
|
|
@@ -121,7 +121,9 @@ class LanguageServer {
|
|
|
121
121
|
if (stru === undefined) {
|
|
122
122
|
return "empty structure";
|
|
123
123
|
}
|
|
124
|
-
|
|
124
|
+
const graphs = new statement_flow_1.StatementFlow().build(stru);
|
|
125
|
+
const wiz = graphs.map(g => g.toDigraph());
|
|
126
|
+
return JSON.stringify(wiz);
|
|
125
127
|
}
|
|
126
128
|
}
|
|
127
129
|
exports.LanguageServer = LanguageServer;
|
package/build/src/registry.js
CHANGED
|
@@ -6,10 +6,7 @@ const Expressions = require("../abap/2_statements/expressions");
|
|
|
6
6
|
const _abap_rule_1 = require("./_abap_rule");
|
|
7
7
|
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
8
8
|
const _irule_1 = require("./_irule");
|
|
9
|
-
|
|
10
|
-
// todo, RaiseEvent
|
|
11
|
-
// todo, CREATE OBJECT
|
|
12
|
-
// todo, RAISE
|
|
9
|
+
const __1 = require("..");
|
|
13
10
|
class AlignParametersConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
14
11
|
}
|
|
15
12
|
exports.AlignParametersConf = AlignParametersConf;
|
|
@@ -22,8 +19,17 @@ class AlignParameters extends _abap_rule_1.ABAPRule {
|
|
|
22
19
|
return {
|
|
23
20
|
key: "align_parameters",
|
|
24
21
|
title: "Align Parameters",
|
|
25
|
-
shortDescription: `Checks for vertially aligned parameters
|
|
26
|
-
extendedInformation: `
|
|
22
|
+
shortDescription: `Checks for vertially aligned parameters`,
|
|
23
|
+
extendedInformation: `Checks:
|
|
24
|
+
* function module calls
|
|
25
|
+
* method calls
|
|
26
|
+
* VALUE constructors
|
|
27
|
+
* NEW constructors
|
|
28
|
+
* RAISE EXCEPTION statements
|
|
29
|
+
* CREATE OBJECT statements
|
|
30
|
+
* RAISE EVENT statements
|
|
31
|
+
|
|
32
|
+
https://github.com/SAP/styleguides/blob/master/clean-abap/CleanABAP.md#align-parameters
|
|
27
33
|
|
|
28
34
|
Does not take effect on non functional method calls, use https://rules.abaplint.org/functional_writing/
|
|
29
35
|
|
|
@@ -69,6 +75,8 @@ foo = VALUE #(
|
|
|
69
75
|
candidates.push(...this.functionParameterCandidates(stru));
|
|
70
76
|
candidates.push(...this.methodCallParamCandidates(stru));
|
|
71
77
|
candidates.push(...this.valueBodyCandidates(stru));
|
|
78
|
+
candidates.push(...this.raiseAndCreateCandidates(stru));
|
|
79
|
+
candidates.push(...this.newCandidates(stru));
|
|
72
80
|
for (const c of candidates) {
|
|
73
81
|
const i = this.checkCandidate(c, file);
|
|
74
82
|
if (i) {
|
|
@@ -90,13 +98,54 @@ foo = VALUE #(
|
|
|
90
98
|
}
|
|
91
99
|
for (const p of candidate.parameters) {
|
|
92
100
|
if (p.eq.getCol() !== expectedEqualsColumn) {
|
|
93
|
-
const pos = candidate.parameters[0].eq;
|
|
94
101
|
const message = "Align parameters to column " + expectedEqualsColumn;
|
|
95
|
-
return issue_1.Issue.atPosition(file,
|
|
102
|
+
return issue_1.Issue.atPosition(file, p.eq, message, this.getMetadata().key);
|
|
96
103
|
}
|
|
97
104
|
}
|
|
98
105
|
return undefined;
|
|
99
106
|
}
|
|
107
|
+
newCandidates(stru) {
|
|
108
|
+
const candidates = [];
|
|
109
|
+
for (const vb of stru.findAllExpressionsRecursive(Expressions.NewObject)) {
|
|
110
|
+
const parameters = [];
|
|
111
|
+
const fieldAssignments = vb.findDirectExpressions(Expressions.FieldAssignment);
|
|
112
|
+
if (fieldAssignments.length >= 2) {
|
|
113
|
+
for (const fs of fieldAssignments) {
|
|
114
|
+
const children = fs.getChildren();
|
|
115
|
+
if (children.length < 3) {
|
|
116
|
+
continue; // unexpected
|
|
117
|
+
}
|
|
118
|
+
parameters.push({
|
|
119
|
+
left: children[0],
|
|
120
|
+
eq: children[1].getFirstToken().getStart(),
|
|
121
|
+
right: children[2],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (parameters.length > 0) {
|
|
125
|
+
candidates.push({ parameters });
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const list = vb.findDirectExpression(Expressions.ParameterListS);
|
|
130
|
+
if (list) {
|
|
131
|
+
for (const c of list.getChildren()) {
|
|
132
|
+
const children = c.getChildren();
|
|
133
|
+
if (children.length < 3) {
|
|
134
|
+
continue; // unexpected
|
|
135
|
+
}
|
|
136
|
+
parameters.push({
|
|
137
|
+
left: children[0],
|
|
138
|
+
eq: children[1].getFirstToken().getStart(),
|
|
139
|
+
right: children[2],
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (parameters.length > 0) {
|
|
143
|
+
candidates.push({ parameters });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return candidates;
|
|
148
|
+
}
|
|
100
149
|
valueBodyCandidates(stru) {
|
|
101
150
|
const candidates = [];
|
|
102
151
|
for (const vb of stru.findAllExpressionsRecursive(Expressions.ValueBody)) {
|
|
@@ -122,6 +171,31 @@ foo = VALUE #(
|
|
|
122
171
|
}
|
|
123
172
|
return candidates;
|
|
124
173
|
}
|
|
174
|
+
raiseAndCreateCandidates(stru) {
|
|
175
|
+
const candidates = [];
|
|
176
|
+
const statements = stru.findAllStatements(__1.Statements.Raise);
|
|
177
|
+
statements.push(...stru.findAllStatements(__1.Statements.CreateObject));
|
|
178
|
+
statements.push(...stru.findAllStatements(__1.Statements.RaiseEvent));
|
|
179
|
+
for (const raise of statements) {
|
|
180
|
+
const parameters = [];
|
|
181
|
+
const param = raise.findDirectExpression(Expressions.ParameterListS);
|
|
182
|
+
for (const p of (param === null || param === void 0 ? void 0 : param.getChildren()) || []) {
|
|
183
|
+
const children = p.getChildren();
|
|
184
|
+
if (children.length < 3) {
|
|
185
|
+
continue; // unexpected
|
|
186
|
+
}
|
|
187
|
+
parameters.push({
|
|
188
|
+
left: children[0],
|
|
189
|
+
eq: children[1].getFirstToken().getStart(),
|
|
190
|
+
right: children[2],
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
if (parameters.length > 0) {
|
|
194
|
+
candidates.push({ parameters });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return candidates;
|
|
198
|
+
}
|
|
125
199
|
methodCallParamCandidates(stru) {
|
|
126
200
|
var _a, _b, _c;
|
|
127
201
|
const candidates = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/core",
|
|
3
|
-
"version": "2.80.
|
|
3
|
+
"version": "2.80.5",
|
|
4
4
|
"description": "abaplint - Core API",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/abaplint.d.ts",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"mocha": "^9.1.3",
|
|
65
65
|
"c8": "^7.10.0",
|
|
66
66
|
"source-map-support": "^0.5.20",
|
|
67
|
-
"ts-json-schema-generator": "^0.
|
|
67
|
+
"ts-json-schema-generator": "^0.97.0",
|
|
68
68
|
"typescript": "^4.4.4"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|