• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package dagger.internal.codegen.writer;
17 
18 import com.google.common.base.Function;
19 import com.google.common.base.Optional;
20 import com.google.common.collect.FluentIterable;
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.Iterables;
23 import com.google.common.collect.Lists;
24 import com.google.common.collect.Sets;
25 import java.io.IOException;
26 import java.util.List;
27 import java.util.Set;
28 import javax.lang.model.element.Modifier;
29 import javax.lang.model.element.TypeElement;
30 
31 import static com.google.common.base.Preconditions.checkState;
32 import static javax.lang.model.element.Modifier.PRIVATE;
33 import static javax.lang.model.element.Modifier.PROTECTED;
34 import static javax.lang.model.element.Modifier.PUBLIC;
35 
36 public final class ClassWriter extends TypeWriter {
37   private Optional<TypeName> superclass;
38   private final List<ConstructorWriter> constructorWriters;
39   private final List<TypeVariableName> typeParameters;
40 
ClassWriter(ClassName className)41   ClassWriter(ClassName className) {
42     super(className);
43     this.superclass = Optional.absent();
44     this.constructorWriters = Lists.newArrayList();
45     this.typeParameters = Lists.newArrayList();
46   }
47 
setSuperclass(TypeName typeReference)48   public void setSuperclass(TypeName typeReference) {
49     checkState(!superclass.isPresent());
50     superclass = Optional.of(typeReference);
51   }
52 
53   /**
54    * If {@code supertype} is a class, makes this class extend it; if it is an interface, makes this
55    * class implement it.
56    */
setSupertype(TypeElement supertype)57   public void setSupertype(TypeElement supertype) {
58     switch (supertype.getKind()) {
59       case CLASS:
60         setSuperclass(ClassName.fromTypeElement(supertype));
61         break;
62       case INTERFACE:
63         addImplementedType(supertype);
64         break;
65       default:
66         throw new IllegalArgumentException(supertype + " must be a class or interface");
67     }
68   }
69 
addConstructor()70   public ConstructorWriter addConstructor() {
71     ConstructorWriter constructorWriter = new ConstructorWriter(name.simpleName());
72     constructorWriters.add(constructorWriter);
73     return constructorWriter;
74   }
75 
addTypeParameter(TypeVariableName typeVariableName)76   public void addTypeParameter(TypeVariableName typeVariableName) {
77     this.typeParameters.add(typeVariableName);
78   }
79 
addTypeParameters(Iterable<TypeVariableName> typeVariableNames)80   public void addTypeParameters(Iterable<TypeVariableName> typeVariableNames) {
81     Iterables.addAll(typeParameters, typeVariableNames);
82   }
83 
typeParameters()84   public List<TypeVariableName> typeParameters() {
85     return ImmutableList.copyOf(typeParameters);
86   }
87 
88   @Override
write(Appendable appendable, Context context)89   public Appendable write(Appendable appendable, Context context) throws IOException {
90     context = context.createSubcontext(FluentIterable.from(nestedTypeWriters)
91         .transform(new Function<TypeWriter, ClassName>() {
92           @Override public ClassName apply(TypeWriter input) {
93             return input.name;
94           }
95         })
96         .toSet());
97     writeAnnotations(appendable, context);
98     writeModifiers(appendable).append("class ").append(name.simpleName());
99     Writables.join(", ", typeParameters, "<", ">", appendable, context);
100     if (superclass.isPresent()) {
101       appendable.append(" extends ");
102       superclass.get().write(appendable, context);
103     }
104     Writables.join(", ", implementedTypes, " implements ", "", appendable, context);
105     appendable.append(" {");
106     if (!fieldWriters.isEmpty()) {
107       appendable.append('\n');
108     }
109     for (VariableWriter fieldWriter : fieldWriters.values()) {
110       fieldWriter.write(new IndentingAppendable(appendable), context).append("\n");
111     }
112     for (ConstructorWriter constructorWriter : constructorWriters) {
113       appendable.append('\n');
114       if (!isDefaultConstructor(constructorWriter)) {
115         constructorWriter.write(new IndentingAppendable(appendable), context);
116       }
117     }
118     for (MethodWriter methodWriter : methodWriters) {
119       appendable.append('\n');
120       methodWriter.write(new IndentingAppendable(appendable), context);
121     }
122     for (TypeWriter nestedTypeWriter : nestedTypeWriters) {
123       appendable.append('\n');
124       nestedTypeWriter.write(new IndentingAppendable(appendable), context);
125     }
126     appendable.append("}\n");
127     return appendable;
128   }
129 
130   private static final Set<Modifier> VISIBILIY_MODIFIERS =
131       Sets.immutableEnumSet(PUBLIC, PROTECTED, PRIVATE);
132 
isDefaultConstructor(ConstructorWriter constructorWriter)133   private boolean isDefaultConstructor(ConstructorWriter constructorWriter) {
134     return Sets.intersection(VISIBILIY_MODIFIERS, modifiers)
135         .equals(Sets.intersection(VISIBILIY_MODIFIERS, constructorWriter.modifiers))
136         && constructorWriter.body().isEmpty();
137   }
138 
139   @Override
referencedClasses()140   public Set<ClassName> referencedClasses() {
141     return FluentIterable.from(ImmutableList.<HasClassReferences>of())
142         .append(nestedTypeWriters)
143         .append(fieldWriters.values())
144         .append(constructorWriters)
145         .append(methodWriters)
146         .append(implementedTypes)
147         .append(superclass.asSet())
148         .append(annotations)
149         .append(typeParameters)
150         .transformAndConcat(HasClassReferences.COMBINER)
151         .toSet();
152   }
153 }
154