All files / src/rules static_call_via_instance.ts

100% Statements 84/84
100% Branches 17/17
100% Functions 6/6
100% Lines 84/84

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 851x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 8924x 8924x 8924x 8924x 8924x 35093x 35093x 35093x 35093x 35093x 35093x 35093x 35093x 8924x 8924x 8485x 8485x 8924x 8924x 202x 202x 8924x 8924x 216x 216x 216x 216x 216x 216x 4646x 4646x 4641x 4641x 5x 5x 4646x 1x 1x 1x 1x 1x 1x 5x 5x 216x 216x 216x 8924x 8924x 944x 944x 944x 269x 262x 262x 269x 3x 3x 269x 944x 944x 728x 728x 944x 944x 944x 8924x 8924x  
/* 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 {
}
 
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) {
    const issues: Issue[] = [];
 
    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;
  }
 
}