diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index a54ab746461..45f0949f8d0 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -875,4 +875,49 @@ public class AST2TemplateTests extends AST2BaseTest { assertInstances( col, T1, 4 ); } + + public void testDeferredInstantiation() throws Exception { + StringBuffer buffer = new StringBuffer(); + buffer.append("template < class T > class A { \n"); //$NON-NLS-1$ + buffer.append(" int f( A * ); \n"); //$NON-NLS-1$ + buffer.append(" A < T > *pA; \n"); //$NON-NLS-1$ + buffer.append("}; \n"); //$NON-NLS-1$ + buffer.append("void f () { \n"); //$NON-NLS-1$ + buffer.append(" A< int > *a; \n"); //$NON-NLS-1$ + buffer.append(" a->f( a ); \n"); //$NON-NLS-1$ + buffer.append(" a->pA; \n"); //$NON-NLS-1$ + buffer.append("}; \n"); //$NON-NLS-1$ + + IASTTranslationUnit tu = parse( buffer.toString(), ParserLanguage.CPP ); + CPPNameCollector col = new CPPNameCollector(); + tu.accept( col ); + + ICPPClassTemplate A = (ICPPClassTemplate) col.getName(1).resolveBinding(); + ICPPMethod f = (ICPPMethod) col.getName(2).resolveBinding(); + ICPPClassType A1 = (ICPPClassType) col.getName(3).resolveBinding(); + ICPPClassType A2 = (ICPPClassType) col.getName(5).resolveBinding(); + ICPPField pA = (ICPPField) col.getName(8).resolveBinding(); + + assertSame( A1, A2 ); + assertTrue( A1 instanceof ICPPTemplateInstance ); + assertSame( ((ICPPTemplateInstance)A1).getOriginalBinding(), A ); + + ICPPClassType AI = (ICPPClassType) col.getName(10).resolveBinding(); + ICPPMethod f2 = (ICPPMethod) col.getName(14).resolveBinding(); + ICPPField pA2 = (ICPPField) col.getName(17).resolveBinding(); + + assertTrue( f2 instanceof ICPPTemplateInstance ); + assertSame( ((ICPPTemplateInstance)f2).getOriginalBinding(), f ); + assertTrue( pA2 instanceof ICPPTemplateInstance ); + assertSame( ((ICPPTemplateInstance)pA2).getOriginalBinding(), pA ); + + IType paT = pA2.getType(); + assertTrue( paT instanceof IPointerType ); + assertSame( ((IPointerType)paT).getType(), AI ); + + IParameter p = f2.getParameters()[0]; + IType pT = p.getType(); + assertTrue( pT instanceof IPointerType ); + assertSame( ((IPointerType)pT).getType(), AI ); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplate.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplate.java index 7a556c8cc61..66b75065700 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplate.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplate.java @@ -14,15 +14,24 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp; import org.eclipse.cdt.core.dom.ast.DOMException; +import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IField; 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.ITypedef; +import org.eclipse.cdt.core.dom.ast.cpp.CPPASTVisitor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; @@ -32,6 +41,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; 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; /** * @author aniefer @@ -39,6 +49,52 @@ import org.eclipse.cdt.core.parser.util.ArrayUtil; public class CPPClassTemplate extends CPPTemplateDefinition implements ICPPClassTemplate, ICPPClassType, ICPPInternalClassType { + private class FindDefinitionAction extends CPPASTVisitor { + private char [] nameArray = CPPClassTemplate.this.getNameCharArray(); + public IASTName result = null; + + { + shouldVisitNames = true; + shouldVisitDeclarations = true; + shouldVisitDeclSpecifiers = true; + shouldVisitDeclarators = true; + } + + public int visit( IASTName name ){ + if( name instanceof ICPPASTTemplateId || name instanceof ICPPASTQualifiedName ) + return PROCESS_CONTINUE; + char [] c = name.toCharArray(); + if( name.getParent() instanceof ICPPASTTemplateId ) + name = (IASTName) name.getParent(); + if( name.getParent() instanceof ICPPASTQualifiedName ){ + IASTName [] ns = ((ICPPASTQualifiedName)name.getParent()).getNames(); + if( ns[ ns.length - 1 ] != name ) + return PROCESS_CONTINUE; + name = (IASTName) name.getParent(); + } + + if( name.getParent() instanceof ICPPASTCompositeTypeSpecifier && + CharArrayUtils.equals( c, nameArray ) ) + { + IBinding binding = name.resolveBinding(); + if( binding == CPPClassTemplate.this ){ + result = name; + return PROCESS_ABORT; + } + } + return PROCESS_CONTINUE; + } + + public int visit( IASTDeclaration declaration ){ + if(declaration instanceof IASTSimpleDeclaration || declaration instanceof ICPPASTTemplateDeclaration ) + return PROCESS_CONTINUE; + return PROCESS_SKIP; + } + public int visit( IASTDeclSpecifier declSpec ){ + return (declSpec instanceof ICPPASTCompositeTypeSpecifier ) ? PROCESS_CONTINUE : PROCESS_SKIP; + } + public int visit( IASTDeclarator declarator ) { return PROCESS_SKIP; } + } /** * @param decl */ @@ -55,17 +111,18 @@ public class CPPClassTemplate extends CPPTemplateDefinition implements return instance; } private void checkForDefinition(){ -// CPPClassType.FindDefinitionAction action = new FindDefinitionAction(); -// IASTNode node = CPPVisitor.getContainingBlockItem( getPhysicalNode() ).getParent(); -// -// node.accept( action ); -// definition = action.result; -// -// if( definition == null ){ -// node.getTranslationUnit().accept( action ); -// definition = action.result; -// } -// + FindDefinitionAction action = new FindDefinitionAction(); + IASTNode node = CPPVisitor.getContainingBlockItem( declarations[0] ).getParent(); + while( node instanceof ICPPASTTemplateDeclaration ) + node = node.getParent(); + node.accept( action ); + definition = action.result; + + if( definition == null ){ + node.getTranslationUnit().accept( action ); + definition = action.result; + } + return; } private ICPPASTCompositeTypeSpecifier getCompositeTypeSpecifier(){ @@ -191,8 +248,17 @@ public class CPPClassTemplate extends CPPTemplateDefinition implements * @see org.eclipse.cdt.core.dom.ast.ICompositeType#getKey() */ public int getKey() { - // TODO Auto-generated method stub - return 0; + if( definition != null ) + return getCompositeTypeSpecifier().getKey(); + + if( declarations != null && declarations.length > 0 ){ + IASTNode n = declarations[0].getParent(); + if( n instanceof ICPPASTElaboratedTypeSpecifier ){ + return ((ICPPASTElaboratedTypeSpecifier)n).getKind(); + } + } + + return ICPPASTElaboratedTypeSpecifier.k_class; } /* (non-Javadoc) 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 14f804b8800..009492362d8 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 @@ -36,6 +36,7 @@ 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.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope; @@ -206,12 +207,24 @@ public class CPPClassType implements ICPPClassType, ICPPInternalClassType { shouldVisitDeclarations = true; shouldVisitDeclSpecifiers = true; shouldVisitDeclarators = true; - shouldVisitNamespaces = true; } public int visit( IASTName name ){ + if( name instanceof ICPPASTTemplateId ) + return PROCESS_SKIP; + if( name instanceof ICPPASTQualifiedName ) + return PROCESS_CONTINUE; + char [] c = name.toCharArray(); + + if( name.getParent() instanceof ICPPASTQualifiedName ){ + IASTName [] ns = ((ICPPASTQualifiedName)name.getParent()).getNames(); + if( ns[ ns.length - 1 ] != name ) + return PROCESS_CONTINUE; + name = (IASTName) name.getParent(); + } + if( name.getParent() instanceof ICPPASTCompositeTypeSpecifier && - CharArrayUtils.equals( name.toCharArray(), nameArray ) ) + CharArrayUtils.equals( c, nameArray ) ) { IBinding binding = name.resolveBinding(); if( binding == CPPClassType.this ){ @@ -228,7 +241,7 @@ public class CPPClassType implements ICPPClassType, ICPPInternalClassType { public int visit( IASTDeclSpecifier declSpec ){ return (declSpec instanceof ICPPASTCompositeTypeSpecifier ) ? PROCESS_CONTINUE : PROCESS_SKIP; } - public int processDeclarators( IASTDeclarator declarator ) { return PROCESS_SKIP; } + public int visit( IASTDeclarator declarator ) { return PROCESS_SKIP; } } private void checkForDefinition(){ 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 c66f84ff8d6..3d7b28e84c1 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 @@ -527,9 +527,19 @@ public class CPPSemantics { ASTNodeProperty prop = data.astName.getPropertyInParent(); if( prop != ICPPASTQualifiedName.SEGMENT_NAME && prop != ICPPASTTemplateId.TEMPLATE_NAME ){ try { - IScope scope = ((ICPPClassType)binding).getCompositeScope(); - if( CPPVisitor.getContainingScope( data.astName ) == scope ){ - binding = CPPTemplates.instantiateWithinClassTemplate( (ICPPClassTemplate) binding ); + IASTNode def = ((ICPPInternalBinding)binding).getDefinition(); + if( def != null ){ + def = def.getParent(); + IASTNode parent = data.astName.getParent(); + while( parent != null ){ + if( parent == def ){ + binding = CPPTemplates.instantiateWithinClassTemplate( (ICPPClassTemplate) binding ); + break; + } + if( parent instanceof ICPPASTNamespaceDefinition ) + break; + parent = parent.getParent(); + } } } catch( DOMException e ) { }