@abaplint/core 2.120.68 → 2.120.69
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 +9 -0
- package/build/src/abap/5_syntax/expressions/form_param.js +3 -0
- package/build/src/abap/5_syntax/expressions/method_param.js +3 -0
- package/build/src/abap/5_syntax/statements/create_object.js +2 -2
- package/build/src/abap/types/basic/index.js +1 -0
- package/build/src/abap/types/basic/ngeneric_type.js +23 -0
- package/build/src/registry.js +1 -1
- package/build/src/rules/downport.js +52 -0
- package/build/src/rules/rfc_error_handling.js +14 -9
- package/package.json +1 -1
package/build/abaplint.d.ts
CHANGED
|
@@ -513,6 +513,7 @@ declare namespace BasicTypes {
|
|
|
513
513
|
HexType,
|
|
514
514
|
IntegerType,
|
|
515
515
|
Integer8Type,
|
|
516
|
+
NGenericType,
|
|
516
517
|
NumericGenericType,
|
|
517
518
|
NumericType,
|
|
518
519
|
ObjectReferenceType,
|
|
@@ -5133,6 +5134,14 @@ declare class NewPage implements IStatement {
|
|
|
5133
5134
|
getMatcher(): IStatementRunnable;
|
|
5134
5135
|
}
|
|
5135
5136
|
|
|
5137
|
+
declare class NGenericType extends NumericType {
|
|
5138
|
+
private static readonly singleton;
|
|
5139
|
+
static get(): NGenericType;
|
|
5140
|
+
private constructor();
|
|
5141
|
+
toText(): string;
|
|
5142
|
+
isGeneric(): boolean;
|
|
5143
|
+
}
|
|
5144
|
+
|
|
5136
5145
|
declare namespace Nodes {
|
|
5137
5146
|
export {
|
|
5138
5147
|
ExpressionNode,
|
|
@@ -52,6 +52,9 @@ class FormParam {
|
|
|
52
52
|
else if (typeName === "P" && bfound instanceof basic_1.PackedType) {
|
|
53
53
|
bfound = basic_1.PGenericType.get();
|
|
54
54
|
}
|
|
55
|
+
else if (typeName === "N" && bfound instanceof basic_1.NumericType) {
|
|
56
|
+
bfound = basic_1.NGenericType.get();
|
|
57
|
+
}
|
|
55
58
|
}
|
|
56
59
|
if (nameToken && bfound) {
|
|
57
60
|
return new _typed_identifier_1.TypedIdentifier(nameToken, input.filename, bfound, ["form_parameter" /* IdentifierMeta.FormParameter */]);
|
|
@@ -70,6 +70,9 @@ class MethodParam {
|
|
|
70
70
|
else if (concat === "TYPE P" || concat.startsWith("TYPE P ")) {
|
|
71
71
|
return new _typed_identifier_1.TypedIdentifier(name.getFirstToken(), input.filename, basic_1.PGenericType.get(), meta);
|
|
72
72
|
}
|
|
73
|
+
else if (concat === "TYPE N" || concat.startsWith("TYPE N ")) {
|
|
74
|
+
return new _typed_identifier_1.TypedIdentifier(name.getFirstToken(), input.filename, basic_1.NGenericType.get(), meta);
|
|
75
|
+
}
|
|
73
76
|
const found = new basic_types_1.BasicTypes(input).parseType(type);
|
|
74
77
|
if (found) {
|
|
75
78
|
return new _typed_identifier_1.TypedIdentifier(name.getFirstToken(), input.filename, found, meta);
|
|
@@ -203,9 +203,9 @@ class CreateObject {
|
|
|
203
203
|
if (name === undefined) {
|
|
204
204
|
continue;
|
|
205
205
|
}
|
|
206
|
-
const source = p.findDirectExpression(Expressions.Source);
|
|
207
|
-
const sourceType = source_1.Source.runSyntax(source, input);
|
|
208
206
|
const found = allImporting === null || allImporting === void 0 ? void 0 : allImporting.find(p => p.getName().toUpperCase() === name);
|
|
207
|
+
const source = p.findDirectExpression(Expressions.Source);
|
|
208
|
+
const sourceType = source_1.Source.runSyntax(source, input, found === null || found === void 0 ? void 0 : found.getType());
|
|
209
209
|
if (found === undefined) {
|
|
210
210
|
const message = `constructor parameter "${name}" does not exist`;
|
|
211
211
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
@@ -32,6 +32,7 @@ __exportStar(require("./generic_object_reference_type"), exports);
|
|
|
32
32
|
__exportStar(require("./hex_type"), exports);
|
|
33
33
|
__exportStar(require("./integer_type"), exports);
|
|
34
34
|
__exportStar(require("./integer8_type"), exports);
|
|
35
|
+
__exportStar(require("./ngeneric_type"), exports);
|
|
35
36
|
__exportStar(require("./numeric_generic_type"), exports);
|
|
36
37
|
__exportStar(require("./numeric_type"), exports);
|
|
37
38
|
__exportStar(require("./object_reference_type"), exports);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NGenericType = void 0;
|
|
4
|
+
const numeric_type_1 = require("./numeric_type");
|
|
5
|
+
// "TYPE n" of a method or FORM parameter, where no length can be given.
|
|
6
|
+
// It is a NumericType, so everything that handles n keeps treating it as such
|
|
7
|
+
class NGenericType extends numeric_type_1.NumericType {
|
|
8
|
+
static get() {
|
|
9
|
+
return this.singleton;
|
|
10
|
+
}
|
|
11
|
+
constructor() {
|
|
12
|
+
super(1);
|
|
13
|
+
}
|
|
14
|
+
toText() {
|
|
15
|
+
return "```n```";
|
|
16
|
+
}
|
|
17
|
+
isGeneric() {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.NGenericType = NGenericType;
|
|
22
|
+
NGenericType.singleton = new NGenericType();
|
|
23
|
+
//# sourceMappingURL=ngeneric_type.js.map
|
package/build/src/registry.js
CHANGED
|
@@ -2419,8 +2419,17 @@ ${indentation} output = ${uniqueName}.\n`;
|
|
|
2419
2419
|
const extra = (valueBody === null || valueBody === void 0 ? void 0 : valueBody.findDirectExpression(Expressions.For)) ? " " : "";
|
|
2420
2420
|
data = indentation + extra + `DATA ${structureName} LIKE LINE OF ${uniqueName}.\n`;
|
|
2421
2421
|
}
|
|
2422
|
+
// all rows are built in the same work area, a component a row leaves out must be initial,
|
|
2423
|
+
// not what an earlier row (or an earlier pass of a surrounding loop) put there
|
|
2424
|
+
const clearRows = valueBody !== undefined && this.valueRowsNeedClear(valueBody);
|
|
2425
|
+
const prefix = [];
|
|
2422
2426
|
for (const a of (valueBody === null || valueBody === void 0 ? void 0 : valueBody.getChildren()) || []) {
|
|
2423
2427
|
if (a.get() instanceof Expressions.FieldAssignment) {
|
|
2428
|
+
if (clearRows === true) {
|
|
2429
|
+
// the shared prefix applies to every following row, re-applied after each CLEAR
|
|
2430
|
+
prefix.push(a.concatTokens());
|
|
2431
|
+
continue;
|
|
2432
|
+
}
|
|
2424
2433
|
if (added === false) {
|
|
2425
2434
|
body += data;
|
|
2426
2435
|
added = true;
|
|
@@ -2444,6 +2453,16 @@ ${indentation} output = ${uniqueName}.\n`;
|
|
|
2444
2453
|
}
|
|
2445
2454
|
if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.ValueBodyLine) {
|
|
2446
2455
|
let skip = false;
|
|
2456
|
+
if (clearRows === true && this.isStructuredValueRow(a)) {
|
|
2457
|
+
if (added === false) {
|
|
2458
|
+
body += data;
|
|
2459
|
+
added = true;
|
|
2460
|
+
}
|
|
2461
|
+
body += indentation + `CLEAR ${structureName}.\n`;
|
|
2462
|
+
for (const p of prefix) {
|
|
2463
|
+
body += indentation + structureName + "-" + p + ".\n";
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2447
2466
|
for (const b of (a === null || a === void 0 ? void 0 : a.getChildren()) || []) {
|
|
2448
2467
|
if (b.get() instanceof Expressions.FieldAssignment) {
|
|
2449
2468
|
if (added === false) {
|
|
@@ -2522,6 +2541,39 @@ ${indentation} output = ${uniqueName}.\n`;
|
|
|
2522
2541
|
}
|
|
2523
2542
|
return undefined;
|
|
2524
2543
|
}
|
|
2544
|
+
/** a row that is built in the work area, ie. not "( source )" or "( LINES OF source )" */
|
|
2545
|
+
isStructuredValueRow(row) {
|
|
2546
|
+
return row.findDirectExpression(Expressions.Source) === undefined
|
|
2547
|
+
&& row.findDirectExpression(Expressions.ValueBodyLines) === undefined;
|
|
2548
|
+
}
|
|
2549
|
+
/** true if a row can observe a component that an earlier row, or an earlier pass of a surrounding loop,
|
|
2550
|
+
* left in the shared work area. Not the case if all rows assign the same components, and the shared
|
|
2551
|
+
* prefix is not changed between rows, eg. FOR rows or "( a = 1 b = 2 ) ( a = 3 b = 4 )" */
|
|
2552
|
+
valueRowsNeedClear(valueBody) {
|
|
2553
|
+
let shape = undefined;
|
|
2554
|
+
let rowSeen = false;
|
|
2555
|
+
for (const c of valueBody.getChildren()) {
|
|
2556
|
+
if (c.get() instanceof Expressions.FieldAssignment) {
|
|
2557
|
+
if (rowSeen === true) {
|
|
2558
|
+
return true;
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
else if (c instanceof nodes_1.ExpressionNode
|
|
2562
|
+
&& c.get() instanceof Expressions.ValueBodyLine
|
|
2563
|
+
&& this.isStructuredValueRow(c)) {
|
|
2564
|
+
rowSeen = true;
|
|
2565
|
+
const current = c.findDirectExpressions(Expressions.FieldAssignment)
|
|
2566
|
+
.map(f => { var _a; return (_a = f.findDirectExpression(Expressions.FieldSub)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase().replace(/\s/g, ""); })
|
|
2567
|
+
.sort()
|
|
2568
|
+
.join(",");
|
|
2569
|
+
if (shape !== undefined && shape !== current) {
|
|
2570
|
+
return true;
|
|
2571
|
+
}
|
|
2572
|
+
shape = current;
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
return false;
|
|
2576
|
+
}
|
|
2525
2577
|
outlineLet(node, indentation, highSyntax, lowFile) {
|
|
2526
2578
|
var _a;
|
|
2527
2579
|
let ret = "";
|
|
@@ -54,7 +54,9 @@ class RFCErrorHandling extends _abap_rule_1.ABAPRule {
|
|
|
54
54
|
title: "RFC error handling",
|
|
55
55
|
tags: [_irule_1.RuleTag.SingleFile],
|
|
56
56
|
shortDescription: `Checks that exceptions 'system_failure' and 'communication_failure' are handled in RFC calls`,
|
|
57
|
-
extendedInformation: `
|
|
57
|
+
extendedInformation: `RESOURCE_FAILURE is also required for asynchronous calls with DESTINATION IN GROUP.
|
|
58
|
+
|
|
59
|
+
https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abenrfc_exception.html`,
|
|
58
60
|
badExample: `CALL FUNCTION 'ZRFC'
|
|
59
61
|
DESTINATION lv_rfc.`,
|
|
60
62
|
goodExample: `CALL FUNCTION 'ZRFC'
|
|
@@ -62,12 +64,12 @@ class RFCErrorHandling extends _abap_rule_1.ABAPRule {
|
|
|
62
64
|
EXCEPTIONS
|
|
63
65
|
system_failure = 1 MESSAGE msg
|
|
64
66
|
communication_failure = 2 MESSAGE msg
|
|
65
|
-
|
|
66
|
-
OTHERS = 4.`,
|
|
67
|
+
OTHERS = 3.`,
|
|
67
68
|
};
|
|
68
69
|
}
|
|
69
|
-
getMessage() {
|
|
70
|
-
return "RFC error handling: At least one unhandled exception from SYSTEM_FAILURE, COMMUNICATION_FAILURE
|
|
70
|
+
getMessage(requireResourceFailure) {
|
|
71
|
+
return "RFC error handling: At least one unhandled exception from SYSTEM_FAILURE, COMMUNICATION_FAILURE"
|
|
72
|
+
+ (requireResourceFailure ? ", RESOURCE_FAILURE" : "");
|
|
71
73
|
}
|
|
72
74
|
getConfig() {
|
|
73
75
|
return this.conf;
|
|
@@ -82,12 +84,15 @@ class RFCErrorHandling extends _abap_rule_1.ABAPRule {
|
|
|
82
84
|
if (!(stat.get() instanceof Statements.CallFunction)) {
|
|
83
85
|
continue;
|
|
84
86
|
}
|
|
85
|
-
|
|
87
|
+
const destination = stat.findFirstExpression(Expressions.Destination);
|
|
88
|
+
if (destination === undefined) {
|
|
86
89
|
continue;
|
|
87
90
|
}
|
|
91
|
+
const requireResourceFailure = stat.findDirectTokenByText("STARTING") !== undefined
|
|
92
|
+
&& destination.findDirectTokenByText("GROUP") !== undefined;
|
|
88
93
|
const list = stat.findFirstExpression(Expressions.ParameterListExceptions);
|
|
89
94
|
if (list === undefined) {
|
|
90
|
-
const issue = issue_1.Issue.atToken(file, token, this.getMessage(), this.getMetadata().key, this.conf.severity);
|
|
95
|
+
const issue = issue_1.Issue.atToken(file, token, this.getMessage(requireResourceFailure), this.getMetadata().key, this.conf.severity);
|
|
91
96
|
output.push(issue);
|
|
92
97
|
continue;
|
|
93
98
|
}
|
|
@@ -98,8 +103,8 @@ class RFCErrorHandling extends _abap_rule_1.ABAPRule {
|
|
|
98
103
|
}
|
|
99
104
|
if (names.indexOf("SYSTEM_FAILURE") < 0
|
|
100
105
|
|| names.indexOf("COMMUNICATION_FAILURE") < 0
|
|
101
|
-
|| names.indexOf("RESOURCE_FAILURE") < 0) {
|
|
102
|
-
const issue = issue_1.Issue.atToken(file, token, this.getMessage(), this.getMetadata().key, this.conf.severity);
|
|
106
|
+
|| (requireResourceFailure && names.indexOf("RESOURCE_FAILURE") < 0)) {
|
|
107
|
+
const issue = issue_1.Issue.atToken(file, token, this.getMessage(requireResourceFailure), this.getMetadata().key, this.conf.severity);
|
|
103
108
|
output.push(issue);
|
|
104
109
|
continue;
|
|
105
110
|
}
|