@abaplint/core 2.93.99 → 2.94.0

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.
@@ -3,15 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Lexer = void 0;
4
4
  const position_1 = require("../../position");
5
5
  const tokens_1 = require("./tokens");
6
- var Mode;
7
- (function (Mode) {
8
- Mode[Mode["Normal"] = 0] = "Normal";
9
- Mode[Mode["Ping"] = 1] = "Ping";
10
- Mode[Mode["Str"] = 2] = "Str";
11
- Mode[Mode["Template"] = 3] = "Template";
12
- Mode[Mode["Comment"] = 4] = "Comment";
13
- Mode[Mode["Pragma"] = 5] = "Pragma";
14
- })(Mode || (Mode = {}));
15
6
  class Buffer {
16
7
  constructor() {
17
8
  this.buf = "";
@@ -101,10 +92,18 @@ class Stream {
101
92
  }
102
93
  }
103
94
  class Lexer {
95
+ constructor() {
96
+ this.ModeNormal = 1;
97
+ this.ModePing = 2;
98
+ this.ModeStr = 3;
99
+ this.ModeTemplate = 4;
100
+ this.ModeComment = 5;
101
+ this.ModePragma = 6;
102
+ }
104
103
  run(file, virtual) {
105
104
  this.virtual = virtual;
106
105
  this.tokens = [];
107
- this.m = Mode.Normal;
106
+ this.m = this.ModeNormal;
108
107
  this.process(file.getRaw());
109
108
  return { file, tokens: this.tokens };
110
109
  }
@@ -130,13 +129,13 @@ class Lexer {
130
129
  pos = new position_1.VirtualPosition(this.virtual, pos.getRow(), pos.getCol());
131
130
  }
132
131
  let tok = undefined;
133
- if (this.m === Mode.Comment) {
132
+ if (this.m === this.ModeComment) {
134
133
  tok = new tokens_1.Comment(pos, s);
135
134
  }
136
- else if (this.m === Mode.Ping || this.m === Mode.Str) {
135
+ else if (this.m === this.ModePing || this.m === this.ModeStr) {
137
136
  tok = new tokens_1.StringToken(pos, s);
138
137
  }
139
- else if (this.m === Mode.Template) {
138
+ else if (this.m === this.ModeTemplate) {
140
139
  const first = s.charAt(0);
141
140
  const last = s.charAt(s.length - 1);
142
141
  if (first === "|" && last === "|") {
@@ -308,39 +307,39 @@ class Lexer {
308
307
  const ahead = this.stream.nextChar();
309
308
  const aahead = this.stream.nextNextChar();
310
309
  const prev = this.stream.prevChar();
311
- if (ahead === "'" && this.m === Mode.Normal) {
310
+ if (ahead === "'" && this.m === this.ModeNormal) {
312
311
  // start string
313
312
  this.add();
314
- this.m = Mode.Str;
313
+ this.m = this.ModeStr;
315
314
  }
316
315
  else if ((ahead === "|" || ahead === "}")
317
- && this.m === Mode.Normal) {
316
+ && this.m === this.ModeNormal) {
318
317
  // start template
319
318
  this.add();
320
- this.m = Mode.Template;
319
+ this.m = this.ModeTemplate;
321
320
  }
322
- else if (ahead === "`" && this.m === Mode.Normal) {
321
+ else if (ahead === "`" && this.m === this.ModeNormal) {
323
322
  // start ping
324
323
  this.add();
325
- this.m = Mode.Ping;
324
+ this.m = this.ModePing;
326
325
  }
327
- else if (aahead === "##" && this.m === Mode.Normal) {
326
+ else if (aahead === "##" && this.m === this.ModeNormal) {
328
327
  // start pragma
329
328
  this.add();
330
- this.m = Mode.Pragma;
329
+ this.m = this.ModePragma;
331
330
  }
332
331
  else if ((ahead === "\"" || (ahead === "*" && current === "\n"))
333
- && this.m === Mode.Normal) {
332
+ && this.m === this.ModeNormal) {
334
333
  // start comment
335
334
  this.add();
336
- this.m = Mode.Comment;
335
+ this.m = this.ModeComment;
337
336
  }
338
- else if (this.m === Mode.Pragma && (ahead === "," || ahead === ":" || ahead === "." || ahead === " " || ahead === "\n")) {
337
+ else if (this.m === this.ModePragma && (ahead === "," || ahead === ":" || ahead === "." || ahead === " " || ahead === "\n")) {
339
338
  // end of pragma
340
339
  this.add();
341
- this.m = Mode.Normal;
340
+ this.m = this.ModeNormal;
342
341
  }
343
- else if (this.m === Mode.Ping
342
+ else if (this.m === this.ModePing
344
343
  && buf.length > 1
345
344
  && current === "`"
346
345
  && aahead !== "``"
@@ -349,21 +348,21 @@ class Lexer {
349
348
  // end of ping
350
349
  this.add();
351
350
  if (ahead === `"`) {
352
- this.m = Mode.Comment;
351
+ this.m = this.ModeComment;
353
352
  }
354
353
  else {
355
- this.m = Mode.Normal;
354
+ this.m = this.ModeNormal;
356
355
  }
357
356
  }
358
- else if (this.m === Mode.Template
357
+ else if (this.m === this.ModeTemplate
359
358
  && buf.length > 1
360
359
  && (current === "|" || current === "{")
361
360
  && (prev !== "\\" || this.stream.prevPrevChar() === "\\\\")) {
362
361
  // end of template
363
362
  this.add();
364
- this.m = Mode.Normal;
363
+ this.m = this.ModeNormal;
365
364
  }
366
- else if (this.m === Mode.Str
365
+ else if (this.m === this.ModeStr
367
366
  && current === "'"
368
367
  && buf.length > 1
369
368
  && aahead !== "''"
@@ -372,13 +371,13 @@ class Lexer {
372
371
  // end of string
373
372
  this.add();
374
373
  if (ahead === "\"") {
375
- this.m = Mode.Comment;
374
+ this.m = this.ModeComment;
376
375
  }
377
376
  else {
378
- this.m = Mode.Normal;
377
+ this.m = this.ModeNormal;
379
378
  }
380
379
  }
381
- else if (this.m === Mode.Normal
380
+ else if (this.m === this.ModeNormal
382
381
  && (ahead === " "
383
382
  || ahead === ":"
384
383
  || ahead === "."
@@ -396,21 +395,21 @@ class Lexer {
396
395
  || ahead === "\n")) {
397
396
  this.add();
398
397
  }
399
- else if (ahead === "\n" && this.m !== Mode.Template) {
398
+ else if (ahead === "\n" && this.m !== this.ModeTemplate) {
400
399
  this.add();
401
- this.m = Mode.Normal;
400
+ this.m = this.ModeNormal;
402
401
  }
403
- else if (this.m === Mode.Template && current === "\n") {
402
+ else if (this.m === this.ModeTemplate && current === "\n") {
404
403
  this.add();
405
404
  }
406
405
  else if (current === ">"
407
406
  && (prev === "-" || prev === "=")
408
407
  && ahead !== " "
409
- && this.m === Mode.Normal) {
408
+ && this.m === this.ModeNormal) {
410
409
  // arrows
411
410
  this.add();
412
411
  }
413
- else if (this.m === Mode.Normal
412
+ else if (this.m === this.ModeNormal
414
413
  && (buf === "."
415
414
  || buf === ","
416
415
  || buf === ":"
@@ -3,16 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FlowGraph = void 0;
4
4
  class FlowGraph {
5
5
  constructor(counter) {
6
- this.label = "undefined";
7
6
  this.edges = {};
8
- this.start = "start#" + counter;
9
- this.end = "end#" + counter;
7
+ this.label = "undefined";
8
+ this.startNode = "start#" + counter;
9
+ this.endNode = "end#" + counter;
10
10
  }
11
11
  getStart() {
12
- return this.start;
12
+ return this.startNode;
13
13
  }
14
14
  getEnd() {
15
- return this.end;
15
+ return this.endNode;
16
16
  }
17
17
  addEdge(from, to) {
18
18
  if (this.edges[from] === undefined) {
@@ -38,6 +38,18 @@ class FlowGraph {
38
38
  }
39
39
  return list;
40
40
  }
41
+ listInto(to, skipStart = true) {
42
+ const ret = [];
43
+ for (const e of this.listEdges()) {
44
+ if (skipStart === true && e.from === this.getStart()) {
45
+ continue;
46
+ }
47
+ if (e.to === to) {
48
+ ret.push(e.from);
49
+ }
50
+ }
51
+ return ret;
52
+ }
41
53
  listNodes() {
42
54
  const set = new Set();
43
55
  for (const l of this.listEdges()) {
@@ -99,7 +111,7 @@ ${this.toTextEdges()}
99
111
  }
100
112
  return Array.from(set.values());
101
113
  }
102
- /** removes all nodes containing "#" that have one ingoing and one outgoing edge */
114
+ /** removes all nodes containing "#" that have one in-going and one out-going edge */
103
115
  reduce() {
104
116
  for (const node of this.listNodes()) {
105
117
  if (node.includes("#") === false) {
@@ -31,6 +31,7 @@ class StatementFlow {
31
31
  }
32
32
  return ret.map(f => f.reduce());
33
33
  }
34
+ ////////////////////
34
35
  findBody(f) {
35
36
  var _a;
36
37
  return ((_a = f.findDirectStructure(Structures.Body)) === null || _a === void 0 ? void 0 : _a.getChildren()) || [];
@@ -63,7 +63,7 @@ class Registry {
63
63
  }
64
64
  static abaplintVersion() {
65
65
  // magic, see build script "version.sh"
66
- return "2.93.99";
66
+ return "2.94.0";
67
67
  }
68
68
  getDDICReferences() {
69
69
  return this.references;
@@ -2,10 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.IfInIf = exports.IfInIfConf = void 0;
4
4
  const issue_1 = require("../issue");
5
+ const Statements = require("../abap/2_statements/statements");
5
6
  const Structures = require("../abap/3_structures/structures");
6
7
  const _abap_rule_1 = require("./_abap_rule");
7
8
  const _basic_rule_config_1 = require("./_basic_rule_config");
8
9
  const _irule_1 = require("./_irule");
10
+ const edit_helper_1 = require("../edit_helper");
9
11
  class IfInIfConf extends _basic_rule_config_1.BasicRuleConfig {
10
12
  }
11
13
  exports.IfInIfConf = IfInIfConf;
@@ -22,7 +24,7 @@ class IfInIf extends _abap_rule_1.ABAPRule {
22
24
  extendedInformation: `
23
25
  Directly nested IFs without ELSE can be refactored to a single condition using AND.
24
26
 
25
- ELSE condtions with directly nested IF refactored to ELSEIF.
27
+ ELSE condtions with directly nested IF refactored to ELSEIF, quickfixes are suggested for this case.
26
28
 
27
29
  https://docs.abapopenchecks.org/checks/01/
28
30
  https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#keep-the-nesting-depth-low`,
@@ -48,12 +50,9 @@ IF condition1.
48
50
  ELSEIF condition2.
49
51
  ...
50
52
  ENDIF.`,
51
- tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
53
+ tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Quickfix],
52
54
  };
53
55
  }
54
- getMessage() {
55
- return "IF in IF. Use IF cond1 AND cond2 instead";
56
- }
57
56
  getConfig() {
58
57
  return this.conf;
59
58
  }
@@ -61,6 +60,7 @@ ENDIF.`,
61
60
  this.conf = conf;
62
61
  }
63
62
  runParsed(file, obj) {
63
+ var _a, _b;
64
64
  const issues = [];
65
65
  if (obj.getType() === "INTF") {
66
66
  return [];
@@ -69,6 +69,7 @@ ENDIF.`,
69
69
  if (stru === undefined) {
70
70
  return [];
71
71
  }
72
+ let fixed = false;
72
73
  let possible = stru.findAllStructures(Structures.If);
73
74
  possible = possible.concat(stru.findAllStructures(Structures.Else));
74
75
  for (const i of possible) {
@@ -94,8 +95,23 @@ ENDIF.`,
94
95
  || nestedIf.findDirectStructures(Structures.Else).length > 0)) {
95
96
  continue;
96
97
  }
98
+ let message = "IF in IF. Use IF cond1 AND cond2 instead";
99
+ let fix = undefined;
100
+ if (i.get() instanceof Structures.Else) {
101
+ message = "Change ELSE part to ELSEIF";
102
+ const els = i.findFirstStatement(Statements.Else);
103
+ const iff = (_a = i.findFirstStructure(Structures.If)) === null || _a === void 0 ? void 0 : _a.findDirectStatement(Statements.If);
104
+ const endif = (_b = i.findFirstStructure(Structures.If)) === null || _b === void 0 ? void 0 : _b.findDirectStatement(Statements.EndIf);
105
+ if (fixed === false && iff && els && endif) {
106
+ const fix1 = edit_helper_1.EditHelper.deleteRange(file, els.getLastToken().getStart(), iff === null || iff === void 0 ? void 0 : iff.getFirstToken().getStart());
107
+ const fix2 = edit_helper_1.EditHelper.deleteStatement(file, endif);
108
+ fix = edit_helper_1.EditHelper.merge(fix1, fix2);
109
+ // max one fix per file at a time
110
+ fixed = true;
111
+ }
112
+ }
97
113
  const token = i.getFirstToken();
98
- const issue = issue_1.Issue.atToken(file, token, this.getMessage(), this.getMetadata().key, this.conf.severity);
114
+ const issue = issue_1.Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity, fix);
99
115
  issues.push(issue);
100
116
  }
101
117
  return issues;
@@ -151,6 +151,7 @@ __exportStar(require("./uncaught_exception"), exports);
151
151
  __exportStar(require("./unknown_types"), exports);
152
152
  __exportStar(require("./unnecessary_chaining"), exports);
153
153
  __exportStar(require("./unnecessary_pragma"), exports);
154
+ __exportStar(require("./unnecessary_return"), exports);
154
155
  __exportStar(require("./unreachable_code"), exports);
155
156
  __exportStar(require("./unsecure_fae"), exports);
156
157
  __exportStar(require("./unused_ddic"), exports);
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UnnecessaryReturn = exports.UnnecessaryReturnConf = void 0;
4
+ const issue_1 = require("../issue");
5
+ const _abap_rule_1 = require("./_abap_rule");
6
+ const _basic_rule_config_1 = require("./_basic_rule_config");
7
+ const _irule_1 = require("./_irule");
8
+ const Statements = require("../abap/2_statements/statements");
9
+ const edit_helper_1 = require("../edit_helper");
10
+ class UnnecessaryReturnConf extends _basic_rule_config_1.BasicRuleConfig {
11
+ }
12
+ exports.UnnecessaryReturnConf = UnnecessaryReturnConf;
13
+ class UnnecessaryReturn extends _abap_rule_1.ABAPRule {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.conf = new UnnecessaryReturnConf();
17
+ }
18
+ getMetadata() {
19
+ return {
20
+ key: "unnecessary_return",
21
+ title: "Unnecessary Return",
22
+ shortDescription: `Finds unnecessary RETURN statements`,
23
+ extendedInformation: `Finds unnecessary RETURN statements`,
24
+ tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Quickfix],
25
+ badExample: `METHOD hello.
26
+ ...
27
+ RETURN.
28
+ ENDMETHOD.`,
29
+ goodExample: `METHOD hello.
30
+ ...
31
+ ENDMETHOD.`,
32
+ };
33
+ }
34
+ getConfig() {
35
+ return this.conf;
36
+ }
37
+ setConfig(conf) {
38
+ this.conf = conf;
39
+ }
40
+ runParsed(file) {
41
+ const issues = [];
42
+ const structure = file.getStructure();
43
+ if (structure === undefined) {
44
+ return [];
45
+ }
46
+ const statements = file.getStatements();
47
+ for (let i = 0; i < statements.length - 1; i++) {
48
+ const node = statements[i];
49
+ const next = statements[i + 1];
50
+ if (node.get() instanceof Statements.Return
51
+ && (next.get() instanceof Statements.EndMethod
52
+ || next.get() instanceof Statements.EndForm
53
+ || next.get() instanceof Statements.EndFunction)) {
54
+ const message = "Unnecessary RETURN";
55
+ const fix = edit_helper_1.EditHelper.deleteStatement(file, node);
56
+ issues.push(issue_1.Issue.atStatement(file, node, message, this.getMetadata().key, this.getConfig().severity, fix));
57
+ }
58
+ }
59
+ return issues;
60
+ }
61
+ }
62
+ exports.UnnecessaryReturn = UnnecessaryReturn;
63
+ //# sourceMappingURL=unnecessary_return.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.93.99",
3
+ "version": "2.94.0",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",
@@ -48,7 +48,7 @@
48
48
  "devDependencies": {
49
49
  "@microsoft/api-extractor": "^7.33.6",
50
50
  "@types/chai": "^4.3.4",
51
- "@types/mocha": "^10.0.0",
51
+ "@types/mocha": "^10.0.1",
52
52
  "@types/node": "^18.11.9",
53
53
  "chai": "^4.3.7",
54
54
  "eslint": "^8.28.0",