@abaplint/core 2.108.14 → 2.109.1
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/abaplint.d.ts +20 -0
- package/build/src/_imacro_references.js +3 -0
- package/build/src/abap/2_statements/expand_macros.js +43 -18
- package/build/src/abap/2_statements/statement_parser.js +2 -2
- package/build/src/lsp/hover.js +4 -0
- package/build/src/macro_references.js +55 -0
- package/build/src/registry.js +6 -1
- package/build/src/rules/index.js +1 -0
- package/build/src/rules/unused_macros.js +74 -0
- package/package.json +1 -1
package/build/abaplint.d.ts
CHANGED
|
@@ -3132,6 +3132,11 @@ export declare interface IFile {
|
|
|
3132
3132
|
getRawRows(): string[];
|
|
3133
3133
|
}
|
|
3134
3134
|
|
|
3135
|
+
declare interface IFilenameAndToken {
|
|
3136
|
+
filename: string;
|
|
3137
|
+
token: Token;
|
|
3138
|
+
}
|
|
3139
|
+
|
|
3135
3140
|
declare interface IFormDefinition extends Identifier {
|
|
3136
3141
|
getTablesParameters(): readonly TypedIdentifier[];
|
|
3137
3142
|
getUsingParameters(): readonly TypedIdentifier[];
|
|
@@ -3211,6 +3216,18 @@ declare interface ILookupResult {
|
|
|
3211
3216
|
object?: IObject;
|
|
3212
3217
|
}
|
|
3213
3218
|
|
|
3219
|
+
declare interface IMacroReferences {
|
|
3220
|
+
addDefinition(ref: IFilenameAndToken, start: Position, end: Position): void;
|
|
3221
|
+
addReference(ref: IFilenameAndToken): void;
|
|
3222
|
+
listDefinitionsByFile(filename: string): Token[];
|
|
3223
|
+
listUsagesbyMacro(filename: string, token: Token): IFilenameAndToken[];
|
|
3224
|
+
getDefinitionPosition(filename: string, token: Token): {
|
|
3225
|
+
start: Position;
|
|
3226
|
+
end: Position;
|
|
3227
|
+
} | undefined;
|
|
3228
|
+
clear(filename: string): void;
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3214
3231
|
declare interface IMatch {
|
|
3215
3232
|
matched: StatementNode[];
|
|
3216
3233
|
unmatched: StatementNode[];
|
|
@@ -3651,6 +3668,7 @@ export declare interface IRegistry {
|
|
|
3651
3668
|
inErrorNamespace(name: string): boolean;
|
|
3652
3669
|
getDDICReferences(): IDDICReferences;
|
|
3653
3670
|
getMSAGReferences(): IMSAGReferences;
|
|
3671
|
+
getMacroReferences(): IMacroReferences;
|
|
3654
3672
|
getConfig(): IConfiguration;
|
|
3655
3673
|
setConfig(conf: IConfiguration): IRegistry;
|
|
3656
3674
|
/** Get all objects, including dependencies */
|
|
@@ -5246,11 +5264,13 @@ export declare class Registry implements IRegistry {
|
|
|
5246
5264
|
private readonly dependencies;
|
|
5247
5265
|
private readonly ddicReferences;
|
|
5248
5266
|
private readonly msagReferences;
|
|
5267
|
+
private readonly macroReferences;
|
|
5249
5268
|
private conf;
|
|
5250
5269
|
constructor(conf?: IConfiguration);
|
|
5251
5270
|
static abaplintVersion(): string;
|
|
5252
5271
|
getDDICReferences(): IDDICReferences;
|
|
5253
5272
|
getMSAGReferences(): IMSAGReferences;
|
|
5273
|
+
getMacroReferences(): IMacroReferences;
|
|
5254
5274
|
getObjects(): Generator<IObject, void, undefined>;
|
|
5255
5275
|
getObjectsByType(type: string): Generator<IObject, void, undefined>;
|
|
5256
5276
|
getFiles(): Generator<IFile, void, undefined>;
|
|
@@ -15,17 +15,23 @@ class Macros {
|
|
|
15
15
|
constructor(globalMacros) {
|
|
16
16
|
this.macros = {};
|
|
17
17
|
for (const m of globalMacros) {
|
|
18
|
-
this.macros[m.toUpperCase()] =
|
|
18
|
+
this.macros[m.toUpperCase()] = {
|
|
19
|
+
statements: [],
|
|
20
|
+
filename: undefined,
|
|
21
|
+
};
|
|
19
22
|
}
|
|
20
23
|
}
|
|
21
|
-
addMacro(name, contents) {
|
|
24
|
+
addMacro(name, contents, filename) {
|
|
22
25
|
if (this.isMacro(name)) {
|
|
23
26
|
return;
|
|
24
27
|
}
|
|
25
|
-
this.macros[name.toUpperCase()] =
|
|
28
|
+
this.macros[name.toUpperCase()] = {
|
|
29
|
+
statements: contents,
|
|
30
|
+
filename: filename,
|
|
31
|
+
};
|
|
26
32
|
}
|
|
27
33
|
getContents(name) {
|
|
28
|
-
return this.macros[name.toUpperCase()];
|
|
34
|
+
return this.macros[name.toUpperCase()].statements;
|
|
29
35
|
}
|
|
30
36
|
listMacroNames() {
|
|
31
37
|
return Object.keys(this.macros);
|
|
@@ -36,6 +42,9 @@ class Macros {
|
|
|
36
42
|
}
|
|
37
43
|
return false;
|
|
38
44
|
}
|
|
45
|
+
getMacroFilename(name) {
|
|
46
|
+
return this.macros[name.toUpperCase()].filename;
|
|
47
|
+
}
|
|
39
48
|
}
|
|
40
49
|
class ExpandMacros {
|
|
41
50
|
// "reg" must be supplied if there are cross object macros via INCLUDE
|
|
@@ -45,35 +54,42 @@ class ExpandMacros {
|
|
|
45
54
|
this.globalMacros = globalMacros;
|
|
46
55
|
this.reg = reg;
|
|
47
56
|
}
|
|
48
|
-
find(statements) {
|
|
49
|
-
var _a, _b;
|
|
50
|
-
let
|
|
57
|
+
find(statements, file, clear = true) {
|
|
58
|
+
var _a, _b, _c;
|
|
59
|
+
let nameToken = undefined;
|
|
60
|
+
let start = undefined;
|
|
51
61
|
let contents = [];
|
|
62
|
+
const macroReferences = (_a = this.reg) === null || _a === void 0 ? void 0 : _a.getMacroReferences();
|
|
63
|
+
if (clear) {
|
|
64
|
+
macroReferences === null || macroReferences === void 0 ? void 0 : macroReferences.clear(file.getFilename());
|
|
65
|
+
}
|
|
52
66
|
for (let i = 0; i < statements.length; i++) {
|
|
53
67
|
const statement = statements[i];
|
|
54
68
|
const type = statement.get();
|
|
55
69
|
if (type instanceof Statements.Define) {
|
|
56
70
|
// todo, will this break if first token is a pragma?
|
|
57
|
-
|
|
71
|
+
nameToken = statement.getTokens()[1];
|
|
72
|
+
start = statement.getFirstToken().getStart();
|
|
58
73
|
contents = [];
|
|
59
74
|
}
|
|
60
75
|
else if (type instanceof Statements.Include) {
|
|
61
|
-
const includeName = (
|
|
76
|
+
const includeName = (_b = statement.findDirectExpression(Expressions.IncludeName)) === null || _b === void 0 ? void 0 : _b.concatTokens();
|
|
62
77
|
// todo, this does not take function module includes into account
|
|
63
|
-
const prog = (
|
|
78
|
+
const prog = (_c = this.reg) === null || _c === void 0 ? void 0 : _c.getObject("PROG", includeName);
|
|
64
79
|
if (prog) {
|
|
65
80
|
prog.parse(this.version, this.globalMacros, this.reg);
|
|
66
|
-
const
|
|
67
|
-
if (
|
|
81
|
+
const includeMainFile = prog.getMainABAPFile();
|
|
82
|
+
if (includeMainFile) {
|
|
68
83
|
// slow, this copies everything,
|
|
69
|
-
this.find([...
|
|
84
|
+
this.find([...includeMainFile.getStatements()], includeMainFile, false);
|
|
70
85
|
}
|
|
71
86
|
}
|
|
72
87
|
}
|
|
73
|
-
else if (
|
|
88
|
+
else if (nameToken) {
|
|
74
89
|
if (type instanceof Statements.EndOfDefinition) {
|
|
75
|
-
this.macros.addMacro(
|
|
76
|
-
|
|
90
|
+
this.macros.addMacro(nameToken.getStr(), contents, file.getFilename());
|
|
91
|
+
macroReferences === null || macroReferences === void 0 ? void 0 : macroReferences.addDefinition({ filename: file.getFilename(), token: nameToken }, start, statement.getLastToken().getEnd());
|
|
92
|
+
nameToken = undefined;
|
|
77
93
|
}
|
|
78
94
|
else if (!(type instanceof _statement_1.Comment)) {
|
|
79
95
|
statements[i] = new statement_node_1.StatementNode(new _statement_1.MacroContent()).setChildren(this.tokensToNodes(statement.getTokens()));
|
|
@@ -82,17 +98,26 @@ class ExpandMacros {
|
|
|
82
98
|
}
|
|
83
99
|
}
|
|
84
100
|
}
|
|
85
|
-
handleMacros(statements) {
|
|
101
|
+
handleMacros(statements, file) {
|
|
102
|
+
var _a;
|
|
86
103
|
const result = [];
|
|
87
104
|
let containsUnknown = false;
|
|
105
|
+
const macroReferences = (_a = this.reg) === null || _a === void 0 ? void 0 : _a.getMacroReferences();
|
|
88
106
|
for (const statement of statements) {
|
|
89
107
|
const type = statement.get();
|
|
90
108
|
if (type instanceof _statement_1.Unknown || type instanceof _statement_1.MacroCall) {
|
|
91
109
|
const macroName = this.findName(statement.getTokens());
|
|
92
110
|
if (macroName && this.macros.isMacro(macroName)) {
|
|
111
|
+
const filename = this.macros.getMacroFilename(macroName);
|
|
112
|
+
if (filename) {
|
|
113
|
+
macroReferences === null || macroReferences === void 0 ? void 0 : macroReferences.addReference({
|
|
114
|
+
filename: filename,
|
|
115
|
+
token: statement.getFirstToken(),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
93
118
|
result.push(new statement_node_1.StatementNode(new _statement_1.MacroCall(), statement.getColon()).setChildren(this.tokensToNodes(statement.getTokens())));
|
|
94
119
|
const expanded = this.expandContents(macroName, statement);
|
|
95
|
-
const handled = this.handleMacros(expanded);
|
|
120
|
+
const handled = this.handleMacros(expanded, file);
|
|
96
121
|
for (const e of handled.statements) {
|
|
97
122
|
result.push(e);
|
|
98
123
|
}
|
|
@@ -82,10 +82,10 @@ class StatementParser {
|
|
|
82
82
|
for (const w of wa) {
|
|
83
83
|
this.process(w);
|
|
84
84
|
this.categorize(w);
|
|
85
|
-
macros.find(w.statements);
|
|
85
|
+
macros.find(w.statements, w.file);
|
|
86
86
|
}
|
|
87
87
|
for (const w of wa) {
|
|
88
|
-
const res = macros.handleMacros(w.statements);
|
|
88
|
+
const res = macros.handleMacros(w.statements, w.file);
|
|
89
89
|
w.statements = res.statements;
|
|
90
90
|
if (res.containsUnknown === true) {
|
|
91
91
|
this.lazyUnknown(w);
|
package/build/src/lsp/hover.js
CHANGED
|
@@ -7,6 +7,7 @@ const LServer = require("vscode-languageserver-types");
|
|
|
7
7
|
const _abap_object_1 = require("../objects/_abap_object");
|
|
8
8
|
const _lsp_utils_1 = require("./_lsp_utils");
|
|
9
9
|
const _lookup_1 = require("./_lookup");
|
|
10
|
+
const _statement_1 = require("../abap/2_statements/statements/_statement");
|
|
10
11
|
class Hover {
|
|
11
12
|
constructor(reg) {
|
|
12
13
|
this.reg = reg;
|
|
@@ -30,6 +31,9 @@ class Hover {
|
|
|
30
31
|
|| found.token instanceof Tokens.StringTemplateMiddle) {
|
|
31
32
|
return { kind: LServer.MarkupKind.Markdown, value: "String Template" };
|
|
32
33
|
}
|
|
34
|
+
else if (found.snode.get() instanceof _statement_1.MacroCall) {
|
|
35
|
+
return { kind: LServer.MarkupKind.Markdown, value: "Macro Call" };
|
|
36
|
+
}
|
|
33
37
|
else if (found.snode.get() instanceof Statements.Define && found.stack.length === 2) {
|
|
34
38
|
return { kind: LServer.MarkupKind.Markdown, value: "Macro Name" };
|
|
35
39
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MacroReferences = void 0;
|
|
4
|
+
class MacroReferences {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.definitions = {};
|
|
7
|
+
this.references = {};
|
|
8
|
+
}
|
|
9
|
+
addDefinition(ref, start, end) {
|
|
10
|
+
if (this.definitions[ref.filename] === undefined) {
|
|
11
|
+
this.definitions[ref.filename] = [];
|
|
12
|
+
}
|
|
13
|
+
else if (this.definitions[ref.filename].find((d) => d.token.getStart().equals(ref.token.getStart()))) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
this.definitions[ref.filename].push({ token: ref.token, start, end });
|
|
17
|
+
}
|
|
18
|
+
getDefinitionPosition(filename, token) {
|
|
19
|
+
for (const d of this.definitions[filename] || []) {
|
|
20
|
+
if (d.token.getStart().equals(token.getStart())) {
|
|
21
|
+
return { start: d.token.getStart(), end: d.token.getEnd() };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
addReference(ref) {
|
|
27
|
+
if (this.references[ref.filename] === undefined) {
|
|
28
|
+
this.references[ref.filename] = [];
|
|
29
|
+
}
|
|
30
|
+
this.references[ref.filename].push(ref);
|
|
31
|
+
}
|
|
32
|
+
listDefinitionsByFile(filename) {
|
|
33
|
+
const ret = [];
|
|
34
|
+
for (const d of this.definitions[filename] || []) {
|
|
35
|
+
ret.push(d.token);
|
|
36
|
+
}
|
|
37
|
+
return ret;
|
|
38
|
+
}
|
|
39
|
+
listUsagesbyMacro(filename, token) {
|
|
40
|
+
const ret = [];
|
|
41
|
+
const tokenStr = token.getStr().toUpperCase();
|
|
42
|
+
for (const ref of this.references[filename] || []) {
|
|
43
|
+
if (ref.token.getStr().toUpperCase() === tokenStr) {
|
|
44
|
+
ret.push(ref);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return ret;
|
|
48
|
+
}
|
|
49
|
+
clear(filename) {
|
|
50
|
+
delete this.definitions[filename];
|
|
51
|
+
delete this.references[filename];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.MacroReferences = MacroReferences;
|
|
55
|
+
//# sourceMappingURL=macro_references.js.map
|
package/build/src/registry.js
CHANGED
|
@@ -8,6 +8,7 @@ const excludeHelper_1 = require("./utils/excludeHelper");
|
|
|
8
8
|
const ddic_references_1 = require("./ddic_references");
|
|
9
9
|
const rules_runner_1 = require("./rules_runner");
|
|
10
10
|
const msag_references_1 = require("./msag_references");
|
|
11
|
+
const macro_references_1 = require("./macro_references");
|
|
11
12
|
// todo, this should really be an instance in case there are multiple Registry'ies
|
|
12
13
|
class ParsingPerformance {
|
|
13
14
|
static clear() {
|
|
@@ -62,10 +63,11 @@ class Registry {
|
|
|
62
63
|
this.conf = conf ? conf : config_1.Config.getDefault();
|
|
63
64
|
this.ddicReferences = new ddic_references_1.DDICReferences();
|
|
64
65
|
this.msagReferences = new msag_references_1.MSAGReferences();
|
|
66
|
+
this.macroReferences = new macro_references_1.MacroReferences();
|
|
65
67
|
}
|
|
66
68
|
static abaplintVersion() {
|
|
67
69
|
// magic, see build script "version.sh"
|
|
68
|
-
return "2.
|
|
70
|
+
return "2.109.1";
|
|
69
71
|
}
|
|
70
72
|
getDDICReferences() {
|
|
71
73
|
return this.ddicReferences;
|
|
@@ -73,6 +75,9 @@ class Registry {
|
|
|
73
75
|
getMSAGReferences() {
|
|
74
76
|
return this.msagReferences;
|
|
75
77
|
}
|
|
78
|
+
getMacroReferences() {
|
|
79
|
+
return this.macroReferences;
|
|
80
|
+
}
|
|
76
81
|
*getObjects() {
|
|
77
82
|
for (const name in this.objects) {
|
|
78
83
|
for (const type in this.objects[name]) {
|
package/build/src/rules/index.js
CHANGED
|
@@ -31,6 +31,7 @@ __exportStar(require("./cds_legacy_view"), exports);
|
|
|
31
31
|
__exportStar(require("./cds_parser_error"), exports);
|
|
32
32
|
__exportStar(require("./chain_mainly_declarations"), exports);
|
|
33
33
|
__exportStar(require("./change_if_to_case"), exports);
|
|
34
|
+
__exportStar(require("./unused_macros"), exports);
|
|
34
35
|
__exportStar(require("./check_abstract"), exports);
|
|
35
36
|
__exportStar(require("./check_comments"), exports);
|
|
36
37
|
__exportStar(require("./check_ddic"), exports);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UnusedMacros = exports.UnusedMacrosConf = void 0;
|
|
4
|
+
const issue_1 = require("../issue");
|
|
5
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
6
|
+
const _irule_1 = require("./_irule");
|
|
7
|
+
const _abap_object_1 = require("../objects/_abap_object");
|
|
8
|
+
const edit_helper_1 = require("../edit_helper");
|
|
9
|
+
class UnusedMacrosConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
10
|
+
constructor() {
|
|
11
|
+
super(...arguments);
|
|
12
|
+
/** skip specific names, case insensitive
|
|
13
|
+
* @uniqueItems true
|
|
14
|
+
*/
|
|
15
|
+
this.skipNames = [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.UnusedMacrosConf = UnusedMacrosConf;
|
|
19
|
+
class UnusedMacros {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.conf = new UnusedMacrosConf();
|
|
22
|
+
}
|
|
23
|
+
getMetadata() {
|
|
24
|
+
return {
|
|
25
|
+
key: "unused_macros",
|
|
26
|
+
title: "Unused macros",
|
|
27
|
+
shortDescription: `Checks for unused macro definitions definitions`,
|
|
28
|
+
tags: [_irule_1.RuleTag.Quickfix],
|
|
29
|
+
badExample: `DEFINE foobar1.
|
|
30
|
+
WRITE 'hello'.
|
|
31
|
+
END-OF-DEFINITION.`,
|
|
32
|
+
goodExample: `DEFINE foobar2.
|
|
33
|
+
WRITE 'hello'.
|
|
34
|
+
END-OF-DEFINITION.
|
|
35
|
+
|
|
36
|
+
foobar2.`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
getConfig() {
|
|
40
|
+
return this.conf;
|
|
41
|
+
}
|
|
42
|
+
setConfig(conf) {
|
|
43
|
+
this.conf = conf;
|
|
44
|
+
if (this.conf.skipNames === undefined) {
|
|
45
|
+
this.conf.skipNames = [];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
initialize(reg) {
|
|
49
|
+
this.reg = reg;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
run(obj) {
|
|
53
|
+
var _a;
|
|
54
|
+
const result = [];
|
|
55
|
+
if (!(obj instanceof _abap_object_1.ABAPObject)) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
const references = this.reg.getMacroReferences();
|
|
59
|
+
for (const file of obj.getABAPFiles()) {
|
|
60
|
+
for (const macroToken of references.listDefinitionsByFile(file.getFilename())) {
|
|
61
|
+
const usages = references.listUsagesbyMacro(file.getFilename(), macroToken);
|
|
62
|
+
if (usages.length === 0 && ((_a = this.conf.skipNames) === null || _a === void 0 ? void 0 : _a.includes(macroToken.getStr().toUpperCase())) === false) {
|
|
63
|
+
const message = "Unused macro definition: " + macroToken.getStr();
|
|
64
|
+
const pos = references.getDefinitionPosition(file.getFilename(), macroToken);
|
|
65
|
+
const fix = edit_helper_1.EditHelper.deleteRange(file, pos.start, pos.end);
|
|
66
|
+
result.push(issue_1.Issue.atToken(file, macroToken, message, this.getMetadata().key, this.conf.severity, fix));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.UnusedMacros = UnusedMacros;
|
|
74
|
+
//# sourceMappingURL=unused_macros.js.map
|