mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Prevent the expansion of a macro when the closing parenthesis is not there, bug 251734.
This commit is contained in:
parent
8961527f07
commit
ee1e58259d
4 changed files with 73 additions and 19 deletions
|
@ -18,7 +18,8 @@ import org.eclipse.cdt.core.parser.IToken;
|
|||
|
||||
|
||||
/**
|
||||
* Scanner2Tests ported to use the CPreprocessor
|
||||
* Scanner2Tests ported to use the CPreprocessor plus additional bugs fixed in
|
||||
* the CPreprocessor, afterwards.
|
||||
*/
|
||||
public class PreprocessorBugsTests extends PreprocessorTestsBase {
|
||||
|
||||
|
@ -165,4 +166,25 @@ public class PreprocessorBugsTests extends PreprocessorTestsBase {
|
|||
validateProblemCount(1);
|
||||
validateProblem(0, IProblem.SCANNER_EXPRESSION_SYNTAX_ERROR, null);
|
||||
}
|
||||
|
||||
// #define BAR1_RX_BLOCK_SIZE 1
|
||||
// #define MAX(__x,__y) ((__x)>(__y)?(__x):(__y))
|
||||
// #define BAR_BLOCK_SIZE (MAX(BAR1_RX_BLOCK_SIZE,
|
||||
// int main(void) {
|
||||
// BAR_BLOCK_SIZE;
|
||||
// }
|
||||
public void testMissingClosingParenthesis_Bug251734() throws Exception {
|
||||
initializeScanner();
|
||||
validateToken(IToken.t_int);
|
||||
validateIdentifier("main");
|
||||
validateToken(IToken.tLPAREN);
|
||||
validateToken(IToken.t_void);
|
||||
validateToken(IToken.tRPAREN);
|
||||
validateToken(IToken.tLBRACE);
|
||||
validateToken(IToken.tLPAREN);
|
||||
validateEOF();
|
||||
validateProblemCount(1);
|
||||
validateProblem(0, IProblem.PREPROCESSOR_MISSING_RPAREN_PARMLIST, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -87,6 +87,8 @@ public class PreprocessorTests extends PreprocessorTestsBase {
|
|||
public void testMissingParenthesis() throws Exception {
|
||||
initializeScanner();
|
||||
validateEOF();
|
||||
validateProblemCount(1);
|
||||
validateProblem(0, IProblem.PREPROCESSOR_MISSING_RPAREN_PARMLIST, "f");
|
||||
}
|
||||
|
||||
// #define b(x) ok
|
||||
|
|
|
@ -35,7 +35,7 @@ ScannerProblemFactory.error.preproc.macroUsage=Macro usage error for macro : {0}
|
|||
ScannerProblemFactory.error.preproc.circularInclusion=Circular inclusion for file : {0}
|
||||
ScannerProblemFactory.error.preproc.invalidDirective=Invalid preprocessor directive : {0}
|
||||
ScannerProblemFactory.error.preproc.macroPasting=Invalid use of macro pasting in macro : {0}
|
||||
ScannerProblemFactory.error.preproc.missingRParen=missing ) in macro parameter list
|
||||
ScannerProblemFactory.error.preproc.missingRParen=missing ')' in parameter list of macro : {0}
|
||||
ScannerProblemFactory.error.preproc.invalidVaArgs=__VA_ARGS__ can only appear in the expansion of a C99 variadic macro
|
||||
|
||||
ScannerProblemFactory.error.scanner.invalidEscapeChar=Invalid escape character encountered
|
||||
|
|
|
@ -32,6 +32,8 @@ import org.eclipse.cdt.internal.core.parser.scanner.MacroDefinitionParser.TokenP
|
|||
* @since 5.0
|
||||
*/
|
||||
public class MacroExpander {
|
||||
private static final class AbortMacroExpansionException extends Exception {}
|
||||
|
||||
private static final int ORIGIN = OffsetLimitReachedException.ORIGIN_MACRO_EXPANSION;
|
||||
private static final Token END_TOKEN = new Token(IToken.tEND_OF_INPUT, null, 0, 0);
|
||||
private static final TokenList EMPTY_TOKEN_LIST = new TokenList();
|
||||
|
@ -179,8 +181,7 @@ public class MacroExpander {
|
|||
input.prepend(firstExpansion);
|
||||
|
||||
result= expandAll(input, forbidden, isPPCondition, null);
|
||||
}
|
||||
catch (CompletionInMacroExpansionException e) {
|
||||
} catch (CompletionInMacroExpansionException e) {
|
||||
// for content assist in macro expansions, we return the list of tokens of the
|
||||
// parameter at the current cursor position and hope that they make sense if
|
||||
// they are inserted at the position of the expansion.
|
||||
|
@ -243,6 +244,7 @@ public class MacroExpander {
|
|||
* tokens from the input (to read the parameters) and stores the resulting tokens together
|
||||
* with boundary markers in the result token list.
|
||||
* Returns the last token of the expansion.
|
||||
* @throws AbortMacroExpansionException
|
||||
*/
|
||||
private Token expandOne(Token lastConsumed, PreprocessorMacro macro,
|
||||
IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden, TokenSource input, TokenList result,
|
||||
|
@ -255,7 +257,28 @@ public class MacroExpander {
|
|||
if (tracker != null) {
|
||||
tracker.startFunctionStyleMacro((Token) lastConsumed.clone());
|
||||
}
|
||||
try {
|
||||
lastConsumed= parseArguments(input, (FunctionStyleMacro) macro, forbidden, argInputs, tracker);
|
||||
} catch (AbortMacroExpansionException e) {
|
||||
// ignore this macro expansion
|
||||
for (int i = 0; i < argInputs.length; i++) {
|
||||
TokenSource argInput= argInputs[i];
|
||||
executeScopeMarkers(argInput, forbidden);
|
||||
if (tracker != null) {
|
||||
tracker.setExpandedMacroArgument(null);
|
||||
}
|
||||
}
|
||||
if (tracker != null) {
|
||||
if (tracker.isRequestedStep()) {
|
||||
tracker.storeFunctionStyleMacroReplacement(macro, new TokenList(), result);
|
||||
} else if (tracker.isDone()) {
|
||||
tracker.appendFunctionStyleMacro(result);
|
||||
}
|
||||
tracker.endFunctionStyleMacro();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
TokenList[] clonedArgs= new TokenList[paramCount];
|
||||
TokenList[] expandedArgs= new TokenList[paramCount];
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
|
@ -278,17 +301,14 @@ public class MacroExpander {
|
|||
}
|
||||
if (tracker == null) {
|
||||
replaceArgs(macro, clonedArgs, expandedArgs, result);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (tracker.isRequestedStep()) {
|
||||
TokenList replacement= new TokenList();
|
||||
replaceArgs(macro, clonedArgs, expandedArgs, replacement);
|
||||
tracker.storeFunctionStyleMacroReplacement(macro, replacement, result);
|
||||
}
|
||||
else if (tracker.isDone()) {
|
||||
} else if (tracker.isDone()) {
|
||||
tracker.appendFunctionStyleMacro(result);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
replaceArgs(macro, clonedArgs, expandedArgs, result);
|
||||
}
|
||||
tracker.endFunctionStyleMacro();
|
||||
|
@ -424,12 +444,9 @@ public class MacroExpander {
|
|||
|
||||
/**
|
||||
* Expects that the identifier has been consumed.
|
||||
* @param forbidden
|
||||
* @param tracker
|
||||
* @throws OffsetLimitReachedException
|
||||
*/
|
||||
private Token parseArguments(TokenSource input, FunctionStyleMacro macro, IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden, TokenSource[] result,
|
||||
MacroExpansionTracker tracker) throws OffsetLimitReachedException {
|
||||
private Token parseArguments(TokenSource input, FunctionStyleMacro macro, IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden,
|
||||
TokenSource[] result, MacroExpansionTracker tracker) throws OffsetLimitReachedException, AbortMacroExpansionException {
|
||||
final int argCount= macro.getParameterPlaceholderList().length;
|
||||
final boolean hasVarargs= macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS;
|
||||
final int requiredArgs= hasVarargs ? argCount-1 : argCount;
|
||||
|
@ -439,13 +456,16 @@ public class MacroExpander {
|
|||
result[i]= new TokenSource(null, false);
|
||||
}
|
||||
|
||||
boolean complete= false;
|
||||
boolean missingRParenthesis= false;
|
||||
boolean tooManyArgs= false;
|
||||
|
||||
boolean isFirstOfArg= true;
|
||||
Token lastToken= null;
|
||||
TokenList spaceMarkers= new TokenList();
|
||||
loop: while (true) {
|
||||
Token t= input.fetchFirst();
|
||||
if (t == null) {
|
||||
missingRParenthesis= true;
|
||||
break loop;
|
||||
}
|
||||
if (tracker != null) {
|
||||
|
@ -470,6 +490,7 @@ public class MacroExpander {
|
|||
}
|
||||
throw new OffsetLimitReachedException(ORIGIN, null);
|
||||
}
|
||||
missingRParenthesis= true;
|
||||
break loop;
|
||||
case IToken.tCOMPLETION:
|
||||
if (idx < result.length) {
|
||||
|
@ -491,7 +512,6 @@ public class MacroExpander {
|
|||
case IToken.tRPAREN:
|
||||
assert nesting >= 0;
|
||||
if (--nesting < 0) {
|
||||
complete= true;
|
||||
break loop;
|
||||
}
|
||||
break;
|
||||
|
@ -506,6 +526,7 @@ public class MacroExpander {
|
|||
continue loop;
|
||||
}
|
||||
else if (!hasVarargs) {
|
||||
tooManyArgs= true;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
|
@ -531,6 +552,7 @@ public class MacroExpander {
|
|||
assert nesting >= 0;
|
||||
}
|
||||
if (argCount == 0) {
|
||||
tooManyArgs= true;
|
||||
break loop;
|
||||
}
|
||||
result[idx].appendAll(spaceMarkers);
|
||||
|
@ -538,7 +560,15 @@ public class MacroExpander {
|
|||
isFirstOfArg= false;
|
||||
}
|
||||
|
||||
if (!complete || idx+1 < requiredArgs) {
|
||||
|
||||
if (missingRParenthesis) {
|
||||
handleProblem(IProblem.PREPROCESSOR_MISSING_RPAREN_PARMLIST, macro.getNameCharArray());
|
||||
throw new AbortMacroExpansionException();
|
||||
}
|
||||
|
||||
if (tooManyArgs)
|
||||
handleProblem(IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, macro.getNameCharArray());
|
||||
else if (idx+1 < requiredArgs) {
|
||||
handleProblem(IProblem.PREPROCESSOR_MACRO_USAGE_ERROR, macro.getNameCharArray());
|
||||
}
|
||||
return lastToken;
|
||||
|
|
Loading…
Add table
Reference in a new issue