diff options
author | Sergey Prigogin | 2009-06-27 20:56:12 +0000 |
---|---|---|
committer | Sergey Prigogin | 2009-06-27 20:56:12 +0000 |
commit | 4823be47c376ff9e6f71623ee2632b0a4e9243b8 (patch) | |
tree | 8b00e08b3901f6fed22c2c3f2425624d34f17f80 /core | |
parent | 8adbf250b9381f6cb7f67eb5a727a4b71511b41a (diff) | |
download | org.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')
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; + } + } + } } } |