| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.netbeans.api.java.source; |
| |
| import com.sun.tools.javac.api.JavacTaskImpl; |
| import com.sun.tools.javac.code.ModuleFinder; |
| import com.sun.tools.javac.code.Symbol; |
| import com.sun.tools.javac.code.Symtab; |
| import com.sun.tools.javac.jvm.Target; |
| import com.sun.tools.javac.tree.JCTree; |
| import com.sun.tools.javac.util.Name; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.logging.Logger; |
| import java.util.logging.Level; |
| import javax.lang.model.element.Element; |
| import javax.lang.model.element.ElementKind; |
| import javax.lang.model.element.ExecutableElement; |
| import javax.lang.model.element.ModuleElement; |
| 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.DeclaredType; |
| import javax.lang.model.type.TypeKind; |
| |
| import org.netbeans.api.annotations.common.CheckForNull; |
| import org.netbeans.api.annotations.common.NonNull; |
| import org.netbeans.modules.java.source.ElementHandleAccessor; |
| import org.netbeans.modules.java.source.ElementUtils; |
| import org.netbeans.modules.java.source.usages.ClassFileUtil; |
| import org.openide.util.Parameters; |
| import org.openide.util.WeakSet; |
| |
| /** |
| * Represents a handle for {@link Element} which can be kept and later resolved |
| * by another javac. The javac {@link Element}s are valid only in a single |
| * {@link javax.tools.JavaCompiler.CompilationTask} or a single run of a |
| * {@link CancellableTask}. A client needing to |
| * keep a reference to an {@link Element} and use it in another {@link CancellableTask} |
| * must serialize it into an {@link ElementHandle}. |
| * Currently not all {@link Element}s can be serialized. See {@link #create} for details. |
| * <div class="nonnormative"> |
| * <p> |
| * Typical usage of {@link ElementHandle} is as follows: |
| * </p> |
| * <pre> |
| * final ElementHandle[] elementHandle = new ElementHandle[1]; |
| * javaSource.runUserActionTask(new Task<CompilationController>() { |
| * public void run(CompilationController compilationController) { |
| * compilationController.toPhase(Phase.RESOLVED); |
| * CompilationUnitTree cu = compilationController.getTree(); |
| * List<? extends Tree> types = getTypeDecls(cu); |
| * Tree tree = getInterestingElementTree(types); |
| * Element element = compilationController.getElement(tree); |
| * elementHandle[0] = ElementHandle.create(element); |
| * } |
| * }, true); |
| * |
| * otherJavaSource.runUserActionTask(new Task<CompilationController>() { |
| * public void run(CompilationController compilationController) { |
| * compilationController.toPhase(Phase.RESOLVED); |
| * Element element = elementHandle[0].resolve(compilationController); |
| * // .... |
| * } |
| * }, true); |
| * </pre> |
| * </div> |
| * @author Tomas Zezula |
| */ |
| public final class ElementHandle<T extends Element> { |
| private static final Logger log = Logger.getLogger(ElementHandle.class.getName()); |
| static { |
| ElementHandleAccessor.setInstance(new ElementHandleAccessorImpl ()); |
| } |
| |
| private final ElementKind kind; |
| private final String[] signatures; |
| |
| |
| private ElementHandle(final ElementKind kind, String... signatures) { |
| assert kind != null; |
| assert signatures != null; |
| this.kind = kind; |
| this.signatures = signatures; |
| } |
| |
| |
| /** |
| * Resolves an {@link Element} from the {@link ElementHandle}. |
| * @param compilationInfo representing the {@link javax.tools.JavaCompiler.CompilationTask} |
| * in which the {@link Element} should be resolved. |
| * @return resolved subclass of {@link Element} or null if the elment does not exist on |
| * the classpath/sourcepath of {@link javax.tools.JavaCompiler.CompilationTask}. |
| */ |
| @SuppressWarnings ("unchecked") // NOI18N |
| public @CheckForNull T resolve (@NonNull final CompilationInfo compilationInfo) { |
| Parameters.notNull("compilationInfo", compilationInfo); // NOI18N |
| ModuleElement module; |
| |
| if (compilationInfo.getFileObject() != null) { |
| JCTree.JCCompilationUnit cut = (JCTree.JCCompilationUnit)compilationInfo.getCompilationUnit(); |
| if (cut != null) { |
| module = cut.modle; |
| } else if (compilationInfo.getTopLevelElements().iterator().hasNext()) { |
| module = ((Symbol) compilationInfo.getTopLevelElements().iterator().next()).packge().modle; |
| } else { |
| module = null; |
| } |
| } else { |
| module = null; |
| } |
| T result = resolveImpl (module, compilationInfo.impl.getJavacTask()); |
| if (result == null) { |
| if (log.isLoggable(Level.INFO)) |
| log.log(Level.INFO, "Cannot resolve: {0}", toString()); //NOI18N |
| } else { |
| if (log.isLoggable(Level.FINE)) |
| log.log(Level.FINE, "Resolved element = {0}", result); |
| } |
| return result; |
| } |
| |
| |
| private T resolveImpl (final ModuleElement module, final JavacTaskImpl jt) { |
| if (log.isLoggable(Level.FINE)) |
| log.log(Level.FINE, "Resolving element kind: {0}", this.kind); // NOI18N |
| ElementKind simplifiedKind = this.kind; |
| if (simplifiedKind.name().equals("RECORD")) { |
| simplifiedKind = ElementKind.CLASS; //TODO: test |
| } |
| if (simplifiedKind.name().equals("RECORD_COMPONENT")) { |
| simplifiedKind = ElementKind.FIELD; //TODO: test |
| } |
| switch (simplifiedKind) { |
| case PACKAGE: |
| assert signatures.length == 1; |
| return (T) jt.getElements().getPackageElement(signatures[0]); |
| case CLASS: |
| case INTERFACE: |
| case ENUM: |
| case ANNOTATION_TYPE: { |
| assert signatures.length == 1; |
| final Element type = getTypeElementByBinaryName (module, signatures[0], jt); |
| if (type instanceof TypeElement) { |
| return (T) type; |
| } else { |
| log.log(Level.INFO, "Resolved type is null for kind = {0}", this.kind); // NOI18N |
| } |
| break; |
| } |
| case OTHER: |
| assert signatures.length == 1; |
| return (T) getTypeElementByBinaryName (module, signatures[0], jt); |
| case METHOD: |
| case CONSTRUCTOR: |
| { |
| assert signatures.length == 3; |
| final Element type = getTypeElementByBinaryName (module, signatures[0], jt); |
| if (type instanceof TypeElement) { |
| final List<? extends Element> members = type.getEnclosedElements(); |
| for (Element member : members) { |
| if (this.kind == member.getKind()) { |
| String[] desc = ClassFileUtil.createExecutableDescriptor((ExecutableElement)member); |
| assert desc.length == 3; |
| if (this.signatures[1].equals(desc[1]) && this.signatures[2].equals(desc[2])) { |
| return (T) member; |
| } |
| } |
| } |
| } else if (type != null) { |
| return (T) new Symbol.MethodSymbol(0, (Name) jt.getElements().getName(this.signatures[1]), Symtab.instance(jt.getContext()).unknownType, (Symbol)type); |
| } else |
| log.log(Level.INFO, "Resolved type is null for kind = {0}", this.kind); // NOI18N |
| break; |
| } |
| case INSTANCE_INIT: |
| case STATIC_INIT: |
| { |
| assert signatures.length == 2; |
| final Element type = getTypeElementByBinaryName (module, signatures[0], jt); |
| if (type instanceof TypeElement) { |
| final List<? extends Element> members = type.getEnclosedElements(); |
| for (Element member : members) { |
| if (this.kind == member.getKind()) { |
| String[] desc = ClassFileUtil.createExecutableDescriptor((ExecutableElement)member); |
| assert desc.length == 2; |
| if (this.signatures[1].equals(desc[1])) { |
| return (T) member; |
| } |
| } |
| } |
| } else |
| log.log(Level.INFO, "Resolved type is null for kind = {0}", this.kind); // NOI18N |
| break; |
| } |
| case FIELD: |
| case ENUM_CONSTANT: |
| { |
| assert signatures.length == 3; |
| final Element type = getTypeElementByBinaryName (module, signatures[0], jt); |
| if (type instanceof TypeElement) { |
| final List<? extends Element> members = type.getEnclosedElements(); |
| for (Element member : members) { |
| if (this.kind == member.getKind()) { |
| String[] desc = ClassFileUtil.createFieldDescriptor((VariableElement)member); |
| assert desc.length == 3; |
| if (this.signatures[1].equals(desc[1]) && this.signatures[2].equals(desc[2])) { |
| return (T) member; |
| } |
| } |
| } |
| } else if (type != null) { |
| return (T) new Symbol.VarSymbol(0, (Name) jt.getElements().getName(this.signatures[1]), Symtab.instance(jt.getContext()).unknownType, (Symbol)type); |
| } else |
| log.log(Level.INFO, "Resolved type is null for kind = {0}", this.kind); // NOI18N |
| break; |
| } |
| case PARAMETER: |
| { |
| assert signatures.length == 3; |
| final Element type = getTypeElementByBinaryName (module, signatures[0], jt); |
| if (type instanceof TypeElement) { |
| final List<? extends Element> members = type.getEnclosedElements(); |
| for (Element member : members) { |
| if (member.getKind() == ElementKind.METHOD || member.getKind() == ElementKind.CONSTRUCTOR) { |
| String[] desc = ClassFileUtil.createExecutableDescriptor((ExecutableElement)member); |
| assert desc.length == 3; |
| if (this.signatures[1].equals(desc[1]) && this.signatures[2].equals(desc[2])) { |
| assert member instanceof ExecutableElement; |
| List<? extends VariableElement> ves =((ExecutableElement)member).getParameters(); |
| for (VariableElement ve : ves) { |
| if (ve.getSimpleName().contentEquals(signatures[3])) { |
| return (T) ve; |
| } |
| } |
| } |
| } |
| } |
| } else |
| log.log(Level.INFO, "Resolved type is null for kind = {0} signatures.length = {1}", new Object[] {this.kind, signatures.length}); // NOI18N |
| break; |
| } |
| case TYPE_PARAMETER: |
| { |
| if (signatures.length == 2) { |
| Element type = getTypeElementByBinaryName (module, signatures[0], jt); |
| if (type instanceof TypeElement) { |
| List<? extends TypeParameterElement> tpes = ((TypeElement)type).getTypeParameters(); |
| for (TypeParameterElement tpe : tpes) { |
| if (tpe.getSimpleName().contentEquals(signatures[1])) { |
| return (T)tpe; |
| } |
| } |
| } else |
| log.log(Level.INFO, "Resolved type is null for kind = {0} signatures.length = {1}", new Object[] {this.kind, signatures.length}); // NOI18N |
| } |
| else if (signatures.length == 4) { |
| final Element type = getTypeElementByBinaryName (module, signatures[0], jt); |
| if (type instanceof TypeElement) { |
| final List<? extends Element> members = type.getEnclosedElements(); |
| for (Element member : members) { |
| if (member.getKind() == ElementKind.METHOD || member.getKind() == ElementKind.CONSTRUCTOR) { |
| String[] desc = ClassFileUtil.createExecutableDescriptor((ExecutableElement)member); |
| assert desc.length == 3; |
| if (this.signatures[1].equals(desc[1]) && this.signatures[2].equals(desc[2])) { |
| assert member instanceof ExecutableElement; |
| List<? extends TypeParameterElement> tpes =((ExecutableElement)member).getTypeParameters(); |
| for (TypeParameterElement tpe : tpes) { |
| if (tpe.getSimpleName().contentEquals(signatures[3])) { |
| return (T) tpe; |
| } |
| } |
| } |
| } |
| } |
| } else |
| log.log(Level.INFO, "Resolved type is null for kind = {0} signatures.length = {1}", new Object[] {this.kind, signatures.length}); // NOI18N |
| } |
| else { |
| throw new IllegalStateException (); |
| } |
| break; |
| } |
| case MODULE: |
| assert signatures.length == 1; |
| final ModuleFinder cml = ModuleFinder.instance(jt.getContext()); |
| final Element me = cml.findModule((Name)jt.getElements().getName(this.signatures[0])); |
| if (me != null) { |
| return (T) me; |
| } else { |
| log.log(Level.INFO, "Cannot resolve module: {0}", this.signatures[0]); // NOI18N |
| } |
| break; |
| default: |
| throw new IllegalStateException (); |
| } |
| if (log.isLoggable(Level.FINE)) |
| log.log(Level.FINE, "All resolvings failed. Returning null."); // NOI18N |
| return null; |
| } |
| |
| |
| /** |
| * Tests if the handle has the same signature as the parameter. |
| * The handles with the same signatures are resolved into the same |
| * element in the same {@link javax.tools.JavaCompiler} task, but may be resolved into |
| * the different {@link Element}s in the different {@link javax.tools.JavaCompiler} tasks. |
| * @param handle to be checked |
| * @return true if the handles resolve into the same {@link Element}s |
| * in the same {@link javax.tools.JavaCompiler} task. |
| */ |
| public boolean signatureEquals (@NonNull final ElementHandle<? extends Element> handle) { |
| if (!isSameKind (this.kind, handle.kind) || this.signatures.length != handle.signatures.length) { |
| return false; |
| } |
| for (int i=0; i<signatures.length; i++) { |
| if (!signatures[i].equals(handle.signatures[i])) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| |
| private static boolean isSameKind (ElementKind k1, ElementKind k2) { |
| if ((k1 == k2) || |
| (k1 == ElementKind.OTHER && (k2.isClass() || k2.isInterface())) || |
| (k2 == ElementKind.OTHER && (k1.isClass() || k1.isInterface()))) { |
| return true; |
| } |
| return false; |
| } |
| |
| |
| /** |
| * Returns a binary name of the {@link TypeElement} represented by this |
| * {@link ElementHandle}. When the {@link ElementHandle} doesn't represent |
| * a {@link TypeElement} it throws a {@link IllegalStateException} |
| * @return the qualified name |
| * @throws IllegalStateException when this {@link ElementHandle} |
| * isn't created for the {@link TypeElement}. |
| */ |
| public @NonNull String getBinaryName () throws IllegalStateException { |
| if ((this.kind.isClass() && !isArray(signatures[0])) || |
| this.kind.isInterface() || |
| this.kind == ElementKind.MODULE || |
| this.kind == ElementKind.OTHER) { |
| return this.signatures[0]; |
| } |
| else { |
| throw new IllegalStateException (); |
| } |
| } |
| |
| |
| /** |
| * Returns a qualified name of the {@link TypeElement} represented by this |
| * {@link ElementHandle}. When the {@link ElementHandle} doesn't represent |
| * a {@link TypeElement} it throws a {@link IllegalStateException} |
| * @return the qualified name |
| * @throws IllegalStateException when this {@link ElementHandle} |
| * isn't creatred for the {@link TypeElement}. |
| */ |
| public @NonNull String getQualifiedName () throws IllegalStateException { |
| if ((this.kind.isClass() && !isArray(signatures[0])) || |
| this.kind.isInterface() || |
| this.kind == ElementKind.MODULE || |
| this.kind == ElementKind.OTHER) { |
| return this.signatures[0].replace (Target.DEFAULT.syntheticNameChar(),'.'); //NOI18N |
| } |
| else { |
| throw new IllegalStateException (); |
| } |
| } |
| |
| |
| /** |
| * Tests if the handle has this same signature as the parameter. |
| * The handles has the same signatures if it is resolved into the same |
| * element in the same {@link javax.tools.JavaCompiler} task, but may be resolved into |
| * the different {@link Element} in the different {@link javax.tools.JavaCompiler} task. |
| * @param element to be checked |
| * @return true if this handle resolves into the same {@link Element} |
| * in the same {@link javax.tools.JavaCompiler} task. |
| */ |
| public boolean signatureEquals (@NonNull final T element) { |
| final ElementKind ek = element.getKind(); |
| final ElementKind thisKind = getKind(); |
| if ((ek != thisKind) && !(thisKind == ElementKind.OTHER && (ek.isClass() || ek.isInterface()))) { |
| return false; |
| } |
| final ElementHandle<T> handle = create (element); |
| return signatureEquals (handle); |
| } |
| |
| /** |
| * Returns the {@link ElementKind} of this element handle, |
| * it is the kind of the {@link Element} from which the handle |
| * was created. |
| * @return {@link ElementKind} |
| * |
| */ |
| public @NonNull ElementKind getKind () { |
| return this.kind; |
| } |
| |
| private static final WeakSet<ElementHandle<?>> NORMALIZATION_CACHE = new WeakSet<ElementHandle<?>>(); |
| |
| /** |
| * Factory method for creating {@link ElementHandle}. |
| * @param element for which the {@link ElementHandle} should be created. Permitted |
| * {@link ElementKind}s |
| * are: {@link ElementKind#PACKAGE}, {@link ElementKind#CLASS}, |
| * {@link ElementKind#INTERFACE}, {@link ElementKind#ENUM}, {@link ElementKind#ANNOTATION_TYPE}, {@link ElementKind#METHOD}, |
| * {@link ElementKind#CONSTRUCTOR}, {@link ElementKind#INSTANCE_INIT}, {@link ElementKind#STATIC_INIT}, |
| * {@link ElementKind#FIELD}, and {@link ElementKind#ENUM_CONSTANT}. |
| * @return a new {@link ElementHandle} |
| * @throws IllegalArgumentException if the element is of an unsupported {@link ElementKind} |
| */ |
| public static @NonNull <T extends Element> ElementHandle<T> create (@NonNull final T element) throws IllegalArgumentException { |
| ElementHandle<T> eh = createImpl(element); |
| |
| return (ElementHandle<T>) NORMALIZATION_CACHE.putIfAbsent(eh); |
| } |
| |
| /** |
| * Creates an {@link ElementHandle} representing a {@link PackageElement}. |
| * @param packageName the name of the package |
| * @return the created {@link ElementHandle} |
| * @since 0.98 |
| */ |
| @NonNull |
| public static ElementHandle<PackageElement> createPackageElementHandle ( |
| @NonNull final String packageName) { |
| Parameters.notNull("packageName", packageName); //NOI18N |
| return new ElementHandle<PackageElement>(ElementKind.PACKAGE, packageName); |
| } |
| |
| /** |
| * Creates an {@link ElementHandle} representing a {@link TypeElement}. |
| * @param kind the {@link ElementKind} of the {@link TypeElement}, |
| * allowed values are {@link ElementKind#CLASS}, {@link ElementKind#INTERFACE}, |
| * {@link ElementKind#ENUM} and {@link ElementKind#ANNOTATION_TYPE}. |
| * @param binaryName the class binary name as specified by JLS §13.1 |
| * @return the created {@link ElementHandle} |
| * @throws IllegalArgumentException if kind is neither class nor interface |
| * @since 0.98 |
| */ |
| @NonNull |
| public static ElementHandle<TypeElement> createTypeElementHandle( |
| @NonNull final ElementKind kind, |
| @NonNull final String binaryName) throws IllegalArgumentException { |
| Parameters.notNull("kind", kind); //NOI18N |
| Parameters.notNull("binaryName", binaryName); //NOI18N |
| if (!kind.isClass() && !kind.isInterface()) { |
| throw new IllegalArgumentException(kind.toString()); |
| } |
| return new ElementHandle<TypeElement>(kind, binaryName); |
| } |
| |
| /** |
| * Creates an {@link ElementHandle} representing a {@link ModuleElement}. |
| * @param moduleName the name of the module |
| * @return the created {@link ElementHandle} |
| * @since 2.26 |
| */ |
| @NonNull |
| public static ElementHandle<ModuleElement> createModuleElementHandle( |
| @NonNull final String moduleName) { |
| Parameters.notNull("moduleName", moduleName); //NOI18N |
| return new ElementHandle<>(ElementKind.MODULE, moduleName); |
| } |
| |
| private static @NonNull <T extends Element> ElementHandle<T> createImpl (@NonNull final T element) throws IllegalArgumentException { |
| Parameters.notNull("element", element); |
| ElementKind kind = element.getKind(); |
| ElementKind simplifiedKind = kind; |
| String[] signatures; |
| switch (simplifiedKind) { |
| case PACKAGE: |
| assert element instanceof PackageElement; |
| signatures = new String[]{((PackageElement)element).getQualifiedName().toString()}; |
| break; |
| case CLASS: |
| case INTERFACE: |
| case ENUM: |
| case ANNOTATION_TYPE: |
| case RECORD: |
| assert element instanceof TypeElement; |
| signatures = new String[] {ClassFileUtil.encodeClassNameOrArray((TypeElement)element)}; |
| break; |
| case METHOD: |
| case CONSTRUCTOR: |
| case INSTANCE_INIT: |
| case STATIC_INIT: |
| assert element instanceof ExecutableElement; |
| signatures = ClassFileUtil.createExecutableDescriptor((ExecutableElement)element); |
| break; |
| case FIELD: |
| case ENUM_CONSTANT: |
| case RECORD_COMPONENT: |
| assert element instanceof VariableElement; |
| signatures = ClassFileUtil.createFieldDescriptor((VariableElement)element); |
| break; |
| case PARAMETER: |
| assert element instanceof VariableElement; |
| Element ee = element.getEnclosingElement(); |
| ElementKind eek = ee.getKind(); |
| if (eek == ElementKind.METHOD || eek == ElementKind.CONSTRUCTOR) { |
| assert ee instanceof ExecutableElement; |
| String[] _sigs = ClassFileUtil.createExecutableDescriptor((ExecutableElement)ee); |
| signatures = new String[_sigs.length + 1]; |
| System.arraycopy(_sigs, 0, signatures, 0, _sigs.length); |
| signatures[_sigs.length] = element.getSimpleName().toString(); |
| } |
| else { |
| throw new IllegalArgumentException(eek.toString()); |
| } |
| break; |
| case TYPE_PARAMETER: |
| assert element instanceof TypeParameterElement; |
| TypeParameterElement tpe = (TypeParameterElement) element; |
| Element ge = tpe.getGenericElement(); |
| ElementKind gek = ge.getKind(); |
| if (gek.isClass() || gek.isInterface()) { |
| assert ge instanceof TypeElement; |
| signatures = new String[2]; |
| signatures[0] = ClassFileUtil.encodeClassNameOrArray((TypeElement)ge); |
| signatures[1] = tpe.getSimpleName().toString(); |
| } |
| else if (gek == ElementKind.METHOD || gek == ElementKind.CONSTRUCTOR) { |
| assert ge instanceof ExecutableElement; |
| String[] _sigs = ClassFileUtil.createExecutableDescriptor((ExecutableElement)ge); |
| signatures = new String[_sigs.length + 1]; |
| System.arraycopy(_sigs, 0, signatures, 0, _sigs.length); |
| signatures[_sigs.length] = tpe.getSimpleName().toString(); |
| } |
| else { |
| throw new IllegalArgumentException(gek.toString()); |
| } |
| break; |
| case MODULE: |
| signatures = new String[]{((ModuleElement)element).getQualifiedName().toString()}; |
| break; |
| default: |
| throw new IllegalArgumentException(kind.toString()); |
| } |
| return new ElementHandle<T> (kind, signatures); |
| } |
| |
| /** |
| * Gets {@link ElementHandle} from {@link TypeMirrorHandle} representing {@link DeclaredType}. |
| * @param typeMirrorHandle from which the {@link ElementHandle} should be retrieved. Permitted |
| * {@link TypeKind} is {@link TypeKind#DECLARED}. |
| * @return an {@link ElementHandle} |
| * @since 0.29.0 |
| */ |
| public static @NonNull ElementHandle<? extends TypeElement> from (@NonNull final TypeMirrorHandle<? extends DeclaredType> typeMirrorHandle) { |
| Parameters.notNull("typeMirrorHandle", typeMirrorHandle); |
| if (typeMirrorHandle.getKind() != TypeKind.DECLARED) { |
| throw new IllegalStateException("Incorrect kind: " + typeMirrorHandle.getKind()); |
| } |
| return (ElementHandle<TypeElement>)typeMirrorHandle.getElementHandle(); |
| } |
| |
| public @Override String toString () { |
| final StringBuilder result = new StringBuilder (); |
| result.append (this.getClass().getSimpleName()); |
| result.append ('['); // NOI18N |
| result.append ("kind=").append (this.kind.toString()); // NOI18N |
| result.append ("; sigs="); // NOI18N |
| for (String sig : this.signatures) { |
| result.append (sig); |
| result.append (' '); // NOI18N |
| } |
| result.append (']'); // NOI18N |
| return result.toString(); |
| } |
| |
| |
| /**{@inheritDoc}*/ |
| @Override |
| public int hashCode () { |
| int hashCode = 0; |
| |
| for (String sig : signatures) { |
| hashCode = hashCode ^ (sig != null ? sig.hashCode() : 0); |
| } |
| |
| return hashCode; |
| } |
| |
| /**{@inheritDoc}*/ |
| @Override |
| public boolean equals (Object other) { |
| if (other instanceof ElementHandle) { |
| return signatureEquals((ElementHandle)other); |
| } |
| return false; |
| } |
| |
| |
| /** |
| * Returns the element signature. |
| * Package private, used by ClassIndex. |
| */ |
| String[] getSignature () { |
| return this.signatures; |
| } |
| |
| |
| private static class ElementHandleAccessorImpl extends ElementHandleAccessor { |
| |
| @Override |
| public ElementHandle create(ElementKind kind, String... descriptors) { |
| assert kind != null; |
| assert descriptors != null; |
| switch (kind) { |
| case PACKAGE: |
| if (descriptors.length != 1) { |
| throw new IllegalArgumentException (); |
| } |
| return new ElementHandle<PackageElement> (kind, descriptors); |
| case MODULE: |
| case CLASS: |
| case INTERFACE: |
| case ENUM: |
| case ANNOTATION_TYPE: |
| case RECORD: |
| case OTHER: |
| if (descriptors.length != 1) { |
| throw new IllegalArgumentException (); |
| } |
| return new ElementHandle<TypeElement> (kind, descriptors); |
| case METHOD: |
| case CONSTRUCTOR: |
| if (descriptors.length != 3) { |
| throw new IllegalArgumentException (); |
| } |
| return new ElementHandle<ExecutableElement> (kind, descriptors); |
| case INSTANCE_INIT: |
| case STATIC_INIT: |
| if (descriptors.length != 2) { |
| throw new IllegalArgumentException (); |
| } |
| return new ElementHandle<ExecutableElement> (kind, descriptors); |
| case FIELD: |
| case ENUM_CONSTANT: |
| if (descriptors.length != 3) { |
| throw new IllegalArgumentException (); |
| } |
| return new ElementHandle<VariableElement> (kind, descriptors); |
| default: |
| throw new IllegalArgumentException(); |
| |
| } |
| } |
| |
| @Override |
| public <T extends Element> T resolve(ElementHandle<T> handle, JavacTaskImpl jti) { |
| return handle.resolveImpl (null, jti); |
| } |
| |
| @Override |
| @NonNull |
| public String[] getJVMSignature(@NonNull final ElementHandle<?> handle) { |
| return Arrays.copyOf(handle.signatures, handle.signatures.length); |
| } |
| |
| } |
| |
| private static Element getTypeElementByBinaryName (final ModuleElement module, final String signature, final JavacTaskImpl jt) { |
| if (log.isLoggable(Level.FINE)) |
| log.log(Level.FINE, "Calling getTypeElementByBinaryName: signature = {0}", signature); |
| if (isNone(signature)) { |
| return Symtab.instance(jt.getContext()).noSymbol; |
| } |
| else if (isArray(signature)) { |
| return Symtab.instance(jt.getContext()).arrayClass; |
| } |
| else { |
| return (TypeElement) (module != null |
| ? ElementUtils.getTypeElementByBinaryName(jt, module, signature) |
| : ElementUtils.getTypeElementByBinaryName(jt, signature)); |
| } |
| } |
| |
| private static boolean isNone (String signature) { |
| return signature.length() == 0; |
| } |
| |
| private static boolean isArray (String signature) { |
| return signature.length() == 1 && signature.charAt(0) == '['; |
| } |
| } |