From 0b8b62e408992c08892e5fe76b5f4f260a926d31 Mon Sep 17 00:00:00 2001 From: Andrew Niefer Date: Wed, 16 Feb 2005 19:24:24 +0000 Subject: [PATCH] C++ friend declarations --- .../core/parser/tests/ast2/AST2CPPTests.java | 95 ++++++++++++++++++- .../cdt/core/dom/ast/cpp/ICPPClassType.java | 2 + .../cdt/core/parser/util/ArrayUtil.java | 94 ++++++++++++++++++ .../core/dom/parser/cpp/CPPClassType.java | 71 +++++++++++++- .../core/dom/parser/cpp/CPPFunction.java | 23 ++++- .../core/dom/parser/cpp/CPPSemantics.java | 25 ++++- .../core/dom/parser/cpp/CPPVisitor.java | 23 ++++- 7 files changed, 323 insertions(+), 10 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java 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 c87c443bd64..f6999bd1191 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 @@ -1248,7 +1248,8 @@ public class AST2CPPTests extends AST2BaseTest { ICPPClassType Node = (ICPPClassType) col.getName(1).resolveBinding(); ICPPClassType Data = (ICPPClassType) col.getName(3).resolveBinding(); - + assertSame( Data.getScope(), tu.getScope() ); + assertInstances(col, Node, 3); assertInstances(col, Data, 2); } @@ -1702,5 +1703,97 @@ public class AST2CPPTests extends AST2BaseTest { assertInstances( col, A, 5 ); assertInstances( col, pm, 2 ); } + + public void testFriend_1() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("class A { \n"); //$NON-NLS-1$ + buffer.append(" friend void set(); \n"); //$NON-NLS-1$ + buffer.append(" friend class B; \n"); //$NON-NLS-1$ + buffer.append("}; \n"); //$NON-NLS-1$ + buffer.append("void set(); \n"); //$NON-NLS-1$ + buffer.append("class B{}; \n"); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse(buffer.toString(), ParserLanguage.CPP); + CPPNameCollector col = new CPPNameCollector(); + CPPVisitor.visitTranslationUnit(tu, col); + + ICPPClassType A = (ICPPClassType) col.getName(0).resolveBinding(); + IFunction set = (IFunction) col.getName(1).resolveBinding(); + ICPPClassType B = (ICPPClassType) col.getName(2).resolveBinding(); + + assertInstances( col, set, 2 ); + assertInstances( col, B, 2 ); + + IBinding [] friends = A.getFriends(); + assertEquals( 2, friends.length ); + assertSame( friends[0], set ); + assertSame( friends[1], B ); + } + + public void testBug59149() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("class A { friend class B; friend class B; }; \n"); //$NON-NLS-1$ + buffer.append("class B{}; \n"); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse(buffer.toString(), ParserLanguage.CPP); + CPPNameCollector col = new CPPNameCollector(); + CPPVisitor.visitTranslationUnit(tu, col); + + ICPPClassType B = (ICPPClassType) col.getName(2).resolveBinding(); + ICPPClassType A = (ICPPClassType) col.getName(0).resolveBinding(); + + assertInstances( col, B, 3 ); + + IBinding [] friends = A.getFriends(); + assertEquals( friends.length, 1 ); + assertSame( friends[0], B ); + } + public void testBug59302() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append( "class A { \n"); //$NON-NLS-1$ + buffer.append( " public: class N {}; \n"); //$NON-NLS-1$ + buffer.append( "}; \n"); //$NON-NLS-1$ + buffer.append( "class B { \n"); //$NON-NLS-1$ + buffer.append( " friend class A::N; \n"); //$NON-NLS-1$ + buffer.append( "}; \n"); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse(buffer.toString(), ParserLanguage.CPP); + CPPNameCollector col = new CPPNameCollector(); + CPPVisitor.visitTranslationUnit(tu, col); + + ICPPClassType N = (ICPPClassType) col.getName(5).resolveBinding(); + ICPPClassType A = (ICPPClassType) col.getName(0).resolveBinding(); + ICPPClassType B = (ICPPClassType) col.getName(2).resolveBinding(); + assertInstances( col, N, 3 ); + + IBinding [] friends = B.getFriends(); + assertEquals( friends.length, 1 ); + assertSame( friends[0], N ); + + assertEquals( A.getFriends().length, 0 ); + assertEquals( N.getFriends().length, 0 ); + } + + public void testBug75482() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append( "class A { \n"); //$NON-NLS-1$ + buffer.append( " friend class B *helper(); \n"); //$NON-NLS-1$ + buffer.append( "}; \n"); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse(buffer.toString(), ParserLanguage.CPP); + CPPNameCollector col = new CPPNameCollector(); + CPPVisitor.visitTranslationUnit(tu, col); + + IFunction helper = (IFunction) col.getName(2).resolveBinding(); + assertSame( helper.getScope(), tu.getScope() ); + + ICPPClassType B = (ICPPClassType) col.getName(1).resolveBinding(); + ICPPClassType A = (ICPPClassType) col.getName(0).resolveBinding(); + assertSame( B.getScope(), A.getScope() ); + + IBinding [] friends = A.getFriends(); + assertEquals( friends.length, 1 ); + assertSame( friends[0], helper ); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPClassType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPClassType.java index 9a5af7fba04..a4ce662db15 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPClassType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPClassType.java @@ -13,6 +13,7 @@ package org.eclipse.cdt.core.dom.ast.cpp; import java.util.List; import org.eclipse.cdt.core.dom.ast.DOMException; +import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.IField; @@ -78,4 +79,5 @@ public interface ICPPClassType extends ICompositeType { */ public ICPPConstructor[] getConstructors() throws DOMException; + public IBinding [] getFriends() throws DOMException; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java new file mode 100644 index 00000000000..2afa519b25b --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ArrayUtil.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +/* + * Created on Feb 16, 2005 + */ +package org.eclipse.cdt.core.parser.util; + +import java.lang.reflect.Array; + +/** + * @author aniefer + */ +public class ArrayUtil { + public static final int DEFAULT_LENGTH = 2; + /** + * Adds obj to array in the first null slot. + * If array is null, a new array is created and obj is added to the new array. + * If the array is full, a new array of larger size is created, the contents + * of array are copied over and obj is added to the new array. + * + * The type of any new arrays will be array of c, where c is given. + * es: c = IBinding.class results in an IBinding[] + * @param Class c + * @param Object [] array + * @param Object obj + * @return + */ + static public Object [] append( Class c, Object[] array, Object obj ){ + if( array == null || array.length == 0){ + array = (Object[]) Array.newInstance( c, DEFAULT_LENGTH ); + array[0] = obj; + return array; + } + + int i = 0; + for( ; i < array.length; i++ ){ + if( array[i] == null ){ + array[i] = obj; + return array; + } + } + Object [] temp = (Object[]) Array.newInstance( c, array.length * 2 ); + System.arraycopy( array, 0, temp, 0, array.length ); + temp[array.length] = obj; + array = temp; + return array; + } + + /** + * Trims the given array and returns a new array with no null entries. + * if array == null, a new array of length 0 is returned + * if forceNew == true, a new array will always be created. + * if forceNew == false, a new array will only be created if the original array + * contained null entries. + * + * @param Class c: the type of the new array + * @param Object [] array, the array to be trimmed + * @param forceNew + * @return + */ + static public Object [] trim( Class c, Object [] array, boolean forceNew ){ + if( array == null ) + return (Object[]) Array.newInstance( c, 0 ); + + int i = 0; + for( ; i < array.length; i++ ){ + if( array[i] == null ) break; + } + if( forceNew || i < array.length ){ + Object [] temp = (Object[]) Array.newInstance( c, i ); + System.arraycopy( array, 0, temp, 0, i ); + array = temp; + } + return array; + } + + /** + * @param class1 + * @param fields + * @return + */ + public static Object[] trim( Class c, Object[] array ) { + return trim( c, array, false ); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassType.java index 04b4d58b0a2..2399198e76f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassType.java @@ -23,6 +23,7 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; @@ -32,6 +33,7 @@ import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; @@ -39,8 +41,12 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; +import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.core.parser.util.ObjectSet; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; /** @@ -88,6 +94,9 @@ public class CPPClassType implements ICPPClassType, ICPPBinding { public List find(String name) throws DOMException { throw new DOMException( this ); } + public IBinding[] getFriends() throws DOMException { + throw new DOMException( this ); + } } private ICPPASTCompositeTypeSpecifier definition; @@ -185,7 +194,7 @@ public class CPPClassType implements ICPPClassType, ICPPBinding { IASTDeclaration[] members = definition.getMembers(); int size = members.length; - IField[] fields = new IField[ size ]; + IField[] fields = null; if( size > 0 ){ for( int i = 0; i < size; i++ ){ @@ -196,13 +205,13 @@ public class CPPClassType implements ICPPClassType, ICPPBinding { IASTDeclarator declarator = declarators[i]; IBinding binding = declarator.getName().resolveBinding(); if( binding != null && binding instanceof IField ) - fields[i] = (IField) binding; + fields = (IField[]) ArrayUtil.append( IField.class, fields, binding ); } } } } - return fields; + return (IField[]) ArrayUtil.trim( IField.class, fields ); } /* (non-Javadoc) @@ -236,7 +245,22 @@ public class CPPClassType implements ICPPClassType, ICPPBinding { IASTName [] ns = ((ICPPASTQualifiedName)name).getNames(); name = ns[ ns.length - 1 ]; } - return CPPVisitor.getContainingScope( name ); + IScope scope = CPPVisitor.getContainingScope( name ); + if( definition == null && name.getPropertyInParent() != ICPPASTQualifiedName.SEGMENT_NAME ){ + IASTNode node = declarations[0].getParent(); + if( node instanceof IASTFunctionDefinition || node instanceof IASTParameterDeclaration || + ( node instanceof IASTSimpleDeclaration && + ( ((IASTSimpleDeclaration) node).getDeclarators().length > 0 || declarations[0].isFriend() ) ) ) + { + while( scope instanceof ICPPClassScope || scope instanceof ICPPFunctionScope ){ + try { + scope = (ICPPScope) scope.getParent(); + } catch (DOMException e1) { + } + } + } + } + return scope; } /* (non-Javadoc) @@ -371,4 +395,43 @@ public class CPPClassType implements ICPPClassType, ICPPBinding { return ((CPPClassScope)scope).getConstructors(); } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType#getFriends() + */ + public IBinding[] getFriends() { + if( definition == null ){ + checkForDefinition(); + if( definition == null ){ + return new IBinding [] { new ProblemBinding( IProblemBinding.SEMANTIC_DEFINITION_NOT_FOUND, getNameCharArray() ) }; + } + } + ObjectSet resultSet = new ObjectSet(2); + IASTDeclaration [] members = definition.getMembers(); + for( int i = 0; i < members.length; i++ ){ + if( members[i] instanceof IASTSimpleDeclaration ){ + ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration)members[i]).getDeclSpecifier(); + if( declSpec.isFriend() ){ + IASTDeclarator [] dtors = ((IASTSimpleDeclaration)members[i]).getDeclarators(); + if( declSpec instanceof ICPPASTElaboratedTypeSpecifier && dtors.length == 0 ){ + resultSet.put( ((ICPPASTElaboratedTypeSpecifier)declSpec).getName().resolveBinding() ); + } else { + for( int j = 0; j < dtors.length; j++ ){ + if( dtors[j] == null ) break; + resultSet.put( dtors[j].getName().resolveBinding() ); + } + } + } + } else if( members[i] instanceof IASTFunctionDefinition ){ + ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration)members[i]).getDeclSpecifier(); + if( declSpec.isFriend() ){ + IASTDeclarator dtor = ((IASTFunctionDefinition)members[i]).getDeclarator(); + resultSet.put( dtor.getName().resolveBinding() ); + } + + } + } + + return (IBinding[]) ArrayUtil.trim( IBinding.class, resultSet.keyArray(), true ); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java index 0dcd0a6596f..0a64832816c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java @@ -18,13 +18,16 @@ import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IParameter; import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; /** @@ -152,7 +155,25 @@ public class CPPFunction implements IFunction, ICPPBinding { * @see org.eclipse.cdt.core.dom.ast.IBinding#getScope() */ public IScope getScope() { - return CPPVisitor.getContainingScope( definition != null ? definition : declarations[0] ); + ICPPASTDeclSpecifier declSpec = null; + if( definition != null ){ + IASTFunctionDefinition def = (IASTFunctionDefinition) definition.getParent(); + declSpec = (ICPPASTDeclSpecifier) def.getDeclSpecifier(); + } else { + IASTSimpleDeclaration decl = (IASTSimpleDeclaration) declarations[0].getParent(); + declSpec = (ICPPASTDeclSpecifier) decl.getDeclSpecifier(); + } + + IScope scope = CPPVisitor.getContainingScope( definition != null ? definition : declarations[0] ); + if( declSpec.isFriend() && scope instanceof ICPPClassScope ){ + try { + while( scope instanceof ICPPClassScope ){ + scope = scope.getParent(); + } + } catch ( DOMException e ) { + } + } + return scope; } /* (non-Javadoc) 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 4e9c5856df0..2300ee6ab6e 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 @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; @@ -28,6 +29,7 @@ import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpressionList; +import org.eclipse.cdt.core.dom.ast.IASTFieldReference; import org.eclipse.cdt.core.dom.ast.IASTForStatement; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; @@ -55,6 +57,7 @@ import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; +import org.eclipse.cdt.core.dom.ast.c.ICASTFieldDesignator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; @@ -192,6 +195,22 @@ public class CPPSemantics { p1 = p1.getParent(); return ( p1 instanceof IASTIdExpression && p1.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME ); } + public boolean checkWholeClassScope() { + if( astName == null ) return false; + ASTNodeProperty prop = astName.getPropertyInParent(); + if( prop == IASTIdExpression.ID_NAME || + prop == IASTFieldReference.FIELD_NAME || + prop == ICASTFieldDesignator.FIELD_NAME || + prop == ICPPASTUsingDirective.QUALIFIED_NAME || + prop == ICPPASTUsingDeclaration.NAME || + prop == IASTFunctionCallExpression.FUNCTION_NAME || + prop == ICPPASTUsingDeclaration.NAME || + prop == IASTNamedTypeSpecifier.NAME ) + { + return true; + } + return false; + } } static protected class Cost @@ -805,11 +824,11 @@ public class CPPSemantics { } int idx = -1; - boolean classScope = ( scope instanceof ICPPClassScope ); + boolean checkWholeClassScope = ( scope instanceof ICPPClassScope ) && data.checkWholeClassScope(); IASTNode item = ( nodes != null ? (nodes.length > 0 ? nodes[++idx] : null ) : parent ); while( item != null ) { - if( !classScope && blockItem != null && ((ASTNode)item).getOffset() > ((ASTNode) blockItem).getOffset() ) + if( !checkWholeClassScope && blockItem != null && ((ASTNode)item).getOffset() > ((ASTNode) blockItem).getOffset() ) break; if( item != blockItem || data.includeBlockItem( item ) ){ @@ -829,7 +848,7 @@ public class CPPSemantics { } } } - if( item == blockItem && !classScope ) + if( item == blockItem && !checkWholeClassScope ) break; if( idx > -1 && ++idx < nodes.length ){ item = nodes[idx]; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java index 7b2bbe563b0..9fa32862d5e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVisitor.java @@ -93,6 +93,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; @@ -255,10 +256,14 @@ public class CPPVisitor { IASTNode parent = elabType.getParent(); IBinding binding = null; boolean mustBeSimple = true; + boolean isFriend = false; if( parent instanceof IASTSimpleDeclaration ){ IASTDeclarator [] dtors = ((IASTSimpleDeclaration)parent).getDeclarators(); - if( dtors.length > 0 ){ + ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration)parent).getDeclSpecifier(); + isFriend = declSpec.isFriend() && dtors.length == 0; + if( dtors.length > 0 || isFriend ){ binding = CPPSemantics.resolveBinding( elabType.getName() ); + mustBeSimple = !isFriend; } else { mustBeSimple = false; } @@ -292,6 +297,13 @@ public class CPPVisitor { } } } + if( scope instanceof ICPPClassScope && isFriend ){ + try { + while( scope instanceof ICPPClassScope ) + scope = (ICPPScope) scope.getParent(); + } catch ( DOMException e1 ) { + } + } try { binding = scope.getBinding( elabType.getName() ); if( binding == null ){ @@ -369,6 +381,15 @@ public class CPPVisitor { } ICPPScope scope = (ICPPScope) getContainingScope( parent ); + if( parent instanceof IASTSimpleDeclaration && scope instanceof ICPPClassScope ){ + ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration)parent).getDeclSpecifier(); + if( declSpec.isFriend() ){ + try { + scope = (ICPPScope) scope.getParent(); + } catch ( DOMException e1 ) { + } + } + } IBinding binding; try { binding = ( scope != null ) ? scope.getBinding( declarator.getName() ) : null;