diff --git a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/reducer/RemoveFunctionBodiesRefactoring.java b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/reducer/RemoveFunctionBodiesRefactoring.java index 5a2da7bb723..73bf5857b8c 100644 --- a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/reducer/RemoveFunctionBodiesRefactoring.java +++ b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/reducer/RemoveFunctionBodiesRefactoring.java @@ -61,6 +61,7 @@ import org.eclipse.cdt.internal.ui.refactoring.changes.CCompositeChange; import org.eclipse.cdt.internal.ui.refactoring.utils.SelectionHelper; public class RemoveFunctionBodiesRefactoring extends CRefactoring { + private static final String PROTECTION_TOKEN = "PRESERVE"; private INodeFactory nodeFactory; private final DefaultCodeFormatterOptions formattingOptions; @@ -124,7 +125,7 @@ public class RemoveFunctionBodiesRefactoring extends CRefactoring { CTextFileChange fileChange = new CTextFileChange(tu.getElementName(), tu); fileChange.setEdit(new MultiTextEdit()); for (IASTFunctionDefinition definition : finder.functionDefinitions) { - if (!SelectionHelper.isNodeInsideRegion(definition, region)) + if (!SelectionHelper.isNodeInsideRegion(definition, region) || containsProtectionToken(definition, code)) continue; IASTStatement body = definition.getBody(); IASTName name = definition.getDeclarator().getName(); @@ -170,6 +171,19 @@ public class RemoveFunctionBodiesRefactoring extends CRefactoring { return change; } + /** + * Checks if the node or the rest of its last line contain text matching {@link #PROTECTION_TOKEN}. + */ + private boolean containsProtectionToken(IASTNode node, String code) { + int offset = ASTNodes.offset(node); + int endOffset = ASTNodes.skipToNextLineAfterNode(code, node); + for (int i = offset; i < endOffset - PROTECTION_TOKEN.length(); i++) { + if (code.regionMatches(i, PROTECTION_TOKEN, 0, PROTECTION_TOKEN.length())) + return true; + } + return false; + } + private static int skipWhitespaceBefore(int offset, String text) { while (--offset >= 0) { char c = text.charAt(offset); diff --git a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/reducer/RemoveUnusedDeclarationsRefactoring.java b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/reducer/RemoveUnusedDeclarationsRefactoring.java index 1167f6f9302..09b6632f585 100644 --- a/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/reducer/RemoveUnusedDeclarationsRefactoring.java +++ b/core/org.eclipse.cdt.ui.tests/src/org/eclipse/cdt/ui/tests/reducer/RemoveUnusedDeclarationsRefactoring.java @@ -98,6 +98,7 @@ import org.eclipse.cdt.internal.ui.refactoring.changes.CCompositeChange; import org.eclipse.cdt.internal.ui.refactoring.utils.SelectionHelper; public class RemoveUnusedDeclarationsRefactoring extends CRefactoring { + private static final String PROTECTION_TOKEN = "PRESERVE"; private static final IASTName UNUSED_NAME = new CPPASTName(null); private static final ProblemFinder problemFinder = new ProblemFinder(); @@ -160,11 +161,14 @@ public class RemoveUnusedDeclarationsRefactoring extends CRefactoring { // it is too slow for the gigantic changes this refactoring has to deal with. NavigableSet names = NameCollector.getContainedNames(ast); + String code = ast.getRawSignature(); + SortedNodeSet nodesToDelete = new SortedNodeSet<>(); IASTPreprocessorMacroExpansion[] macroExpansions = ast.getMacroExpansions(); for (IASTPreprocessorMacroExpansion macroExpansion : macroExpansions) { IASTName name = macroExpansion.getMacroReference(); if (SelectionHelper.isNodeInsideRegion(name, region) + && !containsProtectionToken(name, code) && macroExpansion.getMacroDefinition().getExpansion().isEmpty()) { nodesToDelete.add(macroExpansion); } @@ -177,6 +181,7 @@ public class RemoveUnusedDeclarationsRefactoring extends CRefactoring { for (int i = declarations.size(); --i >= 0;) { IASTDeclaration declaration = declarations.get(i); if (SelectionHelper.isNodeInsideRegion(declaration, region) + && !containsProtectionToken(declaration, code) && !problemFinder.containsProblemBinding(declaration) && !isPossiblyUsed(declaration, names, nodesToDelete)) { nodesToDelete.add(declaration); @@ -184,7 +189,6 @@ public class RemoveUnusedDeclarationsRefactoring extends CRefactoring { } } - String code = ast.getRawSignature(); CTextFileChange fileChange = new CTextFileChange(tu.getElementName(), tu); fileChange.setEdit(new MultiTextEdit()); @@ -215,6 +219,19 @@ public class RemoveUnusedDeclarationsRefactoring extends CRefactoring { return change; } + /** + * Checks if the node or the rest of its last line contain text matching {@link #PROTECTION_TOKEN}. + */ + private boolean containsProtectionToken(IASTNode node, String code) { + int offset = ASTNodes.offset(node); + int endOffset = ASTNodes.skipToNextLineAfterNode(code, node); + for (int i = offset; i < endOffset - PROTECTION_TOKEN.length(); i++) { + if (code.regionMatches(i, PROTECTION_TOKEN, 0, PROTECTION_TOKEN.length())) + return true; + } + return false; + } + private boolean containsAncestor(Collection nodes, IASTNode node) { while ((node = node.getParent()) != null) { if (nodes.contains(node))