diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/ExpansionExplorerTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/ExpansionExplorerTests.java index 1acbbcfff5f..25a81be249c 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/ExpansionExplorerTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/ExpansionExplorerTests.java @@ -56,14 +56,14 @@ public class ExpansionExplorerTests extends BaseTestCase { private void verifyStepCount(MacroExpander expander, String original, int steps) { MacroExpansionTracker tracker= new MacroExpansionTracker(Integer.MAX_VALUE); - expander.expand(original, tracker, "", 1); + expander.expand(original, tracker, "", 1, false); assertEquals(steps, tracker.getStepCount()); } private void verifyStep(MacroExpander expander, String original, int step, String expectedPre, String expectedPost) { MacroExpansionTracker tracker= new MacroExpansionTracker(step); - expander.expand(original, tracker, "", 1); + expander.expand(original, tracker, "", 1, false); String pre = tracker.getCodeBeforeStep(); ReplaceEdit replacement = tracker.getReplacement(); assertNotNull(pre); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/PreprocessorBugsTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/PreprocessorBugsTests.java index 2e6b9ba430b..2b0f329886c 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/PreprocessorBugsTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/PreprocessorBugsTests.java @@ -92,4 +92,33 @@ public class PreprocessorBugsTests extends PreprocessorTestsBase { validateEOF(); validateProblemCount(0); } + + // #define FOO(ARG) defined(ARG##_BAZ) + // #define BAR_BAZ UNDEFINED + // #if FOO(BAR) + // juhuu + // #else + // ojeh + // #endif + // FOO(BAR) // here expansion has to take place + // + // #define PLATFORM(WTF_FEATURE) (defined( WTF_PLATFORM_##WTF_FEATURE ) && WTF_PLATFORM_##WTF_FEATURE) + // #define WTF_PLATFORM_FOO 1 + // #if PLATFORM(FOO) + // ok + // #endif + + + public void testIndirectDefined_Bug225562() throws Exception { + initializeScanner(); + validateIdentifier("juhuu"); + validateIdentifier("defined"); + validateToken(IToken.tLPAREN); + validateIdentifier("UNDEFINED"); // here the expansion has to take place + validateToken(IToken.tRPAREN); + + validateIdentifier("ok"); + validateEOF(); + validateProblemCount(0); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java index afe9e45c284..f933cf0123d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpander.java @@ -11,12 +11,14 @@ package org.eclipse.cdt.internal.core.parser.scanner; import java.util.ArrayList; +import java.util.Arrays; import java.util.BitSet; import java.util.IdentityHashMap; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.parser.IProblem; import org.eclipse.cdt.core.parser.IToken; +import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.core.parser.OffsetLimitReachedException; import org.eclipse.cdt.core.parser.util.CharArrayMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; @@ -49,10 +51,12 @@ public class MacroExpander { fIsStart= isStart; } + @Override public char[] getCharImage() { return CharArrayUtils.EMPTY; } + @Override public String toString() { return "{" + (fIsStart ? '+' : '-') + fMacro.getName() + '}'; //$NON-NLS-1$ } @@ -152,7 +156,7 @@ public class MacroExpander { /** * Expects that the identifier has been consumed, stores the result in the list provided. */ - public TokenList expand(Lexer lexer, boolean stopAtNewline, PreprocessorMacro macro, Token identifier, boolean completionMode) throws OffsetLimitReachedException { + public TokenList expand(Lexer lexer, boolean stopAtNewline, final boolean isPPCondition, PreprocessorMacro macro, Token identifier, boolean completionMode) throws OffsetLimitReachedException { fImplicitMacroExpansions.clear(); fImageLocationInfos.clear(); @@ -172,7 +176,7 @@ public class MacroExpander { input.prepend(firstExpansion); - TokenList result= expandAll(input, forbidden, null); + TokenList result= expandAll(input, forbidden, isPPCondition, null); postProcessTokens(result); return result; @@ -182,7 +186,7 @@ public class MacroExpander { * Method for tracking macro expansions. * @since 5.0 */ - public void expand(String beforeExpansion, MacroExpansionTracker tracker, String filePath, int lineNumber) { + public void expand(String beforeExpansion, MacroExpansionTracker tracker, String filePath, int lineNumber, boolean protectDefinedConstructs) { fImplicitMacroExpansions.clear(); fImageLocationInfos.clear(); fFixedInput= beforeExpansion.toCharArray(); @@ -218,7 +222,7 @@ public class MacroExpander { firstExpansion.append(new ExpansionBoundary(macro, false)); input.prepend(firstExpansion); - TokenList result= expandAll(input, forbidden, tracker); + TokenList result= expandAll(input, forbidden, protectDefinedConstructs, tracker); tracker.finish(result, fEndOffset); } catch (OffsetLimitReachedException e) { } @@ -249,7 +253,7 @@ public class MacroExpander { final boolean needCopy= paramUsage.get(2*i); final boolean needExpansion = paramUsage.get(2*i+1); clonedArgs[i]= needCopy ? argInput.cloneTokens() : EMPTY_TOKEN_LIST; - expandedArgs[i]= needExpansion ? expandAll(argInput, forbidden, tracker) : EMPTY_TOKEN_LIST; + expandedArgs[i]= needExpansion ? expandAll(argInput, forbidden, false, tracker) : EMPTY_TOKEN_LIST; if (!needExpansion) { executeScopeMarkers(argInput, forbidden); } @@ -310,8 +314,9 @@ public class MacroExpander { } private TokenList expandAll(TokenSource input, IdentityHashMap forbidden, - MacroExpansionTracker tracker) throws OffsetLimitReachedException { + boolean protectDefinedConstructs, MacroExpansionTracker tracker) throws OffsetLimitReachedException { final TokenList result= new TokenList(); + boolean protect= false; Token l= null; Token t= input.removeFirst(); while(t != null) { @@ -320,10 +325,16 @@ public class MacroExpander { ((ExpansionBoundary) t).execute(forbidden); break; case IToken.tIDENTIFIER: - PreprocessorMacro macro= fDictionary.get(t.getCharImage()); - if (tracker != null && tracker.isDone()) { + final char[] image = t.getCharImage(); + PreprocessorMacro macro= fDictionary.get(image); + if (protect || (tracker != null && tracker.isDone())) { result.append(t); } + else if (protectDefinedConstructs && Arrays.equals(image, Keywords.cDEFINED)) { + t.setType(CPreprocessor.tDEFINED); + result.append(t); + protect= true; + } // tricky: don't mark function-style macros if you don't find the left parenthesis else if (macro == null || (macro.isFunctionStyle() && !input.findLParenthesis())) { result.append(t); @@ -351,7 +362,13 @@ public class MacroExpander { input.prepend(replacement); } break; + case IToken.tLPAREN: + case CPreprocessor.tNOSPACE: + case CPreprocessor.tSPACE: + result.append(t); + break; default: + protect= false; result.append(t); break; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MultiMacroExpansionExplorer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MultiMacroExpansionExplorer.java index 45fa127d5eb..2d6a9393d6d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MultiMacroExpansionExplorer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MultiMacroExpansionExplorer.java @@ -18,6 +18,10 @@ import java.util.Map; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElifStatement; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfStatement; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; @@ -65,6 +69,7 @@ public class MultiMacroExpansionExplorer extends MacroExpansionExplorer { throw new IllegalArgumentException(); } final ILocationResolver resolver = getResolver(tu); + final IASTNodeSelector nodeLocator= tu.getNodeSelector(null); final IASTPreprocessorMacroExpansion[] expansions= resolver.getMacroExpansions(loc); final int count= expansions.length; @@ -87,11 +92,14 @@ public class MultiMacroExpansionExplorer extends MacroExpansionExplorer { IASTFileLocation refLoc= expansion.getFileLocation(); int from= refLoc.getNodeOffset()-firstOffset; int to= from+refLoc.getNodeLength(); + IASTNode enclosing= nodeLocator.findEnclosingNode(from+firstOffset-1, 2); + boolean isPPCond= enclosing instanceof IASTPreprocessorIfStatement || + enclosing instanceof IASTPreprocessorElifStatement; fBoundaries[++bidx]= from; fBoundaries[++bidx]= to; fDelegates[++didx]= new SingleMacroExpansionExplorer(new String(fSource, from, to-from), refs.toArray(new IASTName[refs.size()]), fMacroLocations, - fFilePath, refLoc.getStartingLineNumber()); + fFilePath, refLoc.getStartingLineNumber(), isPPCond); } } fBoundaries[++bidx]= fSource.length; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SingleMacroExpansionExplorer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SingleMacroExpansionExplorer.java index 9771f5dacc9..492d930fd71 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SingleMacroExpansionExplorer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SingleMacroExpansionExplorer.java @@ -36,17 +36,20 @@ public class SingleMacroExpansionExplorer extends MacroExpansionExplorer { private final CharArrayMap fDictionary; private MacroExpansionStep fFullExpansion; private int fExpansionCount; - private String fFilePath; - private int fLineNumber; + private final String fFilePath; + private final int fLineNumber; private final Map fMacroLocationMap; + private final boolean fIsPPCondition; public SingleMacroExpansionExplorer(String input, IASTName[] refs, - Map macroDefinitionLocationMap, String filePath, int lineNumber) { + Map macroDefinitionLocationMap, + String filePath, int lineNumber, boolean isPPCondition) { fInput= input; fDictionary= createDictionary(refs); fMacroLocationMap= macroDefinitionLocationMap; fFilePath= filePath; fLineNumber= lineNumber; + fIsPPCondition= isPPCondition; } private CharArrayMap createDictionary(IASTName[] refs) { @@ -79,7 +82,7 @@ public class SingleMacroExpansionExplorer extends MacroExpansionExplorer { private void computeExpansion() { MacroExpander expander= new MacroExpander(ILexerLog.NULL, fDictionary, null, LEX_OPTIONS); MacroExpansionTracker tracker= new MacroExpansionTracker(Integer.MAX_VALUE); - expander.expand(fInput, tracker, fFilePath, fLineNumber); + expander.expand(fInput, tracker, fFilePath, fLineNumber, fIsPPCondition); fExpansionCount= tracker.getStepCount(); ReplaceEdit r= tracker.getReplacement(); @@ -95,7 +98,7 @@ public class SingleMacroExpansionExplorer extends MacroExpansionExplorer { } MacroExpander expander= new MacroExpander(ILexerLog.NULL, fDictionary, null, LEX_OPTIONS); MacroExpansionTracker tracker= new MacroExpansionTracker(step); - expander.expand(fInput, tracker, fFilePath, fLineNumber); + expander.expand(fInput, tracker, fFilePath, fLineNumber, fIsPPCondition); fExpansionCount= tracker.getStepCount(); ReplaceEdit r= tracker.getReplacement();