From 0dc064bbd6b09cd0f11091d44c3e5ab4f6b3218c Mon Sep 17 00:00:00 2001 From: John Camelon Date: Sun, 1 Feb 2004 18:38:06 +0000 Subject: [PATCH] org.eclipse.cdt.core Added CompletionKind.UNREACHABLE_CODE to IASTCompletionNode. Updated Scanner to handle unreachable code scenarios in content assist. Added Directives class to centralize preprocessor directive strings. Added keyword completion for preprocessor lines that start with #. --- .../parser/ChangeLog-parser | 6 ++ .../eclipse/cdt/core/parser/Directives.java | 32 ++++++ .../core/parser/ast/IASTCompletionNode.java | 3 + .../internal/core/parser/scanner/Scanner.java | 102 +++++++++++++----- .../core/parser/token/KeywordSets.java | 23 ++++ 5 files changed, 137 insertions(+), 29 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Directives.java diff --git a/core/org.eclipse.cdt.core/parser/ChangeLog-parser b/core/org.eclipse.cdt.core/parser/ChangeLog-parser index 5cae5056b2c..70b179997b2 100644 --- a/core/org.eclipse.cdt.core/parser/ChangeLog-parser +++ b/core/org.eclipse.cdt.core/parser/ChangeLog-parser @@ -1,3 +1,9 @@ +2004-02-01 John Camelon + Added CompletionKind.UNREACHABLE_CODE to IASTCompletionNode. + Updated Scanner to handle unreachable code scenarios in content assist. + Added Directives class to centralize preprocessor directive strings. + Added keyword completion for preprocessor lines that start with #. + 2004-01-30 John Camelon Partial fix for Bug 47752 - Outline does not recognize functions with full body try/catch blocks diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Directives.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Directives.java new file mode 100644 index 00000000000..86648561c77 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Directives.java @@ -0,0 +1,32 @@ +/********************************************************************** + * Copyright (c) 2002,2003 Rational Software Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Rational Software - Initial API and implementation +***********************************************************************/ +package org.eclipse.cdt.core.parser; + +/** + * @author jcamelon + */ +public class Directives { + + public static final String POUND_DEFINE = "#define"; + public static final String POUND_UNDEF = "#undef"; + public static final String POUND_IF = "#if"; + public static final String POUND_IFDEF = "#ifdef"; + public static final String POUND_IFNDEF = "#ifndef"; + public static final String POUND_ELSE = "#else"; + public static final String POUND_ENDIF = "#endif"; + public static final String POUND_INCLUDE = "#include"; + public static final String POUND_LINE = "#line"; + public static final String POUND_ERROR = "#error"; + public static final String POUND_PRAGMA = "#pragma"; + public static final String POUND_ELIF = "#elif"; + public static final String POUND_BLANK = "#"; + +} 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 ec43862503f..9134db9b7fe 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 @@ -70,6 +70,9 @@ public interface IASTCompletionNode { // after a new expression public static final CompletionKind NEW_TYPE_REFERENCE = new CompletionKind( 16 ); + // inside something that does not reach the parser - (#ifdefed out/comment) + public static final CompletionKind UNREACHABLE_CODE = new CompletionKind( 17 ); + // 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/internal/core/parser/scanner/Scanner.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Scanner.java index cbe53a12e25..e6d4bdb27b0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Scanner.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Scanner.java @@ -28,6 +28,7 @@ import java.util.StringTokenizer; import java.util.Vector; import org.eclipse.cdt.core.parser.BacktrackException; +import org.eclipse.cdt.core.parser.Directives; import org.eclipse.cdt.core.parser.EndOfFileException; import org.eclipse.cdt.core.parser.IMacroDescriptor; import org.eclipse.cdt.core.parser.IParser; @@ -350,7 +351,7 @@ public class Scanner implements IScanner { } - protected String getRestOfPreprocessorLine() throws ScannerException { + protected String getRestOfPreprocessorLine() throws ScannerException, EndOfFileException { StringBuffer buffer = new StringBuffer(); skipOverWhitespace(); int c = getChar(); @@ -887,8 +888,7 @@ public class Scanner implements IScanner { while (c != NOCHAR) { if ( ! passOnToClient ) { - - + while (c != NOCHAR && c != '#' ) { c = getChar(); @@ -910,7 +910,12 @@ public class Scanner implements IScanner { } } - if( c == NOCHAR ) continue; + if( c == NOCHAR ) + { + if( isLimitReached() ) + handleInvalidCompletion(); + continue; + } } if ((c == ' ') || (c == '\r') || (c == '\t') || (c == '\n')) { @@ -1251,6 +1256,7 @@ public class Scanner implements IScanner { contextStack.getCurrentContext()); } else if (c == '#') { + int beginningOffset = contextStack.getCurrentContext().getOffset() - 1; int beginningLine = contextStack.getCurrentLineNumber(); // lets prepare for a preprocessor statement @@ -1278,10 +1284,14 @@ public class Scanner implements IScanner { buff.append((char) c); c = getChar(); } + ungetChar(c); String token = buff.toString(); + if( isLimitReached() ) + handleCompletionOnPreprocessorDirective(token); + Object directive = ppDirectives.get(token); if (directive == null) { if (true) @@ -1296,6 +1306,8 @@ public class Scanner implements IScanner { case PreprocessorDirectives.DEFINE : if ( ! passOnToClient ) { skipOverTextUntilNewline(); + if( isLimitReached() ) + handleInvalidCompletion(); c = getChar(); continue; } @@ -1308,6 +1320,8 @@ public class Scanner implements IScanner { case PreprocessorDirectives.INCLUDE : if (! passOnToClient ) { skipOverTextUntilNewline(); + if( isLimitReached() ) + handleInvalidCompletion(); c = getChar(); continue; } @@ -1318,7 +1332,10 @@ public class Scanner implements IScanner { continue; case PreprocessorDirectives.UNDEFINE : if (! passOnToClient) { + skipOverTextUntilNewline(); + if( isLimitReached() ) + handleInvalidCompletion(); c = getChar(); continue; } @@ -1369,6 +1386,9 @@ public class Scanner implements IScanner { continue; case PreprocessorDirectives.ENDIF : String restOfLine = getRestOfPreprocessorLine().trim(); + if( isLimitReached() ) + handleInvalidCompletion(); + if( ! restOfLine.equals( "" ) ) { StringBuffer buffer = new StringBuffer("#endif "); @@ -1390,7 +1410,10 @@ public class Scanner implements IScanner { if (getDefinition(definition2) != null) { // not defined skipOverTextUntilNewline(); - passOnToClient = branches.poundIf( false ); + passOnToClient = branches.poundIf( false ); + if( isLimitReached() ) + handleInvalidCompletion(); + } else { passOnToClient = branches.poundIf( true ); // continue along, act like nothing is wrong :-) @@ -1399,7 +1422,6 @@ public class Scanner implements IScanner { continue; case PreprocessorDirectives.ELSE : - //TODO add in content assist stuff here try { passOnToClient = branches.poundElse(); @@ -1413,6 +1435,9 @@ public class Scanner implements IScanner { } skipOverTextUntilNewline(); + if( isLimitReached() ) + handleInvalidCompletion(); + c = getChar(); continue; @@ -1450,11 +1475,16 @@ public class Scanner implements IScanner { case PreprocessorDirectives.LINE : skipOverTextUntilNewline(); + if( isLimitReached() ) + handleInvalidCompletion(); c = getChar(); continue; case PreprocessorDirectives.ERROR : if (! passOnToClient) { skipOverTextUntilNewline(); + if( isLimitReached() ) + handleInvalidCompletion(); + c = getChar(); continue; } @@ -1463,6 +1493,9 @@ public class Scanner implements IScanner { continue; case PreprocessorDirectives.PRAGMA : skipOverTextUntilNewline(); + if( isLimitReached() ) + handleInvalidCompletion(); + c = getChar(); continue; case PreprocessorDirectives.BLANK : @@ -1825,7 +1858,7 @@ public class Scanner implements IScanner { /** * @param definition */ - private void handleCompletionOnDefinition(String definition) throws EndOfFileException { + protected void handleCompletionOnDefinition(String definition) throws EndOfFileException { IASTCompletionNode node = new ASTCompletionNode( IASTCompletionNode.CompletionKind.MACRO_REFERENCE, null, null, definition, KeywordSets.getKeywords(KeywordSets.Key.EMPTY, language) ); @@ -1835,7 +1868,7 @@ public class Scanner implements IScanner { /** * @param expression2 */ - private void handleCompletionOnExpression(String expression) throws EndOfFileException { + protected void handleCompletionOnExpression(String expression) throws EndOfFileException { int completionPoint = expression.length() + 2; IASTCompletionNode.CompletionKind kind = IASTCompletionNode.CompletionKind.MACRO_REFERENCE; @@ -1882,6 +1915,15 @@ public class Scanner implements IScanner { throwEOF( node ); } + protected void handleInvalidCompletion() throws EndOfFileException + { + throwEOF( new ASTCompletionNode( IASTCompletionNode.CompletionKind.UNREACHABLE_CODE, null, null, "", KeywordSets.getKeywords(KeywordSets.Key.EMPTY, language) )); + } + + protected void handleCompletionOnPreprocessorDirective( String prefix ) throws EndOfFileException + { + throwEOF( new ASTCompletionNode( IASTCompletionNode.CompletionKind.NO_SUCH_KIND, null, null, prefix, KeywordSets.getKeywords(KeywordSets.Key.PP_DIRECTIVE, language ))); + } /** * @param key */ @@ -1892,7 +1934,7 @@ public class Scanner implements IScanner { /** * */ - protected void handlePragmaOperator() throws ScannerException + protected void handlePragmaOperator() throws ScannerException, EndOfFileException { // until we know what to do with pragmas, do the equivalent as // to what we do for #pragma blah blah blah (ignore it) @@ -2140,21 +2182,19 @@ public class Scanner implements IScanner { cppKeywords.put( Keywords.XOR, new Integer(IToken.t_xor)); cppKeywords.put( Keywords.XOR_EQ, new Integer(IToken.t_xor_eq)); - ppDirectives.put("#define", new Integer(PreprocessorDirectives.DEFINE)); - ppDirectives.put("#undef",new Integer(PreprocessorDirectives.UNDEFINE)); - ppDirectives.put("#if", new Integer(PreprocessorDirectives.IF)); - ppDirectives.put("#ifdef", new Integer(PreprocessorDirectives.IFDEF)); - ppDirectives.put("#ifndef", new Integer(PreprocessorDirectives.IFNDEF)); - ppDirectives.put("#else", new Integer(PreprocessorDirectives.ELSE)); - ppDirectives.put("#endif", new Integer(PreprocessorDirectives.ENDIF)); - ppDirectives.put( - "#include", - new Integer(PreprocessorDirectives.INCLUDE)); - ppDirectives.put("#line", new Integer(PreprocessorDirectives.LINE)); - ppDirectives.put("#error", new Integer(PreprocessorDirectives.ERROR)); - ppDirectives.put("#pragma", new Integer(PreprocessorDirectives.PRAGMA)); - ppDirectives.put("#elif", new Integer(PreprocessorDirectives.ELIF)); - ppDirectives.put("#", new Integer(PreprocessorDirectives.BLANK)); + ppDirectives.put(Directives.POUND_DEFINE, new Integer(PreprocessorDirectives.DEFINE)); + ppDirectives.put(Directives.POUND_UNDEF,new Integer(PreprocessorDirectives.UNDEFINE)); + ppDirectives.put(Directives.POUND_IF, new Integer(PreprocessorDirectives.IF)); + ppDirectives.put(Directives.POUND_IFDEF, new Integer(PreprocessorDirectives.IFDEF)); + ppDirectives.put(Directives.POUND_IFNDEF, new Integer(PreprocessorDirectives.IFNDEF)); + ppDirectives.put(Directives.POUND_ELSE, new Integer(PreprocessorDirectives.ELSE)); + ppDirectives.put(Directives.POUND_ENDIF, new Integer(PreprocessorDirectives.ENDIF)); + ppDirectives.put(Directives.POUND_INCLUDE, new Integer(PreprocessorDirectives.INCLUDE)); + ppDirectives.put(Directives.POUND_LINE, new Integer(PreprocessorDirectives.LINE)); + ppDirectives.put(Directives.POUND_ERROR, new Integer(PreprocessorDirectives.ERROR)); + ppDirectives.put(Directives.POUND_PRAGMA, new Integer(PreprocessorDirectives.PRAGMA)); + ppDirectives.put(Directives.POUND_ELIF, new Integer(PreprocessorDirectives.ELIF)); + ppDirectives.put(Directives.POUND_BLANK, new Integer(PreprocessorDirectives.BLANK)); cKeywords.put( Keywords.AUTO, new Integer(IToken.t_auto)); cKeywords.put( Keywords.BREAK, new Integer(IToken.t_break)); @@ -2268,7 +2308,7 @@ public class Scanner implements IScanner { } - protected void skipOverSinglelineComment() throws ScannerException { + protected void skipOverSinglelineComment() throws ScannerException, EndOfFileException { StringBuffer comment = new StringBuffer("//"); int c; @@ -2285,10 +2325,12 @@ public class Scanner implements IScanner { break; } } + if( c== NOCHAR && isLimitReached() ) + handleInvalidCompletion(); } - protected boolean skipOverMultilineComment() throws ScannerException { + protected boolean skipOverMultilineComment() throws ScannerException, EndOfFileException { int state = 0; boolean encounteredNewline = false; StringBuffer comment = new StringBuffer("/*"); @@ -2319,15 +2361,17 @@ public class Scanner implements IScanner { comment.append((char)c); } - if (c == NOCHAR) + if (c == NOCHAR && !isLimitReached() ) handleProblem( IProblem.SCANNER_UNEXPECTED_EOF, null, getCurrentOffset(), false, true ); + else if( c== NOCHAR ) // limit reached + handleInvalidCompletion(); ungetChar(c); return encounteredNewline; } - protected void poundInclude( int beginningOffset, int startLine ) throws ScannerException { + protected void poundInclude( int beginningOffset, int startLine ) throws ScannerException, EndOfFileException { StringBuffer potentialErrorLine = new StringBuffer( "#include "); skipOverWhitespace(); int baseOffset = lastContext.getOffset() - lastContext.undoStackSize(); @@ -2539,7 +2583,7 @@ public class Scanner implements IScanner { } - protected void poundDefine(int beginning, int beginningLine ) throws ScannerException { + protected void poundDefine(int beginning, int beginningLine ) throws ScannerException, EndOfFileException { StringBuffer potentialErrorMessage = new StringBuffer( POUND_DEFINE ); skipOverWhitespace(); // definition diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/KeywordSets.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/KeywordSets.java index fc32cb1e67e..edd7979c8b0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/KeywordSets.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/KeywordSets.java @@ -15,6 +15,7 @@ import java.util.Hashtable; import java.util.Set; import java.util.TreeSet; +import org.eclipse.cdt.core.parser.Directives; import org.eclipse.cdt.core.parser.Enum; import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.core.parser.ParserLanguage; @@ -36,6 +37,7 @@ public class KeywordSets { public static final Key FUNCTION_MODIFIER = new Key( 6 ); public static final Key NAMESPACE_ONLY = new Key(6); public static final Key MACRO = new Key( 7 ); + public static final Key PP_DIRECTIVE = new Key( 8 ); /** * @param enumValue */ @@ -65,6 +67,8 @@ public class KeywordSets { return NAMESPACE_ONLY; if( kind == Key.MACRO ) return MACRO_ONLY; + if( kind == Key.PP_DIRECTIVE ) + return PP_DIRECTIVES; //TODO finish this return null; @@ -236,4 +240,23 @@ public class KeywordSets { FUNCTION_MODIFIER.put( ParserLanguage.CPP, FUNCTION_MODIFIER_CPP ); FUNCTION_MODIFIER.put( ParserLanguage.C, FUNCTION_MODIFIER_C ); } + + private static final Set PP_DIRECTIVES; + static + { + PP_DIRECTIVES = new TreeSet(); + PP_DIRECTIVES.add(Directives.POUND_BLANK); + PP_DIRECTIVES.add(Directives.POUND_DEFINE); + PP_DIRECTIVES.add(Directives.POUND_UNDEF); + PP_DIRECTIVES.add(Directives.POUND_IF); + PP_DIRECTIVES.add(Directives.POUND_IFDEF); + PP_DIRECTIVES.add(Directives.POUND_IFNDEF); + PP_DIRECTIVES.add(Directives.POUND_ELSE); + PP_DIRECTIVES.add(Directives.POUND_ENDIF); + PP_DIRECTIVES.add(Directives.POUND_INCLUDE); + PP_DIRECTIVES.add(Directives.POUND_LINE); + PP_DIRECTIVES.add(Directives.POUND_ERROR); + PP_DIRECTIVES.add(Directives.POUND_PRAGMA); + PP_DIRECTIVES.add(Directives.POUND_ELIF); + } }