blob: b348f4ea761740262708ccbd056d2783b1c1d116 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Google, Inc 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:
* Stefan Xenos (Google) - Initial implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core.nd.java;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.db.IString;
import org.eclipse.jdt.internal.core.nd.db.IndexException;
import org.eclipse.jdt.internal.core.nd.field.FieldManyToOne;
import org.eclipse.jdt.internal.core.nd.field.FieldOneToMany;
import org.eclipse.jdt.internal.core.nd.field.FieldString;
import org.eclipse.jdt.internal.core.nd.field.StructDef;
import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
/**
* Represents a type signature that is anything other than a trivial reference to a concrete
* type. If a type reference includes annotations, generic arguments, wildcards, or is a
* type variable, this object represents it.
* <p>
* Arrays are encoded in a special way. The RAW_TYPE points to a sentinel type called '['
* and the first type argument holds the array type.
*/
public class NdComplexTypeSignature extends NdTypeSignature {
public static final FieldString VARIABLE_IDENTIFIER;
public static final FieldManyToOne<NdTypeId> RAW_TYPE;
public static final FieldOneToMany<NdTypeArgument> TYPE_ARGUMENTS;
public static final FieldManyToOne<NdComplexTypeSignature> DECLARING_TYPE;
public static final FieldOneToMany<NdComplexTypeSignature> DECLARED_TYPES;
@SuppressWarnings("hiding")
public static final StructDef<NdComplexTypeSignature> type;
static {
type = StructDef.create(NdComplexTypeSignature.class, NdTypeSignature.type);
VARIABLE_IDENTIFIER = type.addString();
RAW_TYPE = FieldManyToOne.create(type, NdTypeId.USED_AS_COMPLEX_TYPE);
TYPE_ARGUMENTS = FieldOneToMany.create(type, NdTypeArgument.PARENT);
DECLARING_TYPE = FieldManyToOne.create(type, null);
DECLARED_TYPES = FieldOneToMany.create(type, DECLARING_TYPE);
type.useStandardRefCounting().done();
}
public NdComplexTypeSignature(Nd nd, long address) {
super(nd, address);
}
public NdComplexTypeSignature(Nd nd) {
super(nd);
}
@Override
public NdTypeId getRawType() {
return RAW_TYPE.get(getNd(), this.address);
}
public void setVariableIdentifier(char[] variableIdentifier) {
VARIABLE_IDENTIFIER.put(getNd(), this.address, variableIdentifier);
}
/**
* If this type is a type variable, this returns the variable's identifier.
*/
public IString getVariableIdentifier() {
return VARIABLE_IDENTIFIER.get(getNd(), this.address);
}
public void setRawType(NdTypeId rawType) {
RAW_TYPE.put(getNd(), this.address, rawType);
}
public void setGenericDeclaringType(NdComplexTypeSignature enclosingType) {
DECLARING_TYPE.put(getNd(), this.address, enclosingType);
}
/**
* Returns the declaring type (as reported by the type's generic signature).
* Not to be confused with the declaring type as stored in the class file.
* That is stored in {@link NdType#getDeclaringType}. Any class that is
* nested inside another class with generic arguments will have one of
* these. Classes nested inside non-generic classes won't have one of these,
* and neither will non-nested classes.
*/
public NdComplexTypeSignature getGenericDeclaringType() {
return DECLARING_TYPE.get(getNd(), this.address);
}
@Override
public List<NdTypeArgument> getTypeArguments() {
return TYPE_ARGUMENTS.asList(getNd(), this.address);
}
@Override
public NdTypeSignature getArrayDimensionType() {
if (isArrayType()) {
long size = TYPE_ARGUMENTS.size(getNd(), this.address);
if (size != 1) {
throw new IndexException("Array types should have exactly one argument"); //$NON-NLS-1$
}
return TYPE_ARGUMENTS.get(getNd(), this.address, 0).getType();
}
return null;
}
@Override
public void getSignature(CharArrayBuffer result, boolean includeTrailingSemicolon) {
NdComplexTypeSignature parentSignature = getGenericDeclaringType();
if (isTypeVariable()) {
result.append('T');
result.append(getVariableIdentifier().getChars());
if (includeTrailingSemicolon) {
result.append(';');
}
return;
}
NdTypeSignature arrayDimension = getArrayDimensionType();
if (arrayDimension != null) {
result.append('[');
arrayDimension.getSignature(result);
return;
}
if (parentSignature != null) {
parentSignature.getSignature(result, false);
result.append('.');
char[] simpleName = getRawType().getSimpleName().getChars();
result.append(simpleName);
} else {
result.append(getRawType().getFieldDescriptorWithoutTrailingSemicolon());
}
List<NdTypeArgument> arguments = getTypeArguments();
if (!arguments.isEmpty()) {
result.append('<');
for (NdTypeArgument next : arguments) {
next.getSignature(result);
}
result.append('>');
}
if (includeTrailingSemicolon) {
result.append(';');
}
}
@Override
public boolean isTypeVariable() {
return getVariableIdentifier().length() != 0;
}
@Override
public List<NdTypeSignature> getDeclaringTypeChain() {
NdComplexTypeSignature declaringType = getGenericDeclaringType();
if (declaringType == null) {
return Collections.singletonList((NdTypeSignature)this);
}
List<NdTypeSignature> result = new ArrayList<>();
computeDeclaringTypes(result);
return result;
}
private void computeDeclaringTypes(List<NdTypeSignature> result) {
NdComplexTypeSignature declaringType = getGenericDeclaringType();
if (declaringType != null) {
declaringType.computeDeclaringTypes(result);
}
result.add(this);
}
@Override
public boolean isArrayType() {
NdTypeId rawType = getRawType();
if (rawType == null) {
return false;
}
if (rawType.getFieldDescriptor().comparePrefix(JavaNames.ARRAY_FIELD_DESCRIPTOR_PREFIX, true) == 0) { // $NON-NLS-1$
return true;
}
return false;
}
}