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) {