All files / src/rules begin_end_names.ts

98% Statements 98/100
94.11% Branches 16/17
100% Functions 6/6
98% Lines 98/100

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 1001x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 9362x 9362x 9362x 9362x 27936x 27936x 27936x 27936x 27936x 27936x 27936x 27936x 27936x 27936x 27936x 27936x 27936x 9362x 9362x 8898x 8898x 9362x 9362x 216x 216x 9362x 9362x 260x 260x 260x 260x 12x 12x 248x 248x 248x 248x 248x 248x 248x 248x 248x 248x 9362x 9362x 1488x 1488x 1488x 65x 65x 29x 29x 65x     65x 65x 65x 65x 29x 29x 65x 1x 1x 64x 64x 65x 11x 11x 11x 11x 11x 64x 65x 1x 1x 1x 1x 65x 1488x 1488x 1488x 9362x 9362x
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} 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 [];
    }
 
    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;
  }
 
}