/******************************************************************************* * Copyright (c) 2015, 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 org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.NdNode; 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.StructDef; /** * {@link NdTreeNode} elements form a tree of nodes rooted at a {@link NdResourceFile}. Each node contains a list of * children which it declares and has a pointer to the most specific node which declares it. */ public abstract class NdTreeNode extends NdNode { public static final FieldManyToOne<NdTreeNode> PARENT; public static final FieldOneToMany<NdTreeNode> CHILDREN; @SuppressWarnings("hiding") public static final StructDef<NdTreeNode> type; static { type = StructDef.create(NdTreeNode.class, NdNode.type); PARENT = FieldManyToOne.create(type, null); CHILDREN = FieldOneToMany.create(type, PARENT, 16); type.done(); } public NdTreeNode(Nd nd, long address) { super(nd, address); } protected NdTreeNode(Nd nd, NdTreeNode parent) { super(nd); PARENT.put(nd, this.address, parent == null ? 0 : parent.address); } public int getChildrenCount() { return CHILDREN.size(getNd(), this.address); } public NdTreeNode getChild(int index) { return CHILDREN.get(getNd(), this.address, index); } /** * Returns the closest ancestor of the given type, or null if none. Note that * this looks for an exact match. It will not return subtypes of the given type. */ @SuppressWarnings("unchecked") public <T extends NdTreeNode> T getAncestorOfType(Class<T> ancestorType) { long targetType = getNd().getNodeType(ancestorType); Nd nd = getNd(); long current = PARENT.getAddress(nd, this.address); while (current != 0) { short currentType = NODE_TYPE.get(nd, current); if (currentType == targetType) { NdNode result = load(nd, current); if (ancestorType.isInstance(result)) { return (T) result; } else { throw new IndexException("The node at address " + current + //$NON-NLS-1$ " should have been an instance of " + ancestorType.getName() + //$NON-NLS-1$ " but was an instance of " + result.getClass().getName()); //$NON-NLS-1$ } } current = PARENT.getAddress(nd, current); } return null; } NdTreeNode getParentNode() { return PARENT.get(getNd(), this.address); } public NdBinding getParentBinding() throws IndexException { NdNode parent= getParentNode(); if (parent instanceof NdBinding) { return (NdBinding) parent; } return null; } }