| /******************************************************************************* |
| * Copyright (c) 2000, 2010 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) |
| * Ed Swartz (Nokia) |
| *******************************************************************************/ |
| package org.eclipse.ptp.internal.rdt.core.miners; |
| |
| import static java.lang.Math.max; |
| import static java.lang.Math.min; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.cdt.core.dom.IName; |
| import org.eclipse.cdt.core.dom.ast.ASTNameCollector; |
| import org.eclipse.cdt.core.dom.ast.DOMException; |
| import org.eclipse.cdt.core.dom.ast.IASTDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTFileLocation; |
| import org.eclipse.cdt.core.dom.ast.IASTFunctionStyleMacroParameter; |
| import org.eclipse.cdt.core.dom.ast.IASTImplicitName; |
| import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; |
| import org.eclipse.cdt.core.dom.ast.IASTName; |
| import org.eclipse.cdt.core.dom.ast.IASTNode; |
| import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; |
| import org.eclipse.cdt.core.dom.ast.IASTPreprocessorFunctionStyleMacroDefinition; |
| import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; |
| import org.eclipse.cdt.core.dom.ast.IBinding; |
| import org.eclipse.cdt.core.dom.ast.IParameter; |
| import org.eclipse.cdt.core.dom.ast.IProblemBinding; |
| import org.eclipse.cdt.core.dom.ast.IType; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTranslationUnit; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; |
| import org.eclipse.cdt.core.index.IIndex; |
| import org.eclipse.cdt.core.index.IIndexBinding; |
| import org.eclipse.cdt.core.index.IIndexMacro; |
| import org.eclipse.cdt.core.index.IIndexName; |
| import org.eclipse.cdt.core.index.IndexFilter; |
| import org.eclipse.cdt.core.model.ICElement; |
| import org.eclipse.cdt.core.model.ISourceReference; |
| import org.eclipse.cdt.core.model.ITranslationUnit; |
| import org.eclipse.cdt.core.parser.util.ArrayUtil; |
| import org.eclipse.cdt.core.parser.util.CharArrayUtils; |
| import org.eclipse.cdt.internal.core.dom.parser.ASTNode; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.LookupData; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; |
| import org.eclipse.cdt.internal.core.index.IIndexFragmentName; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.dstore.core.model.DataStore; |
| import org.eclipse.ptp.internal.rdt.core.model.BindingAdapter; |
| import org.eclipse.ptp.internal.rdt.core.model.CElement; |
| import org.eclipse.ptp.internal.rdt.core.model.Path; |
| import org.eclipse.ptp.internal.rdt.core.model.Scope; |
| import org.eclipse.ptp.internal.rdt.core.navigation.OpenDeclarationResult; |
| import org.eclipse.ptp.internal.rdt.core.navigation.SimpleASTFileLocation; |
| import org.eclipse.ptp.internal.rdt.core.navigation.SimpleName; |
| import org.eclipse.ptp.rdt.core.RDTLog; |
| import org.eclipse.rse.dstore.universal.miners.UniversalServerUtilities; |
| |
| public class OpenDeclarationHandler { |
| |
| private enum NameKind { REFERENCE, DECLARATION, USING_DECL, DEFINITION } |
| |
| public static final String CLASS_NAME = "CDTMiner-OpenDeclarationHandler"; //$NON-NLS-1$ |
| |
| private static int PARSE_MODE_FAST = |
| ITranslationUnit.AST_SKIP_ALL_HEADERS | |
| ITranslationUnit.AST_CONFIGURE_USING_SOURCE_CONTEXT; |
| |
| |
| |
| public static OpenDeclarationResult handleOpenDeclaration(String scopeName, String scheme, ITranslationUnit workingCopy, String path, String selectedText, int selectionStart, int selectionLength, DataStore _dataStore) { |
| |
| UniversalServerUtilities.logDebugMessage(CLASS_NAME, "Getting declaration for selection in " + workingCopy.getElementName(), _dataStore); //$NON-NLS-1$ |
| UniversalServerUtilities.logDebugMessage(CLASS_NAME, "scope: " + scopeName, _dataStore); //$NON-NLS-1$ |
| UniversalServerUtilities.logDebugMessage(CLASS_NAME, "path: " + workingCopy.getLocationURI(), _dataStore); //$NON-NLS-1$ |
| UniversalServerUtilities.logDebugMessage(CLASS_NAME, "offset: " + selectionStart, _dataStore); //$NON-NLS-1$ |
| UniversalServerUtilities.logDebugMessage(CLASS_NAME, "length: " + selectionLength, _dataStore); //$NON-NLS-1$ |
| |
| IIndex index = RemoteIndexManager.getInstance().getIndexForScope(Scope.WORKSPACE_ROOT_SCOPE_NAME, _dataStore); |
| |
| UniversalServerUtilities.logDebugMessage(CLASS_NAME, "Acquiring read lock", _dataStore); //$NON-NLS-1$ |
| |
| |
| try { |
| index.acquireReadLock(); |
| } catch (InterruptedException e) { |
| UniversalServerUtilities.logError(CLASS_NAME, e.toString(), e, _dataStore); |
| return OpenDeclarationResult.failureUnexpectedError(); |
| } |
| |
| UniversalServerUtilities.logDebugMessage(CLASS_NAME, "Got Read lock", _dataStore); //$NON-NLS-1$ |
| |
| try { |
| return doHandleOpenDeclaration(scopeName, scheme, workingCopy, path, selectedText, selectionStart, selectionLength, index, _dataStore); |
| |
| } catch (CoreException e) { |
| UniversalServerUtilities.logError(CLASS_NAME, e.toString(), e, _dataStore); |
| return OpenDeclarationResult.failureUnexpectedError(); |
| } finally { |
| index.releaseReadLock(); |
| UniversalServerUtilities.logDebugMessage(CLASS_NAME, "Lock released", _dataStore); //$NON-NLS-1$ |
| } |
| } |
| |
| |
| /** |
| * PDOMNames and ASTNames are not serializable, need to convert them |
| * to a serializable form before returning them. |
| */ |
| private static IName[] convertNames(IName[] names) { |
| int n = names.length; |
| IName[] converted = new IName[n]; |
| for(int i = 0; i < n; i++) { |
| converted[i] = new SimpleName(names[i]); |
| } |
| |
| return converted; |
| } |
| |
| /* -- ST-Origin -- |
| * Source folder: org.eclipse.cdt.ui/src |
| * Class: org.eclipse.cdt.internal.ui.search.actions.OpenDeclarationsJob |
| * Version: 1.16 |
| */ |
| |
| private static OpenDeclarationResult doHandleOpenDeclaration(String scopeName, String scheme, ITranslationUnit workingCopy, String path, String selectedText, |
| int selectionStart, int selectionLength, IIndex index, DataStore _dataStore) throws CoreException { |
| IASTTranslationUnit ast = workingCopy.getAST(index, PARSE_MODE_FAST); |
| |
| final IASTNodeSelector nodeSelector = ast.getNodeSelector(null); |
| |
| IASTName sourceName= nodeSelector.findEnclosingName(selectionStart, selectionLength); |
| IName[] implicitTargets = findImplicitTargets(index, ast, nodeSelector, selectionStart, selectionLength); |
| if (sourceName == null) { |
| if (implicitTargets.length > 0) { |
| ICElement[] elements = convertToCElements(workingCopy, index, implicitTargets, _dataStore); |
| return OpenDeclarationResult.resultCElements(elements); |
| } |
| } else { |
| IASTNode parent = sourceName.getParent(); |
| if (parent instanceof IASTPreprocessorIncludeStatement) { |
| String includedPath = ((IASTPreprocessorIncludeStatement) parent).getPath(); |
| if (includedPath == null || includedPath.equals("")) //$NON-NLS-1$ |
| return OpenDeclarationResult.failureIncludeLookup(selectedText); |
| else |
| return OpenDeclarationResult.resultIncludePath(includedPath); |
| } |
| |
| NameKind kind = getNameKind(sourceName); |
| IBinding b = sourceName.resolveBinding(); |
| IBinding[] bindings = new IBinding[] { b }; |
| if (b instanceof IProblemBinding) { |
| IBinding[] candidateBindings = ((IProblemBinding) b).getCandidateBindings(); |
| if (candidateBindings.length != 0) { |
| bindings = candidateBindings; |
| } |
| } else if (kind == NameKind.DEFINITION && b instanceof IType) { |
| // Don't navigate away from a type definition. |
| // Select the name at the current location instead. |
| return OpenDeclarationResult.resultName(new SimpleName(sourceName)); |
| } |
| IName[] targets = IName.EMPTY_ARRAY; |
| String filename = ast.getFilePath(); |
| for (IBinding binding : bindings) { |
| if (binding != null && !(binding instanceof IProblemBinding)) { |
| IName[] names = findDeclNames(index, ast, kind, binding); |
| for (final IName name : names) { |
| if (name instanceof IIndexName && |
| filename.equals(((IIndexName) name).getFileLocation().getFileName())) { |
| // Exclude index names from the current file. |
| } else if (areOverlappingNames(name, sourceName)) { |
| // Exclude the current location. |
| } else if (binding instanceof IParameter) { |
| if (isInSameFunction(sourceName, name)) { |
| targets = ArrayUtil.append(targets, name); |
| } |
| } else if (binding instanceof ICPPTemplateParameter) { |
| if (isInSameTemplate(sourceName, name)) { |
| targets = ArrayUtil.append(targets, name); |
| } |
| } else if (name != null) { |
| targets = ArrayUtil.append(targets, name); |
| } |
| } |
| } |
| targets = ArrayUtil.trim(ArrayUtil.addAll(targets, implicitTargets)); |
| ICElement[] elements = convertToCElements(workingCopy, index, targets, _dataStore); |
| if(elements != null && elements.length > 0) |
| return OpenDeclarationResult.resultCElements(elements); |
| else if(hasAtLeastOneLocation(targets)) |
| return OpenDeclarationResult.resultNames(convertNames(targets)); |
| |
| return navigationFallBack(ast, index, selectedText, _dataStore, workingCopy, sourceName, kind); |
| } |
| } |
| |
| // No enclosing name, check if we're in an include statement |
| IASTNode node = nodeSelector.findEnclosingNode(selectionStart, selectionLength); |
| if (node instanceof IASTPreprocessorIncludeStatement) { |
| String includedPath = ((IASTPreprocessorIncludeStatement) node).getPath(); |
| if (includedPath != "") //$NON-NLS-1$ |
| return OpenDeclarationResult.resultIncludePath(includedPath); |
| else |
| return OpenDeclarationResult.failureIncludeLookup(selectedText); |
| } else if (node instanceof IASTPreprocessorFunctionStyleMacroDefinition) { |
| IASTPreprocessorFunctionStyleMacroDefinition mdef= (IASTPreprocessorFunctionStyleMacroDefinition) node; |
| for (IASTFunctionStyleMacroParameter par: mdef.getParameters()) { |
| String parName= par.getParameter(); |
| if (parName.equals(selectedText)) { |
| IASTFileLocation location = par.getFileLocation(); |
| if (location != null) |
| return OpenDeclarationResult.resultLocation(new SimpleASTFileLocation(par.getFileLocation())); |
| } |
| } |
| } |
| |
| return navigationFallBack(ast, index, selectedText, _dataStore, workingCopy, sourceName, NameKind.REFERENCE); |
| } |
| |
| private static boolean areOverlappingNames(IName n1, IName n2) { |
| if (n1 == n2) |
| return true; |
| |
| IASTFileLocation loc1 = n1.getFileLocation(); |
| IASTFileLocation loc2 = n2.getFileLocation(); |
| if (loc1 == null || loc2 == null) |
| return false; |
| return loc1.getFileName().equals(loc2.getFileName()) && |
| max(loc1.getNodeOffset(), loc2.getNodeOffset()) < |
| min(loc1.getNodeOffset() + loc1.getNodeLength(), loc2.getNodeOffset() + loc2.getNodeLength()); |
| } |
| |
| private static boolean isInSameFunction(IASTName name1, IName name2) { |
| IASTDeclaration decl1 = getEnclosingDeclaration(name1); |
| IASTDeclaration decl2 = name2 instanceof IASTName ? getEnclosingDeclaration((IASTName) name2) : null; |
| return decl1 != null && decl1.equals(decl2) || decl1 == null && decl2 == null; |
| } |
| |
| private static IASTDeclaration getEnclosingDeclaration(IASTNode node) { |
| while (node != null && !(node instanceof IASTDeclaration)) { |
| node= node.getParent(); |
| } |
| return (IASTDeclaration) node; |
| } |
| |
| private static boolean isInSameTemplate(IASTName name1, IName name2) { |
| IASTDeclaration decl1 = getEnclosingTemplateDeclaration(name1); |
| IASTDeclaration decl2 = name2 instanceof IASTName ? |
| getEnclosingTemplateDeclaration((IASTName) name2) : null; |
| return decl1 != null && decl1.equals(decl2) || decl1 == null && decl2 == null; |
| } |
| |
| private static IASTDeclaration getEnclosingTemplateDeclaration(IASTNode node) { |
| while (node != null && !(node instanceof ICPPASTTemplateDeclaration)) { |
| node= node.getParent(); |
| } |
| return (IASTDeclaration) node; |
| } |
| |
| |
| |
| private static ICElement[] convertToCElements(ITranslationUnit unit, IIndex index, IName[] names, DataStore _dataStore) { |
| List<ICElement> elements = new ArrayList<ICElement>(); |
| for(IName name : names) { |
| try { |
| ICElement element = getCElementForName(unit, index, name); |
| if(element instanceof ISourceReference) |
| elements.add(element); |
| } catch (CoreException e) { |
| UniversalServerUtilities.logError(CLASS_NAME, e.toString(), e, _dataStore); |
| } catch (DOMException e) { |
| UniversalServerUtilities.logError(CLASS_NAME, e.toString(), e, _dataStore); |
| } |
| } |
| return elements.toArray(new ICElement[elements.size()]); |
| } |
| |
| private static ICElement getCElementForName(ITranslationUnit unit, IIndex index, IName name) throws CoreException, DOMException { |
| boolean isDefinition = name.isDefinition(); |
| IBinding binding; |
| int offset, length; |
| |
| if(name instanceof IIndexName) { |
| IIndexName indexName = (IIndexName) name; |
| binding = index.findBinding(indexName); |
| offset = indexName.getNodeOffset(); |
| length = indexName.getNodeLength(); |
| |
| } |
| else if(name instanceof IASTName) { |
| IASTName astName = (IASTName) name; |
| binding = astName.resolveBinding(); |
| if(binding == null) |
| return null; |
| IASTFileLocation loc = astName.getFileLocation(); |
| if(loc == null) |
| return null; |
| offset = loc.getNodeOffset(); |
| length = loc.getNodeLength(); |
| } |
| else { |
| return null; |
| } |
| |
| ICElement element = BindingAdapter.adaptBinding(unit, binding, offset, length, isDefinition); |
| if(element == null) |
| return null; |
| ((CElement)element).setPath(new Path(name.getFileLocation().getFileName())); |
| return element; |
| } |
| |
| |
| private static boolean hasAtLeastOneLocation(IName[] declNames) { |
| for(IName name : declNames) { |
| IASTFileLocation fileloc = name.getFileLocation(); |
| if(fileloc != null) |
| return true; |
| } |
| return false; |
| } |
| |
| private static IName[] findDeclNames(IIndex index, IASTTranslationUnit ast, NameKind kind, IBinding binding) throws CoreException { |
| IName[] declNames = findNames(index, ast, kind, binding); |
| // Bug 207320, handle template instances. |
| while (declNames.length == 0 && binding instanceof ICPPSpecialization) { |
| binding = ((ICPPSpecialization) binding).getSpecializedBinding(); |
| if (binding != null && !(binding instanceof IProblemBinding)) { |
| declNames = findNames(index, ast, NameKind.DEFINITION, binding); |
| } |
| } |
| if (declNames.length == 0 && binding instanceof ICPPMethod) { |
| // Bug 86829, handle implicit methods. |
| ICPPMethod method= (ICPPMethod) binding; |
| if (method.isImplicit()) { |
| try { |
| IBinding clsBinding= method.getClassOwner(); |
| if (clsBinding != null && !(clsBinding instanceof IProblemBinding)) { |
| declNames= findNames(index, ast, NameKind.REFERENCE, clsBinding); |
| } |
| } catch (DOMException e) { |
| // Don't log problem bindings. |
| } |
| } |
| } |
| return declNames; |
| } |
| |
| |
| private static IName[] findNames(IIndex index, IASTTranslationUnit ast, NameKind kind, IBinding binding) throws CoreException { |
| IName[] declNames; |
| if (kind == NameKind.DEFINITION) { |
| declNames= findDeclarations(index, ast, binding); |
| } else { |
| declNames= findDefinitions(index, ast, kind, binding); |
| } |
| |
| if (declNames.length == 0) { |
| if (kind == NameKind.DEFINITION) { |
| declNames= findDefinitions(index, ast, kind, binding); |
| } else { |
| declNames= findDeclarations(index, ast, binding); |
| } |
| } |
| return declNames; |
| } |
| |
| |
| private static IName[] findDefinitions(IIndex index, IASTTranslationUnit ast, NameKind kind, IBinding binding) throws CoreException { |
| List<IASTName> declNames= new ArrayList<IASTName>(); |
| declNames.addAll(Arrays.asList(ast.getDefinitionsInAST(binding))); |
| for (Iterator<IASTName> i = declNames.iterator(); i.hasNext();) { |
| IASTName name= i.next(); |
| final IBinding b2 = name.resolveBinding(); |
| if (b2 instanceof ICPPUsingDeclaration) { |
| i.remove(); |
| } |
| if (binding != b2 && binding instanceof ICPPSpecialization) { |
| // Make sure binding specializes b2 so that for instance we do not navigate from |
| // one partial specialization to another. |
| IBinding spec= binding; |
| while (spec instanceof ICPPSpecialization) { |
| spec= ((ICPPSpecialization) spec).getSpecializedBinding(); |
| if (spec == b2) |
| break; |
| } |
| if (!(spec instanceof ICPPSpecialization)) { |
| i.remove(); |
| } |
| } |
| } |
| if (!declNames.isEmpty()) { |
| return declNames.toArray(new IASTName[declNames.size()]); |
| } |
| |
| // 2. Try definition in index |
| return index.findNames(binding, IIndex.FIND_DEFINITIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES); |
| } |
| |
| |
| private static IName[] findDeclarations(IIndex index, IASTTranslationUnit ast, IBinding binding) throws CoreException { |
| IName[] declNames= ast.getDeclarationsInAST(binding); |
| for (int i = 0; i < declNames.length; i++) { |
| IName name = declNames[i]; |
| if (name.isDefinition()) |
| declNames[i]= null; |
| } |
| declNames= (IName[]) ArrayUtil.removeNulls(IName.class, declNames); |
| if (declNames.length == 0) { |
| declNames= index.findNames(binding, IIndex.FIND_DECLARATIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES); |
| } |
| return declNames; |
| } |
| |
| /** |
| * Returns definitions of bindings referenced by implicit name at the given location. |
| */ |
| private static IName[] findImplicitTargets(IIndex index, IASTTranslationUnit ast, IASTNodeSelector nodeSelector, |
| int offset, int length) throws CoreException { |
| IName[] definitions = IName.EMPTY_ARRAY; |
| IASTName firstName = nodeSelector.findEnclosingImplicitName(offset, length); |
| if (firstName != null) { |
| IASTImplicitNameOwner owner = (IASTImplicitNameOwner) firstName.getParent(); |
| for (IASTImplicitName name : owner.getImplicitNames()) { |
| if (((ASTNode) name).getOffset() == ((ASTNode) firstName).getOffset()) { |
| IBinding binding = name.resolveBinding(); // Guaranteed to resolve. |
| IName[] declNames = findDeclNames(index, ast, NameKind.REFERENCE, binding); |
| definitions = ArrayUtil.addAll(definitions, declNames); |
| } |
| } |
| } |
| return ArrayUtil.trim(definitions); |
| } |
| |
| private static IBinding getBinding(IName name) { |
| if (name instanceof IASTName) { |
| return ((IASTName) name).resolveBinding(); |
| } else if (name instanceof IIndexFragmentName) { |
| try { |
| return ((IIndexFragmentName) name).getBinding(); |
| } catch (CoreException e) { |
| // Fall through to return null. |
| } |
| } |
| return null; |
| } |
| |
| private static NameKind getNameKind(IName name) { |
| if (name.isDefinition()) { |
| if (getBinding(name) instanceof ICPPUsingDeclaration) { |
| return NameKind.USING_DECL; |
| } else { |
| return NameKind.DEFINITION; |
| } |
| } else if (name.isDeclaration()) { |
| return NameKind.DECLARATION; |
| } |
| return NameKind.REFERENCE; |
| } |
| |
| |
| /** |
| * If the names cannot be found using a binding then fall back to a text search. |
| */ |
| private static OpenDeclarationResult navigationFallBack(IASTTranslationUnit ast, IIndex index, String selectedText, DataStore _dataStore, ITranslationUnit tu, IASTName sourceName, NameKind kind) { |
| if(selectedText == null || selectedText.length() == 0) |
| return null; |
| |
| try { |
| final char[] name = selectedText.toCharArray(); |
| List<IName> nameList = new ArrayList<IName>(); |
| List<ICElement> elems= new ArrayList<ICElement>(); |
| |
| // Bug 252549, search for names in the AST first. |
| Set<IBinding> primaryBindings= new HashSet<IBinding>(); |
| Set<IBinding> ignoreIndexBindings= new HashSet<IBinding>(); |
| ASTNameCollector nc= new ASTNameCollector(selectedText); |
| ast.accept(nc); |
| IASTName[] candidates= nc.getNames(); |
| for (IASTName astName : candidates) { |
| try { |
| IBinding b= astName.resolveBinding(); |
| if (b != null && !(b instanceof IProblemBinding) && |
| !ignoreIndexBindings.contains(b) && primaryBindings.add(b)) { |
| ignoreIndexBindings.add(index.adaptBinding(b)); |
| } |
| } catch (RuntimeException e) { |
| RDTLog.logError(e); |
| } |
| } |
| |
| // Search the index, also. |
| IndexFilter filter = IndexFilter.getDeclaredBindingFilter(ast.getLinkage().getLinkageID(), false); |
| IIndexBinding[] idxBindings = index.findBindings(name, false, filter, null); |
| for (IIndexBinding idxBinding : idxBindings) { |
| if (!ignoreIndexBindings.contains(idxBinding)) { |
| primaryBindings.add(idxBinding); |
| } |
| } |
| |
| IIndexMacro[] macros = index.findMacros(name, filter, null); |
| for(final IIndexMacro macro : macros) { |
| IName macroName = new SimpleName(macro.getFileLocation(), macro.getNameCharArray()); |
| nameList.add(macroName); |
| } |
| ICElement[] elements = convertToCElements(tu, index, (nameList.toArray(new IName[nameList.size()])), _dataStore); |
| for (ICElement element : elements) { |
| elems.add(element); |
| } |
| |
| Collection<IBinding> secondaryBindings; |
| if (ast instanceof ICPPASTTranslationUnit) { |
| secondaryBindings= cppRemoveSecondaryBindings(primaryBindings, sourceName); |
| } else { |
| secondaryBindings= defaultRemoveSecondaryBindings(primaryBindings, sourceName); |
| } |
| |
| // Convert bindings to CElements. |
| Collection<IBinding> bs= primaryBindings; |
| for (int k = 0; k < 2; k++) { |
| for (IBinding binding : bs) { |
| IName[] names = (findNames(index, ast, kind, binding)); |
| // Exclude names of the same kind. |
| for (int i = 0; i < names.length; i++) { |
| if (getNameKind(names[i]) == kind) { |
| names[i] = null; |
| } |
| } |
| names = (IName[]) ArrayUtil.removeNulls(IName.class, names); |
| elements = convertToCElements(tu, index, names, _dataStore); |
| for (ICElement element : elements) { |
| elems.add(element); |
| } |
| } |
| // In case we did not find anything, consider the secondary bindings. |
| if (!elems.isEmpty()) |
| break; |
| bs= secondaryBindings; |
| } |
| if(!elems.isEmpty()) |
| return OpenDeclarationResult.resultCElements((ICElement[])elems.toArray()); |
| if (sourceName != null && sourceName.isDeclaration()) { |
| // Select the name at the current location as the last resort. |
| return OpenDeclarationResult.resultName(new SimpleName(sourceName)); |
| } |
| |
| } catch (CoreException e) { |
| UniversalServerUtilities.logError(CLASS_NAME, e.toString(), e, _dataStore); |
| } |
| |
| return OpenDeclarationResult.failureSymbolLookup(selectedText); |
| } |
| |
| private static Collection<IBinding> defaultRemoveSecondaryBindings(Set<IBinding> primaryBindings, IASTName sourceName) { |
| if (sourceName != null) { |
| IBinding b= sourceName.resolveBinding(); |
| if (b != null && ! (b instanceof IProblemBinding)) { |
| try { |
| for (Iterator<IBinding> iterator = primaryBindings.iterator(); iterator.hasNext();) { |
| if (!checkOwnerNames(b, iterator.next())) |
| iterator.remove(); |
| } |
| } catch (DOMException e) { |
| // Ignore |
| } |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| private static boolean checkOwnerNames(IBinding b1, IBinding b2) throws DOMException { |
| IBinding o1 = b1.getOwner(); |
| IBinding o2 = b2.getOwner(); |
| if (o1 == o2) |
| return true; |
| |
| if (o1 == null || o2 == null) |
| return false; |
| |
| if (!CharArrayUtils.equals(o1.getNameCharArray(), o2.getNameCharArray())) |
| return false; |
| |
| return checkOwnerNames(o1, o2); |
| } |
| |
| private static Collection<IBinding> cppRemoveSecondaryBindings(Set<IBinding> primaryBindings, IASTName sourceName) { |
| List<IBinding> result= new ArrayList<IBinding>(); |
| String[] sourceQualifiedName= null; |
| int funcArgCount= -1; |
| if (sourceName != null) { |
| final IBinding binding = sourceName.resolveBinding(); |
| if (binding != null) { |
| sourceQualifiedName= CPPVisitor.getQualifiedName(binding); |
| if (binding instanceof ICPPUnknownBinding) { |
| LookupData data= CPPSemantics.createLookupData(sourceName, false); |
| if (data.isFunctionCall()) { |
| funcArgCount= data.getFunctionArgumentCount(); |
| } |
| } |
| } |
| } |
| |
| for (Iterator<IBinding> iterator = primaryBindings.iterator(); iterator.hasNext();) { |
| IBinding binding = iterator.next(); |
| if (sourceQualifiedName != null) { |
| String[] qualifiedName = CPPVisitor.getQualifiedName(binding); |
| if (!Arrays.equals(qualifiedName, sourceQualifiedName)) { |
| iterator.remove(); |
| continue; |
| } |
| } |
| if (funcArgCount != -1) { |
| // For c++ we can check the number of parameters. |
| if (binding instanceof ICPPFunction) { |
| ICPPFunction f= (ICPPFunction) binding; |
| try { |
| if (f.getRequiredArgumentCount() > funcArgCount) { |
| iterator.remove(); |
| result.add(binding); |
| continue; |
| } |
| if (!f.takesVarArgs() && !f.hasParameterPack()) { |
| final IType[] parameterTypes = f.getType().getParameterTypes(); |
| int maxArgs= parameterTypes.length; |
| if (maxArgs == 1 && SemanticUtil.isVoidType(parameterTypes[0])) { |
| maxArgs= 0; |
| } |
| if (maxArgs < funcArgCount) { |
| iterator.remove(); |
| result.add(binding); |
| continue; |
| } |
| } |
| } catch (DOMException e) { |
| // Ignore problem bindings. |
| continue; |
| } |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| } |