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 javax.annotation.Nullable; 20 21 @AutoValue 22 public abstract class ThrowExpr implements Expr { 23 // TODO(miraleung): Refactor with StringObjectValue and possibly with NewObjectExpr. 24 25 @Nullable throwExpr()26 public abstract Expr throwExpr(); 27 28 @Override type()29 public abstract TypeNode type(); 30 31 @Nullable messageExpr()32 public abstract Expr messageExpr(); 33 34 @Nullable causeExpr()35 public abstract Expr causeExpr(); 36 37 @Override accept(AstNodeVisitor visitor)38 public void accept(AstNodeVisitor visitor) { 39 visitor.visit(this); 40 } 41 builder()42 public static Builder builder() { 43 return new AutoValue_ThrowExpr.Builder(); 44 } 45 46 @AutoValue.Builder 47 public abstract static class Builder { setThrowExpr(Expr throwExpr)48 public abstract Builder setThrowExpr(Expr throwExpr); 49 50 // No-op if setThrowExpr is called. setType(TypeNode type)51 public abstract Builder setType(TypeNode type); 52 setMessageExpr(String message)53 public Builder setMessageExpr(String message) { 54 return setMessageExpr(ValueExpr.withValue(StringObjectValue.withValue(message))); 55 } 56 setMessageExpr(Expr expr)57 public abstract Builder setMessageExpr(Expr expr); 58 setCauseExpr(Expr expr)59 public abstract Builder setCauseExpr(Expr expr); 60 61 // Private. throwExpr()62 abstract Expr throwExpr(); 63 type()64 abstract TypeNode type(); 65 messageExpr()66 abstract Expr messageExpr(); 67 causeExpr()68 abstract Expr causeExpr(); 69 autoBuild()70 abstract ThrowExpr autoBuild(); 71 build()72 public ThrowExpr build() { 73 if (throwExpr() != null) { 74 setType(throwExpr().type()); 75 Preconditions.checkState( 76 messageExpr() == null && causeExpr() == null, 77 "Only one of throwExpr or [messageExpr or causeExpr, inclusive] can be present."); 78 79 if (throwExpr() instanceof VariableExpr) { 80 Preconditions.checkState( 81 !((VariableExpr) throwExpr()).isDecl(), "Cannot throw a variable declaration"); 82 } 83 84 Preconditions.checkState( 85 TypeNode.isExceptionType(throwExpr().type()), 86 String.format("Only exception types can be thrown, found %s", throwExpr().type())); 87 88 return autoBuild(); 89 } 90 91 Preconditions.checkState( 92 TypeNode.isExceptionType(type()), 93 String.format("Type %s must be an exception type", type())); 94 95 if (messageExpr() != null) { 96 Preconditions.checkState( 97 messageExpr().type().equals(TypeNode.STRING), 98 String.format("Message expression type must be a string for exception %s", type())); 99 } 100 101 if (causeExpr() != null) { 102 Preconditions.checkState( 103 TypeNode.THROWABLE.reference().isSupertypeOrEquals(causeExpr().type().reference()), 104 String.format( 105 "Cause expression type must be a subclass of Throwable, but found %s", 106 causeExpr().type())); 107 } 108 109 return autoBuild(); 110 } 111 } 112 } 113