All files / src/rules intf_referencing_clas.ts

94.25% Statements 82/87
71.42% Branches 15/21
100% Functions 8/8
94.25% Lines 82/87

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 871x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 22293x 22293x 22293x 22293x 22293x 22293x 1x 11148x 11148x 11148x 11148x 11148x 33243x 33243x 33243x 33243x 33243x 33243x 33243x 33243x 33243x 33243x 11148x 11148x 10585x     10585x 10585x 11148x 11148x 266x 266x 11148x 11148x 269x 269x 269x 11148x 11148x 336x 315x 315x 21x 21x 21x 11148x 11148x 11148x 11148x 68x 68x 68x 68x 68x 68x 14x 14x 14x 2x 2x   2x     2x 2x 14x 68x 68x 47x 47x 68x 68x 68x 11148x
import {Issue} from "../issue";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IRegistry} from "../_iregistry";
import {Class, Interface} from "../objects";
import {IRule, IRuleMetadata} from "./_irule";
import {IObject} from "../objects/_iobject";
import {SyntaxLogic} from "../abap/5_syntax/syntax";
import {ISpaghettiScopeNode} from "../abap/5_syntax/_spaghetti_scope";
import {ReferenceType} from "../abap/5_syntax/_reference";
import {DDIC} from "../ddic";
 
export class IntfReferencingClasConf extends BasicRuleConfig {
  /** List of classes allowed to be referenced, regex, case insensitive
   * @uniqueItems true
  */
  public allow: string[] = [];
}
 
export class IntfReferencingClas implements IRule {
  private conf = new IntfReferencingClasConf();
  private reg: IRegistry;
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "intf_referencing_clas",
      title: "INTF referencing CLAS",
      shortDescription: `Interface contains references to class`,
      extendedInformation: `Only global interfaces are checked.
      Only first level references are checked.
      Exception class references are ignored.
      Void references are ignored.`,
    };
  }
 
  public getConfig() {
    if (this.conf.allow === undefined) {
      this.conf.allow = [];
    }
    return this.conf;
  }
 
  public setConfig(conf: IntfReferencingClasConf) {
    this.conf = conf;
  }
 
  public initialize(reg: IRegistry): IRule {
    this.reg = reg;
    return this;
  }
 
  public run(obj: IObject): readonly Issue[] {
    if (!(obj instanceof Interface)) {
      return [];
    }
 
    return this.traverse(new SyntaxLogic(this.reg, obj).run().spaghetti.getTop());
  }
 
////////////////
 
  private traverse(node: ISpaghettiScopeNode): readonly Issue[] {
    let ret: Issue[] = [];
    const message = "Referencing CLAS: ";
 
    const ddic = new DDIC(this.reg);
 
    for (const r of node.getData().references) {
      if (r.referenceType === ReferenceType.ObjectOrientedReference
          && r.extra?.ooType === "CLAS"
          && r.extra?.ooName !== undefined) {
        const found = this.reg.getObject("CLAS", r.extra.ooName) as Class || undefined;
        if (found && ddic.isException(found.getClassDefinition(), found)) {
          continue;
        } else if (this.getConfig().allow.some(reg => new RegExp(reg, "i").test(r.extra!.ooName!))) {
          continue;
        }
        ret.push(Issue.atIdentifier(r.position, message + r.extra.ooName, this.getMetadata().key, this.conf.severity));
      }
    }
 
    for (const c of node.getChildren()) {
      ret = ret.concat(this.traverse(c));
    }
 
    return ret;
  }
}