All files / src/rules parser_bad_exceptions.ts

97.43% Statements 76/78
95.45% Branches 21/22
100% Functions 7/7
97.43% Lines 76/78

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 791x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 11455x 11455x 11455x 11455x 34232x 34232x 34232x 34232x 34232x 34232x 34232x 11455x 11455x 10927x 10927x 11455x 11455x 247x 247x 11455x 11455x 270x 270x 270x 1529x 1526x 1526x 3x 3x 3x 1529x 1x 1x 10x 10x 1x 1x 2x 1529x 27x 10x 10x 10x 27x 2x 270x 270x 270x 11455x 11455x 3x 3x 3x 11455x 11455x 3x 3x 3x     3x 3x 11455x 11455x  
import * as Statements from "../abap/2_statements/statements";
import * as Expressions from "../abap/2_statements/expressions";
import {Issue} from "../issue";
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import {RuleTag, IRuleMetadata} from "./_irule";
import {ABAPFile} from "../abap/abap_file";
import {ExpressionNode} from "../abap/nodes/expression_node";
 
// todo: this rule needs refactoring
 
export class ParserBadExceptionsConf extends BasicRuleConfig {
}
 
export class ParserBadExceptions extends ABAPRule {
  private conf = new ParserBadExceptionsConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "parser_bad_exceptions",
      title: "Parser Error, bad EXCEPTIONS in CALL FUNCTION",
      shortDescription: `Checks for syntax not recognized by abaplint, related to EXCEPTIONS in CALL FUNCTION.`,
      tags: [RuleTag.Syntax, RuleTag.SingleFile],
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: ParserBadExceptionsConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile) {
    const issues: Issue[] = [];
 
    for (const statement of file.getStatements()) {
      if (!(statement.get() instanceof Statements.CallFunction)) {
        continue;
      }
 
      const exceptionTokens = this.findExceptionTokens(statement);
      if (exceptionTokens !== undefined
          && this.containsMixedExceptionSyntax(statement.findAllExpressions(Expressions.ParameterException))) {
        const message = "Bad EXCEPTIONS syntax in CALL FUNCTION";
        for (const token of exceptionTokens) {
          issues.push(Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity));
        }
        continue;
      }
 
      for (const e of statement.findAllExpressions(Expressions.ParameterException)) {
        if (e.findDirectTokenByText("=") === undefined) {
          const message = "Bad EXCEPTIONS syntax in CALL FUNCTION";
          issues.push(Issue.atToken(file, e.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
        }
      }
    }
 
    return issues;
  }
 
  private containsMixedExceptionSyntax(exceptions: readonly ExpressionNode[]) {
    return exceptions.some(e => e.findDirectTokenByText("=") === undefined)
      && exceptions.some(e => e.findDirectTokenByText("=") !== undefined);
  }
 
  private findExceptionTokens(statement: ReturnType<ABAPFile["getStatements"]>[number]) {
    const tokens = statement.getTokens();
    const index = tokens.findIndex(t => t.getStr().toUpperCase() === "EXCEPTIONS");
    if (index === -1) {
      return undefined;
    }
    return tokens.slice(index).filter(t => t.getStr() !== ".");
  }
 
}