1 /* 2 * Copyright (C) 2013 The Dagger Authors. 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 17 package dagger.internal.codegen.base; 18 19 import static com.google.auto.common.MoreElements.asExecutable; 20 import static java.util.stream.Collectors.joining; 21 22 import javax.inject.Inject; 23 import javax.lang.model.element.Element; 24 import javax.lang.model.element.ElementVisitor; 25 import javax.lang.model.element.ExecutableElement; 26 import javax.lang.model.element.TypeElement; 27 import javax.lang.model.element.VariableElement; 28 import javax.lang.model.util.ElementKindVisitor8; 29 30 /** 31 * Formats elements into a useful string representation. 32 * 33 * <p>Elements directly enclosed by a type are preceded by the enclosing type's qualified name. 34 * 35 * <p>Parameters are given with their enclosing executable, with other parameters elided. 36 */ 37 public final class ElementFormatter extends Formatter<Element> { 38 @Inject ElementFormatter()39 ElementFormatter() {} 40 41 @Override format(Element element)42 public String format(Element element) { 43 return elementToString(element); 44 } 45 46 /** 47 * Returns a useful string form for an element. 48 * 49 * <p>Elements directly enclosed by a type are preceded by the enclosing type's qualified name. 50 * 51 * <p>Parameters are given with their enclosing executable, with other parameters elided. 52 */ elementToString(Element element)53 public static String elementToString(Element element) { 54 return element.accept(ELEMENT_TO_STRING, null); 55 } 56 57 private static final ElementVisitor<String, Void> ELEMENT_TO_STRING = 58 new ElementKindVisitor8<String, Void>() { 59 @Override 60 public String visitExecutable(ExecutableElement executableElement, Void aVoid) { 61 return enclosingTypeAndMemberName(executableElement) 62 .append( 63 executableElement.getParameters().stream() 64 .map(parameter -> parameter.asType().toString()) 65 .collect(joining(", ", "(", ")"))) 66 .toString(); 67 } 68 69 @Override 70 public String visitVariableAsParameter(VariableElement parameter, Void aVoid) { 71 ExecutableElement methodOrConstructor = asExecutable(parameter.getEnclosingElement()); 72 return enclosingTypeAndMemberName(methodOrConstructor) 73 .append('(') 74 .append( 75 formatArgumentInList( 76 methodOrConstructor.getParameters().indexOf(parameter), 77 methodOrConstructor.getParameters().size(), 78 parameter.getSimpleName())) 79 .append(')') 80 .toString(); 81 } 82 83 @Override 84 public String visitVariableAsField(VariableElement field, Void aVoid) { 85 return enclosingTypeAndMemberName(field).toString(); 86 } 87 88 @Override 89 public String visitType(TypeElement type, Void aVoid) { 90 return type.getQualifiedName().toString(); 91 } 92 93 @Override 94 protected String defaultAction(Element element, Void aVoid) { 95 throw new UnsupportedOperationException( 96 "Can't determine string for " + element.getKind() + " element " + element); 97 } 98 99 private StringBuilder enclosingTypeAndMemberName(Element element) { 100 StringBuilder name = new StringBuilder(element.getEnclosingElement().accept(this, null)); 101 if (!element.getSimpleName().contentEquals("<init>")) { 102 name.append('.').append(element.getSimpleName()); 103 } 104 return name; 105 } 106 }; 107 } 108