15d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin/* 25d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * Copyright (C) 2014 Google, Inc. 35d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * 45d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License"); 55d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * you may not use this file except in compliance with the License. 65d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * You may obtain a copy of the License at 75d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * 85d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0 95d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * 105d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * Unless required by applicable law or agreed to in writing, software 115d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS, 125d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * See the License for the specific language governing permissions and 145d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * limitations under the License. 155d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin */ 165d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinpackage dagger.internal.codegen.writer; 175d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 185d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.base.Function; 195d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.base.Optional; 205d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.collect.FluentIterable; 215d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.collect.ImmutableList; 225d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.collect.Iterables; 235d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.collect.Lists; 245d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.collect.Sets; 255d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport java.io.IOException; 265d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport java.util.List; 275d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport java.util.Set; 285d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.element.Modifier; 295d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.element.TypeElement; 305d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 315d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static com.google.common.base.Preconditions.checkState; 325d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.element.Modifier.PRIVATE; 335d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.element.Modifier.PROTECTED; 345d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.element.Modifier.PUBLIC; 355d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 365d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinpublic final class ClassWriter extends TypeWriter { 375d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin private Optional<TypeName> superclass; 385d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin private final List<ConstructorWriter> constructorWriters; 395d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin private final List<TypeVariableName> typeParameters; 405d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 415d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin ClassWriter(ClassName className) { 425d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin super(className); 435d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin this.superclass = Optional.absent(); 445d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin this.constructorWriters = Lists.newArrayList(); 455d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin this.typeParameters = Lists.newArrayList(); 465d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 475d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 485d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin public void setSuperclass(TypeName typeReference) { 495d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin checkState(!superclass.isPresent()); 505d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin superclass = Optional.of(typeReference); 515d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 525d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 535d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin /** 545d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * If {@code supertype} is a class, makes this class extend it; if it is an interface, makes this 555d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * class implement it. 565d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin */ 575d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin public void setSupertype(TypeElement supertype) { 585d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin switch (supertype.getKind()) { 595d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin case CLASS: 605d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin setSuperclass(ClassName.fromTypeElement(supertype)); 615d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin break; 625d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin case INTERFACE: 635d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin addImplementedType(supertype); 645d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin break; 655d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin default: 665d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin throw new IllegalArgumentException(supertype + " must be a class or interface"); 675d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 685d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 695d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 705d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin public ConstructorWriter addConstructor() { 715d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin ConstructorWriter constructorWriter = new ConstructorWriter(name.simpleName()); 725d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin constructorWriters.add(constructorWriter); 735d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin return constructorWriter; 745d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 755d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 765d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin public void addTypeParameter(TypeVariableName typeVariableName) { 775d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin this.typeParameters.add(typeVariableName); 785d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 795d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 805d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin public void addTypeParameters(Iterable<TypeVariableName> typeVariableNames) { 815d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin Iterables.addAll(typeParameters, typeVariableNames); 825d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 835d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 845d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin public List<TypeVariableName> typeParameters() { 855d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin return ImmutableList.copyOf(typeParameters); 865d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 875d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 885d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin @Override 895d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin public Appendable write(Appendable appendable, Context context) throws IOException { 905d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin context = context.createSubcontext(FluentIterable.from(nestedTypeWriters) 915d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .transform(new Function<TypeWriter, ClassName>() { 925d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin @Override public ClassName apply(TypeWriter input) { 935d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin return input.name; 945d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 955d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin }) 965d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .toSet()); 975d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin writeAnnotations(appendable, context); 985d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin writeModifiers(appendable).append("class ").append(name.simpleName()); 995d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin Writables.join(", ", typeParameters, "<", ">", appendable, context); 1005d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (superclass.isPresent()) { 1015d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin appendable.append(" extends "); 1025d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin superclass.get().write(appendable, context); 1035d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1045d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin Writables.join(", ", implementedTypes, " implements ", "", appendable, context); 1055d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin appendable.append(" {"); 1065d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (!fieldWriters.isEmpty()) { 1075d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin appendable.append('\n'); 1085d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1095d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin for (VariableWriter fieldWriter : fieldWriters.values()) { 1105d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin fieldWriter.write(new IndentingAppendable(appendable), context).append("\n"); 1115d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1125d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin for (ConstructorWriter constructorWriter : constructorWriters) { 1135d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin appendable.append('\n'); 1145d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin if (!isDefaultConstructor(constructorWriter)) { 1155d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin constructorWriter.write(new IndentingAppendable(appendable), context); 1165d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1175d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1185d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin for (MethodWriter methodWriter : methodWriters) { 1195d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin appendable.append('\n'); 1205d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin methodWriter.write(new IndentingAppendable(appendable), context); 1215d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1225d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin for (TypeWriter nestedTypeWriter : nestedTypeWriters) { 1235d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin appendable.append('\n'); 1245d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin nestedTypeWriter.write(new IndentingAppendable(appendable), context); 1255d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1265d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin appendable.append("}\n"); 1275d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin return appendable; 1285d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1295d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 1305d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin private static final Set<Modifier> VISIBILIY_MODIFIERS = 1315d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin Sets.immutableEnumSet(PUBLIC, PROTECTED, PRIVATE); 1325d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 1335d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin private boolean isDefaultConstructor(ConstructorWriter constructorWriter) { 1345d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin return Sets.intersection(VISIBILIY_MODIFIERS, modifiers) 1355d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .equals(Sets.intersection(VISIBILIY_MODIFIERS, constructorWriter.modifiers)) 1365d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin && constructorWriter.body().isEmpty(); 1375d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1385d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin 1395d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin @Override 1405d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin public Set<ClassName> referencedClasses() { 1415d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin return FluentIterable.from(ImmutableList.<HasClassReferences>of()) 1425d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .append(nestedTypeWriters) 1435d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .append(fieldWriters.values()) 1445d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .append(constructorWriters) 1455d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .append(methodWriters) 1465d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .append(implementedTypes) 1475d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .append(superclass.asSet()) 1485d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .append(annotations) 1495d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .append(typeParameters) 1505d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .transformAndConcat(HasClassReferences.COMBINER) 1515d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin .toSet(); 1525d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin } 1535d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin} 154