@abaplint/core 2.110.8 → 2.111.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 +1 -0
- package/build/src/abap/5_syntax/_current_scope.js +17 -0
- package/build/src/abap/5_syntax/basic_types.js +5 -4
- package/build/src/abap/5_syntax/expressions/component_compare_simple.js +1 -1
- package/build/src/abap/5_syntax/expressions/default.js +7 -1
- package/build/src/abap/5_syntax/expressions/field_chain.js +16 -43
- package/build/src/abap/5_syntax/expressions/select.js +11 -4
- package/build/src/abap/5_syntax/statements/tables.js +8 -1
- package/build/src/registry.js +1 -1
- package/build/src/rules/index.js +1 -0
- package/build/src/rules/macro_naming.js +1 -1
- package/build/src/rules/tables_declared_locally.js +56 -0
- package/package.json +2 -2
package/build/abaplint.d.ts
CHANGED
|
@@ -1378,6 +1378,7 @@ export declare class CurrentScope {
|
|
|
1378
1378
|
addFormDefinitions(f: readonly IFormDefinition[]): void;
|
|
1379
1379
|
addInterfaceDefinition(i: IInterfaceDefinition): void;
|
|
1380
1380
|
addNamedIdentifier(name: string, identifier: TypedIdentifier): void;
|
|
1381
|
+
addNamedIdentifierToParent(name: string, identifier: TypedIdentifier): void;
|
|
1381
1382
|
addIdentifier(identifier: TypedIdentifier | undefined): void;
|
|
1382
1383
|
addDeferred(token: Token | undefined, type: "CLAS" | "INTF"): void;
|
|
1383
1384
|
addListPrefix(identifiers: readonly TypedIdentifier[], prefix: string): void;
|
|
@@ -120,6 +120,23 @@ class CurrentScope {
|
|
|
120
120
|
}
|
|
121
121
|
this.current.getData().vars[upper] = identifier;
|
|
122
122
|
}
|
|
123
|
+
addNamedIdentifierToParent(name, identifier) {
|
|
124
|
+
if (this.current === undefined) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const parent = this.current.getParent();
|
|
128
|
+
if (parent === undefined) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const upper = name.toUpperCase();
|
|
132
|
+
if (parent.getData().vars[upper] !== undefined) {
|
|
133
|
+
throw new Error(`Variable name "${name}" already defined`);
|
|
134
|
+
}
|
|
135
|
+
else if (this.isOO() && parent.getData().types[upper] !== undefined) {
|
|
136
|
+
throw new Error(`"${name}" already defined`);
|
|
137
|
+
}
|
|
138
|
+
parent.getData().vars[upper] = identifier;
|
|
139
|
+
}
|
|
123
140
|
addIdentifier(identifier) {
|
|
124
141
|
if (identifier === undefined) {
|
|
125
142
|
return;
|
|
@@ -158,17 +158,18 @@ class BasicTypes {
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
else { // field name
|
|
161
|
-
let sub = undefined;
|
|
162
161
|
if (type instanceof Types.TableType) {
|
|
163
162
|
type = type.getRowType();
|
|
164
163
|
}
|
|
165
164
|
if (type instanceof Types.StructureType) {
|
|
166
|
-
|
|
165
|
+
type = type.getComponentByName(child.getFirstToken().getStr());
|
|
166
|
+
if (type === undefined) {
|
|
167
|
+
return new Types.UnknownType("Type error, field not part of structure " + fullName);
|
|
168
|
+
}
|
|
167
169
|
}
|
|
168
|
-
if (
|
|
170
|
+
else if (!(type instanceof Types.VoidType)) {
|
|
169
171
|
return new Types.UnknownType("Type error, field not part of structure " + fullName);
|
|
170
172
|
}
|
|
171
|
-
type = sub;
|
|
172
173
|
}
|
|
173
174
|
}
|
|
174
175
|
if (type instanceof Types.VoidType) {
|
|
@@ -4,12 +4,18 @@ exports.Default = void 0;
|
|
|
4
4
|
const Expressions = require("../../2_statements/expressions");
|
|
5
5
|
const field_chain_1 = require("./field_chain");
|
|
6
6
|
const _reference_1 = require("../_reference");
|
|
7
|
+
const constant_1 = require("./constant");
|
|
7
8
|
class Default {
|
|
8
9
|
runSyntax(node, scope, filename) {
|
|
9
10
|
const chain = node.findDirectExpression(Expressions.FieldChain);
|
|
10
11
|
if (chain) {
|
|
11
|
-
new field_chain_1.FieldChain().runSyntax(chain, scope, filename, _reference_1.ReferenceType.DataReadReference);
|
|
12
|
+
return new field_chain_1.FieldChain().runSyntax(chain, scope, filename, _reference_1.ReferenceType.DataReadReference);
|
|
12
13
|
}
|
|
14
|
+
const constant = node.findDirectExpression(Expressions.Constant);
|
|
15
|
+
if (constant) {
|
|
16
|
+
return new constant_1.Constant().runSyntax(constant);
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
13
19
|
}
|
|
14
20
|
}
|
|
15
21
|
exports.Default = Default;
|
|
@@ -17,29 +17,25 @@ const source_field_symbol_1 = require("./source_field_symbol");
|
|
|
17
17
|
const source_field_1 = require("./source_field");
|
|
18
18
|
class FieldChain {
|
|
19
19
|
runSyntax(node, scope, filename, refType) {
|
|
20
|
-
var _a, _b, _c
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
context = this.findTop(children[0], scope, filename, refType);
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
20
|
+
var _a, _b, _c;
|
|
21
|
+
if (((_a = node.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.SourceField
|
|
22
|
+
&& node.findDirectExpression(Expressions.ComponentName)) {
|
|
23
|
+
// workaround for names with dashes, eg. "sy-repid"
|
|
27
24
|
const concat = node.concatTokens();
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (refType) {
|
|
35
|
-
scope.addReference(node.getFirstToken(), found, refType, filename);
|
|
36
|
-
}
|
|
37
|
-
// this is not completely correct, but will work, dashes in names is a mess anyhow
|
|
38
|
-
return found.getType();
|
|
25
|
+
const offset = ((_b = node.findDirectExpression(Expressions.FieldOffset)) === null || _b === void 0 ? void 0 : _b.concatTokens()) || "";
|
|
26
|
+
const length = ((_c = node.findDirectExpression(Expressions.FieldLength)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || "";
|
|
27
|
+
const found = scope.findVariable(concat.replace(offset, "").replace(length, ""));
|
|
28
|
+
if (found) {
|
|
29
|
+
if (refType) {
|
|
30
|
+
scope.addReference(node.getFirstToken(), found, refType, filename);
|
|
39
31
|
}
|
|
32
|
+
// this is not completely correct, but will work, dashes in names is a mess anyhow
|
|
33
|
+
return found.getType();
|
|
40
34
|
}
|
|
41
|
-
throw error;
|
|
42
35
|
}
|
|
36
|
+
let context = undefined;
|
|
37
|
+
const children = node.getChildren();
|
|
38
|
+
context = this.findTop(children[0], scope, filename, refType);
|
|
43
39
|
for (let i = 1; i < children.length; i++) {
|
|
44
40
|
const current = children[i];
|
|
45
41
|
if (current === undefined) {
|
|
@@ -90,30 +86,7 @@ class FieldChain {
|
|
|
90
86
|
if (context instanceof basic_1.TableType && context.isWithHeader()) {
|
|
91
87
|
context = context.getRowType();
|
|
92
88
|
}
|
|
93
|
-
|
|
94
|
-
context = new component_name_1.ComponentName().runSyntax(context, current);
|
|
95
|
-
}
|
|
96
|
-
catch (error) {
|
|
97
|
-
const concat = node.concatTokens();
|
|
98
|
-
if (concat.includes("-")) {
|
|
99
|
-
// workaround for names with dashes, eg. "sy-repid"
|
|
100
|
-
const offset = ((_d = node.findDirectExpression(Expressions.FieldOffset)) === null || _d === void 0 ? void 0 : _d.concatTokens()) || "";
|
|
101
|
-
const length = ((_e = node.findDirectExpression(Expressions.FieldLength)) === null || _e === void 0 ? void 0 : _e.concatTokens()) || "";
|
|
102
|
-
const found = scope.findVariable(concat.replace(offset, "").replace(length, ""));
|
|
103
|
-
if (found) {
|
|
104
|
-
if (refType) {
|
|
105
|
-
scope.addReference(node.getFirstToken(), found, refType, filename);
|
|
106
|
-
}
|
|
107
|
-
context = found.getType();
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
throw error;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
throw error;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
89
|
+
context = new component_name_1.ComponentName().runSyntax(context, current);
|
|
117
90
|
}
|
|
118
91
|
else if (current instanceof nodes_1.ExpressionNode
|
|
119
92
|
&& current.get() instanceof Expressions.TableExpression) {
|
|
@@ -12,10 +12,11 @@ const sql_source_1 = require("./sql_source");
|
|
|
12
12
|
const sql_compare_1 = require("./sql_compare");
|
|
13
13
|
const sql_order_by_1 = require("./sql_order_by");
|
|
14
14
|
const dynamic_1 = require("./dynamic");
|
|
15
|
+
const _reference_1 = require("../_reference");
|
|
15
16
|
const isSimple = /^\w+$/;
|
|
16
17
|
class Select {
|
|
17
18
|
runSyntax(node, scope, filename, skipImplicitInto = false) {
|
|
18
|
-
var _a
|
|
19
|
+
var _a;
|
|
19
20
|
const token = node.getFirstToken();
|
|
20
21
|
const from = node.findDirectExpression(Expressions.SQLFrom);
|
|
21
22
|
const dbSources = from ? new sql_from_1.SQLFrom().runSyntax(from, scope, filename) : [];
|
|
@@ -45,9 +46,15 @@ class Select {
|
|
|
45
46
|
const fields = (_a = node.findFirstExpression(Expressions.SQLAggregation)) === null || _a === void 0 ? void 0 : _a.concatTokens();
|
|
46
47
|
const c = new RegExp(/^count\(\s*\*\s*\)$/, "i");
|
|
47
48
|
if (fields === undefined || c.test(fields) === false) {
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
50
|
-
|
|
49
|
+
const nameToken = from === null || from === void 0 ? void 0 : from.findDirectExpression(Expressions.SQLFromSource);
|
|
50
|
+
if (nameToken) {
|
|
51
|
+
const found = scope.findVariable(nameToken.concatTokens());
|
|
52
|
+
if (found) {
|
|
53
|
+
scope.addReference(nameToken.getFirstToken(), found, _reference_1.ReferenceType.DataWriteReference, filename);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
throw new Error(`Target variable ${nameToken.concatTokens()} not found in scope`);
|
|
57
|
+
}
|
|
51
58
|
}
|
|
52
59
|
}
|
|
53
60
|
}
|
|
@@ -4,6 +4,7 @@ exports.Tables = void 0;
|
|
|
4
4
|
const Expressions = require("../../2_statements/expressions");
|
|
5
5
|
const _typed_identifier_1 = require("../../types/_typed_identifier");
|
|
6
6
|
const unknown_type_1 = require("../../types/basic/unknown_type");
|
|
7
|
+
const _scope_type_1 = require("../_scope_type");
|
|
7
8
|
class Tables {
|
|
8
9
|
runSyntax(node, scope, filename) {
|
|
9
10
|
var _a, _b;
|
|
@@ -19,7 +20,13 @@ class Tables {
|
|
|
19
20
|
const found = (_b = scope.getDDIC()) === null || _b === void 0 ? void 0 : _b.lookupTableOrView(name);
|
|
20
21
|
if (found) {
|
|
21
22
|
scope.getDDICReferences().addUsing(scope.getParentObj(), { object: found.object, filename: filename, token: nameToken });
|
|
22
|
-
scope.
|
|
23
|
+
if (scope.getType() === _scope_type_1.ScopeType.Form || scope.getType() === _scope_type_1.ScopeType.FunctionModule) {
|
|
24
|
+
// hoist TABLES definitions to global scope
|
|
25
|
+
scope.addNamedIdentifierToParent(nameToken.getStr(), new _typed_identifier_1.TypedIdentifier(nameToken, filename, found.type));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(nameToken, filename, found.type));
|
|
29
|
+
}
|
|
23
30
|
return;
|
|
24
31
|
}
|
|
25
32
|
// this should never happen,
|
package/build/src/registry.js
CHANGED
package/build/src/rules/index.js
CHANGED
|
@@ -159,6 +159,7 @@ __exportStar(require("./superclass_final"), exports);
|
|
|
159
159
|
__exportStar(require("./superfluous_value"), exports);
|
|
160
160
|
__exportStar(require("./sy_modification"), exports);
|
|
161
161
|
__exportStar(require("./tabl_enhancement_category"), exports);
|
|
162
|
+
__exportStar(require("./tables_declared_locally"), exports);
|
|
162
163
|
__exportStar(require("./try_without_catch"), exports);
|
|
163
164
|
__exportStar(require("./type_form_parameters"), exports);
|
|
164
165
|
__exportStar(require("./types_naming"), exports);
|
|
@@ -26,7 +26,7 @@ class MacroNaming extends _abap_rule_1.ABAPRule {
|
|
|
26
26
|
key: "macro_naming",
|
|
27
27
|
title: "Macro naming conventions",
|
|
28
28
|
shortDescription: `Allows you to enforce a pattern for macro definitions`,
|
|
29
|
-
extendedInformation: `Use rule "avoid_use" to avoid macros
|
|
29
|
+
extendedInformation: `Use rule "avoid_use" to avoid macros altogether.`,
|
|
30
30
|
tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.SingleFile],
|
|
31
31
|
badExample: `DEFINE something.
|
|
32
32
|
END-OF-DEFINITION.`,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TablesDeclaredLocally = exports.TablesDeclaredLocallyConf = void 0;
|
|
4
|
+
const issue_1 = require("../issue");
|
|
5
|
+
const Statements = require("../abap/2_statements/statements");
|
|
6
|
+
const Structures = require("../abap/3_structures/structures");
|
|
7
|
+
const _abap_rule_1 = require("./_abap_rule");
|
|
8
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
9
|
+
const _irule_1 = require("./_irule");
|
|
10
|
+
class TablesDeclaredLocallyConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
11
|
+
}
|
|
12
|
+
exports.TablesDeclaredLocallyConf = TablesDeclaredLocallyConf;
|
|
13
|
+
class TablesDeclaredLocally extends _abap_rule_1.ABAPRule {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.conf = new TablesDeclaredLocallyConf();
|
|
17
|
+
}
|
|
18
|
+
getMetadata() {
|
|
19
|
+
return {
|
|
20
|
+
key: "tables_declared_locally",
|
|
21
|
+
title: "Check for locally declared TABLES",
|
|
22
|
+
shortDescription: `TABLES are always global, so declare them globally`,
|
|
23
|
+
extendedInformation: `https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-us/abaptables.htm`,
|
|
24
|
+
tags: [_irule_1.RuleTag.SingleFile],
|
|
25
|
+
badExample: `FORM foo.
|
|
26
|
+
TABLES t100.
|
|
27
|
+
ENDFORM.`,
|
|
28
|
+
goodExample: `TABLES t000.`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
getConfig() {
|
|
32
|
+
return this.conf;
|
|
33
|
+
}
|
|
34
|
+
setConfig(conf) {
|
|
35
|
+
this.conf = conf;
|
|
36
|
+
}
|
|
37
|
+
runParsed(file) {
|
|
38
|
+
const issues = [];
|
|
39
|
+
const structure = file.getStructure();
|
|
40
|
+
if (structure === undefined) {
|
|
41
|
+
return issues;
|
|
42
|
+
}
|
|
43
|
+
const procedures = structure.findAllStructuresMulti([Structures.Form, Structures.FunctionModule]);
|
|
44
|
+
for (const p of procedures) {
|
|
45
|
+
const tablesStatement = p.findFirstStatement(Statements.Tables);
|
|
46
|
+
if (tablesStatement) {
|
|
47
|
+
const message = "Declare TABLES globaly";
|
|
48
|
+
const issue = issue_1.Issue.atStatement(file, tablesStatement, message, this.getMetadata().key, this.conf.severity);
|
|
49
|
+
issues.push(issue);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return issues;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.TablesDeclaredLocally = TablesDeclaredLocally;
|
|
56
|
+
//# sourceMappingURL=tables_declared_locally.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.111.1",
|
|
4
4
|
"description": "abaplint - Core API",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/abaplint.d.ts",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"homepage": "https://abaplint.org",
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@microsoft/api-extractor": "^7.47.
|
|
53
|
+
"@microsoft/api-extractor": "^7.47.1",
|
|
54
54
|
"@types/chai": "^4.3.16",
|
|
55
55
|
"@types/mocha": "^10.0.7",
|
|
56
56
|
"@types/node": "^20.14.10",
|