@abaplint/core 2.120.4 → 2.120.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.
@@ -7850,8 +7850,8 @@ export declare class SyntaxLogic {
7850
7850
  private issues;
7851
7851
  private readonly object;
7852
7852
  private readonly reg;
7853
- private readonly scope;
7854
- private readonly helpers;
7853
+ private scope;
7854
+ private helpers;
7855
7855
  constructor(reg: IRegistry, object: ABAPObject);
7856
7856
  run(): ISyntaxResult;
7857
7857
  private traverseObject;
@@ -57,7 +57,7 @@ class CondBody {
57
57
  type = source_1.Source.runSyntax(s, input, targetType);
58
58
  }
59
59
  else {
60
- source_1.Source.runSyntax(s, input, targetType);
60
+ source_1.Source.runSyntax(s, input, targetType !== null && targetType !== void 0 ? targetType : type);
61
61
  }
62
62
  }
63
63
  if (scoped === true) {
@@ -117,7 +117,7 @@ class Source {
117
117
  case "SWITCH":
118
118
  {
119
119
  const foundType = this.determineType(node, input, targetType);
120
- const bodyType = switch_body_1.SwitchBody.runSyntax(node.findDirectExpression(Expressions.SwitchBody), input);
120
+ const bodyType = switch_body_1.SwitchBody.runSyntax(node.findDirectExpression(Expressions.SwitchBody), input, foundType);
121
121
  if (foundType === undefined || foundType.isGeneric()) {
122
122
  this.addIfInferred(node, input, bodyType);
123
123
  }
@@ -39,7 +39,7 @@ const source_1 = require("./source");
39
39
  const _syntax_input_1 = require("../_syntax_input");
40
40
  const basic_1 = require("../../types/basic");
41
41
  class SwitchBody {
42
- static runSyntax(node, input) {
42
+ static runSyntax(node, input, targetType) {
43
43
  if (node === undefined) {
44
44
  return;
45
45
  }
@@ -49,12 +49,12 @@ class SwitchBody {
49
49
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
50
50
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
51
51
  }
52
- const type = source_1.Source.runSyntax(thenSource, input);
52
+ const type = source_1.Source.runSyntax(thenSource, input, targetType);
53
53
  for (const s of node.findDirectExpressions(Expressions.Source)) {
54
54
  if (s === thenSource) {
55
55
  continue;
56
56
  }
57
- source_1.Source.runSyntax(s, input);
57
+ source_1.Source.runSyntax(s, input, targetType !== null && targetType !== void 0 ? targetType : type);
58
58
  }
59
59
  return type;
60
60
  }
@@ -53,6 +53,10 @@ class Constant {
53
53
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, found.getToken(), message));
54
54
  return new _typed_identifier_1.TypedIdentifier(found.getToken(), input.filename, basic_2.VoidType.get(_syntax_input_1.CheckSyntaxKey), meta, val);
55
55
  }
56
+ if (this.isNameTooLong(found.getName())) {
57
+ const message = "CONSTANTS name too long, " + found.getName();
58
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, found.getToken(), message));
59
+ }
56
60
  return new _typed_identifier_1.TypedIdentifier(found.getToken(), input.filename, found.getType(), meta, val);
57
61
  }
58
62
  const fallback = node.findFirstExpression(Expressions.DefinitionName);
@@ -61,10 +65,17 @@ class Constant {
61
65
  const message = "not possible to have a name with only digits";
62
66
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, fallback.getFirstToken(), message));
63
67
  }
68
+ if (this.isNameTooLong(fallback.concatTokens())) {
69
+ const message = "CONSTANTS name too long, " + fallback.concatTokens();
70
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, fallback.getFirstToken(), message));
71
+ }
64
72
  return new _typed_identifier_1.TypedIdentifier(fallback.getFirstToken(), input.filename, new basic_1.UnknownType("constant, fallback"));
65
73
  }
66
74
  throw new assert_error_1.AssertError("Statement Constant: unexpected structure");
67
75
  }
76
+ isNameTooLong(name) {
77
+ return name.length > 30;
78
+ }
68
79
  isOnlyDigits(name) {
69
80
  return /^[0-9]+$/.test(name);
70
81
  }
@@ -51,6 +51,10 @@ class Data {
51
51
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, id.getToken(), message));
52
52
  return new _typed_identifier_1.TypedIdentifier(id.getToken(), input.filename, basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey));
53
53
  }
54
+ if (id && this.isNameTooLong(id.getName())) {
55
+ const message = "DATA name too long, " + id.getName();
56
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, id.getToken(), message));
57
+ }
54
58
  if ((id === null || id === void 0 ? void 0 : id.getType().isGeneric()) === true
55
59
  && (id === null || id === void 0 ? void 0 : id.getType().containsVoid()) === false) {
56
60
  const message = "DATA definition cannot be generic, " + (name === null || name === void 0 ? void 0 : name.concatTokens());
@@ -64,10 +68,17 @@ class Data {
64
68
  const message = "not possible to have a name with only digits";
65
69
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, name.getFirstToken(), message));
66
70
  }
71
+ if (this.isNameTooLong(name.concatTokens())) {
72
+ const message = "DATA name too long, " + name.concatTokens();
73
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, name.getFirstToken(), message));
74
+ }
67
75
  return new _typed_identifier_1.TypedIdentifier(name.getFirstToken(), input.filename, new unknown_type_1.UnknownType("data, fallback"));
68
76
  }
69
77
  return undefined;
70
78
  }
79
+ isNameTooLong(name) {
80
+ return name.length > 30;
81
+ }
71
82
  isOnlyDigits(name) {
72
83
  return /^[0-9]+$/.test(name);
73
84
  }
@@ -335,16 +335,17 @@ class SyntaxLogic {
335
335
  this.reg = reg;
336
336
  this.issues = [];
337
337
  this.object = object;
338
- this.scope = _current_scope_1.CurrentScope.buildDefault(this.reg, object);
339
- this.helpers = {
340
- oooc: new _object_oriented_1.ObjectOriented(this.scope),
341
- proc: new _procedural_1.Procedural(this.reg, this.scope),
342
- };
343
338
  }
344
339
  run() {
345
340
  if (this.object.syntaxResult !== undefined) {
346
341
  return this.object.syntaxResult;
347
342
  }
343
+ // the scope is built here instead of in the constructor, cached results must stay cheap
344
+ this.scope = _current_scope_1.CurrentScope.buildDefault(this.reg, this.object);
345
+ this.helpers = {
346
+ oooc: new _object_oriented_1.ObjectOriented(this.scope),
347
+ proc: new _procedural_1.Procedural(this.reg, this.scope),
348
+ };
348
349
  this.issues = [];
349
350
  this.reg.getDDICReferences().clear(this.object);
350
351
  this.reg.getMSAGReferences().clear(this.object);
@@ -75,7 +75,7 @@ class Registry {
75
75
  }
76
76
  static abaplintVersion() {
77
77
  // magic, see build script "version.js"
78
- return "2.120.4";
78
+ return "2.120.5";
79
79
  }
80
80
  getDDICReferences() {
81
81
  return this.ddicReferences;
@@ -59,35 +59,38 @@ class UnusedVariablesConf extends _basic_rule_config_1.BasicRuleConfig {
59
59
  exports.UnusedVariablesConf = UnusedVariablesConf;
60
60
  class WorkArea {
61
61
  constructor() {
62
- this.workarea = [];
62
+ // keyed by filename + start position, this equals Identifier.equals()
63
+ this.workarea = new Map();
63
64
  }
64
65
  push(id, count = 1) {
65
- for (const w of this.workarea) {
66
- if (id.equals(w.id)) {
67
- return;
68
- }
66
+ const key = this.buildKey(id);
67
+ if (this.workarea.has(key)) {
68
+ return;
69
69
  }
70
- this.workarea.push({ id, count });
70
+ this.workarea.set(key, { id, count });
71
71
  }
72
72
  removeIfExists(id) {
73
73
  if (id === undefined) {
74
74
  return;
75
75
  }
76
- for (let i = 0; i < this.workarea.length; i++) {
77
- if (id.equals(this.workarea[i].id)) {
78
- this.workarea[i].count--;
79
- if (this.workarea[i].count === 0) {
80
- this.workarea.splice(i, 1);
81
- }
82
- return;
76
+ const key = this.buildKey(id);
77
+ const found = this.workarea.get(key);
78
+ if (found !== undefined) {
79
+ found.count--;
80
+ if (found.count === 0) {
81
+ this.workarea.delete(key);
83
82
  }
84
83
  }
85
84
  }
86
85
  get() {
87
- return this.workarea;
86
+ return [...this.workarea.values()];
88
87
  }
89
88
  count() {
90
- return this.workarea.length;
89
+ return this.workarea.size;
90
+ }
91
+ buildKey(id) {
92
+ const start = id.getStart();
93
+ return id.getFilename() + "," + start.getRow() + "," + start.getCol();
91
94
  }
92
95
  }
93
96
  class UnusedVariables {
@@ -221,6 +224,9 @@ Errors found in INCLUDES are reported for the main program.`,
221
224
  }
222
225
  buildIssues(obj) {
223
226
  const ret = [];
227
+ const metadata = this.getMetadata();
228
+ const pragma = metadata.pragma + "";
229
+ const files = new Map();
224
230
  for (const w of this.workarea.get()) {
225
231
  const filename = w.id.getFilename();
226
232
  if (this.reg.isFileDependency(filename) === true) {
@@ -229,41 +235,51 @@ Errors found in INCLUDES are reported for the main program.`,
229
235
  else if (obj instanceof objects_1.Program === false && obj.containsFile(filename) === false) {
230
236
  continue;
231
237
  }
232
- const statement = this.findStatement(w.id);
233
- if (statement === null || statement === void 0 ? void 0 : statement.getPragmas().map(t => t.getStr()).includes(this.getMetadata().pragma + "")) {
234
- continue;
238
+ if (files.has(filename) === false) {
239
+ files.set(filename, this.findFile(filename));
235
240
  }
236
- else if (this.suppressedbyPseudo(statement, w.id, obj)) {
237
- continue;
241
+ const file = files.get(filename);
242
+ let statement = undefined;
243
+ let statementIndex = -1;
244
+ if (file !== undefined) {
245
+ const statements = file.getStatements();
246
+ const token = w.id.getToken();
247
+ for (let i = 0; i < statements.length; i++) {
248
+ if (statements[i].includesToken(token)) {
249
+ statement = statements[i];
250
+ statementIndex = i;
251
+ break;
252
+ }
253
+ }
254
+ }
255
+ if (statement !== undefined && file !== undefined) {
256
+ if (statement.getPragmas().some(t => t.getStr() === pragma)) {
257
+ continue;
258
+ }
259
+ else if (this.suppressedbyPseudo(file, statementIndex, w.id, obj)) {
260
+ continue;
261
+ }
238
262
  }
239
263
  const name = w.id.getName();
240
264
  const message = "Variable \"" + name.toLowerCase() + "\" not used";
241
- const fix = this.buildFix(w.id, obj);
242
- ret.push(issue_1.Issue.atIdentifier(w.id, message, this.getMetadata().key, this.conf.severity, fix));
265
+ const fix = this.buildFix(w.id, obj, statement);
266
+ ret.push(issue_1.Issue.atIdentifier(w.id, message, metadata.key, this.conf.severity, fix));
243
267
  }
244
268
  return ret;
245
269
  }
246
- suppressedbyPseudo(statement, v, obj) {
247
- if (statement === undefined) {
270
+ suppressedbyPseudo(file, statementIndex, v, obj) {
271
+ // pseudo comments are only found in files belonging to the object itself, not in eg. includes
272
+ if (obj.getABAPFileByName(v.getFilename()) === undefined) {
248
273
  return false;
249
274
  }
250
- const file = obj.getABAPFileByName(v.getFilename());
251
- if (file === undefined) {
252
- return false;
253
- }
254
- let next = false;
255
- for (const s of file.getStatements()) {
256
- if (next === true && s.get() instanceof _statement_1.Comment) {
257
- return s.concatTokens().includes(this.getMetadata().pseudoComment + "");
258
- }
259
- if (s === statement) {
260
- next = true;
261
- }
262
- }
275
+ const statements = file.getStatements();
276
+ const next = statements[statementIndex + 1];
277
+ return (next === null || next === void 0 ? void 0 : next.get()) instanceof _statement_1.Comment
278
+ && next.concatTokens().includes(this.getMetadata().pseudoComment + "");
263
279
  return false;
264
280
  }
265
- findStatement(v) {
266
- const file = this.reg.getFileByName(v.getFilename());
281
+ findFile(filename) {
282
+ const file = this.reg.getFileByName(filename);
267
283
  if (file === undefined) {
268
284
  return undefined;
269
285
  }
@@ -271,26 +287,17 @@ Errors found in INCLUDES are reported for the main program.`,
271
287
  if (!(object instanceof _abap_object_1.ABAPObject)) {
272
288
  return undefined;
273
289
  }
274
- const abapfile = object.getABAPFileByName(v.getFilename());
275
- if (abapfile === undefined) {
290
+ return object.getABAPFileByName(filename);
291
+ }
292
+ buildFix(v, obj, statement) {
293
+ if (statement === undefined || !(statement.get() instanceof Statements.Data)) {
276
294
  return undefined;
277
295
  }
278
- const statement = edit_helper_1.EditHelper.findStatement(v.getToken(), abapfile);
279
- return statement;
280
- }
281
- buildFix(v, obj) {
282
296
  const file = obj.getABAPFileByName(v.getFilename());
283
297
  if (file === undefined) {
284
298
  return undefined;
285
299
  }
286
- const statement = edit_helper_1.EditHelper.findStatement(v.getToken(), file);
287
- if (statement === undefined) {
288
- return undefined;
289
- }
290
- else if (statement.get() instanceof Statements.Data) {
291
- return edit_helper_1.EditHelper.deleteStatement(file, statement);
292
- }
293
- return undefined;
300
+ return edit_helper_1.EditHelper.deleteStatement(file, statement);
294
301
  }
295
302
  }
296
303
  exports.UnusedVariables = UnusedVariables;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.120.4",
3
+ "version": "2.120.5",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",