@abaplint/core 2.119.37 → 2.119.39
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/basic_types.js +44 -12
- package/build/src/abap/5_syntax/statements/delete_internal.js +11 -1
- package/build/src/abap/5_syntax/syntax.js +4 -0
- package/build/src/registry.js +1 -1
- package/build/src/rules/selection_screen_texts_missing.js +31 -10
- package/package.json +1 -1
|
@@ -480,16 +480,16 @@ class BasicTypes {
|
|
|
480
480
|
options.primaryKey.type = basic_1.TableAccessType.standard;
|
|
481
481
|
return new Types.TableType(structure, options);
|
|
482
482
|
}
|
|
483
|
-
else if (typename && (text
|
|
484
|
-
|| text.startsWith("TYPE TABLE FOR READ ")
|
|
485
|
-
|| text.startsWith("TYPE TABLE FOR DELETE ")
|
|
486
|
-
|| text.startsWith("TYPE TABLE FOR UPDATE "))) {
|
|
483
|
+
else if (typename && this.isRAPTableFor(text)) {
|
|
487
484
|
const name = typename.concatTokens();
|
|
488
485
|
const ddlsName = this.getRAPBaseEntityName(name);
|
|
489
486
|
const type = (_d = this.input.scope.getDDIC().lookupDDLS(ddlsName)) === null || _d === void 0 ? void 0 : _d.type;
|
|
490
487
|
if (type) {
|
|
491
488
|
return new Types.TableType(basic_1.VoidType.get("RAP-TODO"), options);
|
|
492
489
|
}
|
|
490
|
+
else if (this.isRAPDerivedEntityName(name)) {
|
|
491
|
+
return Types.VoidType.get(name);
|
|
492
|
+
}
|
|
493
493
|
else if (this.input.scope.getDDIC().inErrorNamespace(ddlsName)) {
|
|
494
494
|
return new Types.UnknownType(`DDLS ${ddlsName} not found`);
|
|
495
495
|
}
|
|
@@ -501,7 +501,7 @@ class BasicTypes {
|
|
|
501
501
|
return this.parseType(node, name);
|
|
502
502
|
}
|
|
503
503
|
parseType(node, qualifiedName) {
|
|
504
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
504
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
505
505
|
const typeName = node.findFirstExpression(Expressions.TypeName);
|
|
506
506
|
let text = (_a = node.findFirstExpression(Expressions.Type)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
|
|
507
507
|
if (text === undefined) {
|
|
@@ -514,7 +514,10 @@ class BasicTypes {
|
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
516
|
if (text === undefined) {
|
|
517
|
-
text = (_d = node.findFirstExpression(Expressions.
|
|
517
|
+
text = (_d = node.findFirstExpression(Expressions.TypeStructure)) === null || _d === void 0 ? void 0 : _d.concatTokens().toUpperCase();
|
|
518
|
+
}
|
|
519
|
+
if (text === undefined) {
|
|
520
|
+
text = (_e = node.findFirstExpression(Expressions.FormParamType)) === null || _e === void 0 ? void 0 : _e.concatTokens().toUpperCase();
|
|
518
521
|
}
|
|
519
522
|
if (text === undefined
|
|
520
523
|
&& node.get() instanceof Statements.Parameter
|
|
@@ -525,8 +528,11 @@ class BasicTypes {
|
|
|
525
528
|
text = "TYPE";
|
|
526
529
|
}
|
|
527
530
|
let found = undefined;
|
|
528
|
-
if (
|
|
529
|
-
|
|
531
|
+
if (this.isRAPTypeStructure(text)) {
|
|
532
|
+
return Types.VoidType.get((_f = node.findFirstExpression(Expressions.TypeStructure)) === null || _f === void 0 ? void 0 : _f.concatTokens());
|
|
533
|
+
}
|
|
534
|
+
else if (text.startsWith("LIKE LINE OF ")) {
|
|
535
|
+
const name = (_g = node.findFirstExpression(Expressions.FieldChain)) === null || _g === void 0 ? void 0 : _g.concatTokens();
|
|
530
536
|
let e = node.findFirstExpression(Expressions.Type);
|
|
531
537
|
if (e === undefined) {
|
|
532
538
|
e = node.findFirstExpression(Expressions.FormParamType);
|
|
@@ -549,7 +555,7 @@ class BasicTypes {
|
|
|
549
555
|
}
|
|
550
556
|
}
|
|
551
557
|
else if (text.startsWith("LIKE REF TO ")) {
|
|
552
|
-
const name = (
|
|
558
|
+
const name = (_h = node.findFirstExpression(Expressions.FieldChain)) === null || _h === void 0 ? void 0 : _h.concatTokens();
|
|
553
559
|
const type = this.resolveLikeName(node.findFirstExpression(Expressions.Type), false);
|
|
554
560
|
if (type === undefined) {
|
|
555
561
|
return new Types.UnknownType("Type error, could not resolve \"" + name + "\", parseType");
|
|
@@ -640,7 +646,7 @@ class BasicTypes {
|
|
|
640
646
|
}
|
|
641
647
|
}
|
|
642
648
|
if (text.includes(" WITH INDICATORS ")) {
|
|
643
|
-
const componentName = (
|
|
649
|
+
const componentName = (_k = (_j = node.findFirstExpression(Expressions.Type)) === null || _j === void 0 ? void 0 : _j.findDirectExpression(Expressions.ComponentName)) === null || _k === void 0 ? void 0 : _k.concatTokens().toUpperCase();
|
|
644
650
|
if (componentName === undefined) {
|
|
645
651
|
throw new Error("parseType, componentName expected");
|
|
646
652
|
}
|
|
@@ -666,12 +672,38 @@ class BasicTypes {
|
|
|
666
672
|
getRAPBaseEntityName(name) {
|
|
667
673
|
const association = name.indexOf("\\_");
|
|
668
674
|
const path = name.indexOf("\\\\");
|
|
669
|
-
|
|
675
|
+
const action = name.indexOf("~");
|
|
676
|
+
if (association === -1 && path === -1 && action === -1) {
|
|
670
677
|
return name;
|
|
671
678
|
}
|
|
672
|
-
const
|
|
679
|
+
const candidates = [association, path, action].filter(i => i !== -1);
|
|
680
|
+
const splitAt = Math.min(...candidates);
|
|
673
681
|
return name.substring(0, splitAt);
|
|
674
682
|
}
|
|
683
|
+
isRAPDerivedEntityName(name) {
|
|
684
|
+
return name.includes("\\") || name.includes("~");
|
|
685
|
+
}
|
|
686
|
+
isRAPTableFor(text) {
|
|
687
|
+
return text.startsWith("TYPE TABLE FOR ACTION IMPORT ")
|
|
688
|
+
|| text.startsWith("TYPE TABLE FOR ACTION RESULT ")
|
|
689
|
+
|| text.startsWith("TYPE TABLE FOR CREATE ")
|
|
690
|
+
|| text.startsWith("TYPE TABLE FOR DELETE ")
|
|
691
|
+
|| text.startsWith("TYPE TABLE FOR DETERMINATION ")
|
|
692
|
+
|| text.startsWith("TYPE TABLE FOR EVENT ")
|
|
693
|
+
|| text.startsWith("TYPE TABLE FOR FAILED ")
|
|
694
|
+
|| text.startsWith("TYPE TABLE FOR FAILED EARLY ")
|
|
695
|
+
|| text.startsWith("TYPE TABLE FOR LOCK ")
|
|
696
|
+
|| text.startsWith("TYPE TABLE FOR READ ")
|
|
697
|
+
|| text.startsWith("TYPE TABLE FOR READ IMPORT ")
|
|
698
|
+
|| text.startsWith("TYPE TABLE FOR READ RESULT ")
|
|
699
|
+
|| text.startsWith("TYPE TABLE FOR REPORTED EARLY ")
|
|
700
|
+
|| text.startsWith("TYPE TABLE FOR UPDATE ");
|
|
701
|
+
}
|
|
702
|
+
isRAPTypeStructure(text) {
|
|
703
|
+
return text.startsWith("TYPE STRUCTURE FOR ")
|
|
704
|
+
|| text.startsWith("TYPE RESPONSE FOR ")
|
|
705
|
+
|| text.startsWith("TYPE REQUEST FOR CHANGE ");
|
|
706
|
+
}
|
|
675
707
|
// todo, rewrite this method
|
|
676
708
|
resolveTypeChain(expr) {
|
|
677
709
|
var _a, _b, _c, _d;
|
|
@@ -40,6 +40,7 @@ const source_1 = require("../expressions/source");
|
|
|
40
40
|
const component_compare_1 = require("../expressions/component_compare");
|
|
41
41
|
const component_cond_1 = require("../expressions/component_cond");
|
|
42
42
|
const basic_1 = require("../../types/basic");
|
|
43
|
+
const _syntax_input_1 = require("../_syntax_input");
|
|
43
44
|
class DeleteInternal {
|
|
44
45
|
runSyntax(node, input) {
|
|
45
46
|
var _a;
|
|
@@ -50,7 +51,8 @@ class DeleteInternal {
|
|
|
50
51
|
const target = node.findDirectExpression(Expressions.Target);
|
|
51
52
|
if (target) {
|
|
52
53
|
let tabl = undefined;
|
|
53
|
-
|
|
54
|
+
const localVariable = input.scope.findVariable(target.concatTokens());
|
|
55
|
+
if (localVariable === undefined && node.getChildren().length === 5 && node.getChildren()[2].concatTokens().toUpperCase() === "FROM") {
|
|
54
56
|
// it might be a database table
|
|
55
57
|
tabl = (_a = input.scope.getDDIC()) === null || _a === void 0 ? void 0 : _a.lookupTableOrView(target.concatTokens());
|
|
56
58
|
if (tabl) {
|
|
@@ -59,6 +61,14 @@ class DeleteInternal {
|
|
|
59
61
|
}
|
|
60
62
|
if (tabl === undefined) {
|
|
61
63
|
targetType = target_1.Target.runSyntax(target, input);
|
|
64
|
+
if (node.findDirectTokenByText("TABLE") === undefined
|
|
65
|
+
&& node.findDirectTokenByText("FROM")
|
|
66
|
+
&& targetType instanceof basic_1.TableType
|
|
67
|
+
&& targetType.getAccessType() === basic_1.TableAccessType.hashed) {
|
|
68
|
+
const message = "Implicit or explicit index operation on hashed table is not possible";
|
|
69
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
62
72
|
if (targetType instanceof basic_1.TableType) {
|
|
63
73
|
targetType = targetType.getRowType();
|
|
64
74
|
}
|
package/build/src/registry.js
CHANGED
|
@@ -18,6 +18,9 @@ class SelectionScreenTextsMissing {
|
|
|
18
18
|
key: "selection_screen_texts_missing",
|
|
19
19
|
title: "Selection screen texts missing",
|
|
20
20
|
shortDescription: `Checks that selection screen parameters and select-options have selection texts`,
|
|
21
|
+
extendedInformation: `Excludes parameters and select-options that:
|
|
22
|
+
* are inside a "SELECTION-SCREEN BEGIN OF LINE" block
|
|
23
|
+
* have the addition "NO-DISPLAY"`,
|
|
21
24
|
};
|
|
22
25
|
}
|
|
23
26
|
getConfig() {
|
|
@@ -43,7 +46,7 @@ class SelectionScreenTextsMissing {
|
|
|
43
46
|
this.checkFile(obj.getMainABAPFile(), selTexts, output, checked);
|
|
44
47
|
return output;
|
|
45
48
|
}
|
|
46
|
-
checkFile(file, selTexts, output, checked) {
|
|
49
|
+
checkFile(file, selTexts, output, checked, mainProgName = undefined) {
|
|
47
50
|
if (file === undefined) {
|
|
48
51
|
return;
|
|
49
52
|
}
|
|
@@ -51,26 +54,44 @@ class SelectionScreenTextsMissing {
|
|
|
51
54
|
return;
|
|
52
55
|
}
|
|
53
56
|
checked.add(file.getFilename());
|
|
57
|
+
let inLine = false;
|
|
54
58
|
for (const stat of file.getStatements()) {
|
|
55
59
|
const s = stat.get();
|
|
56
|
-
if (s instanceof statements_1.
|
|
57
|
-
const
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
if (s instanceof statements_1.SelectionScreen) {
|
|
61
|
+
const tokens = stat.concatTokens().toUpperCase();
|
|
62
|
+
if (tokens.includes("BEGIN OF LINE")) {
|
|
63
|
+
inLine = true;
|
|
64
|
+
}
|
|
65
|
+
else if (tokens.includes("END OF LINE")) {
|
|
66
|
+
// known issue: doesn't support BEGIN and END OF LINE span across several includes (not seen a lot in the wild)
|
|
67
|
+
inLine = false;
|
|
63
68
|
}
|
|
69
|
+
continue;
|
|
64
70
|
}
|
|
65
|
-
|
|
71
|
+
if (s instanceof statements_1.Include) {
|
|
66
72
|
const nameNode = stat.findFirstExpression(expressions_1.IncludeName);
|
|
67
73
|
if (nameNode) {
|
|
68
74
|
const inclName = nameNode.getFirstToken().getStr().toUpperCase();
|
|
69
75
|
const inclObj = this.reg.getObject("PROG", inclName);
|
|
70
76
|
if (inclObj) {
|
|
71
|
-
this.checkFile(inclObj.getMainABAPFile(), selTexts, output, checked);
|
|
77
|
+
this.checkFile(inclObj.getMainABAPFile(), selTexts, output, checked, mainProgName !== null && mainProgName !== void 0 ? mainProgName : file.getFilename());
|
|
72
78
|
}
|
|
73
79
|
}
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (inLine || !(s instanceof statements_1.Parameter || s instanceof statements_1.SelectOption)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (stat.concatTokens().toUpperCase().includes("NO-DISPLAY")) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const fieldNode = stat.findFirstExpression(expressions_1.FieldSub);
|
|
89
|
+
if (fieldNode) {
|
|
90
|
+
const fieldName = fieldNode.getFirstToken().getStr().toUpperCase();
|
|
91
|
+
if (selTexts[fieldName] === undefined) {
|
|
92
|
+
const suffix = mainProgName ? `, ${mainProgName}` : ``;
|
|
93
|
+
output.push(issue_1.Issue.atToken(file, fieldNode.getFirstToken(), `Selection text missing for "${fieldName}"${suffix}`, this.getMetadata().key, this.conf.severity));
|
|
94
|
+
}
|
|
74
95
|
}
|
|
75
96
|
}
|
|
76
97
|
}
|