From 2c18a23f892be8c3aedea8b796b62066036ad17e Mon Sep 17 00:00:00 2001 From: John Camelon Date: Tue, 13 Jan 2004 17:07:02 +0000 Subject: [PATCH] CORE Fixed bug 48909 - Wrong completion node after a . or an -> Fixed bug 49702 - Wrong completion kind sent in const/dest and code blocks Added new CompletionKind - STATEMENT_START to indicate the beginning of a statement line. TESTS Updated ContextualParseTest to accommodate bugfixes 48909 & 49702. UI Updated CompletionEngine to handle IASTCompletionKind.CompletionKind.STATEMENT_START --- core/org.eclipse.cdt.core.tests/ChangeLog | 3 + .../parser/tests/ContextualParseTest.java | 245 +++++++++++--- .../parser/ChangeLog-parser | 6 + .../core/parser/ast/IASTCompletionNode.java | 4 + .../eclipse/cdt/core/parser/ast/IASTNode.java | 7 + .../core/parser/ContextualParser.java | 22 +- .../cdt/internal/core/parser/KeywordSets.java | 55 +++ .../cdt/internal/core/parser/Parser.java | 318 ++++++++++++------ core/org.eclipse.cdt.ui/ChangeLog | 3 + .../text/contentassist/CompletionEngine.java | 27 +- 10 files changed, 524 insertions(+), 166 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/ChangeLog b/core/org.eclipse.cdt.core.tests/ChangeLog index befc7941986..113307aa711 100644 --- a/core/org.eclipse.cdt.core.tests/ChangeLog +++ b/core/org.eclipse.cdt.core.tests/ChangeLog @@ -1,3 +1,6 @@ +2004-01-13 John Camelon + Updated ContextualParseTest to accommodate bugfixes 48909 & 49702. + 2004-01-08 Andrew Niefer Added CompleteParseASTTest.testBug43110_XRef Added ParserSymbolTableTest.testBug43110_Ellipses diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ContextualParseTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ContextualParseTest.java index 5ee5f4effd4..5c0f0647a44 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ContextualParseTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ContextualParseTest.java @@ -8,6 +8,7 @@ package org.eclipse.cdt.core.parser.tests; import java.io.StringReader; import java.io.StringWriter; +import java.io.Writer; import java.util.Iterator; import org.eclipse.cdt.core.parser.IParser; @@ -25,6 +26,7 @@ import org.eclipse.cdt.core.parser.ast.IASTMethod; import org.eclipse.cdt.core.parser.ast.IASTNode; import org.eclipse.cdt.core.parser.ast.IASTParameterDeclaration; import org.eclipse.cdt.core.parser.ast.IASTVariable; +import org.eclipse.cdt.core.parser.ast.IASTNode.LookupKind; import org.eclipse.cdt.core.parser.ast.IASTNode.LookupResult; import org.eclipse.cdt.internal.core.parser.ParserLogService; @@ -126,30 +128,39 @@ public class ContextualParseTest extends CompleteParseBaseTest { writer.write( "} " ); String code = writer.toString(); - int index = code.indexOf( " a " ); - IASTCompletionNode node = parse( code, index + 2 ); - assertNotNull( node ); - - String prefix = node.getCompletionPrefix(); - assertNotNull( prefix ); - assertTrue( node.getCompletionScope() instanceof IASTFunction ); - assertEquals( prefix, "a" ); - assertEquals( node.getCompletionKind(), IASTCompletionNode.CompletionKind.SINGLE_NAME_REFERENCE ); - - IASTNode.LookupKind[] kinds = new IASTNode.LookupKind[1]; - kinds[0] = IASTNode.LookupKind.ALL; - LookupResult result = node.getCompletionScope().lookup( prefix, kinds, node.getCompletionContext() ); - assertEquals( result.getPrefix(), prefix ); - - Iterator iter = result.getNodes(); - - IASTVariable anotherVar = (IASTVariable) iter.next(); - IASTVariable aVar = (IASTVariable) iter.next(); - - assertFalse( iter.hasNext() ); - assertEquals( anotherVar.getName(), "anotherVar" ); - assertEquals( aVar.getName(), "aVar" ); + for( int i = 0; i < 2; ++i ) + { + int index = ( i == 0 ? code.indexOf( " a " ) + 2 : code.indexOf( " a ") + 1 ); + + IASTCompletionNode node = parse( code, index ); + assertNotNull( node ); + + String prefix = node.getCompletionPrefix(); + assertNotNull( prefix ); + assertTrue( node.getCompletionScope() instanceof IASTFunction ); + assertEquals( prefix, i == 0 ? "a" :"" ); + assertEquals( node.getCompletionKind(), IASTCompletionNode.CompletionKind.STATEMENT_START ); + + IASTNode.LookupKind[] kinds = new IASTNode.LookupKind[1]; + kinds[0] = IASTNode.LookupKind.ALL; + LookupResult result = node.getCompletionScope().lookup( prefix, kinds, node.getCompletionContext() ); + assertEquals( result.getPrefix(), prefix ); + + Iterator iter = result.getNodes(); + + IASTVariable anotherVar = (IASTVariable) iter.next(); + if( i != 0 ) + { + IASTFunction foo = (IASTFunction) iter.next(); + assertEquals( foo.getName(), "foo"); + } + IASTVariable aVar = (IASTVariable) iter.next(); + + assertFalse( iter.hasNext() ); + assertEquals( anotherVar.getName(), "anotherVar" ); + assertEquals( aVar.getName(), "aVar" ); + } } public void testCompletionLookup_Qualified() throws Exception @@ -206,6 +217,63 @@ public class ContextualParseTest extends CompleteParseBaseTest { assertEquals( aField.getName(), "aField" ); } + public void testMemberCompletion_Arrow() throws Exception + { + StringWriter writer = new StringWriter(); + writer.write( "class A {" ); + writer.write( " public: void aPublicBaseMethod();" ); + writer.write( " private: void aPrivateBaseMethod();" ); + writer.write( "};" ); + writer.write( "class B : public A {" ); + writer.write( " public: void aMethod();" ); + writer.write( "};" ); + writer.write( "void foo(){" ); + writer.write( " B * b = new B();" ); + writer.write( " b-> \n" ); + + String code = writer.toString(); + int index = code.indexOf( "b->" ); + + IASTCompletionNode node = parse( code, index + 3 ); + assertNotNull(node); + assertEquals( node.getCompletionPrefix(), "" ); + + assertEquals(node.getCompletionKind(), IASTCompletionNode.CompletionKind.MEMBER_REFERENCE); + assertTrue(node.getCompletionScope() instanceof IASTFunction ); + assertEquals( ((IASTFunction)node.getCompletionScope()).getName(), "foo" ); + assertTrue(node.getCompletionContext() instanceof IASTClassSpecifier ); + assertEquals( ((IASTClassSpecifier)node.getCompletionContext()).getName(), "B" ); + } + + public void testMemberCompletion_Dot() throws Exception + { + StringWriter writer = new StringWriter(); + writer.write( "class A {" ); + writer.write( " public: void aPublicBaseMethod();" ); + writer.write( " private: void aPrivateBaseMethod();" ); + writer.write( "};" ); + writer.write( "class B : public A {" ); + writer.write( " public: void aMethod();" ); + writer.write( "};" ); + writer.write( "void foo(){" ); + writer.write( " B b;" ); + writer.write( " b. \n" ); + + String code = writer.toString(); + int index = code.indexOf( "b." ); + + IASTCompletionNode node = parse( code, index + 2 ); + assertNotNull(node); + assertEquals( node.getCompletionPrefix(), "" ); + + assertEquals(node.getCompletionKind(), IASTCompletionNode.CompletionKind.MEMBER_REFERENCE); + assertTrue(node.getCompletionScope() instanceof IASTFunction ); + assertEquals( ((IASTFunction)node.getCompletionScope()).getName(), "foo" ); + assertTrue(node.getCompletionContext() instanceof IASTClassSpecifier ); + assertEquals( ((IASTClassSpecifier)node.getCompletionContext()).getName(), "B" ); + } + + public void testCompletionLookup_Pointer() throws Exception{ StringWriter writer = new StringWriter(); writer.write( "class A {" ); @@ -219,34 +287,40 @@ public class ContextualParseTest extends CompleteParseBaseTest { writer.write( " B * b = new B();" ); writer.write( " b->a \n" ); - String code = writer.toString(); - int index = code.indexOf( "b->a" ); - - IASTCompletionNode node = parse( code, index + 4 ); - - assertNotNull( node ); - - String prefix = node.getCompletionPrefix(); - assertEquals( prefix, "a" ); - - assertTrue( node.getCompletionScope() instanceof IASTFunction ); - assertEquals( node.getCompletionKind(), IASTCompletionNode.CompletionKind.MEMBER_REFERENCE ); - assertNotNull( node.getCompletionContext() ); - assertTrue( node.getCompletionContext() instanceof IASTClassSpecifier ); - - IASTNode.LookupKind[] kinds = new IASTNode.LookupKind[1]; - kinds[0] = IASTNode.LookupKind.METHODS; - LookupResult result = node.getCompletionScope().lookup( prefix, kinds, node.getCompletionContext() ); - assertEquals( result.getPrefix(), prefix ); - - Iterator iter = result.getNodes(); - IASTMethod method = (IASTMethod) iter.next(); - IASTMethod baseMethod = (IASTMethod) iter.next(); - - assertFalse( iter.hasNext() ); - - assertEquals( method.getName(), "aMethod" ); - assertEquals( baseMethod.getName(), "aPublicBaseMethod" ); + for( int i = 0; i < 2; ++i ) + { + String code = writer.toString(); + + int index; + + index = (i == 0 )? (code.indexOf( "b->a" )+4) :(code.indexOf( "b->") + 3); + + IASTCompletionNode node = parse( code, index); + + assertNotNull( node ); + String prefix = node.getCompletionPrefix(); + + assertEquals( prefix, ( i == 0 ) ? "a" :""); + + assertTrue( node.getCompletionScope() instanceof IASTFunction ); + assertEquals( node.getCompletionKind(), IASTCompletionNode.CompletionKind.MEMBER_REFERENCE ); + assertNotNull( node.getCompletionContext() ); + assertTrue( node.getCompletionContext() instanceof IASTClassSpecifier ); + + IASTNode.LookupKind[] kinds = new IASTNode.LookupKind[1]; + kinds[0] = IASTNode.LookupKind.METHODS; + LookupResult result = node.getCompletionScope().lookup( prefix, kinds, node.getCompletionContext() ); + assertEquals( result.getPrefix(), prefix ); + + Iterator iter = result.getNodes(); + IASTMethod method = (IASTMethod) iter.next(); + IASTMethod baseMethod = (IASTMethod) iter.next(); + + assertFalse( iter.hasNext() ); + + assertEquals( method.getName(), "aMethod" ); + assertEquals( baseMethod.getName(), "aPublicBaseMethod" ); + } } public void testCompletionLookup_FriendClass_1() throws Exception{ @@ -334,6 +408,7 @@ public class ContextualParseTest extends CompleteParseBaseTest { assertEquals( method.getName(), "aPrivateMethod" ); } + public void testCompletionLookup_ParametersAsLocalVariables() throws Exception{ StringWriter writer = new StringWriter(); writer.write( "int foo( int aParameter ){" ); @@ -353,7 +428,7 @@ public class ContextualParseTest extends CompleteParseBaseTest { assertEquals( prefix, "a" ); assertTrue( node.getCompletionScope() instanceof IASTCodeScope ); - assertEquals( node.getCompletionKind(), IASTCompletionNode.CompletionKind.SINGLE_NAME_REFERENCE ); + assertEquals( node.getCompletionKind(), IASTCompletionNode.CompletionKind.STATEMENT_START ); assertNull( node.getCompletionContext() ); LookupResult result = node.getCompletionScope().lookup( prefix, new IASTNode.LookupKind [] { IASTNode.LookupKind.LOCAL_VARIABLES }, node.getCompletionContext() ); @@ -421,4 +496,70 @@ public class ContextualParseTest extends CompleteParseBaseTest { assertFalse( iter.hasNext() ); assertEquals( method.getName(), "aMethod" ); } + + public void testCompletionInConstructor() throws Exception + { + Writer writer = new StringWriter(); + writer.write("class SimpleTest{"); + writer.write(" public:"); + writer.write("SimpleTest();"); + writer.write("~SimpleTest();"); + writer.write("int a, b, c, aa, bb, cc, abc;"); + writer.write("};"); + writer.write("SimpleTest::~SimpleTest()"); + writer.write("{}"); + writer.write("SimpleTest::SimpleTest()"); + writer.write("{"); + writer.write("/**/a"); + writer.write("}"); + + IASTCompletionNode node = parse( writer.toString(), writer.toString().indexOf("/**/a") + 5 ); + assertNotNull(node); + assertEquals(node.getCompletionPrefix(), "a"); + assertTrue(node.getCompletionScope() instanceof IASTMethod); + IASTMethod inquestion = (IASTMethod)node.getCompletionScope(); + assertEquals( inquestion.getName(), "SimpleTest"); + assertTrue(inquestion.isConstructor()); + + assertEquals(node.getCompletionKind(), IASTCompletionNode.CompletionKind.STATEMENT_START ); + assertNull(node.getCompletionContext()); + LookupKind[] kinds = new LookupKind[ 1 ]; + kinds[0] = LookupKind.FIELDS; + + LookupResult result = inquestion.lookup( "a", kinds, null ); + assertEquals(result.getResultsSize(), 3 ); + } + + public void testCompletionInDestructor() throws Exception + { + Writer writer = new StringWriter(); + writer.write("class SimpleTest{"); + writer.write(" public:"); + writer.write("SimpleTest();"); + writer.write("~SimpleTest();"); + writer.write("int a, b, c, aa, bb, cc, abc;"); + writer.write("};"); + writer.write("SimpleTest::SimpleTest()"); + writer.write("{}"); + writer.write("SimpleTest::~SimpleTest()"); + writer.write("{"); + writer.write("/**/a"); + writer.write("}"); + + IASTCompletionNode node = parse( writer.toString(), writer.toString().indexOf("/**/a") + 5 ); + assertNotNull(node); + assertEquals(node.getCompletionPrefix(), "a"); + assertTrue(node.getCompletionScope() instanceof IASTMethod); + IASTMethod inquestion = (IASTMethod)node.getCompletionScope(); + assertEquals( inquestion.getName(), "~SimpleTest"); + assertTrue(inquestion.isDestructor()); + + assertEquals(node.getCompletionKind(), IASTCompletionNode.CompletionKind.STATEMENT_START ); + assertNull(node.getCompletionContext()); + LookupKind[] kinds = new LookupKind[ 1 ]; + kinds[0] = LookupKind.FIELDS; + + LookupResult result = inquestion.lookup( "a", kinds, null ); + assertEquals(result.getResultsSize(), 3 ); + } } diff --git a/core/org.eclipse.cdt.core/parser/ChangeLog-parser b/core/org.eclipse.cdt.core/parser/ChangeLog-parser index 680939a1676..0d30a52db75 100644 --- a/core/org.eclipse.cdt.core/parser/ChangeLog-parser +++ b/core/org.eclipse.cdt.core/parser/ChangeLog-parser @@ -1,3 +1,9 @@ +2004-01-12 John Camelon + Fixed bug 48909 - Wrong completion node after a . or an -> + Fixed bug 49702 - Wrong completion kind sent in const/dest and code blocks + Added new CompletionKind - STATEMENT_START to indicate the beginning of a statement line. + + 2004-01-08 Andrew Niefer fixing bug 43110 - Parser support needed for functions with ellipses Added IParameterizedSymbol.setHasVariableArgs() & hasVariableArgs() diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ast/IASTCompletionNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ast/IASTCompletionNode.java index 5c3e6e75656..4bc2c4c9514 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ast/IASTCompletionNode.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ast/IASTCompletionNode.java @@ -24,6 +24,7 @@ public interface IASTCompletionNode { { // x.[ ] x->[ ] public static final CompletionKind MEMBER_REFERENCE = new CompletionKind( 0 ); + // x::[ ] public static final CompletionKind SCOPED_REFERENCE = new CompletionKind( 1 ); @@ -68,6 +69,9 @@ public interface IASTCompletionNode { // any place where a type or variable name is expected to be introduced public static final CompletionKind USER_SPECIFIED_NAME = new CompletionKind( 15 ); + + // the beginning of a statement + public static final CompletionKind STATEMENT_START = new CompletionKind( 16 ); // error condition -- a place in the grammar where there is nothing to lookup public static final CompletionKind NO_SUCH_KIND = new CompletionKind( 200 ); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ast/IASTNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ast/IASTNode.java index e8b082fa0d9..308cf090d8c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ast/IASTNode.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ast/IASTNode.java @@ -60,6 +60,13 @@ public interface IASTNode { public int getResultsSize(); } + /** + * @param prefix + * @param kind + * @param context + * @return + * @throws LookupException + */ public LookupResult lookup( String prefix, LookupKind[] kind, IASTNode context) throws LookupException; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ContextualParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ContextualParser.java index ca7574ace12..cb32036f5a0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ContextualParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ContextualParser.java @@ -42,6 +42,7 @@ public class ContextualParser extends Parser implements IParser { protected IASTNode context; protected IToken finalToken; private Set keywordSet; + private int boundaryOffset; /** * @param scanner @@ -60,6 +61,7 @@ public class ContextualParser extends Parser implements IParser { */ public IASTCompletionNode parse(int offset) throws ParserNotImplementedException { scanner.setOffsetBoundary(offset); + boundaryOffset = offset; translationUnit(); return new ASTCompletionNode( getCompletionKind(), getCompletionScope(), getCompletionContext(), getCompletionPrefix(), reconcileKeywords( getKeywordSet(), getCompletionPrefix() ) ); } @@ -164,15 +166,29 @@ public class ContextualParser extends Parser implements IParser { * @see org.eclipse.cdt.internal.core.parser.Parser#handleOffsetLimitException() */ protected void handleOffsetLimitException(OffsetLimitReachedException exception) throws EndOfFileException, OffsetLimitReachedException { - finalToken = exception.getFinalToken(); + setCompletionToken( exception.getFinalToken() ); + if( (finalToken!= null )&& (finalToken.getEndOffset() != boundaryOffset )) + setCompletionToken(null); throw exception; } /* (non-Javadoc) * @see org.eclipse.cdt.internal.core.parser.Parser#setCompletionKeywords(java.lang.String[]) */ - protected void setCompletionKeywords(Set keywords) { - this.keywordSet = keywords; + protected void setCompletionKeywords(KeywordSets.Key key) { + this.keywordSet = KeywordSets.getKeywords( key, language ); } + + /* (non-Javadoc) + * @see org.eclipse.cdt.internal.core.parser.Parser#setCompletionToken(org.eclipse.cdt.core.parser.IToken) + */ + protected void setCompletionToken(IToken token) { + finalToken = token; + } + + protected IToken getCompletionToken() + { + return finalToken; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/KeywordSets.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/KeywordSets.java index de239a05b9a..a86cc5a10fc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/KeywordSets.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/KeywordSets.java @@ -29,6 +29,8 @@ public class KeywordSets { { public static final Key EMPTY = new Key( 0 ); public static final Key DECL_SPECIFIER_SEQUENCE = new Key( 1 ); + public static final Key DECLARATION = new Key( 2 ); + public static final Key STATEMENT = new Key(3); /** * @param enumValue */ @@ -44,6 +46,10 @@ public class KeywordSets { return EMPTY; if( kind == Key.DECL_SPECIFIER_SEQUENCE ) return (Set) DECL_SPECIFIER_SEQUENCE.get( language ); + if( kind == Key.DECLARATION ) + return (Set) DECLARATION.get( language ); + if( kind == Key.STATEMENT ) + return (Set) STATEMENT.get( language ); //TODO finish this return null; @@ -109,4 +115,53 @@ public class KeywordSets { DECL_SPECIFIER_SEQUENCE.put( ParserLanguage.C, DECL_SPECIFIER_SEQUENCE_C ); } + private static final Set DECLARATION_CPP; + static + { + DECLARATION_CPP = new TreeSet(); + DECLARATION_CPP.addAll( DECL_SPECIFIER_SEQUENCE_CPP ); + DECLARATION_CPP.add( Keywords.ASM ); + // more to come + } + + private static final Set DECLARATION_C; + static + { + DECLARATION_C = new TreeSet(); + DECLARATION_C.addAll(DECL_SPECIFIER_SEQUENCE_C ); + DECLARATION_C.add(Keywords.ASM ); + // more to come + } + + private static final Hashtable DECLARATION; + static + { + DECLARATION = new Hashtable(); + DECLARATION.put( ParserLanguage.CPP, DECLARATION_CPP ); + DECLARATION.put( ParserLanguage.C, DECLARATION_C ); + } + + private static final Set STATEMENT_C; + static + { + STATEMENT_C= new TreeSet(); + STATEMENT_C.addAll( DECLARATION_C ); + STATEMENT_C.add( Keywords.FOR ); + // more to come + } + + private static final Set STATEMENT_CPP; + static + { + STATEMENT_CPP = new TreeSet( STATEMENT_C ); + STATEMENT_CPP.add( Keywords.TRY ); + } + + private static final Hashtable STATEMENT; + static + { + STATEMENT = new Hashtable(); + STATEMENT.put( ParserLanguage.CPP, STATEMENT_CPP); + STATEMENT.put( ParserLanguage.C, STATEMENT_C ); + } } 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 9858e5568af..45e842e31a9 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 @@ -12,7 +12,6 @@ package org.eclipse.cdt.internal.core.parser; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Set; import java.util.Stack; import org.eclipse.cdt.core.parser.BacktrackException; @@ -48,7 +47,6 @@ import org.eclipse.cdt.core.parser.ast.IASTNamespaceDefinition; import org.eclipse.cdt.core.parser.ast.IASTNode; import org.eclipse.cdt.core.parser.ast.IASTOffsetableElement; import org.eclipse.cdt.core.parser.ast.IASTScope; -import org.eclipse.cdt.core.parser.ast.IASTScopedElement; import org.eclipse.cdt.core.parser.ast.IASTSimpleTypeSpecifier; import org.eclipse.cdt.core.parser.ast.IASTTemplate; import org.eclipse.cdt.core.parser.ast.IASTTemplateDeclaration; @@ -62,6 +60,7 @@ import org.eclipse.cdt.core.parser.ast.IASTUsingDirective; import org.eclipse.cdt.core.parser.ast.IASTClassSpecifier.ClassNameType; import org.eclipse.cdt.core.parser.ast.IASTCompletionNode.CompletionKind; import org.eclipse.cdt.core.parser.ast.IASTExpression.Kind; +import org.eclipse.cdt.internal.core.parser.KeywordSets.Key; /** * This is our first implementation of the IParser interface, serving as a parser for @@ -708,10 +707,12 @@ public abstract class Parser implements IParser throws EndOfFileException, BacktrackException { setCurrentScope(scope); + setCompletionKeywords( Key.DECLARATION ); switch (LT(1)) { case IToken.t_asm : IToken first = consume(IToken.t_asm); + setCompletionKind( CompletionKind.NO_SUCH_KIND ); consume(IToken.tLPAREN); String assembly = consume(IToken.tSTRING).getImage(); consume(IToken.tRPAREN); @@ -753,10 +754,9 @@ public abstract class Parser implements IParser default : simpleDeclarationStrategyUnion(scope, ownerTemplate); } - if( scope instanceof IASTScopedElement ) - setCurrentScope( ((IASTScopedElement)scope).getOwnerScope() ); - else - setCurrentScope( null ); + setCurrentScope(scope); + setCompletionKeywords( Key.DECLARATION ); + } protected void simpleDeclarationStrategyUnion( IASTScope scope, @@ -919,8 +919,7 @@ public abstract class Parser implements IParser * - work in functionTryBlock * * @param container IParserCallback object which serves as the owner scope for this declaration. - * @param tryConstructor true == take strategy1 (constructor ) : false == take strategy 2 ( pointer to function) - * @param forKR Is this for K&R-style parameter declaration (true) or simple declaration (false) + * @param tryConstructor true == take strategy1 (constructor ) : false == take strategy 2 ( pointer to function) * @throws BacktrackException request a backtrack */ protected void simpleDeclaration( @@ -933,8 +932,8 @@ public abstract class Parser implements IParser DeclarationWrapper sdw = new DeclarationWrapper(scope, firstToken.getOffset(), ownerTemplate); - setCompletionKeywords( KeywordSets.getKeywords( KeywordSets.Key.DECL_SPECIFIER_SEQUENCE, language ) ); - declSpecifierSeq(false, strategy == SimpleDeclarationStrategy.TRY_CONSTRUCTOR, sdw ); + setCompletionKeywords( Key.DECL_SPECIFIER_SEQUENCE ); + declSpecifierSeq(sdw, false, strategy == SimpleDeclarationStrategy.TRY_CONSTRUCTOR ); if (sdw.getTypeSpecifier() == null && sdw.getSimpleType() != IASTSimpleTypeSpecifier.Type.UNSPECIFIED ) try { @@ -1162,7 +1161,7 @@ public abstract class Parser implements IParser DeclarationWrapper sdw = new DeclarationWrapper(scope, current.getOffset(), null); - declSpecifierSeq(true, false, sdw); + declSpecifierSeq(sdw, true, false); if (sdw.getTypeSpecifier() == null && sdw.getSimpleType() != IASTSimpleTypeSpecifier.Type.UNSPECIFIED) @@ -1357,9 +1356,9 @@ public abstract class Parser implements IParser * @throws BacktrackException request a backtrack */ protected void declSpecifierSeq( + DeclarationWrapper sdw, boolean parm, - boolean tryConstructor, - DeclarationWrapper sdw ) + boolean tryConstructor ) throws BacktrackException, EndOfFileException { Flags flags = new Flags(parm, tryConstructor); @@ -1783,47 +1782,62 @@ public abstract class Parser implements IParser IToken last = null; IToken mark = mark(); - if (LT(1) == IToken.tCOLONCOLON) - last = consume( IToken.tCOLONCOLON ); - // TODO - whacky way to deal with destructors, please revisit - if (LT(1) == IToken.tCOMPL) - consume(); - switch (LT(1)) - { - case IToken.tIDENTIFIER : - last = consume(IToken.tIDENTIFIER); - IToken secondMark = mark(); - try - { - last = consumeTemplateParameters(last); - } catch( BacktrackException bt ) - { - backup( secondMark ); - } - break; - default : - backup(mark); - throw backtrack; + try + { + if (LT(1) == IToken.tCOLONCOLON) + last = consume( IToken.tCOLONCOLON ); + // TODO - whacky way to deal with destructors, please revisit + if (LT(1) == IToken.tCOMPL) + consume(); + switch (LT(1)) + { + case IToken.tIDENTIFIER : + last = consume(IToken.tIDENTIFIER); + IToken secondMark = null; + try + { + secondMark = mark(); + } + catch( OffsetLimitReachedException olre ) + { + return new TokenDuple(last, last); + } + try + { + last = consumeTemplateParameters(last); + } catch( BacktrackException bt ) + { + backup( secondMark ); + } + break; + default : + backup(mark); + throw backtrack; + } + while (LT(1) == IToken.tCOLONCOLON) + { + last = consume(); + if (LT(1) == IToken.t_template) + consume(); + if (LT(1) == IToken.tCOMPL) + consume(); + switch (LT(1)) + { + case IToken.t_operator : + backup(mark); + throw backtrack; + case IToken.tIDENTIFIER : + last = consume(); + last = consumeTemplateParameters(last); + } + } + + return new TokenDuple(first, last); + } catch( OffsetLimitReachedException olre ) + { + backup(mark); + throw backtrack; } - while (LT(1) == IToken.tCOLONCOLON) - { - last = consume(); - if (LT(1) == IToken.t_template) - consume(); - if (LT(1) == IToken.tCOMPL) - consume(); - switch (LT(1)) - { - case IToken.t_operator : - backup(mark); - throw backtrack; - case IToken.tIDENTIFIER : - last = consume(); - last = consumeTemplateParameters(last); - } - } - - return new TokenDuple(first, last); } /** * Parse a const-volatile qualifier. @@ -2689,7 +2703,7 @@ public abstract class Parser implements IParser ITokenDuple duple = null; setCompletionKind( CompletionKind.USER_SPECIFIED_NAME ); - setCompletionKeywords( KeywordSets.getKeywords( KeywordSets.Key.EMPTY, language ) ); + setCompletionKeywords( Key.EMPTY ); // class name if (LT(1) == IToken.tIDENTIFIER) duple = className(); @@ -2896,6 +2910,9 @@ public abstract class Parser implements IParser { setCurrentScope(scope); + setCompletionKind( CompletionKind.STATEMENT_START ); + setCompletionKeywords( Key.STATEMENT ); + switch (LT(1)) { case IToken.t_case : @@ -3007,13 +3024,20 @@ public abstract class Parser implements IParser default : // can be many things: // label - if (LT(1) == IToken.tIDENTIFIER && LT(2) == IToken.tCOLON) - { - consume(IToken.tIDENTIFIER); - consume(IToken.tCOLON); - statement(scope); - return; - } + + try + { + if (LT(1) == IToken.tIDENTIFIER && LT(2) == IToken.tCOLON) + { + consume(IToken.tIDENTIFIER); + consume(IToken.tCOLON); + statement(scope); + return; + } + }catch( OffsetLimitReachedException olre ) + { + // ok + } // expressionStatement // Note: the function style cast ambiguity is handled in expression // Since it only happens when we are in a statement @@ -3021,7 +3045,10 @@ public abstract class Parser implements IParser try { IASTExpression thisExpression = expression(scope); - consume(IToken.tSEMI); + if( queryLookaheadCapability() ) + consume(IToken.tSEMI); + else + throw new EndOfFileException(); thisExpression.acceptElement( requestor ); return; } @@ -3029,14 +3056,15 @@ public abstract class Parser implements IParser { backup( mark ); } + catch( OffsetLimitReachedException olre ) + { + backup(mark); + } + // declarationStatement declaration(scope, null); - } - - if( scope instanceof IASTScopedElement ) - setCurrentScope( ((IASTScopedElement)scope).getOwnerScope() ); - else - setCurrentScope( null ); + } + } protected void catchHandlerSequence(IASTScope scope) throws EndOfFileException, BacktrackException @@ -3136,9 +3164,12 @@ public abstract class Parser implements IParser newScope.enterScope( requestor ); } IToken checkToken = null; - while (LT(1) != IToken.tRBRACE) + setCurrentScope(createNewScope ? newScope : scope); + setCompletionKind( CompletionKind.STATEMENT_START ); + while (queryLookaheadCapability() && LT(1) != IToken.tRBRACE) { checkToken = LA(1); + setCurrentScope(createNewScope ? newScope : scope); try { statement(createNewScope ? newScope : scope ); @@ -3149,9 +3180,14 @@ public abstract class Parser implements IParser if( LA(1) == checkToken ) errorHandling(); } + setCurrentScope(createNewScope ? newScope : scope); + + setCompletionKind( CompletionKind.STATEMENT_START ); + setCompletionKeywords( Key.STATEMENT ); } - consume(IToken.tRBRACE); + if( queryLookaheadCapability() ) consume(IToken.tRBRACE); + else throw new EndOfFileException(); if( createNewScope ) newScope.exitScope( requestor ); } @@ -3170,6 +3206,7 @@ public abstract class Parser implements IParser public IASTExpression expression(IASTScope scope) throws BacktrackException, EndOfFileException { IASTExpression assignmentExpression = assignmentExpression(scope); + if( !queryLookaheadCapability() ) return assignmentExpression; while (LT(1) == IToken.tCOMMA) { consume(); @@ -3211,6 +3248,7 @@ public abstract class Parser implements IParser && conditionalExpression.getExpressionKind() == IASTExpression.Kind.CONDITIONALEXPRESSION) return conditionalExpression; + if( !queryLookaheadCapability() ) return conditionalExpression; switch (LT(1)) { case IToken.tASSIGN : return assignmentOperatorExpression( @@ -3341,6 +3379,7 @@ public abstract class Parser implements IParser throws BacktrackException, EndOfFileException { IASTExpression firstExpression = logicalOrExpression(scope); + if( !queryLookaheadCapability() ) return firstExpression; if (LT(1) == IToken.tQUESTION) { consume(); @@ -3377,6 +3416,7 @@ public abstract class Parser implements IParser throws BacktrackException, EndOfFileException { IASTExpression firstExpression = logicalAndExpression(scope); + if( !queryLookaheadCapability() ) return firstExpression; while (LT(1) == IToken.tOR) { consume(); @@ -3412,6 +3452,7 @@ public abstract class Parser implements IParser throws BacktrackException, EndOfFileException { IASTExpression firstExpression = inclusiveOrExpression( scope ); + if( !queryLookaheadCapability() ) return firstExpression; while (LT(1) == IToken.tAND) { consume(); @@ -3446,6 +3487,7 @@ public abstract class Parser implements IParser throws BacktrackException, EndOfFileException { IASTExpression firstExpression = exclusiveOrExpression(scope); + if( !queryLookaheadCapability() ) return firstExpression; while (LT(1) == IToken.tBITOR) { consume(); @@ -3481,6 +3523,7 @@ public abstract class Parser implements IParser throws BacktrackException, EndOfFileException { IASTExpression firstExpression = andExpression( scope ); + if( !queryLookaheadCapability() ) return firstExpression; while (LT(1) == IToken.tXOR) { consume(); @@ -3516,6 +3559,7 @@ public abstract class Parser implements IParser protected IASTExpression andExpression(IASTScope scope) throws EndOfFileException, BacktrackException { IASTExpression firstExpression = equalityExpression(scope); + if( !queryLookaheadCapability() ) return firstExpression; while (LT(1) == IToken.tAMPER) { consume(); @@ -3553,6 +3597,7 @@ public abstract class Parser implements IParser IASTExpression firstExpression = relationalExpression(scope); for (;;) { + if( !queryLookaheadCapability() ) return firstExpression; switch (LT(1)) { case IToken.tEQUAL : @@ -3598,6 +3643,7 @@ public abstract class Parser implements IParser IASTExpression firstExpression = shiftExpression(scope); for (;;) { + if( !queryLookaheadCapability() ) return firstExpression; switch (LT(1)) { case IToken.tGT : @@ -3677,6 +3723,7 @@ public abstract class Parser implements IParser IASTExpression firstExpression = additiveExpression(scope); for (;;) { + if( !queryLookaheadCapability() ) return firstExpression; switch (LT(1)) { case IToken.tSHIFTL : @@ -3721,6 +3768,7 @@ public abstract class Parser implements IParser IASTExpression firstExpression = multiplicativeExpression( scope ); for (;;) { + if( !queryLookaheadCapability() ) return firstExpression; switch (LT(1)) { case IToken.tPLUS : @@ -3765,6 +3813,7 @@ public abstract class Parser implements IParser IASTExpression firstExpression = pmExpression(scope); for (;;) { + if( !queryLookaheadCapability() ) return firstExpression; switch (LT(1)) { case IToken.tSTAR : @@ -3819,6 +3868,7 @@ public abstract class Parser implements IParser IASTExpression firstExpression = castExpression(scope); for (;;) { + if( ! queryLookaheadCapability() ) return firstExpression; switch (LT(1)) { case IToken.tDOTSTAR : @@ -3861,6 +3911,7 @@ public abstract class Parser implements IParser protected IASTExpression castExpression( IASTScope scope ) throws EndOfFileException, BacktrackException { // TO DO: we need proper symbol checkint to ensure type name + if( ! queryLookaheadCapability() ) return unaryExpression(scope); if (LT(1) == IToken.tLPAREN) { IToken mark = mark(); @@ -4091,7 +4142,7 @@ public abstract class Parser implements IParser */ protected IASTExpression deleteExpression( IASTScope scope ) throws EndOfFileException, BacktrackException - { + { if (LT(1) == IToken.tCOLONCOLON) { // global scope @@ -4341,6 +4392,7 @@ public abstract class Parser implements IParser protected IASTExpression unaryExpression( IASTScope scope ) throws EndOfFileException, BacktrackException { + if( ! queryLookaheadCapability() ) return postfixExpression( scope ); switch (LT(1)) { case IToken.tSTAR : @@ -4465,6 +4517,8 @@ public abstract class Parser implements IParser { IASTExpression firstExpression = null; boolean isTemplate = false; + + if( ! queryLookaheadCapability() ) return primaryExpression(scope); switch (LT(1)) { case IToken.t_typename : @@ -4625,6 +4679,7 @@ public abstract class Parser implements IParser IASTExpression secondExpression = null; for (;;) { + if( ! queryLookaheadCapability() )return firstExpression; switch (LT(1)) { case IToken.tLBRACKET : @@ -4729,12 +4784,18 @@ public abstract class Parser implements IParser // member access consume(IToken.tDOT); - if (LT(1) == IToken.t_template) - { - consume(IToken.t_template); - isTemplate = true; - } - + try + { + if (LT(1) == IToken.t_template) + { + consume(IToken.t_template); + isTemplate = true; + } + } catch( OffsetLimitReachedException olre ) + { + setCompletionToken( null ); + } + IASTNode context = astFactory.getCompletionContext( (isTemplate ? IASTExpression.Kind.POSTFIX_DOT_TEMPL_IDEXPRESS : IASTExpression.Kind.POSTFIX_DOT_IDEXPRESSION), @@ -4760,22 +4821,29 @@ public abstract class Parser implements IParser catch (ASTSemanticException e5) { failParse(); + setCompletionContext( null ); throw backtrack; } catch (Exception e) - { - throw backtrack; - } finally { setCompletionContext( null ); - } + throw backtrack; + } + break; case IToken.tARROW : // member access consume(IToken.tARROW); - if (LT(1) == IToken.t_template) - { - consume(IToken.t_template); - isTemplate = true; + + try + { + if (LT(1) == IToken.t_template) + { + consume(IToken.t_template); + isTemplate = true; + } + } catch( OffsetLimitReachedException olre ) + { + setCompletionToken( null ); } context = astFactory.getCompletionContext( (isTemplate @@ -4803,13 +4871,12 @@ public abstract class Parser implements IParser catch (ASTSemanticException e) { failParse(); + setCompletionContext( null ); throw backtrack; } catch (Exception e) - { - throw backtrack; - }finally { setCompletionContext( null ); + throw backtrack; } break; default : @@ -4820,7 +4887,24 @@ public abstract class Parser implements IParser - protected IASTExpression specialCastExpression( IASTScope scope, + /** + * @return + * @throws EndOfFileException + */ + protected boolean queryLookaheadCapability() throws EndOfFileException { + //make sure we can look ahead one before doing this + boolean result = true; + try + { + LA(1); + } + catch( OffsetLimitReachedException olre ) + { + result = false; + } + return result; + } + protected IASTExpression specialCastExpression( IASTScope scope, IASTExpression.Kind kind) throws EndOfFileException, BacktrackException { @@ -4886,6 +4970,21 @@ public abstract class Parser implements IParser throws EndOfFileException, BacktrackException { IToken t = null; + IASTExpression emptyExpression = null; + try { + emptyExpression = astFactory.createExpression( + scope, + IASTExpression.Kind.PRIMARY_EMPTY, + null, + null, + null, + null, + null, "", null); + } catch (ASTSemanticException e9) { + // TODO Auto-generated catch block + e9.printStackTrace(); + } + if( !queryLookaheadCapability() ) return emptyExpression; switch (LT(1)) { // TO DO: we need more literals... @@ -5036,7 +5135,7 @@ public abstract class Parser implements IParser case IToken.t_operator : ITokenDuple duple = null; - + IToken mark = mark(); try { duple = name(); @@ -5045,7 +5144,6 @@ public abstract class Parser implements IParser { Declarator d = new Declarator( new DeclarationWrapper(scope, 0, null) ); - IToken mark = mark(); if (LT(1) == IToken.tCOLONCOLON || LT(1) == IToken.tIDENTIFIER) { IToken start = consume(); @@ -5071,6 +5169,11 @@ public abstract class Parser implements IParser duple = d.getNameDuple(); } + catch(OffsetLimitReachedException olre ) + { + backup(mark); + throw backtrack; + } try @@ -5092,24 +5195,7 @@ public abstract class Parser implements IParser throw backtrack; } default : - try - { - return astFactory.createExpression( - scope, - IASTExpression.Kind.PRIMARY_EMPTY, - null, - null, - null, - null, - null, "", null); - } - catch (ASTSemanticException e) - { - throw backtrack; - } catch (Exception e) - { - throw backtrack; - } + return emptyExpression; } } /** @@ -5165,6 +5251,7 @@ public abstract class Parser implements IParser protected IScanner scanner; protected IToken currToken, // current token we plan to consume next lastToken; // last token we consumed + private boolean limitReached = false; protected void setCurrentScope( IASTScope scope ) { @@ -5178,12 +5265,15 @@ public abstract class Parser implements IParser */ protected IToken fetchToken() throws EndOfFileException { + if(limitReached) throw new OffsetLimitReachedException(getCompletionToken()); + try { return scanner.nextToken(); } catch( OffsetLimitReachedException olre ) { + limitReached = true; handleOffsetLimitException(olre); return null; } @@ -5315,8 +5405,16 @@ public abstract class Parser implements IParser { } - protected void setCompletionKeywords( Set keywords ) + protected void setCompletionKeywords(KeywordSets.Key key ) { } + + protected void setCompletionToken( IToken token ) + { + } + protected IToken getCompletionToken() + { + return null; + } } diff --git a/core/org.eclipse.cdt.ui/ChangeLog b/core/org.eclipse.cdt.ui/ChangeLog index c1724963ff8..18f2750fa55 100644 --- a/core/org.eclipse.cdt.ui/ChangeLog +++ b/core/org.eclipse.cdt.ui/ChangeLog @@ -1,3 +1,6 @@ +2004-01-13 John Camelon + Updated CompletionEngine to handle IASTCompletionKind.CompletionKind.STATEMENT_START + 2004-01-08 Hoda Amer Added Content assist log cpabilities diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CompletionEngine.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CompletionEngine.java index 22895896729..329af0dadeb 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CompletionEngine.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/CompletionEngine.java @@ -17,7 +17,6 @@ import java.util.Iterator; import java.util.List; import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.ICLogConstants; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.parser.IParser; @@ -411,6 +410,24 @@ public class CompletionEngine implements RelevanceConstants{ addToCompletions (result); } + + private void completionOnStatementStart( IASTCompletionNode completionNode ) + { + IASTScope searchNode = completionNode.getCompletionScope(); + + LookupResult result = null; + // lookup fields and methods with the right visibility + IASTNode.LookupKind[] kinds = new IASTNode.LookupKind[7]; + kinds[0] = IASTNode.LookupKind.FIELDS; + kinds[1] = IASTNode.LookupKind.METHODS; + kinds[2] = IASTNode.LookupKind.VARIABLES; + kinds[3] = IASTNode.LookupKind.STRUCTURES; + kinds[4] = IASTNode.LookupKind.ENUMERATIONS; + kinds[5] = IASTNode.LookupKind.NAMESPACES; + kinds[6] = IASTNode.LookupKind.FUNCTIONS; + result = lookup (searchNode, completionNode.getCompletionPrefix(), kinds, completionNode.getCompletionContext()); + addToCompletions (result); + } private void completionOnScopedReference(IASTCompletionNode completionNode){ // 1. Get the search scope node // the search node is the name before the qualification @@ -630,6 +647,10 @@ public class CompletionEngine implements RelevanceConstants{ // CompletionOnKeyword completionOnKeyword(completionNode); } + else if(kind == IASTCompletionNode.CompletionKind.STATEMENT_START ) + { + completionOnStatementStart(completionNode); + } addKeywordsToCompletions( completionNode.getKeywords()); return completionNode; @@ -704,6 +725,10 @@ public class CompletionEngine implements RelevanceConstants{ case 15: kindStr = "USER_SPECIFIED_NAME"; break; + + case 16: + kindStr = "STATEMENT_START"; + break; case 200: kindStr = "NO_SUCH_KIND";