1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-30 21:55:31 +02:00

C++ friend declarations

This commit is contained in:
Andrew Niefer 2005-02-16 19:24:24 +00:00
parent 5155c977ec
commit 0b8b62e408
7 changed files with 323 additions and 10 deletions

View file

@ -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 );
}
}

View file

@ -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;
}

View file

@ -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 );
}
}

View file

@ -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 );
}
}

View file

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

View file

@ -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];

View file

@ -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;