All files / src/rules reduce_procedural_code.ts

100% Statements 85/85
100% Branches 21/21
100% Functions 6/6
100% Lines 85/85

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 851x 1x 1x 1x 1x 1x 1x 1x 1x 20688x 20688x 20688x 10346x 10346x 10346x 10346x 10346x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 30858x 10346x 10346x 9830x 9830x 10346x 10346x 241x 241x 10346x 10346x 256x 256x 256x 12x 12x 12x 244x 244x 244x 256x 1444x 35x 35x 1444x 35x 1x 1x 1x 1x 35x 1409x 29x 1374x 128x 128x 1444x 244x 244x 244x 10346x 10346x
import {BasicRuleConfig} from "./_basic_rule_config";
import {ABAPRule} from "./_abap_rule";
import {IRuleMetadata, RuleTag} from "./_irule";
import * as Statements from "../abap/2_statements/statements";
import {ABAPFile} from "../abap/abap_file";
import {Issue} from "../issue";
import {StatementNode} from "../abap/nodes";
import {Comment} from "../abap/2_statements/statements/_statement";
 
export class ReduceProceduralCodeConf extends BasicRuleConfig {
  public maxStatements: number = 10;
}
export class ReduceProceduralCode extends ABAPRule {
 
  private conf = new ReduceProceduralCodeConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "reduce_procedural_code",
      title: "Reduce procedural code",
      shortDescription: `Checks FORM and FUNCTION-MODULE have few statements`,
      extendedInformation: `Delegate logic to a class method instead of using FORM or FUNCTION-MODULE.
 
https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-object-orientation-to-procedural-programming
 
Comments are not counted as statements.`,
      tags: [RuleTag.SingleFile, RuleTag.Styleguide],
      badExample: `FORM foo.
  DATA lv_bar TYPE i.
  lv_bar = 2 + 2.
  IF lv_bar = 4.
    WRITE 'hello world'.
  ENDIF.
  DATA lv_bar TYPE i.
  lv_bar = 2 + 2.
  IF lv_bar = 4.
    WRITE 'hello world'.
  ENDIF.
ENDFORM.`,
      goodExample: `FORM foo.
  NEW zcl_global_class( )->run_logic( ).
ENDFORM.`,
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: ReduceProceduralCodeConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile) {
    const issues: Issue[] = [];
 
    if (file.getStructure() === undefined) {
      // constains syntax errors, skip this check
      return issues;
    }
 
    let doCount: StatementNode | undefined = undefined;
    let count = 0;
    for (const statement of file.getStatements()) {
      if (statement.get() instanceof Statements.Form || statement.get() instanceof Statements.FunctionModule) {
        doCount = statement;
        count = 0;
      } else if (statement.get() instanceof Statements.EndForm || statement.get() instanceof Statements.EndFunction) {
        if (count >= this.conf.maxStatements && doCount !== undefined) {
          const message = "Reduce procedural code, max " + this.conf.maxStatements + " statements";
          const issue = Issue.atStatement(file, doCount, message, this.getMetadata().key, this.conf.severity);
          issues.push(issue);
        }
        doCount = undefined;
      } else if (statement.get() instanceof Comment) {
        continue;
      } else if (doCount !== undefined) {
        count = count + 1;
      }
    }
 
    return issues;
  }
 
}