All files / src/abap/5_syntax/expressions method_call_param.ts

79.56% Statements 74/93
83.33% Branches 25/30
100% Functions 1/1
79.56% Lines 74/93

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 941x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 360x         360x 360x 360x         360x 360x 360x 360x 109x 83x 83x 4x 4x 4x 4x 83x 360x 251x 251x 186x 178x 1x 1x 1x 178x 1x 1x 1x 1x 178x 184x 186x 176x 176x         176x 177x 176x 176x 176x 177x 186x 8x 8x 184x 186x 183x 183x 184x 186x       186x 42x 42x 42x 42x 251x 39x 65x 26x 26x         360x 1x  
import {ExpressionNode} from "../../nodes";
import {StringType, VoidType} from "../../types/basic";
import * as Expressions from "../../2_statements/expressions";
import {IMethodDefinition} from "../../types/_method_definition";
import {MethodParameters} from "./method_parameters";
import {WParenRight, WParenRightW} from "../../1_lexer/tokens";
import {Source} from "./source";
import {AbstractType} from "../../types/basic/_abstract_type";
import {TypeUtils} from "../_type_utils";
import {SyntaxInput, syntaxIssue} from "../_syntax_input";
 
export class MethodCallParam {
  public static runSyntax(node: ExpressionNode, input: SyntaxInput, method: IMethodDefinition | VoidType): void {
    if (!(node.get() instanceof Expressions.MethodCallParam)) {
      const message = "MethodCallParam, unexpected input";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    }
 
    const children = node.getChildren();
    if (children.length < 2 || children.length > 3) {
      const message = "MethodCallParam, unexpected child length";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    }
 
    const child = children[1];
 
    if (child.get() instanceof WParenRight || child.get() instanceof WParenRightW) {
      if (!(method instanceof VoidType)) {
        const required = method.getParameters().getRequiredParameters();
        if (required.length > 0) {
          const message = "Parameter \"" + required[0].getName() + "\" must be supplied";
          input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
          return;
        }
      }
    } else if (child instanceof ExpressionNode
        && (child.get() instanceof Expressions.Source
        || child.get() instanceof Expressions.ConstantString)) {
      if (!(method instanceof VoidType)) {
        if (method.getParameters().getImporting().length === 0) {
          const message = "Method \"" + method.getName() + "\" has no importing parameters";
          input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
          return;
        } else if (method.getParameters().getRequiredParameters().length > 1) {
          const message = "Method \"" + method.getName() + "\" has more than one importing or changing parameter";
          input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
          return;
        }
      }
      let targetType: AbstractType | undefined = undefined;
      if (!(method instanceof VoidType)) {
        const name = method.getParameters().getDefaultImporting();
        if (name === undefined) {
          const message = "No default importing parameter";
          input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
          return;
        }
        for (const i of method.getParameters().getImporting()) {
          if (i.getName().toUpperCase() === name) {
            targetType = i.getType();
            break;
          }
        }
      } else {
        targetType = method;
      }
      let sourceType: AbstractType | undefined = StringType.get();
      if (child.get() instanceof Expressions.Source) {
        sourceType = Source.runSyntax(child, input, targetType);
      }
 
      if (sourceType === undefined) {
        const message = "No source type determined, method source";
        input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
        return;
      } else if (new TypeUtils(input.scope).isAssignableStrict(sourceType, targetType, child) === false) {
        const message = "Method parameter type not compatible";
        input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
        return;
      }
    } else if (child instanceof ExpressionNode && child.get() instanceof Expressions.ParameterListS) {
      new MethodParameters().checkExporting(child, input, method);
    } else if (child.get() instanceof Expressions.MethodParameters) {
      new MethodParameters().runSyntax(child, input, method);
    } else {
      const message = "MethodCallParam, unexpected child";
      input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
      return;
    }
  }
}