1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-31 21:05:37 +02:00

Bug 275382. Fix and test case.

This commit is contained in:
Sergey Prigogin 2009-06-27 19:37:38 +00:00
parent e8622b71d8
commit 6a9e1ff1dd
4 changed files with 182 additions and 5 deletions

View file

@ -1313,6 +1313,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
final char[] namechars= name.getCharImage();
macro= fMacroDictionary.get(namechars);
isActive= (macro == null) == isIfndef;
if (macro == null) {
macro = new UndefinedMacro(namechars);
}
}
}

View file

@ -88,7 +88,7 @@ abstract class PreprocessorMacro implements IMacroBinding {
buf.append(getNameCharArray());
buf.append('(');
for (int i = 0; i < p.length; i++) {
if (i>0) {
if (i > 0) {
buf.append(',');
}
buf.append(p[i]);
@ -271,6 +271,29 @@ class FunctionStyleMacro extends ObjectStyleMacro {
}
}
final class UndefinedMacro extends PreprocessorMacro {
public UndefinedMacro(char[] name) {
super(name);
}
@Override
public TokenList getTokens(MacroDefinitionParser parser, LexerOptions lexOptions, MacroExpander expander) {
return null;
}
public char[] getExpansion() {
return null;
}
public char[] getExpansionImage() {
return null;
}
public boolean isDynamic() {
return false;
}
}
abstract class DynamicMacro extends PreprocessorMacro {
public DynamicMacro(char[] name) {
@ -351,11 +374,13 @@ final class LineMacro extends DynamicMacro {
LineMacro(char[] name) {
super(name);
}
@Override
public Token execute(MacroExpander expander) {
int lineNumber= expander.getCurrentLineNumber();
return new TokenWithImage(IToken.tINTEGER, null, 0, 0, Long.toString(lineNumber).toCharArray());
}
public char[] getExpansionImage() {
return new char[] {'1'};
}
@ -387,4 +412,3 @@ final class TimeMacro extends DynamicMacro {
return createDate();
}
}

View file

@ -123,4 +123,17 @@ public class LinkedNamesFinderTest extends AST2BaseTest {
IRegion[] regions3 = getLinkedRegions(code, "~A();", 2, true);
assertTrue(Arrays.equals(regions3, regions));
}
// #ifndef GUARD //1
// #define GUARD //2
// // This is a GUARD test
// #endif // GUARD
public void testIncludeGuards() throws Exception {
String code = getAboveComment();
IRegion[] regions = getLinkedRegions(code, "GUARD //1", 5, true);
assertEquals(3, regions.length);
assertContents(code, regions[0].getOffset(), "GUARD //1");
assertContents(code, regions[1].getOffset(), "GUARD //2");
assertContents(code, regions[2].getOffset() - 3, "// GUARD");
}
}

View file

@ -11,28 +11,41 @@
package org.eclipse.cdt.internal.ui.search;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElseStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorEndifStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfdefStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfndefStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorUndefStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit;
/**
* Finds locations of linked names. Used by Rename in File.
*/
public class LinkedNamesFinder {
private static final IRegion[] EMPTY_LOCATIONS_ARRAY = new IRegion[0];
public LinkedNamesFinder() {
private LinkedNamesFinder() {
super();
}
@ -56,6 +69,11 @@ public class LinkedNamesFinder {
}
public void find(IBinding target) {
if (target instanceof IMacroBinding) {
findMacro((IMacroBinding) target);
return;
}
try {
if (target instanceof ICPPConstructor ||
target instanceof ICPPMethod && ((ICPPMethod) target).isDestructor()) {
@ -132,5 +150,124 @@ public class LinkedNamesFinder {
}
}
}
/**
* Adds all occurrences of a macro name to the list of locations. Macro occurrences
* may belong to multiple macro bindings with the same name. Macro names are also
* looked for in the comments of #else and #endif statements.
* Comments of #else and #endif statements related to #ifdef or #ifndef are searched
* for the macro name referenced by the #if[n]def.
* @param target a binding representing a macro.
*/
private void findMacro(IMacroBinding target) {
findBinding(target);
char[] nameChars = target.getNameCharArray();
List<IASTName> ifdefNameStack = new ArrayList<IASTName>();
IASTPreprocessorStatement[] statements = root.getAllPreprocessorStatements();
for (IASTPreprocessorStatement statement : statements) {
if (!statement.isPartOfTranslationUnitFile()) {
continue;
}
IASTName macroName = null;
boolean ifStatement = false;
if (statement instanceof IASTPreprocessorIfdefStatement) {
macroName = ((IASTPreprocessorIfdefStatement) statement).getMacroReference();
ifStatement = true;
} else if (statement instanceof IASTPreprocessorIfndefStatement) {
macroName = ((IASTPreprocessorIfndefStatement) statement).getMacroReference();
ifStatement = true;
} else if (statement instanceof IASTPreprocessorMacroDefinition) {
macroName = ((IASTPreprocessorMacroDefinition) statement).getName();
} else if (statement instanceof IASTPreprocessorUndefStatement) {
macroName = ((IASTPreprocessorUndefStatement) statement).getMacroName();
} else if (statement instanceof IASTPreprocessorIfStatement) {
ifStatement = true;
} else if (statement instanceof IASTPreprocessorEndifStatement) {
if (!ifdefNameStack.isEmpty())
if (ifdefNameStack.remove(ifdefNameStack.size() - 1) != null) {
findInStatementComment(nameChars, statement);
}
} else if (statement instanceof IASTPreprocessorElseStatement) {
if (!ifdefNameStack.isEmpty())
if (ifdefNameStack.get(ifdefNameStack.size() - 1) != null) {
findInStatementComment(nameChars, statement);
}
}
if (macroName != null) {
if (Arrays.equals(nameChars, macroName.getSimpleID())) {
IBinding binding = macroName.resolveBinding();
if (!target.equals(binding)) {
findBinding(binding);
}
} else {
macroName = null;
}
}
if (ifStatement) {
ifdefNameStack.add(macroName);
}
}
}
/**
* Finds locations of a given name in the comment of a preprocessor statement.
*/
private void findInStatementComment(char[] nameChars, IASTPreprocessorStatement statement) {
IASTFileLocation location = statement.getFileLocation();
IASTComment comment = findComment(location.getNodeOffset() + location.getNodeLength());
if (comment != null &&
comment.getFileLocation().getStartingLineNumber() == location.getStartingLineNumber()) {
findInComment(nameChars, comment);
}
}
/**
* Returns the first comment after the given offset.
* @param startOffset a file offset.
* @return a comment or <code>null</code>, if there are no comments after the offset.
*/
private IASTComment findComment(int startOffset) {
IASTComment[] comments = ((ASTTranslationUnit) root).getComments();
int low = 0;
int high = comments.length;
while (low < high) {
int mid = (low + high) / 2;
int offset = comments[mid].getFileLocation().getNodeOffset();
if (offset < startOffset) {
low = mid + 1;
} else {
high = mid;
if (offset == startOffset) {
break;
}
}
}
return high < comments.length ? comments[high] : null;
}
/**
* Adds all occurrences of a name in a comment to the list of locations.
*/
private void findInComment(char[] name, IASTComment comment) {
char[] text = comment.getComment();
int j = 0;
// First two characters are either /* or //
for (int i = 2; i <= text.length - name.length + j; i++) {
char c = text[i];
if (!Character.isJavaIdentifierPart(c)) {
j = 0;
} else if (j >= 0 && j < name.length && name[j] == c) {
j++;
if (j == name.length &&
(i + 1 == text.length || !Character.isJavaIdentifierPart(text[i + 1]))) {
int offset = comment.getFileLocation().getNodeOffset() + i + 1 - name.length;
locations.add(new Region(offset, name.length));
j = 0;
}
} else {
j = -1;
}
}
}
}
}