diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner2/Scanner2Test.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner2/Scanner2Test.java index 08816f5c2cc..b78febf72ca 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner2/Scanner2Test.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner2/Scanner2Test.java @@ -1822,4 +1822,20 @@ public class Scanner2Test extends BaseScanner2Test assertTrue( callback.problems.isEmpty() ); } + + public void testBug70073() throws Exception + { + StringBuffer buffer = new StringBuffer( "#if CONST \n #endif \n #elif CONST \n int" ); //$NON-NLS-1$ + final List problems = new ArrayList(); + ISourceElementRequestor requestor = new NullSourceElementRequestor() { + public boolean acceptProblem(IProblem problem) + { + problems.add( problem ); + return super.acceptProblem( problem ); + } + }; + initializeScanner( buffer.toString(), ParserMode.COMPLETE_PARSE, requestor ); + validateToken( IToken.t_int ); + assertEquals( problems.size(), 1 ); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/CharTable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/CharTable.java index 16cc93b63e9..8fb919ddaee 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/CharTable.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/CharTable.java @@ -120,7 +120,13 @@ public class CharTable extends HashTable { final public boolean containsKey( char[] key ){ return lookup( key ) != -1; } - + final public char[] findKey( char[] buffer, int start, int len ){ + int idx = lookup( buffer, start, len ); + if( idx == -1 ) + return null; + + return keyTable[ idx ]; + } protected int lookup(char[] buffer ){ return lookup(buffer, 0, buffer.length); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/Scanner2.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/Scanner2.java index 90b08222a0f..dbf3310e049 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/Scanner2.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner2/Scanner2.java @@ -101,6 +101,16 @@ public class Scanner2 implements IScanner, IScannerData { private int[] bufferLimit = new int[bufferInitialSize]; private int[] bufferLineNums = new int[bufferInitialSize]; + //branch tracking + private int branchStackPos = -1; + private int[] branches = new int[bufferInitialSize]; + //states + final static private int BRANCH_IF = 1; + final static private int BRANCH_ELIF = 2; + final static private int BRANCH_ELSE = 3; + final static private int BRANCH_END = 4; + + // Utility private static String[] emptyStringArray = new String[0]; private static char[] emptyCharArray = new char[0]; @@ -1113,6 +1123,42 @@ public class Scanner2 implements IScanner, IScannerData { return newToken( tokenType, result ); } + private boolean branchState( int state ){ + if( state != BRANCH_IF && branchStackPos == -1 ) + return false; + + switch( state ){ + case BRANCH_IF: + if( ++branchStackPos == branches.length ){ + int [] temp = new int [ branches.length << 1 ]; + System.arraycopy( branches, 0, temp, 0, branches.length ); + } + branches[branchStackPos] = BRANCH_IF; + return true; + case BRANCH_ELIF: + case BRANCH_ELSE: + switch( branches[branchStackPos] ){ + case BRANCH_IF: + case BRANCH_ELIF: + branches[branchStackPos] = state; + return true; + default: + return false; + } + case BRANCH_END: + switch( branches[branchStackPos] ){ + case BRANCH_IF: + case BRANCH_ELSE: + case BRANCH_ELIF: + --branchStackPos; + return true; + default: + return false; + } + } + return false; + } + private void handlePPDirective(int pos) throws ScannerException, EndOfFileException { char[] buffer = bufferStack[bufferStackPos]; int limit = bufferLimit[bufferStackPos]; @@ -1169,6 +1215,7 @@ public class Scanner2 implements IScanner, IScannerData { len = bufferPos[bufferStackPos] - start; if( isLimitReached() ) handleCompletionOnExpression( CharArrayUtils.extract( buffer, start, len ) ); + branchState( BRANCH_IF ); if (expressionEvaluator.evaluate(buffer, start, len, definitions) == 0) { if (dlog != null) dlog.println("#if " + new String(buffer,start+1,len-1)); //$NON-NLS-1$ skipOverConditionalCode(true); @@ -1180,14 +1227,23 @@ public class Scanner2 implements IScanner, IScannerData { case ppElse: case ppElif: // Condition must have been true, skip over the rest - skipToNewLine(); - skipOverConditionalCode(false); + + if( branchState( type == ppElse ? BRANCH_ELSE : BRANCH_ELIF) ){ + skipToNewLine(); + skipOverConditionalCode(false); + } else { + handleProblem( IProblem.PREPROCESSOR_UNBALANCE_CONDITION, start, ppKeywords.findKey( buffer, start, len ) ); + skipToNewLine(); + } + if( isLimitReached() ) handleInvalidCompletion(); return; case ppError: throw new ScannerException(null); case ppEndif: + if( !branchState( BRANCH_END ) ) + handleProblem( IProblem.PREPROCESSOR_UNBALANCE_CONDITION, start, ppKeywords.findKey( buffer, start, len ) ); break; default: problem = true; @@ -1649,6 +1705,8 @@ public class Scanner2 implements IScanner, IScannerData { skipToNewLine(); + branchState( BRANCH_IF ); + if ((definitions.get(buffer, idstart, idlen) != null) == positive) { if (dlog != null) dlog.println((positive ? "#ifdef" : "#ifndef") //$NON-NLS-1$ //$NON-NLS-2$ + " " + new String(buffer, idstart, idlen)); //$NON-NLS-1$ @@ -1705,31 +1763,50 @@ public class Scanner2 implements IScanner, IScannerData { case ppIfndef: case ppIf: ++nesting; + branchState( BRANCH_IF ); break; case ppElse: - if (checkelse && nesting == 0) { - skipToNewLine(); - return; - } + if( branchState( BRANCH_ELSE ) ){ + if (checkelse && nesting == 0) { + skipToNewLine(); + return; + } + } else { + //problem, ignore this one. + handleProblem( IProblem.PREPROCESSOR_UNBALANCE_CONDITION, start, ppKeywords.findKey( buffer, start, len ) ); + skipToNewLine(); + } break; case ppElif: - if (checkelse && nesting == 0) { - // check the condition - start = bufferPos[bufferStackPos]; - skipToNewLine(); - len = bufferPos[bufferStackPos] - start; - if (expressionEvaluator.evaluate(buffer, start, len, definitions) != 0) - // condition passed, we're good - return; - } + if( branchState( BRANCH_ELIF ) ){ + if (checkelse && nesting == 0) { + // check the condition + start = bufferPos[bufferStackPos]; + skipToNewLine(); + len = bufferPos[bufferStackPos] - start; + if (expressionEvaluator.evaluate(buffer, start, len, definitions) != 0) + // condition passed, we're good + return; + } + } else { + //problem, ignore this one. + handleProblem( IProblem.PREPROCESSOR_UNBALANCE_CONDITION, start, ppKeywords.findKey( buffer, start, len ) ); + skipToNewLine(); + } break; case ppEndif: - if (nesting > 0) { - --nesting; - } else { - skipToNewLine(); - return; - } + if( branchState( BRANCH_END ) ){ + if (nesting > 0) { + --nesting; + } else { + skipToNewLine(); + return; + } + } else { + //problem, ignore this one. + handleProblem( IProblem.PREPROCESSOR_UNBALANCE_CONDITION, start, ppKeywords.findKey( buffer, start, len ) ); + skipToNewLine(); + } break; } }