/******************************************************************************* * Copyright (c) 2000, 2008 IBM Corporation 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: * IBM Corporation - initial API and implementation * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.internal.core.parser.util; import java.util.ArrayList; import java.util.List; import junit.framework.Assert; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IName; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.c.CASTVisitor; import org.eclipse.cdt.core.dom.ast.cpp.CPPASTVisitor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.content.IContentType; /** * Utility class to have commonly used algorithms in one place for searching with the DOM. * * @author dsteffle */ public class DOMSearchUtil { private static final IASTName[] BLANK_NAME_ARRAY = new IASTName[0]; // private static final IASTName[] EMPTY_NAME_LIST = BLANK_NAME_ARRAY; public static final int DECLARATIONS = 1; public static final int DEFINITIONS = 2; public static final int DECLARATIONS_DEFINITIONS = 3; public static final int REFERENCES = 4; public static final int ALL_OCCURRENCES = 5; /** * This retrieves the ParserLanguage from an IFile. * * @param file * @return */ public static ParserLanguage getLanguageFromFile(IFile file) { IProject project = file.getProject(); IContentType contentType = CCorePlugin.getContentType(project, file.getFullPath().lastSegment()); if (contentType != null) { String lid = contentType.getId(); if (CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(lid) || CCorePlugin.CONTENT_TYPE_CXXHEADER.equals(lid)) { return ParserLanguage.CPP; } } return ParserLanguage.C; } /** * The CPPNameCollector used to get IASTNames from an IASTNode. * * @author dsteffle */ static public class CPPNameCollector extends CPPASTVisitor { { shouldVisitNames = true; } public List nameList = new ArrayList(); public int visit( IASTName name ){ nameList.add( name ); return PROCESS_CONTINUE; } public IASTName getName( int idx ){ if( idx < 0 || idx >= nameList.size() ) return null; return (IASTName) nameList.get( idx ); } public int size() { return nameList.size(); } } /** * The CNameCollector used to get IASTNames from an IASTNode. * * @author dsteffle */ static public class CNameCollector extends CASTVisitor { { shouldVisitNames = true; } public List nameList = new ArrayList(); public int visit( IASTName name ){ nameList.add( name ); return PROCESS_CONTINUE; } public IASTName getName( int idx ){ if( idx < 0 || idx >= nameList.size() ) return null; return (IASTName) nameList.get( idx ); } public int size() { return nameList.size(); } } /** * Returns the ParserLanguage corresponding to the IPath and IProject. Returns ParserLanguage.CPP if the file type is a header. * * @param path * @param project * @return */ public static ParserLanguage getLanguage( IPath path, IProject project ) { //FIXME: ALAIN, for headers should we assume CPP ?? // The problem is that it really depends on how the header was included. String id = null; IContentType contentType = CCorePlugin.getContentType(project, path.lastSegment()); if (contentType != null) { id = contentType.getId(); } if (id != null) { if (CCorePlugin.CONTENT_TYPE_CXXHEADER.equals(id)) { return ParserLanguage.CPP; } else if (CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(id)) { return ParserLanguage.CPP; } else if (CCorePlugin.CONTENT_TYPE_CHEADER.equals(id)) { return ParserLanguage.C; } else if (CCorePlugin.CONTENT_TYPE_CSOURCE.equals(id)) { return ParserLanguage.C; } else if (CCorePlugin.CONTENT_TYPE_ASMSOURCE.equals(id)) { // ??? // What do we do here ? } } return ParserLanguage.CPP; } /** * This is used to get the names from the TU that the IASTName searchName belongs to. * * @param searchName the IASTName whose references/delcarations are to be retrieved * @param limitTo used to specify whether to get declarations, references, or both, one of: * ( CSearchPattern.DECLARATION | CSearchPattern.REFERENCES | CSearchPattern.ALL_OCCURRENCES ) * @return IASTName[] declarations, references, or both depending on limitTo that correspond to the IASTName searchName searched for */ public static IName[] getNamesFromDOM(IASTName searchName, int limitTo) { IName[] names = null; IASTTranslationUnit tu = searchName.getTranslationUnit(); if (tu == null) { return BLANK_NAME_ARRAY; } IBinding binding = searchName.resolveBinding(); if (binding instanceof IIndexBinding) { Assert.fail("Not implemented"); // try { // ArrayList pdomNames = new ArrayList(); // IPDOMResolver pdom= ((PDOMBinding) binding).getPDOM(); // // First decls // names= pdom.getDeclarations(binding); // pdomNames.addAll(Arrays.asList(names)); // // Next defs // names= pdom.getDefinitions(binding); // pdomNames.addAll(Arrays.asList(names)); // names = (IName[])pdomNames.toArray(new IName[pdomNames.size()]); // } catch (CoreException e) { // CCorePlugin.log(e); // } } else { names = getNames(tu, binding, limitTo); if (names == null || names.length == 0) { // try alternate strategies try { // fix for 86829, 95224 if ((binding instanceof ICPPConstructor || (binding instanceof ICPPMethod && ((ICPPMethod)binding).isDestructor())) && binding.getScope() instanceof ICPPClassScope) { binding = ((ICPPClassScope)binding.getScope()).getClassType(); names = getNames(tu, binding, limitTo); } } catch (DOMException e) {} } } return names; } private static IASTName[] getNames(IASTTranslationUnit tu, IBinding binding, int limitTo) { IASTName[] names = null; if (limitTo == DECLARATIONS || limitTo == DECLARATIONS_DEFINITIONS) { names = tu.getDeclarationsInAST(binding); } else if (limitTo == REFERENCES) { names = tu.getReferences(binding); } else if (limitTo == DEFINITIONS) { names = tu.getDefinitionsInAST(binding); } else if (limitTo == ALL_OCCURRENCES){ names = tu.getDeclarationsInAST(binding); names = (IASTName[])ArrayUtil.addAll(IASTName.class, names, tu.getReferences(binding)); } else { // assume ALL names = tu.getDeclarationsInAST(binding); names = (IASTName[])ArrayUtil.addAll(IASTName.class, names, tu.getReferences(binding)); } return names; } }