All files / src/rules class_attribute_names.ts

97.45% Statements 115/118
93.33% Branches 28/30
100% Functions 9/9
97.45% Lines 115/118

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 105 106 107 108 109 110 111 112 113 114 115 116 117 1181x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 18786x 18786x 18786x 18786x 18786x 18786x 18786x 18786x 18786x 18786x 18786x 18786x 18786x 18786x 1x 9410x 9410x 9410x 9410x 9410x 27962x 27962x 27962x 27962x 27962x 27962x 27962x 9410x 9410x 40x 40x 40x 40x 9410x 9410x 8898x 8898x 9410x 9410x 264x 264x 9410x 9410x 281x 281x 16x 16x 281x 281x 281x 137x 137x 70x 70x 67x 67x 281x 281x 278x 63x 30x 30x 33x 33x 278x 281x 281x 281x 281x 9410x 9410x 281x     281x 281x 281x 69x 69x 36x 36x 69x 10x 10x 69x 23x 23x 69x   69x 69x 281x 281x 9410x 9410x 69x 69x 69x 69x 40x 40x 40x 69x 69x 69x 9410x 9410x
import {Issue} from "../issue";
import {NamingRuleConfig} from "./_naming_rule_config";
import {NameValidator} from "../utils/name_validator";
import {ABAPRule} from "./_abap_rule";
import {Identifier} from "../abap/4_file_information/_identifier";
import {InfoAttribute, AttributeLevel} from "../abap/4_file_information/_abap_file_information";
import {RuleTag} from "./_irule";
import {ABAPObject} from "../objects/_abap_object";
import {DDIC} from "../ddic";
import {ABAPFile} from "../abap/abap_file";
 
export class ClassAttributeNamesConf extends NamingRuleConfig {
  /** Ignore global exception classes */
  public ignoreExceptions: boolean = true;
  /** Ignore local classes */
  public ignoreLocal: boolean = true;
  /** Ignore interfaces */
  public ignoreInterfaces: boolean = false;
  /** The pattern for static variable names */
  public statics: string = "^G._.+$";
  /** The pattern for instance variable names */
  public instance: string = "^M._.+$";
  /** The pattern for constant variable names */
  public constants: string = "";
}
 
export class ClassAttributeNames extends ABAPRule {
 
  private conf = new ClassAttributeNamesConf();
 
  public getMetadata() {
    return {
      key: "class_attribute_names",
      title: "Class attributes naming",
      shortDescription: `Allows you to enforce a pattern, such as a prefix, for class variable names.`,
      tags: [RuleTag.Naming, RuleTag.SingleFile],
    };
  }
 
  private getDescription(actual: string, expected: string): string {
    return this.conf.patternKind === "required" ?
      "Class attribute name \"" + actual + "\" does not match pattern " + expected :
      "Class attribute name \"" + actual + "\" must not match pattern " + expected;
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: ClassAttributeNamesConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile, obj: ABAPObject): Issue[] {
    let issues: Issue[] = [];
    if (this.conf.patternKind === undefined) {
      this.conf.patternKind = "required";
    }
    let attributes: InfoAttribute[] = [];
    const ddic = new DDIC(this.reg);
    for (const classDef of file.getInfo().listClassDefinitions()) {
      if ((classDef.isLocal && this.conf.ignoreLocal)
        || (ddic.isException(classDef, obj) && this.conf.ignoreExceptions)) {
        continue;
      }
      attributes = attributes.concat(classDef.attributes);
    }
 
    if (this.conf.ignoreInterfaces === false) {
      for (const intfDef of file.getInfo().listInterfaceDefinitions()) {
        if (intfDef.isLocal && this.conf.ignoreLocal) {
          continue;
        }
        attributes = attributes.concat(intfDef.attributes);
      }
    }
 
    issues = this.checkAttributes(attributes);
    return issues;
  }
 
  private checkAttributes(attr: InfoAttribute[] | undefined): Issue[] {
    if (attr === undefined) {
      return [];
    }
 
    let ret: Issue[] = [];
    for (const a of attr) {
      switch (a.level) {
        case AttributeLevel.Instance:
          ret = ret.concat(this.checkName(a.identifier, this.conf.instance));
          break;
        case AttributeLevel.Static:
          ret = ret.concat(this.checkName(a.identifier, this.conf.statics));
          break;
        case AttributeLevel.Constant:
          ret = ret.concat(this.checkName(a.identifier, this.conf.constants));
          break;
        default:
          break;
      }
    }
    return ret;
  }
 
  private checkName(attr: Identifier, expected: string): Issue[] {
    const ret: Issue[] = [];
    const regex = new RegExp(expected, "i");
    const name = attr.getName();
    if (NameValidator.violatesRule(name, regex, this.conf)) {
      const issue = Issue.atIdentifier(attr, this.getDescription(name, expected), this.getMetadata().key, this.conf.severity);
      ret.push(issue);
    }
 
    return ret;
  }
 
}