@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.
@@ -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>;
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=_imacro_references.js.map
@@ -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()] = contents;
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 name = undefined;
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
- name = statement.getTokens()[1].getStr();
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 = (_a = statement.findDirectExpression(Expressions.IncludeName)) === null || _a === void 0 ? void 0 : _a.concatTokens();
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 = (_b = this.reg) === null || _b === void 0 ? void 0 : _b.getObject("PROG", includeName);
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 main = prog.getMainABAPFile();
67
- if (main) {
81
+ const includeMainFile = prog.getMainABAPFile();
82
+ if (includeMainFile) {
68
83
  // slow, this copies everything,
69
- this.find([...main.getStatements()]);
84
+ this.find([...includeMainFile.getStatements()], includeMainFile, false);
70
85
  }
71
86
  }
72
87
  }
73
- else if (name) {
88
+ else if (nameToken) {
74
89
  if (type instanceof Statements.EndOfDefinition) {
75
- this.macros.addMacro(name, contents);
76
- name = undefined;
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);
@@ -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
@@ -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.108.14";
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]) {
@@ -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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.108.14",
3
+ "version": "2.109.1",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",