@abaplint/core 2.80.4 → 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.
Files changed (74) hide show
  1. package/README.md +6 -6
  2. package/build/src/abap/flow/flow_graph.js +134 -0
  3. package/build/src/abap/flow/statement_flow.js +145 -189
  4. package/build/src/lsp/help.js +7 -7
  5. package/build/src/lsp/language_server.js +3 -1
  6. package/build/src/registry.js +1 -1
  7. package/build/src/rules/abapdoc.js +1 -1
  8. package/build/src/rules/align_parameters.js +33 -33
  9. package/build/src/rules/ambiguous_statement.js +5 -5
  10. package/build/src/rules/avoid_use.js +6 -6
  11. package/build/src/rules/begin_end_names.js +4 -4
  12. package/build/src/rules/begin_single_include.js +12 -12
  13. package/build/src/rules/call_transaction_authority_check.js +3 -3
  14. package/build/src/rules/chain_mainly_declarations.js +4 -4
  15. package/build/src/rules/check_abstract.js +2 -2
  16. package/build/src/rules/check_comments.js +3 -3
  17. package/build/src/rules/check_include.js +3 -3
  18. package/build/src/rules/check_no_handler_pragma.js +8 -8
  19. package/build/src/rules/check_subrc.js +8 -8
  20. package/build/src/rules/commented_code.js +1 -1
  21. package/build/src/rules/constructor_visibility_public.js +4 -4
  22. package/build/src/rules/contains_tab.js +2 -2
  23. package/build/src/rules/dangerous_statement.js +1 -1
  24. package/build/src/rules/downport.js +35 -35
  25. package/build/src/rules/exit_or_check.js +3 -3
  26. package/build/src/rules/exporting.js +1 -1
  27. package/build/src/rules/forbidden_identifier.js +1 -1
  28. package/build/src/rules/forbidden_void_type.js +2 -2
  29. package/build/src/rules/functional_writing.js +17 -17
  30. package/build/src/rules/global_class.js +10 -10
  31. package/build/src/rules/identical_conditions.js +2 -2
  32. package/build/src/rules/identical_contents.js +15 -15
  33. package/build/src/rules/identical_descriptions.js +4 -4
  34. package/build/src/rules/if_in_if.js +7 -7
  35. package/build/src/rules/implement_methods.js +3 -3
  36. package/build/src/rules/in_statement_indentation.js +11 -11
  37. package/build/src/rules/intf_referencing_clas.js +3 -3
  38. package/build/src/rules/line_break_style.js +2 -2
  39. package/build/src/rules/line_length.js +1 -1
  40. package/build/src/rules/line_only_punc.js +1 -1
  41. package/build/src/rules/local_variable_names.js +2 -2
  42. package/build/src/rules/many_parentheses.js +10 -10
  43. package/build/src/rules/max_one_method_parameter_per_line.js +7 -7
  44. package/build/src/rules/max_one_statement.js +3 -3
  45. package/build/src/rules/nesting.js +1 -1
  46. package/build/src/rules/no_public_attributes.js +1 -1
  47. package/build/src/rules/no_yoda_conditions.js +4 -4
  48. package/build/src/rules/obsolete_statement.js +36 -36
  49. package/build/src/rules/omit_parameter_name.js +3 -3
  50. package/build/src/rules/omit_receiving.js +13 -13
  51. package/build/src/rules/parser_702_chaining.js +2 -2
  52. package/build/src/rules/parser_error.js +2 -2
  53. package/build/src/rules/parser_missing_space.js +1 -1
  54. package/build/src/rules/prefer_inline.js +16 -16
  55. package/build/src/rules/prefer_is_not.js +7 -7
  56. package/build/src/rules/prefer_raise_exception_new.js +3 -3
  57. package/build/src/rules/prefer_returning_to_exporting.js +1 -1
  58. package/build/src/rules/prefer_xsdbool.js +2 -2
  59. package/build/src/rules/remove_descriptions.js +4 -4
  60. package/build/src/rules/rfc_error_handling.js +9 -9
  61. package/build/src/rules/select_add_order_by.js +5 -5
  62. package/build/src/rules/select_performance.js +2 -2
  63. package/build/src/rules/sicf_consistency.js +4 -4
  64. package/build/src/rules/space_before_dot.js +2 -2
  65. package/build/src/rules/start_at_tab.js +1 -1
  66. package/build/src/rules/sy_modification.js +2 -2
  67. package/build/src/rules/tabl_enhancement_category.js +2 -2
  68. package/build/src/rules/unused_methods.js +9 -9
  69. package/build/src/rules/unused_variables.js +6 -6
  70. package/build/src/rules/use_bool_expression.js +8 -8
  71. package/build/src/rules/use_line_exists.js +6 -6
  72. package/build/src/rules/use_new.js +2 -2
  73. package/build/src/rules/when_others_last.js +6 -6
  74. package/package.json +76 -76
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
- # @abaplint/core
2
-
3
- [abaplint](https://abaplint.org/) core library
4
-
5
- Exposes functionallity like the parser and rules, which can be used in other projects.
6
-
1
+ # @abaplint/core
2
+
3
+ [abaplint](https://abaplint.org/) core library
4
+
5
+ Exposes functionallity like the parser and rules, which can be used in other projects.
6
+
7
7
  For more information see https://github.com/abaplint/abaplint
@@ -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,211 +1,184 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.StatementFlow = exports.dumpFlows = exports.dumpFlowsWithDescription = 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
7
  const Expressions = require("../2_statements/expressions");
8
- function dumpFlowsWithDescription(flows) {
9
- let ret = "";
10
- for (const f of flows) {
11
- ret += f.description + ": [" + f.statements.map(b => b === null || b === void 0 ? void 0 : b.get().constructor.name).join(",") + "]\n";
12
- }
13
- return ret.trim();
14
- }
15
- exports.dumpFlowsWithDescription = dumpFlowsWithDescription;
16
- function dumpFlows(flows) {
17
- const ret = "[" + flows.map(f => "[" + f.statements.map(b => b === null || b === void 0 ? void 0 : b.get().constructor.name).join(",") + "]").join(",");
18
- return ret + "]";
19
- }
20
- exports.dumpFlows = dumpFlows;
21
- function findBody(f) {
22
- var _a;
23
- return ((_a = f.findDirectStructure(Structures.Body)) === null || _a === void 0 ? void 0 : _a.getChildren()) || [];
24
- }
25
- function removeDuplicates(flows) {
26
- const result = [];
27
- for (const f of flows) {
28
- let duplicate = false;
29
- for (const r of result) {
30
- if (f.statements.length !== r.statements.length) {
31
- continue;
32
- }
33
- duplicate = true;
34
- for (let index = 0; index < f.statements.length; index++) {
35
- if (f.statements[index] !== r.statements[index]) {
36
- duplicate = false;
37
- break;
38
- }
39
- }
40
- }
41
- if (duplicate === false) {
42
- result.push(f);
43
- }
44
- }
45
- return result;
46
- }
47
- function pruneByStatement(flows, type) {
48
- const result = [];
49
- for (const f of flows) {
50
- const nodes = [];
51
- for (const n of f.statements) {
52
- nodes.push(n);
53
- if (n.get() instanceof type) {
54
- break;
55
- }
56
- }
57
- result.push({ statements: nodes });
58
- }
59
- return removeDuplicates(result);
60
- }
61
- ////////////////////////////////////////////////////////////////
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
62
23
  class StatementFlow {
24
+ constructor() {
25
+ this.counter = 0;
26
+ }
63
27
  build(stru) {
64
28
  var _a, _b;
65
29
  const ret = [];
66
30
  const forms = stru.findAllStructures(Structures.Form);
67
31
  for (const f of forms) {
68
- let body = this.traverseBody(findBody(f));
69
- const formName = (_a = f.findFirstExpression(Expressions.FormName)) === null || _a === void 0 ? void 0 : _a.concatTokens();
70
- body = body.map((b) => { return { description: "FORM " + formName, statements: b.statements }; });
71
- ret.push(...body);
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);
72
37
  }
73
38
  const methods = stru.findAllStructures(Structures.Method);
74
39
  for (const f of methods) {
75
- let body = this.traverseBody(findBody(f));
76
- const methodName = (_b = f.findFirstExpression(Expressions.MethodName)) === null || _b === void 0 ? void 0 : _b.concatTokens();
77
- body = body.map((b) => { return { description: "METHOD " + methodName, statements: b.statements }; });
78
- ret.push(...body);
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);
79
45
  }
80
- return ret;
46
+ return ret.map(f => f.reduce());
81
47
  }
82
- traverseBody(children) {
83
- let flows = [{ statements: [] }];
48
+ findBody(f) {
49
+ var _a;
50
+ return ((_a = f.findDirectStructure(Structures.Body)) === null || _a === void 0 ? void 0 : _a.getChildren()) || [];
51
+ }
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++);
84
60
  if (children.length === 0) {
85
- return [];
61
+ graph.addEdge(graph.getStart(), graph.getEnd());
62
+ return graph;
86
63
  }
87
- for (let i = 0; i < children.length; i++) {
88
- const c = children[i];
89
- // console.dir(c);
64
+ let current = graph.getStart();
65
+ for (const c of children) {
90
66
  if (c.get() instanceof Structures.Normal) {
91
67
  const firstChild = c.getFirstChild(); // "Normal" only has one child
92
68
  if (firstChild instanceof nodes_1.StatementNode) {
93
- flows.forEach(f => f.statements.push(firstChild));
94
- // current.push(firstChild);
95
- // console.dir("push: " + firstChild.constructor.name);
96
- if (firstChild.get() instanceof Statements.Check
97
- || firstChild.get() instanceof Statements.Assert) {
98
- const after = children.slice(i + 1, children.length);
99
- for (const b of this.traverseBody(after)) {
100
- for (const f of [...flows]) {
101
- flows.push({ statements: [...f.statements, ...b.statements] });
102
- }
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);
103
75
  }
104
- break;
76
+ else {
77
+ graph.addEdge(name, procedureEnd);
78
+ }
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;
105
86
  }
106
87
  else if (firstChild.get() instanceof Statements.Exit) {
107
- 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;
108
96
  }
109
97
  else if (firstChild.get() instanceof Statements.Return) {
110
- break;
98
+ graph.addEdge(name, procedureEnd);
99
+ return graph;
111
100
  }
112
101
  }
113
102
  else if (firstChild instanceof nodes_1.StructureNode) {
114
- // console.dir("firstch: " + firstChild.get().constructor.name);
115
- const found = this.traverseStructure(firstChild);
116
- // console.dir("found: " + dump(found));
117
- const n = [];
118
- for (const existing of flows) {
119
- for (const fo of found) {
120
- const add = { statements: [...existing.statements, ...fo.statements] };
121
- n.push(add);
122
- }
123
- }
124
- // console.dir(dump(n));
125
- flows = n;
103
+ const sub = this.traverseStructure(firstChild, procedureEnd, loopStart);
104
+ current = graph.addGraph(current, sub);
126
105
  }
127
106
  }
128
107
  }
129
- return flows;
108
+ graph.addEdge(current, graph.getEnd());
109
+ return graph;
130
110
  }
131
- traverseStructure(n) {
132
- let flows = [];
111
+ traverseStructure(n, procedureEnd, loopStart) {
112
+ const graph = new flow_graph_1.FlowGraph(this.counter++);
133
113
  if (n === undefined) {
134
- return flows;
114
+ return graph;
135
115
  }
116
+ let current = graph.getStart();
136
117
  const type = n.get();
137
- if (type instanceof Structures.Form) {
138
- const formst = n.findDirectStatement(Statements.Form);
139
- let bodyFlows = this.traverseBody(findBody(n));
140
- // console.dir(bodyFlows);
141
- bodyFlows = bodyFlows.map(a => { return { statements: [formst, ...a.statements] }; });
142
- flows.push(...bodyFlows);
143
- }
144
- else if (type instanceof Structures.Any) {
145
- for (const c of n.getChildren()) {
146
- // console.dir("yep");
147
- if (c instanceof nodes_1.StructureNode && c.get() instanceof Structures.Form) {
148
- flows.push(...this.traverseStructure(c));
149
- }
150
- else if (c instanceof nodes_1.StructureNode && c.get() instanceof Structures.If) {
151
- flows.push(...this.traverseStructure(c));
152
- }
153
- else {
154
- console.dir("any, todo, " + c.constructor.name + ", " + c.get().constructor.name);
155
- }
156
- }
157
- }
158
- else if (type instanceof Structures.Try) {
159
- // TODO: this does not take exceptions into account
160
- const firstTry = n.getFirstStatement();
161
- let allPossibleBody = this.traverseBody(findBody(n));
162
- allPossibleBody = allPossibleBody.map(b => { return { statements: [firstTry, ...b.statements] }; });
163
- if (allPossibleBody.length === 0) {
164
- allPossibleBody.push({ statements: [firstTry] });
165
- }
166
- flows.push(...allPossibleBody);
167
- for (const c of n.findDirectStructures(Structures.Catch)) {
168
- const firstCatch = c.getFirstStatement();
169
- const catchBodies = this.traverseBody(findBody(c));
170
- for (const bodyFlow of allPossibleBody) {
171
- for (const catchFlow of catchBodies) {
172
- flows.push({ statements: [...bodyFlow.statements, firstCatch, ...catchFlow.statements] });
173
- }
174
- if (catchBodies.length === 0) {
175
- flows.push({ statements: [...bodyFlow.statements, firstCatch] });
176
- }
177
- }
178
- }
179
- // TODO, handle CLEANUP
180
- }
181
- else if (type instanceof Structures.If) {
182
- const collect = [n.findDirectStatement(Statements.If)];
183
- let bodyFlows = this.traverseBody(findBody(n));
184
- bodyFlows = bodyFlows.map(b => { return { statements: [...collect, ...b.statements] }; });
185
- 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;
186
125
  for (const e of n.findDirectStructures(Structures.ElseIf)) {
187
126
  const elseifst = e.findDirectStatement(Statements.ElseIf);
188
127
  if (elseifst === undefined) {
189
128
  continue;
190
129
  }
191
- collect.push(elseifst);
192
- let bodyFlows = this.traverseBody(findBody(e));
193
- bodyFlows = bodyFlows.map(b => { return { statements: [...collect, ...b.statements] }; });
194
- 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;
195
136
  }
196
137
  const els = n.findDirectStructure(Structures.Else);
197
138
  const elsest = els === null || els === void 0 ? void 0 : els.findDirectStatement(Statements.Else);
198
139
  if (els && elsest) {
199
- let bodyFlows = this.traverseBody(findBody(els));
200
- bodyFlows = bodyFlows.map(b => { return { statements: [...collect, elsest, ...b.statements] }; });
201
- 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());
202
145
  }
203
146
  else {
204
- flows.push({ statements: [...collect] });
147
+ graph.addEdge(ifName, graph.getEnd());
205
148
  }
206
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());
176
+ }
177
+ // TODO, handle CLEANUP
178
+ }
207
179
  else if (type instanceof Structures.Case) {
208
- const cas = n.getFirstStatement();
180
+ const caseName = this.buildName(n.getFirstStatement());
181
+ graph.addEdge(current, caseName);
209
182
  let othersFound = false;
210
183
  for (const w of n.findDirectStructures(Structures.When)) {
211
184
  const first = w.getFirstStatement();
@@ -215,16 +188,19 @@ class StatementFlow {
215
188
  if (first.get() instanceof Statements.WhenOthers) {
216
189
  othersFound = true;
217
190
  }
218
- let bodyFlows = this.traverseBody(findBody(w));
219
- bodyFlows = bodyFlows.map(b => { return { statements: [cas, first, ...b.statements] }; });
220
- 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());
221
196
  }
222
197
  if (othersFound === false) {
223
- flows.push({ statements: [cas] });
198
+ graph.addEdge(caseName, graph.getEnd());
224
199
  }
225
200
  }
226
201
  else if (type instanceof Structures.CaseType) {
227
- const cas = n.getFirstStatement();
202
+ const caseName = this.buildName(n.getFirstStatement());
203
+ graph.addEdge(current, caseName);
228
204
  let othersFound = false;
229
205
  for (const w of n.findDirectStructures(Structures.WhenType)) {
230
206
  const first = w.getFirstStatement();
@@ -234,40 +210,20 @@ class StatementFlow {
234
210
  if (first.get() instanceof Statements.WhenOthers) {
235
211
  othersFound = true;
236
212
  }
237
- let bodyFlows = this.traverseBody(findBody(w));
238
- bodyFlows = bodyFlows.map(b => { return { statements: [cas, first, ...b.statements] }; });
239
- 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());
240
218
  }
241
219
  if (othersFound === false) {
242
- flows.push({ statements: [cas] });
243
- }
244
- }
245
- else if (type instanceof Structures.Loop
246
- || type instanceof Structures.While
247
- || type instanceof Structures.With
248
- || type instanceof Structures.Provide
249
- || type instanceof Structures.Select
250
- || type instanceof Structures.Do) {
251
- const loop = n.getFirstStatement();
252
- const bodyFlows = this.traverseBody(findBody(n));
253
- for (const b of bodyFlows) {
254
- flows.push({ statements: [loop, ...b.statements] });
255
- }
256
- for (const b1 of bodyFlows) {
257
- for (const b2 of bodyFlows) {
258
- const add = [loop, ...b1.statements, ...b2.statements];
259
- flows.push({ statements: add });
260
- }
220
+ graph.addEdge(caseName, graph.getEnd());
261
221
  }
262
- flows.push({ statements: [loop] });
263
- flows = pruneByStatement(flows, Statements.Exit);
264
- flows = pruneByStatement(flows, Statements.Continue);
265
- flows = pruneByStatement(flows, Statements.Return);
266
222
  }
267
223
  else {
268
224
  console.dir("todo, " + n.get().constructor.name);
269
225
  }
270
- return flows;
226
+ return graph;
271
227
  }
272
228
  }
273
229
  exports.StatementFlow = StatementFlow;
@@ -9,13 +9,13 @@ const dump_scope_1 = require("./dump_scope");
9
9
  class Help {
10
10
  static find(reg, textDocument, position) {
11
11
  let content = "";
12
- content = `
13
- <a href="#_tokens" rel="no-refresh">Tokens</a> |
14
- <a href="#_statements" rel="no-refresh">Statements</a> |
15
- <a href="#_structure" rel="no-refresh">Structure</a> |
16
- <a href="#_files" rel="no-refresh">Files</a> |
17
- <a href="#_info" rel="no-refresh">Info Dump</a>
18
- <hr>
12
+ content = `
13
+ <a href="#_tokens" rel="no-refresh">Tokens</a> |
14
+ <a href="#_statements" rel="no-refresh">Statements</a> |
15
+ <a href="#_structure" rel="no-refresh">Structure</a> |
16
+ <a href="#_files" rel="no-refresh">Files</a> |
17
+ <a href="#_info" rel="no-refresh">Info Dump</a>
18
+ <hr>
19
19
  ` +
20
20
  "<tt>" + textDocument.uri + " (" +
21
21
  (position.line + 1) + ", " +
@@ -121,7 +121,9 @@ class LanguageServer {
121
121
  if (stru === undefined) {
122
122
  return "empty structure";
123
123
  }
124
- return (0, statement_flow_1.dumpFlowsWithDescription)(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.4";
71
+ return "2.80.5";
72
72
  }
73
73
  getDDICReferences() {
74
74
  return this.references;
@@ -23,7 +23,7 @@ class Abapdoc extends _abap_rule_1.ABAPRule {
23
23
  return {
24
24
  key: "abapdoc",
25
25
  title: "Check abapdoc",
26
- shortDescription: `Various checks regarding abapdoc.
26
+ shortDescription: `Various checks regarding abapdoc.
27
27
  Base rule checks for existence of abapdoc for public class methods and all interface methods.`,
28
28
  tags: [_irule_1.RuleTag.SingleFile],
29
29
  };