All files / src/rules rfc_error_handling.ts

100% Statements 90/90
100% Branches 22/22
100% Functions 6/6
100% Lines 90/90

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 911x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 14626x 14626x 14626x 14626x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 240643x 14626x 14626x 7x 7x 7x 14626x 14626x 14064x 14064x 14626x 14626x 264x 264x 14626x 14626x 306x 306x 306x 1662x 1662x 1662x 1648x 1648x 14x 14x 1662x 1x 1x 13x 13x 1662x 1662x 1662x 2x 2x 2x 2x 11x 11x 11x 1662x 24x 24x 11x 11x 1662x 1662x 5x 5x 5x 5x 1662x 306x 306x 306x 14626x 14626x  
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import * as Statements from "../abap/2_statements/statements";
import * as Expressions from "../abap/2_statements/expressions";
import {IRuleMetadata, RuleTag} from "./_irule";
import {ABAPFile} from "../abap/abap_file";
 
export class RFCErrorHandlingConf extends BasicRuleConfig {
}
 
export class RFCErrorHandling extends ABAPRule {
  private conf = new RFCErrorHandlingConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "rfc_error_handling",
      title: "RFC error handling",
      tags: [RuleTag.SingleFile],
      shortDescription: `Checks that exceptions 'system_failure' and 'communication_failure' are handled in RFC calls`,
      extendedInformation: `RESOURCE_FAILURE is also required for asynchronous calls with DESTINATION IN GROUP.
 
https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abenrfc_exception.html`,
      badExample: `CALL FUNCTION 'ZRFC'
  DESTINATION lv_rfc.`,
      goodExample: `CALL FUNCTION 'ZRFC'
  DESTINATION lv_rfc
  EXCEPTIONS
    system_failure        = 1 MESSAGE msg
    communication_failure = 2 MESSAGE msg
    OTHERS                = 3.`,
    };
  }
 
  private getMessage(requireResourceFailure: boolean): string {
    return "RFC error handling: At least one unhandled exception from SYSTEM_FAILURE, COMMUNICATION_FAILURE"
      + (requireResourceFailure ? ", RESOURCE_FAILURE" : "");
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: RFCErrorHandlingConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile) {
    const output: Issue[] = [];
 
    for (const stat of file.getStatements()) {
      const token = stat.getFirstToken();
 
      if (!(stat.get() instanceof Statements.CallFunction)) {
        continue;
      }
 
      const destination = stat.findFirstExpression(Expressions.Destination);
      if (destination === undefined) {
        continue;
      }
 
      const requireResourceFailure = stat.findDirectTokenByText("STARTING") !== undefined
        && destination.findDirectTokenByText("GROUP") !== undefined;
      const list = stat.findFirstExpression(Expressions.ParameterListExceptions);
      if (list === undefined) {
        const issue = Issue.atToken(file, token, this.getMessage(requireResourceFailure), this.getMetadata().key, this.conf.severity);
        output.push(issue);
        continue;
      }
 
      const parameters = list.findAllExpressions(Expressions.ParameterName);
      const names: string[] = [];
      for (const par of parameters) {
        names.push(par.getFirstToken().getStr().toUpperCase());
      }
 
      if (names.indexOf("SYSTEM_FAILURE") < 0
          || names.indexOf("COMMUNICATION_FAILURE") < 0
          || (requireResourceFailure && names.indexOf("RESOURCE_FAILURE") < 0)) {
        const issue = Issue.atToken(file, token, this.getMessage(requireResourceFailure), this.getMetadata().key, this.conf.severity);
        output.push(issue);
        continue;
      }
    }
 
    return output;
  }
 
}