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 22391x 22391x 22391x 22391x 1x 11197x 11197x 11197x 11197x 11197x 33389x 33389x 33389x 33389x 33389x 33389x 33389x 33389x 11197x 11197x 10911x 10911x 11197x 11197x 266x 266x 11197x 11197x 279x 279x 279x     279x 279x 279x 279x 279x 6186x 6186x 6174x 6174x 12x 12x 6186x 1x 1x 1x 1x 1x 1x 12x 279x 279x 279x 11197x 11197x 1278x 1278x 1278x 377x 370x 370x 377x 3x 3x 377x 1278x 1278x 999x 999x 1278x 1278x 1278x 11197x 11197x  
/* 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;
  }
 
}