@abaplint/core 2.80.4 → 2.80.8
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/5_syntax/statements/delete_report.js +14 -0
- package/build/src/abap/5_syntax/statements/get_cursor.js +14 -0
- package/build/src/abap/5_syntax/statements/insert_textpool.js +14 -0
- package/build/src/abap/5_syntax/syntax.js +6 -0
- package/build/src/abap/flow/flow_graph.js +134 -0
- package/build/src/abap/flow/statement_flow.js +146 -190
- package/build/src/lsp/language_server.js +3 -1
- package/build/src/lsp/references.js +6 -5
- package/build/src/registry.js +1 -1
- package/build/src/rules/unused_types.js +23 -18
- package/build/src/rules/unused_variables.js +107 -60
- package/package.json +9 -20
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeleteReport = void 0;
|
|
4
|
+
const Expressions = require("../../2_statements/expressions");
|
|
5
|
+
const source_1 = require("../expressions/source");
|
|
6
|
+
class DeleteReport {
|
|
7
|
+
runSyntax(node, scope, filename) {
|
|
8
|
+
for (const s of node.findDirectExpressions(Expressions.Source)) {
|
|
9
|
+
new source_1.Source().runSyntax(s, scope, filename);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.DeleteReport = DeleteReport;
|
|
14
|
+
//# sourceMappingURL=delete_report.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetCursor = void 0;
|
|
4
|
+
const Expressions = require("../../2_statements/expressions");
|
|
5
|
+
const target_1 = require("../expressions/target");
|
|
6
|
+
class GetCursor {
|
|
7
|
+
runSyntax(node, scope, filename) {
|
|
8
|
+
for (const t of node.findAllExpressions(Expressions.Target)) {
|
|
9
|
+
new target_1.Target().runSyntax(t, scope, filename);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.GetCursor = GetCursor;
|
|
14
|
+
//# sourceMappingURL=get_cursor.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InsertTextpool = void 0;
|
|
4
|
+
const Expressions = require("../../2_statements/expressions");
|
|
5
|
+
const source_1 = require("../expressions/source");
|
|
6
|
+
class InsertTextpool {
|
|
7
|
+
runSyntax(node, scope, filename) {
|
|
8
|
+
for (const s of node.findDirectExpressions(Expressions.Source)) {
|
|
9
|
+
new source_1.Source().runSyntax(s, scope, filename);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.InsertTextpool = InsertTextpool;
|
|
14
|
+
//# sourceMappingURL=insert_textpool.js.map
|
|
@@ -122,11 +122,14 @@ const set_titlebar_1 = require("./statements/set_titlebar");
|
|
|
122
122
|
const call_transaction_1 = require("./statements/call_transaction");
|
|
123
123
|
const set_handler_1 = require("./statements/set_handler");
|
|
124
124
|
const wait_1 = require("./statements/wait");
|
|
125
|
+
const delete_report_1 = require("./statements/delete_report");
|
|
125
126
|
const shift_1 = require("./statements/shift");
|
|
126
127
|
const set_bit_1 = require("./statements/set_bit");
|
|
127
128
|
const modify_screen_1 = require("./statements/modify_screen");
|
|
128
129
|
const delete_cluster_1 = require("./statements/delete_cluster");
|
|
129
130
|
const unassign_1 = require("./statements/unassign");
|
|
131
|
+
const insert_textpool_1 = require("./statements/insert_textpool");
|
|
132
|
+
const get_cursor_1 = require("./statements/get_cursor");
|
|
130
133
|
// -----------------------------------
|
|
131
134
|
const map = {};
|
|
132
135
|
function addToMap(handler) {
|
|
@@ -146,6 +149,7 @@ if (Object.keys(map).length === 0) {
|
|
|
146
149
|
addToMap(new move_1.Move());
|
|
147
150
|
addToMap(new get_badi_1.GetBadi());
|
|
148
151
|
addToMap(new call_badi_1.CallBadi());
|
|
152
|
+
addToMap(new get_cursor_1.GetCursor());
|
|
149
153
|
addToMap(new replace_1.Replace());
|
|
150
154
|
addToMap(new truncate_dataset_1.TruncateDataset());
|
|
151
155
|
addToMap(new assert_1.Assert());
|
|
@@ -154,8 +158,10 @@ if (Object.keys(map).length === 0) {
|
|
|
154
158
|
addToMap(new set_pf_status_1.SetPFStatus());
|
|
155
159
|
addToMap(new set_titlebar_1.SetTitlebar());
|
|
156
160
|
addToMap(new submit_1.Submit());
|
|
161
|
+
addToMap(new insert_textpool_1.InsertTextpool());
|
|
157
162
|
addToMap(new read_table_1.ReadTable());
|
|
158
163
|
addToMap(new syntax_check_1.SyntaxCheck());
|
|
164
|
+
addToMap(new delete_report_1.DeleteReport());
|
|
159
165
|
addToMap(new import_1.Import());
|
|
160
166
|
addToMap(new collect_1.Collect());
|
|
161
167
|
addToMap(new export_1.Export());
|
|
@@ -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", shape="box"];
|
|
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 =
|
|
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
|
-
|
|
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");
|
|
62
9
|
class StatementFlow {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.counter = 0;
|
|
12
|
+
}
|
|
63
13
|
build(stru) {
|
|
64
14
|
var _a, _b;
|
|
65
15
|
const ret = [];
|
|
66
16
|
const forms = stru.findAllStructures(Structures.Form);
|
|
67
17
|
for (const f of forms) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
18
|
+
const formName = "FORM " + ((_a = f.findFirstExpression(Expressions.FormName)) === null || _a === void 0 ? void 0 : _a.concatTokens());
|
|
19
|
+
this.counter = 1;
|
|
20
|
+
const graph = this.traverseBody(this.findBody(f), { procedureEnd: "end#1" });
|
|
21
|
+
graph.setLabel(formName);
|
|
22
|
+
ret.push(graph);
|
|
72
23
|
}
|
|
73
24
|
const methods = stru.findAllStructures(Structures.Method);
|
|
74
25
|
for (const f of methods) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
26
|
+
const methodName = "METHOD " + ((_b = f.findFirstExpression(Expressions.MethodName)) === null || _b === void 0 ? void 0 : _b.concatTokens());
|
|
27
|
+
this.counter = 1;
|
|
28
|
+
const graph = this.traverseBody(this.findBody(f), { procedureEnd: "end#1" });
|
|
29
|
+
graph.setLabel(methodName);
|
|
30
|
+
ret.push(graph);
|
|
79
31
|
}
|
|
80
|
-
return ret;
|
|
32
|
+
return ret.map(f => f.reduce());
|
|
33
|
+
}
|
|
34
|
+
findBody(f) {
|
|
35
|
+
var _a;
|
|
36
|
+
return ((_a = f.findDirectStructure(Structures.Body)) === null || _a === void 0 ? void 0 : _a.getChildren()) || [];
|
|
81
37
|
}
|
|
82
|
-
|
|
83
|
-
let
|
|
38
|
+
buildName(statement) {
|
|
39
|
+
let token = undefined;
|
|
40
|
+
const colon = statement.getColon();
|
|
41
|
+
if (colon === undefined) {
|
|
42
|
+
token = statement.getFirstToken();
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
for (const t of statement.getTokens()) {
|
|
46
|
+
if (t.getStart().isAfter(colon.getEnd())) {
|
|
47
|
+
token = t;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (token === undefined) {
|
|
53
|
+
return "tokenError";
|
|
54
|
+
}
|
|
55
|
+
return statement.get().constructor.name +
|
|
56
|
+
":" + token.getRow() +
|
|
57
|
+
"," + token.getCol();
|
|
58
|
+
}
|
|
59
|
+
traverseBody(children, context) {
|
|
60
|
+
const graph = new flow_graph_1.FlowGraph(this.counter++);
|
|
84
61
|
if (children.length === 0) {
|
|
85
|
-
|
|
62
|
+
graph.addEdge(graph.getStart(), graph.getEnd());
|
|
63
|
+
return graph;
|
|
86
64
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// console.dir(c);
|
|
65
|
+
let current = graph.getStart();
|
|
66
|
+
for (const c of children) {
|
|
90
67
|
if (c.get() instanceof Structures.Normal) {
|
|
91
68
|
const firstChild = c.getFirstChild(); // "Normal" only has one child
|
|
92
69
|
if (firstChild instanceof nodes_1.StatementNode) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (firstChild.get() instanceof Statements.Check
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
70
|
+
const name = this.buildName(firstChild);
|
|
71
|
+
graph.addEdge(current, name);
|
|
72
|
+
current = name;
|
|
73
|
+
if (firstChild.get() instanceof Statements.Check) {
|
|
74
|
+
if (context.loopStart) {
|
|
75
|
+
graph.addEdge(name, context.loopStart);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
graph.addEdge(name, context.procedureEnd);
|
|
103
79
|
}
|
|
104
|
-
|
|
80
|
+
}
|
|
81
|
+
else if (firstChild.get() instanceof Statements.Assert) {
|
|
82
|
+
graph.addEdge(name, context.procedureEnd);
|
|
83
|
+
}
|
|
84
|
+
else if (firstChild.get() instanceof Statements.Continue && context.loopStart) {
|
|
85
|
+
graph.addEdge(name, context.loopStart);
|
|
86
|
+
return graph;
|
|
105
87
|
}
|
|
106
88
|
else if (firstChild.get() instanceof Statements.Exit) {
|
|
107
|
-
|
|
89
|
+
if (context.loopEnd) {
|
|
90
|
+
graph.addEdge(name, context.loopEnd);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
graph.addEdge(name, context.procedureEnd);
|
|
94
|
+
}
|
|
95
|
+
return graph;
|
|
108
96
|
}
|
|
109
97
|
else if (firstChild.get() instanceof Statements.Return) {
|
|
110
|
-
|
|
98
|
+
graph.addEdge(name, context.procedureEnd);
|
|
99
|
+
return graph;
|
|
111
100
|
}
|
|
112
101
|
}
|
|
113
102
|
else if (firstChild instanceof nodes_1.StructureNode) {
|
|
114
|
-
|
|
115
|
-
|
|
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, context);
|
|
104
|
+
current = graph.addGraph(current, sub);
|
|
126
105
|
}
|
|
127
106
|
}
|
|
128
107
|
}
|
|
129
|
-
|
|
108
|
+
graph.addEdge(current, graph.getEnd());
|
|
109
|
+
return graph;
|
|
130
110
|
}
|
|
131
|
-
traverseStructure(n) {
|
|
132
|
-
|
|
111
|
+
traverseStructure(n, context) {
|
|
112
|
+
const graph = new flow_graph_1.FlowGraph(this.counter++);
|
|
133
113
|
if (n === undefined) {
|
|
134
|
-
return
|
|
114
|
+
return graph;
|
|
135
115
|
}
|
|
116
|
+
let current = graph.getStart();
|
|
136
117
|
const type = n.get();
|
|
137
|
-
if (type instanceof Structures.
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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), context);
|
|
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
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
130
|
+
const elseIfName = this.buildName(elseifst);
|
|
131
|
+
const sub = this.traverseBody(this.findBody(e), context);
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
140
|
+
const elseName = this.buildName(elsest);
|
|
141
|
+
const sub = this.traverseBody(this.findBody(els), context);
|
|
142
|
+
graph.addEdge(current, elseName);
|
|
143
|
+
graph.addGraph(elseName, sub);
|
|
144
|
+
graph.addEdge(sub.getEnd(), graph.getEnd());
|
|
202
145
|
}
|
|
203
146
|
else {
|
|
204
|
-
|
|
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), Object.assign(Object.assign({}, context), { loopStart: loopName, loopEnd: graph.getEnd() }));
|
|
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), context);
|
|
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), context);
|
|
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
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
191
|
+
const firstName = this.buildName(first);
|
|
192
|
+
const sub = this.traverseBody(this.findBody(w), context);
|
|
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
|
-
|
|
198
|
+
graph.addEdge(caseName, graph.getEnd());
|
|
224
199
|
}
|
|
225
200
|
}
|
|
226
201
|
else if (type instanceof Structures.CaseType) {
|
|
227
|
-
const
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
213
|
+
const firstName = this.buildName(first);
|
|
214
|
+
const sub = this.traverseBody(this.findBody(w), context);
|
|
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
|
-
|
|
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
|
-
console.dir("todo, " + n.get().constructor.name);
|
|
224
|
+
console.dir("StatementFlow,todo, " + n.get().constructor.name);
|
|
269
225
|
}
|
|
270
|
-
return
|
|
226
|
+
return graph;
|
|
271
227
|
}
|
|
272
228
|
}
|
|
273
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;
|
|
@@ -30,12 +30,12 @@ class References {
|
|
|
30
30
|
const locs = this.search(lookup.definitionId, lookup.scope);
|
|
31
31
|
return locs.map(_lsp_utils_1.LSPUtils.identiferToLocation);
|
|
32
32
|
}
|
|
33
|
+
// todo, cleanup this mehtod, some of the method parameters are not used anymore?
|
|
33
34
|
search(identifier, node, exitAfterFound = false, removeDuplicates = true) {
|
|
34
35
|
let ret = [];
|
|
35
36
|
// todo, this first assumes that the identifier is a variable?
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|| node.getIdentifier().stype === _scope_type_1.ScopeType.Form) {
|
|
37
|
+
const stype = node.getIdentifier().stype;
|
|
38
|
+
if (stype === _scope_type_1.ScopeType.Method || stype === _scope_type_1.ScopeType.FunctionModule || stype === _scope_type_1.ScopeType.Form) {
|
|
39
39
|
ret = this.findReferences(node, identifier);
|
|
40
40
|
}
|
|
41
41
|
if (ret.length > 1 && exitAfterFound === true) {
|
|
@@ -71,15 +71,16 @@ class References {
|
|
|
71
71
|
var _a;
|
|
72
72
|
const ret = [];
|
|
73
73
|
if (node.getIdentifier().stype !== _scope_type_1.ScopeType.BuiltIn) {
|
|
74
|
+
const upper = identifier.getName().toUpperCase();
|
|
74
75
|
// this is for finding the definitions
|
|
75
76
|
const vars = node.getData().vars;
|
|
76
|
-
const vid = vars[
|
|
77
|
+
const vid = vars[upper];
|
|
77
78
|
if (vid === null || vid === void 0 ? void 0 : vid.equals(identifier)) {
|
|
78
79
|
ret.push(vid);
|
|
79
80
|
}
|
|
80
81
|
// this is for finding the definitions
|
|
81
82
|
const types = node.getData().types;
|
|
82
|
-
const tid = types[
|
|
83
|
+
const tid = types[upper];
|
|
83
84
|
if (tid === null || tid === void 0 ? void 0 : tid.equals(identifier)) {
|
|
84
85
|
ret.push(tid);
|
|
85
86
|
}
|
package/build/src/registry.js
CHANGED
|
@@ -36,23 +36,25 @@ class WorkArea {
|
|
|
36
36
|
return this.workarea.length;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
39
|
+
/*
|
|
40
|
+
function removeDuplicates(list: readonly TypedIdentifier[]): readonly TypedIdentifier[] {
|
|
41
|
+
const deduplicated: TypedIdentifier[] = [];
|
|
42
|
+
for (const result of list) {
|
|
43
|
+
let cont = false;
|
|
44
|
+
for (const d of deduplicated) {
|
|
45
|
+
if (result.getStart().equals(d.getStart())) {
|
|
46
|
+
cont = true;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (cont === true) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
deduplicated.push(result);
|
|
54
|
+
}
|
|
55
|
+
return deduplicated;
|
|
55
56
|
}
|
|
57
|
+
*/
|
|
56
58
|
class UnusedTypesConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
57
59
|
constructor() {
|
|
58
60
|
super(...arguments);
|
|
@@ -103,7 +105,10 @@ class UnusedTypes {
|
|
|
103
105
|
return []; // exit early if all types are used in the current object
|
|
104
106
|
}
|
|
105
107
|
for (const o of this.reg.getObjects()) {
|
|
106
|
-
if (o
|
|
108
|
+
if (o === obj) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
else if (o instanceof _abap_object_1.ABAPObject) {
|
|
107
112
|
if (this.reg.isDependency(o)) {
|
|
108
113
|
continue; // do not search in dependencies
|
|
109
114
|
}
|
|
@@ -116,7 +121,7 @@ class UnusedTypes {
|
|
|
116
121
|
}
|
|
117
122
|
// what is left is unused
|
|
118
123
|
const ret = [];
|
|
119
|
-
for (const t of
|
|
124
|
+
for (const t of this.workarea.get()) {
|
|
120
125
|
const message = "Type \"" + t.getName() + "\" not used";
|
|
121
126
|
const file = obj.getABAPFileByName(t.getFilename());
|
|
122
127
|
if (file === undefined) {
|
|
@@ -8,10 +8,10 @@ const syntax_1 = require("../abap/5_syntax/syntax");
|
|
|
8
8
|
const _abap_object_1 = require("../objects/_abap_object");
|
|
9
9
|
const _scope_type_1 = require("../abap/5_syntax/_scope_type");
|
|
10
10
|
const objects_1 = require("../objects");
|
|
11
|
-
const references_1 = require("../lsp/references");
|
|
12
11
|
const edit_helper_1 = require("../edit_helper");
|
|
13
12
|
const Statements = require("../abap/2_statements/statements");
|
|
14
13
|
const _statement_1 = require("../abap/2_statements/statements/_statement");
|
|
14
|
+
const _reference_1 = require("../abap/5_syntax/_reference");
|
|
15
15
|
class UnusedVariablesConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
16
16
|
constructor() {
|
|
17
17
|
super(...arguments);
|
|
@@ -22,6 +22,39 @@ class UnusedVariablesConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
exports.UnusedVariablesConf = UnusedVariablesConf;
|
|
25
|
+
class WorkArea {
|
|
26
|
+
constructor() {
|
|
27
|
+
this.workarea = [];
|
|
28
|
+
}
|
|
29
|
+
push(id, count = 1) {
|
|
30
|
+
for (const w of this.workarea) {
|
|
31
|
+
if (id.equals(w.id)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
this.workarea.push({ id, count });
|
|
36
|
+
}
|
|
37
|
+
removeIfExists(id) {
|
|
38
|
+
if (id === undefined) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
for (let i = 0; i < this.workarea.length; i++) {
|
|
42
|
+
if (id.equals(this.workarea[i].id)) {
|
|
43
|
+
this.workarea[i].count--;
|
|
44
|
+
if (this.workarea[i].count === 0) {
|
|
45
|
+
this.workarea.splice(i, 1);
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
get() {
|
|
52
|
+
return this.workarea;
|
|
53
|
+
}
|
|
54
|
+
count() {
|
|
55
|
+
return this.workarea.length;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
25
58
|
class UnusedVariables {
|
|
26
59
|
constructor() {
|
|
27
60
|
this.conf = new UnusedVariablesConf();
|
|
@@ -33,11 +66,11 @@ class UnusedVariables {
|
|
|
33
66
|
shortDescription: `Checks for unused variables and constants`,
|
|
34
67
|
extendedInformation: `WARNING: slow
|
|
35
68
|
|
|
36
|
-
|
|
69
|
+
Experimental, might give false positives. Skips event parameters.
|
|
37
70
|
|
|
38
|
-
|
|
71
|
+
Note that this currently does not work if the source code uses macros.
|
|
39
72
|
|
|
40
|
-
|
|
73
|
+
Unused variables are not reported if the object contains syntax errors. Errors found in INCLUDES are reported for the main program.`,
|
|
41
74
|
tags: [_irule_1.RuleTag.Quickfix],
|
|
42
75
|
pragma: "##NEEDED",
|
|
43
76
|
pseudoComment: "EC NEEDED",
|
|
@@ -68,67 +101,91 @@ class UnusedVariables {
|
|
|
68
101
|
if (syntax.issues.length > 0) {
|
|
69
102
|
return [];
|
|
70
103
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
if (cont === true) {
|
|
104
|
+
this.workarea = new WorkArea();
|
|
105
|
+
const top = syntax.spaghetti.getTop();
|
|
106
|
+
this.buildWorkarea(top, obj);
|
|
107
|
+
if (this.workarea.count() === 0) {
|
|
108
|
+
return this.buildIssues(obj); // exit early if all types are used
|
|
109
|
+
}
|
|
110
|
+
this.findUses(top, obj);
|
|
111
|
+
for (const o of this.reg.getObjects()) {
|
|
112
|
+
if (o === obj) {
|
|
83
113
|
continue;
|
|
84
114
|
}
|
|
85
|
-
|
|
115
|
+
else if (o instanceof _abap_object_1.ABAPObject) {
|
|
116
|
+
if (this.reg.isDependency(o)) {
|
|
117
|
+
continue; // do not search in dependencies
|
|
118
|
+
}
|
|
119
|
+
const syntax = new syntax_1.SyntaxLogic(this.reg, o).run();
|
|
120
|
+
this.findUses(syntax.spaghetti.getTop(), o);
|
|
121
|
+
if (this.workarea.count() === 0) {
|
|
122
|
+
return this.buildIssues(obj); // exit early if all types are used
|
|
123
|
+
}
|
|
124
|
+
}
|
|
86
125
|
}
|
|
87
|
-
return
|
|
126
|
+
return this.buildIssues(obj);
|
|
88
127
|
}
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
128
|
+
findUses(node, obj) {
|
|
129
|
+
for (const r of node.getData().references) {
|
|
130
|
+
if (r.referenceType === _reference_1.ReferenceType.DataReadReference
|
|
131
|
+
|| r.referenceType === _reference_1.ReferenceType.DataWriteReference
|
|
132
|
+
|| r.referenceType === _reference_1.ReferenceType.TypeReference) {
|
|
133
|
+
this.workarea.removeIfExists(r.resolved);
|
|
134
|
+
}
|
|
96
135
|
}
|
|
97
136
|
for (const c of node.getChildren()) {
|
|
98
|
-
|
|
137
|
+
this.findUses(c, obj);
|
|
99
138
|
}
|
|
100
|
-
return ret;
|
|
101
139
|
}
|
|
102
|
-
|
|
140
|
+
buildWorkarea(node, obj) {
|
|
103
141
|
var _a;
|
|
142
|
+
const stype = node.getIdentifier().stype;
|
|
143
|
+
if (stype === _scope_type_1.ScopeType.OpenSQL) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
for (const c of node.getChildren()) {
|
|
147
|
+
this.buildWorkarea(c, obj);
|
|
148
|
+
}
|
|
149
|
+
if (stype !== _scope_type_1.ScopeType.BuiltIn) {
|
|
150
|
+
const vars = node.getData().vars;
|
|
151
|
+
for (const name in vars) {
|
|
152
|
+
const meta = vars[name].getMeta();
|
|
153
|
+
if (((_a = this.conf.skipNames) === null || _a === void 0 ? void 0 : _a.length) > 0
|
|
154
|
+
&& this.conf.skipNames.some((a) => a.toUpperCase() === name)) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
else if (name === "ME"
|
|
158
|
+
|| name === "SUPER"
|
|
159
|
+
|| meta.includes("event_parameter" /* EventParameter */)) {
|
|
160
|
+
// todo, workaround for "me" and "super", these should somehow be typed to built-in
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const isInline = meta.includes("inline" /* InlineDefinition */);
|
|
164
|
+
this.workarea.push(vars[name], isInline ? 2 : 1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
buildIssues(obj) {
|
|
104
169
|
const ret = [];
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
&& this.conf.skipNames.some((a) => a.toUpperCase() === name)) {
|
|
170
|
+
for (const w of this.workarea.get()) {
|
|
171
|
+
const filename = w.id.getFilename();
|
|
172
|
+
if (this.reg.isFileDependency(filename) === true) {
|
|
109
173
|
continue;
|
|
110
174
|
}
|
|
111
|
-
if (
|
|
112
|
-
|| name === "SUPER"
|
|
113
|
-
|| vars[name].getMeta().includes("event_parameter" /* EventParameter */)) {
|
|
114
|
-
// todo, workaround for "me" and "super", these should somehow be typed to built-in
|
|
175
|
+
else if (obj instanceof objects_1.Program === false && obj.containsFile(filename) === false) {
|
|
115
176
|
continue;
|
|
116
177
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
&& this.isUsed(vars[name], node) === false) {
|
|
121
|
-
const message = "Variable \"" + name.toLowerCase() + "\" not used";
|
|
122
|
-
const statement = this.findStatement(vars[name]);
|
|
123
|
-
if (statement === null || statement === void 0 ? void 0 : statement.getPragmas().map(t => t.getStr()).includes(this.getMetadata().pragma + "")) {
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
else if (this.suppressedbyPseudo(statement, vars[name], obj)) {
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
const fix = this.buildFix(vars[name], obj);
|
|
130
|
-
ret.push(issue_1.Issue.atIdentifier(vars[name], message, this.getMetadata().key, this.conf.severity, fix));
|
|
178
|
+
const statement = this.findStatement(w.id);
|
|
179
|
+
if (statement === null || statement === void 0 ? void 0 : statement.getPragmas().map(t => t.getStr()).includes(this.getMetadata().pragma + "")) {
|
|
180
|
+
continue;
|
|
131
181
|
}
|
|
182
|
+
else if (this.suppressedbyPseudo(statement, w.id, obj)) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const name = w.id.getName();
|
|
186
|
+
const message = "Variable \"" + name.toLowerCase() + "\" not used";
|
|
187
|
+
const fix = this.buildFix(w.id, obj);
|
|
188
|
+
ret.push(issue_1.Issue.atIdentifier(w.id, message, this.getMetadata().key, this.conf.severity, fix));
|
|
132
189
|
}
|
|
133
190
|
return ret;
|
|
134
191
|
}
|
|
@@ -151,16 +208,6 @@ class UnusedVariables {
|
|
|
151
208
|
}
|
|
152
209
|
return false;
|
|
153
210
|
}
|
|
154
|
-
isUsed(id, node) {
|
|
155
|
-
const isInline = id.getMeta().includes("inline" /* InlineDefinition */);
|
|
156
|
-
const found = new references_1.References(this.reg).search(id, node, true, isInline === false);
|
|
157
|
-
if (isInline === true) {
|
|
158
|
-
return found.length > 2; // inline definitions are always written to
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
return found.length > 1;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
211
|
findStatement(v) {
|
|
165
212
|
const file = this.reg.getFileByName(v.getFilename());
|
|
166
213
|
if (file === undefined) {
|
package/package.json
CHANGED
|
@@ -1,29 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/core",
|
|
3
|
-
"version": "2.80.
|
|
3
|
+
"version": "2.80.8",
|
|
4
4
|
"description": "abaplint - Core API",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/abaplint.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"madge.orphans": "madge --extensions ts --ts-config tsconfig.json --orphans src/",
|
|
9
|
-
"madge.svg": "madge --extensions ts --ts-config tsconfig.json --image graph.svg src/",
|
|
10
|
-
"madge.circular": "madge --extensions ts --ts-config tsconfig.json --circular src/",
|
|
11
8
|
"lint": "eslint src/**/*.ts test/**/*.ts --format unix",
|
|
12
9
|
"lint:fix": "eslint src/**/*.ts test/**/*.ts --format unix --fix",
|
|
13
|
-
"compile": "tsc",
|
|
14
|
-
"
|
|
15
|
-
"pretest": "npm run compile",
|
|
16
|
-
"test": "mocha --timeout 1000",
|
|
10
|
+
"compile": "tsc && sh scripts/version.sh",
|
|
11
|
+
"test": "npm run compile && mocha --timeout 1000 && npm run lint && npm run schema && api-extractor run",
|
|
17
12
|
"test:only": "npm run compile && mocha",
|
|
18
13
|
"test:parallel": "npm run compile && mocha --timeout 1000 --parallel --reporter dot",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"coverage": "c8 mocha",
|
|
23
|
-
"postcoverage": "c8 report --reporter=html",
|
|
24
|
-
"preschema": "node scripts/schema.js > scripts/schema.ts",
|
|
25
|
-
"schema": "ts-json-schema-generator --tsconfig tsconfig_schema.json --jsDoc extended --path scripts/schema.ts > scripts/schema.json",
|
|
26
|
-
"postschema": "node scripts/schema_post.js"
|
|
14
|
+
"coverage": "npm run compile && c8 mocha && c8 report --reporter=html",
|
|
15
|
+
"schema": "node scripts/schema.js > scripts/schema.ts && ts-json-schema-generator --tsconfig tsconfig_schema.json --jsDoc extended --path scripts/schema.ts > scripts/schema.json && node scripts/schema_post.js",
|
|
16
|
+
"publish:patch": "npm --no-git-tag-version version patch && rm -rf build && npm install && npm run test && npm publish --access public"
|
|
27
17
|
},
|
|
28
18
|
"mocha": {
|
|
29
19
|
"recursive": true,
|
|
@@ -54,17 +44,16 @@
|
|
|
54
44
|
},
|
|
55
45
|
"homepage": "https://abaplint.org",
|
|
56
46
|
"devDependencies": {
|
|
57
|
-
"@microsoft/api-extractor": "^7.18.
|
|
47
|
+
"@microsoft/api-extractor": "^7.18.19",
|
|
58
48
|
"@types/chai": "^4.2.22",
|
|
59
49
|
"@types/mocha": "^9.0.0",
|
|
60
50
|
"@types/node": "^16.11.6",
|
|
61
51
|
"chai": "^4.3.4",
|
|
62
|
-
"eslint": "^8.
|
|
63
|
-
"madge": "^5.0.1",
|
|
52
|
+
"eslint": "^8.2.0",
|
|
64
53
|
"mocha": "^9.1.3",
|
|
65
54
|
"c8": "^7.10.0",
|
|
66
55
|
"source-map-support": "^0.5.20",
|
|
67
|
-
"ts-json-schema-generator": "^0.
|
|
56
|
+
"ts-json-schema-generator": "^0.97.0",
|
|
68
57
|
"typescript": "^4.4.4"
|
|
69
58
|
},
|
|
70
59
|
"dependencies": {
|