From bb4f44882511b3d54fc5a1ac64346dc567c34245 Mon Sep 17 00:00:00 2001 From: Andrew Niefer Date: Thu, 2 Dec 2004 22:27:57 +0000 Subject: [PATCH] class inheritance --- .../core/parser/tests/ast2/AST2CPPTests.java | 82 ++++++++++ .../cpp/ICPPASTCompositeTypeSpecifier.java | 6 +- .../cpp/CPPASTCompositeTypeSpecifier.java | 10 +- .../core/parser2/cpp/CPPASTQualifiedName.java | 29 +++- .../internal/core/parser2/cpp/CPPVisitor.java | 150 +++++++++++++++--- 5 files changed, 245 insertions(+), 32 deletions(-) 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 48a610581c5..67f071926f5 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 @@ -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 ) +// } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTCompositeTypeSpecifier.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTCompositeTypeSpecifier.java index af42c30870e..cf3713b70d1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTCompositeTypeSpecifier.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTCompositeTypeSpecifier.java @@ -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 ); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPASTCompositeTypeSpecifier.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPASTCompositeTypeSpecifier.java index dc1c83ea2b5..edbaa1ae6ee 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPASTCompositeTypeSpecifier.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPASTCompositeTypeSpecifier.java @@ -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) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPASTQualifiedName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPASTQualifiedName.java index 1bee01e457f..8417c2decd7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPASTQualifiedName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPASTQualifiedName.java @@ -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; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPVisitor.java index 0a084994171..4435a487df5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser2/cpp/CPPVisitor.java @@ -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 ); } }