Home | History | Annotate | Download | only in codegen
      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;
     17 
     18 import com.google.auto.common.MoreElements;
     19 import com.google.auto.common.MoreTypes;
     20 import com.google.common.base.Optional;
     21 import java.util.Iterator;
     22 import java.util.List;
     23 import javax.lang.model.element.AnnotationMirror;
     24 import javax.lang.model.element.ExecutableElement;
     25 import javax.lang.model.element.TypeElement;
     26 import javax.lang.model.element.VariableElement;
     27 import javax.lang.model.type.DeclaredType;
     28 import javax.lang.model.type.ExecutableType;
     29 import javax.lang.model.type.TypeKind;
     30 import javax.lang.model.type.TypeMirror;
     31 import javax.lang.model.util.Types;
     32 
     33 import static com.google.common.base.Preconditions.checkState;
     34 import static dagger.internal.codegen.ErrorMessages.stripCommonTypePrefixes;
     35 
     36 /**
     37  * Formats the signature of an {@link ExecutableElement} suitable for use in error messages.
     38  *
     39  * @author Christian Gruber
     40  * @since 2.0
     41  */
     42 final class MethodSignatureFormatter extends Formatter<ExecutableElement> {
     43   private final Types types;
     44 
     45   MethodSignatureFormatter(Types types) {
     46     this.types = types;
     47   }
     48 
     49   @Override public String format(ExecutableElement method) {
     50     return format(method, Optional.<DeclaredType>absent());
     51   }
     52 
     53   /**
     54    * Formats an ExecutableElement as if it were contained within the container, if the container is
     55    * present.
     56    */
     57   public String format(ExecutableElement method, Optional<DeclaredType> container) {
     58     StringBuilder builder = new StringBuilder();
     59     TypeElement type = MoreElements.asType(method.getEnclosingElement());
     60     ExecutableType executableType = MoreTypes.asExecutable(method.asType());
     61     if (container.isPresent()) {
     62       executableType = MoreTypes.asExecutable(types.asMemberOf(container.get(), method));
     63       type = MoreElements.asType(container.get().asElement());
     64     }
     65 
     66     // TODO(cgruber): AnnotationMirror formatter.
     67     List<? extends AnnotationMirror> annotations = method.getAnnotationMirrors();
     68     if (!annotations.isEmpty()) {
     69       Iterator<? extends AnnotationMirror> annotationIterator = annotations.iterator();
     70       for (int i = 0; annotationIterator.hasNext(); i++) {
     71         if (i > 0) {
     72           builder.append(' ');
     73         }
     74         builder.append(ErrorMessages.format(annotationIterator.next()));
     75       }
     76       builder.append(' ');
     77     }
     78     builder.append(nameOfType(executableType.getReturnType()));
     79     builder.append(' ');
     80     builder.append(type.getQualifiedName());
     81     builder.append('.');
     82     builder.append(method.getSimpleName());
     83     builder.append('(');
     84     checkState(method.getParameters().size() == executableType.getParameterTypes().size());
     85     Iterator<? extends VariableElement> parameters = method.getParameters().iterator();
     86     Iterator<? extends TypeMirror> parameterTypes = executableType.getParameterTypes().iterator();
     87     for (int i = 0; parameters.hasNext(); i++) {
     88       if (i > 0) {
     89         builder.append(", ");
     90       }
     91       appendParameter(builder, parameters.next(), parameterTypes.next());
     92     }
     93     builder.append(')');
     94     return builder.toString();
     95   }
     96 
     97   private static void appendParameter(StringBuilder builder, VariableElement parameter,
     98       TypeMirror type) {
     99     Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(parameter);
    100     if (qualifier.isPresent()) {
    101       builder.append(ErrorMessages.format(qualifier.get())).append(' ');
    102     }
    103     builder.append(nameOfType(type));
    104   }
    105 
    106   private static String nameOfType(TypeMirror type) {
    107     if (type.getKind().isPrimitive()) {
    108       return MoreTypes.asPrimitiveType(type).toString();
    109     } else if (type.getKind() == TypeKind.VOID) {
    110       return "void";
    111     } else {
    112       return stripCommonTypePrefixes(MoreTypes.asDeclared(type).toString());
    113     }
    114   }
    115 }
    116