blob: 34f0de591684acfe7ef2f3de461ea016f0d0020b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2013 BEA Systems, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* wharley@bea.com - initial API and implementation
* IBM Corporation - fix for 342470
* IBM Corporation - fix for 342598
* IBM Corporation - Java 8 support
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.apt.model;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.util.ArrayList;
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.PackageElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.TypeMirror;
import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
/**
*
*/
public class TypeParameterElementImpl extends ElementImpl implements TypeParameterElement
{
private final Element _declaringElement;
// Cache the bounds, because they're expensive to compute
private List<? extends TypeMirror> _bounds = null;
/* package */ TypeParameterElementImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding, Element declaringElement) {
super(env, binding);
_declaringElement = declaringElement;
}
/* package */ TypeParameterElementImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding) {
super(env, binding);
_declaringElement = _env.getFactory().newElement(binding.declaringElement);
}
@Override
public List<? extends TypeMirror> getBounds()
{
if (null == _bounds) {
_bounds = calculateBounds();
}
return _bounds;
}
// This code is drawn from org.eclipse.jdt.core.dom.TypeBinding.getTypeBounds()
private List<? extends TypeMirror> calculateBounds() {
TypeVariableBinding typeVariableBinding = (TypeVariableBinding)_binding;
ReferenceBinding varSuperclass = typeVariableBinding.superclass();
TypeBinding firstClassOrArrayBound = typeVariableBinding.firstBound;
int boundsLength = 0;
boolean isFirstBoundATypeVariable = false;
if (firstClassOrArrayBound != null) {
if (firstClassOrArrayBound.isTypeVariable()) {
isFirstBoundATypeVariable = true;
}
if (TypeBinding.equalsEquals(firstClassOrArrayBound, varSuperclass)) {
boundsLength++;
if (firstClassOrArrayBound.isTypeVariable()) {
isFirstBoundATypeVariable = true;
}
} else if (firstClassOrArrayBound.isArrayType()) { // capture of ? extends/super arrayType
boundsLength++;
} else {
firstClassOrArrayBound = null;
}
}
ReferenceBinding[] superinterfaces = typeVariableBinding.superInterfaces();
int superinterfacesLength = 0;
if (superinterfaces != null) {
superinterfacesLength = superinterfaces.length;
boundsLength += superinterfacesLength;
}
List<TypeMirror> typeBounds = new ArrayList<TypeMirror>(boundsLength);
if (boundsLength != 0) {
if (firstClassOrArrayBound != null) {
TypeMirror typeBinding = _env.getFactory().newTypeMirror(firstClassOrArrayBound);
if (typeBinding == null) {
return Collections.emptyList();
}
typeBounds.add(typeBinding);
}
// we need to filter out remaining bounds if the first bound is a type variable
if (superinterfaces != null && !isFirstBoundATypeVariable) {
for (int i = 0; i < superinterfacesLength; i++) {
TypeMirror typeBinding = _env.getFactory().newTypeMirror(superinterfaces[i]);
if (typeBinding == null) {
return Collections.emptyList();
}
typeBounds.add(typeBinding);
}
}
} else {
// at least we must add java.lang.Object
typeBounds.add(_env.getFactory().newTypeMirror(_env.getLookupEnvironment().getType(LookupEnvironment.JAVA_LANG_OBJECT)));
}
return Collections.unmodifiableList(typeBounds);
}
@Override
public Element getGenericElement()
{
return _declaringElement;
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p)
{
return v.visitTypeParameter(this, p);
}
/*
* (non-Javadoc)
* Java supports annotations on type parameters from JLS8
* @see javax.lang.model.element.Element#getAnnotationMirrors()
*/
@Override
protected AnnotationBinding[] getAnnotationBindings()
{
return ((TypeVariableBinding)_binding).getTypeAnnotations();
}
private boolean shouldEmulateJavacBug() {
if (_env.getLookupEnvironment().globalOptions.emulateJavacBug8031744) {
AnnotationBinding [] annotations = getAnnotationBindings();
for (int i = 0, length = annotations.length; i < length; i++) {
ReferenceBinding firstAnnotationType = annotations[i].getAnnotationType();
for (int j = i+1; j < length; j++) {
ReferenceBinding secondAnnotationType = annotations[j].getAnnotationType();
if (firstAnnotationType == secondAnnotationType) //$IDENTITY-COMPARISON$
return true;
}
}
}
return false;
}
@Override
public List<? extends AnnotationMirror> getAnnotationMirrors() {
if (shouldEmulateJavacBug())
return Collections.emptyList();
return super.getAnnotationMirrors();
}
@Override
@SuppressWarnings("unchecked") // for the cast to A
public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
if (shouldEmulateJavacBug())
return (A[]) Array.newInstance(annotationType, 0);
return super.getAnnotationsByType(annotationType);
}
@Override
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
if (shouldEmulateJavacBug())
return null;
return super.getAnnotation(annotationType);
}
/*
* (non-Javadoc)
* Always return an empty list; type parameters do not enclose other elements.
* @see javax.lang.model.element.Element#getEnclosedElements()
*/
@Override
public List<? extends Element> getEnclosedElements()
{
return Collections.emptyList();
}
/*
* (non-Javadoc)
* Always return null.
* @see javax.lang.model.element.Element#getEnclosingElement()
*/
@Override
public Element getEnclosingElement()
{
return getGenericElement();
}
@Override
public ElementKind getKind()
{
return ElementKind.TYPE_PARAMETER;
}
@Override
PackageElement getPackage()
{
// TODO what is the package of a type parameter?
return null;
}
@Override
public String toString() {
return new String(_binding.readableName());
}
}