All files / src/rules unnecessary_chaining.ts

96.03% Statements 97/101
94.59% Branches 35/37
100% Functions 6/6
96.03% Lines 97/101

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 90 91 92 93 94 95 96 97 98 99 100 101 1021x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 22174x 22174x 22174x 22174x 22174x 1x 11088x 11088x 11088x 11088x 11088x 33146x 33146x 33146x 33146x 33146x 33146x 33146x 33146x 33146x 33146x 11088x 11088x 10841x 10841x 11088x 11088x 244x 244x 11088x 11088x 274x 274x 274x 53x 53x 53x 1x 1x 53x 273x 273x 274x     273x 273x 274x 1493x 1493x 1310x 1310x 183x 183x 183x 1493x 2x 2x 2x 183x 183x 183x 1493x 3x 3x 3x 183x 1493x 1493x 1493x 114x 1493x 44x 44x 25x 25x 25x 25x 25x 25x 1493x     1493x 273x 273x 273x 11088x 11088x  
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 {EditHelper} from "../edit_helper";
import {Comment} from "../abap/2_statements/statements/_statement";
import {StatementNode} from "../abap/nodes";
import {ABAPObject} from "../objects/_abap_object";
import {Class} from "../objects";
import {DDIC} from "../ddic";
 
export class UnnecessaryChainingConf extends BasicRuleConfig {
  public maxIssuesPerFile: number | undefined = 10;
  /** Ignore global exception classes */
  public ignoreExceptions: boolean = true;
}
 
export class UnnecessaryChaining extends ABAPRule {
 
  private conf = new UnnecessaryChainingConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "unnecessary_chaining",
      title: "Unnecessary Chaining",
      shortDescription: `Find unnecessary chaining, all statements are checked`,
      extendedInformation: ``,
      tags: [RuleTag.SingleFile, RuleTag.Quickfix],
      badExample: `WRITE: bar.`,
      goodExample: `WRITE bar.`,
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: UnnecessaryChainingConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile, obj: ABAPObject) {
    const issues: Issue[] = [];
 
    if (obj instanceof Class) {
      const definition = obj.getClassDefinition();
      const ddic = new DDIC(this.reg);
      if (this.conf.ignoreExceptions === true && ddic.isException(definition, obj)) {
        return issues;
      }
    }
 
    let max = this.getConfig().maxIssuesPerFile;
    if (max === undefined || max < 1) {
      max = 10;
    }
 
    const statements = file.getStatements();
    for (let i = 0; i < statements.length; i++) {
      const colon = statements[i].getColon();
      if (colon === undefined) {
        continue;
      }
 
      let j = 1;
      let nextStatement = statements[i + j];
      while (nextStatement?.get() instanceof Comment) {
        j++;
        nextStatement = statements[i + j];
      }
 
      j = 1;
      let prevStatement: StatementNode | undefined = statements[i - j];
      while (prevStatement?.get() instanceof Comment) {
        j++;
        prevStatement = statements[i - j];
      }
 
      const next = nextStatement?.getColon();
      const prev = prevStatement?.getColon();
      if (next !== undefined && colon.getStart().equals(next.getStart())) {
        continue;
      } else if (prev !== undefined && colon.getStart().equals(prev.getStart())) {
        continue;
      }
 
      const fix = EditHelper.deleteRange(file, colon.getStart(), colon.getEnd());
      const message = "Unnecessary chaining";
      const issue = Issue.atToken(file, colon, message, this.getMetadata().key, this.conf.severity, fix);
      issues.push(issue);
 
      if (issues.length >= max) {
        break;
      }
    }
 
    return issues;
  }
 
}