diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecFailingTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecFailingTest.java index dbc5c58adc5..c15f2a5ea50 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecFailingTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecFailingTest.java @@ -41,39 +41,6 @@ public class AST2CPPSpecFailingTest extends AST2SpecBaseTest { } } - /** - [--Start Example(CPP 3.4.1-10): - struct A { - typedef int AT; - void f1(AT); - void f2(float); - }; - struct B { - typedef float BT; - friend void A::f1(AT); // parameter type is A::AT - friend void A::f2(BT); // parameter type is B::BT - }; - --End Example] - */ - public void test3_4_1s10() { // TODO raised bug 90609 - StringBuffer buffer = new StringBuffer(); - buffer.append("struct A {\n"); //$NON-NLS-1$ - buffer.append("typedef int AT;\n"); //$NON-NLS-1$ - buffer.append("void f1(AT);\n"); //$NON-NLS-1$ - buffer.append("void f2(float);\n"); //$NON-NLS-1$ - buffer.append("};\n"); //$NON-NLS-1$ - buffer.append("struct B {\n"); //$NON-NLS-1$ - buffer.append("typedef float BT;\n"); //$NON-NLS-1$ - buffer.append("friend void A::f1(AT); // parameter type is A::AT\n"); //$NON-NLS-1$ - buffer.append("friend void A::f2(BT); // parameter type is B::BT\n"); //$NON-NLS-1$ - buffer.append("};\n"); //$NON-NLS-1$ - try { - parse(buffer.toString(), ParserLanguage.CPP, true, 0); - assertTrue(false); - } catch (Exception e) { - } - } - /** [--Start Example(CPP 6.4-3): int foo() { diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java index 121d2ade43a..fc08ec7d7c4 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java @@ -447,6 +447,36 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { parse(buffer.toString(), ParserLanguage.CPP, true, 0); } + /** + [--Start Example(CPP 3.4.1-10): + struct A { + typedef int AT; + void f1(AT); + void f2(float); + }; + struct B { + typedef float BT; + friend void A::f1(AT); // parameter type is A::AT + friend void A::f2(BT); // parameter type is B::BT + }; + --End Example] + */ + public void test3_4_1s10() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("struct A {\n"); //$NON-NLS-1$ + buffer.append("typedef int AT;\n"); //$NON-NLS-1$ + buffer.append("void f1(AT);\n"); //$NON-NLS-1$ + buffer.append("void f2(float);\n"); //$NON-NLS-1$ + buffer.append("};\n"); //$NON-NLS-1$ + buffer.append("struct B {\n"); //$NON-NLS-1$ + buffer.append("typedef float BT;\n"); //$NON-NLS-1$ + buffer.append("friend void A::f1(AT); // parameter type is A::AT\n"); //$NON-NLS-1$ + buffer.append("friend void A::f2(BT); // parameter type is B::BT\n"); //$NON-NLS-1$ + buffer.append("};\n"); //$NON-NLS-1$ + + parse(buffer.toString(), ParserLanguage.CPP, true, 0); + } + /** [--Start Example(CPP 3.4.2-2): namespace NS { @@ -12524,12 +12554,12 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { */ public void test8_5s2() throws ParserException { // 90641 StringBuffer buffer = new StringBuffer(); - buffer.append( "int z() { "); + buffer.append( "int z() { "); //$NON-NLS-1$ buffer.append("int f(int);\n"); //$NON-NLS-1$ buffer.append("int a = 2;\n"); //$NON-NLS-1$ buffer.append("int b = f(a);\n"); //$NON-NLS-1$ buffer.append("int c(b);\n"); //$NON-NLS-1$ - buffer.append( "}"); + buffer.append( "}"); //$NON-NLS-1$ parse(buffer.toString(), ParserLanguage.CPP, true, 0); } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index 36c54e4001b..a5c44956b22 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -4861,4 +4861,32 @@ public class AST2CPPTests extends AST2BaseTest { ICPPMethod f = (ICPPMethod) col.getName(3).resolveBinding(); assertSame( f, col.getName(6).resolveBinding() ); } + + public void testBug90609() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("struct A { \n"); //$NON-NLS-1$ + buffer.append(" typedef int AT; \n"); //$NON-NLS-1$ + buffer.append(" void f1(AT); \n"); //$NON-NLS-1$ + buffer.append(" void f2(float); \n"); //$NON-NLS-1$ + buffer.append("}; \n"); //$NON-NLS-1$ + buffer.append("struct B { \n"); //$NON-NLS-1$ + buffer.append(" typedef float BT; \n"); //$NON-NLS-1$ + buffer.append(" friend void A::f1(AT); \n"); //$NON-NLS-1$ + buffer.append(" friend void A::f2(BT); \n"); //$NON-NLS-1$ + buffer.append("}; \n"); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse(buffer.toString(), ParserLanguage.CPP, true, true ); + CPPNameCollector col = new CPPNameCollector(); + tu.accept( col ); + + ITypedef AT = (ITypedef) col.getName(1).resolveBinding(); + ICPPMethod f1 = (ICPPMethod) col.getName(2).resolveBinding(); + ICPPMethod f2 = (ICPPMethod) col.getName(5).resolveBinding(); + ITypedef BT = (ITypedef) col.getName(8).resolveBinding(); + + assertSame( f1, col.getName(11).resolveBinding() ); + assertSame( AT, col.getName(12).resolveBinding() ); + assertSame( f2, col.getName(16).resolveBinding() ); + assertSame( BT, col.getName(17).resolveBinding() ); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java index e7227ba4456..94c315192b5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java @@ -419,6 +419,47 @@ public class CPPSemantics { } return false; } + + public boolean checkAssociatedScopes() { + if( astName == null || astName instanceof ICPPASTQualifiedName ) + return false; + IASTNode parent = astName.getParent(); + if( parent instanceof ICPPASTQualifiedName ){ + IASTName [] ns = ((ICPPASTQualifiedName)parent).getNames(); + if( ns[ ns.length - 1] != astName ) + return false; + } + return functionCall() && (associated.size() > 0); + } + public boolean checkClassContainingFriend() { + if( astName == null || astName instanceof ICPPASTQualifiedName ) + return false; + + IASTNode p = astName.getParent(); + ASTNodeProperty prop = null; + while( p != null ){ + prop = p.getPropertyInParent(); + if( prop == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT || prop == IASTDeclarator.DECLARATOR_NAME ) + return false; + if( p instanceof IASTDeclarator && !(((IASTDeclarator)p).getName() instanceof ICPPASTQualifiedName) ) + return false; + if( p instanceof IASTDeclaration ){ + if( prop == IASTCompositeTypeSpecifier.MEMBER_DECLARATION ){ + if( p instanceof IASTSimpleDeclaration ){ + ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration)p).getDeclSpecifier(); + return declSpec.isFriend(); + } else if( p instanceof IASTFunctionDefinition ){ + ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) ((IASTFunctionDefinition)p).getDeclSpecifier(); + return declSpec.isFriend(); + } + } else { + return false; + } + } + p = p.getParent(); + } + return false; + } } static protected class Cost @@ -586,11 +627,11 @@ public class CPPSemantics { * @return */ private static IBinding postResolution( IBinding binding, LookupData data ) { - if( !(data.astName instanceof ICPPASTQualifiedName) && data.functionCall() ){ + if( data.checkAssociatedScopes() ){ //3.4.2 argument dependent name lookup, aka Koenig lookup try { IScope scope = (binding != null ) ? binding.getScope() : null; - if( data.associated.size() > 0 && ( scope == null|| !(scope instanceof ICPPClassScope) ) ){ + if( scope == null || !(scope instanceof ICPPClassScope) ){ data.ignoreUsingDirectives = true; data.forceQualified = true; for( int i = 0; i < data.associated.size(); i++ ){ @@ -601,6 +642,22 @@ public class CPPSemantics { } catch ( DOMException e ) { binding = e.getProblem(); } + } + if( binding == null && data.checkClassContainingFriend() ){ + //3.4.1-10 if we don't find a name used in a friend declaration in the member declaration's class + //we should look in the class granting friendship + IASTNode parent = data.astName.getParent(); + while( parent != null && !(parent instanceof ICPPASTCompositeTypeSpecifier) ) + parent = parent.getParent(); + if( parent instanceof ICPPASTCompositeTypeSpecifier ){ + IScope scope = ((ICPPASTCompositeTypeSpecifier)parent).getScope(); + try { + lookup( data, scope ); + binding = resolveAmbiguities( data, data.astName ); + } catch( DOMException e ){ + binding = e.getProblem(); + } + } } if( binding instanceof ICPPClassTemplate ){ ASTNodeProperty prop = data.astName.getPropertyInParent();