All files / src/rules catch_and_raise.ts

91.48% Statements 86/94
83.33% Branches 20/24
100% Functions 6/6
91.48% Lines 86/94

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 951x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 11515x 11515x 11515x 11515x 34367x 34367x 34367x 34367x 34367x 34367x 34367x 34367x 34367x 11515x 11515x 11006x 11006x 11515x 11515x 235x 235x 11515x 11515x 254x 254x 254x 254x 12x 12x 242x 254x 8x 8x     8x 8x 8x 1x 1x 7x 7x 8x     7x 7x 7x 8x 1x 1x 8x     6x 6x 6x 8x     6x 8x 1x 1x 5x 8x 4x 4x 4x 4x 4x 4x 4x 8x 242x 242x 242x 11515x 11515x 4x 4x 11515x  
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 Structures from "../abap/3_structures/structures";
import * as Statements from "../abap/2_statements/statements";
import * as Expressions from "../abap/2_statements/expressions";
 
export class CatchAndRaiseConf extends BasicRuleConfig {
}
 
export class CatchAndRaise extends ABAPRule {
  private conf = new CatchAndRaiseConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "catch_and_raise",
      title: "Catch and re-raise same exception",
      shortDescription: `Reports CATCH blocks that only re-raise the caught exception without any handling`,
      badExample: `TRY.\n  something( ).\nCATCH zcx_something INTO DATA(lv_exc).\n  RAISE EXCEPTION lv_exc.\nENDTRY.`,
      goodExample: `TRY.\n  something( ).\nCATCH zcx_something.\n  " handle exception\nENDTRY.`,
      tags: [RuleTag.SingleFile],
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: CatchAndRaiseConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile): Issue[] {
    const issues: Issue[] = [];
 
    const stru = file.getStructure();
    if (stru === undefined) {
      return [];
    }
 
    for (const catchStruct of stru.findAllStructures(Structures.Catch)) {
      const catchStatement = catchStruct.findDirectStatement(Statements.Catch);
      if (catchStatement === undefined) {
        continue;
      }
 
      const target = catchStatement.findFirstExpression(Expressions.Target);
      if (target === undefined) {
        continue;
      }
 
      const targetField = target.findFirstExpression(Expressions.TargetField);
      if (targetField === undefined) {
        continue;
      }
      const caughtVar = targetField.getFirstToken().getStr().toUpperCase();
 
      const allStatements = catchStruct.findAllStatementNodes();
      if (allStatements.length !== 2) {
        continue;
      }
      if (!(allStatements[1].get() instanceof Statements.Raise)) {
        continue;
      }
 
      const raiseStatement = allStatements[1];
      const raiseConcat = raiseStatement.concatTokens().toUpperCase().replace(/\.$/, "").trim();
      if (!raiseConcat.startsWith("RAISE EXCEPTION ")) {
        continue;
      }
      const parts = raiseConcat.split(/\s+/);
      if (parts.length !== 3) {
        continue;
      }
 
      if (parts[2] === caughtVar) {
        issues.push(Issue.atStatement(
          file,
          catchStatement,
          this.getMessage(),
          this.getMetadata().key,
          this.conf.severity));
      }
    }
 
    return issues;
  }
 
  private getMessage(): string {
    return "Caught exception is immediately re-raised, CATCH block has no effect";
  }
}