/*
* 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.jdt;
import com.google.devtools.j2objc.types.GeneratedVariableElement;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.Name;
import javax.lang.model.element.NestingKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.type.TypeMirror;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
class JdtTypeElement extends JdtElement implements TypeElement {
JdtTypeElement(ITypeBinding binding) {
super(binding.getTypeDeclaration(), binding.getTypeDeclaration().getName(),
getModifiers(binding));
}
private static int getModifiers(ITypeBinding binding) {
int modifiers = binding.getTypeDeclaration().getModifiers();
if (binding.isAnonymous()) {
modifiers |= Modifier.STATIC;
}
return modifiers;
}
@Override
public String toString() {
return ((ITypeBinding) binding).getKey();
}
@Override
public ElementKind getKind() {
ITypeBinding type = (ITypeBinding) binding;
if (type.isAnnotation()) {
return ElementKind.ANNOTATION_TYPE;
}
if (type.isEnum()) {
return ElementKind.ENUM;
}
if (type.isInterface()) {
return ElementKind.INTERFACE;
}
return ElementKind.CLASS;
}
@Override
public NestingKind getNestingKind() {
ITypeBinding type = (ITypeBinding) binding;
if (type.isAnonymous()) {
return NestingKind.ANONYMOUS;
}
if (type.isLocal()) {
return NestingKind.LOCAL;
}
if (type.isMember()) {
return NestingKind.MEMBER;
}
return NestingKind.TOP_LEVEL;
}
@Override
public Name getQualifiedName() {
return BindingConverter.getName(((ITypeBinding) binding).getQualifiedName());
}
@Override
public TypeMirror getSuperclass() {
return BindingConverter.getType(((ITypeBinding) binding).getSuperclass());
}
@Override public TypeMirror asType() {
return BindingConverter.getType((ITypeBinding) binding);
}
@Override
public Element getEnclosingElement() {
ITypeBinding decl = (ITypeBinding) binding;
// We check to make sure that we only return the declaring method as the enclosing element
// if it's inside the declaring class, otherwise the declaring class must be inside
// the method and thus is the true enclosing element.
if (decl.getDeclaringMethod() != null
&& decl.getDeclaringMethod().getDeclaringClass() == decl.getDeclaringClass()) {
return BindingConverter.getElement(decl.getDeclaringMethod());
} else if (decl.isTopLevel()) {
return BindingConverter.getElement(decl.getPackage());
} else if (decl.isLocal()) {
// This comes up when an anonymous class is initializing a member outside of a constructor.
// The enclosing element should be the field it's being assigned to, but the binding doesn't
// give us this information, so we have to fake it.
return GeneratedVariableElement.newField(
"fake_field", this.asType(), BindingConverter.getElement(decl.getDeclaringClass()));
} else {
return BindingConverter.getElement(decl.getDeclaringClass());
}
}
@Override
public List<? extends Element> getEnclosedElements() {
ITypeBinding decl = (ITypeBinding) binding;
List<Element> toReturn = new ArrayList<>();
for (IVariableBinding i : decl.getDeclaredFields()) {
toReturn.add(BindingConverter.getElement(i));
}
for (IMethodBinding i : decl.getDeclaredMethods()) {
toReturn.add(BindingConverter.getElement(i));
}
for (ITypeBinding i : decl.getDeclaredTypes()) {
toReturn.add(BindingConverter.getElement(i));
}
return toReturn;
}
@Override
public List<? extends TypeMirror> getInterfaces() {
List<TypeMirror> interfaces = new ArrayList<>();
for (ITypeBinding iface : ((ITypeBinding) binding).getInterfaces()) {
interfaces.add(BindingConverter.getType(iface));
}
return interfaces;
}
@Override
public List<? extends TypeParameterElement> getTypeParameters() {
List<TypeParameterElement> typeParams = new ArrayList<>();
for (ITypeBinding typeParam : ((ITypeBinding) binding).getTypeParameters()) {
TypeParameterElement tpe = (TypeParameterElement) BindingConverter.getElement(typeParam);
typeParams.add(tpe);
}
return typeParams;
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitType(this, p);
}
}