mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Engine for exploring macro expansions step by step, bug 23540.
This commit is contained in:
parent
3c2dd52cf7
commit
1c83f17a74
27 changed files with 1517 additions and 214 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <code>null</code> 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;
|
||||
}
|
|
@ -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<V> implements ICharArrayMap<V> {
|
|||
return map.values();
|
||||
}
|
||||
|
||||
public Collection<char[]> keys() {
|
||||
Set<Key> keys= map.keySet();
|
||||
ArrayList<char[]> r= new ArrayList<char[]>(keys.size());
|
||||
for (Key key : keys) {
|
||||
r.add(CharArrayUtils.extract(key.buffer, key.start, key.length));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
public void clear() {
|
||||
map.clear();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<PreprocessorMacro> fMacroDictionary = new CharArrayMap<PreprocessorMacro>(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<PreprocessorMacro> predefined= fMacroDictionary.values();
|
||||
for (PreprocessorMacro macro : predefined) {
|
||||
fLocationMap.registerPredefinedMacro(macro);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,13 +417,10 @@ public class CPreprocessor implements ILexerLog, IScanner {
|
|||
}
|
||||
|
||||
public Map<String, IMacroBinding> getMacroDefinitions() {
|
||||
final CharArrayObjectMap objMap= fMacroDictionary;
|
||||
int size = objMap.size();
|
||||
Map<String, IMacroBinding> hashMap = new HashMap<String, IMacroBinding>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
hashMap.put(String.valueOf(objMap.keyAt(i)), (IMacroBinding) objMap.getAt(i));
|
||||
}
|
||||
|
||||
Map<String, IMacroBinding> hashMap = new HashMap<String, IMacroBinding>(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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<PreprocessorMacro> fDictionary;
|
||||
|
||||
public boolean evaluate(TokenList condition, CharArrayObjectMap dictionary) throws EvalException {
|
||||
public boolean evaluate(TokenList condition, CharArrayMap<PreprocessorMacro> macroDictionary) throws EvalException {
|
||||
fTokens= condition.first();
|
||||
fDictionary= dictionary;
|
||||
fDictionary= macroDictionary;
|
||||
return expression() != 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ class LocationCtxContainer extends LocationCtx {
|
|||
fSource= source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LocationCtx> 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<IASTInclusionNode> result) {
|
||||
if (fChildren != null) {
|
||||
for (Iterator<LocationCtx> iterator = fChildren.iterator(); iterator.hasNext();) {
|
||||
|
@ -212,6 +218,7 @@ class LocationCtxContainer extends LocationCtx {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLineNumber(int offset) {
|
||||
if (fLineOffsets == null) {
|
||||
fLineOffsets= computeLineOffsets();
|
||||
|
|
|
@ -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<IASTMacroExpansion> result) {
|
||||
Collection<LocationCtx> 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<ASTProblem> fProblems= new ArrayList<ASTProblem>();
|
||||
private ArrayList<ASTComment> fComments= new ArrayList<ASTComment>();
|
||||
private ArrayList<ASTObjectStyleMacroDefinition> fBuiltinMacros= new ArrayList<ASTObjectStyleMacroDefinition>();
|
||||
private IdentityHashMap<IMacroBinding, List<IASTName>> fMacroReferences= new IdentityHashMap<IMacroBinding, List<IASTName>>();
|
||||
private ArrayList<IASTName> fMacroReferences= new ArrayList<IASTName>();
|
||||
|
||||
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<IASTName> list= fMacroReferences.get(macro);
|
||||
if (list == null) {
|
||||
list= new ArrayList<IASTName>();
|
||||
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<IASTMacroExpansion> list= new ArrayList<IASTMacroExpansion>();
|
||||
|
||||
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<IASTName> list= fMacroReferences.get(binding);
|
||||
if (list == null) {
|
||||
return EMPTY_NAMES;
|
||||
List<IASTName> result= new ArrayList<IASTName>();
|
||||
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<IASTName> result= new ArrayList<IASTName>();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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<PreprocessorMacro> fDictionary;
|
||||
private final LocationMap fLocationMap;
|
||||
private final LexerOptions fLexOptions;
|
||||
private ArrayList<IASTName> fImplicitMacroExpansions= new ArrayList<IASTName>();
|
||||
|
@ -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<PreprocessorMacro> 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<PreprocessorMacro, PreprocessorMacro> forbidden= new IdentityHashMap<PreprocessorMacro, PreprocessorMacro>();
|
||||
|
||||
// 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<PreprocessorMacro, PreprocessorMacro> forbidden, TokenSource input, TokenList result)
|
||||
private Token expandOne(Token lastConsumed, PreprocessorMacro macro,
|
||||
IdentityHashMap<PreprocessorMacro, PreprocessorMacro> 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<PreprocessorMacro, PreprocessorMacro> forbidden) throws OffsetLimitReachedException {
|
||||
private void executeScopeMarkers(TokenSource input, IdentityHashMap<PreprocessorMacro, PreprocessorMacro> 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<PreprocessorMacro, PreprocessorMacro> 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<PreprocessorMacro, PreprocessorMacro> forbidden, TokenSource[] result) throws OffsetLimitReachedException {
|
||||
private Token parseArguments(TokenSource input, FunctionStyleMacro macro, IdentityHashMap<PreprocessorMacro, PreprocessorMacro> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<TokenList> fArguments= new ArrayList<TokenList>();
|
||||
|
||||
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<MacroInfo> fMacroStack= new LinkedList<MacroInfo>();
|
||||
|
||||
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 <code>null</code> 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++;
|
||||
}
|
||||
}
|
|
@ -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<ReplaceEdit> 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<ReplaceEdit> combineReplaceEdits(int count) {
|
||||
ArrayList<ReplaceEdit> edits= new ArrayList<ReplaceEdit>();
|
||||
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<ReplaceEdit> 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<ReplaceEdit> replacements= new ArrayList<ReplaceEdit>();
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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<PreprocessorMacro> fDictionary;
|
||||
private MacroExpansionStep fFullExpansion;
|
||||
private int fExpansionCount;
|
||||
|
||||
public SingleMacroExpansionExplorer(String input, IASTName ref, IASTName[] implicitRefs) {
|
||||
fInput= input;
|
||||
fDictionary= createDictionary(ref, implicitRefs);
|
||||
}
|
||||
|
||||
private CharArrayMap<PreprocessorMacro> createDictionary(IASTName ref, IASTName[] implicitRefs) {
|
||||
// mstodo handle dynamic style macros
|
||||
// mstodo clone index-macros
|
||||
CharArrayMap<PreprocessorMacro> map= new CharArrayMap<PreprocessorMacro>(implicitRefs.length+1);
|
||||
addMacroDefinition(map, ref);
|
||||
for (IASTName name : implicitRefs) {
|
||||
addMacroDefinition(map, name);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private void addMacroDefinition(CharArrayMap<PreprocessorMacro> 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);
|
||||
}
|
||||
}
|
|
@ -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<char[]> paramList = new ArrayList<char[]>();
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue