diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index bc4af461f03..13ab69ba355 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -26,8 +26,10 @@ import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; +import org.eclipse.cdt.core.dom.ast.IASTImplicitName; 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.IASTProblemStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; @@ -5116,4 +5118,26 @@ public class AST2TemplateTests extends AST2BaseTest { final String code= getAboveComment(); parseAndCheckBindings(code); } + + // template struct OutStream { + // OutStream& operator<<(OutStream& (*__pf)(OutStream&)); + // }; + // template OutStream<_CharT>& endl(OutStream<_CharT>& __os); + // + // void test() { + // OutStream out; + // out << endl; + // } + public void testInstantiationOfEndl_297457() throws Exception { + final String code= getAboveComment(); + IASTTranslationUnit tu= parseAndCheckBindings(code); + final IASTNodeSelector nodeSelector = tu.getNodeSelector(null); + + IASTName methodName= nodeSelector.findEnclosingName(code.indexOf("operator<<"), 1); + IASTImplicitName name = nodeSelector.findImplicitName(code.indexOf("<< endl"), 2); + + final IBinding method = methodName.resolveBinding(); + final IBinding reference = name.resolveBinding(); + assertSame(method, ((ICPPSpecialization) reference).getSpecializedBinding()); + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBindingResolutionTestBase.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBindingResolutionTestBase.java index 559d5d7662c..1a41e225ac5 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBindingResolutionTestBase.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBindingResolutionTestBase.java @@ -18,6 +18,7 @@ import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunctionType; @@ -81,7 +82,13 @@ public abstract class IndexBindingResolutionTestBase extends BaseTestCase { protected IASTName findName(String section, int len) { IASTTranslationUnit ast = strategy.getAst(); - return ast.getNodeSelector(null).findName(strategy.getTestData()[1].indexOf(section), len); + final IASTNodeSelector nodeSelector = ast.getNodeSelector(null); + final int offset = strategy.getTestData()[1].indexOf(section); + IASTName name= nodeSelector.findName(offset, len); + if (name == null) + name= nodeSelector.findImplicitName(offset, len); + + return name; } /** diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java index 01a2b7bc090..4e2157f4972 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java @@ -1780,4 +1780,19 @@ public class IndexCPPTemplateResolutionTest extends IndexBindingResolutionTestBa inst = getBindingFromASTName("g(1)", 1); assertTrue(inst.isExplicitSpecialization()); } + + // template struct OutStream { + // OutStream& operator<<(OutStream& (*__pf)(OutStream&)); + // }; + // template OutStream<_CharT>& endl(OutStream<_CharT>& __os); + + // void test() { + // OutStream out; + // out << endl; + // } + public void testInstantiationOfEndl_297457() throws Exception { + final IBinding reference = getBindingFromASTName("<< endl", 2); + assertTrue(reference instanceof ICPPSpecialization); + } + } 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 6cfdd585447..685acf9098d 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 @@ -1906,7 +1906,7 @@ public class CPPSemantics { if (type == null) { type = temp; } else if (!type.equals(temp)) { - int c = compareByRelevance(data, type, temp); + int c = compareByRelevance(data.tu, type, temp); if (c < 0) { type= temp; } else if (c == 0) { @@ -1927,7 +1927,7 @@ public class CPPSemantics { } else if (obj == temp) { // Ok, delegates are synonyms. } else { - int c = compareByRelevance(data, obj, temp); + int c = compareByRelevance(data.tu, obj, temp); if (c < 0) { obj= temp; } else if (c == 0) { @@ -1966,7 +1966,7 @@ public class CPPSemantics { if (obj != null && type != null) { if (obj instanceof ICPPNamespace) { - if (compareByRelevance(data, type, obj) >= 0) { + if (compareByRelevance(data.tu, type, obj) >= 0) { obj= null; } } else if (!data.typesOnly && overrulesByRelevance(data, type, obj)) { @@ -2019,16 +2019,16 @@ public class CPPSemantics { * the two bindings have the same relevance; -1 if b1 is less relevant than * b2. */ - static int compareByRelevance(LookupData data, IBinding b1, IBinding b2) { + static int compareByRelevance(IASTTranslationUnit tu, 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 != null && data.tu != null) { - boolean b1Reachable= isReachableFromAst(data.tu, b1); - boolean b2Reachable= isReachableFromAst(data.tu, b2); + if (tu != null) { + boolean b1Reachable= isReachableFromAst(tu, b1); + boolean b2Reachable= isReachableFromAst(tu, b2); if (b1Reachable != b2Reachable) { return b1Reachable ? 1 : -1; } @@ -2357,7 +2357,7 @@ public class CPPSemantics { potentialCosts.add(fnCost); continue; } - int cmp= fnCost.compareTo(data, bestFnCost); + int cmp= fnCost.compareTo(data.tu, bestFnCost); if (cmp < 0) { bestFnCost= fnCost; ambiguousFunctions= null; @@ -2369,7 +2369,7 @@ public class CPPSemantics { if (potentialCosts != null) { for (FunctionCost fnCost : potentialCosts) { if (!fnCost.mustBeWorse(bestFnCost) && fnCost.performUDC()) { - int cmp= fnCost.compareTo(data, bestFnCost); + int cmp= fnCost.compareTo(data.tu, bestFnCost); if (cmp < 0) { bestFnCost= fnCost; ambiguousFunctions= null; @@ -2765,6 +2765,8 @@ public class CPPSemantics { // Second pass, consider templates ICPPFunction result= null; ICPPFunctionTemplate resultTemplate= null; + boolean isAmbiguous= false; + final IASTTranslationUnit tu= name.getTranslationUnit(); for (IFunction fn : fns) { try { if (fn instanceof ICPPFunctionTemplate) { @@ -2774,10 +2776,14 @@ public class CPPSemantics { int cmp= -1; if (result != null) { cmp= CPPTemplates.orderTemplateFunctions(resultTemplate, template); - if (cmp == 0) - return null; + if (cmp == 0) + cmp= compareByRelevance(tu, resultTemplate, template); } + if (cmp == 0) + isAmbiguous= true; + if (cmp < 0) { + isAmbiguous= false; resultTemplate= template; result= inst; } @@ -2786,6 +2792,9 @@ public class CPPSemantics { } catch (DOMException e) { } } + if (isAmbiguous) + return null; + return result; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java index 55c33b2d906..028a017deae 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java @@ -14,6 +14,7 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IType; @@ -115,7 +116,7 @@ class FunctionCost { /** * Compares this function call cost to another one. */ - public int compareTo(LookupData data, FunctionCost other) throws DOMException { + public int compareTo(IASTTranslationUnit tu, FunctionCost other) throws DOMException { if (other == null) return -1; @@ -163,7 +164,7 @@ class FunctionCost { // if we are ambiguous at this point prefer non-index bindings if (haveBetter == haveWorse) { - return -CPPSemantics.compareByRelevance(data, getFunction(), other.getFunction()); + return -CPPSemantics.compareByRelevance(tu, getFunction(), other.getFunction()); } if (haveBetter)