All files / src/rules static_call_via_instance.ts

97.75% Statements 87/89
90% Branches 18/20
100% Functions 7/7
97.75% Lines 87/89

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 901x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 20649x 20649x 20649x 20649x 1x 10326x 10326x 10326x 10326x 10326x 30801x 30801x 30801x 30801x 30801x 30801x 30801x 30801x 10326x 10326x 10066x 10066x 10326x 10326x 241x 241x 10326x 10326x 255x 255x 255x     255x 255x 255x 255x 255x 5631x 5631x 5619x 5619x 12x 12x 5631x 1x 1x 1x 1x 1x 1x 12x 255x 255x 255x 10326x 10326x 1176x 1176x 1176x 339x 332x 332x 339x 3x 3x 339x 1176x 1176x 921x 921x 1176x 1176x 1176x 10326x 10326x  
/* eslint-disable max-len */
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IRuleMetadata, RuleTag} from "./_irule";
import {ABAPFile} from "../abap/abap_file";
import {SyntaxLogic} from "../abap/5_syntax/syntax";
import {ABAPObject} from "../objects/_abap_object";
import {ISpaghettiScopeNode} from "../abap/5_syntax/_spaghetti_scope";
import {ReferenceType} from "../abap/5_syntax/_reference";
import {MethodDefinition} from "../abap/types";
import {Position} from "../position";
 
export class StaticCallViaInstanceConf extends BasicRuleConfig {
  /** Allow in test class includes */
  public allowInTestclassIncludes?: boolean = false;
}
 
export class StaticCallViaInstance extends ABAPRule {
 
  private conf = new StaticCallViaInstanceConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "static_call_via_instance",
      title: "Static call via instance variable",
      shortDescription: `Static method call via instance variable`,
      extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#dont-call-static-methods-through-instance-variables`,
      tags: [RuleTag.Styleguide],
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: StaticCallViaInstanceConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile, obj: ABAPObject): Issue[] {
    const issues: Issue[] = [];
 
    if (this.getConfig().allowInTestclassIncludes === true && file.getFilename().includes(".testclasses.")) {
      return [];
    }
 
    const staticMethodCalls = this.listMethodCalls(file.getFilename(), new SyntaxLogic(this.reg, obj).run().spaghetti.getTop());
 
    const tokens = file.getTokens();
    for (let i = 0; i < tokens.length - 1; i++) {
      const token = tokens[i];
      if (token.getStr() !== "->") {
        continue;
      }
 
      const next = tokens[i + 1];
      for (const s of staticMethodCalls) {
        if (s.equals(next!.getStart())) {
          const message = "Avoid calling static method via instance";
          issues.push(Issue.atToken(file, token, message, this.getMetadata().key));
          break;
        }
      }
    }
 
    return issues;
  }
 
  private listMethodCalls(filename: string, node: ISpaghettiScopeNode): Position[] {
    const ret: Position[] = [];
 
    for (const r of node.getData().references) {
      if (r.referenceType !== ReferenceType.MethodReference || r.position.getFilename() !== filename) {
        continue;
      }
      if (r.resolved instanceof MethodDefinition && r.resolved.isStatic() === true) {
        ret.push(r.position.getStart());
      }
    }
 
    for (const child of node.getChildren()) {
      ret.push(...this.listMethodCalls(filename, child));
    }
 
    return ret;
  }
 
}