From 51131345dbaa12f210adc03b3ad05a951d937464 Mon Sep 17 00:00:00 2001 From: Andrew Niefer Date: Thu, 18 Mar 2004 23:20:16 +0000 Subject: [PATCH] parsing template-ids, enabling template instantiations & class template partial specializations & indirectly fixes bug 54778 --- core/org.eclipse.cdt.core.tests/ChangeLog | 10 + .../parser/tests/CompleteParseASTTest.java | 198 +++++++++++++++++ .../parser/tests/CompleteParseBaseTest.java | 23 +- .../core/parser/tests/ScannerTestCase.java | 13 ++ .../eclipse/cdt/internal/core/model/Util.java | 2 +- .../parser/ChangeLog-parser | 8 + .../eclipse/cdt/core/parser/ITokenDuple.java | 2 + .../core/parser/ExpressionParser.java | 200 ++++++++++++++--- .../cdt/internal/core/parser/Parser.java | 49 +++-- .../ast/complete/ASTParameterDeclaration.java | 6 + .../ast/complete/CompleteParseASTFactory.java | 205 +++++++++++++++--- .../core/parser/pst/ContainerSymbol.java | 15 ++ .../parser/pst/DeferredTemplateInstance.java | 16 ++ .../parser/pst/DerivableContainerSymbol.java | 16 +- .../core/parser/pst/IContainerSymbol.java | 3 + .../core/parser/pst/TemplateEngine.java | 5 +- .../core/parser/pst/TemplateFactory.java | 52 +++++ .../parser/pst/TemplateSymbolExtension.java | 40 ++++ .../core/parser/token/TokenDuple.java | 23 +- 19 files changed, 791 insertions(+), 95 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateSymbolExtension.java diff --git a/core/org.eclipse.cdt.core.tests/ChangeLog b/core/org.eclipse.cdt.core.tests/ChangeLog index af0f24d138c..7e5c68b9853 100644 --- a/core/org.eclipse.cdt.core.tests/ChangeLog +++ b/core/org.eclipse.cdt.core.tests/ChangeLog @@ -1,3 +1,13 @@ +2003-03-18 Andrew Niefer + parsing template-ids + - added parser/org/eclipse/cdt/core/parser/tests/ScannerTestCase.test54778() + - modified parser/org/eclipse/cdt/core/parser/tests/CompleteParseBaseTests.java + - modified parser/org/eclipse/cdt/core/parser/tests/CompleteParseASTTest.testOverloadedFunctionTemplates() + - added parser/org/eclipse/cdt/core/parser/tests/CompleteParseASTTest.testOverloadedFunctionTemplates_2() + - added parser/org/eclipse/cdt/core/parser/tests/CompleteParseASTTest.testTemplateClassPartialSpecialization() + - added parser/org/eclipse/cdt/core/parser/tests/CompleteParseASTTest.testTemplateInstanceAsBaseClause() + - added parser/org/eclipse/cdt/core/parser/tests/CompleteParseASTTest.testTemplateParameterAsBaseClause() + 2004-03-18 Alain Magloire Change in the hierarchy of the core Model: diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/CompleteParseASTTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/CompleteParseASTTest.java index 2da20140e04..62b74b2db31 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/CompleteParseASTTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/CompleteParseASTTest.java @@ -1455,6 +1455,76 @@ public class CompleteParseASTTest extends CompleteParseBaseTest writer.write( " }" ); Iterator i = parse( writer.toString() ).getDeclarations(); + + IASTTemplateDeclaration template1 = (IASTTemplateDeclaration) i.next(); + IASTTemplateParameter T1 = (IASTTemplateParameter) template1.getTemplateParameters().next(); + + IASTFunction f1 = (IASTFunction) template1.getOwnedDeclaration(); + + IASTTemplateDeclaration template2 = (IASTTemplateDeclaration) i.next(); + IASTFunction f2 = (IASTFunction) template2.getOwnedDeclaration(); + IASTTemplateParameter T2 = (IASTTemplateParameter) template2.getTemplateParameters().next(); + + IASTVariable p = (IASTVariable) i.next(); + IASTFunction main = (IASTFunction) i.next(); + assertFalse( i.hasNext() ); + + assertAllReferences( 6, createTaskList( new Task( T1 ), + new Task( T2 ), + new Task( f1, 1, false, false ), + new Task( p, 2 ), + new Task( f2, 1, false, false ) ) ); + + } + + public void testOverloadedFunctionTemplates_2() throws Exception + { + Writer writer = new StringWriter(); + writer.write("template< class T > struct A { }; \n"); + writer.write("template< class T > void h( const T & ); //#1 \n"); + writer.write("template< class T > void h( A& ); //#2 \n"); + writer.write("void foo() { \n"); + writer.write(" A z; \n"); + writer.write(" h( z ); //calls 2 \n"); + + writer.write(" const A z2; \n"); + writer.write(" h( z2 ); //calls 1 because 2 is not callable. \n"); + writer.write( "} \n"); + + Iterator i = parse( writer.toString() ).getDeclarations(); + + IASTTemplateDeclaration templateA = (IASTTemplateDeclaration) i.next(); + IASTTemplateDeclaration templateh1 = (IASTTemplateDeclaration) i.next(); + IASTTemplateDeclaration templateh2 = (IASTTemplateDeclaration) i.next(); + + IASTClassSpecifier A = (IASTClassSpecifier) templateA.getOwnedDeclaration(); + IASTFunction h1 = (IASTFunction) templateh1.getOwnedDeclaration(); + IASTFunction h2 = (IASTFunction) templateh2.getOwnedDeclaration(); + + IASTTemplateParameter T1 = (IASTTemplateParameter) templateA.getTemplateParameters().next(); + IASTTemplateParameter T2 = (IASTTemplateParameter) templateh1.getTemplateParameters().next(); + IASTTemplateParameter T3 = (IASTTemplateParameter) templateh2.getTemplateParameters().next(); + + IASTFunction foo = (IASTFunction) i.next(); + assertFalse( i.hasNext() ); + + i = getDeclarations( foo ); + IASTVariable z = (IASTVariable) i.next(); + IASTVariable z2 = (IASTVariable) i.next(); + assertFalse( i.hasNext() ); + + assertEquals( ((IASTSimpleTypeSpecifier)z.getAbstractDeclaration().getTypeSpecifier()).getTypeSpecifier(), A ); + assertEquals( ((IASTSimpleTypeSpecifier)z2.getAbstractDeclaration().getTypeSpecifier()).getTypeSpecifier(), A ); + + assertAllReferences( 8 /*9*/, createTaskList( new Task( T2 ), + //new Task( T3 ), + new Task( A, 3 ), + new Task( z ), + new Task( z2 ), + new Task( h1, 1, false, false ), + new Task( h2, 1, false, false ) ) ); + + } public void testBug54639() throws Exception { @@ -1477,6 +1547,134 @@ public class CompleteParseASTTest extends CompleteParseBaseTest assertFalse( i.hasNext() ); } + public void testTemplateClassPartialSpecialization() throws Exception + { + Writer writer = new StringWriter(); + writer.write( "template < class T1, class T2, int I > class A {}; //#1\n" ); + writer.write( "template < class T, int I > class A < T, T*, I > {}; //#2\n"); + writer.write( "template < class T1, class T2, int I > class A < T1*, T2, I > {}; //#3\n"); + writer.write( "template < class T > class A < int, T*, 5 > {}; //#4\n"); + writer.write( "template < class T1, class T2, int I > class A < T1, T2*, I > {}; //#5\n"); + + writer.write( "A a1; //uses #1 \n"); + writer.write( "A a2; //uses #2, T is int, I is 1 \n"); + writer.write( "A a4; //uses #4, T is char \n"); + writer.write( "A a5; //uses #5, T is int, T2 is char, I is1 \n"); + + Iterator i = parse( writer.toString() ).getDeclarations(); + + writer.write( " A amgiguous; //ambiguous, matches #3 & #5 \n"); + + try{ + //we expect this parse to fail because of the ambiguity in the last line + parse( writer.toString() ); + assertFalse( true ); + } catch ( ParserException e ){ + assertEquals( e.getMessage(), "FAILURE" ); + } + + IASTTemplateDeclaration template1 = (IASTTemplateDeclaration) i.next(); + IASTTemplateDeclaration spec2 = (IASTTemplateDeclaration) i.next(); + IASTTemplateDeclaration spec3 = (IASTTemplateDeclaration) i.next(); + IASTTemplateDeclaration spec4 = (IASTTemplateDeclaration) i.next(); + IASTTemplateDeclaration spec5 = (IASTTemplateDeclaration) i.next(); + + IASTVariable a1 = (IASTVariable) i.next(); + IASTVariable a2 = (IASTVariable) i.next(); + IASTVariable a4 = (IASTVariable) i.next(); + IASTVariable a5 = (IASTVariable) i.next(); + + assertFalse( i.hasNext() ); + + IASTClassSpecifier A1 = (IASTClassSpecifier)template1.getOwnedDeclaration(); + IASTClassSpecifier A2 = (IASTClassSpecifier)spec2.getOwnedDeclaration(); + IASTClassSpecifier A3 = (IASTClassSpecifier)spec3.getOwnedDeclaration(); + IASTClassSpecifier A4 = (IASTClassSpecifier)spec4.getOwnedDeclaration(); + IASTClassSpecifier A5 = (IASTClassSpecifier)spec5.getOwnedDeclaration(); + + assertEquals( ((IASTSimpleTypeSpecifier)a1.getAbstractDeclaration().getTypeSpecifier()).getTypeSpecifier(), A1 ); + assertEquals( ((IASTSimpleTypeSpecifier)a2.getAbstractDeclaration().getTypeSpecifier()).getTypeSpecifier(), A2 ); + assertEquals( ((IASTSimpleTypeSpecifier)a4.getAbstractDeclaration().getTypeSpecifier()).getTypeSpecifier(), A4 ); + assertEquals( ((IASTSimpleTypeSpecifier)a5.getAbstractDeclaration().getTypeSpecifier()).getTypeSpecifier(), A5 ); + + } + + public void testTemplateInstanceAsBaseClause() throws Exception + { + Writer writer = new StringWriter(); + writer.write( "template< class T > class A { T t; }; \n" ); + writer.write( "class B : public A< int > {}; \n" ); + writer.write( "void f( int ); \n" ); + + writer.write( "void main(){ \n" ); + writer.write( " B b; \n" ); + writer.write( " f( b.t ); \n" ); //if this function call is good, it implies that b.t is type int + writer.write( "} \n" ); + + Iterator i = parse( writer.toString() ).getDeclarations(); + + IASTTemplateDeclaration template = (IASTTemplateDeclaration) i.next(); + IASTTemplateParameter T = (IASTTemplateParameter) template.getTemplateParameters().next(); + IASTClassSpecifier B = (IASTClassSpecifier)((IASTAbstractTypeSpecifierDeclaration)i.next()).getTypeSpecifier(); + IASTFunction f = (IASTFunction) i.next(); + IASTFunction main = (IASTFunction) i.next(); + assertFalse( i.hasNext() ); + + IASTClassSpecifier A = (IASTClassSpecifier) template.getOwnedDeclaration(); + i = getDeclarations( A ); + IASTField t = (IASTField) i.next(); + assertFalse( i.hasNext() ); + + i = getDeclarations( main ); + + IASTVariable b = (IASTVariable) i.next(); + assertFalse( i.hasNext() ); + + assertAllReferences( 6, createTaskList( new Task( T ), + new Task( A ), + new Task( B ), + new Task( b ), + new Task( t ), + new Task( f ) ) ); + } + + public void testTemplateParameterAsBaseClause() throws Exception + { + Writer writer = new StringWriter(); + writer.write( "template < class T > class A : public T {}; \n" ); + writer.write( "class B { int i; }; \n" ); + writer.write( "void main() { \n" ); + writer.write( " A a; \n" ); + writer.write( " a.i; \n" ); + writer.write( "} \n" ); + writer.write( "\n" ); + + Iterator iter = parse( writer.toString() ).getDeclarations(); + + IASTTemplateDeclaration template = (IASTTemplateDeclaration) iter.next(); + IASTTemplateParameter T = (IASTTemplateParameter) template.getTemplateParameters().next(); + IASTClassSpecifier B = (IASTClassSpecifier)((IASTAbstractTypeSpecifierDeclaration)iter.next()).getTypeSpecifier(); + IASTFunction main = (IASTFunction) iter.next(); + assertFalse( iter.hasNext() ); + + IASTClassSpecifier A = (IASTClassSpecifier) template.getOwnedDeclaration(); + + iter = getDeclarations( B ); + IASTVariable i = (IASTVariable) iter.next(); + + iter = getDeclarations( main ); + IASTVariable a = (IASTVariable) iter.next(); + + assertAllReferences( 4 /*5*/, createTaskList( new Task( T ), + new Task( A ), + //new Task( B ), + new Task( a ), + new Task( i ) ) ); + + } + + + public void testBug55163() throws Exception { Writer writer = new StringWriter(); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/CompleteParseBaseTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/CompleteParseBaseTest.java index 243b05bfcd8..38304da5aca 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/CompleteParseBaseTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/CompleteParseBaseTest.java @@ -733,7 +733,7 @@ public class CompleteParseBaseTest extends TestCase protected void assertReferences( ISourceElementCallbackDelegate element, int expectedDistinctReferenceCount, - boolean allowDuplicates ) + boolean allowDuplicates, boolean allowNameMatching ) { Set matches = new HashSet(); Iterator allReferences = callback.getReferences().iterator(); @@ -748,7 +748,8 @@ public class CompleteParseBaseTest extends TestCase else { if( r.getReferencedElement() instanceof IASTQualifiedNameElement && - element instanceof IASTQualifiedNameElement ) + element instanceof IASTQualifiedNameElement && + allowNameMatching ) { if( qualifiedNamesEquals( ((IASTQualifiedNameElement)r.getReferencedElement()).getFullyQualifiedName(), @@ -770,16 +771,22 @@ public class CompleteParseBaseTest extends TestCase protected static class Task { + private final boolean allowNameMatching; private final boolean unique; private final int count; private final ISourceElementCallbackDelegate element; + public Task( ISourceElementCallbackDelegate element, int referenceCount, boolean distinct, boolean matchNames ){ + this.element = element; + this.count = referenceCount; + this.unique = distinct; + this.allowNameMatching = matchNames; + } + public Task( ISourceElementCallbackDelegate element, int referenceCount, boolean distinct ) { - this.element = element; - this.count = referenceCount; - this.unique = distinct; + this( element, referenceCount, distinct, true ); } public Task( ISourceElementCallbackDelegate element, int referenceCount ) @@ -815,12 +822,16 @@ public class CompleteParseBaseTest extends TestCase { return unique; } + + public boolean allowNameMatching(){ + return allowNameMatching; + } } protected void assertReferenceTask( Task task ) { - assertReferences( task.getElement(), task.getCount(), task.isUnique() ); + assertReferences( task.getElement(), task.getCount(), task.isUnique(), task.allowNameMatching() ); } protected void assertAllReferences( int count, List tasks ) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ScannerTestCase.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ScannerTestCase.java index ef6ef72258c..352fc7123f1 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ScannerTestCase.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ScannerTestCase.java @@ -1564,4 +1564,17 @@ public class ScannerTestCase extends BaseScannerTest validateIdentifier( "Lißä"); validateEOF(); } + public void test54778() throws ScannerException + { + initializeScanner("#if 1 || 0 < 3 \n printf \n #endif\n"); + validateIdentifier("printf"); + validateEOF(); + initializeScanner("#if !defined FOO || FOO > 3\nprintf\n#endif\n"); + validateIdentifier("printf"); + validateEOF(); + initializeScanner("#if !defined FOO || FOO < 3\nprintf\n#endif\n"); + validateIdentifier("printf"); + validateEOF(); + + } } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/Util.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/Util.java index 2dc7b3792c2..590f377eadb 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/Util.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/Util.java @@ -184,7 +184,7 @@ public class Util implements ICLogConstants { if (CCorePlugin.getDefault().isDebugging() && isActive(client)) { // Time stamp if (addTimeStamp) - message = MessageFormat.format("[{0}] {1}", new Object[]{ + message = MessageFormat.format("[{0}] {1}", new Object[]{ //$NON-NLS-1$ new Long(System.currentTimeMillis()), message}); //$NON-NLS-1$ while (message.length() > 100) { String partial = message.substring(0, 100); diff --git a/core/org.eclipse.cdt.core/parser/ChangeLog-parser b/core/org.eclipse.cdt.core/parser/ChangeLog-parser index 8bc671be5fa..195d5aa1507 100644 --- a/core/org.eclipse.cdt.core/parser/ChangeLog-parser +++ b/core/org.eclipse.cdt.core/parser/ChangeLog-parser @@ -1,3 +1,11 @@ +2004-03-18 Andrew Niefer + parsing template-ids: enables clas template partial specializations and fixes 54778 indirectly + - add ITokenDuple.getTemplateIdArgLists + - Added ExpressionParser.templateArgumentList & ExpressionParser.consumeTemplateArguments + - modifications to ExpressionParser & Parser to parse template argument lists + - modified lookups to lookup with template-id if the token duple has argument lists + - modified TemplateFactory to handle partial specializations + 2004-03-17 Andrew Niefer fix bug 55163 - in for-init-statement, try expression-statement before simple-declaration since if it actually is a statement instead of a diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ITokenDuple.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ITokenDuple.java index 08a4b3e6aef..279a67742dc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ITokenDuple.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ITokenDuple.java @@ -11,6 +11,7 @@ package org.eclipse.cdt.core.parser; import java.util.Iterator; +import java.util.List; import org.eclipse.cdt.core.parser.ast.IASTFactory; import org.eclipse.cdt.core.parser.ast.IASTNode; @@ -30,6 +31,7 @@ public interface ITokenDuple { */ public abstract IToken getLastToken(); + public List [] getTemplateIdArgLists(); public abstract Iterator iterator(); public abstract String toString(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ExpressionParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ExpressionParser.java index 52da35235a7..2ba7fa3ce46 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ExpressionParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ExpressionParser.java @@ -11,6 +11,8 @@ package org.eclipse.cdt.internal.core.parser; import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import java.util.Stack; import org.eclipse.cdt.core.parser.BacktrackException; @@ -52,6 +54,8 @@ public class ExpressionParser implements IExpressionParser { protected boolean parsePassed = true; protected ParserLanguage language = ParserLanguage.CPP; protected IASTFactory astFactory = null; + + private Stack templateIdScopes = null; /** * @param scanner2 @@ -149,6 +153,85 @@ public class ExpressionParser implements IExpressionParser { return last; } + protected List templateArgumentList( IASTScope scope ) throws EndOfFileException, BacktrackException + { + IASTExpression expression = null; + List list = new LinkedList(); + + boolean completedArg = false; + boolean failed = false; + + if( templateIdScopes == null ){ + templateIdScopes = new Stack(); + } + templateIdScopes.push( new Integer( IToken.tLT ) ); + + while( LT(1) != IToken.tGT ){ + completedArg = false; + + IToken mark = mark(); + + try{ + IASTTypeId typeId = typeId( scope, false ); + + expression = astFactory.createExpression( scope, IASTExpression.Kind.POSTFIX_TYPEID_TYPEID, + null, null, null, typeId, null, "", null); //$NON-NLS-1$ + list.add( expression ); + completedArg = true; + } catch( BacktrackException e ){ + backup( mark ); + } catch (ASTSemanticException e) { + backup( mark ); + } + + if( ! completedArg ){ + try{ + expression = assignmentExpression( scope ); + if( expression.getExpressionKind() == IASTExpression.Kind.PRIMARY_EMPTY ){ + throw backtrack; + } + list.add( expression ); + completedArg = true; + } catch( BacktrackException e ){ + backup( mark ); + } + } + if( !completedArg ){ + try{ + ITokenDuple nameDuple = name( scope, null ); + expression = astFactory.createExpression( scope, IASTExpression.Kind.ID_EXPRESSION, + null, null, null, null, nameDuple, "", null); //$NON-NLS-1$ + list.add( expression ); + continue; + } catch( ASTSemanticException e ){ + failed = true; + break; + }catch( BacktrackException e ){ + failed = true; + break; + } + } + + if( LT(1) == IToken.tCOMMA ){ + consume(); + } else if( LT(1) != IToken.tGT ){ + failed = true; + break; + } + } + + templateIdScopes.pop(); + if( templateIdScopes.size() == 0 ){ + templateIdScopes = null; + } + + if( failed ) { + throw backtrack; + } + + return list; + } + /** * Parse a template-id, according to the ANSI C++ spec. * @@ -161,8 +244,8 @@ public class ExpressionParser implements IExpressionParser { */ protected IToken templateId(IASTScope scope, CompletionKind kind) throws EndOfFileException, BacktrackException { ITokenDuple duple = name(scope, kind ); - IToken last = consumeTemplateParameters(duple.getLastToken()); - return last; + //IToken last = consumeTemplateParameters(duple.getLastToken()); + return duple.getLastToken();//last; } /** @@ -189,21 +272,16 @@ public class ExpressionParser implements IExpressionParser { if (LT(1) == IToken.tCOMPL) consume(); + List argumentList = new LinkedList(); + boolean hasTemplateId = false; + switch (LT(1)) { case IToken.tIDENTIFIER : last = consume(IToken.tIDENTIFIER); - IToken secondMark = null; - - secondMark = mark(); - - try - { - last = consumeTemplateParameters(last); - } catch( BacktrackException bt ) - { - backup( secondMark ); - } + last = consumeTemplateArguments(scope, last, argumentList); + if( last.getType() == IToken.tGT ) + hasTemplateId = true; break; default : @@ -228,14 +306,44 @@ public class ExpressionParser implements IExpressionParser { throw backtrack; case IToken.tIDENTIFIER : last = consume(); - last = consumeTemplateParameters(last); + last = consumeTemplateArguments(scope, last, argumentList); + if( last.getType() == IToken.tGT ) + hasTemplateId = true; } } - return new TokenDuple(first, last); + return new TokenDuple(first, last, ( hasTemplateId ? argumentList : null ) ); } + /** + * @param scope + * @param last + * @param argumentList + * @return + * @throws EndOfFileException + * @throws BacktrackException + */ + protected IToken consumeTemplateArguments(IASTScope scope, IToken last, List argumentList) throws EndOfFileException, BacktrackException { + if( LT(1) == IToken.tLT ){ + IToken secondMark = mark(); + consume( IToken.tLT ); + try + { + List list = templateArgumentList( scope ); + argumentList.add( list ); + last = consume( IToken.tGT ); + } catch( BacktrackException bt ) + { + argumentList.add( null ); + backup( secondMark ); + } + } else { + argumentList.add( null ); + } + return last; + } + /** * Parse a const-volatile qualifier. * @@ -298,7 +406,7 @@ public class ExpressionParser implements IExpressionParser { } } - protected void operatorId(Declarator d, IToken originalToken) throws BacktrackException, EndOfFileException { + protected void operatorId(Declarator d, IToken originalToken, List templateArgs) throws BacktrackException, EndOfFileException { // we know this is an operator IToken operatorToken = consume(IToken.t_operator); IToken toSend = null; @@ -337,10 +445,17 @@ public class ExpressionParser implements IExpressionParser { typeId(d.getDeclarationWrapper().getScope(), true ); toSend = lastToken; } + + List args = ( templateArgs != null ) ? templateArgs : new LinkedList(); + boolean hasTemplateId = ( templateArgs != null ); + + toSend = consumeTemplateArguments( d.getDeclarationWrapper().getScope(), toSend, args ); + if( toSend.getType() == IToken.tGT ){ + hasTemplateId = true; + } + ITokenDuple duple = - new TokenDuple( - originalToken == null ? operatorToken : originalToken, - toSend); + new TokenDuple( originalToken == null ? operatorToken : originalToken, toSend, (hasTemplateId ? args : null ) ); d.setName(duple); } @@ -814,6 +929,9 @@ public class ExpressionParser implements IExpressionParser { switch (LT(1)) { case IToken.tGT : + if( templateIdScopes != null && ((Integer)templateIdScopes.peek()).intValue() == IToken.tLT ){ + return firstExpression; + } case IToken.tLT : case IToken.tLTEQUAL : case IToken.tGTEQUAL : @@ -1075,12 +1193,15 @@ public class ExpressionParser implements IExpressionParser { { IToken mark = mark(); consume(); + if( templateIdScopes != null ){ templateIdScopes.push( new Integer( IToken.tLPAREN ) ); } + boolean popped = false; IASTTypeId typeId = null; // If this isn't a type name, then we shouldn't be here try { typeId = typeId(scope, false); consume(IToken.tRPAREN); + if( templateIdScopes != null ){ templateIdScopes.pop(); popped = true;} IASTExpression castExpression = castExpression(scope); try { @@ -1104,6 +1225,7 @@ public class ExpressionParser implements IExpressionParser { catch (BacktrackException b) { backup(mark); + if( templateIdScopes != null && !popped ){ templateIdScopes.pop(); } } } return unaryExpression(scope); @@ -1274,8 +1396,9 @@ public class ExpressionParser implements IExpressionParser { TypeId id = new TypeId(scope); IToken last = lastToken; - lastToken = consumeTemplateParameters( last ); - if( lastToken == null ) lastToken = last; + //template parameters are consumed as part of name + //lastToken = consumeTemplateParameters( last ); + //if( lastToken == null ) lastToken = last; consumePointerOperators( id ); if( lastToken == null ) lastToken = last; @@ -1378,7 +1501,8 @@ public class ExpressionParser implements IExpressionParser { if (LT(1) == IToken.tLPAREN) { - consume(IToken.tLPAREN); + consume(IToken.tLPAREN); + if( templateIdScopes != null ){ templateIdScopes.push( new Integer( IToken.tLPAREN ) ); } try { // Try to consume placement list @@ -1386,11 +1510,13 @@ public class ExpressionParser implements IExpressionParser { backtrackMarker = mark(); newPlacementExpressions.add(expression(scope)); consume(IToken.tRPAREN); + if( templateIdScopes != null ){ templateIdScopes.pop(); } //pop 1st Parent placementParseFailure = false; if (LT(1) == IToken.tLPAREN) { beforeSecondParen = mark(); consume(IToken.tLPAREN); + if( templateIdScopes != null ){ templateIdScopes.push( new Integer( IToken.tLPAREN ) ); } //push 2nd Paren typeIdInParen = true; } } @@ -1405,6 +1531,7 @@ public class ExpressionParser implements IExpressionParser { // - then it has to be typeId typeId = typeId(scope, true ); consume(IToken.tRPAREN); + if( templateIdScopes != null ){ templateIdScopes.pop(); } //pop 1st Paren } else { @@ -1448,6 +1575,8 @@ public class ExpressionParser implements IExpressionParser { { typeId = typeId(scope, true); consume(IToken.tRPAREN); + if( templateIdScopes != null ){ templateIdScopes.pop(); } //popping the 2nd Paren + if (LT(1) == IToken.tLPAREN || LT(1) == IToken.tLBRACKET) { @@ -1485,6 +1614,7 @@ public class ExpressionParser implements IExpressionParser { // CASE: new (typeid-looking-as-placement)(initializer-not-looking-as-typeid) // Fallback to initializer processing backup(beforeSecondParen); + if( templateIdScopes != null ){ templateIdScopes.pop(); }//pop that 2nd paren } } } @@ -1500,16 +1630,25 @@ public class ExpressionParser implements IExpressionParser { { // array new consume(); + + if( templateIdScopes != null ){ templateIdScopes.push( new Integer( IToken.tLBRACKET ) ); } + newTypeIdExpressions.add(assignmentExpression(scope)); consume(IToken.tRBRACKET); + + if( templateIdScopes != null ){ templateIdScopes.pop(); } } // newinitializer if (LT(1) == IToken.tLPAREN) { consume(IToken.tLPAREN); + if( templateIdScopes != null ){ templateIdScopes.push( new Integer( IToken.tLPAREN ) ); } + if (LT(1) != IToken.tRPAREN) newInitializerExpressions.add(expression(scope)); + consume(IToken.tRPAREN); + if( templateIdScopes != null ){ templateIdScopes.pop(); } } setCompletionValues(scope, CompletionKind.NO_SUCH_KIND, Key.EMPTY); try @@ -1673,8 +1812,7 @@ public class ExpressionParser implements IExpressionParser { ITokenDuple templateId = null; try { - templateId = new TokenDuple( current, templateId(scope, CompletionKind.SINGLE_NAME_REFERENCE - ) ); + templateId = new TokenDuple( current, templateId(scope, CompletionKind.SINGLE_NAME_REFERENCE ) ); } catch( BacktrackException bt ) { @@ -1683,8 +1821,10 @@ public class ExpressionParser implements IExpressionParser { backup( current ); } consume( IToken.tLPAREN ); + if( templateIdScopes != null ){ templateIdScopes.push( new Integer( IToken.tLPAREN ) ); } IASTExpression expressionList = expression( scope ); consume( IToken.tRPAREN ); + if( templateIdScopes != null ){ templateIdScopes.pop(); } try { firstExpression = astFactory.createExpression( scope, @@ -1777,6 +1917,7 @@ public class ExpressionParser implements IExpressionParser { case IToken.t_typeid : consume(); consume(IToken.tLPAREN); + if( templateIdScopes != null ){ templateIdScopes.push( new Integer( IToken.tLPAREN ) ); } boolean isTypeId = true; IASTExpression lhs = null; IASTTypeId typeId = null; @@ -1790,6 +1931,7 @@ public class ExpressionParser implements IExpressionParser { lhs = expression(scope); } consume(IToken.tRPAREN); + if( templateIdScopes != null ){ templateIdScopes.pop(); } try { firstExpression = @@ -1824,8 +1966,10 @@ public class ExpressionParser implements IExpressionParser { case IToken.tLBRACKET : // array access consume(); + if( templateIdScopes != null ){ templateIdScopes.push( new Integer( IToken.tLBRACKET ) ); } secondExpression = expression(scope); consume(IToken.tRBRACKET); + if( templateIdScopes != null ){ templateIdScopes.pop(); } try { firstExpression = @@ -1850,8 +1994,10 @@ public class ExpressionParser implements IExpressionParser { case IToken.tLPAREN : // function call consume(IToken.tLPAREN); + if( templateIdScopes != null ){ templateIdScopes.push( new Integer( IToken.tLPAREN ) ); } secondExpression = expression(scope); consume(IToken.tRPAREN); + if( templateIdScopes != null ){ templateIdScopes.pop(); } try { firstExpression = @@ -2189,8 +2335,10 @@ public class ExpressionParser implements IExpressionParser { } case IToken.tLPAREN : consume(); + if( templateIdScopes != null ){ templateIdScopes.push( new Integer( IToken.tLPAREN ) ); } IASTExpression lhs = expression(scope); consume(IToken.tRPAREN); + if( templateIdScopes != null ){ templateIdScopes.pop(); } try { return astFactory.createExpression( @@ -2236,7 +2384,7 @@ public class ExpressionParser implements IExpressionParser { end = consumeTemplateParameters(end); } if (LT(1) == IToken.t_operator) - operatorId(d, start); + operatorId(d, start, null); else { backup(mark); @@ -2244,7 +2392,7 @@ public class ExpressionParser implements IExpressionParser { } } else if( LT(1) == IToken.t_operator ) - operatorId( d, null); + operatorId( d, null, null); duple = d.getNameDuple(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Parser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Parser.java index 3952b266cb4..f5d5bf32651 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Parser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Parser.java @@ -11,6 +11,7 @@ package org.eclipse.cdt.internal.core.parser; import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import org.eclipse.cdt.core.parser.BacktrackException; @@ -1703,13 +1704,15 @@ public abstract class Parser extends ExpressionParser implements IParser */ protected ITokenDuple className(IASTScope scope) throws EndOfFileException, BacktrackException { - ITokenDuple duple = name(scope, CompletionKind.USER_SPECIFIED_NAME ); - IToken last = duple.getLastToken(); - if (LT(1) == IToken.tLT) { - last = consumeTemplateParameters(duple.getLastToken()); - } - - return new TokenDuple(duple.getFirstToken(), last); +// ITokenDuple duple = name(scope, CompletionKind.USER_SPECIFIED_NAME ); +// IToken last = duple.getLastToken(); +// if (LT(1) == IToken.tLT) { +// last = consumeTemplateParameters(duple.getLastToken()); +// //last = templateArgumentList( scope, duple.getLastToken() ); +// } +// +// return new TokenDuple(duple.getFirstToken(), last); + return name( scope, CompletionKind.USER_SPECIFIED_NAME ); } /** @@ -2196,7 +2199,7 @@ public abstract class Parser extends ExpressionParser implements IParser throws EndOfFileException, BacktrackException { if (LT(1) == IToken.t_operator) - operatorId(d, null); + operatorId(d, null, null); else { try @@ -2210,23 +2213,35 @@ public abstract class Parser extends ExpressionParser implements IParser Declarator d1 = d; Declarator d11 = d1; IToken start = null; + + List argumentList = new LinkedList(); + boolean hasTemplateId = false; + IToken mark = mark(); if (LT(1) == IToken.tCOLONCOLON || LT(1) == IToken.tIDENTIFIER) { start = consume(); IToken end = null; - if (start.getType() == IToken.tIDENTIFIER) - end = consumeTemplateParameters(end); - while (LT(1) == IToken.tCOLONCOLON - || LT(1) == IToken.tIDENTIFIER) - { - end = consume(); - if (end.getType() == IToken.tIDENTIFIER) - end = consumeTemplateParameters(end); + + if (start.getType() == IToken.tIDENTIFIER){ + end = consumeTemplateArguments(d.getDeclarationWrapper().getScope(), end, argumentList); + if( end != null && end.getType() == IToken.tGT ) + hasTemplateId = true; + } + + while (LT(1) == IToken.tCOLONCOLON + || LT(1) == IToken.tIDENTIFIER) + { + end = consume(); + if (end.getType() == IToken.tIDENTIFIER){ + end = consumeTemplateArguments(d.getDeclarationWrapper().getScope(), end, argumentList); + if( end.getType() == IToken.tGT ) + hasTemplateId = true; } + } if (LT(1) == IToken.t_operator) - operatorId(d11, start); + operatorId(d11, start, ( hasTemplateId ? argumentList : null ) ); else { backup(mark); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ast/complete/ASTParameterDeclaration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ast/complete/ASTParameterDeclaration.java index ca3bd93852a..37d9eedf220 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ast/complete/ASTParameterDeclaration.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ast/complete/ASTParameterDeclaration.java @@ -15,6 +15,7 @@ import java.util.List; import org.eclipse.cdt.core.parser.ISourceElementRequestor; import org.eclipse.cdt.core.parser.ast.ASTPointerOperator; +import org.eclipse.cdt.core.parser.ast.IASTAbstractDeclaration; import org.eclipse.cdt.core.parser.ast.IASTInitializerClause; import org.eclipse.cdt.core.parser.ast.IASTParameterDeclaration; import org.eclipse.cdt.core.parser.ast.IASTTypeSpecifier; @@ -114,6 +115,11 @@ public class ASTParameterDeclaration extends ASTSymbol implements IASTParameterD { return abstractDeclaration.getTypeSpecifier(); } + + public IASTAbstractDeclaration getAbstractDeclaration(){ + return abstractDeclaration; + } + /* (non-Javadoc) * @see org.eclipse.cdt.core.parser.ISourceElementCallbackDelegate#acceptElement(org.eclipse.cdt.core.parser.ISourceElementRequestor) */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ast/complete/CompleteParseASTFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ast/complete/CompleteParseASTFactory.java index be30740b101..36f7c86ce40 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ast/complete/CompleteParseASTFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ast/complete/CompleteParseASTFactory.java @@ -17,6 +17,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Stack; import java.util.StringTokenizer; import org.eclipse.cdt.core.parser.Enum; @@ -91,6 +92,7 @@ import org.eclipse.cdt.internal.core.parser.pst.NamespaceSymbolExtension; import org.eclipse.cdt.internal.core.parser.pst.ParserSymbolTable; import org.eclipse.cdt.internal.core.parser.pst.ParserSymbolTableException; import org.eclipse.cdt.internal.core.parser.pst.StandardSymbolExtension; +import org.eclipse.cdt.internal.core.parser.pst.TemplateSymbolExtension; import org.eclipse.cdt.internal.core.parser.pst.TypeInfo; import org.eclipse.cdt.internal.core.parser.pst.ISymbolASTExtension.ExtensionException; @@ -177,6 +179,10 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto } private ISymbol lookupElement (IContainerSymbol startingScope, String name, TypeInfo.eType type, List parameters, LookupType lookupType ) throws ASTSemanticException { + return lookupElement( startingScope, name, type, parameters, null, lookupType ); + } + + private ISymbol lookupElement (IContainerSymbol startingScope, String name, TypeInfo.eType type, List parameters, List arguments, LookupType lookupType ) throws ASTSemanticException { ISymbol result = null; if( startingScope == null ) return null; try { @@ -188,7 +194,9 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto result = startingDerivableScope.lookupConstructor( new LinkedList(parameters)); } else { - if( lookupType == LookupType.QUALIFIED ) + if( arguments != null ) + result = startingScope.lookupFunctionTemplateId( name, new LinkedList( parameters), new LinkedList( arguments ) ); + else if( lookupType == LookupType.QUALIFIED ) result = startingScope.qualifiedFunctionLookup(name, new LinkedList(parameters)); else if( lookupType == LookupType.UNQUALIFIED || lookupType == LookupType.FORPARENTSCOPE) result = startingScope.unqualifiedFunctionLookup( name, new LinkedList( parameters ) ); @@ -202,7 +210,9 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto result = null; }else{ // looking for something else - if( lookupType == LookupType.QUALIFIED ) + if( arguments != null ) + result = startingScope.lookupTemplateId( name, arguments ); + else if( lookupType == LookupType.QUALIFIED ) result = startingScope.qualifiedLookup(name, type); else if( lookupType == LookupType.UNQUALIFIED || lookupType == LookupType.FORPARENTSCOPE ) result = startingScope.elaboratedLookup( type, name ); @@ -264,6 +274,8 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto if( name == null && throwOnError ) handleProblem( IProblem.SEMANTIC_NAME_NOT_PROVIDED, null ); else if( name == null ) return null; + List [] templateArgLists = name.getTemplateIdArgLists(); + int idx = 0; switch( name.length() ) { case 0: @@ -307,19 +319,37 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto while( iter.hasNext() ) { IToken t = (IToken)iter.next(); - if( t.getType() == IToken.tCOLONCOLON ) continue; + if( t.getType() == IToken.tCOLONCOLON ){ + idx++; + continue; + } if( t.isPointer() ) break; + + String image = t.getImage(); + int offset = t.getOffset(); + + if( templateArgLists != null && templateArgLists[ idx ] != null ){ + t = consumeTemplateIdArguments( t, iter ); + } + try { if( t == name.getLastToken() ) - result = lookupElement((IContainerSymbol)result, t.getImage(), type, parameters, ( lookup == LookupType.FORDEFINITION ) ? lookup : LookupType.QUALIFIED ); + if( templateArgLists != null ) + result = lookupElement((IContainerSymbol)result, image, type, parameters, getTemplateArgList( templateArgLists[idx] ), ( lookup == LookupType.FORDEFINITION ) ? lookup : LookupType.QUALIFIED ); + else + result = lookupElement((IContainerSymbol)result, image, type, parameters, ( lookup == LookupType.FORDEFINITION ) ? lookup : LookupType.QUALIFIED ); else - result = ((IContainerSymbol)result).lookupNestedNameSpecifier( t.getImage() ); + if( templateArgLists != null ) + result = ((IContainerSymbol)result).lookupTemplateId( image, getTemplateArgList( templateArgLists[idx] ) ); + else + result = ((IContainerSymbol)result).lookupNestedNameSpecifier( image ); + if( result != null ){ if( lookup == LookupType.FORPARENTSCOPE && startingScope instanceof ITemplateFactory ){ ((ITemplateFactory)startingScope).pushSymbol( result ); } - addReference( references, createReference( result, t.getImage(), t.getOffset() )); + addReference( references, createReference( result, image, offset )); } else break; @@ -327,7 +357,7 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto catch( ParserSymbolTableException pste ) { if ( throwOnError ) - handleProblem( pste.createProblemID(), t.getImage() ); + handleProblem( pste.createProblemID(), image ); return null; } } @@ -335,7 +365,50 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto return result; } - + protected IToken consumeTemplateIdArguments( IToken name, Iterator iter ){ + IToken token = name; + if( token.getNext().getType() == IToken.tLT ) + { + token = (IToken) iter.next(); + Stack scopes = new Stack(); + scopes.push(new Integer(IToken.tLT)); + + while (!scopes.empty()) + { + int top; + + token = (IToken) iter.next(); + switch( token.getType() ){ + case IToken.tGT: + if (((Integer)scopes.peek()).intValue() == IToken.tLT) { + scopes.pop(); + } + break; + case IToken.tRBRACKET : + do { + top = ((Integer)scopes.pop()).intValue(); + } while (!scopes.empty() && (top == IToken.tGT || top == IToken.tLT)); + //if (top != IToken.tLBRACKET) throw backtrack; + break; + case IToken.tRPAREN : + do { + top = ((Integer)scopes.pop()).intValue(); + } while (!scopes.empty() && (top == IToken.tGT || top == IToken.tLT)); + //if (top != IToken.tLPAREN) throw backtrack; + + break; + case IToken.tLT : + case IToken.tLBRACKET: + case IToken.tLPAREN: + scopes.push(new Integer(token.getType())); + break; + + } + } + } + + return token; + } /* (non-Javadoc) * @see org.eclipse.cdt.core.parser.ast.IASTFactory#createUsingDirective(org.eclipse.cdt.core.parser.ast.IASTScope, org.eclipse.cdt.core.parser.ITokenDuple, int, int) */ @@ -525,7 +598,10 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto { extension = new ForewardDeclaredSymbolExtension( symbol, astSymbol ); } - else + else if( astSymbol instanceof IASTTemplateDeclaration ){ + extension = new TemplateSymbolExtension( symbol, astSymbol ); + } + else { extension = new StandardSymbolExtension( symbol, astSymbol ); } @@ -569,23 +645,37 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto List references = new ArrayList(); String newSymbolName = ""; //$NON-NLS-1$ + List templateIdArgList = null; + boolean isTemplateId = false; if( name != null ){ IToken lastToken = name.getLastToken(); if( name.length() != 1 ) // qualified name { - ITokenDuple containerSymbolName = - name.getSubrange( 0, name.length() - 3 ); // -1 for index, -2 for last hop of qualified name - currentScopeSymbol = (IContainerSymbol)lookupQualifiedName( currentScopeSymbol, - containerSymbolName, references, true); - if( currentScopeSymbol == null ) - handleProblem( IProblem.SEMANTIC_NAME_NOT_FOUND, containerSymbolName.toString(), containerSymbolName.getFirstToken().getOffset(), containerSymbolName.getLastToken().getEndOffset(), containerSymbolName.getLastToken().getLineNumber() ); + int idx = name.findLastTokenType( IToken.tCOLONCOLON ); + if( idx != -1 ){ + ITokenDuple containerSymbolName = + name.getSubrange( 0, idx - 1 ); // -1 for index, -2 for last hop of qualified name + currentScopeSymbol = (IContainerSymbol)lookupQualifiedName( currentScopeSymbol, + containerSymbolName, references, true); + if( currentScopeSymbol == null ) + handleProblem( IProblem.SEMANTIC_NAME_NOT_FOUND, containerSymbolName.toString(), containerSymbolName.getFirstToken().getOffset(), containerSymbolName.getLastToken().getEndOffset(), containerSymbolName.getLastToken().getLineNumber() ); + } + + //template-id + List [] array = name.getTemplateIdArgLists(); + if( array != null ){ + isTemplateId = true; + templateIdArgList = array[ array.length - 1 ]; + lastToken = name.getToken( idx + 1); + } + } newSymbolName = lastToken.getImage(); } ISymbol classSymbol = null; - if( !newSymbolName.equals("") ){ //$NON-NLS-1$ + if( !newSymbolName.equals("") && !isTemplateId ){ //$NON-NLS-1$ try { classSymbol = currentScopeSymbol.lookupMemberForDefinition(newSymbolName); @@ -607,9 +697,16 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto if( classSymbol != null ) classSymbol.setTypeSymbol( newSymbol ); + List args = null; + if( isTemplateId ){ + args = getTemplateArgList( templateIdArgList ); + } try { - currentScopeSymbol.addSymbol( newSymbol ); + if( !isTemplateId ) + currentScopeSymbol.addSymbol( newSymbol ); + else + currentScopeSymbol.addTemplateId( newSymbol, args ); } catch (ParserSymbolTableException e2) { @@ -621,6 +718,25 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto return classSpecifier; } + private List getTemplateArgList( List args ){ + if( args == null ) + return null; + + List list = new LinkedList(); + Iterator iter = args.iterator(); + + ASTExpression exp; + while( iter.hasNext() ) + { + exp = (ASTExpression) iter.next(); + + TypeInfo info = exp.getResultType().getResult();; + + list.add( info ); + } + + return list; + } protected void handleProblem( int id, String attribute ) throws ASTSemanticException { @@ -692,8 +808,9 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto } else handleProblem( IProblem.SEMANTIC_NAME_NOT_PROVIDED, null ); - - IContainerSymbol symbol = (IContainerSymbol) lookupQualifiedName( classSymbol, parentClassName, references, true ); + + //Its possible that the parent is not an IContainerSymbol if its a template parameter or some kinds of template instances + ISymbol symbol = (ISymbol) lookupQualifiedName( classSymbol, parentClassName, references, true ); classSymbol.addParent( symbol, isVirtual, visibility, parentClassName.getFirstToken().getOffset(), references ); } @@ -840,7 +957,7 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto if( idExpression != null ) { logMessage.append( " idexpression=" ); //$NON-NLS-1$ - logMessage.append( "idExpression.toString()"); //$NON-NLS-1$ + logMessage.append( idExpression.toString()); //$NON-NLS-1$ } else if( literal != null && !literal.equals( "" )) //$NON-NLS-1$ { @@ -1091,7 +1208,9 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto ExpressionResult result = null; TypeInfo info = new TypeInfo(); - + if( literal != null && !literal.equals("") ){ //$NON-NLS-1$ + info.setDefault( literal ); + } // types that resolve to void if ((kind == IASTExpression.Kind.PRIMARY_EMPTY) || (kind == IASTExpression.Kind.THROWEXPRESSION) @@ -1574,26 +1693,42 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto ISymbol typeSymbol = getScopeToSearchUpon( scope, first, i ); + List [] argLists = typeName.getTemplateIdArgLists(); + int idx = 0; + while( i.hasNext() ) { IToken current = (IToken)i.next(); - if( current.getType() == IToken.tCOLONCOLON ) continue; + + if( current.getType() == IToken.tCOLONCOLON ){ + idx++; + continue; + } + + String image = current.getImage(); + int offset = current.getOffset(); + + if( argLists != null && argLists[ idx ] != null ){ + current = consumeTemplateIdArguments( current, i ); + } try { - if( current != typeName.getLastToken() ) - typeSymbol = ((IContainerSymbol)typeSymbol).lookupNestedNameSpecifier( current.getImage()); + if( argLists != null && argLists[ idx ] != null ) + typeSymbol = ((IContainerSymbol)typeSymbol).lookupTemplateId( image, getTemplateArgList( argLists[idx] ) ); + else if( current != typeName.getLastToken() ) + typeSymbol = ((IContainerSymbol)typeSymbol).lookupNestedNameSpecifier( image ); else - typeSymbol = ((IContainerSymbol)typeSymbol).lookup( current.getImage()); + typeSymbol = ((IContainerSymbol)typeSymbol).lookup( image ); if( typeSymbol != null ) - addReference( references, createReference( typeSymbol, current.getImage(), current.getOffset() )); + addReference( references, createReference( typeSymbol, image, offset )); else - handleProblem( IProblem.SEMANTIC_NAME_NOT_FOUND, current.getImage() ); + handleProblem( IProblem.SEMANTIC_NAME_NOT_FOUND, image ); } catch (ParserSymbolTableException e) { - handleProblem( e.createProblemID(), current.getImage() ); + handleProblem( e.createProblemID(), image ); } } s.setTypeSymbol( typeSymbol ); @@ -2472,7 +2607,7 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto try { template.addTemplateParameter( param.getSymbol() ); } catch (ParserSymbolTableException e) { - handleProblem( e.createProblemID(), "", startingOffset, -1, startingLine ); + handleProblem( e.createProblemID(), "", startingOffset, -1, startingLine ); //$NON-NLS-1$ } } @@ -2492,21 +2627,23 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto IASTParameterDeclaration parameter, List parms ) throws ASTSemanticException { - ISymbol symbol = ( kind != ParamKind.PARAMETER ) ? pst.newSymbol( identifier, TypeInfo.t_templateParameter ) : null; + ISymbol symbol = pst.newSymbol( identifier, TypeInfo.t_templateParameter ); if( kind == ParamKind.CLASS || kind == ParamKind.TYPENAME ){ symbol.getTypeInfo().setTemplateParameterType( TypeInfo.t_typeName ); } else if ( kind == ParamKind.TEMPLATE_LIST ){ symbol.getTypeInfo().setTemplateParameterType( TypeInfo.t_template ); } else /*ParamKind.PARAMETER*/ { - symbol = ((ASTParameterDeclaration)parameter).getSymbol(); + symbol.setName( parameter.getName() ); + symbol.setTypeInfo( ((ASTSimpleTypeSpecifier)parameter.getTypeSpecifier()).getSymbol().getTypeInfo() ); symbol.getTypeInfo().setTemplateParameterType( symbol.getType() ); symbol.setType( TypeInfo.t_templateParameter ); + + setPointerOperators( symbol, parameter.getPointerOperators(), parameter.getArrayModifiers() ); } ASTTemplateParameter ast = new ASTTemplateParameter( symbol, defaultValue, parameter, parms ); - //TODO what if the symbol was ParamKind.PARAMETER? - attachSymbolExtension( symbol, ast, false ); + attachSymbolExtension( symbol, ast, false ); return ast; } @@ -2544,7 +2681,7 @@ public class CompleteParseASTFactory extends BaseASTFactory implements IASTFacto ISymbol newSymbol = pst.newSymbol( name, TypeInfo.t_type); newSymbol.getTypeInfo().setBit( true,TypeInfo.isTypedef ); - ISymbol typeSymbol = cloneSimpleTypeSymbol( "", mapping, new ArrayList() ); + ISymbol typeSymbol = cloneSimpleTypeSymbol( "", mapping, new ArrayList() ); //$NON-NLS-1$ setPointerOperators( typeSymbol, mapping.getPointerOperators(), mapping.getArrayModifiers() ); newSymbol.setTypeSymbol( typeSymbol ); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ContainerSymbol.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ContainerSymbol.java index 2338bba0908..90aa02d5d8f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ContainerSymbol.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/ContainerSymbol.java @@ -1063,6 +1063,21 @@ public class ContainerSymbol extends BasicSymbol implements IContainerSymbol { private LinkedList _contents; //ordered list of all contents of this symbol private LinkedList _usingDirectives; //collection of nominated namespaces private Map _containedSymbols; //declarations contained by us. + /* (non-Javadoc) + * @see org.eclipse.cdt.internal.core.parser.pst.IContainerSymbol#addTemplateId(org.eclipse.cdt.internal.core.parser.pst.ISymbol, java.util.List) + */ + public void addTemplateId(ISymbol symbol, List args) throws ParserSymbolTableException { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.internal.core.parser.pst.IContainerSymbol#lookupFunctionTemplateId(java.lang.String, java.util.List, java.util.List) + */ + public ISymbol lookupFunctionTemplateId(String name, List parameters, List arguments) throws ParserSymbolTableException { + // TODO Auto-generated method stub + return null; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DeferredTemplateInstance.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DeferredTemplateInstance.java index 67b880aa4ed..80839cd78c1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DeferredTemplateInstance.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DeferredTemplateInstance.java @@ -69,6 +69,22 @@ public class DeferredTemplateInstance extends BasicSymbol implements IDeferredTe return instance; } + public boolean isType( TypeInfo.eType type, TypeInfo.eType upperType ){ + return _template.getTemplatedSymbol().isType( type, upperType ); + } + + public TypeInfo.eType getType(){ + return _template.getTemplatedSymbol().getType(); + } + + public boolean isType( TypeInfo.eType type ){ + return _template.getTemplatedSymbol().isType( type ); + } + + public ISymbolASTExtension getASTExtension() { + return _template.getTemplatedSymbol().getASTExtension(); + } + private ITemplateSymbol _template; private List _arguments; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DerivableContainerSymbol.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DerivableContainerSymbol.java index e5973f641bf..5bdc1db408c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DerivableContainerSymbol.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/DerivableContainerSymbol.java @@ -79,13 +79,13 @@ public class DerivableContainerSymbol extends ContainerSymbol implements IDeriva newSymbol.getParents().add( newWrapper ); } - Iterator constructors = getConstructors().iterator(); - newSymbol.getConstructors().clear(); - IParameterizedSymbol constructor = null; - while( constructors.hasNext() ){ - constructor = (IParameterizedSymbol) constructors.next(); - newSymbol.getConstructors().add( constructor.instantiate( template, argMap ) ); - } +// Iterator constructors = getConstructors().iterator(); +// newSymbol.getConstructors().clear(); +// IParameterizedSymbol constructor = null; +// while( constructors.hasNext() ){ +// constructor = (IParameterizedSymbol) constructors.next(); +// newSymbol.getConstructors().add( constructor.instantiate( template, argMap ) ); +// } //TODO: friends @@ -156,6 +156,8 @@ public class DerivableContainerSymbol extends ContainerSymbol implements IDeriva } constructor.setContainingSymbol( this ); + constructor.setIsTemplateMember( isTemplateMember() || getType() == TypeInfo.t_template ); + addThis( constructor ); getContents().add( constructor ); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/IContainerSymbol.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/IContainerSymbol.java index fc988a69e97..e4afa642679 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/IContainerSymbol.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/IContainerSymbol.java @@ -37,6 +37,8 @@ public interface IContainerSymbol extends ISymbol { * hide the first symbol (3.3.7) or is not a valid function overload (3.4-1) */ public void addSymbol( ISymbol symbol ) throws ParserSymbolTableException; + + public void addTemplateId( ISymbol symbol, List args ) throws ParserSymbolTableException; public boolean removeSymbol( ISymbol symbol ); @@ -117,6 +119,7 @@ public interface IContainerSymbol extends ISymbol { * r_BadTemplateArgument if (14.3.1, 14.3.2) a template argument is invalid */ public ISymbol lookupTemplateId( String name, List arguments ) throws ParserSymbolTableException; + public ISymbol lookupFunctionTemplateId( String name, List parameters, List arguments ) throws ParserSymbolTableException; public IContainerSymbol lookupTemplateIdForDefinition( String name, List arguments ) throws ParserSymbolTableException; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateEngine.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateEngine.java index 7d1adac7cc8..322b0761f6a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateEngine.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateEngine.java @@ -702,14 +702,13 @@ public final class TemplateEngine { return -1; } - Iterator iter = spec1.getContainedSymbols().keySet().iterator(); - ISymbol decl = (ISymbol) spec1.getContainedSymbols().get( iter.next() ); + ISymbol decl = (ISymbol) spec1.getTemplatedSymbol(); //to order class template specializations, we need to transform them into function templates ITemplateSymbol template1 = spec1; ITemplateSymbol template2 = spec2; - if( decl.isType( TypeInfo.t_class ) ) { + if( decl.isType( TypeInfo.t_class, TypeInfo.t_union ) ) { template1 = classTemplateSpecializationToFunctionTemplate( spec1 ); template2 = classTemplateSpecializationToFunctionTemplate( spec2 ); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateFactory.java index 9abefba3119..0f7e934dc09 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateFactory.java @@ -51,6 +51,51 @@ public class TemplateFactory extends ExtensibleSymbol implements ITemplateFactor argMap.put( symbol, new LinkedList( args ) ); } + /* (non-Javadoc) + * @see org.eclipse.cdt.internal.core.parser.pst.IContainerSymbol#addTemplateId(org.eclipse.cdt.internal.core.parser.pst.ISymbol, java.util.List) + */ + public void addTemplateId(ISymbol symbol, List args) throws ParserSymbolTableException { + ISymbol previous = findPreviousSymbol( symbol ); + ITemplateSymbol origTemplate = (previous != null ) ? (ITemplateSymbol) previous.getContainingSymbol() : null; + + if( origTemplate == null ){ + throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTemplate ); + } + + ITemplateSymbol template = (ITemplateSymbol) templates.get( templates.size() - 1 ); + + List params = template.getParameterList(); + if( params.size() == 0 ){ + //explicit specialization + + } else { + //partial speciailization + ISpecializedSymbol spec = template.getSymbolTable().newSpecializedSymbol( symbol.getName() ); + Iterator iter = params.iterator(); + while( iter.hasNext() ){ + spec.addTemplateParameter( (ISymbol) iter.next() ); + } + iter = args.iterator(); + while( iter.hasNext() ){ + spec.addArgument( (TypeInfo) iter.next() ); + } + + spec.addSymbol( symbol ); + origTemplate.addSpecialization( spec ); + + //replace the symbol attached to the AST node. + if( getASTExtension() != null ){ + TemplateSymbolExtension extension = (TemplateSymbolExtension) template.getASTExtension(); + extension.replaceSymbol( spec ); + ASTTemplateDeclaration templateDecl = (ASTTemplateDeclaration) getASTExtension().getPrimaryDeclaration(); + templateDecl.releaseFactory(); + templateDecl.setSymbol( spec ); + } + } + + + } + public void addSymbol(ISymbol symbol) throws ParserSymbolTableException { lastSymbol = (IContainerSymbol) (( symbols.size() > 0 ) ? symbols.get( symbols.size() - 1) : null); @@ -804,4 +849,11 @@ public class TemplateFactory extends ExtensibleSymbol implements ITemplateFactor return null; } + /* (non-Javadoc) + * @see org.eclipse.cdt.internal.core.parser.pst.IContainerSymbol#lookupFunctionTemplateId(java.lang.String, java.util.List, java.util.List) + */ + public ISymbol lookupFunctionTemplateId(String name, List parameters, List arguments) throws ParserSymbolTableException { + // TODO Auto-generated method stub + return null; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateSymbolExtension.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateSymbolExtension.java new file mode 100644 index 00000000000..acf79baa65c --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/pst/TemplateSymbolExtension.java @@ -0,0 +1,40 @@ +/* + * Created on Mar 15, 2004 + * + * To change the template for this generated file go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +package org.eclipse.cdt.internal.core.parser.pst; + +import org.eclipse.cdt.internal.core.parser.ast.complete.ASTSymbol; + +/** + * @author aniefer + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class TemplateSymbolExtension extends StandardSymbolExtension { + + protected ISymbol replacement = null; + + /** + * @param symbol + * @param primaryDeclaration + */ + public TemplateSymbolExtension(ISymbol symbol, ASTSymbol primaryDeclaration) { + super(symbol, primaryDeclaration); + } + + /** + * @param spec + */ + public void replaceSymbol(ISpecializedSymbol spec) { + replacement = spec; + spec.setASTExtension( this ); + } + + public ISymbol getSymbol(){ + return ( replacement == null ) ? super.getSymbol() : replacement; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/TokenDuple.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/TokenDuple.java index a26e95b049d..e3cea62ec9e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/TokenDuple.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/TokenDuple.java @@ -11,6 +11,7 @@ package org.eclipse.cdt.internal.core.parser.token; import java.util.Iterator; +import java.util.List; import java.util.NoSuchElementException; import org.eclipse.cdt.core.parser.IToken; @@ -31,8 +32,21 @@ public class TokenDuple implements ITokenDuple { // assert ( first != null && last != null ) : this; firstToken = first; lastToken = last; + argLists = null; } - protected final IToken firstToken, lastToken; + + public TokenDuple( IToken first, IToken last, List templateArgLists ){ + firstToken = first; + lastToken = last; + if( templateArgLists != null && !templateArgLists.isEmpty() ){ + argLists = (List[]) templateArgLists.toArray( new List [templateArgLists.size()] ); + } else { + argLists = null; + } + } + + protected final IToken firstToken, lastToken; + protected final List [] argLists; /** * @return */ @@ -209,4 +223,11 @@ public class TokenDuple implements ITokenDuple { public int getStartOffset() { return getFirstToken().getOffset(); } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.parser.ITokenDuple#getTemplateIdArgLists() + */ + public List[] getTemplateIdArgLists() { + return argLists; + } }