@abaplint/core 2.119.67 → 2.120.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.
- package/build/abaplint.d.ts +2 -2
- package/build/src/abap/5_syntax/_current_scope.js +1 -1
- package/build/src/abap/5_syntax/expressions/_check_offset_length.js +59 -0
- package/build/src/abap/5_syntax/expressions/method_call_param.js +2 -12
- package/build/src/abap/5_syntax/expressions/method_parameters.js +20 -6
- package/build/src/abap/5_syntax/statements/catch.js +17 -1
- package/build/src/cds/expressions/cds_define_abstract.js +1 -1
- package/build/src/cds/expressions/cds_define_custom.js +1 -1
- package/build/src/cds/expressions/cds_define_external_entity.js +1 -1
- package/build/src/cds/expressions/cds_define_hierarchy.js +1 -1
- package/build/src/cds/expressions/cds_define_projection.js +1 -1
- package/build/src/cds/expressions/cds_define_table_entity.js +1 -1
- package/build/src/config.js +1 -1
- package/build/src/registry.js +1 -1
- package/build/src/rules/clear_exporting_parameters.js +254 -0
- package/build/src/rules/downport.js +9 -9
- package/build/src/rules/index.js +2 -0
- package/build/src/rules/inline_data_old_versions.js +1 -1
- package/build/src/rules/no_inline_in_optional_branches.js +1 -1
- package/build/src/rules/redundant_conversion.js +253 -0
- package/build/src/rules/sql_escape_host_variables.js +1 -1
- package/build/src/rules/use_line_exists.js +1 -1
- package/package.json +1 -1
package/build/abaplint.d.ts
CHANGED
|
@@ -1491,7 +1491,7 @@ export declare class Config implements IConfiguration {
|
|
|
1491
1491
|
getGlobal(): IGlobalConfig;
|
|
1492
1492
|
getSyntaxSetttings(): ISyntaxSettings;
|
|
1493
1493
|
getRelease(): ABAPRelease;
|
|
1494
|
-
|
|
1494
|
+
isOpenABAP(): boolean;
|
|
1495
1495
|
getVersion(): Version;
|
|
1496
1496
|
getLanguageVersion(): LanguageVersion;
|
|
1497
1497
|
private checkVersion;
|
|
@@ -3475,7 +3475,7 @@ export declare interface IConfiguration {
|
|
|
3475
3475
|
getVersion(): Version;
|
|
3476
3476
|
getRelease(): ABAPRelease;
|
|
3477
3477
|
getLanguageVersion(): LanguageVersion;
|
|
3478
|
-
|
|
3478
|
+
isOpenABAP(): boolean;
|
|
3479
3479
|
getSyntaxSetttings(): ISyntaxSettings;
|
|
3480
3480
|
readByRule(rule: string): any;
|
|
3481
3481
|
readByKey(rule: string, key: string): any;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.checkOffsetLength = checkOffsetLength;
|
|
37
|
+
const Expressions = __importStar(require("../../2_statements/expressions"));
|
|
38
|
+
const basic_1 = require("../../types/basic");
|
|
39
|
+
const _syntax_input_1 = require("../_syntax_input");
|
|
40
|
+
const _builtin_1 = require("../_builtin");
|
|
41
|
+
// Offsets or lengths cannot be specified for STRING or XSTRING fields
|
|
42
|
+
// passed as a method parameter source. Returns true if an issue was reported.
|
|
43
|
+
function checkOffsetLength(source, sourceType, method, input) {
|
|
44
|
+
const chain = source.findDirectExpression(Expressions.FieldChain);
|
|
45
|
+
const isCalculated = source.findDirectExpression(Expressions.Source) !== undefined;
|
|
46
|
+
const hasOffsetOrLength = chain !== undefined
|
|
47
|
+
&& isCalculated === false
|
|
48
|
+
&& (chain.findDirectExpression(Expressions.FieldOffset) !== undefined
|
|
49
|
+
|| chain.findDirectExpression(Expressions.FieldLength) !== undefined);
|
|
50
|
+
if (hasOffsetOrLength
|
|
51
|
+
&& !(method instanceof _builtin_1.BuiltInMethod)
|
|
52
|
+
&& (sourceType instanceof basic_1.StringType || sourceType instanceof basic_1.XStringType)) {
|
|
53
|
+
const message = `Offsets or lengths cannot be specified for fields of type "STRING" or "XSTRING" in the current statement`;
|
|
54
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, source.getFirstToken(), message));
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=_check_offset_length.js.map
|
|
@@ -43,7 +43,7 @@ const source_1 = require("./source");
|
|
|
43
43
|
const _type_utils_1 = require("../_type_utils");
|
|
44
44
|
const _syntax_input_1 = require("../_syntax_input");
|
|
45
45
|
const constant_1 = require("./constant");
|
|
46
|
-
const
|
|
46
|
+
const _check_offset_length_1 = require("./_check_offset_length");
|
|
47
47
|
class MethodCallParam {
|
|
48
48
|
static runSyntax(node, input, method) {
|
|
49
49
|
if (!(node.get() instanceof Expressions.MethodCallParam)) {
|
|
@@ -104,17 +104,7 @@ class MethodCallParam {
|
|
|
104
104
|
let sourceType = undefined;
|
|
105
105
|
if (child.get() instanceof Expressions.Source) {
|
|
106
106
|
sourceType = source_1.Source.runSyntax(child, input, targetType);
|
|
107
|
-
|
|
108
|
-
const isCalculated = child.findDirectExpression(Expressions.Source) !== undefined;
|
|
109
|
-
const hasOffsetOrLength = chain !== undefined
|
|
110
|
-
&& isCalculated === false
|
|
111
|
-
&& (chain.findDirectExpression(Expressions.FieldOffset) !== undefined
|
|
112
|
-
|| chain.findDirectExpression(Expressions.FieldLength) !== undefined);
|
|
113
|
-
if (hasOffsetOrLength
|
|
114
|
-
&& !(method instanceof _builtin_1.BuiltInMethod)
|
|
115
|
-
&& (sourceType instanceof basic_1.StringType || sourceType instanceof basic_1.XStringType)) {
|
|
116
|
-
const message = `Offsets or lengths cannot be specified for fields of type "STRING" or "XSTRING" in the current statement`;
|
|
117
|
-
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, child.getFirstToken(), message));
|
|
107
|
+
if ((0, _check_offset_length_1.checkOffsetLength)(child, sourceType, method, input)) {
|
|
118
108
|
return;
|
|
119
109
|
}
|
|
120
110
|
}
|
|
@@ -45,6 +45,7 @@ const _syntax_input_1 = require("../_syntax_input");
|
|
|
45
45
|
const assert_error_1 = require("../assert_error");
|
|
46
46
|
const field_chain_1 = require("./field_chain");
|
|
47
47
|
const _reference_1 = require("../_reference");
|
|
48
|
+
const _check_offset_length_1 = require("./_check_offset_length");
|
|
48
49
|
class MethodParameters {
|
|
49
50
|
constructor() {
|
|
50
51
|
this.requiredParameters = undefined;
|
|
@@ -215,7 +216,6 @@ class MethodParameters {
|
|
|
215
216
|
}
|
|
216
217
|
}
|
|
217
218
|
parameterListS(node, input, method) {
|
|
218
|
-
var _a;
|
|
219
219
|
if (node === undefined) {
|
|
220
220
|
return [];
|
|
221
221
|
}
|
|
@@ -223,14 +223,21 @@ class MethodParameters {
|
|
|
223
223
|
throw new assert_error_1.AssertError("parameterListS, unexpected node");
|
|
224
224
|
}
|
|
225
225
|
const ret = [];
|
|
226
|
+
const supplied = new Set();
|
|
226
227
|
for (const c of node.getChildren()) {
|
|
227
228
|
if (!(c.get() instanceof Expressions.ParameterS) || !(c instanceof nodes_1.ExpressionNode)) {
|
|
228
229
|
throw new assert_error_1.AssertError("parameterListS, unexpected node, child");
|
|
229
230
|
}
|
|
230
|
-
const
|
|
231
|
-
|
|
231
|
+
const nameNode = c.findDirectExpression(Expressions.ParameterName);
|
|
232
|
+
const name = nameNode === null || nameNode === void 0 ? void 0 : nameNode.getFirstToken().getStr().toUpperCase();
|
|
233
|
+
if (name === undefined || nameNode === undefined) {
|
|
232
234
|
throw new assert_error_1.AssertError("parameterListS, no name determined");
|
|
233
235
|
}
|
|
236
|
+
if (supplied.has(name)) {
|
|
237
|
+
const message = `Method parameter "${name}" is supplied more than once`;
|
|
238
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, nameNode.getFirstToken(), message));
|
|
239
|
+
}
|
|
240
|
+
supplied.add(name);
|
|
234
241
|
const source = c.findDirectExpression(Expressions.Source);
|
|
235
242
|
if (source === undefined) {
|
|
236
243
|
throw new assert_error_1.AssertError("parameterListS, no source found");
|
|
@@ -248,6 +255,7 @@ class MethodParameters {
|
|
|
248
255
|
targetType = method;
|
|
249
256
|
}
|
|
250
257
|
let sourceType = source_1.Source.runSyntax(source, input, targetType);
|
|
258
|
+
(0, _check_offset_length_1.checkOffsetLength)(source, sourceType, method, input);
|
|
251
259
|
if (sourceType === undefined) {
|
|
252
260
|
if (method instanceof basic_1.VoidType) {
|
|
253
261
|
sourceType = method;
|
|
@@ -263,7 +271,6 @@ class MethodParameters {
|
|
|
263
271
|
return ret;
|
|
264
272
|
}
|
|
265
273
|
parameterListT(node, input) {
|
|
266
|
-
var _a;
|
|
267
274
|
if (node === undefined) {
|
|
268
275
|
return [];
|
|
269
276
|
}
|
|
@@ -271,14 +278,21 @@ class MethodParameters {
|
|
|
271
278
|
throw new assert_error_1.AssertError("parameterListT, unexpected node");
|
|
272
279
|
}
|
|
273
280
|
const ret = [];
|
|
281
|
+
const supplied = new Set();
|
|
274
282
|
for (const c of node.getChildren()) {
|
|
275
283
|
if (!(c.get() instanceof Expressions.ParameterT) || !(c instanceof nodes_1.ExpressionNode)) {
|
|
276
284
|
throw new assert_error_1.AssertError("parameterListT, unexpected node, child");
|
|
277
285
|
}
|
|
278
|
-
const
|
|
279
|
-
|
|
286
|
+
const nameNode = c.findDirectExpression(Expressions.ParameterName);
|
|
287
|
+
const name = nameNode === null || nameNode === void 0 ? void 0 : nameNode.getFirstToken().getStr().toUpperCase();
|
|
288
|
+
if (name === undefined || nameNode === undefined) {
|
|
280
289
|
throw new assert_error_1.AssertError("parameterListT, no name determined");
|
|
281
290
|
}
|
|
291
|
+
if (supplied.has(name)) {
|
|
292
|
+
const message = `Method parameter "${name}" is supplied more than once`;
|
|
293
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, nameNode.getFirstToken(), message));
|
|
294
|
+
}
|
|
295
|
+
supplied.add(name);
|
|
282
296
|
const target = c.findDirectExpression(Expressions.Target);
|
|
283
297
|
if (target === undefined) {
|
|
284
298
|
throw new assert_error_1.AssertError("parameterListT, no target found");
|
|
@@ -41,6 +41,7 @@ const basic_1 = require("../../types/basic");
|
|
|
41
41
|
const target_1 = require("../expressions/target");
|
|
42
42
|
const _reference_1 = require("../_reference");
|
|
43
43
|
const _syntax_input_1 = require("../_syntax_input");
|
|
44
|
+
const _type_utils_1 = require("../_type_utils");
|
|
44
45
|
class Catch {
|
|
45
46
|
runSyntax(node, input) {
|
|
46
47
|
var _a, _b;
|
|
@@ -91,7 +92,22 @@ class Catch {
|
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
else if (target) {
|
|
94
|
-
target_1.Target.runSyntax(target, input);
|
|
95
|
+
const targetType = target_1.Target.runSyntax(target, input);
|
|
96
|
+
if (targetType instanceof basic_1.ObjectReferenceType) {
|
|
97
|
+
for (const c of node.findDirectExpressions(Expressions.ClassName)) {
|
|
98
|
+
const token = c.getFirstToken();
|
|
99
|
+
const className = token.getStr().toUpperCase();
|
|
100
|
+
const found = input.scope.existsObject(className);
|
|
101
|
+
if (found === null || found === void 0 ? void 0 : found.id) {
|
|
102
|
+
const catchType = new basic_1.ObjectReferenceType(found.id);
|
|
103
|
+
if (new _type_utils_1.TypeUtils(input.scope).isAssignableStrict(catchType, targetType) === false) {
|
|
104
|
+
const message = "CATCH target not compatible with " + className;
|
|
105
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, token, message));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
95
111
|
}
|
|
96
112
|
}
|
|
97
113
|
}
|
|
@@ -8,7 +8,7 @@ class CDSDefineAbstract extends combi_1.Expression {
|
|
|
8
8
|
getRunnable() {
|
|
9
9
|
const field = (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.optPrio)((0, combi_1.str)("KEY")), cds_name_1.CDSName, ":", _1.CDSType, ";");
|
|
10
10
|
const compsiOrAssoci = (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), cds_name_1.CDSName, ":", (0, combi_1.alt)(_1.CDSComposition, _1.CDSAssociation), ";");
|
|
11
|
-
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", (0, combi_1.opt)("ROOT"), "ABSTRACT", "ENTITY", cds_name_1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), (0, combi_1.str)("{"), (0, combi_1.plus)((0, combi_1.alt)(field, compsiOrAssoci)), (0, combi_1.str)("}"), (0, combi_1.opt)(";"));
|
|
11
|
+
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), (0, combi_1.opt)("ROOT"), "ABSTRACT", "ENTITY", cds_name_1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), (0, combi_1.str)("{"), (0, combi_1.plus)((0, combi_1.alt)(field, compsiOrAssoci)), (0, combi_1.str)("}"), (0, combi_1.opt)(";"));
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
exports.CDSDefineAbstract = CDSDefineAbstract;
|
|
@@ -9,7 +9,7 @@ class CDSDefineCustom extends combi_1.Expression {
|
|
|
9
9
|
getRunnable() {
|
|
10
10
|
const field = (0, combi_1.seq)((0, combi_1.optPrio)((0, combi_1.str)("KEY")), cds_name_1.CDSName, ":", cds_type_1.CDSType, ";");
|
|
11
11
|
const compsiOrAssoci = (0, combi_1.seq)(cds_name_1.CDSName, ":", (0, combi_1.alt)(_1.CDSComposition, _1.CDSAssociation), ";");
|
|
12
|
-
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.
|
|
12
|
+
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), (0, combi_1.opt)("ROOT"), (0, combi_1.str)("CUSTOM ENTITY"), cds_name_1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), (0, combi_1.str)("{"), (0, combi_1.plus)((0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.alt)(field, compsiOrAssoci))), (0, combi_1.str)("}"), (0, combi_1.opt)(";"));
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
exports.CDSDefineCustom = CDSDefineCustom;
|
|
@@ -13,7 +13,7 @@ class CDSDefineExternalEntity extends combi_1.Expression {
|
|
|
13
13
|
const body = (0, combi_1.plus)((0, combi_1.alt)(field, assocOrComp));
|
|
14
14
|
const externalEntity = (0, combi_1.seq)((0, combi_1.opt)("WRITABLE"), "EXTERNAL", "ENTITY", _1.CDSName, (0, combi_1.opt)(externalName), (0, combi_1.opt)(_1.CDSWithParameters));
|
|
15
15
|
const staticEntity = (0, combi_1.seq)("STATIC", "ENTITY", _1.CDSName, (0, combi_1.opt)(externalName));
|
|
16
|
-
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", (0, combi_1.alt)(externalEntity, staticEntity), (0, combi_1.str)("{"), body, (0, combi_1.str)("}"), (0, combi_1.opt)((0, combi_1.seq)("WITH", "FEDERATED", "DATA", (0, combi_1.optPrio)((0, combi_1.alt)((0, combi_1.seq)("PROVIDED", "AT", "RUNTIME"), (0, combi_1.seq)("PROVIDED", "BY", _1.CDSName))))), (0, combi_1.opt)(";"));
|
|
16
|
+
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), (0, combi_1.alt)(externalEntity, staticEntity), (0, combi_1.str)("{"), body, (0, combi_1.str)("}"), (0, combi_1.opt)((0, combi_1.seq)("WITH", "FEDERATED", "DATA", (0, combi_1.optPrio)((0, combi_1.alt)((0, combi_1.seq)("PROVIDED", "AT", "RUNTIME"), (0, combi_1.seq)("PROVIDED", "BY", _1.CDSName))))), (0, combi_1.opt)(";"));
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
exports.CDSDefineExternalEntity = CDSDefineExternalEntity;
|
|
@@ -15,7 +15,7 @@ class CDSDefineHierarchy extends combi_1.Expression {
|
|
|
15
15
|
const depthValue = (0, combi_1.altPrio)(_1.CDSString, _1.CDSInteger, _1.CDSPrefixedName);
|
|
16
16
|
const loadMode = (0, combi_1.altPrio)("BULK", "INCREMENTAL", _1.CDSPrefixedName);
|
|
17
17
|
const hierarchyBody = (0, combi_1.seq)("SOURCE", _1.CDSName, (0, combi_1.opt)(_1.CDSParametersSelect), "CHILD", "TO", "PARENT", "ASSOCIATION", _1.CDSName, (0, combi_1.opt)(directory), (0, combi_1.opt)(datePeriod), (0, combi_1.opt)((0, combi_1.seq)("START", "WHERE", _1.CDSCondition)), (0, combi_1.opt)(siblingsOrder), (0, combi_1.opt)((0, combi_1.seq)("LOAD", loadMode)), (0, combi_1.opt)((0, combi_1.seq)("DEPTH", depthValue)), (0, combi_1.opt)((0, combi_1.seq)("NODETYPE", _1.CDSName)), (0, combi_1.opt)((0, combi_1.seq)("MULTIPLE", "PARENTS", (0, combi_1.altPrio)("NOT ALLOWED", "ALLOWED", (0, combi_1.seq)("LEAVES", (0, combi_1.optPrio)("ONLY"))))), (0, combi_1.opt)((0, combi_1.seq)("ORPHANS", (0, combi_1.altPrio)("IGNORE", "ROOT", "ERROR"))), (0, combi_1.opt)((0, combi_1.seq)("CYCLES", (0, combi_1.altPrio)("BREAKUP", "ERROR"))), (0, combi_1.opt)((0, combi_1.seq)("GENERATE", "SPANTREE")), (0, combi_1.opt)((0, combi_1.seq)("CACHE", (0, combi_1.altPrio)("ON", "OFF", "FORCE"))));
|
|
18
|
-
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", "HIERARCHY", _1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), "AS", "PARENT", "CHILD", "HIERARCHY", "(", hierarchyBody, ")", "{", (0, combi_1.seq)(field, (0, combi_1.star)((0, combi_1.seq)(",", field))), "}", (0, combi_1.opt)(";"));
|
|
18
|
+
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), "HIERARCHY", _1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), "AS", "PARENT", "CHILD", "HIERARCHY", "(", hierarchyBody, ")", "{", (0, combi_1.seq)(field, (0, combi_1.star)((0, combi_1.seq)(",", field))), "}", (0, combi_1.opt)(";"));
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
exports.CDSDefineHierarchy = CDSDefineHierarchy;
|
|
@@ -8,7 +8,7 @@ class CDSDefineProjection extends combi_1.Expression {
|
|
|
8
8
|
getRunnable() {
|
|
9
9
|
// redefine association _Assoc redirected to [composition child | parent] Entity
|
|
10
10
|
const redefineAssoc = (0, combi_1.seq)("REDEFINE", "ASSOCIATION", _1.CDSName, "REDIRECTED", "TO", (0, combi_1.optPrio)((0, combi_1.altPrio)((0, combi_1.seq)("COMPOSITION", "CHILD"), "PARENT")), _1.CDSName);
|
|
11
|
-
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", (0, combi_1.opt)("ROOT"), (0, combi_1.opt)("TRANSIENT"), "VIEW", (0, combi_1.ver)(__1.Release.v755, (0, combi_1.opt)("ENTITY")), _1.CDSName, (0, combi_1.opt)(_1.CDSProviderContract), (0, combi_1.opt)(_1.CDSWithParameters), "AS PROJECTION ON", _1.CDSName, (0, combi_1.opt)(_1.CDSParametersSelect), (0, combi_1.opt)(_1.CDSAs), (0, combi_1.star)((0, combi_1.altPrio)(_1.CDSAssociation, redefineAssoc)), (0, combi_1.str)("{"), (0, combi_1.seq)(_1.CDSElement, (0, combi_1.star)((0, combi_1.seq)(",", _1.CDSElement)), (0, combi_1.opt)(",")), (0, combi_1.str)("}"), (0, combi_1.opt)(_1.CDSWhere), (0, combi_1.opt)(";"));
|
|
11
|
+
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), (0, combi_1.opt)("ROOT"), (0, combi_1.opt)("TRANSIENT"), "VIEW", (0, combi_1.ver)(__1.Release.v755, (0, combi_1.opt)("ENTITY")), _1.CDSName, (0, combi_1.opt)(_1.CDSProviderContract), (0, combi_1.opt)(_1.CDSWithParameters), "AS PROJECTION ON", _1.CDSName, (0, combi_1.opt)(_1.CDSParametersSelect), (0, combi_1.opt)(_1.CDSAs), (0, combi_1.star)((0, combi_1.altPrio)(_1.CDSAssociation, redefineAssoc)), (0, combi_1.str)("{"), (0, combi_1.seq)(_1.CDSElement, (0, combi_1.star)((0, combi_1.seq)(",", _1.CDSElement)), (0, combi_1.opt)(",")), (0, combi_1.str)("}"), (0, combi_1.opt)(_1.CDSWhere), (0, combi_1.opt)(";"));
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
exports.CDSDefineProjection = CDSDefineProjection;
|
|
@@ -12,7 +12,7 @@ class CDSDefineTableEntity extends combi_1.Expression {
|
|
|
12
12
|
const elementList = (0, combi_1.seq)(_1.CDSElement, (0, combi_1.star)((0, combi_1.seq)(",", _1.CDSElement)), (0, combi_1.opt)(","));
|
|
13
13
|
const elements = (0, combi_1.seq)((0, combi_1.str)("{"), (0, combi_1.altPrio)("*", elementList), (0, combi_1.str)("}"));
|
|
14
14
|
const selectBody = (0, combi_1.seq)("AS", "SELECT", "FROM", _1.CDSSource, (0, combi_1.star)(_1.CDSJoin), (0, combi_1.star)((0, combi_1.altPrio)(_1.CDSComposition, _1.CDSAssociation)), (0, combi_1.opt)(elements), (0, combi_1.optPrio)(_1.CDSWhere));
|
|
15
|
-
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", (0, combi_1.opt)("ROOT"), "TABLE", "ENTITY", _1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), (0, combi_1.altPrio)((0, combi_1.seq)((0, combi_1.str)("{"), inlineBody, (0, combi_1.str)("}")), selectBody), (0, combi_1.opt)(";"));
|
|
15
|
+
return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), (0, combi_1.opt)("ROOT"), "TABLE", "ENTITY", _1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), (0, combi_1.altPrio)((0, combi_1.seq)((0, combi_1.str)("{"), inlineBody, (0, combi_1.str)("}")), selectBody), (0, combi_1.opt)(";"));
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
exports.CDSDefineTableEntity = CDSDefineTableEntity;
|
package/build/src/config.js
CHANGED
package/build/src/registry.js
CHANGED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ClearExportingParameters = exports.ClearExportingParametersConf = void 0;
|
|
37
|
+
const issue_1 = require("../issue");
|
|
38
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
39
|
+
const _irule_1 = require("./_irule");
|
|
40
|
+
const syntax_1 = require("../abap/5_syntax/syntax");
|
|
41
|
+
const _abap_object_1 = require("../objects/_abap_object");
|
|
42
|
+
const _scope_type_1 = require("../abap/5_syntax/_scope_type");
|
|
43
|
+
const objects_1 = require("../objects");
|
|
44
|
+
const _reference_1 = require("../abap/5_syntax/_reference");
|
|
45
|
+
const basic_1 = require("../abap/types/basic");
|
|
46
|
+
const _statement_1 = require("../abap/2_statements/statements/_statement");
|
|
47
|
+
const edit_helper_1 = require("../edit_helper");
|
|
48
|
+
const Expressions = __importStar(require("../abap/2_statements/expressions"));
|
|
49
|
+
class ClearExportingParametersConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
50
|
+
constructor() {
|
|
51
|
+
super(...arguments);
|
|
52
|
+
/** Skip specific parameter names, case insensitive
|
|
53
|
+
* @uniqueItems true
|
|
54
|
+
*/
|
|
55
|
+
this.skipNames = [];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.ClearExportingParametersConf = ClearExportingParametersConf;
|
|
59
|
+
class ClearExportingParameters {
|
|
60
|
+
constructor() {
|
|
61
|
+
this.conf = new ClearExportingParametersConf();
|
|
62
|
+
}
|
|
63
|
+
getMetadata() {
|
|
64
|
+
return {
|
|
65
|
+
key: "clear_exporting_parameters",
|
|
66
|
+
title: "Clear EXPORTING parameters",
|
|
67
|
+
shortDescription: `Checks that EXPORTING parameters passed by reference are cleared or assigned before they are read`,
|
|
68
|
+
extendedInformation: `An EXPORTING parameter passed by reference behaves like a CHANGING parameter: it is not
|
|
69
|
+
initialized when the method is called, so it can still contain a value supplied by the caller. Clear or overwrite it
|
|
70
|
+
before reading it, so a leftover value is not accidentally used.
|
|
71
|
+
|
|
72
|
+
https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#clear-or-overwrite-exporting-reference-parameters
|
|
73
|
+
|
|
74
|
+
https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abenref_transf_output_param_guidl.htm
|
|
75
|
+
|
|
76
|
+
Note: EXPORTING parameters passed by VALUE are always initialized and are therefore not reported.
|
|
77
|
+
Reading and writing the parameter in the same statement (e.g. "ev_result = ev_result + 1") is reported,
|
|
78
|
+
as the source is evaluated before the parameter is assigned.
|
|
79
|
+
Objects containing parser or syntax errors are not reported.
|
|
80
|
+
|
|
81
|
+
Only class and interface method implementations are checked, function module parameters are currently not supported.`,
|
|
82
|
+
tags: [_irule_1.RuleTag.Styleguide],
|
|
83
|
+
badExample: `CLASS lcl DEFINITION.
|
|
84
|
+
PUBLIC SECTION.
|
|
85
|
+
METHODS foo EXPORTING ev_result TYPE i.
|
|
86
|
+
ENDCLASS.
|
|
87
|
+
CLASS lcl IMPLEMENTATION.
|
|
88
|
+
METHOD foo.
|
|
89
|
+
ev_result = ev_result + 1.
|
|
90
|
+
ENDMETHOD.
|
|
91
|
+
ENDCLASS.`,
|
|
92
|
+
goodExample: `CLASS lcl DEFINITION.
|
|
93
|
+
PUBLIC SECTION.
|
|
94
|
+
METHODS foo EXPORTING ev_result TYPE i.
|
|
95
|
+
ENDCLASS.
|
|
96
|
+
CLASS lcl IMPLEMENTATION.
|
|
97
|
+
METHOD foo.
|
|
98
|
+
CLEAR ev_result.
|
|
99
|
+
ev_result = ev_result + 1.
|
|
100
|
+
ENDMETHOD.
|
|
101
|
+
ENDCLASS.`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
getConfig() {
|
|
105
|
+
return this.conf;
|
|
106
|
+
}
|
|
107
|
+
setConfig(conf) {
|
|
108
|
+
this.conf = conf;
|
|
109
|
+
if (this.conf.skipNames === undefined) {
|
|
110
|
+
this.conf.skipNames = [];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
initialize(reg) {
|
|
114
|
+
this.reg = reg;
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
run(obj) {
|
|
118
|
+
if (!(obj instanceof _abap_object_1.ABAPObject) || obj instanceof objects_1.Interface) {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
for (const file of obj.getABAPFiles()) {
|
|
122
|
+
for (const statement of file.getStatements()) {
|
|
123
|
+
if (statement.get() instanceof _statement_1.Unknown) {
|
|
124
|
+
return []; // contains parser errors
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const syntax = new syntax_1.SyntaxLogic(this.reg, obj).run();
|
|
129
|
+
if (syntax.issues.length > 0) {
|
|
130
|
+
return []; // contains syntax errors
|
|
131
|
+
}
|
|
132
|
+
const issues = [];
|
|
133
|
+
this.traverse(syntax.spaghetti.getTop(), obj, issues);
|
|
134
|
+
return issues;
|
|
135
|
+
}
|
|
136
|
+
traverse(node, obj, issues) {
|
|
137
|
+
if (node.getIdentifier().stype === _scope_type_1.ScopeType.Method) {
|
|
138
|
+
this.checkMethod(node, obj, issues);
|
|
139
|
+
}
|
|
140
|
+
for (const child of node.getChildren()) {
|
|
141
|
+
this.traverse(child, obj, issues);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
checkMethod(node, obj, issues) {
|
|
145
|
+
const parameters = this.findExportingByReference(node, obj);
|
|
146
|
+
if (parameters.length === 0) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const references = this.collectReferences(node);
|
|
150
|
+
for (const parameter of parameters) {
|
|
151
|
+
const issue = this.checkParameter(parameter, references, obj);
|
|
152
|
+
if (issue !== undefined) {
|
|
153
|
+
issues.push(issue);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
findExportingByReference(node, obj) {
|
|
158
|
+
var _a;
|
|
159
|
+
const ret = [];
|
|
160
|
+
const vars = node.getData().vars;
|
|
161
|
+
for (const name in vars) {
|
|
162
|
+
const parameter = vars[name];
|
|
163
|
+
const meta = parameter.getMeta();
|
|
164
|
+
if (meta.includes("exporting" /* IdentifierMeta.MethodExporting */) === false
|
|
165
|
+
|| meta.includes("pass_by_value" /* IdentifierMeta.PassByValue */) === true) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
else if ((_a = this.conf.skipNames) === null || _a === void 0 ? void 0 : _a.some(s => s.toUpperCase() === name.toUpperCase())) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const type = parameter.getType();
|
|
172
|
+
if (type instanceof basic_1.VoidType || type instanceof basic_1.UnknownType) {
|
|
173
|
+
continue; // e.g. RAP magic parameters, or unresolved types
|
|
174
|
+
}
|
|
175
|
+
else if (this.isPassByValue(parameter, obj) === true) {
|
|
176
|
+
continue; // VALUE(..) parameters are always initialized
|
|
177
|
+
}
|
|
178
|
+
ret.push(parameter);
|
|
179
|
+
}
|
|
180
|
+
return ret;
|
|
181
|
+
}
|
|
182
|
+
isPassByValue(parameter, obj) {
|
|
183
|
+
var _a;
|
|
184
|
+
// the PassByValue meta is not set for EXPORTING parameters, so determine it from the definition
|
|
185
|
+
const file = obj.getABAPFileByName(parameter.getFilename());
|
|
186
|
+
if (file === undefined) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
const statement = edit_helper_1.EditHelper.findStatement(parameter.getToken(), file);
|
|
190
|
+
if (statement === undefined) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
for (const param of statement.findAllExpressions(Expressions.MethodParam)) {
|
|
194
|
+
const nameToken = (_a = param.findFirstExpression(Expressions.MethodParamName)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
|
|
195
|
+
if (nameToken !== undefined && nameToken.getStart().equals(parameter.getStart())) {
|
|
196
|
+
return param.getFirstToken().getStr().toUpperCase() === "VALUE";
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
collectReferences(node) {
|
|
202
|
+
// methods do not nest, so all descendant scopes (FOR, LET, ...) belong to this method
|
|
203
|
+
const ret = [...node.getData().references];
|
|
204
|
+
for (const child of node.getChildren()) {
|
|
205
|
+
ret.push(...this.collectReferences(child));
|
|
206
|
+
}
|
|
207
|
+
return ret;
|
|
208
|
+
}
|
|
209
|
+
checkParameter(parameter, references, obj) {
|
|
210
|
+
let firstRead = undefined;
|
|
211
|
+
let earliestWrite = undefined;
|
|
212
|
+
for (const reference of references) {
|
|
213
|
+
if (reference.resolved === undefined || parameter.equals(reference.resolved) === false) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const pos = reference.position.getStart();
|
|
217
|
+
if (reference.referenceType === _reference_1.ReferenceType.DataReadReference) {
|
|
218
|
+
if (firstRead === undefined || pos.isBefore(firstRead.position.getStart())) {
|
|
219
|
+
firstRead = reference;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else if (reference.referenceType === _reference_1.ReferenceType.DataWriteReference) {
|
|
223
|
+
if (earliestWrite === undefined || pos.isBefore(earliestWrite)) {
|
|
224
|
+
earliestWrite = pos;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (firstRead === undefined) {
|
|
229
|
+
return undefined; // never read, no hazard
|
|
230
|
+
}
|
|
231
|
+
// the parameter is safe only if it is written in a statement strictly before the first read
|
|
232
|
+
const readStatement = this.statementStart(firstRead.position.getStart(), obj);
|
|
233
|
+
const writeStatement = earliestWrite === undefined ? undefined : this.statementStart(earliestWrite, obj);
|
|
234
|
+
if (writeStatement !== undefined && readStatement !== undefined && writeStatement.isBefore(readStatement)) {
|
|
235
|
+
return undefined;
|
|
236
|
+
}
|
|
237
|
+
const message = `EXPORTING parameter "${parameter.getName().toLowerCase()}" read before it is cleared or assigned`;
|
|
238
|
+
return issue_1.Issue.atIdentifier(firstRead.position, message, this.getMetadata().key, this.conf.severity);
|
|
239
|
+
}
|
|
240
|
+
statementStart(pos, obj) {
|
|
241
|
+
for (const file of obj.getABAPFiles()) {
|
|
242
|
+
for (const statement of file.getStatements()) {
|
|
243
|
+
const start = statement.getStart();
|
|
244
|
+
const end = statement.getEnd();
|
|
245
|
+
if (pos.equals(start) || (pos.isAfter(start) && pos.isBefore(end))) {
|
|
246
|
+
return start;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
exports.ClearExportingParameters = ClearExportingParameters;
|
|
254
|
+
//# sourceMappingURL=clear_exporting_parameters.js.map
|
|
@@ -204,7 +204,7 @@ Make sure to test the downported code, it might not always be completely correct
|
|
|
204
204
|
initialize(reg) {
|
|
205
205
|
this.lowReg = reg;
|
|
206
206
|
const config = this.lowReg.getConfig();
|
|
207
|
-
if (config.getRelease() === version_1.Release.v702 || config.
|
|
207
|
+
if (config.getRelease() === version_1.Release.v702 || config.isOpenABAP()) {
|
|
208
208
|
this.initHighReg();
|
|
209
209
|
}
|
|
210
210
|
return this;
|
|
@@ -237,7 +237,7 @@ Make sure to test the downported code, it might not always be completely correct
|
|
|
237
237
|
const ret = [];
|
|
238
238
|
this.counter = 1;
|
|
239
239
|
const config = this.lowReg.getConfig();
|
|
240
|
-
if (config.getRelease() !== version_1.Release.v702 && !config.
|
|
240
|
+
if (config.getRelease() !== version_1.Release.v702 && !config.isOpenABAP()) {
|
|
241
241
|
return ret;
|
|
242
242
|
}
|
|
243
243
|
else if (!(lowObj instanceof _abap_object_1.ABAPObject)) {
|
|
@@ -1109,7 +1109,7 @@ ${indentation}`);
|
|
|
1109
1109
|
outlineCatchSimple(node, lowFile) {
|
|
1110
1110
|
// outlines "CATCH cx_bcs INTO DATA(lx_bcs_excep).", note that this does not need to look at types
|
|
1111
1111
|
var _a, _b;
|
|
1112
|
-
if (this.lowReg.getConfig().
|
|
1112
|
+
if (this.lowReg.getConfig().isOpenABAP()) {
|
|
1113
1113
|
return undefined;
|
|
1114
1114
|
}
|
|
1115
1115
|
if (!(node.get() instanceof Statements.Catch)) {
|
|
@@ -1158,7 +1158,7 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
|
|
|
1158
1158
|
if (!(node.get() instanceof Statements.Move)) {
|
|
1159
1159
|
return undefined;
|
|
1160
1160
|
}
|
|
1161
|
-
if (this.lowReg.getConfig().
|
|
1161
|
+
if (this.lowReg.getConfig().isOpenABAP()) {
|
|
1162
1162
|
return undefined;
|
|
1163
1163
|
}
|
|
1164
1164
|
const target = node.findFirstExpression(Expressions.Target);
|
|
@@ -1214,7 +1214,7 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
|
|
|
1214
1214
|
return issue_1.Issue.atToken(lowFile, node.getFirstToken(), "Outline DATA", this.getMetadata().key, this.conf.severity, fix);
|
|
1215
1215
|
}
|
|
1216
1216
|
partiallyImplemented(node, lowFile) {
|
|
1217
|
-
if (this.lowReg.getConfig().
|
|
1217
|
+
if (this.lowReg.getConfig().isOpenABAP()) {
|
|
1218
1218
|
return undefined;
|
|
1219
1219
|
}
|
|
1220
1220
|
if (node.get() instanceof Statements.InterfaceDef) {
|
|
@@ -1890,7 +1890,7 @@ ${indentation} output = ${uniqueName}.\n`;
|
|
|
1890
1890
|
if (!(node.get() instanceof Statements.Loop)) {
|
|
1891
1891
|
return undefined;
|
|
1892
1892
|
}
|
|
1893
|
-
if (this.lowReg.getConfig().
|
|
1893
|
+
if (this.lowReg.getConfig().isOpenABAP()) {
|
|
1894
1894
|
return undefined;
|
|
1895
1895
|
}
|
|
1896
1896
|
const source = (_a = node.findDirectExpression(Expressions.LoopSource)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.SimpleSource2);
|
|
@@ -2566,7 +2566,7 @@ ${indentation} output = ${uniqueName}.\n`;
|
|
|
2566
2566
|
outlineData(node, lowFile, highSyntax) {
|
|
2567
2567
|
// hmm, no guard here, as DATA(SDF) is valid in 702
|
|
2568
2568
|
var _a, _b;
|
|
2569
|
-
if (this.lowReg.getConfig().
|
|
2569
|
+
if (this.lowReg.getConfig().isOpenABAP()) {
|
|
2570
2570
|
return undefined;
|
|
2571
2571
|
}
|
|
2572
2572
|
for (const i of node.findAllExpressionsRecursive(Expressions.InlineData)) {
|
|
@@ -2785,7 +2785,7 @@ ${indentation} output = ${uniqueName}.\n`;
|
|
|
2785
2785
|
return false;
|
|
2786
2786
|
}
|
|
2787
2787
|
replaceXsdBool(node, lowFile, highSyntax) {
|
|
2788
|
-
if (this.lowReg.getConfig().
|
|
2788
|
+
if (this.lowReg.getConfig().isOpenABAP()) {
|
|
2789
2789
|
return undefined;
|
|
2790
2790
|
}
|
|
2791
2791
|
const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
|
|
@@ -2914,7 +2914,7 @@ ${indentation} output = ${uniqueName}.\n`;
|
|
|
2914
2914
|
}
|
|
2915
2915
|
replaceLineFunctions(node, lowFile, highSyntax, highFile) {
|
|
2916
2916
|
var _a, _b;
|
|
2917
|
-
if (this.lowReg.getConfig().
|
|
2917
|
+
if (this.lowReg.getConfig().isOpenABAP()) {
|
|
2918
2918
|
return undefined;
|
|
2919
2919
|
}
|
|
2920
2920
|
const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
|
package/build/src/rules/index.js
CHANGED
|
@@ -45,6 +45,7 @@ __exportStar(require("./check_subrc"), exports);
|
|
|
45
45
|
__exportStar(require("./check_syntax"), exports);
|
|
46
46
|
__exportStar(require("./check_text_elements"), exports);
|
|
47
47
|
__exportStar(require("./check_transformation_exists"), exports);
|
|
48
|
+
__exportStar(require("./clear_exporting_parameters"), exports);
|
|
48
49
|
__exportStar(require("./class_attribute_names"), exports);
|
|
49
50
|
__exportStar(require("./classic_exceptions_overlap"), exports);
|
|
50
51
|
__exportStar(require("./cloud_types"), exports);
|
|
@@ -150,6 +151,7 @@ __exportStar(require("./preferred_compare_operator"), exports);
|
|
|
150
151
|
__exportStar(require("./prefix_is_current_class"), exports);
|
|
151
152
|
__exportStar(require("./reduce_procedural_code"), exports);
|
|
152
153
|
__exportStar(require("./reduce_string_templates"), exports);
|
|
154
|
+
__exportStar(require("./redundant_conversion"), exports);
|
|
153
155
|
__exportStar(require("./release_idoc"), exports);
|
|
154
156
|
__exportStar(require("./remove_descriptions"), exports);
|
|
155
157
|
__exportStar(require("./rfc_error_handling"), exports);
|
|
@@ -32,7 +32,7 @@ class InlineDataOldVersions extends _abap_rule_1.ABAPRule {
|
|
|
32
32
|
runParsed(file) {
|
|
33
33
|
const issues = [];
|
|
34
34
|
if ((0, version_1.releaseAtLeast)(this.reg.getConfig().getRelease(), version_1.Release.v740sp02)
|
|
35
|
-
|| this.reg.getConfig().
|
|
35
|
+
|| this.reg.getConfig().isOpenABAP()
|
|
36
36
|
|| this.reg.getConfig().getLanguageVersion() === version_1.LanguageVersion.Cloud) {
|
|
37
37
|
return [];
|
|
38
38
|
}
|
|
@@ -80,7 +80,7 @@ Not considered optional branches:
|
|
|
80
80
|
const release = this.reg.getConfig().getRelease();
|
|
81
81
|
if (release === version_1.Release.v700
|
|
82
82
|
|| release === version_1.Release.v702
|
|
83
|
-
|| this.reg.getConfig().
|
|
83
|
+
|| this.reg.getConfig().isOpenABAP()) {
|
|
84
84
|
return [];
|
|
85
85
|
}
|
|
86
86
|
const struc = file.getStructure();
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.RedundantConversion = exports.RedundantConversionConf = void 0;
|
|
37
|
+
const Expressions = __importStar(require("../abap/2_statements/expressions"));
|
|
38
|
+
const Statements = __importStar(require("../abap/2_statements/statements"));
|
|
39
|
+
const _reference_1 = require("../abap/5_syntax/_reference");
|
|
40
|
+
const constant_1 = require("../abap/5_syntax/expressions/constant");
|
|
41
|
+
const syntax_1 = require("../abap/5_syntax/syntax");
|
|
42
|
+
const nodes_1 = require("../abap/nodes");
|
|
43
|
+
const _typed_identifier_1 = require("../abap/types/_typed_identifier");
|
|
44
|
+
const basic_1 = require("../abap/types/basic");
|
|
45
|
+
const issue_1 = require("../issue");
|
|
46
|
+
const _abap_object_1 = require("../objects/_abap_object");
|
|
47
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
48
|
+
const _irule_1 = require("./_irule");
|
|
49
|
+
const edit_helper_1 = require("../edit_helper");
|
|
50
|
+
const version_1 = require("../version");
|
|
51
|
+
class RedundantConversionConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
52
|
+
}
|
|
53
|
+
exports.RedundantConversionConf = RedundantConversionConf;
|
|
54
|
+
class RedundantConversion {
|
|
55
|
+
constructor() {
|
|
56
|
+
this.conf = new RedundantConversionConf();
|
|
57
|
+
}
|
|
58
|
+
getMetadata() {
|
|
59
|
+
return {
|
|
60
|
+
key: "redundant_conversion",
|
|
61
|
+
title: "Redundant Conversion",
|
|
62
|
+
shortDescription: `Find redundant CONV expressions`,
|
|
63
|
+
extendedInformation: `Reports CONV expressions whose operand already has the conversion's target type.`,
|
|
64
|
+
tags: [_irule_1.RuleTag.Quickfix],
|
|
65
|
+
badExample: `DATA text TYPE string.
|
|
66
|
+
text = CONV string( text ).`,
|
|
67
|
+
goodExample: `DATA text TYPE string.
|
|
68
|
+
text = text.`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
getConfig() {
|
|
72
|
+
return this.conf;
|
|
73
|
+
}
|
|
74
|
+
setConfig(conf) {
|
|
75
|
+
this.conf = conf;
|
|
76
|
+
}
|
|
77
|
+
initialize(reg) {
|
|
78
|
+
this.reg = reg;
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
run(obj) {
|
|
82
|
+
var _a, _b;
|
|
83
|
+
if (!(0, version_1.releaseAtLeast)(this.reg.getConfig().getRelease(), version_1.Release.v740sp02)
|
|
84
|
+
&& !this.reg.getConfig().isOpenABAP()) {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
if (!(obj instanceof _abap_object_1.ABAPObject)) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
const syntax = new syntax_1.SyntaxLogic(this.reg, obj).run();
|
|
91
|
+
if (syntax.issues.length > 0) {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
const issues = [];
|
|
95
|
+
for (const file of obj.getABAPFiles()) {
|
|
96
|
+
const structure = file.getStructure();
|
|
97
|
+
if (structure === undefined) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
for (const source of structure.findAllExpressions(Expressions.Source)) {
|
|
101
|
+
if (source.getFirstToken().getStr().toUpperCase() !== "CONV") {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const typeExpression = source.findDirectExpression(Expressions.TypeNameOrInfer);
|
|
105
|
+
const bodySource = (_a = source.findDirectExpression(Expressions.ConvBody)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.Source);
|
|
106
|
+
if (typeExpression === undefined
|
|
107
|
+
|| bodySource === undefined) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const scope = syntax.spaghetti.lookupPosition(source.getFirstToken().getStart(), file.getFilename());
|
|
111
|
+
if (scope === undefined) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const target = (_b = scope.getData().references.find(reference => reference.referenceType === _reference_1.ReferenceType.InferredType
|
|
115
|
+
&& reference.position.getStart().equals(typeExpression.getFirstToken().getStart()))) === null || _b === void 0 ? void 0 : _b.resolved;
|
|
116
|
+
const operandType = this.sourceType(bodySource, scope);
|
|
117
|
+
if (!(target instanceof _typed_identifier_1.TypedIdentifier)) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const operandHasSameType = operandType !== undefined && this.sameType(target.getType(), operandType);
|
|
121
|
+
const arithmeticHasSameContext = this.arithmeticUsesSameTargetType(source, bodySource, file, scope, target.getType());
|
|
122
|
+
if (operandHasSameType === false && arithmeticHasSameContext === false) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const closingParen = source.getDirectTokens().find(token => token.getStr() === ")" && token.getStart().isAfter(bodySource.getLastToken().getStart()));
|
|
126
|
+
if (closingParen === undefined) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const preserveParentheses = bodySource.findDirectExpression(Expressions.ArithOperator) !== undefined
|
|
130
|
+
|| bodySource.findDirectTokenByText("&&") !== undefined;
|
|
131
|
+
// Apply the later edit first so the original positions remain valid when
|
|
132
|
+
// both parts of the CONV wrapper are changed on the same line.
|
|
133
|
+
const fix = edit_helper_1.EditHelper.merge(edit_helper_1.EditHelper.replaceRange(file, bodySource.getLastToken().getEnd(), closingParen.getEnd(), preserveParentheses ? ")" : ""), edit_helper_1.EditHelper.replaceRange(file, source.getFirstToken().getStart(), bodySource.getFirstToken().getStart(), preserveParentheses ? "(" : ""));
|
|
134
|
+
issues.push(issue_1.Issue.atRange(file, source.getFirstToken().getStart(), closingParen.getEnd(), "Redundant CONV expression", this.getMetadata().key, this.conf.severity, fix));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return issues;
|
|
138
|
+
}
|
|
139
|
+
arithmeticUsesSameTargetType(conversion, bodySource, file, scope, conversionType) {
|
|
140
|
+
var _a, _b;
|
|
141
|
+
if (bodySource.findDirectExpression(Expressions.ArithOperator) === undefined) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
const statement = file.getStatements().find(candidate => candidate.includesToken(conversion.getFirstToken()));
|
|
145
|
+
if (!((statement === null || statement === void 0 ? void 0 : statement.get()) instanceof Statements.Move)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
const targetToken = (_a = statement.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
|
|
149
|
+
if (targetToken === undefined) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
const assignmentTarget = (_b = scope.getData().references.find(reference => reference.referenceType === _reference_1.ReferenceType.DataWriteReference
|
|
153
|
+
&& reference.position.getStart().equals(targetToken.getStart()))) === null || _b === void 0 ? void 0 : _b.resolved;
|
|
154
|
+
return assignmentTarget instanceof _typed_identifier_1.TypedIdentifier
|
|
155
|
+
&& this.sameType(conversionType, assignmentTarget.getType());
|
|
156
|
+
}
|
|
157
|
+
sourceType(source, scope) {
|
|
158
|
+
let context;
|
|
159
|
+
for (const child of source.getChildren()) {
|
|
160
|
+
if (!(child instanceof nodes_1.ExpressionNode)) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
else if (child.get() instanceof Expressions.FieldChain) {
|
|
164
|
+
context = this.fieldChainType(child, scope);
|
|
165
|
+
if (context === undefined) {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (child.get() instanceof Expressions.Constant) {
|
|
170
|
+
context = this.infer(context, constant_1.Constant.runSyntax(child));
|
|
171
|
+
}
|
|
172
|
+
else if (child.get() instanceof Expressions.Source) {
|
|
173
|
+
context = this.infer(context, this.sourceType(child, scope));
|
|
174
|
+
}
|
|
175
|
+
else if (child.get() instanceof Expressions.ArithOperator) {
|
|
176
|
+
if (child.concatTokens() === "**") {
|
|
177
|
+
context = new basic_1.FloatType();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (source.findDirectTokenByText("&&")) {
|
|
185
|
+
return basic_1.StringType.get();
|
|
186
|
+
}
|
|
187
|
+
return context;
|
|
188
|
+
}
|
|
189
|
+
fieldChainType(fieldChain, scope) {
|
|
190
|
+
var _a;
|
|
191
|
+
const operand = (_a = scope.getData().references.find(reference => reference.referenceType === _reference_1.ReferenceType.DataReadReference
|
|
192
|
+
&& reference.position.getStart().equals(fieldChain.getFirstToken().getStart()))) === null || _a === void 0 ? void 0 : _a.resolved;
|
|
193
|
+
if (!(operand instanceof _typed_identifier_1.TypedIdentifier)) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
let type = operand.getType();
|
|
197
|
+
for (const child of fieldChain.getChildren()) {
|
|
198
|
+
if (!(child instanceof nodes_1.ExpressionNode)
|
|
199
|
+
|| child.get() instanceof Expressions.SourceField) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
else if (child.get() instanceof Expressions.ComponentName) {
|
|
203
|
+
if (type instanceof basic_1.TableType) {
|
|
204
|
+
type = type.getRowType();
|
|
205
|
+
}
|
|
206
|
+
if (!(type instanceof basic_1.StructureType)) {
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
type = type.getComponentByName(child.concatTokens());
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
// Offsets, table expressions, attributes, and dereferences need more
|
|
213
|
+
// context than the initial data reference provides.
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return type;
|
|
218
|
+
}
|
|
219
|
+
infer(context, found) {
|
|
220
|
+
if (context instanceof basic_1.FloatType && found instanceof basic_1.IntegerType) {
|
|
221
|
+
return context;
|
|
222
|
+
}
|
|
223
|
+
else if (context instanceof basic_1.IntegerType && found instanceof basic_1.HexType) {
|
|
224
|
+
return context;
|
|
225
|
+
}
|
|
226
|
+
else if ((context instanceof basic_1.IntegerType || context instanceof basic_1.FloatType) && (found === null || found === void 0 ? void 0 : found.isGeneric())) {
|
|
227
|
+
return context;
|
|
228
|
+
}
|
|
229
|
+
return found;
|
|
230
|
+
}
|
|
231
|
+
sameType(first, second) {
|
|
232
|
+
var _a, _b;
|
|
233
|
+
if (first instanceof basic_1.UnknownType
|
|
234
|
+
|| second instanceof basic_1.UnknownType
|
|
235
|
+
|| first instanceof basic_1.VoidType
|
|
236
|
+
|| second instanceof basic_1.VoidType
|
|
237
|
+
|| first.isGeneric()
|
|
238
|
+
|| second.isGeneric()) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
if (first.constructor !== second.constructor) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
if (first instanceof basic_1.StructureType || first instanceof basic_1.TableType) {
|
|
245
|
+
const firstName = (_a = first.getQualifiedName()) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
246
|
+
const secondName = (_b = second.getQualifiedName()) === null || _b === void 0 ? void 0 : _b.toUpperCase();
|
|
247
|
+
return firstName !== undefined && firstName === secondName;
|
|
248
|
+
}
|
|
249
|
+
return first.toABAP() === second.toABAP();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
exports.RedundantConversion = RedundantConversion;
|
|
253
|
+
//# sourceMappingURL=redundant_conversion.js.map
|
|
@@ -75,7 +75,7 @@ class SQLEscapeHostVariables extends _abap_rule_1.ABAPRule {
|
|
|
75
75
|
}
|
|
76
76
|
if (!(0, version_1.releaseAtLeast)(this.reg.getConfig().getRelease(), version_1.Release.v740sp02)
|
|
77
77
|
&& this.reg.getConfig().getLanguageVersion() !== version_1.LanguageVersion.Cloud
|
|
78
|
-
&& !this.reg.getConfig().
|
|
78
|
+
&& !this.reg.getConfig().isOpenABAP()) {
|
|
79
79
|
return [];
|
|
80
80
|
}
|
|
81
81
|
for (const s of file.getStatements()) {
|
|
@@ -80,7 +80,7 @@ ENDIF.`,
|
|
|
80
80
|
}
|
|
81
81
|
const release = this.reg.getConfig().getRelease();
|
|
82
82
|
const langVers = this.reg.getConfig().getLanguageVersion();
|
|
83
|
-
if (this.reg.getConfig().
|
|
83
|
+
if (this.reg.getConfig().isOpenABAP()) {
|
|
84
84
|
return [];
|
|
85
85
|
}
|
|
86
86
|
else if (!(0, version_1.releaseAtLeast)(release, version_1.Release.v740sp02) && langVers !== version_1.LanguageVersion.Cloud) {
|