• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.api.generator.gapic.model.RegionTag;
18 import com.google.auto.value.AutoValue;
19 import com.google.common.base.Preconditions;
20 import com.google.common.collect.ImmutableList;
21 import java.util.Arrays;
22 import java.util.Collections;
23 import java.util.List;
24 import javax.annotation.Nullable;
25 
26 @AutoValue
27 public abstract class ClassDefinition implements AstNode {
28   // Optional.
fileHeader()29   public abstract ImmutableList<CommentStatement> fileHeader();
30   // Required for samples classes.
31   @Nullable
regionTag()32   public abstract RegionTag regionTag();
33   // Required.
scope()34   public abstract ScopeNode scope();
35   // Required.
classIdentifier()36   public abstract IdentifierNode classIdentifier();
37   // Required for outer classes.
38   @Nullable
packageString()39   public abstract String packageString();
40 
isNested()41   public abstract boolean isNested();
42 
43   // Optional.
headerCommentStatements()44   public abstract ImmutableList<CommentStatement> headerCommentStatements();
45 
annotations()46   public abstract ImmutableList<AnnotationNode> annotations();
47 
48   // Using a list helps with determinism in unit tests.
implementsTypes()49   public abstract ImmutableList<TypeNode> implementsTypes();
50 
51   @Nullable
extendsType()52   public abstract TypeNode extendsType();
53 
isStatic()54   public abstract boolean isStatic();
55 
isFinal()56   public abstract boolean isFinal();
57 
isAbstract()58   public abstract boolean isAbstract();
59 
statements()60   public abstract ImmutableList<Statement> statements();
61 
methods()62   public abstract ImmutableList<MethodDefinition> methods();
63 
nestedClasses()64   public abstract ImmutableList<ClassDefinition> nestedClasses();
65 
66   // Private.
name()67   abstract String name();
68 
69   @Override
accept(AstNodeVisitor visitor)70   public void accept(AstNodeVisitor visitor) {
71     visitor.visit(this);
72   }
73 
builder()74   public static Builder builder() {
75     return new AutoValue_ClassDefinition.Builder()
76         .setFileHeader(Collections.emptyList())
77         .setHeaderCommentStatements(Collections.emptyList())
78         .setIsNested(false)
79         .setIsFinal(false)
80         .setIsStatic(false)
81         .setIsAbstract(false)
82         .setAnnotations(Collections.emptyList())
83         .setImplementsTypes(Collections.emptyList())
84         .setStatements(Collections.emptyList())
85         .setMethods(Collections.emptyList())
86         .setNestedClasses(Collections.emptyList());
87   }
88 
toBuilder()89   public abstract Builder toBuilder();
90 
91   @AutoValue.Builder
92   public abstract static class Builder {
setFileHeader(CommentStatement... headerComments)93     public Builder setFileHeader(CommentStatement... headerComments) {
94       return setFileHeader(Arrays.asList(headerComments));
95     }
96 
setFileHeader(List<CommentStatement> fileHeader)97     public abstract Builder setFileHeader(List<CommentStatement> fileHeader);
98 
setRegionTag(RegionTag regionTag)99     public abstract Builder setRegionTag(RegionTag regionTag);
100 
setHeaderCommentStatements(CommentStatement... comments)101     public Builder setHeaderCommentStatements(CommentStatement... comments) {
102       return setHeaderCommentStatements(Arrays.asList(comments));
103     }
104 
setHeaderCommentStatements( List<CommentStatement> headerCommentStatements)105     public abstract Builder setHeaderCommentStatements(
106         List<CommentStatement> headerCommentStatements);
107 
setScope(ScopeNode scope)108     public abstract Builder setScope(ScopeNode scope);
109 
setPackageString(String pkg)110     public abstract Builder setPackageString(String pkg);
111 
setName(String name)112     public abstract Builder setName(String name);
113 
setIsNested(boolean isNested)114     public abstract Builder setIsNested(boolean isNested);
115 
setAnnotations(List<AnnotationNode> annotations)116     public abstract Builder setAnnotations(List<AnnotationNode> annotations);
117 
setIsAbstract(boolean isAbstract)118     public abstract Builder setIsAbstract(boolean isAbstract);
119 
setIsStatic(boolean isStatic)120     public abstract Builder setIsStatic(boolean isStatic);
121 
setIsFinal(boolean isFinal)122     public abstract Builder setIsFinal(boolean isFinal);
123 
setExtendsType(TypeNode type)124     public abstract Builder setExtendsType(TypeNode type);
125 
setImplementsTypes(List<TypeNode> types)126     public abstract Builder setImplementsTypes(List<TypeNode> types);
127 
setStatements(List<Statement> body)128     public abstract Builder setStatements(List<Statement> body);
129 
setMethods(List<MethodDefinition> methods)130     public abstract Builder setMethods(List<MethodDefinition> methods);
131 
setNestedClasses(List<ClassDefinition> nestedClasses)132     public abstract Builder setNestedClasses(List<ClassDefinition> nestedClasses);
133 
134     // Private accessors.
name()135     abstract String name();
136 
autoBuild()137     abstract ClassDefinition autoBuild();
138 
setClassIdentifier(IdentifierNode methodIdentifier)139     abstract Builder setClassIdentifier(IdentifierNode methodIdentifier);
140 
build()141     public ClassDefinition build() {
142       IdentifierNode classIdentifier = IdentifierNode.builder().setName(name()).build();
143       setClassIdentifier(classIdentifier);
144 
145       ClassDefinition classDef = autoBuild();
146       performNullChecks(classDef);
147 
148       // Only nested classes can forego having a package.
149       if (!classDef.isNested()) {
150         Preconditions.checkNotNull(
151             classDef.packageString(), "Outer classes must have a package name defined");
152         Preconditions.checkState(!classDef.isStatic(), "Outer classes cannot be static");
153         Preconditions.checkState(
154             !classDef.scope().equals(ScopeNode.PRIVATE), "Outer classes cannot be private");
155       } else {
156         Preconditions.checkState(
157             classDef.fileHeader().isEmpty(), "Nested classes cannot have a file header");
158       }
159 
160       // Abstract classes cannot be marked final.
161       if (classDef.isAbstract()) {
162         Preconditions.checkState(!classDef.isFinal(), "Abstract classes cannot be marked final");
163       }
164 
165       // Check abstract extended type.
166       if (classDef.extendsType() != null) {
167         Preconditions.checkState(
168             TypeNode.isReferenceType(classDef.extendsType()),
169             "Classes cannot extend non-reference types");
170         Preconditions.checkState(
171             !classDef.implementsTypes().contains(classDef.extendsType()),
172             "Classes cannot extend and implement the same type");
173       }
174 
175       // Check implemented interface types.
176       for (TypeNode implType : classDef.implementsTypes()) {
177         Preconditions.checkState(
178             TypeNode.isReferenceType(implType), "Classes cannot implement non-reference types");
179       }
180 
181       for (Statement statement : classDef.statements()) {
182         Preconditions.checkState(
183             statement instanceof CommentStatement
184                 || statement instanceof EmptyLineStatement
185                 || statement instanceof ExprStatement
186                 || statement instanceof BlockStatement,
187             "Class statement type must be either an expression, block, or comment statement");
188         if (statement instanceof ExprStatement) {
189           Expr expr = ((ExprStatement) statement).expression();
190           if (expr instanceof VariableExpr) {
191             VariableExpr variableExpr = (VariableExpr) expr;
192             Preconditions.checkState(
193                 variableExpr.isDecl(), "Class expression variable statements must be declarations");
194             Preconditions.checkState(
195                 !variableExpr.scope().equals(ScopeNode.LOCAL),
196                 "Class variable statement cannot have a local scope");
197           } else {
198             Preconditions.checkState(
199                 expr instanceof AssignmentExpr,
200                 "Class expression statement must be assignment or variable declaration");
201             VariableExpr variableExpr = ((AssignmentExpr) expr).variableExpr();
202             Preconditions.checkState(
203                 !variableExpr.scope().equals(ScopeNode.LOCAL),
204                 "Class variable in assignment statement cannot have a local scope");
205           }
206         }
207       }
208 
209       return classDef;
210     }
211 
performNullChecks(ClassDefinition classDef)212     void performNullChecks(ClassDefinition classDef) {
213       String contextInfo = String.format("class  definition of %s", name());
214       NodeValidator.checkNoNullElements(
215           classDef.headerCommentStatements(), "header comments", contextInfo);
216       NodeValidator.checkNoNullElements(classDef.annotations(), "annotations", contextInfo);
217 
218       NodeValidator.checkNoNullElements(
219           classDef.implementsTypes(), "implemented types", contextInfo);
220       NodeValidator.checkNoNullElements(classDef.statements(), "statements", contextInfo);
221 
222       NodeValidator.checkNoNullElements(classDef.methods(), "methods", contextInfo);
223       NodeValidator.checkNoNullElements(classDef.nestedClasses(), "nested classes", contextInfo);
224     }
225   }
226 }
227