@abaplint/core 2.120.50 → 2.120.51
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.
|
@@ -337,6 +337,20 @@ class TypeUtils {
|
|
|
337
337
|
|| node.findFirstExpression(Expressions.ArithOperator) !== undefined;
|
|
338
338
|
return calculated;
|
|
339
339
|
}
|
|
340
|
+
// a character constant is only assignable to a hexadecimal target if it can be
|
|
341
|
+
// interpreted as a hexadecimal value
|
|
342
|
+
isHexConstant(node) {
|
|
343
|
+
const constant = node === null || node === void 0 ? void 0 : node.concatTokens();
|
|
344
|
+
if (constant === undefined) {
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
if ((constant.startsWith("'") && constant.endsWith("'"))
|
|
348
|
+
|| (constant.startsWith("`") && constant.endsWith("`"))) {
|
|
349
|
+
const value = constant.substring(1, constant.length - 1);
|
|
350
|
+
return value.length > 0 && /^[0-9A-Fa-f]+$/.test(value);
|
|
351
|
+
}
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
340
354
|
isAssignableNew(source, target, node) {
|
|
341
355
|
const calculated = (node === null || node === void 0 ? void 0 : node.findFirstExpression(Expressions.ArithOperator)) !== undefined;
|
|
342
356
|
if (calculated && source instanceof basic_1.HexType && target instanceof basic_1.IntegerType) {
|
|
@@ -402,7 +416,7 @@ class TypeUtils {
|
|
|
402
416
|
}
|
|
403
417
|
else if (target instanceof basic_1.XStringType) {
|
|
404
418
|
if (((_d = source.getAbstractTypeData()) === null || _d === void 0 ? void 0 : _d.derivedFromConstant) === true) {
|
|
405
|
-
return (node
|
|
419
|
+
return this.isHexConstant(node);
|
|
406
420
|
}
|
|
407
421
|
return false;
|
|
408
422
|
}
|
package/build/src/registry.js
CHANGED
|
@@ -1058,15 +1058,19 @@ ${indentation}${uniqueName} = ${source.concatTokens()}.\n${indentation}`);
|
|
|
1058
1058
|
continue;
|
|
1059
1059
|
}
|
|
1060
1060
|
const condition = this.tableCondition(tableExpression);
|
|
1061
|
-
|
|
1061
|
+
// ASSIGNING, not INTO: from v740 a table expression in a read position addresses the
|
|
1062
|
+
// row rather than copying it, so "REF #( tab[ i ]-comp )" and "ASSIGN tab[ i ]-comp"
|
|
1063
|
+
// hand back an address INTO a work area would not preserve. The write path
|
|
1064
|
+
// (moveWithTableTarget) already lowers to ASSIGNING for the same reason.
|
|
1065
|
+
const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
|
|
1062
1066
|
const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
|
|
1063
1067
|
const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
|
|
1064
1068
|
const firstToken = high.getFirstToken();
|
|
1065
1069
|
// note that the tabix restore should be done before throwing the exception
|
|
1066
|
-
const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `
|
|
1070
|
+
const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `FIELD-SYMBOLS ${uniqueName} LIKE LINE OF ${pre}.
|
|
1067
1071
|
${indentation}DATA ${tabixBackup} LIKE sy-tabix.
|
|
1068
1072
|
${indentation}${tabixBackup} = sy-tabix.
|
|
1069
|
-
${indentation}READ TABLE ${pre} ${condition}
|
|
1073
|
+
${indentation}READ TABLE ${pre} ${condition}ASSIGNING ${uniqueName}.
|
|
1070
1074
|
${indentation}sy-tabix = ${tabixBackup}.
|
|
1071
1075
|
${indentation}IF sy-subrc <> 0.
|
|
1072
1076
|
${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
|
|
@@ -1820,8 +1824,7 @@ CONSTANTS: BEGIN OF ${structureName},\n`;
|
|
|
1820
1824
|
if (index === undefined) {
|
|
1821
1825
|
return undefined;
|
|
1822
1826
|
}
|
|
1823
|
-
|
|
1824
|
-
uniqueName = `<${uniqueName}>`;
|
|
1827
|
+
const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
|
|
1825
1828
|
const tName = target.concatTokens().split("[")[0];
|
|
1826
1829
|
const condition = this.tableCondition(tableExpression);
|
|
1827
1830
|
const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
|
|
@@ -2833,12 +2836,16 @@ ${indentation} output = ${uniqueName}.\n`;
|
|
|
2833
2836
|
}
|
|
2834
2837
|
return undefined;
|
|
2835
2838
|
}
|
|
2836
|
-
|
|
2839
|
+
/** a FIELD-SYMBOLS declaration is known to the scope under its bracketed spelling, so
|
|
2840
|
+
* the collision check has to use that spelling too - otherwise a second outline in the
|
|
2841
|
+
* same method is handed a name that is already taken and the result does not compile */
|
|
2842
|
+
uniqueName(position, filename, highSyntax, fieldSymbol = false) {
|
|
2843
|
+
const decorate = (name) => fieldSymbol === true ? `<${name}>` : name;
|
|
2837
2844
|
const spag = highSyntax.spaghetti.lookupPosition(position, filename);
|
|
2838
2845
|
if (spag === undefined) {
|
|
2839
2846
|
const name = "temprr" + this.counter;
|
|
2840
2847
|
this.counter++;
|
|
2841
|
-
return name;
|
|
2848
|
+
return decorate(name);
|
|
2842
2849
|
}
|
|
2843
2850
|
let postfix = "";
|
|
2844
2851
|
if (spag.getIdentifier().stype === _scope_type_1.ScopeType.ClassDefinition) {
|
|
@@ -2847,7 +2854,7 @@ ${indentation} output = ${uniqueName}.\n`;
|
|
|
2847
2854
|
postfix = "_" + hash.substring(0, 10);
|
|
2848
2855
|
}
|
|
2849
2856
|
while (true) {
|
|
2850
|
-
const name = "temp" + this.counter + postfix;
|
|
2857
|
+
const name = decorate("temp" + this.counter + postfix);
|
|
2851
2858
|
const exists = this.existsRecursive(spag, name);
|
|
2852
2859
|
this.counter++;
|
|
2853
2860
|
if (exists === false) {
|
package/build/src/rules/index.js
CHANGED
|
@@ -202,6 +202,7 @@ __exportStar(require("./use_line_exists"), exports);
|
|
|
202
202
|
__exportStar(require("./use_new"), exports);
|
|
203
203
|
__exportStar(require("./when_others_last"), exports);
|
|
204
204
|
__exportStar(require("./whitespace_end"), exports);
|
|
205
|
+
__exportStar(require("./wrong_abapdoc_position"), exports);
|
|
205
206
|
__exportStar(require("./xml_consistency"), exports);
|
|
206
207
|
__exportStar(require("./no_exclamation_escape"), exports);
|
|
207
208
|
__exportStar(require("./xml_bom"), exports);
|
|
@@ -0,0 +1,162 @@
|
|
|
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.WrongAbapdocPosition = exports.WrongAbapdocPositionConf = void 0;
|
|
37
|
+
const Statements = __importStar(require("../abap/2_statements/statements"));
|
|
38
|
+
const issue_1 = require("../issue");
|
|
39
|
+
const _abap_rule_1 = require("./_abap_rule");
|
|
40
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
41
|
+
const _irule_1 = require("./_irule");
|
|
42
|
+
const _statement_1 = require("../abap/2_statements/statements/_statement");
|
|
43
|
+
class WrongAbapdocPositionConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
44
|
+
}
|
|
45
|
+
exports.WrongAbapdocPositionConf = WrongAbapdocPositionConf;
|
|
46
|
+
class WrongAbapdocPosition extends _abap_rule_1.ABAPRule {
|
|
47
|
+
constructor() {
|
|
48
|
+
super(...arguments);
|
|
49
|
+
this.conf = new WrongAbapdocPositionConf();
|
|
50
|
+
}
|
|
51
|
+
getMetadata() {
|
|
52
|
+
return {
|
|
53
|
+
key: "wrong_abapdoc_position",
|
|
54
|
+
title: "Wrong ABAP Doc position",
|
|
55
|
+
shortDescription: `ABAP Doc must be placed directly in front of the declaration it documents.`,
|
|
56
|
+
extendedInformation: `ABAP Doc documents the single declaration following it, an ABAP Doc block placed
|
|
57
|
+
elsewhere is silently ignored, leaving the declaration undocumented.
|
|
58
|
+
|
|
59
|
+
The following positions are reported,
|
|
60
|
+
* in front of a chained keyword, ie. before "CONSTANTS:" instead of after the colon,
|
|
61
|
+
* in the middle of a statement, ie. between the parameters of a METHODS definition,
|
|
62
|
+
* directly in front of ENDCLASS, ENDINTERFACE or a SECTION statement.
|
|
63
|
+
|
|
64
|
+
Only checks ABAP Doc inside class definitions and interfaces.`,
|
|
65
|
+
tags: [_irule_1.RuleTag.SingleFile],
|
|
66
|
+
badExample: `CLASS zcl_foo DEFINITION PUBLIC.
|
|
67
|
+
PUBLIC SECTION.
|
|
68
|
+
"! Navigation modes
|
|
69
|
+
CONSTANTS:
|
|
70
|
+
BEGIN OF cs_nav_mode,
|
|
71
|
+
back TYPE i VALUE 1,
|
|
72
|
+
END OF cs_nav_mode.
|
|
73
|
+
ENDCLASS.`,
|
|
74
|
+
goodExample: `CLASS zcl_foo DEFINITION PUBLIC.
|
|
75
|
+
PUBLIC SECTION.
|
|
76
|
+
CONSTANTS:
|
|
77
|
+
"! Navigation modes
|
|
78
|
+
BEGIN OF cs_nav_mode,
|
|
79
|
+
back TYPE i VALUE 1,
|
|
80
|
+
END OF cs_nav_mode.
|
|
81
|
+
ENDCLASS.`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
getConfig() {
|
|
85
|
+
return this.conf;
|
|
86
|
+
}
|
|
87
|
+
setConfig(conf) {
|
|
88
|
+
this.conf = conf;
|
|
89
|
+
}
|
|
90
|
+
runParsed(file) {
|
|
91
|
+
const issues = [];
|
|
92
|
+
const statements = file.getStatements();
|
|
93
|
+
let definition = false;
|
|
94
|
+
for (let i = 0; i < statements.length; i++) {
|
|
95
|
+
const statement = statements[i];
|
|
96
|
+
const type = statement.get();
|
|
97
|
+
if (type instanceof Statements.ClassDefinition || type instanceof Statements.Interface) {
|
|
98
|
+
definition = true;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
else if (type instanceof Statements.EndClass || type instanceof Statements.EndInterface) {
|
|
102
|
+
definition = false;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
else if (definition === false || this.isAbapdoc(statement) === false) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
else if (this.isAbapdoc(statements[i - 1]) === true
|
|
109
|
+
&& statements[i - 1].getStart().getRow() + 1 === statement.getStart().getRow()) {
|
|
110
|
+
continue; // only report the first row of each block
|
|
111
|
+
}
|
|
112
|
+
let next = undefined;
|
|
113
|
+
for (let j = i + 1; j < statements.length; j++) {
|
|
114
|
+
if (statements[j].get() instanceof _statement_1.Comment) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
next = statements[j];
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
if (next === undefined) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const message = this.check(statement, next);
|
|
124
|
+
if (message !== undefined) {
|
|
125
|
+
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return issues;
|
|
129
|
+
}
|
|
130
|
+
isAbapdoc(statement) {
|
|
131
|
+
return (statement === null || statement === void 0 ? void 0 : statement.get()) instanceof _statement_1.Comment
|
|
132
|
+
&& statement.getFirstToken().getStr().startsWith(`"!`);
|
|
133
|
+
}
|
|
134
|
+
check(abapdoc, next) {
|
|
135
|
+
const type = next.get();
|
|
136
|
+
if (type instanceof Statements.EndClass
|
|
137
|
+
|| type instanceof Statements.EndInterface
|
|
138
|
+
|| type instanceof Statements.Public
|
|
139
|
+
|| type instanceof Statements.Protected
|
|
140
|
+
|| type instanceof Statements.Private) {
|
|
141
|
+
return "ABAP Doc does not document anything, move or delete it";
|
|
142
|
+
}
|
|
143
|
+
const position = abapdoc.getStart();
|
|
144
|
+
const colon = next.getColon();
|
|
145
|
+
if (colon === undefined) {
|
|
146
|
+
if (position.isAfter(next.getStart()) === true) {
|
|
147
|
+
return "ABAP Doc inside statement, move it in front of the statement";
|
|
148
|
+
}
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
if (position.isBefore(colon.getStart()) === true) {
|
|
152
|
+
return "ABAP Doc in front of chained statement, move it after the colon";
|
|
153
|
+
}
|
|
154
|
+
const member = next.getTokens().find(t => t.getStart().isAfter(colon.getStart()));
|
|
155
|
+
if (member !== undefined && position.isAfter(member.getStart()) === true) {
|
|
156
|
+
return "ABAP Doc inside statement, move it in front of the chained declaration";
|
|
157
|
+
}
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.WrongAbapdocPosition = WrongAbapdocPosition;
|
|
162
|
+
//# sourceMappingURL=wrong_abapdoc_position.js.map
|