From 86c3d8eecaca52f0e6ecbfeeaf1b708bb83ab13c Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Wed, 11 Oct 2017 01:01:13 -0400 Subject: [PATCH] Bug 525739 - Have Open Declaration find potentially-matching definitions for a declaration The implementation strategy is as follows: - Implement an option to find potential matches during an AST definition search. - Store names that resolve to ProblemBindings in the index, as references for the candidate bindings, annotated as being potential matches. - Add an option to Index.findNames() to include potential matches. - Use the added options for the index and AST searches in OpenDeclarationsJob, prioritizing them accordingly (e.g. exact index matches take precedence over potential AST matches, but if there are no exact matches, potential matches from the AST and the index are combined). Change-Id: I19f5c58820eb3ec79a31652d69fd5b86acaba115 --- .../cdt/core/dom/ast/IASTTranslationUnit.java | 12 +++++- .../org/eclipse/cdt/core/index/IIndex.java | 10 ++++- .../eclipse/cdt/core/index/IIndexName.java | 8 ++++ .../dom/parser/c/CASTTranslationUnit.java | 8 +++- .../dom/parser/cpp/CPPASTTranslationUnit.java | 9 +++- .../dom/parser/cpp/semantics/CPPVisitor.java | 26 +++++++++-- .../internal/core/index/IIndexFragment.java | 6 ++- .../eclipse/cdt/internal/core/pdom/PDOM.java | 9 ++-- .../cdt/internal/core/pdom/dom/PDOMFile.java | 21 ++++++++- .../pdom/dom/PDOMMacroDefinitionName.java | 5 +++ .../core/pdom/dom/PDOMMacroReferenceName.java | 5 +++ .../cdt/internal/core/pdom/dom/PDOMName.java | 21 ++++++++- .../selection/CPPSelectionTestsIndexer.java | 43 +++++++++++++++++++ .../selection/CPPSelectionTestsNoIndexer.java | 15 +++++++ .../search/actions/OpenDeclarationsJob.java | 43 ++++++++++++++++--- 15 files changed, 218 insertions(+), 23 deletions(-) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java index b748c474160..731f1b951de 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java @@ -117,15 +117,25 @@ public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomi */ public IName[] getDefinitions(IBinding binding); + /** + * Equivalent to getDefinitionsInAst(binding, false). + */ + public IASTName[] getDefinitionsInAST(IBinding binding); + /** * Returns the array of definitions in this translation unit for the given binding. * The array contains the IASTName nodes that define the binding. * These are part of the AST, no definitions are pulled in from the index. * + * If 'permissive' is true, definitions that are not exact matches (for example, + * a method definition with a non-matching signature) are also returned. + * * @param binding + * @param permissive * @return Array of IASTName nodes for the binding's declaration + * @since 6.4 */ - public IASTName[] getDefinitionsInAST(IBinding binding); + public IASTName[] getDefinitionsInAST(IBinding binding, boolean permissive); /** * Returns the list of references in this translation unit to the given diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java index 450bfd4231c..472d150b289 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java @@ -64,6 +64,13 @@ public interface IIndex { * the c-linkage. */ final int SEARCH_ACROSS_LANGUAGE_BOUNDARIES= 0x8; + /** + * Constant to include potential matches in the results of a search. + * An example of a potential match might be a function definition that does match + * a declaration exactly in signature. + * @since 6.4 + */ + final int FIND_POTENTIAL_MATCHES = 0x10; /** * Constant to search for all declarations including definitions. */ @@ -387,7 +394,8 @@ public interface IIndex { * * @param binding a binding for which names are searched for * @param flags a combination of {@link #FIND_DECLARATIONS}, {@link #FIND_DEFINITIONS}, - * {@link #FIND_REFERENCES} and {@link #SEARCH_ACROSS_LANGUAGE_BOUNDARIES}. + * {@link #FIND_REFERENCES}, {@link #SEARCH_ACROSS_LANGUAGE_BOUNDARIES}, and + * {@link #FIND_POTENTIAL_MATCHES}. * @return an array of names * @throws CoreException */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexName.java index 465feb354a9..ebe96542b8d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexName.java @@ -69,6 +69,14 @@ public interface IIndexName extends IName { */ public boolean couldBePolymorphicMethodCall() throws CoreException; + /** + * Returns whether this name is a potential match for its binding, rather than an exact match. + * An example of a potential match might be a function definition that does match a + * declaration exactly in signature. + * @since 6.4 + */ + public boolean isPotentialMatch() throws CoreException; + /** * Returns whether this name specifies an inline namespace. * @since 5.3 diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTTranslationUnit.java index 7f510904e9e..cb66a98d628 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTTranslationUnit.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTTranslationUnit.java @@ -67,11 +67,17 @@ public class CASTTranslationUnit extends ASTTranslationUnit implements IASTAmbig return CVisitor.getDeclarations(this, binding); } - @Override + @Override public IASTName[] getDefinitionsInAST(IBinding binding) { + return getDefinitionsInAST(binding, false); + } + + @Override + public IASTName[] getDefinitionsInAST(IBinding binding, boolean permissive) { if (binding instanceof IMacroBinding) { return getMacroDefinitionsInAST((IMacroBinding) binding); } + // TODO: Implement support for permissive=true. IASTName[] names = CVisitor.getDeclarations(this, binding); for (int i = 0; i < names.length; i++) { if (!names[i].isDefinition()) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java index 81199682052..9ff0ec7ae5c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java @@ -130,11 +130,16 @@ public class CPPASTTranslationUnit extends ASTTranslationUnit implements ICPPAST } @Override - public IASTName[] getDefinitionsInAST(IBinding binding) { + public IASTName[] getDefinitionsInAST(IBinding binding) { + return getDefinitionsInAST(binding, false); + } + + @Override + public IASTName[] getDefinitionsInAST(IBinding binding, boolean permissive) { if (binding instanceof IMacroBinding) { return getMacroDefinitionsInAST((IMacroBinding) binding); } - IASTName[] names = CPPVisitor.getDeclarations(this, binding); + IASTName[] names = CPPVisitor.getDeclarations(this, binding, permissive); for (int i = 0; i < names.length; i++) { if (!names[i].isDefinition()) names[i] = null; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index 4ccbc5f2741..3bc98035370 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -1508,6 +1508,7 @@ public class CPPVisitor extends ASTQueries { private int kind; private char[] requiredName; private IIndex index; + private boolean permissive; private static final int KIND_LABEL = 1; private static final int KIND_OBJ_FN = 2; @@ -1516,10 +1517,11 @@ public class CPPVisitor extends ASTQueries { private static final int KIND_COMPOSITE = 5; private static final int KIND_TEMPLATE_PARAMETER = 6; - public CollectDeclarationsAction(IBinding binding) { + public CollectDeclarationsAction(IBinding binding, boolean permissive) { shouldVisitTranslationUnit = true; shouldVisitNames = true; this.decls = new IASTName[DEFAULT_LIST_SIZE]; + this.permissive = permissive; final String bname = binding.getName(); if (bname.length() > 0 && !bname.startsWith("operator")) { //$NON-NLS-1$ @@ -1645,7 +1647,7 @@ public class CPPVisitor extends ASTQueries { private boolean isDeclarationBinding(IBinding nameBinding) { if (nameBinding != null) { for (IBinding binding : bindings) { - if (areEquivalentBindings(nameBinding, binding, index)) { + if (areEquivalentBindings(nameBinding, binding, index, permissive)) { return true; } // A using declaration is a declaration for the references of its delegates. @@ -1667,6 +1669,20 @@ public class CPPVisitor extends ASTQueries { } } + private static boolean areEquivalentBindings(IBinding candidate, IBinding target, IIndex index, + boolean permissive) { + if (permissive && candidate instanceof IProblemBinding && !(target instanceof IProblemBinding)) { + IProblemBinding problem = (IProblemBinding) candidate; + for (IBinding c : problem.getCandidateBindings()) { + if (areEquivalentBindings(c, target, index)) { + return true; + } + } + return false; + } + return areEquivalentBindings(candidate, target, index); + } + private static boolean areEquivalentBindings(IBinding binding1, IBinding binding2, IIndex index) { if (binding1.equals(binding2)) { return true; @@ -2759,7 +2775,11 @@ public class CPPVisitor extends ASTQueries { } public static IASTName[] getDeclarations(IASTTranslationUnit tu, IBinding binding) { - CollectDeclarationsAction action = new CollectDeclarationsAction(binding); + return getDeclarations(tu, binding, false); + } + + public static IASTName[] getDeclarations(IASTTranslationUnit tu, IBinding binding, boolean permissive) { + CollectDeclarationsAction action = new CollectDeclarationsAction(binding, permissive); tu.accept(action); IASTName[] found = action.getDeclarations(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java index b765e822361..6239ac0b992 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java @@ -49,6 +49,10 @@ public interface IIndexFragment { * @see IIndex#SEARCH_ACROSS_LANGUAGE_BOUNDARIES */ final int SEARCH_ACROSS_LANGUAGE_BOUNDARIES = IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES; + /** + * @see IIndex#FIND_POTENTIAL_MATCHES + */ + final int FIND_POTENTIAL_MATCHES = IIndex.FIND_POTENTIAL_MATCHES; /** * @see IIndex#FIND_DECLARATIONS_DEFINITIONS */ @@ -210,7 +214,7 @@ public interface IIndexFragment { * references, declarations or definitions, or a combination of those. * @param binding a binding for which names are searched for * @param flags a combination of {@link #FIND_DECLARATIONS}, {@link #FIND_DEFINITIONS}, - * {@link #FIND_REFERENCES} and {@link #FIND_NON_LOCAL_ONLY} + * {@link #FIND_REFERENCES}, {@link #FIND_NON_LOCAL_ONLY}, and {@link #FIND_POTENTIAL_MATCHES}. * @return an array of names * @throws CoreException */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index d2b3b725c68..c99dccbdd56 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -1234,27 +1234,28 @@ public class PDOM extends PlatformObject implements IPDOM { PDOMName name; if ((options & FIND_DECLARATIONS) != 0) { for (name= pdomBinding.getFirstDeclaration(); name != null; name= name.getNextInBinding()) { - if (isCommitted(name)) { + if (isCommitted(name) && !name.isPotentialMatch()) { names.add(name); } } } if ((options & FIND_DEFINITIONS) != 0) { for (name = pdomBinding.getFirstDefinition(); name != null; name= name.getNextInBinding()) { - if (isCommitted(name)) { + boolean findPotentialMatches = (options & FIND_POTENTIAL_MATCHES) != 0; + if (isCommitted(name) && (!name.isPotentialMatch() || findPotentialMatches)) { names.add(name); } } } if ((options & FIND_REFERENCES) != 0) { for (name = pdomBinding.getFirstReference(); name != null; name= name.getNextInBinding()) { - if (isCommitted(name)) { + if (isCommitted(name) && !name.isPotentialMatch()) { names.add(name); } } for (IPDOMIterator iterator = pdomBinding.getExternalReferences(); iterator.hasNext();) { name = iterator.next(); - if (isCommitted(name)) + if (isCommitted(name) && !name.isPotentialMatch()) names.add(name); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java index c10eb66bb56..57b095fcd7d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java @@ -29,6 +29,7 @@ import org.eclipse.cdt.core.dom.ast.IASTPreprocessorUndefStatement; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IMacroBinding; import org.eclipse.cdt.core.dom.ast.IParameter; +import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.index.IIndexInclude; @@ -514,9 +515,27 @@ public class PDOMFile implements IIndexFragmentFile { } PDOMBinding pdomBinding = linkage.addBinding(name); if (pdomBinding != null) { - final PDOMName result= new PDOMName(fLinkage, name, this, pdomBinding, caller); + final PDOMName result= new PDOMName(fLinkage, name, this, pdomBinding, caller, + false /* exact match */); linkage.onCreateName(this, name, result); return result; + } else { + IBinding b = name.resolveBinding(); + if (b instanceof IProblemBinding) { + IIndexFragmentName result = null; + for (IBinding candidate : ((IProblemBinding) b).getCandidateBindings()) { + pdomBinding = linkage.adaptBinding(candidate); + if (pdomBinding != null) { + final PDOMName pdomName = new PDOMName(fLinkage, name, this, pdomBinding, caller, + true /* potential match */); + linkage.onCreateName(this, name, pdomName); + if (result == null) { + result = pdomName; + } + } + } + return result; + } } } catch (CoreException e) { final IStatus status = e.getStatus(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroDefinitionName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroDefinitionName.java index 52481198ff5..1c0ee690c2d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroDefinitionName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroDefinitionName.java @@ -33,6 +33,11 @@ class PDOMMacroDefinitionName implements IIndexFragmentName { public boolean couldBePolymorphicMethodCall() throws CoreException { return false; } + + @Override + public boolean isPotentialMatch() throws CoreException { + return false; + } @Override public IIndexName[] getEnclosedNames() throws CoreException { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java index e8f25631521..65a11e802a9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacroReferenceName.java @@ -172,6 +172,11 @@ public final class PDOMMacroReferenceName implements IIndexFragmentName { public boolean couldBePolymorphicMethodCall() throws CoreException { return false; } + + @Override + public boolean isPotentialMatch() throws CoreException { + return false; + } @Override public boolean isInlineNamespaceDefinition() { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java index ba7dcb2511f..f1ea800f77f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMName.java @@ -56,9 +56,17 @@ public final class PDOMName implements IIndexFragmentName { public static final int COULD_BE_POLYMORPHIC_METHOD_CALL = 0x10; public static final int READ_ACCESS = 0x20; public static final int WRITE_ACCESS = 0x40; + // Whether this name is a potential match for its binding, rather than an exact match. + // Potential matches are recorded in the index so that we can e.g. offer best-effort + // navigation even in the presence of errors in the code (or an incomplete project + // configuration), but they are annotated as such so exact matches can be preferred + // where appropriate. + public static final int IS_POTENTIAL_MATCH = 0x80; + // Note: There is no room in the flags byte for more flags. If more flags are + // needed, the flag byte needs to be expanded to a short. - public PDOMName(PDOMLinkage linkage, IASTName name, PDOMFile file, PDOMBinding binding, PDOMName caller) - throws CoreException { + public PDOMName(PDOMLinkage linkage, IASTName name, PDOMFile file, PDOMBinding binding, PDOMName caller, + boolean isPotentialMatch) throws CoreException { this.linkage = linkage; Database db = linkage.getDB(); record = db.malloc(RECORD_SIZE); @@ -66,6 +74,10 @@ public final class PDOMName implements IIndexFragmentName { // What kind of name are we int flags= getRoleOfName(name); + if (isPotentialMatch) { + flags |= IS_POTENTIAL_MATCH; + } + flags |= binding.getAdditionalNameFlags(flags, name); db.putByte(record + FLAGS, (byte) flags); @@ -285,6 +297,11 @@ public final class PDOMName implements IIndexFragmentName { public boolean couldBePolymorphicMethodCall() throws CoreException { return getFlags(COULD_BE_POLYMORPHIC_METHOD_CALL) == COULD_BE_POLYMORPHIC_METHOD_CALL; } + + @Override + public boolean isPotentialMatch() throws CoreException { + return getFlags(IS_POTENTIAL_MATCH) == IS_POTENTIAL_MATCH; + } @Override public boolean isReadAccess() throws CoreException { diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java index cf2e1c2b2c1..520523db2a6 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsIndexer.java @@ -26,6 +26,7 @@ import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNameOwner; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IMacroBinding; @@ -1336,4 +1337,46 @@ public class CPPSelectionTestsIndexer extends BaseSelectionTestsIndexer { IASTNode def = testF3(file, offset + 1); assertTrue(def instanceof IASTName); } + + // class Waldo { + // void find(); + // }; + + // #include "test.hpp" + // int Waldo::find() {} + public void testNavigationToDefinitionWithWrongSignature_525739() throws Exception { + StringBuilder[] buffers = getContents(3); + String hpp = buffers[0].toString(); + String cpp = buffers[1].toString(); + IFile hppFile = importFile("test.hpp", hpp); + IFile cppFile = importFile("test.cpp", cpp); + waitUntilFileIsIndexed(index, cppFile); + + // We should find the definition, even though the signature doesn't match exactly. + IASTNode target = testF3(hppFile, hpp.indexOf("void find") + 6); + assertInstance(target, IASTName.class); + assertEquals(IASTNameOwner.r_definition, ((IASTName) target).getRoleOfName(false)); + } + + // class Waldo { + // void find(); + // }; + + // #include "test.hpp" + // void Waldo::find() {} + // int Waldo::find() {} + public void testNavigationPrefersCorrectDefinition_525739() throws Exception { + StringBuilder[] buffers = getContents(3); + String hpp = buffers[0].toString(); + String cpp = buffers[1].toString(); + IFile hppFile = importFile("test.hpp", hpp); + IFile cppFile = importFile("test.cpp", cpp); + waitUntilFileIsIndexed(index, cppFile); + + // We should find the definition that's an exact match, rather than asking the + // user to disambiguate between two alternatives. + IASTNode target = testF3(hppFile, hpp.indexOf("void find") + 6); + assertInstance(target, IASTName.class); + assertEquals(IASTNameOwner.r_definition, ((IASTName) target).getRoleOfName(false)); + } } diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java index 3542e6660d9..26f14de3f9c 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/selection/CPPSelectionTestsNoIndexer.java @@ -37,6 +37,7 @@ import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNameOwner; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; @@ -1402,4 +1403,18 @@ public class CPPSelectionTestsNoIndexer extends BaseSelectionTests { int offset = code.indexOf("auto") - 2; IASTNode target = testF3(file, offset); } + + // class Waldo { + // void find(); + // }; + // int Waldo::find() {} + public void testNavigationToDefinitionWithWrongSignature_525739() throws Exception { + String code = getAboveComment(); + IFile file = importFile("testBug525739.cpp", code); + + int offset = code.indexOf("void find") + 6; + IASTNode target = testF3(file, offset); + assertInstance(target, IASTName.class); + assertEquals(IASTNameOwner.r_definition, ((IASTName) target).getRoleOfName(false)); + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/OpenDeclarationsJob.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/OpenDeclarationsJob.java index 3f3fdb17253..1d434f07566 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/OpenDeclarationsJob.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/actions/OpenDeclarationsJob.java @@ -406,9 +406,15 @@ class OpenDeclarationsJob extends Job implements ASTRunnable { } private IName[] findDefinitions(IIndex index, IASTTranslationUnit ast, IBinding binding) throws CoreException { - List declNames= new ArrayList<>(); - declNames.addAll(Arrays.asList(ast.getDefinitionsInAST(binding))); - for (Iterator i = declNames.iterator(); i.hasNext();) { + // The priority of matches are as follows: + // - If there are exact AST matches, those are returned. + // - Otherwise, if there are exact index matches, those are returned. + // - Otherwise, permissive matches from the AST and index, if any, are + // combined and returned. + List exactAstMatches = new ArrayList<>(); + List permissiveMatches = new ArrayList<>(); + exactAstMatches.addAll(Arrays.asList(ast.getDefinitionsInAST(binding, /* permissive = */ true))); + for (Iterator i = exactAstMatches.iterator(); i.hasNext();) { IASTName name= i.next(); final IBinding b2 = name.resolveBinding(); if (b2 instanceof ICPPUsingDeclaration) { @@ -427,13 +433,36 @@ class OpenDeclarationsJob extends Job implements ASTRunnable { i.remove(); } } + if (b2 instanceof IProblemBinding) { + permissiveMatches.add(name); + i.remove(); + } } - if (!declNames.isEmpty()) { - return declNames.toArray(new IASTName[declNames.size()]); + if (!exactAstMatches.isEmpty()) { + return exactAstMatches.toArray(new IASTName[exactAstMatches.size()]); } - // 2. Try definition in index. - return index.findNames(binding, IIndex.FIND_DEFINITIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES); + // Try definition in index. + IName[] indexMatches = index.findNames(binding, IIndex.FIND_DEFINITIONS | + IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES | IIndex.FIND_POTENTIAL_MATCHES); + List exactIndexMatches = new ArrayList<>(); + exactIndexMatches.addAll(Arrays.asList(indexMatches)); + for (Iterator i = exactIndexMatches.iterator(); i.hasNext();) { + IName name = i.next(); + if (name instanceof IIndexName && ((IIndexName) name).isPotentialMatch()) { + permissiveMatches.add(name); + i.remove(); + } + } + if (!exactIndexMatches.isEmpty()) { + return exactIndexMatches.toArray(new IName[exactIndexMatches.size()]); + } + + if (!permissiveMatches.isEmpty()) { + return permissiveMatches.toArray(new IName[permissiveMatches.size()]); + } + + return IName.EMPTY_ARRAY; } private IName[] findDeclarations(IIndex index, IASTTranslationUnit ast, IBinding binding) throws CoreException {