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
new file mode 100644
index 00000000000..5d9868ee808
--- /dev/null
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/ExpansionExplorerTests.java
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * 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.core.parser.tests.scanner;
+
+import junit.framework.TestSuite;
+
+import org.eclipse.cdt.core.dom.parser.c.GCCScannerExtensionConfiguration;
+import org.eclipse.cdt.core.parser.CodeReader;
+import org.eclipse.cdt.core.parser.IToken;
+import org.eclipse.cdt.core.parser.NullLogService;
+import org.eclipse.cdt.core.parser.OffsetLimitReachedException;
+import org.eclipse.cdt.core.parser.ParserLanguage;
+import org.eclipse.cdt.core.parser.ScannerInfo;
+import org.eclipse.cdt.core.testplugin.CTestPlugin;
+import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
+import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
+import org.eclipse.cdt.internal.core.dom.NullCodeReaderFactory;
+import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
+import org.eclipse.cdt.internal.core.parser.scanner.MacroExpander;
+import org.eclipse.cdt.internal.core.parser.scanner.MacroExpansionTracker;
+import org.eclipse.text.edits.ReplaceEdit;
+
+
+public class ExpansionExplorerTests extends BaseTestCase {
+
+ public static TestSuite suite() {
+ return suite(ExpansionExplorerTests.class);
+ }
+
+ private void performTest(int steps) throws Exception {
+ StringBuffer[] bufs= TestSourceReader.getContentsForTest(
+ CTestPlugin.getDefault().getBundle(), "parser", getClass(), getName(), steps+2);
+ String[] input= new String[steps+2];
+ int i= -1;
+ for (StringBuffer buf : bufs) {
+ input[++i]= buf.toString().trim();
+ }
+ final MacroExpander expander= createExpander(input[0]);
+ final String original= input[1];
+
+ verifyStep(expander, original, Integer.MAX_VALUE, original, input[steps+1]);
+ for (i= 0; i < steps; i++) {
+ verifyStep(expander, original, i, input[i+1], input[i+2]);
+ }
+ }
+
+ private void verifyStep(MacroExpander expander, String original, int step, String expectedPre,
+ String expectedPost) {
+ MacroExpansionTracker tracker= new MacroExpansionTracker(step);
+ expander.expand(original, tracker);
+ String pre = tracker.getCodeBeforeStep();
+ ReplaceEdit replacement = tracker.getReplacement();
+ assertNotNull(pre);
+ assertNotNull(replacement);
+ String post= apply(pre, replacement);
+
+ assertEquals(expectedPre, pre);
+ assertEquals(expectedPost, post);
+ }
+
+ private String apply(String pre, ReplaceEdit replacement) {
+ StringBuilder buf= new StringBuilder();
+ buf.append(pre, 0, replacement.getOffset());
+ buf.append(replacement.getText());
+ buf.append(pre, replacement.getExclusiveEnd(), pre.length());
+ return buf.toString();
+ }
+
+ private MacroExpander createExpander(final String macrodefs) throws OffsetLimitReachedException {
+ CPreprocessor cpp= new CPreprocessor(new CodeReader(macrodefs.toCharArray()),
+ new ScannerInfo(), ParserLanguage.C, new NullLogService(),
+ new GCCScannerExtensionConfiguration(), NullCodeReaderFactory.getInstance());
+ int type;
+ do {
+ type= cpp.nextTokenRaw().getType();
+ } while (type != IToken.tEND_OF_INPUT);
+ return (MacroExpander) cpp.getAdapter(MacroExpander.class);
+ }
+
+ // #define A
+
+ // B
+
+ // B
+ public void testNoOp() throws Exception {
+ performTest(1);
+ }
+
+ // #define A B
+
+ // A
+
+ // B
+ public void testObject() throws Exception {
+ performTest(1);
+ }
+
+ // #define A A1
+ // #define A1 A2
+ // #define A2 A
+
+ // A
+
+ // A1
+
+ // A2
+
+ // A
+ public void testObjectChain() throws Exception {
+ performTest(3);
+ }
+
+ // #define A(x) B+x
+
+ // A(c)
+
+ // B+c
+ public void testFunction() throws Exception {
+ performTest(1);
+ }
+
+
+ // #define A(x) x+x
+ // #define _t t
+
+ // A(_t)
+
+ // A(t)
+
+ // t+t
+ public void testFunctionParam() throws Exception {
+ performTest(2);
+ }
+
+ // #define A(x,y) x+y
+ // #define _t t
+
+ // A(_t, _t)
+
+ // A(t, _t)
+
+ // A(t, t)
+
+ // t+t
+ public void test2Params() throws Exception {
+ performTest(3);
+ }
+
+ // #define A(x,y,z) x + y + z
+ // #define _t t
+
+ // A ( _t , , _t )
+
+ // A ( t , , _t )
+
+ // A ( t , , t )
+
+ // t + + t
+ public void test3Params() throws Exception {
+ performTest(3);
+ }
+
+ // #define m !(m)+n
+ // #define n(n) n(m)
+
+ // m(m)
+
+ // !(m)+n(m)
+
+ // !(m)+n(!(m)+n)
+
+ // !(m)+!(m)+n(m)
+
+ // !(m)+!(m)+n(!(m)+n)
+ public void testRecursiveExpansion() throws Exception {
+ performTest(4);
+ }
+
+ // #define f(x,y) (x + y)
+ // #define g(x,y) (x*y)
+ // #define _a a
+ // #define _b b
+
+ // f( g(_a,_b), g(_b,_a) )
+
+ // f( g(a,_b), g(_b,_a) )
+
+ // f( g(a,b), g(_b,_a) )
+
+ // f( (a*b), g(_b,_a) )
+
+ // f( (a*b), g(b,_a) )
+
+ // f( (a*b), g(b,a) )
+
+ // f( (a*b), (b*a) )
+
+ // ((a*b) + (b*a))
+ public void testNestedFunctions() throws Exception {
+ performTest(7);
+ }
+
+
+
+}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java
index 68a700770db..08e4c6faf87 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 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
@@ -464,17 +464,18 @@ public class LocationMapTests extends BaseTestCase {
fLocationMap.encounteredComment(12, 23, false);
checkComment(fLocationMap.getComments()[0], new String(LONGDIGITS, 110, 15), false, FN, 110, 15, 2, 2);
- IASTName[] refs= fLocationMap.getReferences(macro1);
+ IASTName[] refs= fLocationMap.getReferences(macro3);
assertEquals(1, refs.length);
- checkName(refs[0], macro1, "n1", fTu, IASTTranslationUnit.EXPANSION_NAME, ROLE_REFERENCE, FN, 110, 15, 2, 2, new String(LONGDIGITS, 110, 15));
+ IASTName macro3ref= refs[0];
+ checkName(refs[0], macro3, "n3", fTu, IASTTranslationUnit.EXPANSION_NAME, ROLE_REFERENCE, FN, 110, 5, 2, 2, new String(LONGDIGITS, 110, 5));
+
+ refs= fLocationMap.getReferences(macro1);
+ assertEquals(1, refs.length);
+ checkName(refs[0], macro1, "n1", macro3ref, IASTTranslationUnit.EXPANSION_NAME, ROLE_REFERENCE, FN, 110, 15, 2, 2, new String(LONGDIGITS, 110, 15));
refs= fLocationMap.getReferences(macro2);
assertEquals(1, refs.length);
- checkName(refs[0], macro2, "n2", fTu, IASTTranslationUnit.EXPANSION_NAME, ROLE_REFERENCE, FN, 110, 15, 2, 2, new String(LONGDIGITS, 110, 15));
-
- refs= fLocationMap.getReferences(macro3);
- assertEquals(1, refs.length);
- checkName(refs[0], macro3, "n3", fTu, IASTTranslationUnit.EXPANSION_NAME, ROLE_REFERENCE, FN, 110, 5, 2, 2, new String(LONGDIGITS, 110, 5));
+ checkName(refs[0], macro2, "n2", macro3ref, IASTTranslationUnit.EXPANSION_NAME, ROLE_REFERENCE, FN, 110, 15, 2, 2, new String(LONGDIGITS, 110, 15));
}
public void testContexts() {
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 a16d044ad2a..65c9db08c35 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2007 IBM Corporation and others.
+ * Copyright (c) 2004, 2008 IBM Corporation 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
@@ -11,9 +11,6 @@
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.scanner;
-import java.util.Iterator;
-import java.util.List;
-
import junit.framework.TestSuite;
import org.eclipse.cdt.core.parser.IProblem;
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/PreprocessorTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/PreprocessorTests.java
index ca6ef20302c..6b9249cdd4b 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/PreprocessorTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/PreprocessorTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2007 IBM Corporation and others.
+ * Copyright (c) 2004, 2008 IBM Corporation 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
@@ -286,6 +286,69 @@ public class PreprocessorTests extends PreprocessorTestsBase {
validateProblemCount(0);
}
+ // #define variadic(x...) (a, ##x)
+ // #define _c c
+ // variadic();
+ // variadic(_c);
+ // variadic(_c,_c);
+ public void testGccVariadicMacroExtensions2() throws Exception {
+ initializeScanner();
+ validateToken(IToken.tLPAREN);
+ validateIdentifier("a");
+ validateToken(IToken.tRPAREN);
+ validateToken(IToken.tSEMI);
+
+ validateToken(IToken.tLPAREN);
+ validateIdentifier("a");
+ validateToken(IToken.tCOMMA);
+ validateIdentifier("c");
+ validateToken(IToken.tRPAREN);
+ validateToken(IToken.tSEMI);
+
+ validateToken(IToken.tLPAREN);
+ validateIdentifier("a");
+ validateToken(IToken.tCOMMA);
+ validateIdentifier("c");
+ validateToken(IToken.tCOMMA);
+ validateIdentifier("c");
+ validateToken(IToken.tRPAREN);
+ validateToken(IToken.tSEMI);
+ validateEOF();
+ validateProblemCount(0);
+ }
+
+ // #define variadic(y, x...) (a, ##x)
+ // #define _c c
+ // variadic(1);
+ // variadic(,_c);
+ // variadic(,_c,_c);
+ public void testGccVariadicMacroExtensions3() throws Exception {
+ initializeScanner();
+ validateToken(IToken.tLPAREN);
+ validateIdentifier("a");
+ validateToken(IToken.tRPAREN);
+ validateToken(IToken.tSEMI);
+
+ validateToken(IToken.tLPAREN);
+ validateIdentifier("a");
+ validateToken(IToken.tCOMMA);
+ validateIdentifier("c");
+ validateToken(IToken.tRPAREN);
+ validateToken(IToken.tSEMI);
+
+ validateToken(IToken.tLPAREN);
+ validateIdentifier("a");
+ validateToken(IToken.tCOMMA);
+ validateIdentifier("c");
+ validateToken(IToken.tCOMMA);
+ validateIdentifier("c");
+ validateToken(IToken.tRPAREN);
+ validateToken(IToken.tSEMI);
+
+ validateEOF();
+ validateProblemCount(0);
+ }
+
// #define str(x) #x
// str();
public void testEmptyStringify() throws Exception {
@@ -810,14 +873,14 @@ public class PreprocessorTests extends PreprocessorTestsBase {
}
- public void _testSpecExample3_2() throws Exception {
+ public void testSpecExample3_2() throws Exception {
StringBuffer sb = getExample3Defines();
sb.append("g(x+(3,4)-w) | h 5) & m (f)^m(m); \n");
// f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); //47
initializeScanner(sb.toString());
- validateIdentifier("g");
+ validateIdentifier("f");
validateToken(IToken.tLPAREN);
validateInteger("2");
validateToken(IToken.tSTAR);
@@ -849,7 +912,7 @@ public class PreprocessorTests extends PreprocessorTestsBase {
validateIdentifier("f");
validateToken(IToken.tLPAREN);
validateInteger("2");
- validateToken(IToken.tLPAREN);
+ validateToken(IToken.tSTAR);
validateToken(IToken.tLPAREN);
validateInteger("0");
validateToken(IToken.tCOMMA);
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/ScannerTestSuite.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/ScannerTestSuite.java
index 26df045ebb0..290588438d6 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/ScannerTestSuite.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/ScannerTestSuite.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 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
@@ -23,6 +23,7 @@ public class ScannerTestSuite extends TestSuite {
suite.addTest(PreprocessorTests.suite());
suite.addTest(InclusionTests.suite());
suite.addTest(PreprocessorBugsTests.suite());
+ suite.addTest(ExpansionExplorerTests.suite());
return suite;
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/IPDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/IPDOM.java
deleted file mode 100644
index d198ea46738..00000000000
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/IPDOM.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2006 QNX Software Systems 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:
- * QNX - Initial API and implementation
- * Markus Schorn (Wind River Systems)
- *******************************************************************************/
-package org.eclipse.cdt.core.dom;
-
-import org.eclipse.core.runtime.IAdaptable;
-
-/**
- * @deprecated use IIndex instead.
- */
-public interface IPDOM extends IAdaptable {}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTMacroExpansion.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTMacroExpansion.java
index 0500a5e9cab..a650c2c3fee 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTMacroExpansion.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTMacroExpansion.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2007 IBM Corporation and others.
+ * Copyright (c) 2004, 2008 IBM Corporation 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
@@ -27,6 +27,12 @@ public interface IASTMacroExpansion extends IASTNodeLocation {
*/
public IASTPreprocessorMacroDefinition getMacroDefinition();
+ /**
+ * The macro reference for the explicit macro expansion containing this expansion.
+ * @since 5.0
+ */
+ public IASTName getMacroReference();
+
/**
* Returns an offset within the macro-expansion. The offset can be used to compare
* nodes within the same macro-expansion. However, it does not serve as an offset
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java
index cf37fc7b365..9fe999998d0 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2007 IBM Corporation and others.
+ * Copyright (c) 2004, 2008 IBM Corporation 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
@@ -115,18 +115,9 @@ public interface IASTTranslationUnit extends IASTNode, IAdaptable {
* @return List of IASTName nodes representing uses of the binding
*/
public IASTName[] getReferences(IBinding binding);
-
- /**
- * Returns an array of locations. This is a sequence of file locations and macro-expansion locations.
- * @param offset sequence number as stored in the ast nodes.
- * @param length
- * @return and array of locations.
- * @deprecated the offsets needed for this method are not accessible via public API.
- */
- public IASTNodeLocation[] getLocationInfo(int offset, int length);
/**
- * Select the node in the treet that best fits the offset/length/file path.
+ * Select the node in the treat that best fits the offset/length/file path.
*
* @param path - file name specified through path
* @param offset - location in the file as an offset
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/rewrite/MacroExpansionExplorer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/rewrite/MacroExpansionExplorer.java
new file mode 100644
index 00000000000..fa07e1b34a8
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/rewrite/MacroExpansionExplorer.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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.core.dom.rewrite;
+
+import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.dom.ast.IMacroBinding;
+import org.eclipse.cdt.internal.core.parser.scanner.MultiMacroExpansionExplorer;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.text.edits.ReplaceEdit;
+
+/**
+ * Allows to understand macro expansions step by step.
+ * @since 5.0
+ */
+public abstract class MacroExpansionExplorer {
+
+ /**
+ * Representation of a single expansion step or a complete expansion.
+ */
+ public interface IMacroExpansionStep {
+ /**
+ * Returns the code before this step.
+ */
+ String getCodeBeforeStep();
+ /**
+ * Returns the code after this step.
+ */
+ String getCodeAfterStep();
+
+ /**
+ * Returns an array of replacements representing the change from the code before
+ * this step to the code after this step.
+ */
+ ReplaceEdit[] getReplacements();
+
+ /**
+ * Returns the macro that gets expanded in this step, or null
for
+ * a step representing a full expansion.
+ */
+ IMacroBinding getExpandedMacro();
+ }
+
+ /**
+ * Creates a macro expansion explorer for a given file location in a translation unit.
+ */
+ public static MacroExpansionExplorer create(IASTTranslationUnit tu, IASTFileLocation loc) {
+ return new MultiMacroExpansionExplorer(tu, loc);
+ }
+
+ /**
+ * Creates a macro expansion explorer for a given region in the outermost file of a
+ * translation unit.
+ */
+ public static MacroExpansionExplorer create(IASTTranslationUnit tu, IRegion loc) {
+ return new MultiMacroExpansionExplorer(tu, loc);
+ }
+
+ /**
+ * Returns the full expansion for the region of this expansion explorer.
+ */
+ public abstract IMacroExpansionStep getFullExpansion();
+
+ /**
+ * Returns the total number of available steps for expanding the region of this expansion
+ * explorer.
+ */
+ public abstract int getExpansionStepCount();
+
+ /**
+ * Returns a description for the requested step within the expansion of the region of this
+ * expansion explorer.
+ * @throws IndexOutOfBoundsException if step < 0 or step >= getExpansionStepCount().
+ */
+ public abstract IMacroExpansionStep getExpansionStep(int step) throws IndexOutOfBoundsException;
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayMap.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayMap.java
index 55546f4bf16..ab9c00981f5 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayMap.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayMap.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007 IBM Corporation and others.
+ * Copyright (c) 2007, 2008 IBM Corporation 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
@@ -10,9 +10,11 @@
*******************************************************************************/
package org.eclipse.cdt.core.parser.util;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
/**
@@ -174,6 +176,15 @@ public final class CharArrayMap implements ICharArrayMap {
return map.values();
}
+ public Collection keys() {
+ Set keys= map.keySet();
+ ArrayList r= new ArrayList(keys.size());
+ for (Key key : keys) {
+ r.add(CharArrayUtils.extract(key.buffer, key.start, key.length));
+ }
+ return r;
+ }
+
public void clear() {
map.clear();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTTranslationUnit.java
index 27ec23fa710..fe529e88cfe 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTTranslationUnit.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTTranslationUnit.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2002, 2007 IBM Corporation and others.
+ * Copyright (c) 2002, 2008 IBM Corporation 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
@@ -57,7 +57,6 @@ import org.eclipse.core.runtime.CoreException;
public class CASTTranslationUnit extends CASTNode implements IASTTranslationUnit {
private static final IASTPreprocessorStatement[] EMPTY_PREPROCESSOR_STATEMENT_ARRAY = new IASTPreprocessorStatement[0];
- private static final IASTNodeLocation[] EMPTY_PREPROCESSOR_LOCATION_ARRAY = new IASTNodeLocation[0];
private static final IASTPreprocessorMacroDefinition[] EMPTY_PREPROCESSOR_MACRODEF_ARRAY = new IASTPreprocessorMacroDefinition[0];
private static final IASTPreprocessorIncludeStatement[] EMPTY_PREPROCESSOR_INCLUSION_ARRAY = new IASTPreprocessorIncludeStatement[0];
private static final IASTProblem[] EMPTY_PROBLEM_ARRAY = new IASTProblem[0];
@@ -185,18 +184,6 @@ public class CASTTranslationUnit extends CASTNode implements IASTTranslationUnit
return CVisitor.getReferences(this, binding);
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getLocationInfo(int,
- * int)
- */
- public IASTNodeLocation[] getLocationInfo(int offset, int length) {
- if (resolver == null)
- return EMPTY_PREPROCESSOR_LOCATION_ARRAY;
- return resolver.getLocations(offset, length);
- }
-
private class CFindNodeForOffsetAction extends CASTVisitor {
{
shouldVisitNames = true;
@@ -546,6 +533,7 @@ public class CASTTranslationUnit extends CASTNode implements IASTTranslationUnit
return new IASTComment[0];
}
+ @SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
if (adapter.isAssignableFrom(resolver.getClass())) {
return resolver;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java
index 247e1714c3c..257f6a96438 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2007 IBM Corporation and others.
+ * Copyright (c) 2004, 2008 IBM Corporation 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
@@ -71,7 +71,6 @@ import org.eclipse.core.runtime.CoreException;
public class CPPASTTranslationUnit extends CPPASTNode implements ICPPASTTranslationUnit, IASTAmbiguityParent {
private static final IASTPreprocessorStatement[] EMPTY_PREPROCESSOR_STATEMENT_ARRAY = new IASTPreprocessorStatement[0];
- private static final IASTNodeLocation[] EMPTY_PREPROCESSOR_LOCATION_ARRAY = new IASTNodeLocation[0];
private static final IASTPreprocessorMacroDefinition[] EMPTY_PREPROCESSOR_MACRODEF_ARRAY = new IASTPreprocessorMacroDefinition[0];
private static final IASTPreprocessorIncludeStatement[] EMPTY_PREPROCESSOR_INCLUSION_ARRAY = new IASTPreprocessorIncludeStatement[0];
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
@@ -225,13 +224,6 @@ public class CPPASTTranslationUnit extends CPPASTNode implements ICPPASTTranslat
return CPPVisitor.getReferences(this, b);
}
-
- public IASTNodeLocation[] getLocationInfo(int offset, int length) {
- if (resolver == null)
- return EMPTY_PREPROCESSOR_LOCATION_ARRAY;
- return resolver.getLocations(offset, length);
- }
-
private class CPPFindNodeForOffsetAction extends CPPASTVisitor {
{
shouldVisitNames = true;
@@ -512,6 +504,7 @@ public class CPPASTTranslationUnit extends CPPASTNode implements ICPPASTTranslat
return new IASTComment[0];
}
+ @SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
if (adapter.isAssignableFrom(resolver.getClass())) {
return resolver;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorName.java
index 4c2afd1b275..59198c3b1af 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorName.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorName.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 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
@@ -124,10 +124,12 @@ class ASTMacroReferenceName extends ASTPreprocessorName {
fImageLocationInfo= imgLocationInfo;
}
+ @Override
public boolean isReference() {
return true;
}
+ @Override
public IASTImageLocation getImageLocation() {
if (fImageLocationInfo != null) {
IASTTranslationUnit tu= getTranslationUnit();
@@ -140,5 +142,5 @@ class ASTMacroReferenceName extends ASTPreprocessorName {
return null;
}
return super.getImageLocation();
- }
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java
index 0a27cf07b21..4e54f2961dc 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java
@@ -467,6 +467,10 @@ class ASTFileLocation implements IASTFileLocation {
public int getSequenceEndNumber() {
return fLocationCtx.getSequenceNumberForOffset(fOffset+fLength, true);
}
+
+ public LocationCtxFile getLocationContext() {
+ return fLocationCtx;
+ }
}
class ASTMacroExpansionLocation implements IASTMacroExpansion {
@@ -489,6 +493,10 @@ class ASTMacroExpansionLocation implements IASTMacroExpansion {
public IASTPreprocessorMacroDefinition getMacroDefinition() {
return fContext.getMacroDefinition();
}
+
+ public IASTName getMacroReference() {
+ return fContext.getMacroReference();
+ }
public IASTFileLocation asFileLocation() {
return ((LocationCtxContainer) fContext.getParent()).createFileLocation(fContext.fOffsetInParent, fContext.fEndOffsetInParent-fContext.fOffsetInParent);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
index f9a6baf3b69..74dc2ff4a4f 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
@@ -14,7 +14,9 @@ package org.eclipse.cdt.internal.core.parser.scanner;
import java.io.File;
import java.io.IOException;
+import java.text.DateFormatSymbols;
import java.util.Calendar;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -42,18 +44,19 @@ import org.eclipse.cdt.core.parser.OffsetLimitReachedException;
import org.eclipse.cdt.core.parser.ParseError;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.util.CharArrayIntMap;
-import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
+import org.eclipse.cdt.core.parser.util.CharArrayMap;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator.EvalException;
import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
import org.eclipse.cdt.internal.core.parser.scanner.MacroDefinitionParser.InvalidMacroDefinitionException;
+import org.eclipse.core.runtime.IAdaptable;
/**
* C-Preprocessor providing tokens for the parsers. The class should not be used directly, rather than that
* you should be using the {@link IScanner} interface.
* @since 5.0
*/
-public class CPreprocessor implements ILexerLog, IScanner {
+public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
public static final String PROP_VALUE = "CPreprocessor"; //$NON-NLS-1$
public static final int tDEFINED= IToken.FIRST_RESERVED_PREPROCESSOR;
@@ -62,7 +65,6 @@ public class CPreprocessor implements ILexerLog, IScanner {
public static final int tSPACE= IToken.FIRST_RESERVED_PREPROCESSOR+3;
public static final int tNOSPACE= IToken.FIRST_RESERVED_PREPROCESSOR+4;
public static final int tMACRO_PARAMETER= IToken.FIRST_RESERVED_PREPROCESSOR+5;
- public static final int tEMPTY_TOKEN = IToken.FIRST_RESERVED_PREPROCESSOR+6;
@@ -81,6 +83,7 @@ public class CPreprocessor implements ILexerLog, IScanner {
private static final ObjectStyleMacro __STDC_HOSTED__ = new ObjectStyleMacro("__STDC_HOSTED_".toCharArray(), ONE); //$NON-NLS-1$
private static final ObjectStyleMacro __STDC_VERSION__ = new ObjectStyleMacro("__STDC_VERSION_".toCharArray(), "199901L".toCharArray()); //$NON-NLS-1$ //$NON-NLS-2$
+
private interface IIncludeFileTester {
Object checkFile(String path, String fileName);
}
@@ -120,7 +123,8 @@ public class CPreprocessor implements ILexerLog, IScanner {
public Token execute() {
StringBuffer buffer = new StringBuffer("\""); //$NON-NLS-1$
Calendar cal = Calendar.getInstance();
- buffer.append(cal.get(Calendar.MONTH));
+ DateFormatSymbols dfs= new DateFormatSymbols();
+ buffer.append(dfs.getShortMonths()[cal.get(Calendar.MONTH)]);
buffer.append(" "); //$NON-NLS-1$
append(buffer, cal.get(Calendar.DAY_OF_MONTH));
buffer.append(" "); //$NON-NLS-1$
@@ -140,7 +144,7 @@ public class CPreprocessor implements ILexerLog, IScanner {
public Token execute() {
StringBuffer buffer = new StringBuffer("\""); //$NON-NLS-1$
Calendar cal = Calendar.getInstance();
- append(buffer, cal.get(Calendar.HOUR));
+ append(buffer, cal.get(Calendar.HOUR_OF_DAY));
buffer.append(":"); //$NON-NLS-1$
append(buffer, cal.get(Calendar.MINUTE));
buffer.append(":"); //$NON-NLS-1$
@@ -176,7 +180,7 @@ public class CPreprocessor implements ILexerLog, IScanner {
private boolean fHandledCompletion= false;
// state information
- private final CharArrayObjectMap fMacroDictionary = new CharArrayObjectMap(512);
+ private final CharArrayMap fMacroDictionary = new CharArrayMap(512);
private final LocationMap fLocationMap = new LocationMap();
/** Set of already included files */
@@ -345,9 +349,9 @@ public class CPreprocessor implements ILexerLog, IScanner {
}
}
- Object[] predefined= fMacroDictionary.valueArray();
- for (int i = 0; i < predefined.length; i++) {
- fLocationMap.registerPredefinedMacro((PreprocessorMacro) predefined[i]);
+ Collection predefined= fMacroDictionary.values();
+ for (PreprocessorMacro macro : predefined) {
+ fLocationMap.registerPredefinedMacro(macro);
}
}
@@ -413,13 +417,10 @@ public class CPreprocessor implements ILexerLog, IScanner {
}
public Map getMacroDefinitions() {
- final CharArrayObjectMap objMap= fMacroDictionary;
- int size = objMap.size();
- Map hashMap = new HashMap(size);
- for (int i = 0; i < size; i++) {
- hashMap.put(String.valueOf(objMap.keyAt(i)), (IMacroBinding) objMap.getAt(i));
- }
-
+ Map hashMap = new HashMap(fMacroDictionary.size());
+ for (char[] key : fMacroDictionary.keys()) {
+ hashMap.put(String.valueOf(key), fMacroDictionary.get(key));
+ }
return hashMap;
}
@@ -1165,7 +1166,7 @@ public class CPreprocessor implements ILexerLog, IScanner {
lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
final int endOffset= lexer.currentToken().getEndOffset();
final char[] namechars= name.getCharImage();
- PreprocessorMacro definition= (PreprocessorMacro) fMacroDictionary.remove(namechars, 0, namechars.length);
+ PreprocessorMacro definition= fMacroDictionary.remove(namechars, 0, namechars.length);
fLocationMap.encounterPoundUndef(definition, startOffset, name.getOffset(), name.getEndOffset(), endOffset, namechars);
}
@@ -1392,7 +1393,7 @@ public class CPreprocessor implements ILexerLog, IScanner {
*/
private boolean expandMacro(final Token identifier, Lexer lexer, boolean stopAtNewline) throws OffsetLimitReachedException {
final char[] name= identifier.getCharImage();
- PreprocessorMacro macro= (PreprocessorMacro) fMacroDictionary.get(name);
+ PreprocessorMacro macro= fMacroDictionary.get(name);
if (macro == null) {
return false;
}
@@ -1419,4 +1420,12 @@ public class CPreprocessor implements ILexerLog, IScanner {
fCurrentContext= new ScannerContext(ctx, fCurrentContext, replacement);
return true;
}
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if (adapter.isAssignableFrom(fMacroExpander.getClass())) {
+ return fMacroExpander;
+ }
+ return null;
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java
index 7a9063aeebc..0da348357f3 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ExpressionEvaluator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2007 IBM Corporation and others.
+ * Copyright (c) 2004, 2008 IBM Corporation 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
@@ -15,7 +15,7 @@ package org.eclipse.cdt.internal.core.parser.scanner;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.IToken;
-import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
+import org.eclipse.cdt.core.parser.util.CharArrayMap;
/**
* Used to evaluate expressions in preprocessor directives.
@@ -40,11 +40,11 @@ class ExpressionEvaluator {
}
private Token fTokens;
- private CharArrayObjectMap fDictionary;
+ private CharArrayMap fDictionary;
- public boolean evaluate(TokenList condition, CharArrayObjectMap dictionary) throws EvalException {
+ public boolean evaluate(TokenList condition, CharArrayMap macroDictionary) throws EvalException {
fTokens= condition.first();
- fDictionary= dictionary;
+ fDictionary= macroDictionary;
return expression() != 0;
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ILocationResolver.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ILocationResolver.java
index a335791b57a..13049444d49 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ILocationResolver.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ILocationResolver.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2007 IBM Corporation and others.
+ * Copyright (c) 2004, 2008 IBM Corporation 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
@@ -14,6 +14,7 @@ package org.eclipse.cdt.internal.core.parser.scanner;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation;
+import org.eclipse.cdt.core.dom.ast.IASTMacroExpansion;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
@@ -103,9 +104,12 @@ public interface ILocationResolver {
*/
IASTFileLocation getMappedFileLocation(int offset, int length);
- /**
- * @see IASTTranslationUnit#getLocationInfo(int, int).
- */
+ /**
+ * Returns an array of locations. This is a sequence of file locations and macro-expansion locations.
+ * @param offset sequence number as stored in the ast nodes.
+ * @param length
+ * @return and array of locations.
+ */
IASTNodeLocation[] getLocations(int sequenceNumber, int length);
/**
@@ -122,7 +126,7 @@ public interface ILocationResolver {
int getSequenceNumberForFileOffset(String filePath, int fileOffset);
/**
- * @see IASTTranslationUnit#getUnpreprocessedSignature(IASTFileLocation).
+ * @see IASTNode#getRawSignature().
*/
char[] getUnpreprocessedSignature(IASTFileLocation loc);
@@ -144,4 +148,21 @@ public interface ILocationResolver {
* Same as {@link #getMappedFileLocation(int, int)} for the given array of consecutive node locations.
*/
IASTFileLocation flattenLocations(IASTNodeLocation[] nodeLocations);
+
+ /**
+ * Returns all explicit macro expansions that intersect with the given file location.
+ * Include files that may be included within the given location are not examined.
+ * @param loc the file-location to search for macro references
+ * @return an array of macro expansions.
+ * @since 5.0
+ */
+ IASTMacroExpansion[] getMacroExpansions(IASTFileLocation loc);
+
+ /**
+ * Returns all implicit macro references related to an explicit one.
+ * @param ref an explicit macro expansion.
+ * @return an array of names representing implicit macro expansions.
+ * @since 5.0
+ */
+ IASTName[] getImplicitMacroReferences(IASTName ref);
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtx.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtx.java
index df3e204c95a..97ec22d0369 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtx.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtx.java
@@ -14,7 +14,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree.IASTInclusionNode;
@@ -103,14 +102,14 @@ abstract class LocationCtx implements ILocationCtx {
* Returns the minimal file location containing the specified sequence number range, assuming
* that it is contained in this context.
*/
- public IASTFileLocation findMappedFileLocation(int sequenceNumber, int length) {
+ public ASTFileLocation findMappedFileLocation(int sequenceNumber, int length) {
return fParent.createMappedFileLocation(fOffsetInParent, fEndOffsetInParent-fOffsetInParent);
}
/**
* Returns the file location containing the specified offset range in this context.
*/
- public IASTFileLocation createMappedFileLocation(int offset, int length) {
+ public ASTFileLocation createMappedFileLocation(int offset, int length) {
return fParent.createMappedFileLocation(fOffsetInParent, fEndOffsetInParent-fOffsetInParent);
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxContainer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxContainer.java
index 32c4af4daa9..d67bb91168b 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxContainer.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxContainer.java
@@ -40,6 +40,7 @@ class LocationCtxContainer extends LocationCtx {
fSource= source;
}
+ @Override
public Collection getChildren() {
if (fChildren == null) {
return Collections.emptyList();
@@ -84,10 +85,12 @@ class LocationCtxContainer extends LocationCtx {
return result;
}
+ @Override
public void addChildSequenceLength(int childLength) {
fChildSequenceLength+= childLength;
}
+ @Override
public final LocationCtx findSurroundingContext(int sequenceNumber, int length) {
int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber;
final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, false);
@@ -97,6 +100,7 @@ class LocationCtxContainer extends LocationCtx {
return this;
}
+ @Override
public final LocationCtxMacroExpansion findSurroundingMacroExpansion(int sequenceNumber, int length) {
int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber;
final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, true);
@@ -106,7 +110,8 @@ class LocationCtxContainer extends LocationCtx {
return null;
}
- public IASTFileLocation findMappedFileLocation(int sequenceNumber, int length) {
+ @Override
+ public ASTFileLocation findMappedFileLocation(int sequenceNumber, int length) {
// try to delegate to a child.
int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber;
final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, false);
@@ -198,6 +203,7 @@ class LocationCtxContainer extends LocationCtx {
return idx >= 0 ? fChildren.get(idx) : null;
}
+ @Override
public void getInclusions(ArrayList result) {
if (fChildren != null) {
for (Iterator iterator = fChildren.iterator(); iterator.hasNext();) {
@@ -212,6 +218,7 @@ class LocationCtxContainer extends LocationCtx {
}
}
+ @Override
public int getLineNumber(int offset) {
if (fLineOffsets == null) {
fLineOffsets= computeLineOffsets();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java
index 2ea099d04a4..0963ddadde0 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java
@@ -10,7 +10,10 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
-import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.cdt.core.dom.ast.IASTMacroExpansion;
/**
* A location context representing a file.
@@ -26,15 +29,18 @@ class LocationCtxFile extends LocationCtxContainer {
fASTInclude= inclusionStatement;
}
+ @Override
public final void addChildSequenceLength(int childLength) {
super.addChildSequenceLength(childLength);
}
+ @Override
public final String getFilePath() {
return fFilename;
}
- public IASTFileLocation findMappedFileLocation(int sequenceNumber, int length) {
+ @Override
+ public ASTFileLocation findMappedFileLocation(int sequenceNumber, int length) {
// try to delegate to a child.
final int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber;
final int sequenceEnd= sequenceNumber+length;
@@ -76,14 +82,17 @@ class LocationCtxFile extends LocationCtxContainer {
return new ASTFileLocation(this, startOffset, endOffset-startOffset);
}
- public IASTFileLocation createMappedFileLocation(int offset, int length) {
+ @Override
+ public ASTFileLocation createMappedFileLocation(int offset, int length) {
return new ASTFileLocation(this, offset, length);
}
+ @Override
public ASTInclusionStatement getInclusionStatement() {
return fASTInclude;
}
+ @Override
ASTFileLocation createFileLocation(int start, int length) {
return new ASTFileLocation(this, start, length);
}
@@ -95,4 +104,20 @@ class LocationCtxFile extends LocationCtxContainer {
}
return sequenceNumber >= child.fSequenceNumber + child.getSequenceLength();
}
+
+ public void collectExplicitMacroExpansions(int offset, int length, ArrayList result) {
+ Collection children= getChildren();
+ for (LocationCtx ctx : children) {
+ // context must start before the end of the search range
+ if (ctx.fOffsetInParent >= offset+length) {
+ break;
+ }
+ if (ctx instanceof LocationCtxMacroExpansion) {
+ // expansion must end after the search start
+ if (ctx.fEndOffsetInParent > offset) {
+ result.add(new ASTMacroExpansionLocation(((LocationCtxMacroExpansion) ctx), 0, ctx.getSequenceLength()));
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java
index 81fbce6a917..6e6b307f647 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java
@@ -19,6 +19,7 @@ import java.util.List;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation;
+import org.eclipse.cdt.core.dom.ast.IASTMacroExpansion;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
@@ -48,7 +49,7 @@ public class LocationMap implements ILocationResolver {
private ArrayList fProblems= new ArrayList();
private ArrayList fComments= new ArrayList();
private ArrayList fBuiltinMacros= new ArrayList();
- private IdentityHashMap> fMacroReferences= new IdentityHashMap>();
+ private ArrayList fMacroReferences= new ArrayList();
private LocationCtxFile fRootContext= null;
private LocationCtx fCurrentContext= null;
@@ -157,27 +158,22 @@ public class LocationMap implements ILocationResolver {
int endNumber= getSequenceNumberForOffset(endOffset);
final int length= endNumber-nameNumber;
+ ASTMacroReferenceName expansion= new ASTMacroReferenceName(fTranslationUnit, nameNumber, nameEndNumber, macro, null);
for (int i = 0; i < implicitMacroReferences.length; i++) {
ASTMacroReferenceName name = (ASTMacroReferenceName) implicitMacroReferences[i];
name.setOffsetAndLength(nameNumber, length);
- addMacroReference((IMacroBinding) name.getBinding(), name);
+ name.setParent(expansion);
+ addMacroReference(name);
}
-
- ASTMacroReferenceName expansion= new ASTMacroReferenceName(fTranslationUnit, nameNumber, nameEndNumber, macro, null);
- addMacroReference(macro, expansion);
+ addMacroReference(expansion);
fCurrentContext= new LocationCtxMacroExpansion(this, (LocationCtxContainer) fCurrentContext, nameOffset, endOffset, endNumber, contextLength, imageLocations, expansion);
fLastChildInsertionOffset= 0;
return fCurrentContext;
}
- private void addMacroReference(IMacroBinding macro, IASTName name) {
- List list= fMacroReferences.get(macro);
- if (list == null) {
- list= new ArrayList();
- fMacroReferences.put(macro, list);
- }
- list.add(name);
+ private void addMacroReference(IASTName name) {
+ fMacroReferences.add(name);
}
/**
@@ -310,7 +306,7 @@ public class LocationMap implements ILocationResolver {
// not using endOffset, compatible with 4.0: endOffset= getSequenceNumberForOffset(endOffset);
final ASTUndef undef = new ASTUndef(fTranslationUnit, name, startOffset, nameOffset, nameEndOffset, definition);
fDirectives.add(undef);
- addMacroReference(definition, undef.getMacroName());
+ addMacroReference(undef.getMacroName());
}
public void setRootNode(IASTTranslationUnit root) {
@@ -351,15 +347,54 @@ public class LocationMap implements ILocationResolver {
return new String(ctx.getFilePath());
}
- public IASTFileLocation getMappedFileLocation(int sequenceNumber, int length) {
+ public ASTFileLocation getMappedFileLocation(int sequenceNumber, int length) {
return fRootContext.findMappedFileLocation(sequenceNumber, length);
}
public char[] getUnpreprocessedSignature(IASTFileLocation loc) {
- if (loc instanceof ASTFileLocation) {
- return ((ASTFileLocation) loc).getSource();
- }
- return CharArrayUtils.EMPTY;
+ ASTFileLocation floc= convertFileLocation(loc);
+ if (floc == null) {
+ return CharArrayUtils.EMPTY;
+ }
+ return floc.getSource();
+ }
+
+ public IASTMacroExpansion[] getMacroExpansions(IASTFileLocation loc) {
+ ASTFileLocation floc= convertFileLocation(loc);
+ if (floc == null) {
+ return new IASTMacroExpansion[0];
+ }
+
+ LocationCtxFile ctx= floc.getLocationContext();
+ ArrayList list= new ArrayList();
+
+ ctx.collectExplicitMacroExpansions(floc.getNodeOffset(), floc.getNodeLength(), list);
+ return list.toArray(new IASTMacroExpansion[list.size()]);
+ }
+
+ private ASTFileLocation convertFileLocation(IASTFileLocation loc) {
+ if (loc == null) {
+ return null;
+ }
+ if (loc instanceof ASTFileLocation) {
+ return (ASTFileLocation) loc;
+ }
+ final String fileName = loc.getFileName();
+ final int nodeOffset = loc.getNodeOffset();
+ final int nodeLength = loc.getNodeLength();
+ int sequenceNumber= getSequenceNumberForFileOffset(fileName, nodeOffset);
+ if (sequenceNumber < 0) {
+ return null;
+ }
+
+ int length= 0;
+ if (nodeLength > 0) {
+ length= getSequenceNumberForFileOffset(fileName, nodeOffset + nodeLength-1)+1 - sequenceNumber;
+ if (length < 0) {
+ return null;
+ }
+ }
+ return getMappedFileLocation(sequenceNumber, length);
}
public IASTNodeLocation[] getLocations(int sequenceNumber, int length) {
@@ -538,13 +573,25 @@ public class LocationMap implements ILocationResolver {
}
public IASTName[] getReferences(IMacroBinding binding) {
- List list= fMacroReferences.get(binding);
- if (list == null) {
- return EMPTY_NAMES;
+ List result= new ArrayList();
+ for (IASTName name : fMacroReferences) {
+ if (name.getBinding() == binding) {
+ result.add(name);
+ }
}
- return list.toArray(new IASTName[list.size()]);
+ return result.toArray(new IASTName[result.size()]);
}
+ public IASTName[] getImplicitMacroReferences(IASTName ref) {
+ List result= new ArrayList();
+ for (IASTName name : fMacroReferences) {
+ if (name.getParent() == ref) {
+ result.add(name);
+ }
+ }
+ return result.toArray(new IASTName[result.size()]);
+ }
+
public IDependencyTree getDependencyTree() {
return new DependencyTree(fRootContext);
}
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 6aef6aded7a..99b9b3af247 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,13 +11,14 @@
package org.eclipse.cdt.internal.core.parser.scanner;
import java.util.ArrayList;
+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.OffsetLimitReachedException;
-import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
+import org.eclipse.cdt.core.parser.util.CharArrayMap;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.parser.scanner.ImageLocationInfo.MacroImageLocationInfo;
import org.eclipse.cdt.internal.core.parser.scanner.ImageLocationInfo.ParameterImageLocationInfo;
@@ -31,7 +32,8 @@ import org.eclipse.cdt.internal.core.parser.scanner.MacroDefinitionParser.TokenP
public class MacroExpander {
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();
+
/**
* Marks the beginning and the end of the scope of a macro expansion. Necessary to properly
* handle recursive expansions and to figure out whether spaces are required during a stringify
@@ -125,7 +127,7 @@ public class MacroExpander {
private final ILexerLog fLog;
private final MacroDefinitionParser fDefinitionParser;
- private final CharArrayObjectMap fDictionary;
+ private final CharArrayMap fDictionary;
private final LocationMap fLocationMap;
private final LexerOptions fLexOptions;
private ArrayList fImplicitMacroExpansions= new ArrayList();
@@ -133,9 +135,9 @@ public class MacroExpander {
private boolean fCompletionMode;
private int fStartOffset;
private int fEndOffset;
-
- public MacroExpander(ILexerLog log, CharArrayObjectMap dict, LocationMap locationMap, LexerOptions lexOptions) {
- fDictionary= dict;
+
+ public MacroExpander(ILexerLog log, CharArrayMap macroDictionary, LocationMap locationMap, LexerOptions lexOptions) {
+ fDictionary= macroDictionary;
fLocationMap= locationMap;
fDefinitionParser= new MacroDefinitionParser();
fLexOptions= lexOptions;
@@ -158,45 +160,144 @@ public class MacroExpander {
// setup input sequence
TokenSource input= new TokenSource(lexer, stopAtNewline);
TokenList firstExpansion= new TokenList();
- expandOne(identifier, macro, forbidden, input, firstExpansion);
+ expandOne(identifier, macro, forbidden, input, firstExpansion, null);
input.prepend(firstExpansion);
- TokenList result= expandAll(input, forbidden);
+ TokenList result= expandAll(input, forbidden, null);
postProcessTokens(result);
return result;
}
+ /**
+ * Method for tracking macro expansions.
+ * @since 5.0
+ */
+ public void expand(String beforeExpansion, MacroExpansionTracker tracker) {
+ Lexer lexer= new Lexer(beforeExpansion.toCharArray(), fLexOptions, fLog, this);
+ fImplicitMacroExpansions.clear();
+ fImageLocationInfos.clear();
+
+ try {
+ tracker.start(lexer);
+ Token identifier= lexer.nextToken();
+ if (identifier.getType() != IToken.tIDENTIFIER) {
+ tracker.fail();
+ return;
+ }
+ PreprocessorMacro macro= fDictionary.get(identifier.getCharImage());
+ if (macro == null) {
+ tracker.fail();
+ return;
+ }
+ lexer.nextToken();
+
+ fStartOffset= identifier.getOffset();
+ fEndOffset= identifier.getEndOffset();
+ fCompletionMode= false;
+ IdentityHashMap forbidden= new IdentityHashMap();
+
+ // setup input sequence
+ TokenSource input= new TokenSource(lexer, false);
+ TokenList firstExpansion= new TokenList();
+ expandOne(identifier, macro, forbidden, input, firstExpansion, tracker);
+ input.prepend(firstExpansion);
+
+ TokenList result= expandAll(input, forbidden, tracker);
+ tracker.finish(result, fEndOffset);
+ } catch (OffsetLimitReachedException e) {
+ }
+ }
+
/**
* Expects that the identifier of the macro expansion has been consumed. Expands the macro consuming
* 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.
*/
- private Token expandOne(Token lastConsumed, PreprocessorMacro macro, IdentityHashMap forbidden, TokenSource input, TokenList result)
+ private Token expandOne(Token lastConsumed, PreprocessorMacro macro,
+ IdentityHashMap forbidden, TokenSource input, TokenList result,
+ MacroExpansionTracker tracker)
throws OffsetLimitReachedException {
result.append(new ExpansionBoundary(macro, true));
if (macro.isFunctionStyle()) {
- final TokenSource[] argInputs= new TokenSource[macro.getParameterPlaceholderList().length];
- lastConsumed= parseArguments(input, (FunctionStyleMacro) macro, forbidden, argInputs);
- TokenList[] clonedArgs= new TokenList[argInputs.length];
- TokenList[] expandedArgs= new TokenList[argInputs.length];
- for (int i = 0; i < argInputs.length; i++) {
- final TokenSource argInput = argInputs[i];
- clonedArgs[i]= argInput.cloneTokens();
- final TokenList expandedArg= expandAll(argInput, forbidden);
- expandedArgs[i]= expandedArg;
+ final int paramCount = macro.getParameterPlaceholderList().length;
+ final TokenSource[] argInputs= new TokenSource[paramCount];
+ final BitSet paramUsage= getParamUsage(macro);
+ if (tracker != null) {
+ tracker.startFunctionStyleMacro((Token) lastConsumed.clone());
+ }
+ lastConsumed= parseArguments(input, (FunctionStyleMacro) macro, forbidden, argInputs, tracker);
+ TokenList[] clonedArgs= new TokenList[paramCount];
+ TokenList[] expandedArgs= new TokenList[paramCount];
+ for (int i = 0; i < paramCount; i++) {
+ final TokenSource argInput = argInputs[i];
+ 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;
+ if (!needExpansion) {
+ executeScopeMarkers(argInput, forbidden);
+ }
+
+ if (tracker != null) {
+ tracker.setExpandedMacroArgument(needExpansion ? expandedArgs[i] : null);
+ // make sure that the trailing arguments do not get expanded.
+ if (tracker.isDone()) {
+ paramUsage.clear();
+ }
+ }
+ }
+ if (tracker == null) {
+ replaceArgs(macro, clonedArgs, expandedArgs, result);
+ }
+ else {
+ if (tracker.isRequestedStep()) {
+ TokenList replacement= new TokenList();
+ replaceArgs(macro, clonedArgs, expandedArgs, replacement);
+ tracker.storeFunctionStyleMacroReplacement(macro, replacement, result);
+ }
+ else if (tracker.isDone()) {
+ tracker.appendFunctionStyleMacro(result);
+ }
+ else {
+ replaceArgs(macro, clonedArgs, expandedArgs, result);
+ }
+ tracker.endFunctionStyleMacro();
}
- replaceArgs(macro, clonedArgs, expandedArgs, result);
}
else {
- objStyleTokenPaste(macro, result);
+ if (tracker == null) {
+ objStyleTokenPaste(macro, result);
+ }
+ else {
+ if (tracker.isRequestedStep()) {
+ TokenList replacement= new TokenList();
+ objStyleTokenPaste(macro, replacement);
+ tracker.storeObjectStyleMacroReplacement(macro, lastConsumed, replacement, result);
+ }
+ else {
+ objStyleTokenPaste(macro, result);
+ }
+ tracker.endObjectStyleMacro();
+ }
}
result.append(new ExpansionBoundary(macro, false));
return lastConsumed;
}
- private TokenList expandAll(TokenSource input, IdentityHashMap forbidden) throws OffsetLimitReachedException {
+ private void executeScopeMarkers(TokenSource input, IdentityHashMap forbidden) {
+ Token t= input.removeFirst();
+ while(t != null) {
+ if (t.getType() == CPreprocessor.tSCOPE_MARKER) {
+ ((ExpansionBoundary) t).execute(forbidden);
+ }
+ t= input.removeFirst();
+ }
+ }
+
+ private TokenList expandAll(TokenSource input, IdentityHashMap forbidden,
+ MacroExpansionTracker tracker) throws OffsetLimitReachedException {
final TokenList result= new TokenList();
Token l= null;
Token t= input.removeFirst();
@@ -207,9 +308,12 @@ public class MacroExpander {
t= input.removeFirst(); // don't change l
continue;
case IToken.tIDENTIFIER:
- PreprocessorMacro macro= (PreprocessorMacro) fDictionary.get(t.getCharImage());
+ PreprocessorMacro macro= fDictionary.get(t.getCharImage());
+ if (tracker != null && tracker.isDone()) {
+ result.append(t);
+ }
// tricky: don't mark function-style macros if you don't find the left parenthesis
- if (macro == null || (macro.isFunctionStyle() && !input.findLParenthesis())) {
+ else if (macro == null || (macro.isFunctionStyle() && !input.findLParenthesis())) {
result.append(t);
}
else if (forbidden.containsKey(macro)) {
@@ -227,7 +331,7 @@ public class MacroExpander {
TokenList replacement= new TokenList();
addSpacemarker(l, t, replacement); // start expansion
- Token last= expandOne(t, macro, forbidden, input, replacement);
+ Token last= expandOne(t, macro, forbidden, input, replacement, tracker);
addSpacemarker(last, input.first(), replacement); // end expansion
input.prepend(replacement);
@@ -262,12 +366,12 @@ public class MacroExpander {
if (l != null && t != null) {
final Object s1= l.fSource;
final Object s2= t.fSource;
- if (s1 == s2 && s1 != null) {
+ if (s1 == s2 && s1 != null && l.getType() != CPreprocessor.tSPACE) {
if (l.getEndOffset() == t.getOffset()) {
target.append(new Token(CPreprocessor.tNOSPACE, null, 0, 0));
}
else {
- target.append(new Token(CPreprocessor.tSPACE, null, 0, 0));
+ target.append(new Token(CPreprocessor.tSPACE, s1, l.getEndOffset(), t.getOffset()));
}
}
}
@@ -276,9 +380,11 @@ public class MacroExpander {
/**
* Expects that the identifier has been consumed.
* @param forbidden
+ * @param tracker
* @throws OffsetLimitReachedException
*/
- private Token parseArguments(TokenSource input, FunctionStyleMacro macro, IdentityHashMap forbidden, TokenSource[] result) throws OffsetLimitReachedException {
+ private Token parseArguments(TokenSource input, FunctionStyleMacro macro, IdentityHashMap forbidden, TokenSource[] result,
+ MacroExpansionTracker tracker) throws OffsetLimitReachedException {
final int argCount= macro.getParameterPlaceholderList().length;
final boolean hasVarargs= macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS;
final int requiredArgs= hasVarargs ? argCount-1 : argCount;
@@ -296,6 +402,17 @@ public class MacroExpander {
Token t= input.fetchFirst();
if (t == null) {
break loop;
+ }
+ if (tracker != null) {
+ switch(t.getType()) {
+ case IToken.tEND_OF_INPUT:
+ case IToken.tCOMPLETION:
+ case CPreprocessor.tSCOPE_MARKER:
+ break;
+ default:
+ tracker.addFunctionStyleMacroExpansionToken((Token) t.clone());
+ break;
+ }
}
lastToken= t;
switch(t.getType()) {
@@ -414,7 +531,7 @@ public class MacroExpander {
case IToken.tPOUND:
addSpacemarker(l, t, result); // start stringify
- StringBuffer buf= new StringBuffer();
+ StringBuilder buf= new StringBuilder();
buf.append('"');
if (n != null && n.getType() == CPreprocessor.tMACRO_PARAMETER) {
idx= ((TokenParameterReference) n).getIndex();
@@ -441,65 +558,65 @@ public class MacroExpander {
break;
case IToken.tPOUNDPOUND:
- if (pasteArg1 != null) {
- Token pasteArg2= null;
- TokenList rest= null;
- if (n != null) {
- if (n.getType() == CPreprocessor.tMACRO_PARAMETER) {
- idx= ((TokenParameterReference) n).getIndex();
- if (idx < args.length) { // be defensive
- TokenList arg= clone(args[idx]);
- pasteArg2= arg.first();
-
- // gcc-extension
- if (idx == args.length-1 && macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS) {
- if (pasteArg1.getType() == IToken.tCOMMA) { // no paste operation
- if (arg.first() != null) {
- result.append(pasteArg1);
- rest= arg;
- }
- pasteArg1= pasteArg2= null;
- }
+ Token pasteArg2= null;
+ TokenList rest= null;
+ if (n != null) {
+ if (n.getType() == CPreprocessor.tMACRO_PARAMETER) {
+ TokenList arg;
+ idx= ((TokenParameterReference) n).getIndex();
+ if (idx < args.length) { // be defensive
+ // gcc-extension
+ if (idx == args.length-1 && macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS &&
+ pasteArg1 != null && pasteArg1.getType() == IToken.tCOMMA) { // no paste operation
+ arg= clone(expandedArgs[idx]);
+ if (arg.first() != null) {
+ result.append(pasteArg1);
+ rest= arg;
}
+ pasteArg1= pasteArg2= null;
+ }
+ else {
+ arg= clone(args[idx]);
+ pasteArg2= arg.first();
if (pasteArg2 != null && arg.first() != arg.last()) {
rest= arg;
rest.removeFirst();
}
}
}
- else {
- idx= -1;
- pasteArg2= n;
- }
- t= n;
- n= (Token) n.getNext();
- pasteNext= n != null && n.getType() == IToken.tPOUNDPOUND;
-
- generated= tokenpaste(pasteArg1, pasteArg2, macro);
- pasteArg1= null;
+ }
+ else {
+ idx= -1;
+ pasteArg2= n;
+ }
+ t= n;
+ n= (Token) n.getNext();
+ pasteNext= n != null && n.getType() == IToken.tPOUNDPOUND;
- if (generated != null) {
- if (pasteNext && rest == null) {
- pasteArg1= generated; // no need to mark spaces, done ahead
- }
- else {
- result.append(generated);
- addSpacemarker(pasteArg2, rest == null ? n : rest.first(), result); // end token paste
+ generated= tokenpaste(pasteArg1, pasteArg2, macro);
+ pasteArg1= null;
+
+ if (generated != null) {
+ if (pasteNext && rest == null) {
+ pasteArg1= generated; // no need to mark spaces, done ahead
+ }
+ else {
+ result.append(generated);
+ addSpacemarker(pasteArg2, rest == null ? n : rest.first(), result); // end token paste
+ }
+ }
+ if (rest != null) {
+ if (pasteNext) {
+ pasteArg1= rest.last();
+ if (pasteArg1 != null) {
+ result.appendAllButLast(rest);
+ addSpacemarker(result.last(), pasteArg1, result); // start token paste
}
}
- if (rest != null) {
- if (pasteNext) {
- pasteArg1= rest.last();
- if (pasteArg1 != null) {
- result.appendAllButLast(rest);
- addSpacemarker(result.last(), pasteArg1, result); // start token paste
- }
- }
- else {
- result.appendAll(rest);
- if (idx >= 0) {
- addSpacemarker(t, n, result); // end argument replacement
- }
+ else {
+ result.appendAll(rest);
+ if (idx >= 0) {
+ addSpacemarker(t, n, result); // end argument replacement
}
}
}
@@ -519,6 +636,53 @@ public class MacroExpander {
}
}
+ private BitSet getParamUsage(PreprocessorMacro macro) {
+ final BitSet result= new BitSet();
+ final TokenList replacement= macro.getTokens(fDefinitionParser, fLexOptions);
+
+ Token l= null;
+ Token n;
+ for (Token t= replacement.first(); t != null; l=t, t=n) {
+ n= (Token) t.getNext();
+ switch(t.getType()) {
+ case CPreprocessor.tMACRO_PARAMETER:
+ int idx= 2*((TokenParameterReference) t).getIndex();
+ if (n == null || n.getType() != IToken.tPOUNDPOUND) {
+ idx++;
+ }
+ result.set(idx);
+ break;
+
+ case IToken.tPOUND:
+ if (n != null && n.getType() == CPreprocessor.tMACRO_PARAMETER) {
+ idx= ((TokenParameterReference) n).getIndex();
+ result.set(2*idx);
+ t= n; n= (Token) n.getNext();
+ }
+ break;
+
+ case IToken.tPOUNDPOUND:
+ if (n != null) {
+ if (n.getType() == CPreprocessor.tMACRO_PARAMETER) {
+ idx= ((TokenParameterReference) n).getIndex();
+
+ // gcc-extension
+ if (l != null && l.getType() == IToken.tCOMMA && macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS
+ && idx == macro.getParameterPlaceholderList().length-1) {
+ result.set(2*idx+1);
+ }
+ else {
+ result.set(2*idx);
+ }
+ }
+ t= n; n= (Token) n.getNext();
+ }
+ break;
+ }
+ }
+ return result;
+ }
+
private void objStyleTokenPaste(PreprocessorMacro macro, TokenList result) {
TokenList replacement= clone(macro.getTokens(fDefinitionParser, fLexOptions));
@@ -574,6 +738,9 @@ public class MacroExpander {
}
private Token tokenpaste(Token arg1, Token arg2, PreprocessorMacro macro) {
+ if (arg1 == null) {
+ return arg2;
+ }
if (arg2 == null) {
return arg1;
}
@@ -598,7 +765,7 @@ public class MacroExpander {
return null;
}
- private void stringify(TokenList tokenList, StringBuffer buf) {
+ private void stringify(TokenList tokenList, StringBuilder buf) {
Token t= tokenList.first();
if (t == null) {
return;
@@ -608,8 +775,7 @@ public class MacroExpander {
boolean space= false;
for (; t != null; l=t, t=n) {
n= (Token) t.getNext();
- if (!space && l != null && l.fSource != null && l.fSource == t.fSource &&
- l.getEndOffset() != t.getOffset()) {
+ if (!space && hasImplicitSpace(l, t)) {
buf.append(' ');
space= true;
}
@@ -695,4 +861,10 @@ public class MacroExpander {
l= t;
}
}
+
+ static boolean hasImplicitSpace(Token l, Token t) {
+ return l != null &&
+ l.fSource != null && l.fSource == t.fSource &&
+ l.getEndOffset() != t.getOffset() && t.getType() != CPreprocessor.tSPACE;
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpansionStep.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpansionStep.java
new file mode 100644
index 00000000000..9796d2e10be
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpansionStep.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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.dom.ast.IMacroBinding;
+import org.eclipse.cdt.core.dom.rewrite.MacroExpansionExplorer.IMacroExpansionStep;
+import org.eclipse.text.edits.ReplaceEdit;
+
+/**
+ * Implementation for {@link IMacroExpansionStep}.
+ */
+public class MacroExpansionStep implements IMacroExpansionStep {
+ private final String fBefore;
+ private final IMacroBinding fMacroDefinition;
+ private final ReplaceEdit[] fReplacements;
+
+ public MacroExpansionStep(String before, IMacroBinding def, ReplaceEdit[] replacements) {
+ fBefore= before;
+ fReplacements= replacements;
+ fMacroDefinition= def;
+ }
+
+ public String getCodeBeforeStep() {
+ return fBefore;
+ }
+
+ public String getCodeAfterStep() {
+ StringBuilder result= new StringBuilder();
+ int offset= 0;
+ for (int i = 0; i < fReplacements.length; i++) {
+ ReplaceEdit r= fReplacements[i];
+ result.append(fBefore, offset, r.getOffset());
+ result.append(r.getText());
+ offset= r.getExclusiveEnd();
+ }
+ result.append(fBefore, offset, fBefore.length());
+ return result.toString();
+ }
+
+ public IMacroBinding getExpandedMacro() {
+ return fMacroDefinition;
+ }
+ public ReplaceEdit[] getReplacements() {
+ return fReplacements;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpansionTracker.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpansionTracker.java
new file mode 100644
index 00000000000..7eeeb2434d2
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MacroExpansionTracker.java
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 java.util.ArrayList;
+import java.util.LinkedList;
+
+import org.eclipse.cdt.core.dom.ast.IMacroBinding;
+import org.eclipse.cdt.core.parser.IToken;
+import org.eclipse.text.edits.ReplaceEdit;
+
+/**
+ * Collects information while macro expansion is performed.
+ */
+public class MacroExpansionTracker {
+ public class MacroInfo {
+ private TokenList fMacroCall= new TokenList();
+ private ArrayList fArguments= new ArrayList();
+
+ public MacroInfo(Token identifier) {
+ fMacroCall.append(identifier);
+ }
+
+ public void setArgument(TokenList tokenList) {
+ fArguments.add(tokenList);
+ }
+ }
+
+ private final int fStepToTrack;
+
+ private int fStepCount;
+ private String fPreStep;
+ private ReplaceEdit fReplacement;
+ private IMacroBinding fMacroDefinition;
+
+ private Lexer fLexer;
+ private String fReplacementText= ""; //$NON-NLS-1$
+ private LinkedList fMacroStack= new LinkedList();
+
+ private IToken fReplaceFrom;
+ private IToken fReplaceTo;
+
+ public MacroExpansionTracker(int stepToTrack) {
+ fStepToTrack= stepToTrack;
+ }
+
+ /**
+ * Returns whether the requested step has already been encountered.
+ */
+ public boolean isDone() {
+ return fStepCount > fStepToTrack;
+ }
+
+ /**
+ * Returns whether we are currently looking at the requested step.
+ */
+ public boolean isRequestedStep() {
+ return fStepCount == fStepToTrack;
+ }
+
+ /**
+ * Returns the total amount of steps encountered so far.
+ */
+ public int getStepCount() {
+ return fStepCount;
+ }
+
+ /**
+ * Returns the code as it looks like just before performing the step that was tracked.
+ */
+ public String getCodeBeforeStep() {
+ return fPreStep;
+ }
+
+ /**
+ * Returns the replacement that represents the change by the step that was tracked.
+ */
+ public ReplaceEdit getReplacement() {
+ return fReplacement;
+ }
+
+ /**
+ * Returns the macro that is expanded in the step that was tracked.
+ */
+ public IMacroBinding getExpandedMacro() {
+ return fMacroDefinition;
+ }
+
+ /**
+ * Informs the tracker that macro expansion is started.
+ */
+ void start(Lexer lexer) {
+ fLexer= lexer;
+ }
+
+ /**
+ * Informs the tracker that the expansion is done.
+ * @param result the list of tokens after performing partial expansion up to the step that was
+ * tracked.
+ * @param endOffset the end offset of the input that was read from the lexer.
+ */
+ void finish(TokenList result, int endOffset) {
+ final char[] lexInput = fLexer.getInput();
+ if (!isDone()) {
+ // special case we compute the entire expansion as one step, the result contains the
+ // expanded text
+ StringBuilder replacementText= new StringBuilder();
+ toString(result, lexInput, replacementText, replacementText, replacementText);
+ fPreStep= new String(lexInput);
+ fReplacement= new ReplaceEdit(0, endOffset, replacementText.toString());
+ }
+ else {
+ // the regular case the result contains the text before the step
+ StringBuilder before= new StringBuilder();
+ StringBuilder replace= new StringBuilder();
+ StringBuilder after= new StringBuilder();
+ toString(result, lexInput, before, replace, after);
+ int offset= before.length();
+ before.append(replace).append(after);
+ before.append(lexInput, endOffset, lexInput.length-endOffset);
+ fPreStep= before.toString();
+ fReplacement= new ReplaceEdit(offset, replace.length(), fReplacementText);
+ }
+ }
+
+ /**
+ * There was no macro at the beginning of the input.
+ */
+ void fail() {
+ fPreStep= new String(fLexer.getInput());
+ fReplacement= new ReplaceEdit(0, 0, ""); //$NON-NLS-1$
+ }
+
+ private void toString(TokenList tokenList, char[] rootInput, StringBuilder before, StringBuilder replace, StringBuilder after) {
+ StringBuilder buf= before;
+ Token t= tokenList.first();
+ if (t == null) {
+ return ;
+ }
+ Token l= null;
+ Token n;
+ for (; t != null; l=t, t=n) {
+ n= (Token) t.getNext();
+ if (MacroExpander.hasImplicitSpace(l, t)) {
+ char[] input= getInputForSource(l.fSource, rootInput);
+ if (input == null) {
+ buf.append(' ');
+ }
+ else {
+ final int from = l.getEndOffset();
+ final int to = t.getOffset();
+ buf.append(input, from, to-from);
+ }
+ }
+ if (t == fReplaceFrom) {
+ buf= replace;
+ }
+ char[] input= getInputForSource(t.fSource, rootInput);
+ if (input == null) {
+ buf.append(t.getCharImage());
+ }
+ else {
+ buf.append(input, t.getOffset(), t.getLength());
+ }
+ if (t == fReplaceTo) {
+ buf= after;
+ }
+ }
+ }
+
+ private char[] getInputForSource(Object source, char[] rootInput) {
+ if (source instanceof MacroExpander) {
+ return rootInput;
+ }
+ if (source instanceof PreprocessorMacro) {
+ return ((PreprocessorMacro) source).getExpansionImage();
+ }
+ return null;
+ }
+
+ /**
+ * Informs the tracker that a function-style expansion is started.
+ * @param identifier the identifier token for the macro expansion.
+ */
+ public void startFunctionStyleMacro(Token identifier) {
+ fMacroStack.add(new MacroInfo(identifier));
+ }
+
+ /**
+ * All tokens defining a function-style macro expansion are reported.
+ */
+ public void addFunctionStyleMacroExpansionToken(Token t) {
+ fMacroStack.getLast().fMacroCall.append(t);
+ }
+
+ /**
+ * The expanded arguments for the function-style macro expansion are reported.
+ * @param tokenList the expanded argument, or null
if it should not
+ * be expanded.
+ */
+ public void setExpandedMacroArgument(TokenList tokenList) {
+ fMacroStack.getLast().setArgument(tokenList);
+ }
+
+ /**
+ * Called for the requested step.
+ * @param macro the macro expanded in the requested step.
+ * @param replacement the replacement for the expansion.
+ * @param result a list to store the macro call with the arguments substituted in.
+ */
+ public void storeFunctionStyleMacroReplacement(PreprocessorMacro macro, TokenList replacement, TokenList result) {
+ MacroInfo minfo= fMacroStack.getLast();
+ fMacroDefinition= macro;
+ fReplaceFrom= minfo.fMacroCall.first();
+ appendFunctionStyleMacro(result);
+ fReplaceTo= result.last();
+ StringBuilder buf= new StringBuilder();
+ toString(replacement, fLexer.getInput(), buf, buf, buf);
+ fReplacementText= buf.toString();
+ }
+
+ /**
+ * Append the current function-style macro with the arguments substituted.
+ */
+ public void appendFunctionStyleMacro(TokenList result) {
+ MacroInfo minfo= fMacroStack.getLast();
+ boolean active= true;
+ int nesting= -1;
+ int pcount= 0;
+
+ Token n;
+ Token l= null;
+ for (Token t = minfo.fMacroCall.first(); t != null; l=t, t=n) {
+ n = (Token) t.getNext();
+ switch (t.getType()) {
+ case IToken.tLPAREN:
+ if (active) {
+ result.append(t);
+ }
+ // the first one sets nesting to zero.
+ ++nesting;
+ if (nesting == 0) {
+ if (pcount < minfo.fArguments.size()) {
+ TokenList p = minfo.fArguments.get(pcount);
+ if (p != null) {
+ active = false;
+ addSpacemarker(t, n, result);
+ result.appendAll(p);
+ }
+ }
+ }
+ break;
+
+ case IToken.tRPAREN:
+ if (!active && nesting == 0) {
+ addSpacemarker(l, t, result);
+ active= true;
+ }
+ if (active) {
+ result.append(t);
+ }
+ if (nesting > 0) {
+ nesting--;
+ }
+ break;
+
+ case IToken.tCOMMA:
+ if (nesting == 0) {
+ if (++pcount < minfo.fArguments.size()) {
+ if (!active) {
+ addSpacemarker(l, t, result);
+ }
+ result.append(t);
+ TokenList p = minfo.fArguments.get(pcount);
+ active = p == null;
+ if (!active) {
+ addSpacemarker(t, n, result);
+ result.appendAll(p);
+ }
+ }
+ } else if (active) {
+ result.append(t);
+ }
+ break;
+
+ default:
+ if (active) {
+ result.append(t);
+ }
+ }
+ }
+ }
+
+ private void addSpacemarker(Token l, Token t, TokenList target) {
+ Token tl= target.last();
+ if (tl != null && tl.getType() == CPreprocessor.tSPACE) {
+ return;
+ }
+ if (l != null && t != null) {
+ final Object s1= l.fSource;
+ final Object s2= t.fSource;
+ if (s1 == s2 && s1 != null && l.getType() != CPreprocessor.tSPACE) {
+ if (l.getEndOffset() != t.getOffset()) {
+ target.append(new Token(CPreprocessor.tSPACE, s1, l.getEndOffset(), t.getOffset()));
+ }
+ }
+ }
+ }
+
+ /**
+ * Informs the tracker that the function style macro has been expanded.
+ */
+ public void endFunctionStyleMacro() {
+ fStepCount++;
+ fMacroStack.removeLast();
+ }
+
+ /**
+ * Called for the requested step
+ * @param macro the macro expanded in the requested step.
+ * @param identifier the token that gets replaced.
+ * @param replacement the replacement
+ * @param result a list to store the macro in.
+ */
+ public void storeObjectStyleMacroReplacement(PreprocessorMacro macro, Token identifier, TokenList replacement, TokenList result) {
+ fMacroDefinition= macro;
+ fReplaceFrom= fReplaceTo= identifier;
+ result.append(identifier);
+ StringBuilder buf= new StringBuilder();
+ toString(replacement, fLexer.getInput(), buf, buf, buf);
+ fReplacementText= buf.toString();
+ }
+
+ /**
+ * Informs the tracker that an object style macro has been expanded.
+ */
+ public void endObjectStyleMacro() {
+ fStepCount++;
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 00000000000..cbb0d900eb6
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/MultiMacroExpansionExplorer.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * 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 java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import org.eclipse.cdt.core.dom.ast.IASTMacroExpansion;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.dom.rewrite.MacroExpansionExplorer;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.text.edits.ReplaceEdit;
+
+/**
+ * Delegates the task of exploring macro expansions to simpler explorers dealing with
+ * a single macro, only.
+ * @since 5.0
+ */
+public class MultiMacroExpansionExplorer extends MacroExpansionExplorer {
+ private static final class ASTFileLocation implements IASTFileLocation {
+ private final String fFilePath;
+ private final int fOffset;
+ private final int fLength;
+
+ private ASTFileLocation(String filePath, int offset, int length) {
+ fFilePath= filePath;
+ fOffset= offset;
+ fLength= length;
+ }
+ public int getNodeOffset() {return fOffset;}
+ public int getNodeLength() {return fLength;}
+ public String getFileName() {return fFilePath;}
+
+ public int getStartingLineNumber() {return 0;}
+ public int getEndingLineNumber() {return 0;}
+ public IASTFileLocation asFileLocation() {return this;}
+ }
+
+ private final char[] fSource;
+ private final int[] fBoundaries;
+ private final SingleMacroExpansionExplorer[] fDelegates;
+
+ public MultiMacroExpansionExplorer(IASTTranslationUnit tu, IASTFileLocation loc) {
+ if (tu == null || loc == null || loc.getNodeLength() == 0) {
+ throw new IllegalArgumentException();
+ }
+ final ILocationResolver resolver = (ILocationResolver) tu.getAdapter(ILocationResolver.class);
+ if (resolver == null) {
+ throw new IllegalArgumentException();
+ }
+ final IASTMacroExpansion[] expansions = resolver.getMacroExpansions(loc);
+ final int count= expansions.length;
+ if (count > 0) {
+ int from= loc.getNodeOffset();
+ int to= from+loc.getNodeLength();
+
+ final int lfrom = expansions[0].asFileLocation().getNodeOffset();
+ final IASTFileLocation l= expansions[count-1].asFileLocation();
+ final int lto= l.getNodeOffset() + l.getNodeLength();
+
+ if (lfrom < from || lto > to) {
+ from= Math.min(from, lfrom);
+ to= Math.max(to, lto);
+ loc= new ASTFileLocation(loc.getFileName(), from, to-from);
+ }
+ }
+
+ fSource= resolver.getUnpreprocessedSignature(loc);
+ fBoundaries= new int[count*2+1];
+ fDelegates= new SingleMacroExpansionExplorer[count];
+
+ final int firstOffset= loc.getNodeOffset();
+ int bidx= -1;
+ int didx= -1;
+ for (IASTMacroExpansion expansion : expansions) {
+ IASTName ref= expansion.getMacroReference();
+ if (ref != null) {
+ IASTFileLocation refLoc= expansion.asFileLocation();
+ int from= refLoc.getNodeOffset()-firstOffset;
+ int to= from+refLoc.getNodeLength();
+ fBoundaries[++bidx]= from;
+ fBoundaries[++bidx]= to;
+ fDelegates[++didx]= new SingleMacroExpansionExplorer(new String(fSource, from, to-from), ref,
+ resolver.getImplicitMacroReferences(ref));
+ }
+ }
+ fBoundaries[++bidx]= fSource.length;
+ }
+
+ public MultiMacroExpansionExplorer(final IASTTranslationUnit tu, final IRegion loc) {
+ this(tu, new ASTFileLocation(tu.getFilePath(), loc.getOffset(), loc.getLength()));
+ }
+
+ @Override
+ public IMacroExpansionStep getFullExpansion() {
+ List edits = combineReplaceEdits(fDelegates.length);
+ return new MacroExpansionStep(new String(fSource), null, edits.toArray(new ReplaceEdit[edits.size()]));
+ }
+
+ /**
+ * Combines the replace edits of the leading delegates.
+ */
+ private List combineReplaceEdits(int count) {
+ ArrayList edits= new ArrayList();
+ for (int i=0; i < count; i++) {
+ IMacroExpansionStep step= fDelegates[i].getFullExpansion();
+ shiftAndAddEdits(fBoundaries[2*i], step.getReplacements(), edits);
+ }
+ return edits;
+ }
+
+ /**
+ * Shifts and adds the replace edits to the target list.
+ */
+ private void shiftAndAddEdits(final int shift, ReplaceEdit[] stepEdits, List target) {
+ for (int j = 0; j < stepEdits.length; j++) {
+ final ReplaceEdit r = stepEdits[j];
+ final String rtext = r.getText();
+ target.add(new ReplaceEdit(shift+r.getOffset(), r.getLength(), rtext));
+ }
+ }
+
+
+ @Override
+ public int getExpansionStepCount() {
+ int result= 0;
+ for (int i=0; i < fDelegates.length; i++) {
+ result+= fDelegates[i].getExpansionStepCount();
+ }
+ return result;
+ }
+
+ @Override
+ public IMacroExpansionStep getExpansionStep(int step) throws IndexOutOfBoundsException {
+ if (step < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ int i;
+ MacroExpansionStep dresult= null;
+ StringBuilder before= new StringBuilder();
+ before.append(fSource, 0, fBoundaries[0]);
+
+ for (i=0; i < fDelegates.length; i++) {
+ final SingleMacroExpansionExplorer delegate = fDelegates[i];
+ int dsteps= delegate.getExpansionStepCount();
+ if (step < dsteps) {
+ dresult= delegate.getExpansionStep(step);
+ break;
+ }
+ before.append(delegate.getFullExpansion().getCodeAfterStep());
+ appendGap(before, i);
+ step-= dsteps;
+ }
+ if (dresult == null) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ final int shift= before.length();
+ final int end= fBoundaries[2*i+1];
+ before.append(dresult.getCodeBeforeStep());
+ before.append(fSource, end, fSource.length-end);
+
+ List replacements= new ArrayList();
+ shiftAndAddEdits(shift, dresult.getReplacements(), replacements);
+ return new MacroExpansionStep(before.toString(), dresult.getExpandedMacro(), replacements.toArray(new ReplaceEdit[replacements.size()]));
+ }
+
+ private void appendGap(StringBuilder result, int i) {
+ int idx= 2*i+1;
+ int gapFrom= fBoundaries[idx];
+ int gapTo= fBoundaries[++idx];
+ result.append(fSource, gapFrom, gapTo-gapFrom);
+ }
+}
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
new file mode 100644
index 00000000000..f5004cb278e
--- /dev/null
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SingleMacroExpansionExplorer.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * 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.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.rewrite.MacroExpansionExplorer;
+import org.eclipse.cdt.core.parser.util.CharArrayMap;
+import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
+import org.eclipse.text.edits.ReplaceEdit;
+
+/**
+ * Performs step by step macro expansion for an exact macro expansion location.
+ * @since 5.0
+ */
+public class SingleMacroExpansionExplorer extends MacroExpansionExplorer {
+
+ private static final LexerOptions LEX_OPTIONS= new LexerOptions();
+ static {
+ LEX_OPTIONS.fCreateImageLocations= false;
+ }
+
+ private final String fInput;
+ private final CharArrayMap fDictionary;
+ private MacroExpansionStep fFullExpansion;
+ private int fExpansionCount;
+
+ public SingleMacroExpansionExplorer(String input, IASTName ref, IASTName[] implicitRefs) {
+ fInput= input;
+ fDictionary= createDictionary(ref, implicitRefs);
+ }
+
+ private CharArrayMap createDictionary(IASTName ref, IASTName[] implicitRefs) {
+ // mstodo handle dynamic style macros
+ // mstodo clone index-macros
+ CharArrayMap map= new CharArrayMap(implicitRefs.length+1);
+ addMacroDefinition(map, ref);
+ for (IASTName name : implicitRefs) {
+ addMacroDefinition(map, name);
+ }
+ return map;
+ }
+
+ private void addMacroDefinition(CharArrayMap map, IASTName name) {
+ IBinding binding= name.getBinding();
+ if (binding instanceof PreprocessorMacro) {
+ map.put(name.toCharArray(), (PreprocessorMacro) binding);
+ }
+ }
+
+ @Override
+ public IMacroExpansionStep getFullExpansion() {
+ computeExpansion();
+ return fFullExpansion;
+ }
+
+ @Override
+ public int getExpansionStepCount() {
+ computeExpansion();
+ return fExpansionCount;
+ }
+
+ private void computeExpansion() {
+ MacroExpander expander= new MacroExpander(ILexerLog.NULL, fDictionary, null, LEX_OPTIONS);
+ MacroExpansionTracker tracker= new MacroExpansionTracker(Integer.MAX_VALUE);
+ expander.expand(fInput, tracker);
+
+ fExpansionCount= tracker.getStepCount();
+ ReplaceEdit r= tracker.getReplacement();
+ ReplaceEdit[] replacements= r==null ? new ReplaceEdit[0] : new ReplaceEdit[]{r};
+ fFullExpansion= new MacroExpansionStep(fInput, null, replacements);
+ }
+
+ @Override
+ public MacroExpansionStep getExpansionStep(int step) throws IndexOutOfBoundsException {
+ computeExpansion();
+ if (step < 0 || step >= fExpansionCount) {
+ throw new IndexOutOfBoundsException();
+ }
+ MacroExpander expander= new MacroExpander(ILexerLog.NULL, fDictionary, null, LEX_OPTIONS);
+ MacroExpansionTracker tracker= new MacroExpansionTracker(step);
+ expander.expand(fInput, tracker);
+
+ fExpansionCount= tracker.getStepCount();
+ ReplaceEdit r= tracker.getReplacement();
+ ReplaceEdit[] replacements= r==null ? new ReplaceEdit[0] : new ReplaceEdit[]{r};
+ return new MacroExpansionStep(tracker.getCodeBeforeStep(), tracker.getExpandedMacro(), replacements);
+ }
+}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacro.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacro.java
index 5df83345fb8..231341e9bbd 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacro.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMMacro.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2007 QNX Software Systems and others.
+ * Copyright (c) 2006, 2008 QNX Software Systems 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
@@ -152,13 +152,13 @@ public class PDOMMacro implements IIndexMacro, IASTFileLocation {
try {
byte style= pdom.getDB().getByte(record + MACRO_STYLE);
if (style == MACROSTYLE_FUNCTION) {
- List paramList = new ArrayList();
+ List paramList = new ArrayList();
PDOMMacroParameter param= getFirstParameter();
while (param != null) {
paramList.add(param.getName().getChars());
param = param.getNextParameter();
}
- fParameterList= (char[][])paramList.toArray(new char[paramList.size()][]);
+ fParameterList= paramList.toArray(new char[paramList.size()][]);
}
} catch (CoreException e) {
CCorePlugin.log(e);
@@ -285,6 +285,7 @@ public class PDOMMacro implements IIndexMacro, IASTFileLocation {
return null;
}
+ @SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
return null;
}