diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CompletionInMacroExpansionException.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CompletionInMacroExpansionException.java new file mode 100644 index 00000000000..c90cc4db43a --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CompletionInMacroExpansionException.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Markus Schorn - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.core.parser.scanner; + +import org.eclipse.cdt.core.parser.IToken; +import org.eclipse.cdt.core.parser.OffsetLimitReachedException; + +/** + * Thrown when content assist is used within the parameter list of a macro expansion. + * It transports the token list of the current parameter for further use in attempting + * a completion. + * @since 5.0 + */ +public class CompletionInMacroExpansionException extends OffsetLimitReachedException { + + private TokenList fParameterTokens; + + public CompletionInMacroExpansionException(int origin, IToken lastToken, TokenList paramTokens) { + super(origin, lastToken); + fParameterTokens = paramTokens; + } + + public TokenList getParameterTokens() { + return fParameterTokens; + } +} 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 f933cf0123d..474eefe48d8 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 @@ -170,15 +170,25 @@ public class MacroExpander { TokenSource input= new TokenSource(lexer, stopAtNewline); TokenList firstExpansion= new TokenList(); - firstExpansion.append(new ExpansionBoundary(macro, true)); - expandOne(identifier, macro, forbidden, input, firstExpansion, null); - firstExpansion.append(new ExpansionBoundary(macro, false)); + TokenList result; + try { + firstExpansion.append(new ExpansionBoundary(macro, true)); + expandOne(identifier, macro, forbidden, input, firstExpansion, null); + firstExpansion.append(new ExpansionBoundary(macro, false)); - input.prepend(firstExpansion); - - TokenList result= expandAll(input, forbidden, isPPCondition, null); + input.prepend(firstExpansion); + + result= expandAll(input, forbidden, isPPCondition, null); + } + 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. + // For a better solution one would have to perform the expansion with artificial + // parameters and then check where the completion token ends up in the expansion. + result= e.getParameterTokens().cloneTokens(); + } postProcessTokens(result); - return result; } @@ -455,11 +465,17 @@ public class MacroExpander { case IToken.tEND_OF_INPUT: assert nesting >= 0; if (fCompletionMode) { - t.setType(IToken.tCOMPLETION); + if (idx < result.length) { + throw new CompletionInMacroExpansionException(ORIGIN, t, result[idx]); + } throw new OffsetLimitReachedException(ORIGIN, null); } break loop; case IToken.tCOMPLETION: + if (idx < result.length) { + result[idx].append(t); + throw new CompletionInMacroExpansionException(ORIGIN, t, result[idx]); + } throw new OffsetLimitReachedException(ORIGIN, t); case Lexer.tNEWLINE: @@ -840,13 +856,12 @@ public class MacroExpander { case IToken.tCHAR: case IToken.tLCHAR: final char[] image= t.getCharImage(); - for (int i = 0; i < image.length; i++) { - final char c = image[i]; - if (c == '"' || c == '\\') { - buf.append('\\'); + for (final char c : image) { + if (c == '"' || c == '\\') { + buf.append('\\'); + } + buf.append(c); } - buf.append(c); - } space= false; break; @@ -911,6 +926,12 @@ public class MacroExpander { case CPreprocessor.tNOSPACE: replacement.removeBehind(l); continue; + + case IToken.tCOMPLETION: + // we need to preserve the length of the completion token. + t.setOffset(offset, offset+t.getLength()); + t.setNext(null); + return; } t.setOffset(offset, ++offset); l= t; diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java index 09aa8330ed2..a8310af7764 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests.java @@ -1059,4 +1059,39 @@ public class CompletionTests extends AbstractContentAssistTest { }; assertCompletionResults(fCursorOffset, expected, AbstractContentAssistTest.COMPARE_REP_STRINGS); } + + // #define INIT_PTR(PtrName) (PtrName) = 0; + // class CCApp { + // public: + // int pIShell; + // }; + // + // int main(void) { + // CCApp *pThis = 0; + // + // INIT_PTR(pTh/*cursor*/); + // } + public void testCompletionInMacroArguments1_Bug200208() throws Exception { + final String[] expected= {"pThis"}; + assertCompletionResults(fCursorOffset, expected, AbstractContentAssistTest.COMPARE_REP_STRINGS); + } + + // #define INIT_PTR(PtrName) (PtrName) = 0; + // #define COPY_PTR(pTarget, pSource) (pTarget) = (pSource) + // + // class CCApp { + // public: + // int pIShell; + // }; + // + // int main(void) { + // CCApp *pThis = 0; + // + // INIT_PTR(pThis); + // COPY_PTR(pThis->pIShell, pThis->pI/*cursor*/) + // } + public void testCompletionInMacroArguments2_Bug200208() throws Exception { + final String[] expected= {"pIShell"}; + assertCompletionResults(fCursorOffset, expected, AbstractContentAssistTest.COMPARE_REP_STRINGS); + } } diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java index d1a1895a87e..567dffa8bde 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/contentassist2/CompletionTests_PlainC.java @@ -867,4 +867,35 @@ public class CompletionTests_PlainC extends AbstractContentAssistTest { assertCompletionResults(expected); } + // #define INIT_PTR(PtrName) (PtrName) = 0; + // struct CCApp { + // int pIShell; + // }; + // + // int main(void) { + // struct CCApp *pThis = 0; + // INIT_PTR(pTh/*cursor*/); + // } + public void testCompletionInMacroArguments1_Bug200208() throws Exception { + final String[] expected= {"pThis"}; + assertCompletionResults(expected); + } + + // #define INIT_PTR(PtrName) (PtrName) = 0; + // #define COPY_PTR(pTarget, pSource) (pTarget) = (pSource) + // + // struct CCApp { + // int pIShell; + // }; + // + // int main(void) { + // struct CCApp *pThis = 0; + // + // INIT_PTR(pThis); + // COPY_PTR(pThis->pIShell, pThis->pI/*cursor*/) + // } + public void testCompletionInMacroArguments2_Bug200208() throws Exception { + final String[] expected= {"pIShell"}; + assertCompletionResults(expected); + } }