blob: 51f524f01b572ac9c15938db365de685dfd21fbd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 Wind River Systems, 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:
* Markus Schorn - initial API and implementation
* IBM Corporation
*******************************************************************************/
/* -- ST-Origin --
* Source folder: org.eclipse.cdt.ui/src
* Class: org.eclipse.cdt.internal.ui.typehierarchy.THGraph
* Version: 1.14
*/
package org.eclipse.ptp.internal.rdt.core.typehierarchy;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import org.eclipse.cdt.core.dom.IName;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexLocationConverter;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.ptp.internal.rdt.core.index.IndexQueries;
import org.eclipse.ptp.internal.rdt.core.model.ICProjectFactory;
import org.eclipse.ptp.rdt.core.RDTLog;
public class THGraph implements Serializable {
private static final long serialVersionUID = 1L;
private static final ICElement[] NO_MEMBERS = new ICElement[0];
private THGraphNode fInputNode= null;
private HashSet<THGraphNode> fRootNodes= new HashSet<THGraphNode>();
private HashSet<THGraphNode> fLeaveNodes= new HashSet<THGraphNode>();
private HashMap<ICElement, THGraphNode> fNodes= new HashMap<ICElement, THGraphNode>();
private boolean fFileIsIndexed;
private transient IIndexLocationConverter fConverter;
public THGraph() {
}
public THGraphNode getInputNode() {
return fInputNode;
}
public THGraphNode getNode(ICElement elem) {
return fNodes.get(elem);
}
public void setLocationConverter(IIndexLocationConverter converter) {
fConverter = converter;
}
private THGraphNode addNode(ICElement input) {
THGraphNode node= fNodes.get(input);
if (node == null) {
node= new THGraphNode(input);
fNodes.put(input, node);
fRootNodes.add(node);
fLeaveNodes.add(node);
}
return node;
}
private THGraphEdge addEdge(THGraphNode from, THGraphNode to) {
if (createsLoopOrIsDuplicate(from, to)) {
return null;
}
THGraphEdge edge= new THGraphEdge(from, to);
from.startEdge(edge);
to.endEdge(edge);
fRootNodes.remove(to);
fLeaveNodes.remove(from);
return edge;
}
private boolean createsLoopOrIsDuplicate(THGraphNode from, THGraphNode to) {
if (from == to) {
return true;
}
if (to.getOutgoing().isEmpty() || from.getIncoming().isEmpty()) {
return false;
}
HashSet<THGraphNode> checked= new HashSet<THGraphNode>();
ArrayList<THGraphNode> stack= new ArrayList<THGraphNode>();
stack.add(to);
while (!stack.isEmpty()) {
THGraphNode node= stack.remove(stack.size()-1);
List out= node.getOutgoing();
for (Iterator iterator = out.iterator(); iterator.hasNext();) {
THGraphEdge edge= (THGraphEdge) iterator.next();
node= edge.getEndNode();
if (node == from) {
return true;
}
if (checked.add(node)) {
stack.add(node);
}
}
}
// check if edge is already there.
List out= from.getOutgoing();
for (Iterator iterator = out.iterator(); iterator.hasNext();) {
THGraphEdge edge = (THGraphEdge) iterator.next();
if (edge.getEndNode() == to) {
return true;
}
}
return false;
}
public Collection<THGraphNode> getRootNodes() {
return fRootNodes;
}
public Collection<THGraphNode> getLeaveNodes() {
return fLeaveNodes;
}
public void defineInputNode(IIndex index, ICElement input, ICProjectFactory projectFactory) {
if (input != null) {
try {
fFileIsIndexed= true;
input= IndexQueries.attemptConvertionToHandle(index, input, fConverter, projectFactory);
fInputNode= addNode(input);
} catch (CoreException e) {
RDTLog.logError(e);
}
}
}
public void addSuperClasses(IIndex index, IProgressMonitor monitor, ICProjectFactory projectFactory) {
if (fInputNode == null) {
return;
}
HashSet<ICElement> handled= new HashSet<ICElement>();
ArrayList<ICElement> stack= new ArrayList<ICElement>();
stack.add(fInputNode.getElement());
handled.add(fInputNode.getElement());
while (!stack.isEmpty()) {
if (monitor.isCanceled()) {
return;
}
ICElement elem= stack.remove(stack.size()-1);
THGraphNode graphNode= addNode(elem);
try {
IIndexBinding binding = IndexQueries.elementToBinding(index, elem);
if (binding != null) {
addMembers(index, graphNode, binding, projectFactory);
}
if (binding instanceof ICPPClassType) {
ICPPClassType ct= (ICPPClassType) binding;
ICPPBase[] bases= ct.getBases();
for (int i = 0; i < bases.length; i++) {
if (monitor.isCanceled()) {
return;
}
ICPPBase base= bases[i];
IName name= base.getBaseClassSpecifierName();
IBinding basecl= name != null ? index.findBinding(name) : base.getBaseClass();
ICElement[] baseElems= IndexQueries.findRepresentative(index, basecl, fConverter, null, projectFactory);
for (int j = 0; j < baseElems.length; j++) {
ICElement baseElem = baseElems[j];
THGraphNode baseGraphNode= addNode(baseElem);
addMembers(index, baseGraphNode, basecl, projectFactory);
addEdge(graphNode, baseGraphNode);
if (handled.add(baseElem)) {
stack.add(baseElem);
}
}
}
}
else if (binding instanceof ITypedef) {
ITypedef ct= (ITypedef) binding;
IType type= ct.getType();
if (type instanceof IBinding) {
IBinding basecl= (IBinding) type;
ICElement[] baseElems= IndexQueries.findRepresentative(index, basecl, fConverter, null, projectFactory);
if (baseElems.length > 0) {
ICElement baseElem= baseElems[0];
THGraphNode baseGraphNode= addNode(baseElem);
addMembers(index, baseGraphNode, basecl, projectFactory);
addEdge(graphNode, baseGraphNode);
if (handled.add(baseElem)) {
stack.add(baseElem);
}
}
}
}
} catch (DOMException e) {
// index bindings should not throw this kind of exception, might as well log it.
RDTLog.logError(e);
} catch (CoreException e) {
RDTLog.logError(e);
}
}
}
public void addSubClasses(IIndex index, IProgressMonitor monitor, ICProjectFactory projectFactory) {
if (fInputNode == null) {
return;
}
HashSet<ICElement> handled= new HashSet<ICElement>();
ArrayList<ICElement> stack= new ArrayList<ICElement>();
ICElement element = fInputNode.getElement();
stack.add(element);
handled.add(element);
while (!stack.isEmpty()) {
if (monitor.isCanceled()) {
return;
}
ICElement elem= stack.remove(stack.size()-1);
THGraphNode graphNode= addNode(elem);
try {
IBinding binding = IndexQueries.elementToBinding(index, elem);
if (binding != null) {
IIndexName[] names= index.findNames(binding, IIndex.FIND_REFERENCES | IIndex.FIND_DEFINITIONS);
for (int i = 0; i < names.length; i++) {
if (monitor.isCanceled()) {
return;
}
IIndexName indexName = names[i];
if (indexName.isBaseSpecifier()) {
IIndexName subClassDef= indexName.getEnclosingDefinition();
if (subClassDef != null) {
IBinding subClass= index.findBinding(subClassDef);
ICElement[] subClassElems= IndexQueries.findRepresentative(index, subClass, fConverter, null, projectFactory);
if (subClassElems.length > 0) {
ICElement subClassElem= subClassElems[0];
THGraphNode subGraphNode= addNode(subClassElem);
addMembers(index, subGraphNode, subClass, projectFactory);
addEdge(subGraphNode, graphNode);
if (handled.add(subClassElem)) {
stack.add(subClassElem);
}
}
}
}
}
}
} catch (CoreException e) {
RDTLog.logError(e);
}
}
}
private void addMembers(IIndex index, THGraphNode graphNode, IBinding binding, ICProjectFactory projectFactory) throws CoreException {
if (graphNode.getMembers(false) == null) {
ArrayList<ICElement> memberList= new ArrayList<ICElement>();
try {
if (binding instanceof ICPPClassType) {
ICPPClassType ct= (ICPPClassType) binding;
IBinding[] members= ct.getDeclaredFields();
addMemberElements(index, members, memberList, projectFactory);
members= ct.getDeclaredMethods();
addMemberElements(index, members, memberList, projectFactory);
}
else if (binding instanceof ICompositeType) {
ICompositeType ct= (ICompositeType) binding;
IBinding[] members= ct.getFields();
addMemberElements(index, members, memberList, projectFactory);
}
else if (binding instanceof IEnumeration) {
IEnumeration ct= (IEnumeration) binding;
IBinding[] members= ct.getEnumerators();
addMemberElements(index, members, memberList, projectFactory);
}
} catch (DOMException e) {
// problem bindings should not be reported to the log.
}
if (memberList.isEmpty()) {
graphNode.setMembers(NO_MEMBERS);
}
else {
graphNode.setMembers(memberList.toArray(new ICElement[memberList.size()]));
}
}
}
private void addMemberElements(IIndex index, IBinding[] members, List<ICElement> memberList, ICProjectFactory projectFactory)
throws CoreException {
for (int i = 0; i < members.length; i++) {
IBinding binding = members[i];
ICElement[] elems= IndexQueries.findRepresentative(index, binding, fConverter, null, projectFactory);
if (elems.length > 0) {
memberList.add(elems[0]);
}
}
}
public boolean isTrivial() {
return fNodes.size() < 2;
}
public boolean isFileIndexed() {
return fFileIsIndexed;
}
}