blob: 0288554022ac90d1519068f8798ef19d487d71b8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2016 Google, Inc and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Stefan Xenos (Google) - Initial implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core.nd.java;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.NdNode;
import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
/**
* Corresponds roughly to a JavaTypeSignature, as described in section 4.7.9.1 of the Java VM spec version 4, with the
* addition of annotations and backpointers to locations where the type is used.
* <p>
* Holds back-pointers to all the entities that refer to the name, along with pointers to all classes that have this
* name. Note that this isn't the class declaration itself. The same index can hold multiple jar files, some of which
* may contain classes with the same name. All classes that use this fully-qualified name point to the same
* {@link NdTypeSignature}.
* <p>
* Other entities should refer to a type via its TypeId if there is any possiblity that the type may change based on the
* classpath. It should refer to the type directly if there is no possibility for a type lookup. For example, nested
* classes refer to their enclosing class directly since they live in the same file and there is no possibility for the
* enclosing class to change based on the classpath. Classes refer to their base class via its TypeId since the parent
* class might live in a different jar and need to be resolved on the classpath.
*/
public abstract class NdTypeSignature extends NdNode {
public static final FieldOneToMany<NdType> SUBCLASSES;
public static final FieldOneToMany<NdAnnotation> ANNOTATIONS_OF_THIS_TYPE;
public static final FieldOneToMany<NdTypeInterface> IMPLEMENTATIONS;
public static final FieldOneToMany<NdVariable> VARIABLES_OF_TYPE;
public static final FieldOneToMany<NdConstantClass> USED_AS_CONSTANT;
public static final FieldOneToMany<NdConstantEnum> USED_AS_ENUM_CONSTANT;
public static final FieldOneToMany<NdTypeArgument> USED_AS_TYPE_ARGUMENT;
public static final FieldOneToMany<NdTypeBound> USED_AS_TYPE_BOUND;
public static final FieldOneToMany<NdMethodParameter> USED_AS_METHOD_ARGUMENT;
public static final FieldOneToMany<NdMethodException> USED_AS_EXCEPTION;
public static final FieldOneToMany<NdMethod> USED_AS_RETURN_TYPE;
@SuppressWarnings("hiding")
public static StructDef<NdTypeSignature> type;
static {
type = StructDef.createAbstract(NdTypeSignature.class, NdNode.type);
SUBCLASSES = FieldOneToMany.create(type, NdType.SUPERCLASS);
ANNOTATIONS_OF_THIS_TYPE = FieldOneToMany.create(type, NdAnnotation.ANNOTATION_TYPE);
IMPLEMENTATIONS = FieldOneToMany.create(type, NdTypeInterface.IMPLEMENTS);
VARIABLES_OF_TYPE = FieldOneToMany.create(type, NdVariable.TYPE);
USED_AS_CONSTANT = FieldOneToMany.create(type, NdConstantClass.VALUE);
USED_AS_ENUM_CONSTANT = FieldOneToMany.create(type, NdConstantEnum.ENUM_TYPE);
USED_AS_TYPE_ARGUMENT = FieldOneToMany.create(type, NdTypeArgument.TYPE_SIGNATURE);
USED_AS_TYPE_BOUND = FieldOneToMany.create(type, NdTypeBound.TYPE);
USED_AS_METHOD_ARGUMENT = FieldOneToMany.create(type, NdMethodParameter.ARGUMENT_TYPE);
USED_AS_EXCEPTION = FieldOneToMany.create(type, NdMethodException.EXCEPTION_TYPE);
USED_AS_RETURN_TYPE = FieldOneToMany.create(type, NdMethod.RETURN_TYPE);
type.useStandardRefCounting().done();
}
public NdTypeSignature(Nd nd, long address) {
super(nd, address);
}
public NdTypeSignature(Nd nd) {
super(nd);
}
public List<NdType> getSubclasses() {
return SUBCLASSES.asList(getNd(), this.address);
}
public List<NdTypeInterface> getImplementations() {
return IMPLEMENTATIONS.asList(getNd(), this.address);
}
/**
* Returns all subclasses (for classes) and implementations (for interfaces) of this type
*/
public List<NdType> getSubTypes() {
List<NdType> result = new ArrayList<>();
result.addAll(getSubclasses());
for (NdTypeInterface next : getImplementations()) {
result.add(next.getImplementation());
}
return result;
}
/**
* Returns the raw version of this type, if one exists. That is, the version of this type
* without any generic arguments or annotations, which the java runtime sees. Returns null
* of this signature doesn't have a raw type, for example if it is a type variable.
*/
public abstract NdTypeId getRawType();
public final void getSignature(CharArrayBuffer result) {
getSignature(result, true);
}
public abstract void getSignature(CharArrayBuffer result, boolean includeTrailingSemicolon);
/**
* Returns true iff this is an array type signature (ie: that getArrayDimensionType() will return a non-null
* answer). Note that this only returns true for the type signature that holds the reference to the array dimension
* type. The raw type for that signature will return false, even though it has a field descriptor starting with '['.
* <p>
* In other words:
*
* <pre>
* NdVariable someVariable = getSomeVariableWithAnArrayType()
* System.out.println(someVariable.getType().isArrayType()); // true
* System.out.println(someVariable.getType().getRawType().isArrayType()); // false
* </pre>
*/
public abstract boolean isArrayType();
public abstract boolean isTypeVariable();
/**
* Returns the chain of declaring generic types. The first element in the chain is a top-level type and the
* receiver is the last element in the chain.
*/
public abstract List<NdTypeSignature> getDeclaringTypeChain();
/**
* If the receiver is an array type, it returns the signature of the array's next dimension. Returns null if
* this is not an array type.
*/
public abstract NdTypeSignature getArrayDimensionType();
/**
* Returns the type arguments for this type signature, if any. Returns the empty list if none.
*/
public abstract List<NdTypeArgument> getTypeArguments();
@Override
public String toString() {
try {
CharArrayBuffer result = new CharArrayBuffer();
getSignature(result);
return result.toString();
} catch (RuntimeException e) {
// This is called most often from the debugger, so we want to return something meaningful even
// if the code is buggy, the database is corrupt, or we don't have a read lock.
return super.toString();
}
}
}