All files / src/rules unnecessary_return.ts

100% Statements 105/105
100% Branches 28/28
100% Functions 6/6
100% Lines 105/105

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 102 103 104 1051x 1x 1x 1x 1x 1x 1x 1x 1x 21792x 21792x 21792x 21792x 1x 10899x 10899x 10899x 10899x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 32491x 10899x 10899x 10349x 10349x 10899x 10899x 260x 260x 10899x 10899x 277x 277x 277x 277x 12x 12x 265x 265x 265x 265x 265x 265x 277x 1540x 1540x 1540x 1540x 1540x 93x 93x 93x 1447x 1540x 1426x 1426x 1447x 1447x 1540x 1540x 1354x 1354x 93x 93x 1540x 5x 2x 2x 3x 3x 3x 3x 91x 91x 91x 91x 1540x 1540x 1x 1x 1x 1540x 265x 265x 265x 10899x 10899x
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 * as Statements from "../abap/2_statements/statements";
import {EditHelper} from "../edit_helper";
import {Comment} from "../abap/2_statements/statements/_statement";
 
export class UnnecessaryReturnConf extends BasicRuleConfig {
  /** Allow empty METHODs + FORMs + FUNCTION-MODULEs */
  public allowEmpty = false;
}
 
export class UnnecessaryReturn extends ABAPRule {
  private conf = new UnnecessaryReturnConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "unnecessary_return",
      title: "Unnecessary Return",
      shortDescription: `Finds unnecessary RETURN statements`,
      extendedInformation: `Finds unnecessary RETURN statements`,
      tags: [RuleTag.SingleFile, RuleTag.Quickfix],
      badExample: `FORM hello1.
  WRITE 'world'.
  RETURN.
ENDFORM.
 
FORM foo.
  IF 1 = 2.
    RETURN.
  ENDIF.
ENDFORM.`,
      goodExample: `FORM hello2.
  WRITE 'world'.
ENDFORM.`,
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: UnnecessaryReturnConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile) {
    const issues: Issue[] = [];
 
    const structure = file.getStructure();
    if (structure === undefined) {
      return [];
    }
 
    const message = "Unnecessary RETURN";
 
    const statements = file.getStatements();
    let statementCounter = 0;
 
    for (let i = 0; i < statements.length; i++) {
      const node = statements[i];
      const nodeType = node.get();
      if ((nodeType instanceof Statements.MethodImplementation
          || nodeType instanceof Statements.Form
          || nodeType instanceof Statements.FunctionModule)) {
        statementCounter = 0;
        continue;
      }
 
      if (!(nodeType instanceof Comment)) {
        statementCounter++;
      }
 
      if (!(nodeType instanceof Statements.EndMethod
          || nodeType instanceof Statements.EndForm
          || nodeType instanceof Statements.EndFunction)) {
        continue;
      }
 
      const prev = statements[i - 1];
      if (prev && prev.get() instanceof Statements.Return) {
        if (this.conf.allowEmpty === true && statementCounter === 2) {
          continue;
        }
 
        const fix = EditHelper.deleteStatement(file, prev);
        issues.push(Issue.atStatement(file, prev, message, this.getMetadata().key, this.getConfig().severity, fix));
      }
 
      // note: ENDTRY is not checked, it will usually just make it an empty catch handler, which is also bad
      const prevprev = statements[i - 2];
      if (prev && prevprev
          && prevprev.get() instanceof Statements.Return
          && prev.get() instanceof Statements.EndIf) {
        const fix = EditHelper.deleteStatement(file, prevprev);
        issues.push(Issue.atStatement(file, prevprev, message, this.getMetadata().key, this.getConfig().severity, fix));
      }
    }
 
    return issues;
  }
 
}