diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java index d9fc8c3fea1..7b7a0d9d916 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java @@ -1907,7 +1907,7 @@ public class IndexBugsTests extends BaseTestCase { // a.i = 0; // a.j = 0; // } - public void _testDisambiguationByReachability_268704_1() throws Exception { + public void testDisambiguationByReachability_268704_1() throws Exception { waitForIndexer(); String[] testData = getContentsForTest(4); @@ -1948,7 +1948,7 @@ public class IndexBugsTests extends BaseTestCase { // #include "b.h" // int i = e; - public void _testDisambiguationByReachability_268704_2() throws Exception { + public void testDisambiguationByReachability_268704_2() throws Exception { waitForIndexer(); String[] testData = getContentsForTest(4); @@ -1972,45 +1972,4 @@ public class IndexBugsTests extends BaseTestCase { index.releaseReadLock(); } } - - // // a.h - // namespace ns { namespace ns2 { - // enum E { e = 1 }; - // }} - // using namespace ns::ns2; - - // #include "a.h" - // E i = e; - - // // b.h - // enum E { e = 2 }; - - // #include "b.h" - // E i = e; - public void _testDisambiguationByReachability_268704_3() throws Exception { - waitForIndexer(); - - String[] testData = getContentsForTest(4); - TestSourceReader.createFile(fCProject.getProject(), "a.h", testData[0]); - IFile a = TestSourceReader.createFile(fCProject.getProject(), "a.cpp", testData[1]); - TestSourceReader.createFile(fCProject.getProject(), "b.h", testData[2]); - IFile b = TestSourceReader.createFile(fCProject.getProject(), "b.cpp", testData[3]); - final IIndexManager indexManager = CCorePlugin.getIndexManager(); - indexManager.reindex(fCProject); - waitForIndexer(); - IIndex index= indexManager.getIndex(fCProject); - index.acquireReadLock(); - try { - BindingAssertionHelper aHelper = new BindingAssertionHelper(a, testData[1], index); - aHelper.assertNonProblem("E i", 1, IEnumeration.class); - IEnumerator e1 = aHelper.assertNonProblem("e;", 1, IEnumerator.class); - assertEquals(1, e1.getValue().numericalValue().longValue()); - BindingAssertionHelper bHelper = new BindingAssertionHelper(b, testData[3], index); - aHelper.assertNonProblem("E i", 1, IEnumeration.class); - IEnumerator e2 = bHelper.assertNonProblem("e;", 1, IEnumerator.class); - assertEquals(2, e2.getValue().numericalValue().longValue()); - } finally { - index.releaseReadLock(); - } - } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFileSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFileSet.java index aa82e44da17..2fcee3e6f0a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFileSet.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFileSet.java @@ -7,6 +7,7 @@ * * Contributors: * Markus Schorn - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.core.index; @@ -29,6 +30,13 @@ public interface IIndexFileSet { */ boolean contains(IIndexFile file) throws CoreException; + /** + * Returns true if this file set contains a declaration or definition of + * the given binding. + * @since 5.1 + */ + boolean containsDeclaration(IIndexBinding binding); + /** * Returns an array of bindings where all local bindings that are not part of this file-set * have been removed. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 7d8403bc9d2..ee8f2d3e62a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -1843,37 +1843,30 @@ public class CPPSemantics { if (type == null) { type = temp; } else if (type != temp) { - boolean i1= isFromIndex(type); - boolean i2= isFromIndex(temp); - if (i1 != i2) { - // prefer non-index bindings - if (i1) - type= temp; - } else { - if (((IType)type).isSameType((IType) temp)) { + int c = compareByRelevance(data, type, temp); + if (c < 0) { + type= temp; + } else if (c == 0) { + if (((IType) type).isSameType((IType) temp)) { if (type instanceof ITypedef && !(temp instanceof ITypedef)) { - // prefer non-typedefs + // Between same types prefer non-typedef. type= temp; } } else { return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP); } - } + } } } else { if (obj == null) { obj = temp; } else if (obj == temp) { - //ok, delegates are synonyms + // Ok, delegates are synonyms. } else { - // ignore index stuff in case we have bindings from the ast - boolean ibobj= isFromIndex(obj); - boolean ibtemp= isFromIndex(temp); - // blame it on the index - if (ibobj != ibtemp) { - if (ibobj) - obj= temp; - } else { + int c = compareByRelevance(data, obj, temp); + if (c < 0) { + obj= temp; + } else if (c == 0) { return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP); } } @@ -1917,6 +1910,36 @@ public class CPPSemantics { return type; } + /** + * Compares two bindings for relevance in the context of an AST. AST bindings are + * considered more relevant than index ones since the index may be out of date, + * built for a different configuration, etc. Index bindings reachable through includes + * are more relevant than unreachable ones. + * @param ast + * @param b1 + * @param b2 + * @return 1 if binding b1 is more relevant than b2; 0 if + * the two bindings have the same relevance; -1 if b1 is less relevant than + * b2. + */ + private static int compareByRelevance(LookupData data, IBinding b1, IBinding b2) { + boolean b1FromIndex= isFromIndex(b1); + boolean b2FromIndex= isFromIndex(b2); + if (b1FromIndex != b2FromIndex) { + return !b1FromIndex ? 1 : -1; + } else if (b1FromIndex) { + // Both are from index. + if (data.tu != null) { + boolean b1Reachable= isReachableFromAst(data.tu, b1); + boolean b2Reachable= isReachableFromAst(data.tu, b2); + if (b1Reachable != b2Reachable) { + return b1Reachable ? 1 : -1; + } + } + } + return 0; + } + private static boolean isFromIndex(IBinding binding) { if (binding instanceof IIndexBinding) { return true; @@ -1926,7 +1949,32 @@ public class CPPSemantics { } return false; } - + + /** + * Checks if a binding belongs to an AST or is reachable from it through includes. + * @param ast + * @param binding + * @return true if the binding is reachable from ast. + */ + private static boolean isReachableFromAst(IASTTranslationUnit ast, IBinding binding) { + IIndexBinding indexBinding = null; + if (binding instanceof IIndexBinding) { + indexBinding = (IIndexBinding) binding; + } + if (binding instanceof ICPPSpecialization) { + binding = ((ICPPSpecialization) binding).getSpecializedBinding(); + if (binding instanceof IIndexBinding) { + indexBinding = (IIndexBinding) binding; + } + } + if (indexBinding != null) { + IIndexFileSet indexFileSet = ast.getIndexFileSet(); + return indexFileSet != null && indexFileSet.containsDeclaration(indexBinding); + } else { + return ast.getDeclarationsInAST(binding).length != 0; + } + } + static private void reduceToViable(LookupData data, IBinding[] functions) throws DOMException { if (functions == null || functions.length == 0) return; @@ -2142,14 +2190,19 @@ public class CPPSemantics { } } - // if we are ambiguous at this point prefer non-index bindings + // Ff we are ambiguous at this point, prefer a non-index binding or reachable index one. if (hasBetter == hasWorse) { - final boolean bestIsFromIndex= isFromIndex(bestFn); - final boolean currIsFromIndex= isFromIndex(fn); - if (bestIsFromIndex != currIsFromIndex) { - hasBetter= bestIsFromIndex; - hasWorse= currIsFromIndex; + int c = compareByRelevance(data, bestFn, fn); + if (c != 0) { + hasBetter = (c < 0); + hasWorse = !hasBetter; } +// final boolean bestIsFromIndex= isFromIndex(bestFn); +// final boolean currIsFromIndex= isFromIndex(fn); +// if (bestIsFromIndex != currIsFromIndex) { +// hasBetter= bestIsFromIndex; +// hasWorse= currIsFromIndex; +// } } // If function has a parameter match that is better than the current best, @@ -2356,14 +2409,21 @@ public class CPPSemantics { ft = e.getProblem(); } if (type.isSameType(ft)) { - if (result != null) { - boolean fromIndex= isFromIndex(fn); - if (isFromIndex(result) == fromIndex) - return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP); - if (!fromIndex) + if (result == null) { + result = fn; + } else { + int c = compareByRelevance(data, result, fn); + if (c < 0) { result= fn; + } else if (c == 0) { + return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP); + } +// boolean fromIndex= isFromIndex(fn); +// if (isFromIndex(result) == fromIndex) +// return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP); +// if (!fromIndex) +// result= fn; } - result = fn; } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexFileSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexFileSet.java index 78220069169..1a5c9af86bc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexFileSet.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexFileSet.java @@ -12,9 +12,11 @@ package org.eclipse.cdt.internal.core.index; import java.util.BitSet; import java.util.HashMap; +import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.core.runtime.CoreException; @@ -37,6 +39,26 @@ public class IndexFileSet implements IIndexFileSet { subSet.add(fragFile); } + public boolean containsDeclaration(IIndexBinding binding) { + for (Map.Entry entry : fSubSets.entrySet()) { + try { + IIndexFragmentName[] names = + entry.getKey().findNames(binding, IIndexFragment.FIND_DECLARATIONS_DEFINITIONS); + for (IIndexFragmentName name : names) { + try { + if (entry.getValue().contains((IIndexFragmentFile) name.getFile())) { + return true; + } + } catch (CoreException e) { + CCorePlugin.log(e); + } + } + } catch (CoreException e) { + CCorePlugin.log(e); + } + } + return false; + } public IBinding[] filterFileLocalBindings(IBinding[] bindings) { if (bindings == null || bindings.length == 0) {