1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-10 17:55:39 +02:00

Bug 286081.

This commit is contained in:
Sergey Prigogin 2009-08-16 23:31:33 +00:00
parent 4b2dc9b25f
commit 44d46d0b79

View file

@ -55,7 +55,7 @@ import org.eclipse.cdt.internal.core.parser.scanner.ScannerContext.Conditional;
import org.eclipse.core.runtime.IAdaptable; 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
*/ */
@ -98,7 +98,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
T checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath); T checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath);
} }
final private IIncludeFileTester<IncludeFileContent> createCodeReaderTester= new IIncludeFileTester<IncludeFileContent>() { final private IIncludeFileTester<IncludeFileContent> createCodeReaderTester= new IIncludeFileTester<IncludeFileContent>() {
public IncludeFileContent checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath) { public IncludeFileContent checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath) {
final IncludeFileContent fc= fCodeReaderFactory.getContentForInclusion(path); final IncludeFileContent fc= fCodeReaderFactory.getContentForInclusion(path);
if (fc != null) { if (fc != null) {
@ -108,9 +108,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
return fc; return fc;
} }
}; };
private static class IncludeResolution {String fLocation; boolean fHeuristic;} private static class IncludeResolution {String fLocation; boolean fHeuristic;}
final private IIncludeFileTester<IncludeResolution> createPathTester= new IIncludeFileTester<IncludeResolution>() { final private IIncludeFileTester<IncludeResolution> createPathTester= new IIncludeFileTester<IncludeResolution>() {
public IncludeResolution checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath) { public IncludeResolution checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath) {
if (fCodeReaderFactory.getInclusionExists(path)) { if (fCodeReaderFactory.getInclusionExists(path)) {
IncludeResolution res= new IncludeResolution(); IncludeResolution res= new IncludeResolution();
@ -215,7 +215,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
final String filePath= new String(reader.filename); final String filePath= new String(reader.filename);
configureIncludeSearchPath(new File(filePath).getParentFile(), info); configureIncludeSearchPath(new File(filePath).getParentFile(), info);
setupMacroDictionary(configuration, info, language); setupMacroDictionary(configuration, info, language);
fAllIncludedFiles.add(filePath); fAllIncludedFiles.add(filePath);
ILocationCtx ctx= fLocationMap.pushTranslationUnit(filePath, reader.buffer); ILocationCtx ctx= fLocationMap.pushTranslationUnit(filePath, reader.buffer);
fCodeReaderFactory.reportTranslationUnitFile(filePath); fCodeReaderFactory.reportTranslationUnitFile(filePath);
@ -227,7 +227,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
fPreIncludedFiles= new String[][] {einfo.getMacroFiles(), einfo.getIncludeFiles()}; fPreIncludedFiles= new String[][] {einfo.getMacroFiles(), einfo.getIncludeFiles()};
} }
} }
private IIndexBasedCodeReaderFactory wrapReaderFactory(final ICodeReaderFactory readerFactory) { private IIndexBasedCodeReaderFactory wrapReaderFactory(final ICodeReaderFactory readerFactory) {
if (readerFactory instanceof IIndexBasedCodeReaderFactory) { if (readerFactory instanceof IIndexBasedCodeReaderFactory) {
return (IIndexBasedCodeReaderFactory) readerFactory; return (IIndexBasedCodeReaderFactory) readerFactory;
@ -270,7 +270,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
public void setComputeImageLocations(boolean val) { public void setComputeImageLocations(boolean val) {
fLexOptions.fCreateImageLocations= val; fLexOptions.fCreateImageLocations= val;
} }
public void setContentAssistMode(int offset) { public void setContentAssistMode(int offset) {
fContentAssistLimit= offset; fContentAssistLimit= offset;
fRootLexer.setContentAssistMode(offset); fRootLexer.setContentAssistMode(offset);
@ -291,8 +291,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
Keywords.addKeywordsPreprocessor(fPPKeywords); Keywords.addKeywordsPreprocessor(fPPKeywords);
if (language == ParserLanguage.C) { if (language == ParserLanguage.C) {
Keywords.addKeywordsC(fKeywords); Keywords.addKeywordsC(fKeywords);
} } else {
else {
Keywords.addKeywordsCpp(fKeywords); Keywords.addKeywordsCpp(fKeywords);
} }
CharArrayIntMap additionalKeywords= configuration.getAdditionalKeywords(); CharArrayIntMap additionalKeywords= configuration.getAdditionalKeywords();
@ -324,7 +323,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
for (String qip : quoteIncludeSearchPath) { for (String qip : quoteIncludeSearchPath) {
fIncludeSearchPath[idx++]= new IncludeSearchPathElement(makeAbsolute(directory, qip), true); fIncludeSearchPath[idx++]= new IncludeSearchPathElement(makeAbsolute(directory, qip), true);
} }
} }
} }
if (fIncludeSearchPath == null) { if (fIncludeSearchPath == null) {
fIncludeSearchPath= new IncludeSearchPathElement[searchPath.length]; fIncludeSearchPath= new IncludeSearchPathElement[searchPath.length];
@ -350,20 +349,20 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
fMacroDictionary.put(__TIME__.getNameCharArray(), __TIME__); fMacroDictionary.put(__TIME__.getNameCharArray(), __TIME__);
fMacroDictionary.put(__LINE__.getNameCharArray(), __LINE__); fMacroDictionary.put(__LINE__.getNameCharArray(), __LINE__);
if (lang == ParserLanguage.CPP) if (lang == ParserLanguage.CPP) {
fMacroDictionary.put(__cplusplus.getNameCharArray(), __cplusplus); fMacroDictionary.put(__cplusplus.getNameCharArray(), __cplusplus);
else { } else {
fMacroDictionary.put(__STDC_HOSTED__.getNameCharArray(), __STDC_HOSTED__); fMacroDictionary.put(__STDC_HOSTED__.getNameCharArray(), __STDC_HOSTED__);
fMacroDictionary.put(__STDC_VERSION__.getNameCharArray(), __STDC_VERSION__); fMacroDictionary.put(__STDC_VERSION__.getNameCharArray(), __STDC_VERSION__);
} }
IMacro[] toAdd = config.getAdditionalMacros(); IMacro[] toAdd = config.getAdditionalMacros();
if(toAdd != null) { if (toAdd != null) {
for (final IMacro macro : toAdd) { for (final IMacro macro : toAdd) {
addMacroDefinition(macro.getSignature(), macro.getExpansion()); addMacroDefinition(macro.getSignature(), macro.getExpansion());
} }
} }
final Map<String, String> macroDict= info.getDefinedSymbols(); final Map<String, String> macroDict= info.getDefinedSymbols();
if (macroDict != null) { if (macroDict != null) {
for (Map.Entry<String, String> entry : macroDict.entrySet()) { for (Map.Entry<String, String> entry : macroDict.entrySet()) {
@ -372,7 +371,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
addMacroDefinition(key.toCharArray(), value.toCharArray()); addMacroDefinition(key.toCharArray(), value.toCharArray());
} }
} }
Collection<PreprocessorMacro> predefined= fMacroDictionary.values(); Collection<PreprocessorMacro> predefined= fMacroDictionary.values();
for (PreprocessorMacro macro : predefined) { for (PreprocessorMacro macro : predefined) {
fLocationMap.registerPredefinedMacro(macro); fLocationMap.registerPredefinedMacro(macro);
@ -398,8 +397,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
fCurrentContext= new ScannerContext(ctx, fCurrentContext, new Lexer(buffer, fLexOptions, this, this)); fCurrentContext= new ScannerContext(ctx, fCurrentContext, new Lexer(buffer, fLexOptions, this, this));
ScannerContext preCtx= fCurrentContext; ScannerContext preCtx= fCurrentContext;
try { try {
while(internalFetchToken(preCtx, CHECK_NUMBERS, false).getType() != IToken.tEND_OF_INPUT) { while (internalFetchToken(preCtx, CHECK_NUMBERS, false).getType() != IToken.tEND_OF_INPUT) {
// just eat the tokens // just eat the tokens
} }
final ILocationCtx locationCtx = fCurrentContext.getLocationCtx(); final ILocationCtx locationCtx = fCurrentContext.getLocationCtx();
fLocationMap.popContext(locationCtx); fLocationMap.popContext(locationCtx);
@ -415,8 +414,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
fCurrentContext= new ScannerContext(ctx, fCurrentContext, new Lexer(buffer, fLexOptions, this, this)); fCurrentContext= new ScannerContext(ctx, fCurrentContext, new Lexer(buffer, fLexOptions, this, this));
} }
fPreIncludedFiles= null; fPreIncludedFiles= null;
} }
private char[] createSyntheticFile(String[] files) { private char[] createSyntheticFile(String[] files) {
int totalLength= 0; int totalLength= 0;
final char[] instruction= "#include <".toCharArray(); //$NON-NLS-1$ final char[] instruction= "#include <".toCharArray(); //$NON-NLS-1$
@ -436,7 +435,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
} }
return buffer; return buffer;
} }
public PreprocessorMacro addMacroDefinition(char[] key, char[] value) { public PreprocessorMacro addMacroDefinition(char[] key, char[] value) {
final Lexer lex= new Lexer(key, fLexOptions, ILexerLog.NULL, null); final Lexer lex= new Lexer(key, fLexOptions, ILexerLog.NULL, null);
try { try {
@ -444,13 +443,12 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
fLocationMap.registerPredefinedMacro(result); fLocationMap.registerPredefinedMacro(result);
fMacroDictionary.put(result.getNameCharArray(), result); fMacroDictionary.put(result.getNameCharArray(), result);
return result; return result;
} } catch (Exception e) {
catch (Exception e) {
fLog.traceLog("Invalid macro definition: '" + String.valueOf(key) + "'"); //$NON-NLS-1$//$NON-NLS-2$ fLog.traceLog("Invalid macro definition: '" + String.valueOf(key) + "'"); //$NON-NLS-1$//$NON-NLS-2$
return null; return null;
} }
} }
public Map<String, IMacroBinding> getMacroDefinitions() { public Map<String, IMacroBinding> getMacroDefinitions() {
Map<String, IMacroBinding> hashMap = new HashMap<String, IMacroBinding>(fMacroDictionary.size()); Map<String, IMacroBinding> hashMap = new HashMap<String, IMacroBinding>(fMacroDictionary.size());
for (char[] key : fMacroDictionary.keys()) { for (char[] key : fMacroDictionary.keys()) {
@ -498,14 +496,14 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
t.setNext(null); t.setNext(null);
return t; return t;
} }
private void pushbackToken(Token t) { private void pushbackToken(Token t) {
t.setNext(fPrefetchedTokens); t.setNext(fPrefetchedTokens);
fPrefetchedTokens= t; fPrefetchedTokens= t;
} }
/** /**
* Returns next token for the parser. String literals are not concatenated. When * Returns next token for the parser. String literals are not concatenated. When
* the end is reached tokens with type {@link IToken#tEND_OF_INPUT}. * the end is reached tokens with type {@link IToken#tEND_OF_INPUT}.
* @throws OffsetLimitReachedException see {@link Lexer}. * @throws OffsetLimitReachedException see {@link Lexer}.
*/ */
@ -513,7 +511,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
if (isCancelled) { if (isCancelled) {
throw new ParseError(ParseError.ParseErrorKind.TIMEOUT_OR_CANCELLED); throw new ParseError(ParseError.ParseErrorKind.TIMEOUT_OR_CANCELLED);
} }
Token t1= fetchToken(); Token t1= fetchToken();
switch (t1.getType()) { switch (t1.getType()) {
case IToken.tCOMPLETION: case IToken.tCOMPLETION:
@ -521,7 +519,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
break; break;
case IToken.tEND_OF_INPUT: case IToken.tEND_OF_INPUT:
if (fContentAssistLimit >= 0) { if (fContentAssistLimit >= 0) {
int useType= fHandledCompletion ? IToken.tEOC : IToken.tCOMPLETION; int useType= fHandledCompletion ? IToken.tEOC : IToken.tCOMPLETION;
int sequenceNumber= fLocationMap.getSequenceNumberForOffset(fContentAssistLimit); int sequenceNumber= fLocationMap.getSequenceNumberForOffset(fContentAssistLimit);
t1= new Token(useType, null, sequenceNumber, sequenceNumber); t1= new Token(useType, null, sequenceNumber, sequenceNumber);
fHandledCompletion= true; fHandledCompletion= true;
@ -544,11 +542,11 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
if (isCancelled) { if (isCancelled) {
throw new ParseError(ParseError.ParseErrorKind.TIMEOUT_OR_CANCELLED); throw new ParseError(ParseError.ParseErrorKind.TIMEOUT_OR_CANCELLED);
} }
Token t1= fetchToken(); Token t1= fetchToken();
final int tt1= t1.getType(); final int tt1= t1.getType();
switch(tt1) { switch (tt1) {
case IToken.tCOMPLETION: case IToken.tCOMPLETION:
fHandledCompletion= true; fHandledCompletion= true;
break; break;
@ -557,7 +555,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
if (fContentAssistLimit < 0) { if (fContentAssistLimit < 0) {
throw new EndOfFileException(); throw new EndOfFileException();
} }
int useType= fHandledCompletion ? IToken.tEOC : IToken.tCOMPLETION; int useType= fHandledCompletion ? IToken.tEOC : IToken.tCOMPLETION;
int sequenceNumber= fLocationMap.getSequenceNumberForOffset(fContentAssistLimit); int sequenceNumber= fLocationMap.getSequenceNumberForOffset(fContentAssistLimit);
t1= new Token(useType, null, sequenceNumber, sequenceNumber); t1= new Token(useType, null, sequenceNumber, sequenceNumber);
fHandledCompletion= true; fHandledCompletion= true;
@ -572,10 +570,10 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
Token t2; Token t2;
StringBuffer buf= null; StringBuffer buf= null;
int endOffset= 0; int endOffset= 0;
loop: while(true) { loop: while (true) {
t2= fetchToken(); t2= fetchToken();
final int tt2= t2.getType(); final int tt2= t2.getType();
switch(tt2) { switch (tt2) {
case IToken.tLSTRING: case IToken.tLSTRING:
case IToken.tSTRING: case IToken.tSTRING:
case IToken.tUTF16STRING: case IToken.tUTF16STRING:
@ -602,12 +600,12 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
char[] image= new char[buf.length() + prefix.length + 2]; char[] image= new char[buf.length() + prefix.length + 2];
int off= -1; int off= -1;
for(char c : prefix) for (char c : prefix)
image[++off] = c; image[++off] = c;
image[++off]= '"'; image[++off]= '"';
buf.getChars(0, buf.length(), image, ++off); buf.getChars(0, buf.length(), image, ++off);
image[image.length-1]= '"'; image[image.length - 1]= '"';
t1= new TokenWithImage(st.getTokenValue(), null, t1.getOffset(), endOffset, image); t1= new TokenWithImage(st.getTokenValue(), null, t1.getOffset(), endOffset, image);
} }
} }
@ -618,8 +616,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
fLastToken= t1; fLastToken= t1;
return t1; return t1;
} }
public void skipInactiveCode() throws OffsetLimitReachedException { public void skipInactiveCode() throws OffsetLimitReachedException {
final Lexer lexer= fCurrentContext.getLexer(); final Lexer lexer= fCurrentContext.getLexer();
if (lexer != null) { if (lexer != null) {
@ -631,7 +628,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
} }
} }
public int getCodeBranchNesting() { public int getCodeBranchNesting() {
return fCurrentContext.getCodeBranchNesting(); return fCurrentContext.getCodeBranchNesting();
} }
@ -640,14 +637,14 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
final char[] image= t1.getCharImage(); final char[] image= t1.getCharImage();
final int length= image.length; final int length= image.length;
int start = 1; int start = 1;
for(char c : image) { for (char c : image) {
if(c == '"') if (c == '"')
break; break;
start++; start++;
} }
if (length > 1) { if (length > 1) {
final int diff= image[length-1] == '"' ? length-start-1 : length-start; final int diff= image[length - 1] == '"' ? length - start - 1 : length - start;
if (diff > 0) { if (diff > 0) {
buf.append(image, start, diff); buf.append(image, start, diff);
} }
@ -656,8 +653,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
Token internalFetchToken(final ScannerContext uptoEndOfCtx, int options, boolean withinExpansion) throws OffsetLimitReachedException { Token internalFetchToken(final ScannerContext uptoEndOfCtx, int options, boolean withinExpansion) throws OffsetLimitReachedException {
Token ppToken= fCurrentContext.currentLexerToken(); Token ppToken= fCurrentContext.currentLexerToken();
while(true) { while (true) {
switch(ppToken.getType()) { switch (ppToken.getType()) {
case Lexer.tBEFORE_INPUT: case Lexer.tBEFORE_INPUT:
ppToken= fCurrentContext.nextPPToken(); ppToken= fCurrentContext.nextPPToken();
continue; continue;
@ -670,7 +667,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
continue; continue;
case Lexer.tOTHER_CHARACTER: case Lexer.tOTHER_CHARACTER:
handleProblem(IProblem.SCANNER_BAD_CHARACTER, ppToken.getCharImage(), handleProblem(IProblem.SCANNER_BAD_CHARACTER, ppToken.getCharImage(),
ppToken.getOffset(), ppToken.getEndOffset()); ppToken.getOffset(), ppToken.getEndOffset());
ppToken= fCurrentContext.nextPPToken(); ppToken= fCurrentContext.nextPPToken();
continue; continue;
@ -687,7 +684,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
ppToken= fCurrentContext.currentLexerToken(); ppToken= fCurrentContext.currentLexerToken();
continue; continue;
case IToken.tPOUND: case IToken.tPOUND:
{ {
final Lexer lexer= fCurrentContext.getLexer(); final Lexer lexer= fCurrentContext.getLexer();
if (lexer != null && lexer.currentTokenIsFirstOnLine()) { if (lexer != null && lexer.currentTokenIsFirstOnLine()) {
@ -736,12 +733,12 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
final char[] image= number.getCharImage(); final char[] image= number.getCharImage();
boolean hasExponent = false; boolean hasExponent = false;
// Integer constants written in binary are a non-standard extension // Integer constants written in binary are a non-standard extension
// supported by GCC since 4.3 and by some other C compilers // supported by GCC since 4.3 and by some other C compilers
// They consist of a prefix 0b or 0B, followed by a sequence of 0 and 1 digits // They consist of a prefix 0b or 0B, followed by a sequence of 0 and 1 digits
// see http://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html // see http://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html
boolean isBin = false; boolean isBin = false;
boolean isHex = false; boolean isHex = false;
boolean isOctal = false; boolean isOctal = false;
boolean hasDot= false; boolean hasDot= false;
@ -784,17 +781,17 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
} }
switch (image[pos]) { switch (image[pos]) {
// octal digits // octal digits
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
continue; continue;
// decimal digits // decimal digits
case '8': case '9': case '8': case '9':
if (isOctal) { if (isOctal) {
handleProblem(IProblem.SCANNER_BAD_OCTAL_FORMAT, image, number.getOffset(), number.getEndOffset()); handleProblem(IProblem.SCANNER_BAD_OCTAL_FORMAT, image, number.getOffset(), number.getEndOffset());
return; return;
} }
continue; continue;
// hex digits // hex digits
case 'a': case 'A': case 'b': case 'B': case 'c': case 'C': case 'd': case 'D': case 'f': case 'F': case 'a': case 'A': case 'b': case 'B': case 'c': case 'C': case 'd': case 'D': case 'f': case 'F':
if (isHex && !hasExponent) { if (isHex && !hasExponent) {
@ -843,7 +840,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
break loop; break loop;
} }
} }
// check the suffix // check the suffix
loop: for (; pos < image.length; pos++) { loop: for (; pos < image.length; pos++) {
final char c= image[pos]; final char c= image[pos];
@ -864,31 +861,27 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
// The check for bin has to come before float, otherwise binary integers // The check for bin has to come before float, otherwise binary integers
// with float components get flagged as BAD_FLOATING_POINT // with float components get flagged as BAD_FLOATING_POINT
handleProblem(IProblem.SCANNER_BAD_BINARY_FORMAT, image, number.getOffset(), number.getEndOffset()); handleProblem(IProblem.SCANNER_BAD_BINARY_FORMAT, image, number.getOffset(), number.getEndOffset());
} } else if (isFloat) {
else if (isFloat) {
handleProblem(IProblem.SCANNER_BAD_FLOATING_POINT, image, number.getOffset(), number.getEndOffset()); handleProblem(IProblem.SCANNER_BAD_FLOATING_POINT, image, number.getOffset(), number.getEndOffset());
} } else if (isHex) {
else if (isHex) {
handleProblem(IProblem.SCANNER_BAD_HEX_FORMAT, image, number.getOffset(), number.getEndOffset()); handleProblem(IProblem.SCANNER_BAD_HEX_FORMAT, image, number.getOffset(), number.getEndOffset());
} } else if (isOctal) {
else if (isOctal) {
handleProblem(IProblem.SCANNER_BAD_OCTAL_FORMAT, image, number.getOffset(), number.getEndOffset()); handleProblem(IProblem.SCANNER_BAD_OCTAL_FORMAT, image, number.getOffset(), number.getEndOffset());
} } else {
else {
handleProblem(IProblem.SCANNER_BAD_DECIMAL_FORMAT, image, number.getOffset(), number.getEndOffset()); handleProblem(IProblem.SCANNER_BAD_DECIMAL_FORMAT, image, number.getOffset(), number.getEndOffset());
} }
return; return;
} }
} }
private <T> T findInclusion(final String includeDirective, final boolean quoteInclude, private <T> T findInclusion(final String includeDirective, final boolean quoteInclude,
final boolean includeNext, final String currentFile, final IIncludeFileTester<T> tester) { final boolean includeNext, final String currentFile, final IIncludeFileTester<T> tester) {
T reader = null; T reader = null;
// filename is an absolute path or it is a Linux absolute path on a windows machine // filename is an absolute path or it is a Linux absolute path on a windows machine
if (new File(includeDirective).isAbsolute() || includeDirective.startsWith("/")) { //$NON-NLS-1$ if (new File(includeDirective).isAbsolute() || includeDirective.startsWith("/")) { //$NON-NLS-1$
return tester.checkFile(includeDirective, false, null); return tester.checkFile(includeDirective, false, null);
} }
if (currentFile != null && quoteInclude && !includeNext) { if (currentFile != null && quoteInclude && !includeNext) {
// Check to see if we find a match in the current directory // Check to see if we find a match in the current directory
final File currentDir= new File(currentFile).getParentFile(); final File currentDir= new File(currentFile).getParentFile();
@ -900,10 +893,17 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
} }
} }
} }
// if we're not include_next, then we are looking for the first occurrence of // If we're not include_next, then we are looking for the first occurrence of
// the file, otherwise, we ignore all the paths before the current directory // the file, otherwise, we ignore all the paths before the current directory.
IncludeSearchPathElement searchAfter= includeNext ? fCurrentContext.getFoundOnPath() : null; IncludeSearchPathElement searchAfter= null;
if (includeNext) {
searchAfter = fCurrentContext.getFoundOnPath();
if (searchAfter == null) {
searchAfter = findFileInIncludePath(currentFile, includeDirective);
}
}
for (IncludeSearchPathElement path : fIncludeSearchPath) { for (IncludeSearchPathElement path : fIncludeSearchPath) {
if (searchAfter != null) { if (searchAfter != null) {
if (searchAfter.equals(path)) { if (searchAfter.equals(path)) {
@ -928,6 +928,16 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
return null; return null;
} }
private IncludeSearchPathElement findFileInIncludePath(String file, String includeDirective) {
for (IncludeSearchPathElement path : fIncludeSearchPath) {
String fileLocation = path.getLocation(includeDirective);
if (file.equals(fileLocation)) {
return path;
}
}
return null;
}
@Override @Override
public String toString() { public String toString() {
StringBuffer buffer = new StringBuffer("Scanner @ file:"); //$NON-NLS-1$ StringBuffer buffer = new StringBuffer("Scanner @ file:"); //$NON-NLS-1$
@ -936,27 +946,24 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
buffer.append(fLocationMap.getCurrentLineNumber(fCurrentContext.currentLexerToken().getOffset())); buffer.append(fLocationMap.getCurrentLineNumber(fCurrentContext.currentLexerToken().getOffset()));
return buffer.toString(); return buffer.toString();
} }
private void addMacroDefinition(IIndexMacro macro) { private void addMacroDefinition(IIndexMacro macro) {
try { try {
final char[] expansionImage = macro.getExpansionImage(); final char[] expansionImage = macro.getExpansionImage();
if (expansionImage == null) { if (expansionImage == null) {
// this is an undef // this is an undef
fMacroDictionary.remove(macro.getNameCharArray()); fMacroDictionary.remove(macro.getNameCharArray());
} } else {
else {
PreprocessorMacro result= MacroDefinitionParser.parseMacroDefinition(macro.getNameCharArray(), macro.getParameterList(), expansionImage); PreprocessorMacro result= MacroDefinitionParser.parseMacroDefinition(macro.getNameCharArray(), macro.getParameterList(), expansionImage);
final IASTFileLocation loc= macro.getFileLocation(); final IASTFileLocation loc= macro.getFileLocation();
fLocationMap.registerMacroFromIndex(result, loc, -1); fLocationMap.registerMacroFromIndex(result, loc, -1);
fMacroDictionary.put(result.getNameCharArray(), result); fMacroDictionary.put(result.getNameCharArray(), result);
} }
} } catch (Exception e) {
catch (Exception e) {
fLog.traceLog("Invalid macro definition: '" + macro.getName() + "'"); //$NON-NLS-1$//$NON-NLS-2$ fLog.traceLog("Invalid macro definition: '" + macro.getName() + "'"); //$NON-NLS-1$//$NON-NLS-2$
} }
} }
public ILocationResolver getLocationMap() { public ILocationResolver getLocationMap() {
return fLocationMap; return fLocationMap;
} }
@ -978,7 +985,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
switch (ident.getType()) { switch (ident.getType()) {
case IToken.tCOMPLETION: case IToken.tCOMPLETION:
lexer.nextToken(); lexer.nextToken();
Token completionToken= new TokenWithImage(ident.getType(), null, Token completionToken= new TokenWithImage(ident.getType(), null,
startOffset, ident.getEndOffset(), ("#" + ident.getImage()).toCharArray()); //$NON-NLS-1$ startOffset, ident.getEndOffset(), ("#" + ident.getImage()).toCharArray()); //$NON-NLS-1$
throw new OffsetLimitReachedException(ORIGIN_PREPROCESSOR_DIRECTIVE, completionToken); throw new OffsetLimitReachedException(ORIGIN_PREPROCESSOR_DIRECTIVE, completionToken);
@ -1035,16 +1042,16 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
if (executeIfdef(lexer, startOffset, true, withinExpansion) == CodeState.eSkipInactive) if (executeIfdef(lexer, startOffset, true, withinExpansion) == CodeState.eSkipInactive)
skipOverConditionalCode(lexer, withinExpansion); skipOverConditionalCode(lexer, withinExpansion);
break; break;
case IPreprocessorDirective.ppIf: case IPreprocessorDirective.ppIf:
if (executeIf(lexer, startOffset, false, withinExpansion) == CodeState.eSkipInactive) if (executeIf(lexer, startOffset, false, withinExpansion) == CodeState.eSkipInactive)
skipOverConditionalCode(lexer, withinExpansion); skipOverConditionalCode(lexer, withinExpansion);
break; break;
case IPreprocessorDirective.ppElif: case IPreprocessorDirective.ppElif:
if (executeIf(lexer, startOffset, true, withinExpansion) == CodeState.eSkipInactive) { if (executeIf(lexer, startOffset, true, withinExpansion) == CodeState.eSkipInactive) {
skipOverConditionalCode(lexer, withinExpansion); skipOverConditionalCode(lexer, withinExpansion);
} }
break; break;
case IPreprocessorDirective.ppElse: case IPreprocessorDirective.ppElse:
if (executeElse(lexer, startOffset, withinExpansion) == CodeState.eSkipInactive) { if (executeElse(lexer, startOffset, withinExpansion) == CodeState.eSkipInactive) {
skipOverConditionalCode(lexer, withinExpansion); skipOverConditionalCode(lexer, withinExpansion);
} }
@ -1052,21 +1059,21 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
case IPreprocessorDirective.ppEndif: case IPreprocessorDirective.ppEndif:
executeEndif(lexer, startOffset, withinExpansion); executeEndif(lexer, startOffset, withinExpansion);
break; break;
case IPreprocessorDirective.ppWarning: case IPreprocessorDirective.ppWarning:
case IPreprocessorDirective.ppError: case IPreprocessorDirective.ppError:
int condOffset= lexer.nextToken().getOffset(); int condOffset= lexer.nextToken().getOffset();
condEndOffset= lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); condEndOffset= lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
if (fCurrentContext.getCodeState() == CodeState.eActive) { if (fCurrentContext.getCodeState() == CodeState.eActive) {
int endOffset= lexer.currentToken().getEndOffset(); int endOffset= lexer.currentToken().getEndOffset();
final char[] warning= lexer.getInputChars(condOffset, condEndOffset); final char[] warning= lexer.getInputChars(condOffset, condEndOffset);
final int id= type == IPreprocessorDirective.ppError final int id= type == IPreprocessorDirective.ppError
? IProblem.PREPROCESSOR_POUND_ERROR ? IProblem.PREPROCESSOR_POUND_ERROR
: IProblem.PREPROCESSOR_POUND_WARNING; : IProblem.PREPROCESSOR_POUND_WARNING;
handleProblem(id, warning, condOffset, condEndOffset); handleProblem(id, warning, condOffset, condEndOffset);
fLocationMap.encounterPoundError(startOffset, condOffset, condEndOffset, endOffset); fLocationMap.encounterPoundError(startOffset, condOffset, condEndOffset, endOffset);
} }
break; break;
case IPreprocessorDirective.ppPragma: case IPreprocessorDirective.ppPragma:
condOffset= lexer.nextToken().getOffset(); condOffset= lexer.nextToken().getOffset();
condEndOffset= lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); condEndOffset= lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
if (fCurrentContext.getCodeState() == CodeState.eActive) { if (fCurrentContext.getCodeState() == CodeState.eActive) {
@ -1103,7 +1110,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
char[] headerName= null; char[] headerName= null;
boolean userInclude= true; boolean userInclude= true;
switch(header.getType()) { switch (header.getType()) {
case Lexer.tSYSTEM_HEADER_NAME: case Lexer.tSYSTEM_HEADER_NAME:
userInclude= false; userInclude= false;
headerName = extractHeaderName(header.getCharImage(), '<', '>', nameOffsets); headerName = extractHeaderName(header.getCharImage(), '<', '>', nameOffsets);
@ -1118,12 +1125,12 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
case IToken.tCOMPLETION: case IToken.tCOMPLETION:
throw new OffsetLimitReachedException(ORIGIN_PREPROCESSOR_DIRECTIVE, header); throw new OffsetLimitReachedException(ORIGIN_PREPROCESSOR_DIRECTIVE, header);
case IToken.tIDENTIFIER: case IToken.tIDENTIFIER:
TokenList tl= new TokenList(); TokenList tl= new TokenList();
condEndOffset= nameOffsets[1]= getTokensWithinPPDirective(false, tl, false); condEndOffset= nameOffsets[1]= getTokensWithinPPDirective(false, tl, false);
Token t= tl.first(); Token t= tl.first();
if (t != null) { if (t != null) {
switch(t.getType()) { switch (t.getType()) {
case IToken.tSTRING: case IToken.tSTRING:
headerName = extractHeaderName(t.getCharImage(), '"', '"', new int[]{0,0}); headerName = extractHeaderName(t.getCharImage(), '"', '"', new int[]{0,0});
break; break;
@ -1152,7 +1159,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
condEndOffset= lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); condEndOffset= lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
break; break;
} }
if (headerName == null || headerName.length==0) { if (headerName == null || headerName.length == 0) {
if (active) { if (active) {
handleProblem(IProblem.PREPROCESSOR_INVALID_DIRECTIVE, handleProblem(IProblem.PREPROCESSOR_INVALID_DIRECTIVE,
lexer.getInputChars(poundOffset, condEndOffset), poundOffset, condEndOffset); lexer.getInputChars(poundOffset, condEndOffset), poundOffset, condEndOffset);
@ -1166,18 +1173,19 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
if (!active) { if (!active) {
// test if the include is inactive just because it was included before (bug 167100) // test if the include is inactive just because it was included before (bug 167100)
final IncludeResolution resolved= findInclusion(new String(headerName), userInclude, include_next, getCurrentFilename(), createPathTester); final IncludeResolution resolved= findInclusion(new String(headerName), userInclude, include_next,
getCurrentFilename(), createPathTester);
if (resolved != null && fCodeReaderFactory.hasFileBeenIncludedInCurrentTranslationUnit(resolved.fLocation)) { if (resolved != null && fCodeReaderFactory.hasFileBeenIncludedInCurrentTranslationUnit(resolved.fLocation)) {
path= resolved.fLocation; path= resolved.fLocation;
isHeuristic= resolved.fHeuristic; isHeuristic= resolved.fHeuristic;
} }
} } else {
else { final IncludeFileContent fi= findInclusion(new String(headerName), userInclude, include_next,
final IncludeFileContent fi= findInclusion(new String(headerName), userInclude, include_next, getCurrentFilename(), createCodeReaderTester); getCurrentFilename(), createCodeReaderTester);
if (fi != null) { if (fi != null) {
path= fi.getFileLocation(); path= fi.getFileLocation();
isHeuristic= fi.isFoundByHeuristics(); isHeuristic= fi.isFoundByHeuristics();
switch(fi.getKind()) { switch (fi.getKind()) {
case FOUND_IN_INDEX: case FOUND_IN_INDEX:
processInclusionFromIndex(poundOffset, path, fi); processInclusionFromIndex(poundOffset, path, fi);
break; break;
@ -1186,8 +1194,10 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
if (reader != null && !isCircularInclusion(path)) { if (reader != null && !isCircularInclusion(path)) {
reported= true; reported= true;
fAllIncludedFiles.add(path); fAllIncludedFiles.add(path);
ILocationCtx ctx= fLocationMap.pushInclusion(poundOffset, nameOffsets[0], nameOffsets[1], condEndOffset, reader.buffer, path, headerName, userInclude, isHeuristic, fi.isSource()); ILocationCtx ctx= fLocationMap.pushInclusion(poundOffset, nameOffsets[0], nameOffsets[1],
ScannerContext fctx= new ScannerContext(ctx, fCurrentContext, new Lexer(reader.buffer, fLexOptions, this, this)); condEndOffset, reader.buffer, path, headerName, userInclude, isHeuristic, fi.isSource());
ScannerContext fctx= new ScannerContext(ctx, fCurrentContext, new Lexer(reader.buffer,
fLexOptions, this, this));
fctx.setFoundOnPath(fi.getFoundOnPath()); fctx.setFoundOnPath(fi.getFoundOnPath());
fCurrentContext= fctx; fCurrentContext= fctx;
} }
@ -1196,9 +1206,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
case SKIP_FILE: case SKIP_FILE:
break; break;
} }
} } else {
else { final int len = headerName.length + 2;
final int len = headerName.length+2;
StringBuilder name= new StringBuilder(len); StringBuilder name= new StringBuilder(len);
name.append(userInclude ? '"' : '<'); name.append(userInclude ? '"' : '<');
name.append(headerName); name.append(headerName);
@ -1211,7 +1220,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
} }
if (!reported) { if (!reported) {
fLocationMap.encounterPoundInclude(poundOffset, nameOffsets[0], nameOffsets[1], condEndOffset, headerName, path, userInclude, active, isHeuristic); fLocationMap.encounterPoundInclude(poundOffset, nameOffsets[0], nameOffsets[1], condEndOffset, headerName, path, userInclude, active, isHeuristic);
} }
} }
@ -1227,7 +1236,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
char[] headerName; char[] headerName;
int start= 0; int start= 0;
int length= image.length; int length= image.length;
if (length > 0 && image[length-1] == endDelim) { if (length > 0 && image[length - 1] == endDelim) {
length--; length--;
offsets[1]--; offsets[1]--;
if (length > 0 && image[0] == startDelim) { if (length > 0 && image[0] == startDelim) {
@ -1260,7 +1269,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
fMacroDictionary.put(macrodef.getNameCharArray(), macrodef); fMacroDictionary.put(macrodef.getNameCharArray(), macrodef);
final Token name= fMacroDefinitionParser.getNameToken(); final Token name= fMacroDefinitionParser.getNameToken();
fLocationMap.encounterPoundDefine(startOffset, name.getOffset(), name.getEndOffset(), fLocationMap.encounterPoundDefine(startOffset, name.getOffset(), name.getEndOffset(),
macrodef.getExpansionOffset(), macrodef.getExpansionEndOffset(), isActive, macrodef); macrodef.getExpansionOffset(), macrodef.getExpansionEndOffset(), isActive, macrodef);
} catch (InvalidMacroDefinitionException e) { } catch (InvalidMacroDefinitionException e) {
lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
@ -1335,7 +1344,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
int condEndOffset= lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); int condEndOffset= lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
handleProblem(IProblem.PREPROCESSOR_UNBALANCE_CONDITION, name, startOffset, condEndOffset); handleProblem(IProblem.PREPROCESSOR_UNBALANCE_CONDITION, name, startOffset, condEndOffset);
return fCurrentContext.getCodeState(); return fCurrentContext.getCodeState();
} }
boolean isActive= false; boolean isActive= false;
IASTName[] refs= IASTName.EMPTY_NAME_ARRAY; IASTName[] refs= IASTName.EMPTY_NAME_ARRAY;
@ -1370,7 +1379,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
} }
return fCurrentContext.setBranchState(cond, isActive, withinExpansion, startOffset); return fCurrentContext.setBranchState(cond, isActive, withinExpansion, startOffset);
} }
private CodeState executeElse(final Lexer lexer, final int startOffset,boolean withinExpansion) private CodeState executeElse(final Lexer lexer, final int startOffset,boolean withinExpansion)
throws OffsetLimitReachedException { throws OffsetLimitReachedException {
final int endOffset= lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); final int endOffset= lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
@ -1398,8 +1407,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
/** /**
* Runs the preprocessor on the rest of the line, storing the tokens in the holder supplied. * Runs the preprocessor on the rest of the line, storing the tokens in the holder supplied.
* Macro expansion is reported to the location map. * Macro expansion is reported to the location map.
* In case isCondition is set to <code>true</code>, identifiers with image 'defined' are * In case isCondition is set to <code>true</code>, identifiers with image 'defined' are
* converted to the defined-token and its argument is not macro expanded. * converted to the defined-token and its argument is not macro expanded.
* Returns the end-offset of the last token that was consumed. * Returns the end-offset of the last token that was consumed.
*/ */
@ -1410,9 +1419,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
if (isCondition) if (isCondition)
options |= PROTECT_DEFINED; options |= PROTECT_DEFINED;
loop: while(true) { loop: while (true) {
Token t= internalFetchToken(scannerCtx, options, withinExpansion); Token t= internalFetchToken(scannerCtx, options, withinExpansion);
switch(t.getType()) { switch (t.getType()) {
case IToken.tEND_OF_INPUT: case IToken.tEND_OF_INPUT:
case IToken.tCOMPLETION: case IToken.tCOMPLETION:
scannerCtx.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); // make sure the exception is thrown. scannerCtx.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); // make sure the exception is thrown.
@ -1436,7 +1445,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
// make sure an exception is thrown if we are running content assist at the end of the line // make sure an exception is thrown if we are running content assist at the end of the line
return scannerCtx.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); return scannerCtx.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
} }
private void skipOverConditionalCode(final Lexer lexer, boolean withinExpansion) throws OffsetLimitReachedException { private void skipOverConditionalCode(final Lexer lexer, boolean withinExpansion) throws OffsetLimitReachedException {
CodeState state= CodeState.eSkipInactive; CodeState state= CodeState.eSkipInactive;
while (state == CodeState.eSkipInactive) { while (state == CodeState.eSkipInactive) {
@ -1445,13 +1454,13 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
} }
private CodeState skipBranch(final Lexer lexer, boolean withinExpansion) throws OffsetLimitReachedException { private CodeState skipBranch(final Lexer lexer, boolean withinExpansion) throws OffsetLimitReachedException {
while(true) { while (true) {
final Token pound = lexer.nextDirective(); final Token pound = lexer.nextDirective();
int tt = pound.getType(); int tt = pound.getType();
if (tt != IToken.tPOUND) { if (tt != IToken.tPOUND) {
if (tt == IToken.tCOMPLETION) { if (tt == IToken.tCOMPLETION) {
// completion in inactive code // completion in inactive code
throw new OffsetLimitReachedException(ORIGIN_INACTIVE_CODE, pound); throw new OffsetLimitReachedException(ORIGIN_INACTIVE_CODE, pound);
} }
// must be the end of the lexer // must be the end of the lexer
return CodeState.eActive; return CodeState.eActive;
@ -1461,7 +1470,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
if (tt != IToken.tIDENTIFIER) { if (tt != IToken.tIDENTIFIER) {
if (tt == IToken.tCOMPLETION) { if (tt == IToken.tCOMPLETION) {
// completion in inactive directive // completion in inactive directive
throw new OffsetLimitReachedException(ORIGIN_INACTIVE_CODE, ident); throw new OffsetLimitReachedException(ORIGIN_INACTIVE_CODE, ident);
} }
lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE); lexer.consumeLine(ORIGIN_PREPROCESSOR_DIRECTIVE);
continue; continue;
@ -1506,7 +1515,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
* If applicable the macro is expanded and the resulting tokens are put onto a new context. * If applicable the macro is expanded and the resulting tokens are put onto a new context.
* @param identifier the token where macro expansion may occur. * @param identifier the token where macro expansion may occur.
* @param lexer the input for the expansion. * @param lexer the input for the expansion.
* @param stopAtNewline whether or not tokens to be read are limited to the current line. * @param stopAtNewline whether or not tokens to be read are limited to the current line.
* @param isPPCondition whether the expansion is inside of a preprocessor condition. This * @param isPPCondition whether the expansion is inside of a preprocessor condition. This
* implies a specific handling for the defined token. * implies a specific handling for the defined token.
*/ */
@ -1520,7 +1529,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
if (macro instanceof FunctionStyleMacro) { if (macro instanceof FunctionStyleMacro) {
Token t= lexer.currentToken(); Token t= lexer.currentToken();
if (!stopAtNewline) { if (!stopAtNewline) {
while(t.getType() == Lexer.tNEWLINE) { while (t.getType() == Lexer.tNEWLINE) {
t= lexer.nextToken(); t= lexer.nextToken();
} }
} }
@ -1536,7 +1545,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
final IASTName[] expansions= expander.clearImplicitExpansions(); final IASTName[] expansions= expander.clearImplicitExpansions();
final ImageLocationInfo[] ili= expander.clearImageLocationInfos(); final ImageLocationInfo[] ili= expander.clearImageLocationInfos();
final Token last= replacement.last(); final Token last= replacement.last();
final int length= last == null ? 0 : last.getEndOffset(); final int length= last == null ? 0 : last.getEndOffset();
ILocationCtx ctx= fLocationMap.pushMacroExpansion( ILocationCtx ctx= fLocationMap.pushMacroExpansion(
identifier.getOffset(), identifier.getEndOffset(), lexer.getLastEndOffset(), length, macro, expansions, ili); identifier.getOffset(), identifier.getEndOffset(), lexer.getLastEndOffset(), length, macro, expansions, ili);
fCurrentContext= new ScannerContext(ctx, fCurrentContext, replacement); fCurrentContext= new ScannerContext(ctx, fCurrentContext, replacement);