mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-23 17:05:26 +02:00
class inheritance
This commit is contained in:
parent
cf4ba671c8
commit
bb4f448825
5 changed files with 245 additions and 32 deletions
|
@ -33,6 +33,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
|
|||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
|
||||
import org.eclipse.cdt.core.parser.ParserLanguage;
|
||||
|
||||
/**
|
||||
|
@ -240,5 +241,86 @@ public class AST2CPPTests extends AST2BaseTest {
|
|||
assertSame( i1, i2 );
|
||||
}
|
||||
|
||||
public void testBasicInheritance() throws Exception {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append( "class A { int i; }; \n" ); //$NON-NLS-1$
|
||||
buffer.append( "class B : public A { void f(); }; \n" ); //$NON-NLS-1$
|
||||
buffer.append( "void B::f() { i; } \n" ); //$NON-NLS-1$
|
||||
|
||||
IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.CPP );
|
||||
|
||||
IASTSimpleDeclaration decl = (IASTSimpleDeclaration) tu.getDeclarations()[0];
|
||||
ICPPASTCompositeTypeSpecifier comp = (ICPPASTCompositeTypeSpecifier) decl.getDeclSpecifier();
|
||||
IASTName name_A1 = comp.getName();
|
||||
|
||||
decl = (IASTSimpleDeclaration) comp.getMembers()[0];
|
||||
IASTName name_i1 = decl.getDeclarators()[0].getName();
|
||||
|
||||
decl = (IASTSimpleDeclaration) tu.getDeclarations()[1];
|
||||
comp = (ICPPASTCompositeTypeSpecifier) decl.getDeclSpecifier();
|
||||
IASTName name_B1 = comp.getName();
|
||||
|
||||
ICPPASTBaseSpecifier base = comp.getBaseSpecifiers()[0];
|
||||
IASTName name_A2 = base.getName();
|
||||
|
||||
decl = (IASTSimpleDeclaration) comp.getMembers()[0];
|
||||
IASTName name_f1 = decl.getDeclarators()[0].getName();
|
||||
|
||||
IASTFunctionDefinition def = (IASTFunctionDefinition) tu.getDeclarations()[2];
|
||||
ICPPASTQualifiedName name_f2 = (ICPPASTQualifiedName) def.getDeclarator().getName();
|
||||
IASTName name_B2 = name_f2.getNames()[0];
|
||||
IASTName name_f3 = name_f2.getNames()[1];
|
||||
|
||||
IASTCompoundStatement compound = (IASTCompoundStatement) def.getBody();
|
||||
IASTExpressionStatement statement = (IASTExpressionStatement) compound.getStatements()[0];
|
||||
IASTIdExpression idExp = (IASTIdExpression) statement.getExpression();
|
||||
IASTName name_i2 = idExp.getName();
|
||||
|
||||
ICPPField i2 = (ICPPField) name_i2.resolveBinding();
|
||||
ICPPField i1 = (ICPPField) name_i1.resolveBinding();
|
||||
|
||||
ICPPClassType A2 = (ICPPClassType) name_A2.resolveBinding();
|
||||
ICPPClassType A1 = (ICPPClassType) name_A1.resolveBinding();
|
||||
ICPPClassType B2 = (ICPPClassType) name_B2.resolveBinding();
|
||||
ICPPClassType B1 = (ICPPClassType) name_B1.resolveBinding();
|
||||
|
||||
ICPPMethod f3 = (ICPPMethod) name_f3.resolveBinding();
|
||||
ICPPMethod f2 = (ICPPMethod) name_f2.resolveBinding();
|
||||
ICPPMethod f1 = (ICPPMethod) name_f1.resolveBinding();
|
||||
assertNotNull( A1 );
|
||||
assertNotNull( B1 );
|
||||
assertNotNull( i1 );
|
||||
assertNotNull( f1 );
|
||||
assertSame( A1, A2 );
|
||||
assertSame( B1, B2 );
|
||||
assertSame( i1, i2 );
|
||||
assertSame( f1, f2 );
|
||||
assertSame( f2, f3 );
|
||||
}
|
||||
|
||||
// public void testNamespaces() throws Exception {
|
||||
// StringBuffer buffer = new StringBuffer();
|
||||
// buffer.append( "namespace A{ \n"); //$NON-NLS-1$
|
||||
// buffer.append( " int a; \n"); //$NON-NLS-1$
|
||||
// buffer.append( "} \n"); //$NON-NLS-1$
|
||||
// buffer.append( "namespace B{ \n"); //$NON-NLS-1$
|
||||
// buffer.append( " using namespace A; \n"); //$NON-NLS-1$
|
||||
// buffer.append( "} \n"); //$NON-NLS-1$
|
||||
// buffer.append( "namespace C{ \n"); //$NON-NLS-1$
|
||||
// buffer.append( " using namespace A; \n"); //$NON-NLS-1$
|
||||
// buffer.append( "} \n"); //$NON-NLS-1$
|
||||
// buffer.append( " \n"); //$NON-NLS-1$
|
||||
// buffer.append( "namespace BC{ \n"); //$NON-NLS-1$
|
||||
// buffer.append( " using namespace B; \n"); //$NON-NLS-1$
|
||||
// buffer.append( " using namespace C; \n"); //$NON-NLS-1$
|
||||
// buffer.append( "} \n"); //$NON-NLS-1$
|
||||
// buffer.append( " \n"); //$NON-NLS-1$
|
||||
// buffer.append( "void f(){ \n"); //$NON-NLS-1$
|
||||
// buffer.append( " BC::a++; //ok \n"); //$NON-NLS-1$
|
||||
// buffer.append( "} \n"); //$NON-NLS-1$
|
||||
//
|
||||
// IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.CPP );
|
||||
//
|
||||
// //CPPVisitor.visitTranslationUnit( tu )
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
**********************************************************************/
|
||||
package org.eclipse.cdt.core.dom.ast.cpp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
|
@ -31,6 +29,8 @@ public interface ICPPASTCompositeTypeSpecifier extends IASTCompositeTypeSpecifie
|
|||
|
||||
public static interface ICPPASTBaseSpecifier extends IASTNode
|
||||
{
|
||||
public static final ICPPASTBaseSpecifier[] EMPTY_BASESPECIFIER_ARRAY = new ICPPASTBaseSpecifier[0];
|
||||
|
||||
public boolean isVirtual();
|
||||
public void setVirtual( boolean value );
|
||||
|
||||
|
@ -46,7 +46,7 @@ public interface ICPPASTCompositeTypeSpecifier extends IASTCompositeTypeSpecifie
|
|||
public void setName( IASTName name );
|
||||
}
|
||||
|
||||
public List getBaseSpecifiers();
|
||||
public ICPPASTBaseSpecifier[] getBaseSpecifiers();
|
||||
public void addBaseSpecifier( ICPPASTBaseSpecifier baseSpec );
|
||||
|
||||
}
|
||||
|
|
|
@ -10,10 +10,6 @@
|
|||
**********************************************************************/
|
||||
package org.eclipse.cdt.internal.core.parser2.cpp;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IScope;
|
||||
|
@ -32,10 +28,10 @@ public class CPPASTCompositeTypeSpecifier extends CPPASTBaseDeclSpecifier
|
|||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier#getBaseSpecifiers()
|
||||
*/
|
||||
public List getBaseSpecifiers() {
|
||||
if( baseSpecs == null ) return Collections.EMPTY_LIST;
|
||||
public ICPPASTBaseSpecifier[] getBaseSpecifiers() {
|
||||
if( baseSpecs == null ) return ICPPASTBaseSpecifier.EMPTY_BASESPECIFIER_ARRAY;
|
||||
removeNullBaseSpecs();
|
||||
return Arrays.asList( baseSpecs );
|
||||
return baseSpecs;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
|
|
@ -109,8 +109,33 @@ public class CPPASTQualifiedName extends CPPASTNode implements ICPPASTQualifiedN
|
|||
* @see org.eclipse.cdt.core.dom.ast.IASTName#toCharArray()
|
||||
*/
|
||||
public char[] toCharArray() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
if( names == null ) return null;
|
||||
removeNullNames();
|
||||
|
||||
//count first
|
||||
int len = 0;
|
||||
for( int i = 0; i < names.length; ++i )
|
||||
{
|
||||
char [] n = names[i].toCharArray();
|
||||
if( n == null )
|
||||
return null;
|
||||
len += n.length;
|
||||
if( i != names.length - 1 )
|
||||
len += 2;
|
||||
}
|
||||
|
||||
char [] nameArray = new char[ len ];
|
||||
int pos = 0;
|
||||
for( int i = 0; i < names.length; i++ ){
|
||||
char [] n = names[i].toCharArray();
|
||||
System.arraycopy( n, 0, nameArray, pos, n.length );
|
||||
pos += n.length;
|
||||
if( i != names.length - 1 ){
|
||||
nameArray[pos++] = ':';
|
||||
nameArray[pos++] = ':';
|
||||
}
|
||||
}
|
||||
return nameArray;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -52,10 +52,12 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
|||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope;
|
||||
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.CharArrayUtils;
|
||||
import org.eclipse.cdt.core.parser.util.ObjectMap;
|
||||
import org.eclipse.cdt.core.parser.util.ObjectSet;
|
||||
import org.eclipse.cdt.internal.core.parser2.c.CASTFunctionDeclarator;
|
||||
import org.eclipse.cdt.internal.core.parser.pst.ISymbol;
|
||||
import org.eclipse.cdt.internal.core.parser.pst.ITypeInfo;
|
||||
|
||||
/**
|
||||
* @author aniefer
|
||||
|
@ -68,7 +70,8 @@ public class CPPVisitor {
|
|||
public static IBinding createBinding(IASTName name) {
|
||||
IASTNode parent = name.getParent();
|
||||
if( parent instanceof IASTNamedTypeSpecifier ||
|
||||
parent instanceof ICPPASTQualifiedName )
|
||||
parent instanceof ICPPASTQualifiedName ||
|
||||
parent instanceof ICPPASTBaseSpecifier )
|
||||
{
|
||||
return resolveBinding( name );
|
||||
} else if( parent instanceof IASTIdExpression ){
|
||||
|
@ -134,6 +137,8 @@ public class CPPVisitor {
|
|||
}
|
||||
|
||||
public static IScope getContainingScope( IASTNode node ){
|
||||
if( node == null )
|
||||
return null;
|
||||
if( node instanceof IASTName )
|
||||
return getContainingScope( (IASTName) node );
|
||||
else if( node instanceof IASTDeclaration )
|
||||
|
@ -323,6 +328,8 @@ public class CPPVisitor {
|
|||
}
|
||||
} else if( parent instanceof IASTDeclarator ){
|
||||
data.forDefinition = true;
|
||||
} else if ( parent instanceof ICPPASTBaseSpecifier ) {
|
||||
//filter out non-type names
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
@ -379,10 +386,14 @@ public class CPPVisitor {
|
|||
}
|
||||
} else if( declaration instanceof IASTFunctionDefinition ){
|
||||
IASTFunctionDefinition functionDef = (IASTFunctionDefinition) declaration;
|
||||
CASTFunctionDeclarator declarator = (CASTFunctionDeclarator) functionDef.getDeclarator();
|
||||
IASTFunctionDeclarator declarator = functionDef.getDeclarator();
|
||||
|
||||
//check the function itself
|
||||
IASTName declName = declarator.getName();
|
||||
if( declName instanceof ICPPASTQualifiedName ){
|
||||
IASTName [] names = ((ICPPASTQualifiedName)declName).getNames();
|
||||
declName = names[ names.length - 1 ];
|
||||
}
|
||||
if( CharArrayUtils.equals( declName.toCharArray(), data.name ) ){
|
||||
return declName;
|
||||
}
|
||||
|
@ -408,8 +419,11 @@ public class CPPVisitor {
|
|||
while( scope != null ){
|
||||
IASTNode blockItem = getContainingBlockItem( node );
|
||||
List directives = null;
|
||||
if( !data.usingDirectivesOnly )
|
||||
directives = lookupInScope( data, scope, blockItem );
|
||||
if( !data.usingDirectivesOnly ){
|
||||
directives = new ArrayList(2);
|
||||
data.foundItems = lookupInScope( data, scope, blockItem, directives );
|
||||
}
|
||||
|
||||
|
||||
if( !data.ignoreUsingDirectives ) {
|
||||
data.visited.clear();
|
||||
|
@ -434,7 +448,7 @@ public class CPPVisitor {
|
|||
return;
|
||||
|
||||
if( !data.usingDirectivesOnly && scope instanceof ICPPClassScope ){
|
||||
//TODO : lookupInParents
|
||||
data.foundItems = lookupInParents( data, (ICPPClassScope) scope );
|
||||
}
|
||||
|
||||
if( data.foundItems != null && !data.foundItems.isEmpty() )
|
||||
|
@ -443,11 +457,104 @@ public class CPPVisitor {
|
|||
//if still not found, loop and check our containing scope
|
||||
if( data.qualified && !data.usingDirectives.isEmpty() )
|
||||
data.usingDirectivesOnly = true;
|
||||
node = blockItem.getParent();
|
||||
|
||||
if( blockItem != null )
|
||||
node = blockItem.getParent();
|
||||
scope = (ICPPScope) scope.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
private static List lookupInParents( LookupData data, ICPPClassScope lookIn ){
|
||||
ICPPASTCompositeTypeSpecifier compositeTypeSpec = (ICPPASTCompositeTypeSpecifier) lookIn.getPhysicalNode();
|
||||
ICPPASTBaseSpecifier [] bases = compositeTypeSpec.getBaseSpecifiers();
|
||||
|
||||
List inherited = null;
|
||||
List result = null;
|
||||
|
||||
if( bases.length == 0 )
|
||||
return null;
|
||||
|
||||
//use data to detect circular inheritance
|
||||
if( data.inheritanceChain == null )
|
||||
data.inheritanceChain = new ObjectSet( 2 );
|
||||
|
||||
data.inheritanceChain.put( lookIn );
|
||||
|
||||
int size = bases.length;
|
||||
for( int i = 0; i < size; i++ )
|
||||
{
|
||||
ICPPClassType binding = (ICPPClassType) bases[i].getName().resolveBinding();
|
||||
ICPPClassScope parent = (ICPPClassScope) binding.getCompositeScope();
|
||||
|
||||
if( parent == null )
|
||||
continue;
|
||||
|
||||
if( !bases[i].isVirtual() || !data.visited.containsKey( parent ) ){
|
||||
if( bases[i].isVirtual() ){
|
||||
if( data.visited == ObjectSet.EMPTY_SET )
|
||||
data.visited = new ObjectSet(2);
|
||||
data.visited.put( parent );
|
||||
}
|
||||
|
||||
//if the inheritanceChain already contains the parent, then that
|
||||
//is circular inheritance
|
||||
if( ! data.inheritanceChain.containsKey( parent ) ){
|
||||
//is this name define in this scope?
|
||||
inherited = lookupInScope( data, parent, null, null );
|
||||
|
||||
if( inherited == null || inherited.isEmpty() ){
|
||||
inherited = lookupInParents( data, parent );
|
||||
}
|
||||
} else {
|
||||
//throw new ParserSymbolTableException( ParserSymbolTableException.r_CircularInheritance );
|
||||
}
|
||||
}
|
||||
|
||||
if( inherited != null && !inherited.isEmpty() ){
|
||||
if( result == null || result.isEmpty() ){
|
||||
result = inherited;
|
||||
} else if ( inherited != null && !inherited.isEmpty() ) {
|
||||
for( int j = 0; j < result.size(); j++ ) {
|
||||
IASTName n = (IASTName) result.get(j);
|
||||
if( !checkAmbiguity( n, inherited ) ){
|
||||
//throw new ParserSymbolTableException( ParserSymbolTableException.r_Ambiguous );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
inherited = null; //reset temp for next iteration
|
||||
}
|
||||
}
|
||||
|
||||
data.inheritanceChain.remove( lookIn );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean checkAmbiguity( Object obj1, Object obj2 ){
|
||||
//it is not ambiguous if they are the same thing and it is static or an enumerator
|
||||
if( obj1 == obj2 ){
|
||||
List objList = ( obj1 instanceof List ) ? (List) obj1 : null;
|
||||
int objListSize = ( objList != null ) ? objList.size() : 0;
|
||||
ISymbol symbol = ( objList != null ) ? (ISymbol) objList.get(0) : ( ISymbol )obj1;
|
||||
int idx = 1;
|
||||
while( symbol != null ) {
|
||||
ITypeInfo type = ((ISymbol)obj1).getTypeInfo();
|
||||
if( !type.checkBit( ITypeInfo.isStatic ) && !type.isType( ITypeInfo.t_enumerator ) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
if( objList != null && idx < objListSize ){
|
||||
symbol = (ISymbol) objList.get( idx++ );
|
||||
} else {
|
||||
symbol = null;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static private void processDirectives( LookupData data, IScope scope, List directives ){
|
||||
if( directives == null || directives.size() == 0 )
|
||||
return;
|
||||
|
@ -503,12 +610,12 @@ public class CPPVisitor {
|
|||
* @param scope
|
||||
* @return List of encountered using directives
|
||||
*/
|
||||
static private List lookupInScope( LookupData data, ICPPScope scope, IASTNode blockItem ) {
|
||||
static private List lookupInScope( LookupData data, ICPPScope scope, IASTNode blockItem, List usingDirectives ) {
|
||||
IASTName possible = null;
|
||||
IASTNode [] nodes = null;
|
||||
IASTNode parent = scope.getPhysicalNode();
|
||||
|
||||
List usingDirectives = null;
|
||||
List found = null;
|
||||
|
||||
if( parent instanceof IASTCompoundStatement ){
|
||||
IASTCompoundStatement compound = (IASTCompoundStatement) parent;
|
||||
|
@ -529,16 +636,15 @@ public class CPPVisitor {
|
|||
break;
|
||||
|
||||
if( item instanceof ICPPASTUsingDirective && !data.ignoreUsingDirectives ) {
|
||||
if( usingDirectives == null )
|
||||
usingDirectives = new ArrayList(2);
|
||||
usingDirectives.add( item );
|
||||
if( usingDirectives != null )
|
||||
usingDirectives.add( item );
|
||||
continue;
|
||||
}
|
||||
possible = collectResult( data, item, (item == parent) );
|
||||
if( possible != null ){
|
||||
if( data.foundItems == null )
|
||||
data.foundItems = new ArrayList(2);
|
||||
data.foundItems.add( possible );
|
||||
if( found == null )
|
||||
found = new ArrayList(2);
|
||||
found.add( possible );
|
||||
}
|
||||
if( idx > -1 && ++idx < nodes.length ){
|
||||
item = nodes[idx];
|
||||
|
@ -546,7 +652,7 @@ public class CPPVisitor {
|
|||
item = null;
|
||||
}
|
||||
}
|
||||
return usingDirectives;
|
||||
return found;
|
||||
}
|
||||
|
||||
static private List lookupInNominated( LookupData data, ICPPScope scope, List transitives ){
|
||||
|
@ -567,13 +673,17 @@ public class CPPVisitor {
|
|||
data.visited = new ObjectSet(2);
|
||||
}
|
||||
data.visited.put( temp );
|
||||
int pre = ( data.foundItems != null ) ? 0 : data.foundItems.size();
|
||||
List usings = lookupInScope( data, scope, null );
|
||||
int post = ( data.foundItems != null ) ? 0 : data.foundItems.size();
|
||||
List usings = new ArrayList(2);
|
||||
List found = lookupInScope( data, scope, null, usings );
|
||||
if( data.foundItems == null )
|
||||
data.foundItems = found;
|
||||
else if( found != null )
|
||||
data.foundItems.addAll( found );
|
||||
|
||||
|
||||
//only consider the transitive using directives if we are an unqualified
|
||||
//lookup, or we didn't find the name in decl
|
||||
if( usings != null && usings.size() > 0 && (!data.qualified || (pre == post)) ){
|
||||
if( usings != null && usings.size() > 0 && (!data.qualified || found == null ) ){
|
||||
transitives.addAll( usings );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue