diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ASTComparer.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ASTComparer.java index 2af63f30a0d..49e36dddf9b 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ASTComparer.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ASTComparer.java @@ -48,7 +48,9 @@ public class ASTComparer extends Assert { // avoid name resolution "isDeclaration", "isDefinition", - "isReference" + "isReference", + "isAssociatedWithLastName", + "getNestingLevel" )); 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 ee85cd65de3..7a26e205353 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 @@ -3858,4 +3858,39 @@ public class AST2TemplateTests extends AST2BaseTest { bh.assertNonProblem("getline2(i)", 8, ICPPTemplateInstance.class); parseAndCheckBindings(code, ParserLanguage.CPP); } + + // class C { + // friend int f1(int); + // }; + // template class CT { + // template friend int f2(S); + // }; + // template class C1 { + // template class C2 { + // template class C3 { + // }; + // }; + // }; + public void testOwnerOfFriendTemplate_265671() throws Exception { + final String code = getAboveComment(); + BindingAssertionHelper bh= new BindingAssertionHelper(code, true); + IFunction f= bh.assertNonProblem("f1(", 2, IFunction.class); + IBinding owner= f.getOwner(); + assertNull(owner); + ICPPFunctionTemplate ft= bh.assertNonProblem("f2(", 2, ICPPFunctionTemplate.class); + owner= f.getOwner(); + assertNull(owner); + ICPPTemplateParameter tpar= ft.getTemplateParameters()[0]; + assertEquals(0, tpar.getTemplateNestingLevel()); + + tpar= bh.assertNonProblem("T1", 2, ICPPTemplateParameter.class); + assertEquals(0, tpar.getTemplateNestingLevel()); + tpar= bh.assertNonProblem("T2", 2, ICPPTemplateParameter.class); + assertEquals(1, tpar.getTemplateNestingLevel()); + tpar= bh.assertNonProblem("T3", 2, ICPPTemplateParameter.class); + assertEquals(2, tpar.getTemplateNestingLevel()); + + parseAndCheckBindings(code, ParserLanguage.CPP); + } + } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateParameter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateParameter.java index dcafeb96e4e..2687697d9b5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateParameter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateParameter.java @@ -57,6 +57,7 @@ public abstract class CPPTemplateParameter extends PlatformObject if (tps == null) { tps= tdecl.getTemplateParameters(); } + break; } else if (node instanceof ICPPASTTemplatedTypeTemplateParameter) { nesting++; if (tps == null) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java index 08f9d3caebe..77fb357247a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java @@ -1068,18 +1068,18 @@ public class CPPTemplates { } // determine nesting level of parent - int level= 0; - node= outerMostTDecl.getParent(); - while (node != null) { - if (node instanceof ICPPASTInternalTemplateDeclaration) { - level= ((ICPPASTInternalTemplateDeclaration) node).getNestingLevel() + 1; - break; + int level= additionalLevels; + if (!CPPVisitor.isFriendFunctionDeclaration(innerMostTDecl.getDeclaration())) { + node= outerMostTDecl.getParent(); + while (node != null) { + if (node instanceof ICPPASTInternalTemplateDeclaration) { + level+= ((ICPPASTInternalTemplateDeclaration) node).getNestingLevel() + 1; + break; + } + node= node.getParent(); } - node= node.getParent(); } - level += additionalLevels; - tdecl= outerMostTDecl; while(true) { tdecl.setNestingLevel((short) level++); 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 9b4f56d06d9..7d9dca0440a 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 @@ -2010,6 +2010,14 @@ public class CPPVisitor extends ASTQueries { node= node.getParent(); } + boolean isFriend= false; + if (node instanceof IASTSimpleDeclaration) { + ICPPASTDeclSpecifier declSpec= (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration) node).getDeclSpecifier(); + if (declSpec.isFriend()) { + isFriend= true; + } + } + // Search for enclosing binding IASTName name= null; node= node.getParent(); @@ -2025,6 +2033,8 @@ public class CPPVisitor extends ASTQueries { break; } if (node instanceof IASTCompositeTypeSpecifier) { + if (isFriend) + continue; name= ((IASTCompositeTypeSpecifier) node).getName(); break; } @@ -2038,4 +2048,24 @@ public class CPPVisitor extends ASTQueries { return name.resolveBinding(); } + + /** + * Check whether a given declaration is a friend function declaration. + */ + public static boolean isFriendFunctionDeclaration(IASTDeclaration declaration) { + while (declaration instanceof ICPPASTTemplateDeclaration) { + declaration= ((ICPPASTTemplateDeclaration) declaration).getDeclaration(); + } + if (declaration instanceof IASTSimpleDeclaration) { + IASTSimpleDeclaration sdecl = (IASTSimpleDeclaration) declaration; + ICPPASTDeclSpecifier declspec= (ICPPASTDeclSpecifier) sdecl.getDeclSpecifier(); + if (declspec.isFriend()) { + IASTDeclarator[] dtors= sdecl.getDeclarators(); + if (dtors.length == 1 && findTypeRelevantDeclarator(dtors[0]) instanceof IASTFunctionDeclarator) { + return true; + } + } + } + return false; + } }