/* * 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.AbstractTypeMirror; import com.google.devtools.j2objc.types.GeneratedElement; import com.google.devtools.j2objc.types.GeneratedExecutableElement; import com.google.devtools.j2objc.types.GeneratedPackageElement; import com.google.devtools.j2objc.types.GeneratedTypeElement; import com.google.devtools.j2objc.types.GeneratedVariableElement; import com.google.devtools.j2objc.util.BindingUtil; import java.util.HashMap; import java.util.Map; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; import org.eclipse.jdt.core.dom.IAnnotationBinding; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.IPackageBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.PackageDeclaration; /** * Factory for wrapping JDT IBindings, and generating javax.lang.model.element and * javax.lang.model.type wrappers of them. */ public final class BindingConverter { private static Map<IBinding, JdtElement> elementCache = new HashMap<>(); private static Map<GeneratedElement, IBinding> generatedBindingCache = new HashMap<>(); private static Map<String, Name> nameCache = new HashMap<>(); private static Map<IBinding, JdtTypeMirror> typeCache = new HashMap<>(); public static final JdtNoType NO_TYPE = new JdtNoType(null); public static final JdtTypeMirror NULL_TYPE = new JdtNullType(); public static Name getName(String s) { if (s == null) { throw new IllegalArgumentException("null name"); } Name result = nameCache.get(s); if (result == null) { result = new StringName(s); nameCache.put(s, result); } return result; } public static TypeMirror getType(ITypeBinding binding) { if (binding == null) { return null; } JdtTypeMirror type = typeCache.get(binding); if (type != null) { return type; } if (binding.isArray()) { type = new JdtArrayType(binding); } else if (BindingUtil.isIntersectionType(binding)) { type = JdtIntersectionType.fromJdtIntersection(binding); } else if (binding.isPrimitive()) { if (binding.getBinaryName().charAt(0) == 'V') { type = new JdtNoType(binding); } else { type = new JdtPrimitiveType(binding); } } else if (binding.isTypeVariable()) { type = JdtTypeVariable.fromTypeVariable(binding); } else if (binding.isWildcardType()) { type = new JdtWildcardType(binding); } else if (binding.isCapture()) { type = JdtTypeVariable.fromCapture(binding); } else if (binding.isNullType()) { return NULL_TYPE; } else { type = new JdtDeclaredType(binding); } typeCache.put(binding, type); return type; } public static JdtExecutableType getType(IMethodBinding binding) { JdtTypeMirror type = typeCache.get(binding); if (type != null) { return (JdtExecutableType) type; } JdtExecutableType executableType = new JdtExecutableType(binding); typeCache.put(binding, executableType); return executableType; } public static VariableElement getVariableElement(IVariableBinding binding) { return (VariableElement) getElement(binding); } public static ExecutableElement getExecutableElement(IMethodBinding binding) { return (ExecutableElement) getElement(binding); } public static TypeElement getTypeElement(ITypeBinding binding) { return (TypeElement) getElement(binding); } public static Element getElement(IBinding binding) { if (binding == null) { return null; } JdtElement element = elementCache.get(binding); if (element != null) { return element; } if (binding instanceof GeneratedMethodBinding) { return ((GeneratedMethodBinding) binding).asElement(); } else if (binding instanceof GeneratedVariableBinding) { return ((GeneratedVariableBinding) binding).asElement(); } else if (binding instanceof IMethodBinding) { element = new JdtExecutableElement((IMethodBinding) binding); } else if (binding instanceof IPackageBinding) { element = new JdtPackageElement((IPackageBinding) binding); } else if (binding instanceof ITypeBinding) { ITypeBinding typeBinding = (ITypeBinding) binding; element = typeBinding.isTypeVariable() || typeBinding.isCapture() ? new JdtTypeParameterElement(typeBinding) : new JdtTypeElement(typeBinding); } else if (binding instanceof IVariableBinding) { element = JdtVariableElement.create((IVariableBinding) binding); } else { throw new AssertionError("unknown element binding: " + binding.getClass().getSimpleName()); } elementCache.put(binding, element); return element; } /** * JDT package bindings do not include annotations, so add them from the * package's AST node. */ public static JdtPackageElement getPackageElement(PackageDeclaration pkg) { IPackageBinding binding = pkg.resolveBinding(); JdtPackageElement pkgElement = (JdtPackageElement) getElement(binding); if (pkgElement.getAnnotationMirrors().isEmpty() && pkg.annotations().size() > 0) { for (Object modifier : pkg.annotations()) { IAnnotationBinding annotation = ((org.eclipse.jdt.core.dom.Annotation) modifier).resolveAnnotationBinding(); pkgElement.addAnnotation(new JdtAnnotationMirror(annotation)); } } return pkgElement; } public static JdtPackageElement getPackageElement(IPackageBinding binding) { return (JdtPackageElement) getElement(binding); } public static IBinding unwrapElement(Element element) { if (element instanceof GeneratedElement) { return unwrapGeneratedElement((GeneratedElement) element); } return element != null ? ((JdtElement) element).binding : null; } private static IBinding unwrapGeneratedElement(GeneratedElement element) { IBinding binding = generatedBindingCache.get(element); if (binding != null) { return binding; } if (element instanceof GeneratedVariableElement) { binding = new GeneratedVariableBinding((GeneratedVariableElement) element); generatedBindingCache.put(element, binding); return binding; } if (element instanceof GeneratedExecutableElement) { binding = new GeneratedMethodBinding((GeneratedExecutableElement) element); generatedBindingCache.put(element, binding); return binding; } if (element instanceof GeneratedTypeElement) { throw new AssertionError("not supported"); } if (element instanceof GeneratedPackageElement) { binding = new GeneratedPackageBinding(((GeneratedPackageElement) element).getName()); generatedBindingCache.put(element, binding); return binding; } throw new AssertionError("unknown generated element kind"); } public static ITypeBinding unwrapTypeElement(TypeElement t) { return (ITypeBinding) unwrapElement(t); } public static IVariableBinding unwrapVariableElement(VariableElement v) { return (IVariableBinding) unwrapElement(v); } public static IMethodBinding unwrapExecutableElement(ExecutableElement e) { return (IMethodBinding) unwrapElement(e); } public static IBinding unwrapTypeMirrorIntoBinding(TypeMirror t) { if (t == null) { return null; } else if (t instanceof AbstractTypeMirror) { throw new AssertionError("not supported"); } else if (t instanceof GeneratedExecutableElement.Mirror) { return new GeneratedMethodBinding( ((GeneratedExecutableElement.Mirror) t).asExecutableElement()); } return ((JdtTypeMirror) t).binding; } public static ITypeBinding unwrapTypeMirrorIntoTypeBinding(TypeMirror t) { IBinding b = unwrapTypeMirrorIntoBinding(t); return b instanceof ITypeBinding ? (ITypeBinding) b : null; } public static IAnnotationBinding unwrapAnnotationMirror(AnnotationMirror a) { return ((JdtAnnotationMirror) a).binding; } public static void reset() { generatedBindingCache.clear(); elementCache.clear(); nameCache.clear(); typeCache.clear(); } }