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

83.87% Statements 52/62
76.19% Branches 16/21
100% Functions 2/2
83.87% Lines 52/62

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 621x 1x 1x 1x 1x 1x 1x 1x 1x 1x 565x 565x 1x 1x 1x 565x 565x 2x 565x   563x 1x 1x 1x 1x 564x 565x 2x 2x 2x 2x 564x 564x 564x 564x 565x           565x 1x 1x 1x 1x 1x 564x 564x 526x 526x 38x 564x 11x 564x 27x 27x         1x
import {ExpressionNode} from "../../nodes";
import * as Expressions from "../../2_statements/expressions";
import {TypedIdentifier, IdentifierMeta} from "../../types/_typed_identifier";
import {CGenericType, CharacterType, CLikeType, CSequenceType, IntegerType, StringType, UnknownType, VoidType, XSequenceType} from "../../types/basic";
import {AbstractType} from "../../types/basic/_abstract_type";
import {ReferenceType} from "../_reference";
import {CheckSyntaxKey, SyntaxInput, syntaxIssue} from "../_syntax_input";
 
export class InlineData {
  public static runSyntax(node: ExpressionNode, input: SyntaxInput, type: AbstractType | undefined): void {
    const token = node.findFirstExpression(Expressions.TargetField)?.getFirstToken();
    if (token && token.getStr().length > 30) {
      const message = "DATA name too long, " + token.getStr();
      input.issues.push(syntaxIssue(input, token, message));
    }
    if (token && type) {
      if (type instanceof CSequenceType || type instanceof CLikeType) {
        type = StringType.get();
      } else if (type instanceof XSequenceType) {
        type = StringType.get();
      } else if (type instanceof CGenericType) {
        const message = "InlineData, generic type C cannot be used for inferred type";
        input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
        return;
      }
 
      if (type.isGeneric()) {
        const message = "DATA definition cannot be generic, " + type.constructor.name;
        input.issues.push(syntaxIssue(input, node.getFirstToken(), message));
        type = VoidType.get(CheckSyntaxKey);
      }
 
      const identifier = new TypedIdentifier(token, input.filename, this.stripDerivedFromConstant(type), [IdentifierMeta.InlineDefinition]);
      input.scope.addIdentifier(identifier);
      input.scope.addReference(token, identifier, ReferenceType.DataWriteReference, input.filename);
    } else if (token) {
      const message = "InlineData, could not determine type for \"" + token.getStr() + "\"";
      const identifier = new TypedIdentifier(token, input.filename, new UnknownType(message), [IdentifierMeta.InlineDefinition]);
      input.scope.addIdentifier(identifier);
      input.scope.addReference(token, identifier, ReferenceType.DataWriteReference, input.filename);
    }
  }
 
  // The inferred type is taken from the source expression, which might be a literal.
  // The variable itself is not a constant, so the relaxations that apply to literals
  // must not be inherited, eg. a "c" variable is not assignable to a "string" parameter
  private static stripDerivedFromConstant(type: AbstractType): AbstractType {
    const data = type.getAbstractTypeData();
    if (data?.derivedFromConstant !== true) {
      return type;
    }
    const {derivedFromConstant, ...rest} = data;
    if (type instanceof CharacterType) {
      return new CharacterType(type.getLength(), rest);
    } else if (type instanceof IntegerType) {
      return IntegerType.get(rest);
    } else if (type instanceof StringType) {
      return StringType.get(rest);
    }
    return type;
  }
}