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