@abaplint/core 2.115.14 → 2.115.16
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 -0
- package/build/src/abap/5_syntax/_procedural.js +34 -2
- package/build/src/abap/5_syntax/_type_utils.js +23 -0
- package/build/src/abap/5_syntax/expressions/compare.js +12 -2
- package/build/src/abap/5_syntax/expressions/string_template.js +64 -33
- package/build/src/abap/5_syntax/statements/move.js +1 -1
- package/build/src/abap/5_syntax/syntax.js +3 -0
- package/build/src/abap/types/function_module_definition.js +4 -0
- package/build/src/registry.js +1 -1
- package/build/src/rules/fm_global_parameters_obsolete.js +52 -0
- package/build/src/rules/index.js +2 -1
- package/package.json +1 -1
package/build/abaplint.d.ts
CHANGED
|
@@ -2870,12 +2870,14 @@ declare class FunctionModuleDefinition {
|
|
|
2870
2870
|
private name;
|
|
2871
2871
|
private description;
|
|
2872
2872
|
private parameters;
|
|
2873
|
+
private globalParameters;
|
|
2873
2874
|
private moduleType;
|
|
2874
2875
|
constructor(data: any);
|
|
2875
2876
|
getParameters(): readonly IFunctionModuleParameter[];
|
|
2876
2877
|
getModuleType(): FunctionModuleType | undefined;
|
|
2877
2878
|
getDescription(): string | undefined;
|
|
2878
2879
|
getName(): string;
|
|
2880
|
+
isGlobalParameters(): boolean;
|
|
2879
2881
|
private parse;
|
|
2880
2882
|
}
|
|
2881
2883
|
|
|
@@ -72,8 +72,25 @@ class Procedural {
|
|
|
72
72
|
}
|
|
73
73
|
return undefined;
|
|
74
74
|
}
|
|
75
|
+
findFunctionGroupScope(fg) {
|
|
76
|
+
var _a, _b, _c;
|
|
77
|
+
for (const module of fg.getModules()) {
|
|
78
|
+
if (module.isGlobalParameters() === false) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
// console.dir(fg.getSequencedFiles());
|
|
82
|
+
const fmFile = fg.getSequencedFiles().find((f) => { return f.getFilename().endsWith(".fugr." + module.getName().toLowerCase().replace(/\//g, "#") + ".abap"); });
|
|
83
|
+
if (fmFile === undefined) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const nameToken = (_c = (_b = (_a = fmFile.getStructure()) === null || _a === void 0 ? void 0 : _a.findFirstStatement(Statements.FunctionModule)) === null || _b === void 0 ? void 0 : _b.findFirstExpression(Expressions.Field)) === null || _c === void 0 ? void 0 : _c.getFirstToken();
|
|
87
|
+
if (nameToken === undefined) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
this.addFunctionScope(module, nameToken, fmFile.getFilename(), true);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
75
93
|
findFunctionScope(obj, node, filename) {
|
|
76
|
-
var _a, _b, _c, _d, _e;
|
|
77
94
|
if (!(obj instanceof objects_1.FunctionGroup)) {
|
|
78
95
|
throw new Error("findFunctionScope, expected function group input");
|
|
79
96
|
}
|
|
@@ -84,6 +101,13 @@ class Procedural {
|
|
|
84
101
|
if (definition === undefined) {
|
|
85
102
|
throw new Error("Function module definition \"" + name + "\" not found");
|
|
86
103
|
}
|
|
104
|
+
if (definition.isGlobalParameters() === true) {
|
|
105
|
+
return; // already added at global level
|
|
106
|
+
}
|
|
107
|
+
this.addFunctionScope(definition, nameToken, filename);
|
|
108
|
+
}
|
|
109
|
+
addFunctionScope(definition, nameToken, filename, ignoreIfAlreadyExists = false) {
|
|
110
|
+
var _a, _b, _c, _d, _e;
|
|
87
111
|
const ddic = new ddic_1.DDIC(this.reg);
|
|
88
112
|
const allNames = new Set();
|
|
89
113
|
for (const param of definition.getParameters()) {
|
|
@@ -169,7 +193,15 @@ class Procedural {
|
|
|
169
193
|
}
|
|
170
194
|
else {
|
|
171
195
|
const type = new _typed_identifier_1.TypedIdentifier(nameToken, filename, found);
|
|
172
|
-
|
|
196
|
+
if (ignoreIfAlreadyExists === true) {
|
|
197
|
+
const exists = this.scope.findVariable(param.name);
|
|
198
|
+
if (exists === undefined) {
|
|
199
|
+
this.scope.addNamedIdentifier(param.name, type);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
this.scope.addNamedIdentifier(param.name, type);
|
|
204
|
+
}
|
|
173
205
|
allNames.add(param.name.toUpperCase());
|
|
174
206
|
}
|
|
175
207
|
}
|
|
@@ -214,6 +214,22 @@ class TypeUtils {
|
|
|
214
214
|
// todo
|
|
215
215
|
return true;
|
|
216
216
|
}
|
|
217
|
+
isCompareable(source1, source2, node1, node2) {
|
|
218
|
+
/*
|
|
219
|
+
console.dir(source1);
|
|
220
|
+
console.dir(source2);
|
|
221
|
+
*/
|
|
222
|
+
if (source1 === undefined || source2 === undefined) {
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
if (source1 instanceof basic_1.HexType && this.isCalculated(node1) && source2 instanceof basic_1.IntegerType) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
if (source2 instanceof basic_1.HexType && this.isCalculated(node2) && source1 instanceof basic_1.IntegerType) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
217
233
|
structureContainsString(structure) {
|
|
218
234
|
for (const c of structure.getComponents()) {
|
|
219
235
|
if (c.type instanceof basic_1.StringType) {
|
|
@@ -243,6 +259,13 @@ class TypeUtils {
|
|
|
243
259
|
|| node.findFirstExpression(Expressions.ArithOperator) !== undefined;
|
|
244
260
|
return calculated;
|
|
245
261
|
}
|
|
262
|
+
isAssignableNew(source, target, node) {
|
|
263
|
+
const calculated = (node === null || node === void 0 ? void 0 : node.findFirstExpression(Expressions.ArithOperator)) !== undefined;
|
|
264
|
+
if (calculated && source instanceof basic_1.HexType && target instanceof basic_1.IntegerType) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
return this.isAssignable(source, target);
|
|
268
|
+
}
|
|
246
269
|
isAssignableStrict(source, target, node) {
|
|
247
270
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
248
271
|
const calculated = node ? this.isCalculated(node) : false;
|
|
@@ -5,10 +5,14 @@ const Expressions = require("../../2_statements/expressions");
|
|
|
5
5
|
const source_1 = require("./source");
|
|
6
6
|
const method_call_chain_1 = require("./method_call_chain");
|
|
7
7
|
const source_field_symbol_1 = require("./source_field_symbol");
|
|
8
|
+
const _syntax_input_1 = require("../_syntax_input");
|
|
9
|
+
const _type_utils_1 = require("../_type_utils");
|
|
8
10
|
class Compare {
|
|
9
11
|
static runSyntax(node, input) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
const sourceTypes = [];
|
|
13
|
+
const sources = node.findDirectExpressions(Expressions.Source);
|
|
14
|
+
for (const t of sources) {
|
|
15
|
+
sourceTypes.push(source_1.Source.runSyntax(t, input));
|
|
12
16
|
}
|
|
13
17
|
for (const t of node.findDirectExpressions(Expressions.SourceFieldSymbolChain)) {
|
|
14
18
|
source_field_symbol_1.SourceFieldSymbol.runSyntax(t, input);
|
|
@@ -16,6 +20,12 @@ class Compare {
|
|
|
16
20
|
for (const t of node.findDirectExpressions(Expressions.MethodCallChain)) {
|
|
17
21
|
method_call_chain_1.MethodCallChain.runSyntax(t, input);
|
|
18
22
|
}
|
|
23
|
+
if (node.findDirectExpression(Expressions.CompareOperator)
|
|
24
|
+
&& new _type_utils_1.TypeUtils(input.scope).isCompareable(sourceTypes[0], sourceTypes[1], sources[0], sources[1]) === false
|
|
25
|
+
&& sourceTypes.length === 2) {
|
|
26
|
+
const message = "Incompatible types for comparison";
|
|
27
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
28
|
+
}
|
|
19
29
|
}
|
|
20
30
|
}
|
|
21
31
|
exports.Compare = Compare;
|
|
@@ -1,53 +1,84 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.StringTemplate = void 0;
|
|
4
|
+
const nodes_1 = require("../../nodes");
|
|
4
5
|
const basic_1 = require("../../types/basic");
|
|
5
6
|
const Expressions = require("../../2_statements/expressions");
|
|
6
7
|
const source_1 = require("./source");
|
|
7
8
|
const _type_utils_1 = require("../_type_utils");
|
|
8
9
|
const _syntax_input_1 = require("../_syntax_input");
|
|
10
|
+
const Tokens = require("../../1_lexer/tokens");
|
|
9
11
|
class StringTemplate {
|
|
10
12
|
static runSyntax(node, input) {
|
|
11
13
|
const typeUtils = new _type_utils_1.TypeUtils(input.scope);
|
|
12
14
|
const ret = basic_1.StringType.get();
|
|
13
|
-
for (const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
for (const child of node.getChildren()) {
|
|
16
|
+
if (child instanceof nodes_1.ExpressionNode && child.get() instanceof Expressions.StringTemplateSource) {
|
|
17
|
+
const s = child.findDirectExpression(Expressions.Source);
|
|
18
|
+
const type = source_1.Source.runSyntax(s, input, ret);
|
|
19
|
+
if (type === undefined) {
|
|
20
|
+
const message = "No target type determined";
|
|
21
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
22
|
+
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
23
|
+
}
|
|
24
|
+
else if ((typeUtils.isCharLike(type) === false
|
|
25
|
+
&& typeUtils.isHexLike(type) === false
|
|
26
|
+
&& !(type instanceof basic_1.UTCLongType))
|
|
27
|
+
|| type instanceof basic_1.StructureType) {
|
|
28
|
+
const message = "String template, not character like, " + type.constructor.name;
|
|
29
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
30
|
+
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
31
|
+
}
|
|
32
|
+
const format = child.findDirectExpression(Expressions.StringTemplateFormatting);
|
|
33
|
+
const formatConcat = format === null || format === void 0 ? void 0 : format.concatTokens();
|
|
34
|
+
for (const formatSource of (format === null || format === void 0 ? void 0 : format.findAllExpressions(Expressions.Source)) || []) {
|
|
35
|
+
source_1.Source.runSyntax(formatSource, input);
|
|
36
|
+
}
|
|
37
|
+
if (format
|
|
38
|
+
&& (formatConcat === null || formatConcat === void 0 ? void 0 : formatConcat.includes("ALPHA = "))
|
|
39
|
+
&& !(type instanceof basic_1.UnknownType)
|
|
40
|
+
&& !(type instanceof basic_1.VoidType)
|
|
41
|
+
&& !(type instanceof basic_1.StringType)
|
|
42
|
+
&& !(type instanceof basic_1.CLikeType)
|
|
43
|
+
&& !(type instanceof basic_1.CharacterType)
|
|
44
|
+
&& !(type instanceof basic_1.NumericGenericType)
|
|
45
|
+
&& !(type instanceof basic_1.NumericType)
|
|
46
|
+
&& !(type instanceof basic_1.AnyType)) {
|
|
47
|
+
const message = `Cannot apply ALPHA to this type (${type.constructor.name})`;
|
|
48
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, format.getFirstToken(), message));
|
|
49
|
+
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
50
|
+
}
|
|
20
51
|
}
|
|
21
|
-
else if (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
if (format
|
|
35
|
-
&& (formatConcat === null || formatConcat === void 0 ? void 0 : formatConcat.includes("ALPHA = "))
|
|
36
|
-
&& !(type instanceof basic_1.UnknownType)
|
|
37
|
-
&& !(type instanceof basic_1.VoidType)
|
|
38
|
-
&& !(type instanceof basic_1.StringType)
|
|
39
|
-
&& !(type instanceof basic_1.CLikeType)
|
|
40
|
-
&& !(type instanceof basic_1.CharacterType)
|
|
41
|
-
&& !(type instanceof basic_1.NumericGenericType)
|
|
42
|
-
&& !(type instanceof basic_1.NumericType)
|
|
43
|
-
&& !(type instanceof basic_1.AnyType)) {
|
|
44
|
-
const message = `Cannot apply ALPHA to this type (${type.constructor.name})`;
|
|
45
|
-
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, format.getFirstToken(), message));
|
|
46
|
-
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
52
|
+
else if (child instanceof nodes_1.TokenNode) {
|
|
53
|
+
const token = child.get();
|
|
54
|
+
if (token instanceof Tokens.StringTemplate
|
|
55
|
+
|| token instanceof Tokens.StringTemplateBegin
|
|
56
|
+
|| token instanceof Tokens.StringTemplateMiddle
|
|
57
|
+
|| token instanceof Tokens.StringTemplateEnd) {
|
|
58
|
+
const issue = this.validateEscapeSequences(token.getStr(), input, child);
|
|
59
|
+
if (issue) {
|
|
60
|
+
input.issues.push(issue);
|
|
61
|
+
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
47
64
|
}
|
|
48
65
|
}
|
|
49
66
|
return ret;
|
|
50
67
|
}
|
|
68
|
+
static validateEscapeSequences(str, input, node) {
|
|
69
|
+
// Valid escape sequences in ABAP string templates: \|, \{, \}, \\, \n, \r, \t
|
|
70
|
+
const validEscapes = new Set(["\\|", "\\{", "\\}", "\\\\", "\\n", "\\r", "\\t"]);
|
|
71
|
+
for (let i = 0; i < str.length; i++) {
|
|
72
|
+
if (str[i] === "\\") {
|
|
73
|
+
const escape = str.substring(i, i + 2);
|
|
74
|
+
if (!validEscapes.has(escape)) {
|
|
75
|
+
return (0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), `Invalid escape sequence "${escape}" in string template`);
|
|
76
|
+
}
|
|
77
|
+
i++; // skip the next character as it's part of the escape sequence
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
51
82
|
}
|
|
52
83
|
exports.StringTemplate = StringTemplate;
|
|
53
84
|
//# sourceMappingURL=string_template.js.map
|
|
@@ -40,7 +40,7 @@ class Move {
|
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
else if (new _type_utils_1.TypeUtils(input.scope).
|
|
43
|
+
else if (new _type_utils_1.TypeUtils(input.scope).isAssignableNew(sourceType, targetType, source) === false) {
|
|
44
44
|
const message = "Incompatible types";
|
|
45
45
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
46
46
|
return;
|
|
@@ -338,6 +338,9 @@ class SyntaxLogic {
|
|
|
338
338
|
stype = _scope_type_1.ScopeType.FunctionGroup;
|
|
339
339
|
}
|
|
340
340
|
this.scope.push(stype, this.object.getName(), new position_1.Position(1, 1), main.getFilename());
|
|
341
|
+
if (this.object instanceof objects_1.FunctionGroup) {
|
|
342
|
+
this.helpers.proc.findFunctionGroupScope(this.object);
|
|
343
|
+
}
|
|
341
344
|
}
|
|
342
345
|
}
|
|
343
346
|
else if (this.object instanceof objects_1.TypePool) {
|
|
@@ -31,6 +31,9 @@ class FunctionModuleDefinition {
|
|
|
31
31
|
getName() {
|
|
32
32
|
return this.name;
|
|
33
33
|
}
|
|
34
|
+
isGlobalParameters() {
|
|
35
|
+
return this.globalParameters;
|
|
36
|
+
}
|
|
34
37
|
///////////////
|
|
35
38
|
parse(data) {
|
|
36
39
|
if (data.FUNCNAME === undefined) {
|
|
@@ -39,6 +42,7 @@ class FunctionModuleDefinition {
|
|
|
39
42
|
this.name = data.FUNCNAME;
|
|
40
43
|
this.description = data.SHORT_TEXT;
|
|
41
44
|
this.parameters = [];
|
|
45
|
+
this.globalParameters = data.GLOBAL_FLAG === "X";
|
|
42
46
|
this.moduleType = FunctionModuleType.regular;
|
|
43
47
|
if (data.REMOTE_CALL === "R") {
|
|
44
48
|
this.moduleType = FunctionModuleType.remote;
|
package/build/src/registry.js
CHANGED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FMGlobalParametersObsolete = exports.FMGlobalParametersObsoleteConf = void 0;
|
|
4
|
+
const issue_1 = require("../issue");
|
|
5
|
+
const Objects = require("../objects");
|
|
6
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
7
|
+
const position_1 = require("../position");
|
|
8
|
+
class FMGlobalParametersObsoleteConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
9
|
+
}
|
|
10
|
+
exports.FMGlobalParametersObsoleteConf = FMGlobalParametersObsoleteConf;
|
|
11
|
+
class FMGlobalParametersObsolete {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.conf = new FMGlobalParametersObsoleteConf();
|
|
14
|
+
}
|
|
15
|
+
getMetadata() {
|
|
16
|
+
return {
|
|
17
|
+
key: "fm_global_parameters_obsolete",
|
|
18
|
+
title: "FM Global Parameters Obsolete",
|
|
19
|
+
shortDescription: `Check for function modules with global parameteers`,
|
|
20
|
+
extendedInformation: `https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abenglobal_parameters_obsolete.htm`,
|
|
21
|
+
tags: [],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
initialize(_reg) {
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
getConfig() {
|
|
28
|
+
return this.conf;
|
|
29
|
+
}
|
|
30
|
+
setConfig(conf) {
|
|
31
|
+
this.conf = conf;
|
|
32
|
+
}
|
|
33
|
+
run(obj) {
|
|
34
|
+
if (!(obj instanceof Objects.FunctionGroup)) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
const issues = [];
|
|
38
|
+
for (const module of obj.getModules()) {
|
|
39
|
+
if (module.isGlobalParameters() === true) {
|
|
40
|
+
const file = obj.getMainABAPFile();
|
|
41
|
+
if (file === undefined) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const message = `Function Module "${module.getName()}" uses obsolete global parameters`;
|
|
45
|
+
issues.push(issue_1.Issue.atPosition(file, new position_1.Position(1, 1), message, this.getMetadata().key, this.conf.severity));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return issues;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.FMGlobalParametersObsolete = FMGlobalParametersObsolete;
|
|
52
|
+
//# sourceMappingURL=fm_global_parameters_obsolete.js.map
|
package/build/src/rules/index.js
CHANGED
|
@@ -65,6 +65,7 @@ __exportStar(require("./empty_structure"), exports);
|
|
|
65
65
|
__exportStar(require("./exit_or_check"), exports);
|
|
66
66
|
__exportStar(require("./expand_macros"), exports);
|
|
67
67
|
__exportStar(require("./exporting"), exports);
|
|
68
|
+
__exportStar(require("./fm_global_parameters_obsolete"), exports);
|
|
68
69
|
__exportStar(require("./forbidden_identifier"), exports);
|
|
69
70
|
__exportStar(require("./forbidden_pseudo_and_pragma"), exports);
|
|
70
71
|
__exportStar(require("./forbidden_void_type"), exports);
|
|
@@ -78,6 +79,7 @@ __exportStar(require("./identical_conditions"), exports);
|
|
|
78
79
|
__exportStar(require("./identical_contents"), exports);
|
|
79
80
|
__exportStar(require("./identical_descriptions"), exports);
|
|
80
81
|
__exportStar(require("./identical_form_names"), exports);
|
|
82
|
+
__exportStar(require("./identical_move"), exports);
|
|
81
83
|
__exportStar(require("./if_in_if"), exports);
|
|
82
84
|
__exportStar(require("./implement_methods"), exports);
|
|
83
85
|
__exportStar(require("./implicit_start_of_selection"), exports);
|
|
@@ -89,7 +91,6 @@ __exportStar(require("./intf_referencing_clas"), exports);
|
|
|
89
91
|
__exportStar(require("./invalid_table_index"), exports);
|
|
90
92
|
__exportStar(require("./keep_single_parameter_on_one_line"), exports);
|
|
91
93
|
__exportStar(require("./keyword_case"), exports);
|
|
92
|
-
__exportStar(require("./identical_move"), exports);
|
|
93
94
|
__exportStar(require("./line_break_multiple_parameters"), exports);
|
|
94
95
|
__exportStar(require("./line_break_style"), exports);
|
|
95
96
|
__exportStar(require("./line_length"), exports);
|