/*******************************************************************************
* 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.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.FieldByte;
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 TypeParameter, as described in Section 4.7.9.1 of the java VM specification, Java SE 8 edititon.
*/
public class NdTypeParameter extends NdNode {
public static final FieldManyToOne<NdBinding> PARENT;
public static final FieldString IDENTIFIER;
public static final FieldOneToMany<NdTypeBound> BOUNDS;
public static final FieldByte TYPE_PARAMETER_FLAGS;
public static final byte FLG_FIRST_BOUND_IS_A_CLASS = 0x01;
@SuppressWarnings("hiding")
public static final StructDef<NdTypeParameter> type;
static {
type = StructDef.create(NdTypeParameter.class, NdNode.type);
PARENT = FieldManyToOne.createOwner(type, NdBinding.TYPE_PARAMETERS);
IDENTIFIER = type.addString();
BOUNDS = FieldOneToMany.create(type, NdTypeBound.PARENT);
TYPE_PARAMETER_FLAGS = type.addByte();
type.done();
}
public NdTypeParameter(Nd nd, long address) {
super(nd, address);
}
public NdTypeParameter(NdBinding parent, char[] identifier) {
super(parent.getNd());
PARENT.put(getNd(), this.address, parent);
IDENTIFIER.put(getNd(), this.address, identifier);
}
public char[] getIdentifier() {
return IDENTIFIER.get(getNd(), this.address).getChars();
}
public void setFirstBoundIsClass(boolean isClass) {
setFlag(FLG_FIRST_BOUND_IS_A_CLASS, isClass);
}
public boolean isFirstBoundAClass() {
return (TYPE_PARAMETER_FLAGS.get(getNd(), this.address) & FLG_FIRST_BOUND_IS_A_CLASS) != 0;
}
private void setFlag(byte flag, boolean value) {
byte oldValue = TYPE_PARAMETER_FLAGS.get(getNd(), this.address);
byte newValue;
if (value) {
newValue = (byte) (oldValue | flag);
} else {
newValue = (byte) (oldValue & ~flag);
}
TYPE_PARAMETER_FLAGS.put(getNd(), this.address, newValue);
}
public List<NdTypeBound> getBounds() {
return BOUNDS.asList(getNd(), this.address);
}
public void getSignature(CharArrayBuffer result) {
result.append(getIdentifier());
List<NdTypeBound> bounds = getBounds();
// If none of the bounds are classes and there is at least one bound, then insert a double-colon
// in the type signature.
if (!bounds.isEmpty() && !isFirstBoundAClass()) {
result.append(':');
}
for (NdTypeBound next : bounds) {
next.getSignature(result);
}
}
public static void getSignature(CharArrayBuffer buffer, List<NdTypeParameter> params) {
if (!params.isEmpty()) {
buffer.append('<');
for (NdTypeParameter next : params) {
next.getSignature(buffer);
}
buffer.append('>');
}
}
}