@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.
@@ -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.Source);
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 = exports.dumpFlow = void 0;
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
- function dumpFlow(flows) {
8
- const ret = "[" + flows.map(f => "[" + f.statements.map(b => b === null || b === void 0 ? void 0 : b.get().constructor.name).join(",") + "]").join(",");
9
- return ret + "]";
10
- }
11
- exports.dumpFlow = dumpFlow;
12
- function findBody(f) {
13
- var _a;
14
- return ((_a = f.findDirectStructure(Structures.Body)) === null || _a === void 0 ? void 0 : _a.getChildren()) || [];
15
- }
16
- function removeDuplicates(flows) {
17
- const result = [];
18
- for (const f of flows) {
19
- let duplicate = false;
20
- for (const r of result) {
21
- if (f.statements.length !== r.statements.length) {
22
- continue;
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
- ret.push(...this.traverseBody(findBody(f)));
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
- ret.push(...this.traverseBody(findBody(f)));
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
- traverseBody(children) {
67
- let flows = [{ statements: [] }];
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
- return [];
61
+ graph.addEdge(graph.getStart(), graph.getEnd());
62
+ return graph;
70
63
  }
71
- for (let i = 0; i < children.length; i++) {
72
- const c = children[i];
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
- flows.forEach(f => f.statements.push(firstChild));
78
- // current.push(firstChild);
79
- // console.dir("push: " + firstChild.constructor.name);
80
- if (firstChild.get() instanceof Statements.Check
81
- || firstChild.get() instanceof Statements.Assert) {
82
- const after = children.slice(i + 1, children.length);
83
- for (const b of this.traverseBody(after)) {
84
- for (const f of [...flows]) {
85
- flows.push({ statements: [...f.statements, ...b.statements] });
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
- break;
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
- break;
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
- break;
98
+ graph.addEdge(name, procedureEnd);
99
+ return graph;
95
100
  }
96
101
  }
97
102
  else if (firstChild instanceof nodes_1.StructureNode) {
98
- // console.dir("firstch: " + firstChild.get().constructor.name);
99
- const found = this.traverseStructure(firstChild);
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
- return flows;
108
+ graph.addEdge(current, graph.getEnd());
109
+ return graph;
114
110
  }
115
- traverseStructure(n) {
116
- let flows = [];
111
+ traverseStructure(n, procedureEnd, loopStart) {
112
+ const graph = new flow_graph_1.FlowGraph(this.counter++);
117
113
  if (n === undefined) {
118
- return flows;
114
+ return graph;
119
115
  }
116
+ let current = graph.getStart();
120
117
  const type = n.get();
121
- if (type instanceof Structures.Form) {
122
- const formst = n.findDirectStatement(Statements.Form);
123
- let bodyFlows = this.traverseBody(findBody(n));
124
- // console.dir(bodyFlows);
125
- bodyFlows = bodyFlows.map(a => { return { statements: [formst, ...a.statements] }; });
126
- flows.push(...bodyFlows);
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
- collect.push(elseifst);
176
- let bodyFlows = this.traverseBody(findBody(e));
177
- bodyFlows = bodyFlows.map(b => { return { statements: [...collect, ...b.statements] }; });
178
- flows.push(...bodyFlows);
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
- let bodyFlows = this.traverseBody(findBody(els));
184
- bodyFlows = bodyFlows.map(b => { return { statements: [...collect, elsest, ...b.statements] }; });
185
- flows.push(...bodyFlows);
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
- flows.push({ statements: [...collect] });
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 cas = n.getFirstStatement();
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
- let bodyFlows = this.traverseBody(findBody(w));
203
- bodyFlows = bodyFlows.map(b => { return { statements: [cas, first, ...b.statements] }; });
204
- flows.push(...bodyFlows);
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
- flows.push({ statements: [cas] });
198
+ graph.addEdge(caseName, graph.getEnd());
208
199
  }
209
200
  }
210
201
  else if (type instanceof Structures.CaseType) {
211
- const cas = n.getFirstStatement();
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
- let bodyFlows = this.traverseBody(findBody(w));
222
- bodyFlows = bodyFlows.map(b => { return { statements: [cas, first, ...b.statements] }; });
223
- flows.push(...bodyFlows);
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
- flows.push({ statements: [cas] });
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 flows;
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
- return (0, statement_flow_1.dumpFlow)(new statement_flow_1.StatementFlow().build(stru)).replace(/\],\[/, "],\n[");
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;
@@ -68,7 +68,7 @@ class Registry {
68
68
  }
69
69
  static abaplintVersion() {
70
70
  // magic, see build script "version.sh"
71
- return "2.80.1";
71
+ return "2.80.5";
72
72
  }
73
73
  getDDICReferences() {
74
74
  return this.references;
@@ -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
- // todo, NEW #()
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 in function module calls, method calls and VALUE constructors.`,
26
- extendedInformation: `https://github.com/SAP/styleguides/blob/master/clean-abap/CleanABAP.md#align-parameters
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, pos, message, this.getMetadata().key);
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.1",
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.96.0",
67
+ "ts-json-schema-generator": "^0.97.0",
68
68
  "typescript": "^4.4.4"
69
69
  },
70
70
  "dependencies": {