All files / src/rules unused_macros.ts

97.43% Statements 76/78
87.5% Branches 14/16
100% Functions 7/7
97.43% Lines 76/78

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 781x 1x 1x 1x 1x 1x 1x 1x 23555x 23555x 23555x 23555x 23555x 23555x 1x 11783x 11783x 11783x 11783x 11783x 147545x 147545x 147545x 147545x 147545x 147545x 147545x 147545x 147545x 147545x 147545x 147545x 147545x 147545x 147545x 11783x 11783x 11236x 11236x 11783x 11783x 253x 253x     253x 11783x 11783x 264x 264x 264x 11783x 11783x 352x 352x 352x 79x 79x 273x 273x 352x 282x 10x 10x 10x 6x 6x 6x 6x 6x 6x 10x 282x 273x 273x 273x 11783x 11783x
import {Issue} from "../issue";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IRegistry} from "../_iregistry";
import {IRule, IRuleMetadata, RuleTag} from "./_irule";
import {IObject} from "../objects/_iobject";
import {ABAPObject} from "../objects/_abap_object";
import {EditHelper} from "../edit_helper";
 
export class UnusedMacrosConf extends BasicRuleConfig {
  /** skip specific names, case insensitive
   * @uniqueItems true
   */
  public skipNames?: string[] = [];
}
 
export class UnusedMacros implements IRule {
  private conf = new UnusedMacrosConf();
  private reg: IRegistry;
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "unused_macros",
      title: "Unused macros",
      shortDescription: `Checks for unused macro definitions definitions`,
      tags: [RuleTag.Quickfix],
      badExample: `DEFINE foobar1.
  WRITE 'hello'.
END-OF-DEFINITION.`,
      goodExample: `DEFINE foobar2.
  WRITE 'hello'.
END-OF-DEFINITION.
 
foobar2.`,
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: UnusedMacrosConf) {
    this.conf = conf;
    if (this.conf.skipNames === undefined) {
      this.conf.skipNames = [];
    }
  }
 
  public initialize(reg: IRegistry) {
    this.reg = reg;
    return this;
  }
 
  public run(obj: IObject): Issue[] {
    const result: Issue[] = [];
 
    if (!(obj instanceof ABAPObject)) {
      return [];
    }
 
    const references = this.reg.getMacroReferences();
    for (const file of obj.getABAPFiles()) {
      for (const macroToken of references.listDefinitionsByFile(file.getFilename())) {
        const usages = references.listUsagesbyMacro(file.getFilename(), macroToken);
 
        if (usages.length === 0 && this.conf.skipNames?.includes(macroToken.getStr().toUpperCase()) === false) {
          const message = "Unused macro definition: " + macroToken.getStr();
 
          const pos = references.getDefinitionRange(file.getFilename(), macroToken);
          const fix = EditHelper.deleteRange(file, pos!.start, pos!.end);
          result.push(Issue.atToken(file, macroToken, message, this.getMetadata().key, this.conf.severity, fix));
        }
      }
    }
 
    return result;
  }
 
}