All files / src/rules begin_end_names.ts

100% Statements 105/105
100% Branches 22/22
100% Functions 6/6
100% Lines 105/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 11298x 11298x 11298x 11298x 33748x 33748x 33748x 33748x 33748x 33748x 33748x 33748x 33748x 33748x 33748x 33748x 33748x 11298x 11298x 10802x 10802x 11298x 11298x 232x 232x 11298x 11298x 273x 273x 273x 273x 12x 12x 261x 261x 273x 9x 9x 252x 252x 252x 252x 252x 252x 252x 252x 252x 252x 11298x 11298x 1512x 1512x 1512x 82x 82x 38x 38x 82x 1x 1x 81x 81x 81x 82x 37x 37x 82x 1x 1x 80x 80x 82x 11x 11x 11x 11x 11x 80x 82x 1x 1x 1x 1x 82x 1512x 1512x 1512x 11298x 11298x
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;
  }
 
}