All files / src/abap/5_syntax/statements case.ts

100% Statements 52/52
88% Branches 22/25
100% Functions 2/2
100% Lines 52/52

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 531x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 11x 11x 11x 11x 11x 11x 1x 1x 1x 1x 24x 24x 24x 24x 14x 14x 10x 10x 24x 5x 5x 5x 24x 24x 24x 2x 2x 3x 3x 24x 24x 1x 1x 1x 1x 1x 2x 2x 2x 2x  
import * as Expressions from "../../2_statements/expressions";
import {ExpressionNode, StatementNode} from "../../nodes";
import {Source} from "../expressions/source";
import {StatementSyntax} from "../_statement_syntax";
import {SyntaxInput, syntaxIssue} from "../_syntax_input";
import {BuiltIn} from "../_builtin";
import {ObjectOriented} from "../_object_oriented";
import {ObjectReferenceType} from "../../types/basic";
import {LanguageVersion, Release, releaseAtLeast} from "../../../version";
 
export class Case implements StatementSyntax {
  public runSyntax(node: StatementNode, input: SyntaxInput): void {
    // just recurse
    for (const s of node.findDirectExpressions(Expressions.Source)) {
      Source.runSyntax(s, input);
      checkCaseOperand(s, input);
    }
  }
}
 
// Before 7.40 SP02 the operands of CASE and WHEN are enhanced functional operand positions: besides
// data objects and functional methods, only built-in functions with exactly one unnamed argument are allowed
export function checkCaseOperand(source: ExpressionNode, input: SyntaxInput): void {
  if (releaseAtLeast(input.scope.getRelease(), Release.v740sp02)
      || input.scope.getLanguageVersion() === LanguageVersion.Cloud
      || input.scope.getOpenABAP()) {
    return;
  }
 
  const chain = source.findDirectExpression(Expressions.MethodCallChain);
  if (chain === undefined || source.getChildren().length !== 1 || chain.getChildren().length !== 1) {
    return;
  }
  const call = chain.findDirectExpression(Expressions.MethodCall);
  const nameToken = call?.findDirectExpression(Expressions.MethodName)?.getFirstToken();
  const name = nameToken?.getStr();
  if (nameToken === undefined || BuiltIn.searchBuiltin(name) === undefined || BuiltIn.hasUnnamedArgument(name)) {
    return;
  }
 
  // a method of the enclosing class takes precedence over the built-in function
  const meType = input.scope.findVariable("me")?.getType();
  if (meType instanceof ObjectReferenceType) {
    const def = input.scope.findObjectDefinition(meType.getIdentifierName());
    if (new ObjectOriented(input.scope).searchMethodName(def, name).method !== undefined) {
      return;
    }
  }
 
  const message = "Built-in function " + name + " not allowed as CASE/WHEN operand before v740sp02";
  input.issues.push(syntaxIssue(input, nameToken, message));
}