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 com.google.common.collect.ImmutableList; 20 import java.util.ArrayList; 21 import java.util.Collections; 22 import java.util.List; 23 import javax.annotation.Nonnull; 24 import javax.annotation.Nullable; 25 26 @AutoValue 27 public abstract class TryCatchStatement implements Statement { 28 29 // Required. tryBody()30 public abstract ImmutableList<Statement> tryBody(); 31 32 // Optional only if the sample code bit is set (i.e. this is sample code). catchVariableExprs()33 public abstract List<VariableExpr> catchVariableExprs(); 34 // Optional only if the sample code bit is set (i.e. this is sample code). catchBlocks()35 public abstract List<List<Statement>> catchBlocks(); 36 37 // Optional. 38 @Nullable tryResourceExpr()39 public abstract AssignmentExpr tryResourceExpr(); 40 isSampleCode()41 public abstract boolean isSampleCode(); 42 43 @Override accept(AstNodeVisitor visitor)44 public void accept(AstNodeVisitor visitor) { 45 visitor.visit(this); 46 } 47 builder()48 public static Builder builder() { 49 return new AutoValue_TryCatchStatement.Builder() 50 .setCatchVariableExprs(Collections.emptyList()) 51 .setCatchBlocks(Collections.emptyList()) 52 .setIsSampleCode(false); 53 } 54 55 @AutoValue.Builder 56 public abstract static class Builder { setTryResourceExpr(AssignmentExpr assignmentExpr)57 public abstract Builder setTryResourceExpr(AssignmentExpr assignmentExpr); 58 setTryBody(List<Statement> body)59 public abstract Builder setTryBody(List<Statement> body); 60 setIsSampleCode(boolean isSampleCode)61 public abstract Builder setIsSampleCode(boolean isSampleCode); 62 addCatch(@onnull VariableExpr variableExpr, List<Statement> body)63 public Builder addCatch(@Nonnull VariableExpr variableExpr, List<Statement> body) { 64 List<VariableExpr> catchVarExprs = new ArrayList<>(catchVariableExprs()); 65 catchVarExprs.add(variableExpr); 66 setCatchVariableExprs(catchVarExprs); 67 68 List<List<Statement>> blocks = new ArrayList<>(catchBlocks()); 69 blocks.add(body); 70 return setCatchBlocks(blocks); 71 } 72 73 // Private. setCatchVariableExprs(List<VariableExpr> variableExpr)74 abstract Builder setCatchVariableExprs(List<VariableExpr> variableExpr); 75 setCatchBlocks(List<List<Statement>> body)76 abstract Builder setCatchBlocks(List<List<Statement>> body); 77 tryBody()78 abstract ImmutableList<Statement> tryBody(); 79 isSampleCode()80 abstract boolean isSampleCode(); 81 catchVariableExprs()82 abstract List<VariableExpr> catchVariableExprs(); 83 catchBlocks()84 abstract List<List<Statement>> catchBlocks(); 85 autoBuild()86 abstract TryCatchStatement autoBuild(); 87 build()88 public TryCatchStatement build() { 89 NodeValidator.checkNoNullElements(tryBody(), "try body", "try-catch"); 90 NodeValidator.checkNoNullElements( 91 catchVariableExprs(), "catch variable expressions", "try-catch"); 92 catchBlocks() 93 .forEach(body -> NodeValidator.checkNoNullElements(body, "catch body", "try-catch")); 94 95 if (!isSampleCode()) { 96 Preconditions.checkState( 97 !catchVariableExprs().isEmpty(), 98 "Catch variable expression must be set for real, non-sample try-catch blocks."); 99 Preconditions.checkState( 100 catchVariableExprs().stream().allMatch(v -> v.isDecl()), 101 "Catch variable expressions must all be declarations"); 102 Preconditions.checkState( 103 catchVariableExprs().stream() 104 .allMatch(v -> TypeNode.isExceptionType(v.variable().type())), 105 "Catch variables must be an Exception object references"); 106 } 107 108 // Catch any potential future breakage due to changing addCatch above. 109 Preconditions.checkState( 110 catchVariableExprs().size() == catchBlocks().size(), 111 String.format( 112 "%d catch variables found and %d blocks found, but these numbers must be equal", 113 catchVariableExprs().size(), catchBlocks().size())); 114 115 return autoBuild(); 116 } 117 } 118 } 119