All files / src/rules check_abstract.ts

98.7% Statements 76/77
94.44% Branches 17/18
100% Functions 6/6
98.7% Lines 76/77

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 771x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 14682x 14682x 14682x 14682x 14682x 72154x 72154x 72154x 72154x 72154x 72154x 72154x 72154x 72154x 72154x 14682x 14682x 6x 6x 3x 6x 3x 6x   6x 6x 14682x 14682x 14120x 14120x 14682x 14682x 264x 264x 14682x 14682x 299x 299x 299x 140x 8x 3x 3x 3x 3x 3x 3x 8x 8x 140x 65x 3x 3x 3x 3x 3x 3x 65x 132x 299x 299x 14682x
import {ABAPFile} from "../abap/abap_file";
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IRuleMetadata, RuleTag} from "./_irule";
 
export class CheckAbstractConf extends BasicRuleConfig {
}
 
enum IssueType {
  /** Abstract method defined in non-abstract class */
  NotAbstractClass,
  AbstractAndFinal,
}
 
export class CheckAbstract extends ABAPRule {
 
  private conf = new CheckAbstractConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "check_abstract",
      title: "Check abstract methods and classes",
      shortDescription: `Checks abstract methods and classes:
- class defined as abstract and final,
- non-abstract class contains abstract methods`,
      extendedInformation: `If a class defines only constants, use an interface instead`,
      tags: [RuleTag.SingleFile],
    };
  }
 
  private getDescription(issueType: IssueType, name: string): string {
    switch (issueType) {
      case IssueType.AbstractAndFinal:
        return "Classes should not be ABSTRACT and FINAL: " + name;
      case IssueType.NotAbstractClass:
        return "Abstract methods require abstract classes: " + name;
      default:
        return "";
    }
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: CheckAbstractConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile) {
    const issues: Issue[] = [];
 
    for (const classDef of file.getInfo().listClassDefinitions()) {
      if (classDef.isAbstract === true) {
        if (classDef.isFinal === true && classDef.isForTesting === false) {
          issues.push(Issue.atIdentifier(
            classDef.identifier,
            this.getDescription(IssueType.AbstractAndFinal, classDef.name),
            this.getMetadata().key,
            this.conf.severity));
        }
        continue;
      }
      for (const methodDef of classDef.methods) {
        if (methodDef.isAbstract === true) {
          issues.push(Issue.atIdentifier(
            methodDef.identifier,
            this.getDescription(IssueType.NotAbstractClass, methodDef.name),
            this.getMetadata().key,
            this.conf.severity));
        }
      }
    }
    return issues;
  }
}