1
0
Fork 0
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:
Markus Schorn 2008-01-16 16:43:52 +00:00
parent 3c2dd52cf7
commit 1c83f17a74
27 changed files with 1517 additions and 214 deletions

View file

@ -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);
}
}

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -464,17 +464,18 @@ public class LocationMapTests extends BaseTestCase {
fLocationMap.encounteredComment(12, 23, false); fLocationMap.encounteredComment(12, 23, false);
checkComment(fLocationMap.getComments()[0], new String(LONGDIGITS, 110, 15), false, FN, 110, 15, 2, 2); 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); 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); refs= fLocationMap.getReferences(macro2);
assertEquals(1, refs.length); 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)); checkName(refs[0], macro2, "n2", macro3ref, 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));
} }
public void testContexts() { public void testContexts() {

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -11,9 +11,6 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.core.parser.tests.scanner; package org.eclipse.cdt.core.parser.tests.scanner;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestSuite; import junit.framework.TestSuite;
import org.eclipse.cdt.core.parser.IProblem; import org.eclipse.cdt.core.parser.IProblem;

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -286,6 +286,69 @@ public class PreprocessorTests extends PreprocessorTestsBase {
validateProblemCount(0); 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 // #define str(x) #x
// str(); // str();
public void testEmptyStringify() throws Exception { 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(); StringBuffer sb = getExample3Defines();
sb.append("g(x+(3,4)-w) | h 5) & m (f)^m(m); \n"); 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 // f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); //47
initializeScanner(sb.toString()); initializeScanner(sb.toString());
validateIdentifier("g"); validateIdentifier("f");
validateToken(IToken.tLPAREN); validateToken(IToken.tLPAREN);
validateInteger("2"); validateInteger("2");
validateToken(IToken.tSTAR); validateToken(IToken.tSTAR);
@ -849,7 +912,7 @@ public class PreprocessorTests extends PreprocessorTestsBase {
validateIdentifier("f"); validateIdentifier("f");
validateToken(IToken.tLPAREN); validateToken(IToken.tLPAREN);
validateInteger("2"); validateInteger("2");
validateToken(IToken.tLPAREN); validateToken(IToken.tSTAR);
validateToken(IToken.tLPAREN); validateToken(IToken.tLPAREN);
validateInteger("0"); validateInteger("0");
validateToken(IToken.tCOMMA); validateToken(IToken.tCOMMA);

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -23,6 +23,7 @@ public class ScannerTestSuite extends TestSuite {
suite.addTest(PreprocessorTests.suite()); suite.addTest(PreprocessorTests.suite());
suite.addTest(InclusionTests.suite()); suite.addTest(InclusionTests.suite());
suite.addTest(PreprocessorBugsTests.suite()); suite.addTest(PreprocessorBugsTests.suite());
suite.addTest(ExpansionExplorerTests.suite());
return suite; return suite;
} }
} }

View file

@ -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 {}

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -27,6 +27,12 @@ public interface IASTMacroExpansion extends IASTNodeLocation {
*/ */
public IASTPreprocessorMacroDefinition getMacroDefinition(); 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 * 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 * nodes within the same macro-expansion. However, it does not serve as an offset

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -117,16 +117,7 @@ public interface IASTTranslationUnit extends IASTNode, IAdaptable {
public IASTName[] getReferences(IBinding binding); public IASTName[] getReferences(IBinding binding);
/** /**
* Returns an array of locations. This is a sequence of file locations and macro-expansion locations. * Select the node in the treat that best fits the offset/length/file path.
* @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.
* *
* @param path - file name specified through path * @param path - file name specified through path
* @param offset - location in the file as an offset * @param offset - location in the file as an offset

View file

@ -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;
}

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -10,9 +10,11 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.core.parser.util; package org.eclipse.cdt.core.parser.util;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
@ -174,6 +176,15 @@ public final class CharArrayMap<V> implements ICharArrayMap<V> {
return map.values(); 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() { public void clear() {
map.clear(); map.clear();

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * 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 { public class CASTTranslationUnit extends CASTNode implements IASTTranslationUnit {
private static final IASTPreprocessorStatement[] EMPTY_PREPROCESSOR_STATEMENT_ARRAY = new IASTPreprocessorStatement[0]; 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 IASTPreprocessorMacroDefinition[] EMPTY_PREPROCESSOR_MACRODEF_ARRAY = new IASTPreprocessorMacroDefinition[0];
private static final IASTPreprocessorIncludeStatement[] EMPTY_PREPROCESSOR_INCLUSION_ARRAY = new IASTPreprocessorIncludeStatement[0]; private static final IASTPreprocessorIncludeStatement[] EMPTY_PREPROCESSOR_INCLUSION_ARRAY = new IASTPreprocessorIncludeStatement[0];
private static final IASTProblem[] EMPTY_PROBLEM_ARRAY = new IASTProblem[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); 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 { private class CFindNodeForOffsetAction extends CASTVisitor {
{ {
shouldVisitNames = true; shouldVisitNames = true;
@ -546,6 +533,7 @@ public class CASTTranslationUnit extends CASTNode implements IASTTranslationUnit
return new IASTComment[0]; return new IASTComment[0];
} }
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) { public Object getAdapter(Class adapter) {
if (adapter.isAssignableFrom(resolver.getClass())) { if (adapter.isAssignableFrom(resolver.getClass())) {
return resolver; return resolver;

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * 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 { public class CPPASTTranslationUnit extends CPPASTNode implements ICPPASTTranslationUnit, IASTAmbiguityParent {
private static final IASTPreprocessorStatement[] EMPTY_PREPROCESSOR_STATEMENT_ARRAY = new IASTPreprocessorStatement[0]; 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 IASTPreprocessorMacroDefinition[] EMPTY_PREPROCESSOR_MACRODEF_ARRAY = new IASTPreprocessorMacroDefinition[0];
private static final IASTPreprocessorIncludeStatement[] EMPTY_PREPROCESSOR_INCLUSION_ARRAY = new IASTPreprocessorIncludeStatement[0]; private static final IASTPreprocessorIncludeStatement[] EMPTY_PREPROCESSOR_INCLUSION_ARRAY = new IASTPreprocessorIncludeStatement[0];
private static final String EMPTY_STRING = ""; //$NON-NLS-1$ 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); 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 { private class CPPFindNodeForOffsetAction extends CPPASTVisitor {
{ {
shouldVisitNames = true; shouldVisitNames = true;
@ -512,6 +504,7 @@ public class CPPASTTranslationUnit extends CPPASTNode implements ICPPASTTranslat
return new IASTComment[0]; return new IASTComment[0];
} }
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) { public Object getAdapter(Class adapter) {
if (adapter.isAssignableFrom(resolver.getClass())) { if (adapter.isAssignableFrom(resolver.getClass())) {
return resolver; return resolver;

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -124,10 +124,12 @@ class ASTMacroReferenceName extends ASTPreprocessorName {
fImageLocationInfo= imgLocationInfo; fImageLocationInfo= imgLocationInfo;
} }
@Override
public boolean isReference() { public boolean isReference() {
return true; return true;
} }
@Override
public IASTImageLocation getImageLocation() { public IASTImageLocation getImageLocation() {
if (fImageLocationInfo != null) { if (fImageLocationInfo != null) {
IASTTranslationUnit tu= getTranslationUnit(); IASTTranslationUnit tu= getTranslationUnit();

View file

@ -467,6 +467,10 @@ class ASTFileLocation implements IASTFileLocation {
public int getSequenceEndNumber() { public int getSequenceEndNumber() {
return fLocationCtx.getSequenceNumberForOffset(fOffset+fLength, true); return fLocationCtx.getSequenceNumberForOffset(fOffset+fLength, true);
} }
public LocationCtxFile getLocationContext() {
return fLocationCtx;
}
} }
class ASTMacroExpansionLocation implements IASTMacroExpansion { class ASTMacroExpansionLocation implements IASTMacroExpansion {
@ -490,6 +494,10 @@ class ASTMacroExpansionLocation implements IASTMacroExpansion {
return fContext.getMacroDefinition(); return fContext.getMacroDefinition();
} }
public IASTName getMacroReference() {
return fContext.getMacroReference();
}
public IASTFileLocation asFileLocation() { public IASTFileLocation asFileLocation() {
return ((LocationCtxContainer) fContext.getParent()).createFileLocation(fContext.fOffsetInParent, fContext.fEndOffsetInParent-fContext.fOffsetInParent); return ((LocationCtxContainer) fContext.getParent()).createFileLocation(fContext.fOffsetInParent, fContext.fEndOffsetInParent-fContext.fOffsetInParent);
} }

View file

@ -14,7 +14,9 @@ package org.eclipse.cdt.internal.core.parser.scanner;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.text.DateFormatSymbols;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; 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.ParseError;
import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.util.CharArrayIntMap; 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.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator.EvalException; 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.Lexer.LexerOptions;
import org.eclipse.cdt.internal.core.parser.scanner.MacroDefinitionParser.InvalidMacroDefinitionException; 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 * 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. * you should be using the {@link IScanner} interface.
* @since 5.0 * @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 String PROP_VALUE = "CPreprocessor"; //$NON-NLS-1$
public static final int tDEFINED= IToken.FIRST_RESERVED_PREPROCESSOR; 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 tSPACE= IToken.FIRST_RESERVED_PREPROCESSOR+3;
public static final int tNOSPACE= IToken.FIRST_RESERVED_PREPROCESSOR+4; 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 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_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 static final ObjectStyleMacro __STDC_VERSION__ = new ObjectStyleMacro("__STDC_VERSION_".toCharArray(), "199901L".toCharArray()); //$NON-NLS-1$ //$NON-NLS-2$
private interface IIncludeFileTester { private interface IIncludeFileTester {
Object checkFile(String path, String fileName); Object checkFile(String path, String fileName);
} }
@ -120,7 +123,8 @@ public class CPreprocessor implements ILexerLog, IScanner {
public Token execute() { public Token execute() {
StringBuffer buffer = new StringBuffer("\""); //$NON-NLS-1$ StringBuffer buffer = new StringBuffer("\""); //$NON-NLS-1$
Calendar cal = Calendar.getInstance(); 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$ buffer.append(" "); //$NON-NLS-1$
append(buffer, cal.get(Calendar.DAY_OF_MONTH)); append(buffer, cal.get(Calendar.DAY_OF_MONTH));
buffer.append(" "); //$NON-NLS-1$ buffer.append(" "); //$NON-NLS-1$
@ -140,7 +144,7 @@ public class CPreprocessor implements ILexerLog, IScanner {
public Token execute() { public Token execute() {
StringBuffer buffer = new StringBuffer("\""); //$NON-NLS-1$ StringBuffer buffer = new StringBuffer("\""); //$NON-NLS-1$
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
append(buffer, cal.get(Calendar.HOUR)); append(buffer, cal.get(Calendar.HOUR_OF_DAY));
buffer.append(":"); //$NON-NLS-1$ buffer.append(":"); //$NON-NLS-1$
append(buffer, cal.get(Calendar.MINUTE)); append(buffer, cal.get(Calendar.MINUTE));
buffer.append(":"); //$NON-NLS-1$ buffer.append(":"); //$NON-NLS-1$
@ -176,7 +180,7 @@ public class CPreprocessor implements ILexerLog, IScanner {
private boolean fHandledCompletion= false; private boolean fHandledCompletion= false;
// state information // state information
private final CharArrayObjectMap fMacroDictionary = new CharArrayObjectMap(512); private final CharArrayMap<PreprocessorMacro> fMacroDictionary = new CharArrayMap<PreprocessorMacro>(512);
private final LocationMap fLocationMap = new LocationMap(); private final LocationMap fLocationMap = new LocationMap();
/** Set of already included files */ /** Set of already included files */
@ -345,9 +349,9 @@ public class CPreprocessor implements ILexerLog, IScanner {
} }
} }
Object[] predefined= fMacroDictionary.valueArray(); Collection<PreprocessorMacro> predefined= fMacroDictionary.values();
for (int i = 0; i < predefined.length; i++) { for (PreprocessorMacro macro : predefined) {
fLocationMap.registerPredefinedMacro((PreprocessorMacro) predefined[i]); fLocationMap.registerPredefinedMacro(macro);
} }
} }
@ -413,13 +417,10 @@ public class CPreprocessor implements ILexerLog, IScanner {
} }
public Map<String, IMacroBinding> getMacroDefinitions() { public Map<String, IMacroBinding> getMacroDefinitions() {
final CharArrayObjectMap objMap= fMacroDictionary; Map<String, IMacroBinding> hashMap = new HashMap<String, IMacroBinding>(fMacroDictionary.size());
int size = objMap.size(); for (char[] key : fMacroDictionary.keys()) {
Map<String, IMacroBinding> hashMap = new HashMap<String, IMacroBinding>(size); hashMap.put(String.valueOf(key), fMacroDictionary.get(key));
for (int i = 0; i < size; i++) { }
hashMap.put(String.valueOf(objMap.keyAt(i)), (IMacroBinding) objMap.getAt(i));
}
return hashMap; return hashMap;
} }
@ -1165,7 +1166,7 @@ public class CPreprocessor implements ILexerLog, IScanner {
lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
final int endOffset= lexer.currentToken().getEndOffset(); final int endOffset= lexer.currentToken().getEndOffset();
final char[] namechars= name.getCharImage(); 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); 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 { private boolean expandMacro(final Token identifier, Lexer lexer, boolean stopAtNewline) throws OffsetLimitReachedException {
final char[] name= identifier.getCharImage(); final char[] name= identifier.getCharImage();
PreprocessorMacro macro= (PreprocessorMacro) fMacroDictionary.get(name); PreprocessorMacro macro= fMacroDictionary.get(name);
if (macro == null) { if (macro == null) {
return false; return false;
} }
@ -1419,4 +1420,12 @@ public class CPreprocessor implements ILexerLog, IScanner {
fCurrentContext= new ScannerContext(ctx, fCurrentContext, replacement); fCurrentContext= new ScannerContext(ctx, fCurrentContext, replacement);
return true; return true;
} }
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) {
if (adapter.isAssignableFrom(fMacroExpander.getClass())) {
return fMacroExpander;
}
return null;
}
} }

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * 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.IProblem;
import org.eclipse.cdt.core.parser.IToken; 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. * Used to evaluate expressions in preprocessor directives.
@ -40,11 +40,11 @@ class ExpressionEvaluator {
} }
private Token fTokens; 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(); fTokens= condition.first();
fDictionary= dictionary; fDictionary= macroDictionary;
return expression() != 0; return expression() != 0;
} }

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * 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.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation; 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.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
@ -103,9 +104,12 @@ public interface ILocationResolver {
*/ */
IASTFileLocation getMappedFileLocation(int offset, int length); 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); IASTNodeLocation[] getLocations(int sequenceNumber, int length);
/** /**
@ -122,7 +126,7 @@ public interface ILocationResolver {
int getSequenceNumberForFileOffset(String filePath, int fileOffset); int getSequenceNumberForFileOffset(String filePath, int fileOffset);
/** /**
* @see IASTTranslationUnit#getUnpreprocessedSignature(IASTFileLocation). * @see IASTNode#getRawSignature().
*/ */
char[] getUnpreprocessedSignature(IASTFileLocation loc); 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. * Same as {@link #getMappedFileLocation(int, int)} for the given array of consecutive node locations.
*/ */
IASTFileLocation flattenLocations(IASTNodeLocation[] nodeLocations); 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);
} }

View file

@ -14,7 +14,6 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; 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.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree.IASTInclusionNode; 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 * Returns the minimal file location containing the specified sequence number range, assuming
* that it is contained in this context. * 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); return fParent.createMappedFileLocation(fOffsetInParent, fEndOffsetInParent-fOffsetInParent);
} }
/** /**
* Returns the file location containing the specified offset range in this context. * 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); return fParent.createMappedFileLocation(fOffsetInParent, fEndOffsetInParent-fOffsetInParent);
} }

View file

@ -40,6 +40,7 @@ class LocationCtxContainer extends LocationCtx {
fSource= source; fSource= source;
} }
@Override
public Collection<LocationCtx> getChildren() { public Collection<LocationCtx> getChildren() {
if (fChildren == null) { if (fChildren == null) {
return Collections.emptyList(); return Collections.emptyList();
@ -84,10 +85,12 @@ class LocationCtxContainer extends LocationCtx {
return result; return result;
} }
@Override
public void addChildSequenceLength(int childLength) { public void addChildSequenceLength(int childLength) {
fChildSequenceLength+= childLength; fChildSequenceLength+= childLength;
} }
@Override
public final LocationCtx findSurroundingContext(int sequenceNumber, int length) { public final LocationCtx findSurroundingContext(int sequenceNumber, int length) {
int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber; int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber;
final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, false); final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, false);
@ -97,6 +100,7 @@ class LocationCtxContainer extends LocationCtx {
return this; return this;
} }
@Override
public final LocationCtxMacroExpansion findSurroundingMacroExpansion(int sequenceNumber, int length) { public final LocationCtxMacroExpansion findSurroundingMacroExpansion(int sequenceNumber, int length) {
int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber; int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber;
final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, true); final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, true);
@ -106,7 +110,8 @@ class LocationCtxContainer extends LocationCtx {
return null; return null;
} }
public IASTFileLocation findMappedFileLocation(int sequenceNumber, int length) { @Override
public ASTFileLocation findMappedFileLocation(int sequenceNumber, int length) {
// try to delegate to a child. // try to delegate to a child.
int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber; int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber;
final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, false); final LocationCtx child= findChildLessOrEqualThan(sequenceNumber, false);
@ -198,6 +203,7 @@ class LocationCtxContainer extends LocationCtx {
return idx >= 0 ? fChildren.get(idx) : null; return idx >= 0 ? fChildren.get(idx) : null;
} }
@Override
public void getInclusions(ArrayList<IASTInclusionNode> result) { public void getInclusions(ArrayList<IASTInclusionNode> result) {
if (fChildren != null) { if (fChildren != null) {
for (Iterator<LocationCtx> iterator = fChildren.iterator(); iterator.hasNext();) { for (Iterator<LocationCtx> iterator = fChildren.iterator(); iterator.hasNext();) {
@ -212,6 +218,7 @@ class LocationCtxContainer extends LocationCtx {
} }
} }
@Override
public int getLineNumber(int offset) { public int getLineNumber(int offset) {
if (fLineOffsets == null) { if (fLineOffsets == null) {
fLineOffsets= computeLineOffsets(); fLineOffsets= computeLineOffsets();

View file

@ -10,7 +10,10 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner; 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. * A location context representing a file.
@ -26,15 +29,18 @@ class LocationCtxFile extends LocationCtxContainer {
fASTInclude= inclusionStatement; fASTInclude= inclusionStatement;
} }
@Override
public final void addChildSequenceLength(int childLength) { public final void addChildSequenceLength(int childLength) {
super.addChildSequenceLength(childLength); super.addChildSequenceLength(childLength);
} }
@Override
public final String getFilePath() { public final String getFilePath() {
return fFilename; return fFilename;
} }
public IASTFileLocation findMappedFileLocation(int sequenceNumber, int length) { @Override
public ASTFileLocation findMappedFileLocation(int sequenceNumber, int length) {
// try to delegate to a child. // try to delegate to a child.
final int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber; final int testEnd= length > 1 ? sequenceNumber+length-1 : sequenceNumber;
final int sequenceEnd= sequenceNumber+length; final int sequenceEnd= sequenceNumber+length;
@ -76,14 +82,17 @@ class LocationCtxFile extends LocationCtxContainer {
return new ASTFileLocation(this, startOffset, endOffset-startOffset); 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); return new ASTFileLocation(this, offset, length);
} }
@Override
public ASTInclusionStatement getInclusionStatement() { public ASTInclusionStatement getInclusionStatement() {
return fASTInclude; return fASTInclude;
} }
@Override
ASTFileLocation createFileLocation(int start, int length) { ASTFileLocation createFileLocation(int start, int length) {
return new ASTFileLocation(this, start, length); return new ASTFileLocation(this, start, length);
} }
@ -95,4 +104,20 @@ class LocationCtxFile extends LocationCtxContainer {
} }
return sequenceNumber >= child.fSequenceNumber + child.getSequenceLength(); 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()));
}
}
}
}
} }

View file

@ -19,6 +19,7 @@ import java.util.List;
import org.eclipse.cdt.core.dom.ast.IASTComment; import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation; 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.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; 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<ASTProblem> fProblems= new ArrayList<ASTProblem>();
private ArrayList<ASTComment> fComments= new ArrayList<ASTComment>(); private ArrayList<ASTComment> fComments= new ArrayList<ASTComment>();
private ArrayList<ASTObjectStyleMacroDefinition> fBuiltinMacros= new ArrayList<ASTObjectStyleMacroDefinition>(); 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 LocationCtxFile fRootContext= null;
private LocationCtx fCurrentContext= null; private LocationCtx fCurrentContext= null;
@ -157,27 +158,22 @@ public class LocationMap implements ILocationResolver {
int endNumber= getSequenceNumberForOffset(endOffset); int endNumber= getSequenceNumberForOffset(endOffset);
final int length= endNumber-nameNumber; final int length= endNumber-nameNumber;
ASTMacroReferenceName expansion= new ASTMacroReferenceName(fTranslationUnit, nameNumber, nameEndNumber, macro, null);
for (int i = 0; i < implicitMacroReferences.length; i++) { for (int i = 0; i < implicitMacroReferences.length; i++) {
ASTMacroReferenceName name = (ASTMacroReferenceName) implicitMacroReferences[i]; ASTMacroReferenceName name = (ASTMacroReferenceName) implicitMacroReferences[i];
name.setOffsetAndLength(nameNumber, length); name.setOffsetAndLength(nameNumber, length);
addMacroReference((IMacroBinding) name.getBinding(), name); name.setParent(expansion);
addMacroReference(name);
} }
addMacroReference(expansion);
ASTMacroReferenceName expansion= new ASTMacroReferenceName(fTranslationUnit, nameNumber, nameEndNumber, macro, null);
addMacroReference(macro, expansion);
fCurrentContext= new LocationCtxMacroExpansion(this, (LocationCtxContainer) fCurrentContext, nameOffset, endOffset, endNumber, contextLength, imageLocations, expansion); fCurrentContext= new LocationCtxMacroExpansion(this, (LocationCtxContainer) fCurrentContext, nameOffset, endOffset, endNumber, contextLength, imageLocations, expansion);
fLastChildInsertionOffset= 0; fLastChildInsertionOffset= 0;
return fCurrentContext; return fCurrentContext;
} }
private void addMacroReference(IMacroBinding macro, IASTName name) { private void addMacroReference(IASTName name) {
List<IASTName> list= fMacroReferences.get(macro); fMacroReferences.add(name);
if (list == null) {
list= new ArrayList<IASTName>();
fMacroReferences.put(macro, list);
}
list.add(name);
} }
/** /**
@ -310,7 +306,7 @@ public class LocationMap implements ILocationResolver {
// not using endOffset, compatible with 4.0: endOffset= getSequenceNumberForOffset(endOffset); // not using endOffset, compatible with 4.0: endOffset= getSequenceNumberForOffset(endOffset);
final ASTUndef undef = new ASTUndef(fTranslationUnit, name, startOffset, nameOffset, nameEndOffset, definition); final ASTUndef undef = new ASTUndef(fTranslationUnit, name, startOffset, nameOffset, nameEndOffset, definition);
fDirectives.add(undef); fDirectives.add(undef);
addMacroReference(definition, undef.getMacroName()); addMacroReference(undef.getMacroName());
} }
public void setRootNode(IASTTranslationUnit root) { public void setRootNode(IASTTranslationUnit root) {
@ -351,15 +347,54 @@ public class LocationMap implements ILocationResolver {
return new String(ctx.getFilePath()); return new String(ctx.getFilePath());
} }
public IASTFileLocation getMappedFileLocation(int sequenceNumber, int length) { public ASTFileLocation getMappedFileLocation(int sequenceNumber, int length) {
return fRootContext.findMappedFileLocation(sequenceNumber, length); return fRootContext.findMappedFileLocation(sequenceNumber, length);
} }
public char[] getUnpreprocessedSignature(IASTFileLocation loc) { public char[] getUnpreprocessedSignature(IASTFileLocation loc) {
if (loc instanceof ASTFileLocation) { ASTFileLocation floc= convertFileLocation(loc);
return ((ASTFileLocation) loc).getSource(); if (floc == null) {
} return CharArrayUtils.EMPTY;
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) { public IASTNodeLocation[] getLocations(int sequenceNumber, int length) {
@ -538,11 +573,23 @@ public class LocationMap implements ILocationResolver {
} }
public IASTName[] getReferences(IMacroBinding binding) { public IASTName[] getReferences(IMacroBinding binding) {
List<IASTName> list= fMacroReferences.get(binding); List<IASTName> result= new ArrayList<IASTName>();
if (list == null) { for (IASTName name : fMacroReferences) {
return EMPTY_NAMES; 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() { public IDependencyTree getDependencyTree() {

View file

@ -11,13 +11,14 @@
package org.eclipse.cdt.internal.core.parser.scanner; package org.eclipse.cdt.internal.core.parser.scanner;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.BitSet;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.parser.IProblem; import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.IToken; import org.eclipse.cdt.core.parser.IToken;
import org.eclipse.cdt.core.parser.OffsetLimitReachedException; 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.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.parser.scanner.ImageLocationInfo.MacroImageLocationInfo; import org.eclipse.cdt.internal.core.parser.scanner.ImageLocationInfo.MacroImageLocationInfo;
import org.eclipse.cdt.internal.core.parser.scanner.ImageLocationInfo.ParameterImageLocationInfo; import org.eclipse.cdt.internal.core.parser.scanner.ImageLocationInfo.ParameterImageLocationInfo;
@ -31,6 +32,7 @@ import org.eclipse.cdt.internal.core.parser.scanner.MacroDefinitionParser.TokenP
public class MacroExpander { public class MacroExpander {
private static final int ORIGIN = OffsetLimitReachedException.ORIGIN_MACRO_EXPANSION; 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 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 * Marks the beginning and the end of the scope of a macro expansion. Necessary to properly
@ -125,7 +127,7 @@ public class MacroExpander {
private final ILexerLog fLog; private final ILexerLog fLog;
private final MacroDefinitionParser fDefinitionParser; private final MacroDefinitionParser fDefinitionParser;
private final CharArrayObjectMap fDictionary; private final CharArrayMap<PreprocessorMacro> fDictionary;
private final LocationMap fLocationMap; private final LocationMap fLocationMap;
private final LexerOptions fLexOptions; private final LexerOptions fLexOptions;
private ArrayList<IASTName> fImplicitMacroExpansions= new ArrayList<IASTName>(); private ArrayList<IASTName> fImplicitMacroExpansions= new ArrayList<IASTName>();
@ -134,8 +136,8 @@ public class MacroExpander {
private int fStartOffset; private int fStartOffset;
private int fEndOffset; private int fEndOffset;
public MacroExpander(ILexerLog log, CharArrayObjectMap dict, LocationMap locationMap, LexerOptions lexOptions) { public MacroExpander(ILexerLog log, CharArrayMap<PreprocessorMacro> macroDictionary, LocationMap locationMap, LexerOptions lexOptions) {
fDictionary= dict; fDictionary= macroDictionary;
fLocationMap= locationMap; fLocationMap= locationMap;
fDefinitionParser= new MacroDefinitionParser(); fDefinitionParser= new MacroDefinitionParser();
fLexOptions= lexOptions; fLexOptions= lexOptions;
@ -158,45 +160,144 @@ public class MacroExpander {
// setup input sequence // setup input sequence
TokenSource input= new TokenSource(lexer, stopAtNewline); TokenSource input= new TokenSource(lexer, stopAtNewline);
TokenList firstExpansion= new TokenList(); TokenList firstExpansion= new TokenList();
expandOne(identifier, macro, forbidden, input, firstExpansion); expandOne(identifier, macro, forbidden, input, firstExpansion, null);
input.prepend(firstExpansion); input.prepend(firstExpansion);
TokenList result= expandAll(input, forbidden); TokenList result= expandAll(input, forbidden, null);
postProcessTokens(result); postProcessTokens(result);
return 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 * 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 * tokens from the input (to read the parameters) and stores the resulting tokens together
* with boundary markers in the result token list. * with boundary markers in the result token list.
* Returns the last token of the expansion. * 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 { throws OffsetLimitReachedException {
result.append(new ExpansionBoundary(macro, true)); result.append(new ExpansionBoundary(macro, true));
if (macro.isFunctionStyle()) { if (macro.isFunctionStyle()) {
final TokenSource[] argInputs= new TokenSource[macro.getParameterPlaceholderList().length]; final int paramCount = macro.getParameterPlaceholderList().length;
lastConsumed= parseArguments(input, (FunctionStyleMacro) macro, forbidden, argInputs); final TokenSource[] argInputs= new TokenSource[paramCount];
TokenList[] clonedArgs= new TokenList[argInputs.length]; final BitSet paramUsage= getParamUsage(macro);
TokenList[] expandedArgs= new TokenList[argInputs.length]; if (tracker != null) {
for (int i = 0; i < argInputs.length; i++) { tracker.startFunctionStyleMacro((Token) lastConsumed.clone());
final TokenSource argInput = argInputs[i]; }
clonedArgs[i]= argInput.cloneTokens(); lastConsumed= parseArguments(input, (FunctionStyleMacro) macro, forbidden, argInputs, tracker);
final TokenList expandedArg= expandAll(argInput, forbidden); TokenList[] clonedArgs= new TokenList[paramCount];
expandedArgs[i]= expandedArg; 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 { 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)); result.append(new ExpansionBoundary(macro, false));
return lastConsumed; 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(); final TokenList result= new TokenList();
Token l= null; Token l= null;
Token t= input.removeFirst(); Token t= input.removeFirst();
@ -207,9 +308,12 @@ public class MacroExpander {
t= input.removeFirst(); // don't change l t= input.removeFirst(); // don't change l
continue; continue;
case IToken.tIDENTIFIER: 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 // 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); result.append(t);
} }
else if (forbidden.containsKey(macro)) { else if (forbidden.containsKey(macro)) {
@ -227,7 +331,7 @@ public class MacroExpander {
TokenList replacement= new TokenList(); TokenList replacement= new TokenList();
addSpacemarker(l, t, replacement); // start expansion 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 addSpacemarker(last, input.first(), replacement); // end expansion
input.prepend(replacement); input.prepend(replacement);
@ -262,12 +366,12 @@ public class MacroExpander {
if (l != null && t != null) { if (l != null && t != null) {
final Object s1= l.fSource; final Object s1= l.fSource;
final Object s2= t.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()) { if (l.getEndOffset() == t.getOffset()) {
target.append(new Token(CPreprocessor.tNOSPACE, null, 0, 0)); target.append(new Token(CPreprocessor.tNOSPACE, null, 0, 0));
} }
else { 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. * Expects that the identifier has been consumed.
* @param forbidden * @param forbidden
* @param tracker
* @throws OffsetLimitReachedException * @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 int argCount= macro.getParameterPlaceholderList().length;
final boolean hasVarargs= macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS; final boolean hasVarargs= macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS;
final int requiredArgs= hasVarargs ? argCount-1 : argCount; final int requiredArgs= hasVarargs ? argCount-1 : argCount;
@ -296,6 +402,17 @@ public class MacroExpander {
Token t= input.fetchFirst(); Token t= input.fetchFirst();
if (t == null) { if (t == null) {
break loop; 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; lastToken= t;
switch(t.getType()) { switch(t.getType()) {
@ -414,7 +531,7 @@ public class MacroExpander {
case IToken.tPOUND: case IToken.tPOUND:
addSpacemarker(l, t, result); // start stringify addSpacemarker(l, t, result); // start stringify
StringBuffer buf= new StringBuffer(); StringBuilder buf= new StringBuilder();
buf.append('"'); buf.append('"');
if (n != null && n.getType() == CPreprocessor.tMACRO_PARAMETER) { if (n != null && n.getType() == CPreprocessor.tMACRO_PARAMETER) {
idx= ((TokenParameterReference) n).getIndex(); idx= ((TokenParameterReference) n).getIndex();
@ -441,65 +558,65 @@ public class MacroExpander {
break; break;
case IToken.tPOUNDPOUND: case IToken.tPOUNDPOUND:
if (pasteArg1 != null) { Token pasteArg2= null;
Token pasteArg2= null; TokenList rest= null;
TokenList rest= null; if (n != null) {
if (n != null) { if (n.getType() == CPreprocessor.tMACRO_PARAMETER) {
if (n.getType() == CPreprocessor.tMACRO_PARAMETER) { TokenList arg;
idx= ((TokenParameterReference) n).getIndex(); idx= ((TokenParameterReference) n).getIndex();
if (idx < args.length) { // be defensive if (idx < args.length) { // be defensive
TokenList arg= clone(args[idx]); // gcc-extension
pasteArg2= arg.first(); if (idx == args.length-1 && macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS &&
pasteArg1 != null && pasteArg1.getType() == IToken.tCOMMA) { // no paste operation
// gcc-extension arg= clone(expandedArgs[idx]);
if (idx == args.length-1 && macro.hasVarArgs() != FunctionStyleMacro.NO_VAARGS) { if (arg.first() != null) {
if (pasteArg1.getType() == IToken.tCOMMA) { // no paste operation result.append(pasteArg1);
if (arg.first() != null) { rest= arg;
result.append(pasteArg1);
rest= arg;
}
pasteArg1= pasteArg2= null;
}
} }
pasteArg1= pasteArg2= null;
}
else {
arg= clone(args[idx]);
pasteArg2= arg.first();
if (pasteArg2 != null && arg.first() != arg.last()) { if (pasteArg2 != null && arg.first() != arg.last()) {
rest= arg; rest= arg;
rest.removeFirst(); 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;
if (generated != null) {
if (pasteNext && rest == null) {
pasteArg1= generated; // no need to mark spaces, done ahead
}
else { else {
idx= -1; result.append(generated);
pasteArg2= n; addSpacemarker(pasteArg2, rest == null ? n : rest.first(), result); // end token paste
} }
t= n; }
n= (Token) n.getNext(); if (rest != null) {
pasteNext= n != null && n.getType() == IToken.tPOUNDPOUND; if (pasteNext) {
pasteArg1= rest.last();
generated= tokenpaste(pasteArg1, pasteArg2, macro); if (pasteArg1 != null) {
pasteArg1= null; result.appendAllButLast(rest);
addSpacemarker(result.last(), pasteArg1, result); // start token paste
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) { else {
if (pasteNext) { result.appendAll(rest);
pasteArg1= rest.last(); if (idx >= 0) {
if (pasteArg1 != null) { addSpacemarker(t, n, result); // end argument replacement
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
}
} }
} }
} }
@ -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) { private void objStyleTokenPaste(PreprocessorMacro macro, TokenList result) {
TokenList replacement= clone(macro.getTokens(fDefinitionParser, fLexOptions)); TokenList replacement= clone(macro.getTokens(fDefinitionParser, fLexOptions));
@ -574,6 +738,9 @@ public class MacroExpander {
} }
private Token tokenpaste(Token arg1, Token arg2, PreprocessorMacro macro) { private Token tokenpaste(Token arg1, Token arg2, PreprocessorMacro macro) {
if (arg1 == null) {
return arg2;
}
if (arg2 == null) { if (arg2 == null) {
return arg1; return arg1;
} }
@ -598,7 +765,7 @@ public class MacroExpander {
return null; return null;
} }
private void stringify(TokenList tokenList, StringBuffer buf) { private void stringify(TokenList tokenList, StringBuilder buf) {
Token t= tokenList.first(); Token t= tokenList.first();
if (t == null) { if (t == null) {
return; return;
@ -608,8 +775,7 @@ public class MacroExpander {
boolean space= false; boolean space= false;
for (; t != null; l=t, t=n) { for (; t != null; l=t, t=n) {
n= (Token) t.getNext(); n= (Token) t.getNext();
if (!space && l != null && l.fSource != null && l.fSource == t.fSource && if (!space && hasImplicitSpace(l, t)) {
l.getEndOffset() != t.getOffset()) {
buf.append(' '); buf.append(' ');
space= true; space= true;
} }
@ -695,4 +861,10 @@ public class MacroExpander {
l= t; 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;
}
} }

View file

@ -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;
}
}

View file

@ -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++;
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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 * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -152,13 +152,13 @@ public class PDOMMacro implements IIndexMacro, IASTFileLocation {
try { try {
byte style= pdom.getDB().getByte(record + MACRO_STYLE); byte style= pdom.getDB().getByte(record + MACRO_STYLE);
if (style == MACROSTYLE_FUNCTION) { if (style == MACROSTYLE_FUNCTION) {
List paramList = new ArrayList(); List<char[]> paramList = new ArrayList<char[]>();
PDOMMacroParameter param= getFirstParameter(); PDOMMacroParameter param= getFirstParameter();
while (param != null) { while (param != null) {
paramList.add(param.getName().getChars()); paramList.add(param.getName().getChars());
param = param.getNextParameter(); param = param.getNextParameter();
} }
fParameterList= (char[][])paramList.toArray(new char[paramList.size()][]); fParameterList= paramList.toArray(new char[paramList.size()][]);
} }
} catch (CoreException e) { } catch (CoreException e) {
CCorePlugin.log(e); CCorePlugin.log(e);
@ -285,6 +285,7 @@ public class PDOMMacro implements IIndexMacro, IASTFileLocation {
return null; return null;
} }
@SuppressWarnings("unchecked")
public Object getAdapter(Class adapter) { public Object getAdapter(Class adapter) {
return null; return null;
} }