All files / src/rules method_parameter_names.ts

93.33% Statements 56/60
84.21% Branches 16/19
100% Functions 10/10
93.33% Lines 56/60

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 118 119 120 121 122 123 124 125 126 127 128 1291x 1x     1x 1x 1x 1x 1x   1x   14554x   14554x   14554x   14554x   14554x     1x   7283x       21672x                 14x           7008x       129x       133x 133x       151x 151x       151x 8x     143x   143x 147x 35x 13x     147x 80x 2x   78x 30x 7x   23x         143x       36x   36x 25x   18x 18x   2x 2x         5x 5x           36x       25x 25x 25x 25x 14x 14x 14x     25x      
import {Issue} from "../issue";
import {IRule, RuleTag} from "./_irule";
import {IObject} from "../objects/_iobject";
import {IRegistry} from "../_iregistry";
import {ABAPObject} from "../objects/_abap_object";
import {NamingRuleConfig} from "./_naming_rule_config";
import {NameValidator} from "../utils/name_validator";
import {InfoMethodDefinition, MethodParameterDirection, InfoMethodParameter} from "../abap/4_file_information/_abap_file_information";
import {DDIC} from "../ddic";
 
export class MethodParameterNamesConf extends NamingRuleConfig {
  /** Ignore parameters in methods of exception classes */
  public ignoreExceptions: boolean = true;
  /** The pattern for importing parameters */
  public importing: string = "^I._.+$";
  /** The pattern for returning parameters */
  public returning: string = "^R._.+$";
  /** The pattern for changing parameters */
  public changing: string = "^C._.+$";
  /** The pattern for exporting parameters */
  public exporting: string = "^E._.+$";
}
 
export class MethodParameterNames implements IRule {
 
  private conf = new MethodParameterNamesConf();
  private reg: IRegistry;
 
  public getMetadata() {
    return {
      key: "method_parameter_names",
      title: "Method parameter naming conventions",
      shortDescription: `Allows you to enforce a pattern, such as a prefix, for method parameter names`,
      tags: [RuleTag.Naming, RuleTag.SingleFile],
    };
  }
 
  private getDescription(expected: string, actual: string): string {
    return this.conf.patternKind === "required" ?
      "Method parameter name does not match pattern " + expected + ": " + actual :
      "Method parameter name must not match pattern " + expected + ": " + actual;
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: MethodParameterNamesConf) {
    this.conf = conf;
  }
 
  public initialize(reg: IRegistry) {
    this.reg = reg;
    return this;
  }
 
  public run(obj: IObject): Issue[] {
    let ret: Issue[] = [];
    Iif (this.conf.patternKind === undefined) {
      this.conf.patternKind = "required";
    }
 
    if (!(obj instanceof ABAPObject)) {
      return [];
    }
 
    const ddic = new DDIC(this.reg);
 
    for (const file of obj.getABAPFiles()) {
      for (const def of file.getInfo().listInterfaceDefinitions()) {
        for (const method of def.methods) {
          ret = ret.concat(this.checkMethod(method));
        }
      }
      for (const def of file.getInfo().listClassDefinitions()) {
        if (this.conf.ignoreExceptions && ddic.isException(def, obj)) {
          continue;
        }
        for (const method of def.methods) {
          if (method.isEventHandler) {
            continue;
          }
          ret = ret.concat(this.checkMethod(method));
        }
      }
    }
 
    return ret;
  }
 
  private checkMethod(method: InfoMethodDefinition): Issue[] {
    let ret: Issue[] = [];
 
    for (const p of method.parameters) {
      switch (p.direction) {
        case MethodParameterDirection.Importing:
          ret = ret.concat(this.checkParameter(p, this.conf.importing));
          break;
        case MethodParameterDirection.Exporting:
          ret = ret.concat(this.checkParameter(p, this.conf.exporting));
          break;
        case MethodParameterDirection.Changing:
          ret = ret.concat(this.checkParameter(p, this.conf.changing));
          break;
        case MethodParameterDirection.Returning:
          ret = ret.concat(this.checkParameter(p, this.conf.returning));
          break;
        default:
          break;
      }
    }
 
    return ret;
  }
 
  private checkParameter(param: InfoMethodParameter, expected: string): Issue[] {
    const ret: Issue[] = [];
    const regex = new RegExp(expected, "i");
    const name = param.name;
    if (NameValidator.violatesRule(name, regex, this.conf)) {
      const message = this.getDescription(expected, name);
      const issue = Issue.atIdentifier(param.identifier, message, this.getMetadata().key, this.conf.severity);
      ret.push(issue);
    }
 
    return ret;
  }
 
}