@abaplint/core 2.88.8 → 2.89.0
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 +8 -1
- package/build/src/abap/2_statements/expressions/index.js +1 -0
- package/build/src/abap/2_statements/expressions/select.js +2 -2
- package/build/src/abap/2_statements/expressions/select_loop.js +3 -3
- package/build/src/abap/2_statements/expressions/sql_up_to.js +13 -0
- package/build/src/abap/5_syntax/statements/data.js +5 -0
- package/build/src/abap/5_syntax/statements/selection_screen.js +4 -1
- package/build/src/objects/class.js +8 -0
- package/build/src/registry.js +1 -1
- package/build/src/rules/check_transformation_exists.js +7 -5
- package/build/src/rules/classic_exceptions_overlap.js +69 -0
- package/build/src/rules/definitions_top.js +2 -1
- package/build/src/rules/double_space.js +1 -0
- package/build/src/rules/downport.js +4 -2
- package/build/src/rules/identical_form_names.js +1 -0
- package/build/src/rules/index.js +4 -2
- package/build/src/rules/local_testclass_consistency.js +63 -0
- package/build/src/rules/no_inline_in_optional_branches.js +71 -0
- package/build/src/rules/unused_variables.js +1 -0
- package/package.json +4 -4
- package/build/src/rules/local_testclass_location.js +0 -54
package/build/abaplint.d.ts
CHANGED
|
@@ -741,6 +741,7 @@ declare class Class extends ABAPObject {
|
|
|
741
741
|
getNameFromXML(): string | undefined;
|
|
742
742
|
getCategory(): string | undefined;
|
|
743
743
|
getLocalsImpFile(): ABAPFile | undefined;
|
|
744
|
+
getTestclassFile(): ABAPFile | undefined;
|
|
744
745
|
private parseXML;
|
|
745
746
|
}
|
|
746
747
|
|
|
@@ -1952,6 +1953,7 @@ declare namespace Expressions {
|
|
|
1952
1953
|
TypeTableKey,
|
|
1953
1954
|
TypeTable,
|
|
1954
1955
|
Type_2 as Type,
|
|
1956
|
+
SQLUpTo,
|
|
1955
1957
|
ValueBody,
|
|
1956
1958
|
ValueBodyLines,
|
|
1957
1959
|
Value,
|
|
@@ -2651,7 +2653,8 @@ export declare const enum IdentifierMeta {
|
|
|
2651
2653
|
BuiltIn = "built-in",
|
|
2652
2654
|
DDIC = "ddic",
|
|
2653
2655
|
Static = "static",
|
|
2654
|
-
Enum = "enum"
|
|
2656
|
+
Enum = "enum",
|
|
2657
|
+
SelectionScreenTab = "selection_screen_tab"
|
|
2655
2658
|
}
|
|
2656
2659
|
|
|
2657
2660
|
export declare interface IDependency {
|
|
@@ -4977,6 +4980,10 @@ declare class SQLTarget extends Expression {
|
|
|
4977
4980
|
getRunnable(): IStatementRunnable;
|
|
4978
4981
|
}
|
|
4979
4982
|
|
|
4983
|
+
declare class SQLUpTo extends Expression {
|
|
4984
|
+
getRunnable(): IStatementRunnable;
|
|
4985
|
+
}
|
|
4986
|
+
|
|
4980
4987
|
declare class StartOfSelection implements IStatement {
|
|
4981
4988
|
getMatcher(): IStatementRunnable;
|
|
4982
4989
|
}
|
|
@@ -200,6 +200,7 @@ __exportStar(require("./type_param"), exports);
|
|
|
200
200
|
__exportStar(require("./type_table_key"), exports);
|
|
201
201
|
__exportStar(require("./type_table"), exports);
|
|
202
202
|
__exportStar(require("./type"), exports);
|
|
203
|
+
__exportStar(require("./sql_up_to"), exports);
|
|
203
204
|
__exportStar(require("./value_body"), exports);
|
|
204
205
|
__exportStar(require("./value_body_lines"), exports);
|
|
205
206
|
__exportStar(require("./value"), exports);
|
|
@@ -8,16 +8,16 @@ const sql_group_by_1 = require("./sql_group_by");
|
|
|
8
8
|
const sql_into_structure_1 = require("./sql_into_structure");
|
|
9
9
|
const tokens_1 = require("../../1_lexer/tokens");
|
|
10
10
|
const sql_field_name_1 = require("./sql_field_name");
|
|
11
|
+
const sql_up_to_1 = require("./sql_up_to");
|
|
11
12
|
class Select extends combi_1.Expression {
|
|
12
13
|
getRunnable() {
|
|
13
14
|
const into = (0, combi_1.altPrio)(_1.SQLIntoTable, sql_into_structure_1.SQLIntoStructure);
|
|
14
15
|
const where = (0, combi_1.seq)("WHERE", _1.SQLCond);
|
|
15
|
-
const up = (0, combi_1.seq)("UP TO", _1.SQLSource, "ROWS");
|
|
16
16
|
const offset = (0, combi_1.ver)(version_1.Version.v751, (0, combi_1.seq)("OFFSET", _1.SQLSource));
|
|
17
17
|
const client = (0, combi_1.str)("CLIENT SPECIFIED");
|
|
18
18
|
const bypass = (0, combi_1.str)("BYPASSING BUFFER");
|
|
19
19
|
const fields = (0, combi_1.seq)("FIELDS", _1.SQLFieldList);
|
|
20
|
-
const perm = (0, combi_1.per)(_1.SQLFrom, into, _1.SQLForAllEntries, where, _1.SQLOrderBy,
|
|
20
|
+
const perm = (0, combi_1.per)(_1.SQLFrom, into, _1.SQLForAllEntries, where, _1.SQLOrderBy, sql_up_to_1.SQLUpTo, offset, client, _1.SQLHaving, bypass, sql_group_by_1.SQLGroupBy, fields, _1.DatabaseConnection);
|
|
21
21
|
const paren = (0, combi_1.seq)((0, combi_1.tok)(tokens_1.WParenLeftW), sql_field_name_1.SQLFieldName, (0, combi_1.tok)(tokens_1.WParenRightW));
|
|
22
22
|
const ret = (0, combi_1.seq)("SELECT", (0, combi_1.altPrio)("DISTINCT", (0, combi_1.optPrio)((0, combi_1.seq)("SINGLE", (0, combi_1.optPrio)("FOR UPDATE")))), (0, combi_1.optPrio)((0, combi_1.altPrio)(_1.SQLFieldList, paren)), perm, (0, combi_1.optPrio)(_1.SQLHints));
|
|
23
23
|
return ret;
|
|
@@ -9,16 +9,16 @@ const sql_into_structure_1 = require("./sql_into_structure");
|
|
|
9
9
|
const sql_field_list_1 = require("./sql_field_list");
|
|
10
10
|
const sql_hints_1 = require("./sql_hints");
|
|
11
11
|
const sql_field_list_loop_1 = require("./sql_field_list_loop");
|
|
12
|
+
const sql_up_to_1 = require("./sql_up_to");
|
|
12
13
|
class SelectLoop extends combi_1.Expression {
|
|
13
14
|
getRunnable() {
|
|
14
15
|
const where = (0, combi_1.seq)("WHERE", _1.SQLCond);
|
|
15
16
|
const client = "CLIENT SPECIFIED";
|
|
16
17
|
const bypass = "BYPASSING BUFFER";
|
|
17
|
-
const up = (0, combi_1.seq)("UP TO", _1.SQLSource, "ROWS");
|
|
18
18
|
const pack = (0, combi_1.seq)("PACKAGE SIZE", _1.SQLSource);
|
|
19
19
|
const tab = (0, combi_1.seq)(_1.SQLIntoTable, (0, combi_1.alt)(pack, (0, combi_1.seq)(_1.SQLFrom, pack), (0, combi_1.seq)(pack, _1.SQLFrom)));
|
|
20
|
-
const perm = (0, combi_1.per)(_1.SQLFrom, where,
|
|
21
|
-
const strict = (0, combi_1.seq)(_1.SQLFrom, "FIELDS", sql_field_list_1.SQLFieldList, where, sql_into_structure_1.SQLIntoStructure,
|
|
20
|
+
const perm = (0, combi_1.per)(_1.SQLFrom, where, sql_up_to_1.SQLUpTo, sql_order_by_1.SQLOrderBy, sql_having_1.SQLHaving, client, bypass, _1.SQLGroupBy, _1.SQLForAllEntries, (0, combi_1.alt)(tab, sql_into_structure_1.SQLIntoStructure));
|
|
21
|
+
const strict = (0, combi_1.seq)(_1.SQLFrom, "FIELDS", sql_field_list_1.SQLFieldList, where, sql_into_structure_1.SQLIntoStructure, sql_up_to_1.SQLUpTo);
|
|
22
22
|
const ret = (0, combi_1.seq)("SELECT", (0, combi_1.altPrio)((0, combi_1.seq)((0, combi_1.optPrio)("DISTINCT"), sql_field_list_loop_1.SQLFieldListLoop, perm), strict), (0, combi_1.optPrio)(sql_hints_1.SQLHints));
|
|
23
23
|
return ret;
|
|
24
24
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SQLUpTo = void 0;
|
|
4
|
+
const combi_1 = require("../combi");
|
|
5
|
+
const sql_source_1 = require("./sql_source");
|
|
6
|
+
class SQLUpTo extends combi_1.Expression {
|
|
7
|
+
getRunnable() {
|
|
8
|
+
const up = (0, combi_1.seq)("UP TO", sql_source_1.SQLSource, "ROWS");
|
|
9
|
+
return up;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.SQLUpTo = SQLUpTo;
|
|
13
|
+
//# sourceMappingURL=sql_up_to.js.map
|
|
@@ -5,8 +5,13 @@ const Expressions = require("../../2_statements/expressions");
|
|
|
5
5
|
const _typed_identifier_1 = require("../../types/_typed_identifier");
|
|
6
6
|
const data_definition_1 = require("../expressions/data_definition");
|
|
7
7
|
const unknown_type_1 = require("../../types/basic/unknown_type");
|
|
8
|
+
const basic_types_1 = require("../basic_types");
|
|
8
9
|
class Data {
|
|
9
10
|
runSyntax(node, scope, filename) {
|
|
11
|
+
const val = node.findFirstExpression(Expressions.Value);
|
|
12
|
+
if (val) {
|
|
13
|
+
new basic_types_1.BasicTypes(filename, scope).findValue(node);
|
|
14
|
+
}
|
|
10
15
|
const dd = node.findFirstExpression(Expressions.DataDefinition);
|
|
11
16
|
if (dd) {
|
|
12
17
|
return new data_definition_1.DataDefinition().runSyntax(dd, scope, filename);
|
|
@@ -18,7 +18,10 @@ class SelectionScreen {
|
|
|
18
18
|
{ name: "DYNNR", type: new basic_1.CharacterType(4) },
|
|
19
19
|
{ name: "ACTIVETAB", type: new basic_1.CharacterType(132) },
|
|
20
20
|
]);
|
|
21
|
-
scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(name, filename, type));
|
|
21
|
+
scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(name, filename, type, ["selection_screen_tab" /* SelectionScreenTab */]));
|
|
22
|
+
}
|
|
23
|
+
else if (concat.startsWith("SELECTION-SCREEN TAB")) {
|
|
24
|
+
scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(name, filename, new basic_1.CharacterType(83), ["selection_screen_tab" /* SelectionScreenTab */]));
|
|
22
25
|
}
|
|
23
26
|
else {
|
|
24
27
|
scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(name, filename, new basic_1.CharacterType(83)));
|
|
@@ -78,6 +78,14 @@ class Class extends _abap_object_1.ABAPObject {
|
|
|
78
78
|
}
|
|
79
79
|
return undefined;
|
|
80
80
|
}
|
|
81
|
+
getTestclassFile() {
|
|
82
|
+
for (const file of this.getABAPFiles()) {
|
|
83
|
+
if (file.getFilename().endsWith(".clas.testclasses.abap")) {
|
|
84
|
+
return file;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
81
89
|
/////////////////////////
|
|
82
90
|
parseXML() {
|
|
83
91
|
if (this.parsedXML !== undefined) {
|
package/build/src/registry.js
CHANGED
|
@@ -40,13 +40,15 @@ class CheckTransformationExists extends _abap_rule_1.ABAPRule {
|
|
|
40
40
|
}
|
|
41
41
|
for (const s of file.getStatements()) {
|
|
42
42
|
if (s.get() instanceof statements_1.CallTransformation) {
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
43
|
+
const nameExpression = s.findFirstExpression(expressions_1.NamespaceSimpleName);
|
|
44
|
+
if (nameExpression === undefined) {
|
|
45
45
|
continue;
|
|
46
46
|
}
|
|
47
|
-
const tok =
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
const tok = nameExpression.getFirstToken();
|
|
48
|
+
const name = tok.getStr();
|
|
49
|
+
if (this.reg.inErrorNamespace(name) === true
|
|
50
|
+
&& this.reg.getObject("XSLT", name) === undefined) {
|
|
51
|
+
const issue = issue_1.Issue.atToken(file, tok, this.getDescription(name), this.getMetadata().key);
|
|
50
52
|
output.push(issue);
|
|
51
53
|
}
|
|
52
54
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClassicExceptionsOverlap = exports.ClassicExceptionsOverlapConf = void 0;
|
|
4
|
+
const issue_1 = require("../issue");
|
|
5
|
+
const _abap_rule_1 = require("./_abap_rule");
|
|
6
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
7
|
+
const Expressions = require("../abap/2_statements/expressions");
|
|
8
|
+
const _irule_1 = require("./_irule");
|
|
9
|
+
class ClassicExceptionsOverlapConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
10
|
+
}
|
|
11
|
+
exports.ClassicExceptionsOverlapConf = ClassicExceptionsOverlapConf;
|
|
12
|
+
class ClassicExceptionsOverlap extends _abap_rule_1.ABAPRule {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this.conf = new ClassicExceptionsOverlapConf();
|
|
16
|
+
}
|
|
17
|
+
getMetadata() {
|
|
18
|
+
return {
|
|
19
|
+
key: "classic_exceptions_overlap",
|
|
20
|
+
title: "Classic exceptions overlap when catching",
|
|
21
|
+
shortDescription: `Find overlapping classic exceptions`,
|
|
22
|
+
extendedInformation: `When debugging its typically good to know exactly which exception is caught`,
|
|
23
|
+
tags: [_irule_1.RuleTag.SingleFile],
|
|
24
|
+
badExample: ` EXCEPTIONS
|
|
25
|
+
system_failure = 1 MESSAGE lv_message
|
|
26
|
+
communication_failure = 1 MESSAGE lv_message
|
|
27
|
+
resource_failure = 1
|
|
28
|
+
OTHERS = 1.`,
|
|
29
|
+
goodExample: ` EXCEPTIONS
|
|
30
|
+
system_failure = 1 MESSAGE lv_message
|
|
31
|
+
communication_failure = 2 MESSAGE lv_message
|
|
32
|
+
resource_failure = 3
|
|
33
|
+
OTHERS = 4.`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
getConfig() {
|
|
37
|
+
return this.conf;
|
|
38
|
+
}
|
|
39
|
+
setConfig(conf) {
|
|
40
|
+
this.conf = conf;
|
|
41
|
+
}
|
|
42
|
+
runParsed(file) {
|
|
43
|
+
var _a;
|
|
44
|
+
const output = [];
|
|
45
|
+
const struc = file.getStructure();
|
|
46
|
+
if (struc === undefined) {
|
|
47
|
+
return []; // syntax error
|
|
48
|
+
}
|
|
49
|
+
for (const p of struc.findAllExpressions(Expressions.ParameterListExceptions)) {
|
|
50
|
+
const set = new Set();
|
|
51
|
+
for (const e of p.findAllExpressions(Expressions.ParameterException)) {
|
|
52
|
+
const text = (_a = e.findDirectExpression(Expressions.SimpleName)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
|
|
53
|
+
if (text === undefined) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (set.has(text)) {
|
|
57
|
+
const message = "Exception overlap, " + text;
|
|
58
|
+
const issue = issue_1.Issue.atToken(file, e.getFirstToken(), message, this.getMetadata().key, this.getConfig().severity);
|
|
59
|
+
output.push(issue);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
set.add(text);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return output;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.ClassicExceptionsOverlap = ClassicExceptionsOverlap;
|
|
69
|
+
//# sourceMappingURL=classic_exceptions_overlap.js.map
|
|
@@ -122,7 +122,8 @@ class DefinitionsTop extends _abap_rule_1.ABAPRule {
|
|
|
122
122
|
return undefined;
|
|
123
123
|
}
|
|
124
124
|
buildFix(file, statement, start) {
|
|
125
|
-
|
|
125
|
+
let concat = statement.concatTokens();
|
|
126
|
+
concat = concat.replace(/,$/, ".");
|
|
126
127
|
const fix1 = edit_helper_1.EditHelper.deleteStatement(file, statement);
|
|
127
128
|
const indentation = " ".repeat(statement.getFirstToken().getCol() - 1);
|
|
128
129
|
const fix2 = edit_helper_1.EditHelper.insertAt(file, start.getEnd(), "\n" + indentation + concat);
|
|
@@ -145,6 +145,7 @@ class DoubleSpace extends _abap_rule_1.ABAPRule {
|
|
|
145
145
|
const upper = prev.get().getStr().toUpperCase();
|
|
146
146
|
if (prev instanceof nodes_1.TokenNodeRegex
|
|
147
147
|
|| upper === "("
|
|
148
|
+
|| upper === ")"
|
|
148
149
|
|| upper === "CHANGING"
|
|
149
150
|
|| upper === "EXPORTING"
|
|
150
151
|
|| upper === "OTHERS") {
|
|
@@ -502,14 +502,15 @@ ${indentation}${uniqueName} = ${source.concatTokens()}.\n${indentation}`);
|
|
|
502
502
|
const tabixBackup = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
|
|
503
503
|
const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
|
|
504
504
|
const firstToken = node.getFirstToken();
|
|
505
|
+
// note that the tabix restore should be done before throwing the exception
|
|
505
506
|
const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.
|
|
506
507
|
${indentation}DATA ${tabixBackup} LIKE sy-tabix.
|
|
507
508
|
${indentation}${tabixBackup} = sy-tabix.
|
|
508
509
|
${indentation}READ TABLE ${pre} ${condition}INTO ${uniqueName}.
|
|
510
|
+
${indentation}sy-tabix = ${tabixBackup}.
|
|
509
511
|
${indentation}IF sy-subrc <> 0.
|
|
510
512
|
${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
|
|
511
513
|
${indentation}ENDIF.
|
|
512
|
-
${indentation}sy-tabix = ${tabixBackup}.
|
|
513
514
|
${indentation}`);
|
|
514
515
|
const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, startToken.getStart(), tableExpression.getLastToken().getEnd(), uniqueName);
|
|
515
516
|
const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
|
|
@@ -760,14 +761,15 @@ ${indentation}RAISE EXCEPTION ${uniqueName2}.`;
|
|
|
760
761
|
const condition = this.tableCondition(tableExpression);
|
|
761
762
|
const tabixBackup = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
|
|
762
763
|
const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
|
|
764
|
+
// restore tabix before exeption
|
|
763
765
|
const code = `FIELD-SYMBOLS ${uniqueName} LIKE LINE OF ${tName}.
|
|
764
766
|
${indentation}DATA ${tabixBackup} LIKE sy-tabix.
|
|
765
767
|
${indentation}${tabixBackup} = sy-tabix.
|
|
766
768
|
${indentation}READ TABLE ${tName} ${condition}ASSIGNING ${uniqueName}.
|
|
769
|
+
${indentation}sy-tabix = ${tabixBackup}.
|
|
767
770
|
${indentation}IF sy-subrc <> 0.
|
|
768
771
|
${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
|
|
769
772
|
${indentation}ENDIF.
|
|
770
|
-
${indentation}sy-tabix = ${tabixBackup}.
|
|
771
773
|
${indentation}${uniqueName}`;
|
|
772
774
|
const start = target.getFirstToken().getStart();
|
|
773
775
|
const end = (_a = tableExpression.findDirectTokenByText("]")) === null || _a === void 0 ? void 0 : _a.getEnd();
|
|
@@ -8,6 +8,7 @@ const _abap_object_1 = require("../objects/_abap_object");
|
|
|
8
8
|
class IdenticalFormNamesConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
9
9
|
}
|
|
10
10
|
exports.IdenticalFormNamesConf = IdenticalFormNamesConf;
|
|
11
|
+
// todo: deprecation candidate? this is/should be handled by the syntax check?
|
|
11
12
|
class IdenticalFormNames {
|
|
12
13
|
constructor() {
|
|
13
14
|
this.conf = new IdenticalFormNamesConf();
|
package/build/src/rules/index.js
CHANGED
|
@@ -30,9 +30,9 @@ __exportStar(require("./check_abstract"), exports);
|
|
|
30
30
|
__exportStar(require("./check_comments"), exports);
|
|
31
31
|
__exportStar(require("./check_ddic"), exports);
|
|
32
32
|
__exportStar(require("./check_include"), exports);
|
|
33
|
-
__exportStar(require("./unnecessary_pragma"), exports);
|
|
34
33
|
__exportStar(require("./check_subrc"), exports);
|
|
35
34
|
__exportStar(require("./check_syntax"), exports);
|
|
35
|
+
__exportStar(require("./classic_exceptions_overlap"), exports);
|
|
36
36
|
__exportStar(require("./check_text_elements"), exports);
|
|
37
37
|
__exportStar(require("./check_transformation_exists"), exports);
|
|
38
38
|
__exportStar(require("./class_attribute_names"), exports);
|
|
@@ -80,7 +80,7 @@ __exportStar(require("./line_break_style"), exports);
|
|
|
80
80
|
__exportStar(require("./line_length"), exports);
|
|
81
81
|
__exportStar(require("./line_only_punc"), exports);
|
|
82
82
|
__exportStar(require("./local_class_naming"), exports);
|
|
83
|
-
__exportStar(require("./
|
|
83
|
+
__exportStar(require("./local_testclass_consistency"), exports);
|
|
84
84
|
__exportStar(require("./local_variable_names"), exports);
|
|
85
85
|
__exportStar(require("./main_file_contents"), exports);
|
|
86
86
|
__exportStar(require("./many_parentheses"), exports);
|
|
@@ -99,6 +99,7 @@ __exportStar(require("./nesting"), exports);
|
|
|
99
99
|
__exportStar(require("./newline_between_methods"), exports);
|
|
100
100
|
__exportStar(require("./no_aliases"), exports);
|
|
101
101
|
__exportStar(require("./no_chained_assignment"), exports);
|
|
102
|
+
__exportStar(require("./no_inline_in_optional_branches"), exports);
|
|
102
103
|
__exportStar(require("./no_public_attributes"), exports);
|
|
103
104
|
__exportStar(require("./no_yoda_conditions"), exports);
|
|
104
105
|
__exportStar(require("./nrob_consistency"), exports);
|
|
@@ -144,6 +145,7 @@ __exportStar(require("./types_naming"), exports);
|
|
|
144
145
|
__exportStar(require("./uncaught_exception"), exports);
|
|
145
146
|
__exportStar(require("./unknown_types"), exports);
|
|
146
147
|
__exportStar(require("./unnecessary_chaining"), exports);
|
|
148
|
+
__exportStar(require("./unnecessary_pragma"), exports);
|
|
147
149
|
__exportStar(require("./unreachable_code"), exports);
|
|
148
150
|
__exportStar(require("./unsecure_fae"), exports);
|
|
149
151
|
__exportStar(require("./unused_ddic"), exports);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalTestclassConsistency = exports.LocalTestclassConsistencyConf = void 0;
|
|
4
|
+
const issue_1 = require("../issue");
|
|
5
|
+
const _abap_rule_1 = require("./_abap_rule");
|
|
6
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
7
|
+
const objects_1 = require("../objects");
|
|
8
|
+
const _irule_1 = require("./_irule");
|
|
9
|
+
const version_1 = require("../version");
|
|
10
|
+
class LocalTestclassConsistencyConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
11
|
+
}
|
|
12
|
+
exports.LocalTestclassConsistencyConf = LocalTestclassConsistencyConf;
|
|
13
|
+
class LocalTestclassConsistency extends _abap_rule_1.ABAPRule {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.conf = new LocalTestclassConsistencyConf();
|
|
17
|
+
}
|
|
18
|
+
getMetadata() {
|
|
19
|
+
return {
|
|
20
|
+
key: "local_testclass_consistency",
|
|
21
|
+
title: "Local testclass consistency",
|
|
22
|
+
shortDescription: `Checks that local test classes are placed in the test include, and class unit test flag is set`,
|
|
23
|
+
tags: [_irule_1.RuleTag.Syntax],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
getConfig() {
|
|
27
|
+
return this.conf;
|
|
28
|
+
}
|
|
29
|
+
setConfig(conf) {
|
|
30
|
+
this.conf = conf;
|
|
31
|
+
}
|
|
32
|
+
runParsed(file, obj) {
|
|
33
|
+
var _a;
|
|
34
|
+
const issues = [];
|
|
35
|
+
if (this.reg.getConfig().getVersion() === version_1.Version.v700) {
|
|
36
|
+
// 700 does not have testclass includes
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
if (!(obj instanceof objects_1.Class)) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
for (const c of file.getInfo().listClassDefinitions()) {
|
|
43
|
+
if (c.isLocal && c.isForTesting && !file.getFilename().includes(".testclasses.abap")) {
|
|
44
|
+
const message = "Place local testclass \"" + c.name + "\" in the testclass include";
|
|
45
|
+
const issue = issue_1.Issue.atIdentifier(c.identifier, message, this.getMetadata().key, this.conf.severity);
|
|
46
|
+
issues.push(issue);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (file.getFilename().includes(".testclasses.") === true
|
|
50
|
+
&& obj.getTestclassFile() !== undefined
|
|
51
|
+
&& ((_a = obj.getXML()) === null || _a === void 0 ? void 0 : _a.includes("<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>")) === false) {
|
|
52
|
+
const id = obj.getIdentifier();
|
|
53
|
+
if (id) {
|
|
54
|
+
const message = "Has testclass, but XML does not set <WITH_UNIT_TESTS>";
|
|
55
|
+
const issue = issue_1.Issue.atIdentifier(id, message, this.getMetadata().key, this.conf.severity);
|
|
56
|
+
issues.push(issue);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return issues;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.LocalTestclassConsistency = LocalTestclassConsistency;
|
|
63
|
+
//# sourceMappingURL=local_testclass_consistency.js.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NoInlineInOptionalBranches = exports.NoInlineInOptionalBranchesConf = void 0;
|
|
4
|
+
const issue_1 = require("../issue");
|
|
5
|
+
const _abap_rule_1 = require("./_abap_rule");
|
|
6
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
7
|
+
const Structures = require("../abap/3_structures/structures");
|
|
8
|
+
const Expressions = require("../abap/2_statements/expressions");
|
|
9
|
+
const _irule_1 = require("./_irule");
|
|
10
|
+
class NoInlineInOptionalBranchesConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
11
|
+
}
|
|
12
|
+
exports.NoInlineInOptionalBranchesConf = NoInlineInOptionalBranchesConf;
|
|
13
|
+
class NoInlineInOptionalBranches extends _abap_rule_1.ABAPRule {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.conf = new NoInlineInOptionalBranchesConf();
|
|
17
|
+
}
|
|
18
|
+
getMetadata() {
|
|
19
|
+
return {
|
|
20
|
+
key: "no_inline_in_optional_branches",
|
|
21
|
+
title: "Don't declare inline in optional branches",
|
|
22
|
+
shortDescription: `Don't declare inline in optional branches`,
|
|
23
|
+
extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#dont-declare-inline-in-optional-branches
|
|
24
|
+
|
|
25
|
+
Considered optional branches:
|
|
26
|
+
* inside IF/ELSEIF/ELSE
|
|
27
|
+
* inside LOOP
|
|
28
|
+
* inside WHILE
|
|
29
|
+
* inside CASE/WHEN, CASE TYPE OF
|
|
30
|
+
* inside DO
|
|
31
|
+
* inside SELECT loops
|
|
32
|
+
|
|
33
|
+
Not considered optional branches:
|
|
34
|
+
* TRY/CATCH/CLEANUP`,
|
|
35
|
+
tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.SingleFile],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
getConfig() {
|
|
39
|
+
return this.conf;
|
|
40
|
+
}
|
|
41
|
+
setConfig(conf) {
|
|
42
|
+
this.conf = conf;
|
|
43
|
+
}
|
|
44
|
+
runParsed(file) {
|
|
45
|
+
const output = [];
|
|
46
|
+
const struc = file.getStructure();
|
|
47
|
+
if (struc === undefined) {
|
|
48
|
+
return []; // syntax error
|
|
49
|
+
}
|
|
50
|
+
const candidates = [
|
|
51
|
+
...struc.findAllStructures(Structures.If),
|
|
52
|
+
...struc.findAllStructures(Structures.Loop),
|
|
53
|
+
...struc.findAllStructures(Structures.While),
|
|
54
|
+
...struc.findAllStructures(Structures.Case),
|
|
55
|
+
...struc.findAllStructures(Structures.CaseType),
|
|
56
|
+
...struc.findAllStructures(Structures.Do),
|
|
57
|
+
...struc.findAllStructures(Structures.Select)
|
|
58
|
+
];
|
|
59
|
+
for (const c of candidates) {
|
|
60
|
+
const inline = c.findFirstExpression(Expressions.InlineData);
|
|
61
|
+
if (inline) {
|
|
62
|
+
const message = "Don't declare inline in optional branches";
|
|
63
|
+
const issue = issue_1.Issue.atToken(file, c.getFirstToken(), message, this.getMetadata().key, this.getConfig().severity);
|
|
64
|
+
output.push(issue);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return output;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.NoInlineInOptionalBranches = NoInlineInOptionalBranches;
|
|
71
|
+
//# sourceMappingURL=no_inline_in_optional_branches.js.map
|
|
@@ -156,6 +156,7 @@ Unused variables are not reported if the object contains syntax errors. Errors f
|
|
|
156
156
|
}
|
|
157
157
|
else if (name === "ME"
|
|
158
158
|
|| name === "SUPER"
|
|
159
|
+
|| meta.includes("selection_screen_tab" /* SelectionScreenTab */)
|
|
159
160
|
|| meta.includes("event_parameter" /* EventParameter */)) {
|
|
160
161
|
// todo, workaround for "me" and "super", these should somehow be typed to built-in
|
|
161
162
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.89.0",
|
|
4
4
|
"description": "abaplint - Core API",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/abaplint.d.ts",
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
},
|
|
46
46
|
"homepage": "https://abaplint.org",
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@microsoft/api-extractor": "^7.22.
|
|
49
|
-
"@types/chai": "^4.3.
|
|
48
|
+
"@microsoft/api-extractor": "^7.22.2",
|
|
49
|
+
"@types/chai": "^4.3.1",
|
|
50
50
|
"@types/mocha": "^9.1.0",
|
|
51
|
-
"@types/node": "^17.0.
|
|
51
|
+
"@types/node": "^17.0.24",
|
|
52
52
|
"chai": "^4.3.6",
|
|
53
53
|
"eslint": "^8.13.0",
|
|
54
54
|
"mocha": "^9.2.2",
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LocalTestclassLocation = exports.LocalTestclassLocationConf = void 0;
|
|
4
|
-
const issue_1 = require("../issue");
|
|
5
|
-
const _abap_rule_1 = require("./_abap_rule");
|
|
6
|
-
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
7
|
-
const objects_1 = require("../objects");
|
|
8
|
-
const _irule_1 = require("./_irule");
|
|
9
|
-
const version_1 = require("../version");
|
|
10
|
-
class LocalTestclassLocationConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
11
|
-
}
|
|
12
|
-
exports.LocalTestclassLocationConf = LocalTestclassLocationConf;
|
|
13
|
-
class LocalTestclassLocation extends _abap_rule_1.ABAPRule {
|
|
14
|
-
constructor() {
|
|
15
|
-
super(...arguments);
|
|
16
|
-
this.conf = new LocalTestclassLocationConf();
|
|
17
|
-
}
|
|
18
|
-
getMetadata() {
|
|
19
|
-
return {
|
|
20
|
-
key: "local_testclass_location",
|
|
21
|
-
title: "Local testclass location",
|
|
22
|
-
shortDescription: `Checks that local test classes are placed in the test include.`,
|
|
23
|
-
tags: [_irule_1.RuleTag.SingleFile],
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
getDescription(className) {
|
|
27
|
-
return "Place local testclass \"" + className + "\" in the testclass include";
|
|
28
|
-
}
|
|
29
|
-
getConfig() {
|
|
30
|
-
return this.conf;
|
|
31
|
-
}
|
|
32
|
-
setConfig(conf) {
|
|
33
|
-
this.conf = conf;
|
|
34
|
-
}
|
|
35
|
-
runParsed(file, obj) {
|
|
36
|
-
const issues = [];
|
|
37
|
-
if (this.reg.getConfig().getVersion() === version_1.Version.v700) {
|
|
38
|
-
// 700 does not have testclass includes
|
|
39
|
-
return [];
|
|
40
|
-
}
|
|
41
|
-
if (!(obj instanceof objects_1.Class)) {
|
|
42
|
-
return [];
|
|
43
|
-
}
|
|
44
|
-
for (const c of file.getInfo().listClassDefinitions()) {
|
|
45
|
-
if (c.isLocal && c.isForTesting && !file.getFilename().includes(".testclasses.abap")) {
|
|
46
|
-
const issue = issue_1.Issue.atIdentifier(c.identifier, this.getDescription(c.name), this.getMetadata().key, this.conf.severity);
|
|
47
|
-
issues.push(issue);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return issues;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
exports.LocalTestclassLocation = LocalTestclassLocation;
|
|
54
|
-
//# sourceMappingURL=local_testclass_location.js.map
|