Skip to main content
aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorSergey Prigogin2009-06-27 20:56:12 +0000
committerSergey Prigogin2009-06-27 20:56:12 +0000
commit4823be47c376ff9e6f71623ee2632b0a4e9243b8 (patch)
tree8b00e08b3901f6fed22c2c3f2425624d34f17f80 /core
parent8adbf250b9381f6cb7f67eb5a727a4b71511b41a (diff)
downloadorg.eclipse.cdt-4823be47c376ff9e6f71623ee2632b0a4e9243b8.tar.gz
org.eclipse.cdt-4823be47c376ff9e6f71623ee2632b0a4e9243b8.tar.xz
org.eclipse.cdt-4823be47c376ff9e6f71623ee2632b0a4e9243b8.zip
Bug 275383. Fix and test case.
Diffstat (limited to 'core')
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java3
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/PreprocessorMacro.java28
-rw-r--r--core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/LinkedNamesFinderTest.java13
-rw-r--r--core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/LinkedNamesFinder.java143
4 files changed, 182 insertions, 5 deletions
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
index 2f229daf857..c85cf94da7d 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
@@ -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);
+ }
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/PreprocessorMacro.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/PreprocessorMacro.java
index ee69e3f29be..8d0384b7489 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/PreprocessorMacro.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/PreprocessorMacro.java
@@ -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();
}
}
-
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/LinkedNamesFinderTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/LinkedNamesFinderTest.java
index 03670e5a033..2970cd2a847 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/LinkedNamesFinderTest.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/search/LinkedNamesFinderTest.java
@@ -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");
+ }
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/LinkedNamesFinder.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/LinkedNamesFinder.java
index afc63403659..0eb79982e00 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/LinkedNamesFinder.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/search/LinkedNamesFinder.java
@@ -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];
+ private static final IRegion[] EMPTY_LOCATIONS_ARRAY = new IRegion[0];
- public LinkedNamesFinder() {
+ private LinkedNamesFinder() {
super();
}
@@ -49,13 +62,18 @@ public class LinkedNamesFinder {
private static class BindingFinder {
private final IASTTranslationUnit root;
private final List<IRegion> locations;
-
+
public BindingFinder(IASTTranslationUnit root) {
this.root = root;
locations = new ArrayList<IRegion>();
}
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;
+ }
+ }
+ }
}
}

Back to the top