diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/rename/RenameMoveHeaderRefactoringTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/rename/RenameMoveHeaderRefactoringTest.java index 06a739be753..ec213ccf8d1 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/rename/RenameMoveHeaderRefactoringTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/rename/RenameMoveHeaderRefactoringTest.java @@ -277,47 +277,47 @@ public class RenameMoveHeaderRefactoringTest extends RefactoringTestBase { compareFiles(); } - // original-class.h - //#ifndef ORIGINAL_CLASS_H_ - //#define ORIGINAL_CLASS_H_ + // my-class.h + //#ifndef MY_CLASS_H_ + //#define MY_CLASS_H_ // - //class OriginalClass {}; + //class MyClass {}; // - //#endif // ORIGINAL_CLASS_H_ + //#endif // MY_CLASS_H_ //==================== - // renamed-class.h - //#ifndef RENAMED_CLASS_H_ - //#define RENAMED_CLASS_H_ + // my-new-class.h + //#ifndef MY_NEW_CLASS_H_ + //#define MY_NEW_CLASS_H_ // - //class RenamedClass {}; + //class MyNewClass {}; // - //#endif // RENAMED_CLASS_H_ + //#endif // MY_NEW_CLASS_H_ - // original-class.cpp - //#include "original-class.h" + // my-class.cpp + //#include "my-class.h" // //#include //==================== - // renamed-class.cpp - //#include "renamed-class.h" + // my-new-class.cpp + //#include "my-new-class.h" // //#include - // original-class_test.cpp - //#include "original-class.h" + // my-class_test.cpp + //#include "my-class.h" //==================== - // renamed-class_test.cpp - //#include "renamed-class.h" + // my-new-class_test.cpp + //#include "my-new-class.h" // some-other-file.cpp - //#include "original-class.h" - ///*$*/OriginalClass/*$$*/ a; + //#include "my-class.h" + ///*$*/MyClass/*$$*/ a; //==================== // some-other-file.cpp - //#include "renamed-class.h" - //RenamedClass a; + //#include "my-new-class.h" + //MyNewClass a; public void testClassRename() throws Exception { - executeRenameRefactoring("RenamedClass", true); + executeRenameRefactoring("MyNewClass", true); compareFiles(); } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/CRefactoringMatch.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/CRefactoringMatch.java index 0d80f66fe8c..acc7af19d96 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/CRefactoringMatch.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/CRefactoringMatch.java @@ -25,11 +25,11 @@ public class CRefactoringMatch { public static final int IN_COMMENT = 4; private static String[] LABELS= { - RenameMessages.CRefactoringMatch_label_potentialOccurrence, - RenameMessages.CRefactoringMatch_label_occurrence, + RenameMessages.CRefactoringMatch_label_potentialOccurrences, + RenameMessages.CRefactoringMatch_label_occurrences, "", //$NON-NLS-1$ - RenameMessages.CRefactoringMatch_label_potentialOccurrence, - RenameMessages.CRefactoringMatch_label_comment }; + RenameMessages.CRefactoringMatch_label_potentialOccurrences, + RenameMessages.CRefactoringMatch_label_inComment }; private IFile fFile; private int fOffset; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/HeaderFileReferenceAdjuster.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/HeaderFileReferenceAdjuster.java index 3e8b0bcb3d5..eea99a70aba 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/HeaderFileReferenceAdjuster.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/HeaderFileReferenceAdjuster.java @@ -46,6 +46,7 @@ import org.eclipse.text.edits.InsertEdit; import org.eclipse.text.edits.MultiTextEdit; import org.eclipse.text.edits.ReplaceEdit; import org.eclipse.text.edits.TextEdit; +import org.eclipse.text.edits.TextEditGroup; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.IASTComment; @@ -183,16 +184,25 @@ public class HeaderFileReferenceAdjuster { private void addFileChange(ITranslationUnit tu, List changes, ValidateEditChecker checker, IProgressMonitor pm) throws CoreException { - TextEdit edit = createEdit(tu, pm); - if (edit != null) { + TextEditGroup editGroup = createEdit(tu, pm); + if (editGroup != null) { CTextFileChange fileChange = new CTextFileChange(tu.getElementName(), tu); - fileChange.setEdit(edit); + TextEdit[] edits = editGroup.getTextEdits(); + if (edits.length == 1) { + fileChange.setEdit(edits[0]); + } else { + fileChange.setEdit(new MultiTextEdit()); + for (TextEdit edit : edits) { + fileChange.addEdit(edit); + } + } + fileChange.addTextEditGroup(editGroup); changes.add(fileChange); checker.addFile(fileChange.getFile()); } } - private TextEdit createEdit(ITranslationUnit tu, IProgressMonitor pm) + private TextEditGroup createEdit(ITranslationUnit tu, IProgressMonitor pm) throws CoreException, OperationCanceledException { checkCanceled(pm); @@ -205,7 +215,7 @@ public class HeaderFileReferenceAdjuster { } } - private TextEdit createEdit(IASTTranslationUnit ast, ITranslationUnit tu, IProgressMonitor pm) + private TextEditGroup createEdit(IASTTranslationUnit ast, ITranslationUnit tu, IProgressMonitor pm) throws CoreException, OperationCanceledException { IncludeCreationContext context = new IncludeCreationContext(tu, index); // Adjust the translation unit location in the inclusion context. @@ -216,6 +226,7 @@ public class HeaderFileReferenceAdjuster { String contents = context.getSourceContents(); MultiTextEdit rootEdit = createIncludeGuardEdit(ast, tu, contents); + int numIncludeGuardEdits = rootEdit == null ? 0 : rootEdit.getChildrenSize(); Map affectedIncludes = new IdentityHashMap<>(); IASTPreprocessorIncludeStatement[] existingIncludes = ast.getIncludeDirectives(); @@ -240,152 +251,163 @@ public class HeaderFileReferenceAdjuster { } } } - if (affectedIncludes.isEmpty()) - return rootEdit; - - NodeCommentMap commentedNodeMap = ASTCommenter.getCommentedNodeMap(ast); - IRegion includeRegion = - IncludeUtil.getSafeIncludeReplacementRegion(contents, ast, commentedNodeMap); - - IncludePreferences preferences = context.getPreferences(); - - if (rootEdit == null) - rootEdit = new MultiTextEdit(); - - context.addHeadersIncludedPreviously(existingIncludes); - - if (preferences.allowReordering) { - List modifiedIncludes = new ArrayList<>(); - // Put the changed includes into modifiedIncludes. - for (Entry entry : affectedIncludes.entrySet()) { - IASTPreprocessorIncludeStatement existingInclude = entry.getKey(); - if (IncludeUtil.isContainedInRegion(existingInclude, includeRegion)) { - IPath header = entry.getValue(); - IncludeGroupStyle style = context.getIncludeStyle(header); - IncludeInfo includeInfo = context.createIncludeInfo(header, style); - StyledInclude include = new StyledInclude(header, includeInfo, style, existingInclude); - modifiedIncludes.add(include); - } - } - - Collections.sort(modifiedIncludes, preferences); - - // Populate a list of the existing unchanged includes in the include insertion region. - List mergedIncludes = - IncludeUtil.getIncludesInRegion(existingIncludes, includeRegion, context); - Deque deletes = new ArrayDeque<>(); - // Create text deletes for old locations of the includes that will be changed. - int deleteOffset = -1; - boolean emptyLineEncountered = false; - int j = 0; - for (int i = 0; i < mergedIncludes.size(); i++) { - StyledInclude include = mergedIncludes.get(i); - IASTPreprocessorIncludeStatement existingInclude = include.getExistingInclude(); - int offset = ASTNodes.offset(existingInclude); - boolean previousLineBlank = TextUtil.isPreviousLineBlank(contents, offset); - if (affectedIncludes.containsKey(existingInclude)) { - if (deleteOffset < 0) { - deleteOffset = offset; - } else if (!emptyLineEncountered && previousLineBlank) { - // Preserve the first encountered blank line. - deletes.add(new DeleteEdit(deleteOffset, offset - deleteOffset)); - deleteOffset = -1; + if (!affectedIncludes.isEmpty()) { + NodeCommentMap commentedNodeMap = ASTCommenter.getCommentedNodeMap(ast); + IRegion includeRegion = + IncludeUtil.getSafeIncludeReplacementRegion(contents, ast, commentedNodeMap); + + IncludePreferences preferences = context.getPreferences(); + + if (rootEdit == null) + rootEdit = new MultiTextEdit(); + + context.addHeadersIncludedPreviously(existingIncludes); + + if (preferences.allowReordering) { + List modifiedIncludes = new ArrayList<>(); + // Put the changed includes into modifiedIncludes. + for (Entry entry : affectedIncludes.entrySet()) { + IASTPreprocessorIncludeStatement existingInclude = entry.getKey(); + if (IncludeUtil.isContainedInRegion(existingInclude, includeRegion)) { + IPath header = entry.getValue(); + IncludeGroupStyle style = context.getIncludeStyle(header); + IncludeInfo includeInfo = context.createIncludeInfo(header, style); + StyledInclude include = new StyledInclude(header, includeInfo, style, existingInclude); + modifiedIncludes.add(include); } - emptyLineEncountered |= previousLineBlank; - } else { - if (deleteOffset >= 0) { - if (!emptyLineEncountered && previousLineBlank) { - offset = TextUtil.getPreviousLineStart(contents, offset); + } + + Collections.sort(modifiedIncludes, preferences); + + // Populate a list of the existing unchanged includes in the include insertion region. + List mergedIncludes = + IncludeUtil.getIncludesInRegion(existingIncludes, includeRegion, context); + Deque deletes = new ArrayDeque<>(); + // Create text deletes for old locations of the includes that will be changed. + int deleteOffset = -1; + boolean emptyLineEncountered = false; + int j = 0; + for (int i = 0; i < mergedIncludes.size(); i++) { + StyledInclude include = mergedIncludes.get(i); + IASTPreprocessorIncludeStatement existingInclude = include.getExistingInclude(); + int offset = ASTNodes.offset(existingInclude); + boolean previousLineBlank = TextUtil.isPreviousLineBlank(contents, offset); + if (affectedIncludes.containsKey(existingInclude)) { + if (deleteOffset < 0) { + deleteOffset = offset; + } else if (!emptyLineEncountered && previousLineBlank) { + // Preserve the first encountered blank line. + deletes.add(new DeleteEdit(deleteOffset, offset - deleteOffset)); + deleteOffset = -1; } - deletes.add(new DeleteEdit(deleteOffset, offset - deleteOffset)); - deleteOffset = -1; + emptyLineEncountered |= previousLineBlank; + } else { + if (deleteOffset >= 0) { + if (!emptyLineEncountered && previousLineBlank) { + offset = TextUtil.getPreviousLineStart(contents, offset); + } + deletes.add(new DeleteEdit(deleteOffset, offset - deleteOffset)); + deleteOffset = -1; + } + emptyLineEncountered = false; + if (j < i) + mergedIncludes.set(j, include); + j++; } - emptyLineEncountered = false; - if (j < i) - mergedIncludes.set(j, include); - j++; } - } - while (j < mergedIncludes.size()) { - mergedIncludes.remove(mergedIncludes.size() - 1); - } - if (deleteOffset >= 0) - deletes.add(new DeleteEdit(deleteOffset, includeRegion.getOffset() + includeRegion.getLength() - deleteOffset)); - - // Since the order of existing include statements may not match the include order - // preferences, we find positions for the new include statements by pushing them up - // from the bottom of the include insertion region. - for (StyledInclude include : modifiedIncludes) { - if (IncludeUtil.isContainedInRegion(include.getExistingInclude(), includeRegion)) { - int i = mergedIncludes.size(); - while (--i >= 0 && preferences.compare(include, mergedIncludes.get(i)) < 0) {} - mergedIncludes.add(i + 1, include); + while (j < mergedIncludes.size()) { + mergedIncludes.remove(mergedIncludes.size() - 1); } - } - - int offset = includeRegion.getOffset(); - StringBuilder text = new StringBuilder(); - StyledInclude previousInclude = null; - for (StyledInclude include : mergedIncludes) { - IASTPreprocessorIncludeStatement existingInclude = include.getExistingInclude(); - if (affectedIncludes.containsKey(existingInclude)) { - if (previousInclude != null) { - IASTNode previousNode = previousInclude.getExistingInclude(); - if (!affectedIncludes.containsKey(previousNode)) { - offset = ASTNodes.skipToNextLineAfterNode(contents, previousNode); - flushEditBuffer(offset, text, deletes, rootEdit); - if (contents.charAt(offset - 1) != '\n') - text.append(context.getLineDelimiter()); - } - if (isBlankLineNeededBetween(previousInclude, include, preferences)) { - if (TextUtil.isLineBlank(contents, offset)) { - int oldOffset = offset; - offset = TextUtil.skipToNextLine(contents, offset); - if (offset == oldOffset || contents.charAt(offset - 1) != '\n') + if (deleteOffset >= 0) + deletes.add(new DeleteEdit(deleteOffset, includeRegion.getOffset() + includeRegion.getLength() - deleteOffset)); + + // Since the order of existing include statements may not match the include order + // preferences, we find positions for the new include statements by pushing them up + // from the bottom of the include insertion region. + for (StyledInclude include : modifiedIncludes) { + if (IncludeUtil.isContainedInRegion(include.getExistingInclude(), includeRegion)) { + int i = mergedIncludes.size(); + while (--i >= 0 && preferences.compare(include, mergedIncludes.get(i)) < 0) {} + mergedIncludes.add(i + 1, include); + } + } + + int offset = includeRegion.getOffset(); + StringBuilder text = new StringBuilder(); + StyledInclude previousInclude = null; + for (StyledInclude include : mergedIncludes) { + IASTPreprocessorIncludeStatement existingInclude = include.getExistingInclude(); + if (affectedIncludes.containsKey(existingInclude)) { + if (previousInclude != null) { + IASTNode previousNode = previousInclude.getExistingInclude(); + if (!affectedIncludes.containsKey(previousNode)) { + offset = ASTNodes.skipToNextLineAfterNode(contents, previousNode); + flushEditBuffer(offset, text, deletes, rootEdit); + if (contents.charAt(offset - 1) != '\n') text.append(context.getLineDelimiter()); - } else { - text.append(context.getLineDelimiter()); + } + if (isBlankLineNeededBetween(previousInclude, include, preferences)) { + if (TextUtil.isLineBlank(contents, offset)) { + int oldOffset = offset; + offset = TextUtil.skipToNextLine(contents, offset); + if (offset == oldOffset || contents.charAt(offset - 1) != '\n') + text.append(context.getLineDelimiter()); + } else { + text.append(context.getLineDelimiter()); + } } } - } - text.append(include.getIncludeInfo().composeIncludeStatement()); - List comments = commentedNodeMap.getTrailingCommentsForNode(existingInclude); - for (IASTComment comment : comments) { - text.append(ASTNodes.getPrecedingWhitespaceInLine(contents, comment)); - text.append(comment.getRawSignature()); - } - text.append(context.getLineDelimiter()); - } else { - if (previousInclude != null && affectedIncludes.containsKey(previousInclude.getExistingInclude()) && - isBlankLineNeededBetween(previousInclude, include, preferences) && - TextUtil.findBlankLine(contents, skipDeletedRegion(offset, deletes), ASTNodes.offset(existingInclude)) < 0) { + text.append(include.getIncludeInfo().composeIncludeStatement()); + List comments = commentedNodeMap.getTrailingCommentsForNode(existingInclude); + for (IASTComment comment : comments) { + text.append(ASTNodes.getPrecedingWhitespaceInLine(contents, comment)); + text.append(comment.getRawSignature()); + } text.append(context.getLineDelimiter()); + } else { + if (previousInclude != null && affectedIncludes.containsKey(previousInclude.getExistingInclude()) && + isBlankLineNeededBetween(previousInclude, include, preferences) && + TextUtil.findBlankLine(contents, skipDeletedRegion(offset, deletes), ASTNodes.offset(existingInclude)) < 0) { + text.append(context.getLineDelimiter()); + } + flushEditBuffer(offset, text, deletes, rootEdit); } - flushEditBuffer(offset, text, deletes, rootEdit); + previousInclude = include; } - previousInclude = include; + if (includeRegion.getLength() == 0 && !TextUtil.isLineBlank(contents, includeRegion.getOffset())) { + text.append(context.getLineDelimiter()); + } + offset = includeRegion.getOffset() + includeRegion.getLength(); + flushEditBuffer(offset, text, deletes, rootEdit); } - if (includeRegion.getLength() == 0 && !TextUtil.isLineBlank(contents, includeRegion.getOffset())) { - text.append(context.getLineDelimiter()); - } - offset = includeRegion.getOffset() + includeRegion.getLength(); - flushEditBuffer(offset, text, deletes, rootEdit); - } - - for (IASTPreprocessorIncludeStatement existingInclude : existingIncludes) { - IPath header = affectedIncludes.get(existingInclude); - if (header != null && - (!preferences.allowReordering || !IncludeUtil.isContainedInRegion(existingInclude, includeRegion))) { - IncludeGroupStyle style = context.getIncludeStyle(header); - IncludeInfo includeInfo = context.createIncludeInfo(header, style); - IASTName name = existingInclude.getName(); - int offset = ASTNodes.offset(name) - 1; - int length = ASTNodes.endOffset(name) + 1 - offset; - rootEdit.addChild(new ReplaceEdit(offset, length, includeInfo.toString())); + + for (IASTPreprocessorIncludeStatement existingInclude : existingIncludes) { + IPath header = affectedIncludes.get(existingInclude); + if (header != null && + (!preferences.allowReordering || !IncludeUtil.isContainedInRegion(existingInclude, includeRegion))) { + IncludeGroupStyle style = context.getIncludeStyle(header); + IncludeInfo includeInfo = context.createIncludeInfo(header, style); + IASTName name = existingInclude.getName(); + int offset = ASTNodes.offset(name) - 1; + int length = ASTNodes.endOffset(name) + 1 - offset; + rootEdit.addChild(new ReplaceEdit(offset, length, includeInfo.toString())); + } } } - return rootEdit; + if (rootEdit == null) + return null; + + int numEdits = rootEdit.getChildrenSize(); + String message = + numEdits == numIncludeGuardEdits ? + RenameMessages.HeaderReferenceAdjuster_update_include_guards : + numIncludeGuardEdits == 0 ? + RenameMessages.HeaderReferenceAdjuster_update_includes : + RenameMessages.HeaderReferenceAdjuster_update_include_guards_and_includes; + TextEditGroup editGroup= new TextEditGroup(message, rootEdit); + + return editGroup; } private static boolean isBlankLineNeededBetween(StyledInclude include1, StyledInclude include2, diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/RenameMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/RenameMessages.java index 9b4d3a2d44e..c6c8c3b0d31 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/RenameMessages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/RenameMessages.java @@ -22,9 +22,9 @@ class RenameMessages extends NLS { public static String ASTManager_warning_parsingError_withFile; public static String ASTManager_warning_parsingError_withFileAndLine; public static String ASTManager_warning_parsingError; - public static String CRefactoringMatch_label_comment; - public static String CRefactoringMatch_label_occurrence; - public static String CRefactoringMatch_label_potentialOccurrence; + public static String CRefactoringMatch_label_inComment; + public static String CRefactoringMatch_label_occurrences; + public static String CRefactoringMatch_label_potentialOccurrences; public static String CRefactory_title_rename; public static String CRenameIncludeProcessor_includeDirective; public static String CRenameLocalProcessor_constructor; @@ -99,6 +99,9 @@ class RenameMessages extends NLS { public static String CRenameTopProcessor_wizard_title; public static String HeaderFileMoveParticipant_name; public static String HeaderFileRenameParticipant_name; + public static String HeaderReferenceAdjuster_update_include_guards; + public static String HeaderReferenceAdjuster_update_includes; + public static String HeaderReferenceAdjuster_update_include_guards_and_includes; public static String RenameCSourceFolderChange_ErrorMsg; public static String RenameCSourceFolderChange_Name0; public static String SourceFolderRenameParticipant_name; @@ -124,7 +127,7 @@ class RenameMessages extends NLS { NLS.initializeMessages(RenameMessages.class.getName(), RenameMessages.class); } - // Do not instantiate + // Do not instantiate. private RenameMessages() { } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/RenameMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/RenameMessages.properties index 175d3e4a123..a7c6ccbcadd 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/RenameMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/rename/RenameMessages.properties @@ -18,9 +18,9 @@ ASTManager_warning_parsingError_detailed=Parsing error - {0} - ASTManager_warning_parsingError_withFile={0} in file ''{1}'' ASTManager_warning_parsingError_withFileAndLine={0} in file ''{1}'' at line ''{2}'' ASTManager_warning_parsingError=Parsing error -CRefactoringMatch_label_comment=Rename in comment -CRefactoringMatch_label_occurrence=Rename occurrence -CRefactoringMatch_label_potentialOccurrence=Rename potential occurrence +CRefactoringMatch_label_inComment=Rename in comment +CRefactoringMatch_label_occurrences=Rename occurrences +CRefactoringMatch_label_potentialOccurrences=Rename potential occurrences CRefactory_title_rename=Rename CRenameIncludeProcessor_includeDirective=include directive CRenameLocalProcessor_constructor=Constructor @@ -95,6 +95,9 @@ CRenameTopProcessor_wizard_backup_title=Rename CRenameTopProcessor_wizard_title=Rename ''{0}'' HeaderFileMoveParticipant_name=Header File Move HeaderFileRenameParticipant_name=Header File Rename +HeaderReferenceAdjuster_update_include_guards=Update include guards +HeaderReferenceAdjuster_update_includes=Update includes +HeaderReferenceAdjuster_update_include_guards_and_includes=Update include guards and includes RenameCSourceFolderChange_ErrorMsg=Folder {0} does not exist RenameCSourceFolderChange_Name0=Rename source folder {0} to {1} SourceFolderRenameParticipant_name=Rename C/C++ Source Folder