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 11279x 11279x 11279x 11279x 33688x 33688x 33688x 33688x 33688x 33688x 33688x 33688x 33688x 33688x 33688x 33688x 33688x 11279x 11279x 10789x 10789x 11279x 11279x 229x 229x 11279x 11279x 270x 270x 270x 270x 12x 12x 258x 258x 270x 9x 9x 249x 249x 249x 249x 249x 249x 249x 249x 249x 249x 11279x 11279x 1494x 1494x 1494x 80x 80x 37x 37x 80x 1x 1x 79x 79x 79x 80x 36x 36x 80x 1x 1x 78x 78x 80x 11x 11x 11x 11x 11x 78x 80x 1x 1x 1x 1x 80x 1494x 1494x 1494x 11279x 11279x
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;
  }
 
}