All files / src/rules unnecessary_return.ts

100% Statements 108/108
100% Branches 30/30
100% Functions 6/6
100% Lines 108/108

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 105 106 107 1081x 1x 1x 1x 1x 1x 1x 1x 1x 22183x 22183x 22183x 22183x 1x 11095x 11095x 11095x 11095x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 33124x 11095x 11095x 10572x 10572x 11095x 11095x 246x 246x 11095x 11095x 273x 273x 273x 273x 12x 12x 261x 261x 261x 261x 261x 261x 273x 1501x 1501x 1501x 1501x 1501x 70x 70x 70x 1431x 1501x 1408x 1408x 1431x 1431x 1501x 1501x 1361x 1361x 70x 70x 70x 70x 1501x 5x 2x 2x 3x 3x 3x 3x 68x 68x 68x 68x 1501x 1501x 1501x 1x 1x 1x 1501x 261x 261x 261x 11095x 11095x
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
          && prev.getChildren().length === 2) {
        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
          && prevprev.getChildren().length === 2
          && 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;
  }
 
}