/******************************************************************************* * Copyright (c) 2005, 2011 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.compiler.apt.model; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ElementVisitor; import javax.lang.model.element.ExecutableElement; 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.element.VariableElement; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; 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 TypeElementImpl extends ElementImpl implements TypeElement { private final ElementKind _kindHint; /** * In general, clients should call {@link Factory#newDeclaredType(ReferenceBinding)} or * {@link Factory#newElement(org.eclipse.jdt.internal.compiler.lookup.Binding)} to * create new instances. */ TypeElementImpl(BaseProcessingEnvImpl env, ReferenceBinding binding, ElementKind kindHint) { super(env, binding); _kindHint = kindHint; } @Override public <R, P> R accept(ElementVisitor<R, P> v, P p) { return v.visitType(this, p); } @Override protected AnnotationBinding[] getAnnotationBindings() { return ((ReferenceBinding)_binding).getAnnotations(); } @Override public List<? extends Element> getEnclosedElements() { ReferenceBinding binding = (ReferenceBinding)_binding; List<Element> enclosed = new ArrayList<Element>(binding.fieldCount() + binding.methods().length); for (MethodBinding method : binding.methods()) { ExecutableElement executable = new ExecutableElementImpl(_env, method); enclosed.add(executable); } for (FieldBinding field : binding.fields()) { // TODO no field should be excluded according to the JLS if (!field.isSynthetic()) { VariableElement variable = new VariableElementImpl(_env, field); enclosed.add(variable); } } for (ReferenceBinding memberType : binding.memberTypes()) { TypeElement type = new TypeElementImpl(_env, memberType, null); enclosed.add(type); } return Collections.unmodifiableList(enclosed); } @Override public Element getEnclosingElement() { ReferenceBinding binding = (ReferenceBinding)_binding; ReferenceBinding enclosingType = binding.enclosingType(); if (null == enclosingType) { // this is a top level type; get its package return _env.getFactory().newPackageElement(binding.fPackage); } else { return _env.getFactory().newElement(binding.enclosingType()); } } @Override public String getFileName() { char[] name = ((ReferenceBinding)_binding).getFileName(); if (name == null) return null; return new String(name); } @Override public List<? extends TypeMirror> getInterfaces() { ReferenceBinding binding = (ReferenceBinding)_binding; if (null == binding.superInterfaces() || binding.superInterfaces().length == 0) { return Collections.emptyList(); } List<TypeMirror> interfaces = new ArrayList<TypeMirror>(binding.superInterfaces().length); for (ReferenceBinding interfaceBinding : binding.superInterfaces()) { TypeMirror interfaceType = _env.getFactory().newTypeMirror(interfaceBinding); if (interfaceType.getKind() == TypeKind.ERROR) { if (this._env.getSourceVersion().compareTo(SourceVersion.RELEASE_6) > 0) { // for jdk 7 and above, add error types interfaces.add(interfaceType); } } else { interfaces.add(interfaceType); } } return Collections.unmodifiableList(interfaces); } @Override public ElementKind getKind() { if (null != _kindHint) { return _kindHint; } ReferenceBinding refBinding = (ReferenceBinding)_binding; // The order of these comparisons is important: e.g., enum is subset of class if (refBinding.isEnum()) { return ElementKind.ENUM; } else if (refBinding.isAnnotationType()) { return ElementKind.ANNOTATION_TYPE; } else if (refBinding.isInterface()) { return ElementKind.INTERFACE; } else if (refBinding.isClass()) { return ElementKind.CLASS; } else { throw new IllegalArgumentException("TypeElement " + new String(refBinding.shortReadableName()) + //$NON-NLS-1$ " has unexpected attributes " + refBinding.modifiers); //$NON-NLS-1$ } } @Override public Set<Modifier> getModifiers() { ReferenceBinding refBinding = (ReferenceBinding)_binding; int modifiers = refBinding.modifiers; if (refBinding.isInterface() && refBinding.isNestedType()) { modifiers |= ClassFileConstants.AccStatic; } return Factory.getModifiers(modifiers, getKind(), refBinding.isBinaryBinding()); } @Override public NestingKind getNestingKind() { ReferenceBinding refBinding = (ReferenceBinding)_binding; if (refBinding.isAnonymousType()) { return NestingKind.ANONYMOUS; } else if (refBinding.isLocalType()) { return NestingKind.LOCAL; } else if (refBinding.isMemberType()) { return NestingKind.MEMBER; } return NestingKind.TOP_LEVEL; } @Override PackageElement getPackage() { ReferenceBinding binding = (ReferenceBinding)_binding; return _env.getFactory().newPackageElement((PackageBinding)binding.fPackage); } @Override public Name getQualifiedName() { ReferenceBinding binding = (ReferenceBinding)_binding; char[] qName; if (binding.isMemberType()) { qName = CharOperation.concatWith(binding.enclosingType().compoundName, binding.sourceName, '.'); CharOperation.replace(qName, '$', '.'); } else { qName = CharOperation.concatWith(binding.compoundName, '.'); } return new NameImpl(qName); } /* * (non-Javadoc) * @see org.eclipse.jdt.internal.compiler.apt.model.ElementImpl#getSimpleName() * @return last segment of name, e.g. for pa.pb.X.Y return Y. */ @Override public Name getSimpleName() { ReferenceBinding binding = (ReferenceBinding)_binding; return new NameImpl(binding.sourceName()); } @Override public TypeMirror getSuperclass() { ReferenceBinding binding = (ReferenceBinding)_binding; ReferenceBinding superBinding = binding.superclass(); if (null == superBinding || binding.isInterface()) { return _env.getFactory().getNoType(TypeKind.NONE); } // superclass of a type must be a DeclaredType return _env.getFactory().newTypeMirror(superBinding); } @Override public List<? extends TypeParameterElement> getTypeParameters() { ReferenceBinding binding = (ReferenceBinding)_binding; TypeVariableBinding[] variables = binding.typeVariables(); if (variables.length == 0) { return Collections.emptyList(); } List<TypeParameterElement> params = new ArrayList<TypeParameterElement>(variables.length); for (TypeVariableBinding variable : variables) { params.add(_env.getFactory().newTypeParameterElement(variable, this)); } return Collections.unmodifiableList(params); } @Override public boolean hides(Element hidden) { if (!(hidden instanceof TypeElementImpl)) { return false; } ReferenceBinding hiddenBinding = (ReferenceBinding)((TypeElementImpl)hidden)._binding; if (hiddenBinding.isPrivate()) { return false; } ReferenceBinding hiderBinding = (ReferenceBinding)_binding; if (TypeBinding.equalsEquals(hiddenBinding, hiderBinding)) { return false; } if (!hiddenBinding.isMemberType() || !hiderBinding.isMemberType()) { return false; } if (!CharOperation.equals(hiddenBinding.sourceName, hiderBinding.sourceName)) { return false; } return null != hiderBinding.enclosingType().findSuperTypeOriginatingFrom(hiddenBinding.enclosingType()); } @Override public String toString() { ReferenceBinding binding = (ReferenceBinding) this._binding; char[] concatWith = CharOperation.concatWith(binding.compoundName, '.'); if (binding.isNestedType()) { CharOperation.replace(concatWith, '$', '.'); return new String(concatWith); } return new String(concatWith); } }