All files / src/rules class_attribute_names.ts

96.43% Statements 54/56
91.67% Branches 22/24
100% Functions 9/9
96.43% Lines 54/56

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   14604x   14604x   14604x   14604x   14604x   14604x     1x   7319x     21706x                 33x           7013x       162x       178x 178x 16x   178x 178x 178x 100x   50x   50x     178x 175x 45x 21x   24x       178x 178x       178x       178x 178x 61x   29x 29x   10x 10x   22x 22x         178x       61x 61x 61x 61x 33x 33x     61x      
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[] {
    Iif (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;
  }
 
}