/* * 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.google.devtools.j2objc.types; import com.google.common.base.Preconditions; import com.google.devtools.j2objc.util.ElementUtil; import com.google.devtools.j2objc.util.NameTable; import com.google.devtools.j2objc.util.TypeUtil; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ElementVisitor; import javax.lang.model.element.Modifier; import javax.lang.model.element.Name; import javax.lang.model.element.NestingKind; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeParameterElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeVisitor; /** * Element class for types created during translation. * * @author Keith Stanger */ public class GeneratedTypeElement extends GeneratedElement implements TypeElement { private final TypeMirror superclass; private List<TypeMirror> interfaces = new ArrayList<>(); private final NestingKind nestingKind; private final Name qualifiedName; private final String header; private final boolean isIosType; protected GeneratedTypeElement( String name, ElementKind kind, Element enclosingElement, TypeMirror superclass, NestingKind nestingKind, String header, boolean isIosType, boolean synthetic) { super(Preconditions.checkNotNull(name), checkElementKind(kind), enclosingElement, synthetic); this.superclass = superclass; this.nestingKind = nestingKind; qualifiedName = new NameImpl(getQualifiedPrefix(enclosingElement) + name); this.header = header; this.isIosType = isIosType; } public static GeneratedTypeElement mutableCopy(TypeElement element) { return new GeneratedTypeElement( element.getSimpleName().toString(), element.getKind(), element.getEnclosingElement(), element.getSuperclass(), element.getNestingKind(), ElementUtil.getHeader(element), ElementUtil.isIosType(element), ElementUtil.isSynthetic(element)); } private static GeneratedTypeElement newEmulatedType( String qualifiedName, ElementKind kind, TypeMirror superclass) { int idx = qualifiedName.lastIndexOf('.'); String packageName = idx < 0 ? "" : qualifiedName.substring(0, idx); PackageElement packageElement = new GeneratedPackageElement(packageName); return new GeneratedTypeElement( qualifiedName.substring(idx + 1), kind, packageElement, superclass, NestingKind.TOP_LEVEL, null, false, false); } public static GeneratedTypeElement newEmulatedClass(String qualifiedName, TypeMirror superclass) { return newEmulatedType(qualifiedName, ElementKind.CLASS, superclass); } public static GeneratedTypeElement newEmulatedInterface(String qualifiedName) { return newEmulatedType(qualifiedName, ElementKind.INTERFACE, null); } public static GeneratedTypeElement newIosType( String name, ElementKind kind, TypeElement superclass, String header) { return new GeneratedTypeElement( name, kind, null, superclass != null ? superclass.asType() : null, NestingKind.TOP_LEVEL, header, true, false); } public static GeneratedTypeElement newIosClass( String name, TypeElement superclass, String header) { return newIosType(name, ElementKind.CLASS, superclass, header); } public static GeneratedTypeElement newIosInterface(String name, String header) { return newIosType(name, ElementKind.INTERFACE, null, header); } public static GeneratedTypeElement newPackageInfoClass( PackageElement pkgElem, TypeUtil typeUtil) { return (GeneratedTypeElement) new GeneratedTypeElement( NameTable.PACKAGE_INFO_CLASS_NAME, ElementKind.CLASS, pkgElem, typeUtil.getJavaObject().asType(), NestingKind.TOP_LEVEL, null, false, false) .addModifiers(Modifier.PRIVATE); } private static ElementKind checkElementKind(ElementKind kind) { Preconditions.checkArgument(kind.isClass() || kind.isInterface()); return kind; } private static String getQualifiedPrefix(Element enclosing) { if (enclosing == null) { return ""; } else if (ElementUtil.isTypeElement(enclosing)) { return ((TypeElement) enclosing).getQualifiedName().toString() + '.'; } else if (ElementUtil.isPackage(enclosing)) { PackageElement pkg = (PackageElement) enclosing; return pkg.isUnnamed() ? "" : pkg.getQualifiedName().toString() + '.'; } else { return getQualifiedPrefix(enclosing.getEnclosingElement()); } } @Override public TypeMirror asType() { return new Mirror(); } @Override public Name getQualifiedName() { return qualifiedName; } public String getHeader() { return header; } public boolean isIosType() { return isIosType; } @Override public TypeMirror getSuperclass() { return superclass; } @Override public NestingKind getNestingKind() { return nestingKind; } @Override public List<? extends TypeMirror> getInterfaces() { return interfaces; } public List<? extends TypeMirror> getDirectSupertypes() { List<TypeMirror> result = new ArrayList<>(interfaces); if (superclass != null) { result.add(0, superclass); // Superclass must be first. } return result; } public void addInterface(TypeMirror t) { interfaces.add(t); } public void addInterfaces(Collection<? extends TypeMirror> types) { interfaces.addAll(types); } @Override public List<? extends TypeParameterElement> getTypeParameters() { return Collections.emptyList(); } @Override public <R, P> R accept(ElementVisitor<R, P> v, P p) { return v.visitType(this, p); } /** * The associated TypeMirror. * TODO(kstanger): Make private when javac conversion is complete. */ public class Mirror extends AbstractTypeMirror implements DeclaredType { @Override public TypeKind getKind() { return TypeKind.DECLARED; } @Override public Element asElement() { return GeneratedTypeElement.this; } @Override public TypeMirror getEnclosingType() { TypeElement declaringClass = ElementUtil.getDeclaringClass(GeneratedTypeElement.this); return declaringClass == null ? null : declaringClass.asType(); } @Override public List<? extends TypeMirror> getTypeArguments() { return Collections.emptyList(); } @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) { return GeneratedTypeElement.this.getAnnotation(annotationType); } @Override public List<? extends AnnotationMirror> getAnnotationMirrors() { return GeneratedTypeElement.this.getAnnotationMirrors(); } @Override public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) { return GeneratedTypeElement.this.getAnnotationsByType(annotationType); } @Override public <R, P> R accept(TypeVisitor<R, P> v, P p) { return v.visitDeclared(this, p); } @Override public boolean equals(Object obj) { return obj instanceof Mirror && ((Mirror) obj).asElement().equals(GeneratedTypeElement.this); } @Override public int hashCode() { return 31 * GeneratedTypeElement.this.hashCode(); } @Override public String toString() { return GeneratedTypeElement.this.getQualifiedName().toString(); } } }