All files / src/rules begin_end_names.ts

98.09% Statements 103/105
95% Branches 19/20
100% Functions 6/6
98.09% Lines 103/105

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 1051x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 10325x 10325x 10325x 10325x 30814x 30814x 30814x 30814x 30814x 30814x 30814x 30814x 30814x 30814x 30814x 30814x 30814x 10325x 10325x 9811x 9811x 10325x 10325x 241x 241x 10325x 10325x 283x 283x 283x 283x 12x 12x 271x 271x 283x 8x 8x 263x 263x 263x 263x 263x 263x 263x 263x 263x 263x 10325x 10325x 1578x 1578x 1578x 69x 69x 30x 30x 69x     69x 69x 69x 69x 30x 30x 69x 1x 1x 68x 68x 69x 11x 11x 11x 11x 11x 68x 69x 1x 1x 1x 1x 69x 1578x 1578x 1578x 10325x 10325x
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import * as Structures from "../abap/3_structures/structures";
import * as Expressions from "../abap/2_statements/expressions";
import * as Statements from "../abap/2_statements/statements";
import {StructureNode} from "../abap/nodes";
import {IStructure} from "../abap/3_structures/structures/_structure";
import {IStatement, Unknown} from "../abap/2_statements/statements/_statement";
import {IRuleMetadata, RuleTag} from "./_irule";
import {EditHelper} from "../edit_helper";
import {ABAPFile} from "../abap/abap_file";
 
export class BeginEndNamesConf extends BasicRuleConfig {
}
 
export class BeginEndNames extends ABAPRule {
  private conf = new BeginEndNamesConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "begin_end_names",
      title: "Check BEGIN END names",
      shortDescription: `Check BEGIN OF and END OF names match, plus there must be statements between BEGIN and END`,
      tags: [RuleTag.Syntax, RuleTag.Quickfix, RuleTag.SingleFile],
      badExample: `DATA: BEGIN OF stru,
        field TYPE i,
      END OF structure_not_the_same.`,
      goodExample: `DATA: BEGIN OF stru,
        field TYPE i,
      END OF stru.`,
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: BeginEndNamesConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile) {
    const output: Issue[] = [];
 
    const struc = file.getStructure();
    if (struc === undefined) {
      return [];
    }
 
    const containsUnknown = file.getStatements().some(s => s.get() instanceof Unknown);
    if (containsUnknown === true) {
      return [];
    }
 
    output.push(...this.test(struc, Structures.Data, Statements.DataBegin, Statements.DataEnd, file));
    output.push(...this.test(struc, Structures.ClassData, Statements.ClassDataBegin, Statements.ClassDataEnd, file));
    output.push(...this.test(struc, Structures.Constants, Statements.ConstantBegin, Statements.ConstantEnd, file));
    output.push(...this.test(struc, Structures.Statics, Statements.StaticBegin, Statements.StaticEnd, file));
    output.push(...this.test(struc, Structures.TypeEnum, Statements.TypeEnumBegin, Statements.TypeEnumEnd, file));
    output.push(...this.test(struc, Structures.Types, Statements.TypeBegin, Statements.TypeEnd, file));
 
    return output;
  }
 
  private test(stru: StructureNode, type: new() => IStructure, b: new() => IStatement, e: new() => IStatement, file: ABAPFile): Issue[] {
    const output: Issue[] = [];
 
    for (const sub of stru.findAllStructuresRecursive(type)) {
      let begin = sub.findDirectStatements(b)[0].findFirstExpression(Expressions.NamespaceSimpleName);
      if (begin === undefined) {
        begin = sub.findDirectStatements(b)[0].findFirstExpression(Expressions.DefinitionName);
      }
      if (begin === undefined) {
        continue;
      }
      const first = begin.getFirstToken();
 
      let end = sub.findDirectStatements(e)[0].findFirstExpression(Expressions.NamespaceSimpleName);
      if (end === undefined) {
        end = sub.findDirectStatements(e)[0].findFirstExpression(Expressions.DefinitionName);
      }
      if (end === undefined) {
        continue;
      }
      const last = end.getFirstToken();
 
      if (first.getStr().toUpperCase() !== last.getStr().toUpperCase()) {
        const fix = EditHelper.replaceRange(file, last.getStart(), last.getEnd(), first.getStr());
        const message = "BEGIN END names must match";
        const issue = Issue.atToken(file, first, message, this.getMetadata().key, this.conf.severity, fix);
        output.push(issue);
      }
 
      if (sub.getChildren().length === 2) {
        const message = "There must be statements between BEGIN and END";
        const issue = Issue.atToken(file, first, message, this.getMetadata().key, this.conf.severity);
        output.push(issue);
      }
    }
 
    return output;
  }
 
}