blob: d27167338756aa197c51b35b09e3d98a46837b51 [file] [log] [blame]
/*
* Copyright 2013-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.facebook.buck.java.abi;
import static javax.lang.model.element.ElementKind.CLASS;
import static javax.lang.model.element.ElementKind.ENUM;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.TypeMirror;
class TypeSummary implements Renderable {
private String summary;
public TypeSummary(RenderableTypes renderables, TypeElement element) {
StringBuilder builder = new StringBuilder();
appendTypeSignature(builder, element);
Set<String> nestedTypes = new TreeSet<>();
Set<String> contained = new TreeSet<>();
// Ordering matters for enum constants.
Set<String> enumValues = new LinkedHashSet<>();
// Collect the enclosed elements, keeping enclosed types separately.
for (Element enclosed : element.getEnclosedElements()) {
StringBuilder elementBuilder = new StringBuilder();
Renderable renderable = renderables.deriveFor(enclosed);
renderable.appendTo(elementBuilder);
if (renderable instanceof TypeSummary) {
nestedTypes.add(elementBuilder.toString());
} else if (renderable instanceof EnumConstantSummary) {
enumValues.add(elementBuilder.toString());
} else {
contained.add(elementBuilder.toString());
}
}
// Append enum constants
for (String value : enumValues) {
builder.append(value);
}
// Append all methods, fields, enum values and constants
for (String text : contained) {
builder.append(text);
}
// Append all nested types.
if (!nestedTypes.isEmpty()) {
builder.append("-----\n");
Joiner.on("-----\n").appendTo(builder, nestedTypes);
}
summary = builder.toString();
}
private void appendTypeSignature(StringBuilder builder, TypeElement element) {
ElementKind kind = element.getKind();
builder.append(Annotations.printAnnotations(element.getAnnotationMirrors()));
// Note that this causes all interfaces to be marked as "abstract". Since we're just generating
// a text representation of the interface and not something perfect, I'm okay with this.
builder.append(Modifiers.printModifiers(element.getModifiers()));
switch (kind) {
case ANNOTATION_TYPE:
builder.append("@interface ");
break;
case CLASS:
builder.append("class ");
break;
case ENUM:
builder.append("enum ");
break;
case INTERFACE:
builder.append("interface ");
break;
default:
throw new RuntimeException("Unhandled kind: " + kind);
}
builder.append(element.getQualifiedName());
List<? extends TypeParameterElement> typeParams = element.getTypeParameters();
if (!typeParams.isEmpty()) {
builder.append("<");
Joiner.on(", ").appendTo(builder, typeParams);
builder.append(">");
}
if (kind == CLASS) {
builder.append(" extends ").append(element.getSuperclass());
}
// Sort the list alphabetically.
List<String> converted = new ArrayList<>();
for (TypeMirror mirror : element.getInterfaces()) {
converted.add(mirror.toString());
}
Collections.sort(converted);
if (!converted.isEmpty()) {
if (kind == CLASS || kind == ENUM) {
builder.append(" implements ");
} else {
builder.append(" extends ");
}
Joiner.on(", ").appendTo(builder, converted);
}
builder.append("\n");
}
@Override
public void appendTo(StringBuilder builder) {
builder.append(summary);
}
}