/******************************************************************************* * 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; } }