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 21007x 21007x 21007x 21007x 1x 10505x 10505x 10505x 10505x 10505x 31328x 31328x 31328x 31328x 31328x 31328x 31328x 31328x 10505x 10505x 10235x 10235x 10505x 10505x 251x 251x 10505x 10505x 265x 265x 265x     265x 265x 265x 265x 265x 5827x 5827x 5815x 5815x 12x 12x 5827x 1x 1x 1x 1x 1x 1x 12x 265x 265x 265x 10505x 10505x 1214x 1214x 1214x 350x 343x 343x 350x 3x 3x 350x 1214x 1214x 949x 949x 1214x 1214x 1214x 10505x 10505x  
/* 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;
  }
 
}