1 // Copyright 2020 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package com.google.api.generator.engine.ast; 16 17 import com.google.auto.value.AutoValue; 18 import com.google.common.base.Preconditions; 19 import java.util.Arrays; 20 import java.util.Collections; 21 import java.util.List; 22 import javax.annotation.Nullable; 23 24 @AutoValue 25 public abstract class MethodInvocationExpr implements Expr { methodIdentifier()26 public abstract IdentifierNode methodIdentifier(); 27 returnType()28 public abstract TypeNode returnType(); 29 30 @Nullable exprReferenceExpr()31 public abstract Expr exprReferenceExpr(); 32 33 @Nullable staticReferenceType()34 public abstract TypeNode staticReferenceType(); 35 arguments()36 public abstract List<Expr> arguments(); 37 generics()38 public abstract List<Reference> generics(); 39 40 // Private. methodName()41 abstract String methodName(); 42 isGeneric()43 public boolean isGeneric() { 44 return !generics().isEmpty(); 45 } 46 47 @Override type()48 public TypeNode type() { 49 return returnType(); 50 } 51 52 @Override accept(AstNodeVisitor visitor)53 public void accept(AstNodeVisitor visitor) { 54 visitor.visit(this); 55 } 56 toBuilder()57 public abstract Builder toBuilder(); 58 builder()59 public static Builder builder() { 60 return new AutoValue_MethodInvocationExpr.Builder() 61 .setReturnType(TypeNode.VOID) 62 .setGenerics(Collections.emptyList()) 63 .setArguments(Collections.emptyList()); 64 } 65 66 @AutoValue.Builder 67 public abstract static class Builder { 68 // Required. setMethodName(String methodName)69 public abstract Builder setMethodName(String methodName); 70 methodName()71 abstract String methodName(); 72 73 // Required only if this is used in an AssignmentExpr (for type-checking). setReturnType(TypeNode type)74 public abstract Builder setReturnType(TypeNode type); 75 76 // Optional, but cannot co-exist with a static reference. setExprReferenceExpr(Expr exprReference)77 public abstract Builder setExprReferenceExpr(Expr exprReference); 78 79 // Optional, but cannot co-exist with an expression reference. setStaticReferenceType(TypeNode type)80 public abstract Builder setStaticReferenceType(TypeNode type); 81 82 // Optional. setArguments(Expr... arguments)83 public Builder setArguments(Expr... arguments) { 84 return setArguments(Arrays.asList(arguments)); 85 } 86 setArguments(List<Expr> arguments)87 public abstract Builder setArguments(List<Expr> arguments); 88 89 // Optional. setGenerics(List<Reference> generics)90 public abstract Builder setGenerics(List<Reference> generics); 91 92 // Private setter. setMethodIdentifier(IdentifierNode methodIdentifier)93 abstract Builder setMethodIdentifier(IdentifierNode methodIdentifier); 94 autoBuild()95 abstract MethodInvocationExpr autoBuild(); 96 build()97 public MethodInvocationExpr build() { 98 // IdentifierNode will validate the name. 99 IdentifierNode identifier = IdentifierNode.builder().setName(methodName()).build(); 100 setMethodIdentifier(identifier); 101 102 MethodInvocationExpr methodInvocationExpr = autoBuild(); 103 104 if (methodInvocationExpr.staticReferenceType() != null) { 105 Preconditions.checkState( 106 TypeNode.isReferenceType(methodInvocationExpr.staticReferenceType()), 107 "Static references can only be made on object types"); 108 } 109 110 Preconditions.checkState( 111 !methodInvocationExpr.type().equals(TypeNode.NULL), 112 "Methods cannot be invoked on null types."); 113 114 Preconditions.checkState( 115 methodInvocationExpr.exprReferenceExpr() == null 116 || methodInvocationExpr.staticReferenceType() == null, 117 "Only the expression reference or the static reference can be set, not both"); 118 119 NodeValidator.checkNoNullElements( 120 methodInvocationExpr.arguments(), 121 "arguments", 122 String.format("method invocation of %s", methodInvocationExpr.methodIdentifier().name())); 123 124 NodeValidator.checkNoNullElements( 125 methodInvocationExpr.generics(), 126 "generics", 127 String.format("method invocation of %s", methodInvocationExpr.methodIdentifier().name())); 128 129 // TODO(v2): If type-checking is ever added for arguments, beware of lambdas and their type 130 // workarounds. 131 132 return methodInvocationExpr; 133 } 134 } 135 } 136