mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Automatic update of include statements and include guards when header
files are renamed or moved.
This commit is contained in:
parent
cf4556f05f
commit
d962e2eee7
30 changed files with 1580 additions and 379 deletions
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
||||||
Bundle-ManifestVersion: 2
|
Bundle-ManifestVersion: 2
|
||||||
Bundle-Name: %pluginName
|
Bundle-Name: %pluginName
|
||||||
Bundle-SymbolicName: org.eclipse.cdt.core; singleton:=true
|
Bundle-SymbolicName: org.eclipse.cdt.core; singleton:=true
|
||||||
Bundle-Version: 5.7.0.qualifier
|
Bundle-Version: 5.8.0.qualifier
|
||||||
Bundle-Activator: org.eclipse.cdt.core.CCorePlugin
|
Bundle-Activator: org.eclipse.cdt.core.CCorePlugin
|
||||||
Bundle-Vendor: %providerName
|
Bundle-Vendor: %providerName
|
||||||
Bundle-Localization: plugin
|
Bundle-Localization: plugin
|
||||||
|
|
|
@ -77,7 +77,8 @@ public class WorkingCopy extends TranslationUnit implements IWorkingCopy {
|
||||||
CommitWorkingCopyOperation op= new CommitWorkingCopyOperation(this, force);
|
CommitWorkingCopyOperation op= new CommitWorkingCopyOperation(this, force);
|
||||||
op.runOperation(monitor);
|
op.runOperation(monitor);
|
||||||
} else {
|
} else {
|
||||||
String contents = this.getSource();
|
IBuffer buffer = getBuffer();
|
||||||
|
String contents = buffer.getContents();
|
||||||
if (contents == null)
|
if (contents == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -502,54 +502,6 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat
|
||||||
return fSizeofCalculator;
|
return fSizeofCalculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the offset of the given node, or -1 if the node is not part of the translation
|
|
||||||
* unit file or doesn't have a file-location.
|
|
||||||
* @see IASTNode#getFileLocation()
|
|
||||||
*/
|
|
||||||
public static int getNodeOffset(IASTNode node) {
|
|
||||||
if (!node.isPartOfTranslationUnitFile())
|
|
||||||
return -1;
|
|
||||||
IASTFileLocation nodeLocation = node.getFileLocation();
|
|
||||||
return nodeLocation != null ? nodeLocation.getNodeOffset() : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the end offset of the given node, or -1 if the node is not part of the translation
|
|
||||||
* unit file or doesn't have a file-location.
|
|
||||||
* @see IASTNode#getFileLocation()
|
|
||||||
*/
|
|
||||||
public static int getNodeEndOffset(IASTNode node) {
|
|
||||||
if (!node.isPartOfTranslationUnitFile())
|
|
||||||
return -1;
|
|
||||||
IASTFileLocation nodeLocation = node.getFileLocation();
|
|
||||||
return nodeLocation != null ? nodeLocation.getNodeOffset() + nodeLocation.getNodeLength() : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the 1-based starting line number of the given node, or 0 if the node is not part of
|
|
||||||
* the translation unit file or doesn't have a file-location.
|
|
||||||
* @see IASTNode#getFileLocation()
|
|
||||||
*/
|
|
||||||
public static int getStartingLineNumber(IASTNode node) {
|
|
||||||
if (!node.isPartOfTranslationUnitFile())
|
|
||||||
return 0;
|
|
||||||
IASTFileLocation nodeLocation = node.getFileLocation();
|
|
||||||
return nodeLocation != null ? nodeLocation.getStartingLineNumber() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the 1-based ending line number of the given node, or 0 if the node is not part of
|
|
||||||
* the translation unit file or doesn't have a file-location.
|
|
||||||
* @see IASTNode#getFileLocation()
|
|
||||||
*/
|
|
||||||
public static int getEndingLineNumber(IASTNode node) {
|
|
||||||
if (!node.isPartOfTranslationUnitFile())
|
|
||||||
return 0;
|
|
||||||
IASTFileLocation nodeLocation = node.getFileLocation();
|
|
||||||
return nodeLocation != null ? nodeLocation.getEndingLineNumber() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNodesOmitted() {
|
public boolean hasNodesOmitted() {
|
||||||
return fNodesOmitted;
|
return fNodesOmitted;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2012 Google, Inc and others.
|
* Copyright (c) 2012, 2014 Google, Inc and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -10,8 +10,6 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.internal.core.dom.rewrite.util;
|
package org.eclipse.cdt.internal.core.dom.rewrite.util;
|
||||||
|
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit.getNodeEndOffset;
|
|
||||||
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
|
|
||||||
|
@ -24,18 +22,51 @@ public class ASTNodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the offset of an AST node.
|
* Returns the offset of the given node, or -1 if the node is not part of the translation
|
||||||
|
* unit file or doesn't have a file-location.
|
||||||
|
* @see IASTNode#getFileLocation()
|
||||||
*/
|
*/
|
||||||
public static int offset(IASTNode node) {
|
public static int offset(IASTNode node) {
|
||||||
return node.getFileLocation().getNodeOffset();
|
if (!node.isPartOfTranslationUnitFile())
|
||||||
|
return -1;
|
||||||
|
IASTFileLocation nodeLocation = node.getFileLocation();
|
||||||
|
return nodeLocation != null ? nodeLocation.getNodeOffset() : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the exclusive end offset of an AST node.
|
* Returns the end offset of the given node, or -1 if the node is not part of the translation
|
||||||
|
* unit file or doesn't have a file-location.
|
||||||
|
* @see IASTNode#getFileLocation()
|
||||||
*/
|
*/
|
||||||
public static int endOffset(IASTNode node) {
|
public static int endOffset(IASTNode node) {
|
||||||
IASTFileLocation location = node.getFileLocation();
|
if (!node.isPartOfTranslationUnitFile())
|
||||||
return location.getNodeOffset() + location.getNodeLength();
|
return -1;
|
||||||
|
IASTFileLocation nodeLocation = node.getFileLocation();
|
||||||
|
return nodeLocation != null ? nodeLocation.getNodeOffset() + nodeLocation.getNodeLength() : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the 1-based starting line number of the given node, or 0 if the node is not part of
|
||||||
|
* the translation unit file or doesn't have a file-location.
|
||||||
|
* @see IASTNode#getFileLocation()
|
||||||
|
*/
|
||||||
|
public static int getStartingLineNumber(IASTNode node) {
|
||||||
|
if (!node.isPartOfTranslationUnitFile())
|
||||||
|
return 0;
|
||||||
|
IASTFileLocation nodeLocation = node.getFileLocation();
|
||||||
|
return nodeLocation != null ? nodeLocation.getStartingLineNumber() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the 1-based ending line number of the given node, or 0 if the node is not part of
|
||||||
|
* the translation unit file or doesn't have a file-location.
|
||||||
|
* @see IASTNode#getFileLocation()
|
||||||
|
*/
|
||||||
|
public static int getEndingLineNumber(IASTNode node) {
|
||||||
|
if (!node.isPartOfTranslationUnitFile())
|
||||||
|
return 0;
|
||||||
|
IASTFileLocation nodeLocation = node.getFileLocation();
|
||||||
|
return nodeLocation != null ? nodeLocation.getEndingLineNumber() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,6 +74,25 @@ public class ASTNodes {
|
||||||
* offset if there is no line delimiter after the node.
|
* offset if there is no line delimiter after the node.
|
||||||
*/
|
*/
|
||||||
public static int skipToNextLineAfterNode(String text, IASTNode node) {
|
public static int skipToNextLineAfterNode(String text, IASTNode node) {
|
||||||
return TextUtil.skipToNextLine(text, getNodeEndOffset(node));
|
return TextUtil.skipToNextLine(text, endOffset(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the whitespace preceding the given node. The newline character in not considered
|
||||||
|
* whitespace for the purpose of this method.
|
||||||
|
*/
|
||||||
|
public static String getPrecedingWhitespaceInLine(String text, IASTNode node) {
|
||||||
|
int offset = offset(node);
|
||||||
|
if (offset >= 0) {
|
||||||
|
int i = offset;
|
||||||
|
while (--i >= 0) {
|
||||||
|
char c = text.charAt(i);
|
||||||
|
if (c == '\n' || !Character.isWhitespace(c))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
return text.substring(i, offset);
|
||||||
|
}
|
||||||
|
return ""; //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,17 @@ public class TextUtil {
|
||||||
return offset + 1;
|
return offset + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the offset of the beginning of the line before the one containing the given offset,
|
||||||
|
* or the beginning of the line containing the given offset if it is first in the text.
|
||||||
|
*/
|
||||||
|
public static int getPreviousLineStart(String text, int offset) {
|
||||||
|
offset = getLineStart(text, offset);
|
||||||
|
if (offset != 0)
|
||||||
|
offset = getLineStart(text, offset);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@code true} if the line corresponding to the given {@code offset} does not contain
|
* Returns {@code true} if the line corresponding to the given {@code offset} does not contain
|
||||||
* non-whitespace characters.
|
* non-whitespace characters.
|
||||||
|
@ -80,4 +91,23 @@ public class TextUtil {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the beginning offset of the first blank line contained between the two given offsets.
|
||||||
|
* Returns -1, if not found.
|
||||||
|
*/
|
||||||
|
public static int findBlankLine(String text, int startOffset, int endOffset) {
|
||||||
|
int blankOffset = startOffset == 0 || text.charAt(startOffset - 1) == '\n' ? startOffset : -1;
|
||||||
|
while (startOffset < endOffset) {
|
||||||
|
char c = text.charAt(startOffset++);
|
||||||
|
if (c == '\n') {
|
||||||
|
if (blankOffset >= 0)
|
||||||
|
return blankOffset;
|
||||||
|
blankOffset = startOffset;
|
||||||
|
} else if (!Character.isWhitespace(c)) {
|
||||||
|
blankOffset = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<version>5.7.0-SNAPSHOT</version>
|
<version>5.8.0-SNAPSHOT</version>
|
||||||
<artifactId>org.eclipse.cdt.core</artifactId>
|
<artifactId>org.eclipse.cdt.core</artifactId>
|
||||||
<packaging>eclipse-plugin</packaging>
|
<packaging>eclipse-plugin</packaging>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2012, 2013 Google, Inc and others.
|
* Copyright (c) 2012, 2014 Google, Inc and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -17,9 +17,11 @@ import java.io.StringReader;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.eclipse.core.filesystem.URIUtil;
|
import org.eclipse.core.filesystem.URIUtil;
|
||||||
import org.eclipse.core.resources.IFile;
|
import org.eclipse.core.resources.IFile;
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.resources.IResource;
|
import org.eclipse.core.resources.IResource;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
import org.eclipse.core.runtime.Path;
|
import org.eclipse.core.runtime.Path;
|
||||||
|
@ -42,6 +44,7 @@ import org.eclipse.cdt.core.model.CoreModel;
|
||||||
import org.eclipse.cdt.core.model.ICProject;
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
import org.eclipse.cdt.core.testplugin.CProjectHelper;
|
import org.eclipse.cdt.core.testplugin.CProjectHelper;
|
||||||
|
import org.eclipse.cdt.core.testplugin.TestScannerProvider;
|
||||||
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
|
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
|
||||||
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
|
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
|
||||||
import org.eclipse.cdt.ui.CUIPlugin;
|
import org.eclipse.cdt.ui.CUIPlugin;
|
||||||
|
@ -55,6 +58,7 @@ import org.eclipse.cdt.internal.ui.refactoring.CRefactoringContext;
|
||||||
* Common base for refactoring tests.
|
* Common base for refactoring tests.
|
||||||
*/
|
*/
|
||||||
public abstract class RefactoringTestBase extends BaseTestCase {
|
public abstract class RefactoringTestBase extends BaseTestCase {
|
||||||
|
private static final Pattern FILENAME_PATTERN = Pattern.compile("^(\\w+/)*\\w+\\.\\w+$");
|
||||||
/** Allows empty files to be created during test setup. */
|
/** Allows empty files to be created during test setup. */
|
||||||
protected boolean createEmptyFiles = true;
|
protected boolean createEmptyFiles = true;
|
||||||
/** See {@link PreferenceConstants.CLASS_MEMBER_ASCENDING_VISIBILITY_ORDER} */
|
/** See {@link PreferenceConstants.CLASS_MEMBER_ASCENDING_VISIBILITY_ORDER} */
|
||||||
|
@ -67,7 +71,7 @@ public abstract class RefactoringTestBase extends BaseTestCase {
|
||||||
|
|
||||||
private boolean cpp = true;
|
private boolean cpp = true;
|
||||||
private ICProject cproject;
|
private ICProject cproject;
|
||||||
private final Set<TestSourceFile> testFiles = new LinkedHashSet<TestSourceFile>();
|
private final Set<TestSourceFile> testFiles = new LinkedHashSet<>();
|
||||||
private TestSourceFile selectedFile;
|
private TestSourceFile selectedFile;
|
||||||
private TextSelection selection;
|
private TextSelection selection;
|
||||||
private TestSourceFile historyScript;
|
private TestSourceFile historyScript;
|
||||||
|
@ -87,22 +91,41 @@ public abstract class RefactoringTestBase extends BaseTestCase {
|
||||||
cproject = cpp ?
|
cproject = cpp ?
|
||||||
CProjectHelper.createCCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER) :
|
CProjectHelper.createCCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER) :
|
||||||
CProjectHelper.createCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER);
|
CProjectHelper.createCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER);
|
||||||
|
TestScannerProvider.sLocalIncludes = new String[] { cproject.getProject().getLocation().toOSString() };
|
||||||
|
|
||||||
Bundle bundle = CTestPlugin.getDefault().getBundle();
|
Bundle bundle = CTestPlugin.getDefault().getBundle();
|
||||||
CharSequence[] testData = TestSourceReader.getContentsForTest(bundle, "ui", getClass(), getName(), 0);
|
CharSequence[] testData = TestSourceReader.getContentsForTest(bundle, "ui", getClass(), getName(), 0);
|
||||||
|
|
||||||
for (CharSequence contents : testData) {
|
for (CharSequence contents : testData) {
|
||||||
TestSourceFile testFile = null;
|
TestSourceFile testFile = null;
|
||||||
|
boolean firstAfterDelimiter = false;
|
||||||
boolean expectedResult = false;
|
boolean expectedResult = false;
|
||||||
BufferedReader reader = new BufferedReader(new StringReader(contents.toString()));
|
BufferedReader reader = new BufferedReader(new StringReader(contents.toString()));
|
||||||
String line;
|
String line;
|
||||||
while ((line = reader.readLine()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
String trimmedLine = line.trim();
|
String trimmedLine = line.trim();
|
||||||
if (testFile == null) {
|
if (testFile == null) {
|
||||||
assertTrue("Invalid file name \"" + trimmedLine + "\"", trimmedLine.matches("^(\\w+/)*\\w+\\.\\w+$"));
|
if (isResultDelimiter(trimmedLine)) {
|
||||||
testFile = new TestSourceFile(trimmedLine);
|
expectedResult = true;
|
||||||
|
firstAfterDelimiter = true;
|
||||||
|
testFile = new TestSourceFile(null);
|
||||||
|
} else {
|
||||||
|
assertTrue("Invalid file name \"" + trimmedLine + "\"",
|
||||||
|
FILENAME_PATTERN.matcher(trimmedLine).matches());
|
||||||
|
testFile = new TestSourceFile(trimmedLine);
|
||||||
|
}
|
||||||
} else if (isResultDelimiter(trimmedLine)) {
|
} else if (isResultDelimiter(trimmedLine)) {
|
||||||
expectedResult = true;
|
expectedResult = true;
|
||||||
|
firstAfterDelimiter = true;
|
||||||
} else if (expectedResult) {
|
} else if (expectedResult) {
|
||||||
|
if (firstAfterDelimiter) {
|
||||||
|
firstAfterDelimiter = false;
|
||||||
|
if (FILENAME_PATTERN.matcher(trimmedLine).matches()) {
|
||||||
|
testFile.setExpectedName(trimmedLine);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(testFile.getExpectedName() != null);
|
||||||
testFile.addLineToExpectedSource(line);
|
testFile.addLineToExpectedSource(line);
|
||||||
} else {
|
} else {
|
||||||
testFile.addLineToSource(line);
|
testFile.addLineToSource(line);
|
||||||
|
@ -110,7 +133,7 @@ public abstract class RefactoringTestBase extends BaseTestCase {
|
||||||
}
|
}
|
||||||
reader.close();
|
reader.close();
|
||||||
|
|
||||||
if (createEmptyFiles || !testFile.getSource().isEmpty()) {
|
if (testFile.getName() != null && (createEmptyFiles || !testFile.getSource().isEmpty())) {
|
||||||
TestSourceReader.createFile(cproject.getProject(), new Path(testFile.getName()),
|
TestSourceReader.createFile(cproject.getProject(), new Path(testFile.getName()),
|
||||||
testFile.getSource());
|
testFile.getSource());
|
||||||
}
|
}
|
||||||
|
@ -149,7 +172,7 @@ public abstract class RefactoringTestBase extends BaseTestCase {
|
||||||
executeRefactoring(false);
|
executeRefactoring(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeRefactoring(boolean expectedSuccess) throws Exception {
|
protected void executeRefactoring(boolean expectedSuccess) throws Exception {
|
||||||
if (ascendingVisibilityOrder) {
|
if (ascendingVisibilityOrder) {
|
||||||
getPreferenceStore().setValue(PreferenceConstants.CLASS_MEMBER_ASCENDING_VISIBILITY_ORDER,
|
getPreferenceStore().setValue(PreferenceConstants.CLASS_MEMBER_ASCENDING_VISIBILITY_ORDER,
|
||||||
ascendingVisibilityOrder);
|
ascendingVisibilityOrder);
|
||||||
|
@ -169,6 +192,11 @@ public abstract class RefactoringTestBase extends BaseTestCase {
|
||||||
executeRefactoring(refactoring, context, true, expectedSuccess);
|
executeRefactoring(refactoring, context, true, expectedSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void executeRefactoring(Refactoring refactoring, boolean expectedSuccess)
|
||||||
|
throws CoreException, Exception {
|
||||||
|
executeRefactoring(refactoring, null, false, expectedSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
protected void executeRefactoring(Refactoring refactoring, RefactoringContext context,
|
protected void executeRefactoring(Refactoring refactoring, RefactoringContext context,
|
||||||
boolean withUserInput, boolean expectedSuccess) throws CoreException, Exception {
|
boolean withUserInput, boolean expectedSuccess) throws CoreException, Exception {
|
||||||
try {
|
try {
|
||||||
|
@ -232,6 +260,10 @@ public abstract class RefactoringTestBase extends BaseTestCase {
|
||||||
return cproject;
|
return cproject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected IProject getProject() {
|
||||||
|
return cproject.getProject();
|
||||||
|
}
|
||||||
|
|
||||||
protected TestSourceFile getSelectedTestFile() {
|
protected TestSourceFile getSelectedTestFile() {
|
||||||
return selectedFile;
|
return selectedFile;
|
||||||
}
|
}
|
||||||
|
@ -348,7 +380,7 @@ public abstract class RefactoringTestBase extends BaseTestCase {
|
||||||
protected void compareFiles() throws Exception {
|
protected void compareFiles() throws Exception {
|
||||||
for (TestSourceFile testFile : testFiles) {
|
for (TestSourceFile testFile : testFiles) {
|
||||||
String expectedSource = testFile.getExpectedSource();
|
String expectedSource = testFile.getExpectedSource();
|
||||||
IFile file = cproject.getProject().getFile(new Path(testFile.getName()));
|
IFile file = cproject.getProject().getFile(new Path(testFile.getExpectedName()));
|
||||||
String actualSource = getFileContents(file);
|
String actualSource = getFileContents(file);
|
||||||
expectedSource= expectedSource.replace("\r\n", "\n");
|
expectedSource= expectedSource.replace("\r\n", "\n");
|
||||||
actualSource= actualSource.replace("\r\n", "\n");
|
actualSource= actualSource.replace("\r\n", "\n");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2008, 2012 Institute for Software, HSR Hochschule fuer Technik
|
* Copyright (c) 2008, 2014 Institute for Software, HSR Hochschule fuer Technik
|
||||||
* Rapperswil, University of applied sciences and others
|
* Rapperswil, University of applied sciences and others
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.ui.tests.refactoring;
|
package org.eclipse.cdt.ui.tests.refactoring;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ public class TestSourceFile {
|
||||||
private static final Pattern SELECTION_END = Pattern.compile("/\\*\\$\\$\\*/"); //$NON-NLS-1$
|
private static final Pattern SELECTION_END = Pattern.compile("/\\*\\$\\$\\*/"); //$NON-NLS-1$
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private String expectedName;
|
||||||
private final StringBuilder source = new StringBuilder();
|
private final StringBuilder source = new StringBuilder();
|
||||||
private final StringBuilder expectedSource = new StringBuilder();
|
private final StringBuilder expectedSource = new StringBuilder();
|
||||||
private int selectionStart = -1;
|
private int selectionStart = -1;
|
||||||
|
@ -45,6 +47,20 @@ public class TestSourceFile {
|
||||||
return source.toString();
|
return source.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the expected name after refactoring.
|
||||||
|
*/
|
||||||
|
public String getExpectedName() {
|
||||||
|
return expectedName == null ? name : expectedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpectedName(String name) {
|
||||||
|
expectedName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the expected contents after refactoring.
|
||||||
|
*/
|
||||||
public String getExpectedSource() {
|
public String getExpectedSource() {
|
||||||
if (expectedSource.length() == 0) {
|
if (expectedSource.length() == 0) {
|
||||||
return getSource();
|
return getSource();
|
||||||
|
@ -80,7 +96,7 @@ public class TestSourceFile {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return name.hashCode();
|
return Objects.hash(name, expectedName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -90,6 +106,6 @@ public class TestSourceFile {
|
||||||
if (obj == null || getClass() != obj.getClass())
|
if (obj == null || getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
TestSourceFile other = (TestSourceFile) obj;
|
TestSourceFile other = (TestSourceFile) obj;
|
||||||
return name.equals(other.name);
|
return Objects.equals(name, other.name) && Objects.equals(expectedName, other.expectedName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ public class IncludeOrganizerTest extends IncludesTestBase {
|
||||||
*/
|
*/
|
||||||
private String organizeIncludes(ITranslationUnit tu) throws Exception {
|
private String organizeIncludes(ITranslationUnit tu) throws Exception {
|
||||||
IHeaderChooser headerChooser = new FirstHeaderChooser();
|
IHeaderChooser headerChooser = new FirstHeaderChooser();
|
||||||
IncludeOrganizer organizer = new IncludeOrganizer(tu, index, LINE_DELIMITER, headerChooser);
|
IncludeOrganizer organizer = new IncludeOrganizer(tu, index, headerChooser);
|
||||||
MultiTextEdit edit = organizer.organizeIncludes(ast);
|
MultiTextEdit edit = organizer.organizeIncludes(ast);
|
||||||
IDocument document = new Document(new String(tu.getContents()));
|
IDocument document = new Document(new String(tu.getContents()));
|
||||||
edit.apply(document);
|
edit.apply(document);
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class RenameMacroTests extends RenameTestBase {
|
||||||
IFile cpp= importFile("test.cpp", contents); //$NON-NLS-1$
|
IFile cpp= importFile("test.cpp", contents); //$NON-NLS-1$
|
||||||
|
|
||||||
int offset1= contents.indexOf("HALLO"); //$NON-NLS-1$
|
int offset1= contents.indexOf("HALLO"); //$NON-NLS-1$
|
||||||
int offset2= contents.indexOf("HALLO", offset1+1); //$NON-NLS-1$
|
int offset2= contents.indexOf("HALLO", offset1 + 1); //$NON-NLS-1$
|
||||||
|
|
||||||
Change ch= getRefactorChanges(cpp, offset1, "WELT"); //$NON-NLS-1$
|
Change ch= getRefactorChanges(cpp, offset1, "WELT"); //$NON-NLS-1$
|
||||||
assertTotalChanges(6, ch);
|
assertTotalChanges(6, ch);
|
||||||
|
@ -120,7 +120,6 @@ public class RenameMacroTests extends RenameTestBase {
|
||||||
importFile("other.cpp", buf.toString()); //$NON-NLS-1$
|
importFile("other.cpp", buf.toString()); //$NON-NLS-1$
|
||||||
waitForIndexer();
|
waitForIndexer();
|
||||||
|
|
||||||
|
|
||||||
int offset1= contents.indexOf("MACRO"); //$NON-NLS-1$
|
int offset1= contents.indexOf("MACRO"); //$NON-NLS-1$
|
||||||
|
|
||||||
// conflicts after renaming
|
// conflicts after renaming
|
||||||
|
@ -130,7 +129,7 @@ public class RenameMacroTests extends RenameTestBase {
|
||||||
"New element: w1 \n" +
|
"New element: w1 \n" +
|
||||||
"Conflicting element type: Local variable"); //$NON-NLS-1$
|
"Conflicting element type: Local variable"); //$NON-NLS-1$
|
||||||
status= checkConditions(cpp, contents.indexOf("par1"), "MACRO"); //$NON-NLS-1$ //$NON-NLS-2$
|
status= checkConditions(cpp, contents.indexOf("par1"), "MACRO"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
assertRefactoringError(status, "'MACRO' conflicts with the name of an existing macro!"); //$NON-NLS-1$
|
assertRefactoringError(status, "'MACRO' conflicts with the name of an existing macro."); //$NON-NLS-1$
|
||||||
status= checkConditions(cpp, offset1, "par1"); //$NON-NLS-1$
|
status= checkConditions(cpp, offset1, "par1"); //$NON-NLS-1$
|
||||||
assertRefactoringError(status, "A conflict was encountered during refactoring. \n" +
|
assertRefactoringError(status, "A conflict was encountered during refactoring. \n" +
|
||||||
"Type of problem: Name conflict \n" +
|
"Type of problem: Name conflict \n" +
|
||||||
|
@ -201,7 +200,7 @@ public class RenameMacroTests extends RenameTestBase {
|
||||||
IFile cpp= importFile("test.cpp", contents); //$NON-NLS-1$
|
IFile cpp= importFile("test.cpp", contents); //$NON-NLS-1$
|
||||||
|
|
||||||
int offset1= contents.indexOf("_guard"); //$NON-NLS-1$
|
int offset1= contents.indexOf("_guard"); //$NON-NLS-1$
|
||||||
int offset2= contents.indexOf("_guard", offset1+1); //$NON-NLS-1$
|
int offset2= contents.indexOf("_guard", offset1 + 1); //$NON-NLS-1$
|
||||||
Change ch= getRefactorChanges(cpp, offset2, "WELT"); //$NON-NLS-1$
|
Change ch= getRefactorChanges(cpp, offset2, "WELT"); //$NON-NLS-1$
|
||||||
assertTotalChanges(2, 0, 1, ch);
|
assertTotalChanges(2, 0, 1, ch);
|
||||||
int off= offset1;
|
int off= offset1;
|
||||||
|
|
|
@ -0,0 +1,252 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2014 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.ui.tests.refactoring.rename;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IFolder;
|
||||||
|
import org.eclipse.core.resources.IResource;
|
||||||
|
import org.eclipse.ltk.core.refactoring.participants.MoveRefactoring;
|
||||||
|
import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring;
|
||||||
|
import org.eclipse.ltk.internal.core.refactoring.resource.MoveResourcesProcessor;
|
||||||
|
import org.eclipse.ltk.internal.core.refactoring.resource.RenameResourceProcessor;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.ui.PreferenceConstants;
|
||||||
|
import org.eclipse.cdt.ui.tests.refactoring.RefactoringTestBase;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.CRefactoring;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for
|
||||||
|
* {@link org.eclipse.cdt.internal.ui.refactoring.rename.HeaderFileRenameParticipant} and
|
||||||
|
* {@link org.eclipse.cdt.internal.ui.refactoring.rename.HeaderFileMoveParticipant}.
|
||||||
|
*/
|
||||||
|
public class RenameMoveHeaderRefactoringTest extends RefactoringTestBase {
|
||||||
|
|
||||||
|
public RenameMoveHeaderRefactoringTest() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenameMoveHeaderRefactoringTest(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Test suite() {
|
||||||
|
return suite(RenameMoveHeaderRefactoringTest.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void resetPreferences() {
|
||||||
|
super.resetPreferences();
|
||||||
|
getPreferenceStore().setToDefault(PreferenceConstants.FUNCTION_OUTPUT_PARAMETERS_BEFORE_INPUT);
|
||||||
|
getPreferenceStore().setToDefault(PreferenceConstants.FUNCTION_PASS_OUTPUT_PARAMETERS_BY_POINTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CRefactoring createRefactoring() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// test1.h
|
||||||
|
//#ifndef TEST1_H_
|
||||||
|
//#define TEST1_H_
|
||||||
|
//
|
||||||
|
//class A {};
|
||||||
|
//
|
||||||
|
//#endif // TEST1_H_
|
||||||
|
//====================
|
||||||
|
// test.h
|
||||||
|
//#ifndef TEST_H_
|
||||||
|
//#define TEST_H_
|
||||||
|
//
|
||||||
|
//class A {};
|
||||||
|
//
|
||||||
|
//#endif // TEST_H_
|
||||||
|
|
||||||
|
// test.cpp
|
||||||
|
//#include <string>
|
||||||
|
//#include "test1.h" /* Comment1 */ // Comment2
|
||||||
|
//====================
|
||||||
|
// test.cpp
|
||||||
|
//#include "test.h" /* Comment1 */ // Comment2
|
||||||
|
//
|
||||||
|
//#include <string>
|
||||||
|
public void testFileRename() throws Exception {
|
||||||
|
IResource resource = getProject().getFile("test1.h");
|
||||||
|
RenameResourceProcessor processor = new RenameResourceProcessor(resource);
|
||||||
|
processor.setNewResourceName("test.h");
|
||||||
|
RenameRefactoring refactoring = new RenameRefactoring(processor);
|
||||||
|
executeRefactoring(refactoring, true);
|
||||||
|
compareFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
// header1.h
|
||||||
|
//#ifndef HEADER1_H_
|
||||||
|
//#define HEADER1_H_
|
||||||
|
//
|
||||||
|
//class A {};
|
||||||
|
//
|
||||||
|
//#endif // HEADER1_H_
|
||||||
|
//====================
|
||||||
|
// dir/header1.h
|
||||||
|
//#ifndef DIR_HEADER1_H_
|
||||||
|
//#define DIR_HEADER1_H_
|
||||||
|
//
|
||||||
|
//class A {};
|
||||||
|
//
|
||||||
|
//#endif // DIR_HEADER1_H_
|
||||||
|
|
||||||
|
// source1.cpp
|
||||||
|
//#include "header1.h"
|
||||||
|
//====================
|
||||||
|
// source1.cpp
|
||||||
|
//#include "dir/header1.h"
|
||||||
|
public void testFileMove() throws Exception {
|
||||||
|
IResource resource = getProject().getFile("header1.h");
|
||||||
|
MoveResourcesProcessor processor = new MoveResourcesProcessor(new IResource[] { resource });
|
||||||
|
IFolder destination = getProject().getFolder("dir");
|
||||||
|
destination.create(true, true, npm());
|
||||||
|
processor.setDestination(destination);
|
||||||
|
MoveRefactoring refactoring = new MoveRefactoring(processor);
|
||||||
|
executeRefactoring(refactoring, true);
|
||||||
|
compareFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
// dir1/header1.h
|
||||||
|
//#ifndef DIR1_HEADER1_H_
|
||||||
|
//#define DIR1_HEADER1_H_
|
||||||
|
//
|
||||||
|
//#include "dir1/header2.h"
|
||||||
|
//
|
||||||
|
//#endif // DIR1_HEADER1_H_
|
||||||
|
//====================
|
||||||
|
// dir3/header1.h
|
||||||
|
//#ifndef DIR3_HEADER1_H_
|
||||||
|
//#define DIR3_HEADER1_H_
|
||||||
|
//
|
||||||
|
//#include "dir3/header2.h"
|
||||||
|
//
|
||||||
|
//#endif // DIR3_HEADER1_H_
|
||||||
|
|
||||||
|
// dir1/header2.h
|
||||||
|
//#if !defined(DIR1_HEADER2_H_)
|
||||||
|
//#define DIR1_HEADER2_H_
|
||||||
|
//
|
||||||
|
//class A {};
|
||||||
|
//
|
||||||
|
//#endif /* DIR1_HEADER2_H_ */
|
||||||
|
//====================
|
||||||
|
// dir3/header2.h
|
||||||
|
//#if !defined(DIR3_HEADER2_H_)
|
||||||
|
//#define DIR3_HEADER2_H_
|
||||||
|
//
|
||||||
|
//class A {};
|
||||||
|
//
|
||||||
|
//#endif /* DIR3_HEADER2_H_ */
|
||||||
|
|
||||||
|
// dir1/source1.cpp
|
||||||
|
//#include <string>
|
||||||
|
//
|
||||||
|
//#include "dir1/header1.h"
|
||||||
|
//====================
|
||||||
|
// dir3/source1.cpp
|
||||||
|
//#include <string>
|
||||||
|
//
|
||||||
|
//#include "dir3/header1.h"
|
||||||
|
|
||||||
|
// header2.cpp
|
||||||
|
//#include "dir1/header1.h"
|
||||||
|
//#include "dir2/header3.h"
|
||||||
|
//
|
||||||
|
//#ifdef SOMETHING
|
||||||
|
// #include "dir1/header2.h"
|
||||||
|
//#endif
|
||||||
|
//====================
|
||||||
|
//#include "dir2/header3.h"
|
||||||
|
//#include "dir3/header1.h"
|
||||||
|
//
|
||||||
|
//#ifdef SOMETHING
|
||||||
|
// #include "dir3/header2.h"
|
||||||
|
//#endif
|
||||||
|
public void testFolderRename() throws Exception {
|
||||||
|
IFolder resource = getProject().getFolder("dir1");
|
||||||
|
RenameResourceProcessor processor = new RenameResourceProcessor(resource);
|
||||||
|
processor.setNewResourceName("dir3");
|
||||||
|
RenameRefactoring refactoring = new RenameRefactoring(processor);
|
||||||
|
executeRefactoring(refactoring, true);
|
||||||
|
compareFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
// dir1/header1.h
|
||||||
|
//#ifndef DIR1_HEADER1_H_
|
||||||
|
//#define DIR1_HEADER1_H_
|
||||||
|
//
|
||||||
|
//#include "dir1/header2.h"
|
||||||
|
//
|
||||||
|
//#endif // DIR1_HEADER1_H_
|
||||||
|
//====================
|
||||||
|
// dir3/dir1/header1.h
|
||||||
|
//#ifndef DIR3_DIR1_HEADER1_H_
|
||||||
|
//#define DIR3_DIR1_HEADER1_H_
|
||||||
|
//
|
||||||
|
//#include "dir3/dir1/header2.h"
|
||||||
|
//
|
||||||
|
//#endif // DIR3_DIR1_HEADER1_H_
|
||||||
|
|
||||||
|
// dir1/header2.h
|
||||||
|
//#if !defined(DIR1_HEADER2_H_)
|
||||||
|
//#define DIR1_HEADER2_H_
|
||||||
|
//
|
||||||
|
//class A {};
|
||||||
|
//
|
||||||
|
//#endif /* DIR1_HEADER2_H_ */
|
||||||
|
//====================
|
||||||
|
// dir3/dir1/header2.h
|
||||||
|
//#if !defined(DIR3_DIR1_HEADER2_H_)
|
||||||
|
//#define DIR3_DIR1_HEADER2_H_
|
||||||
|
//
|
||||||
|
//class A {};
|
||||||
|
//
|
||||||
|
//#endif /* DIR3_DIR1_HEADER2_H_ */
|
||||||
|
|
||||||
|
// dir1/source1.cpp
|
||||||
|
//#include <string>
|
||||||
|
//
|
||||||
|
//#include "dir1/header1.h"
|
||||||
|
//====================
|
||||||
|
// dir3/dir1/source1.cpp
|
||||||
|
//#include <string>
|
||||||
|
//
|
||||||
|
//#include "dir3/dir1/header1.h"
|
||||||
|
|
||||||
|
// header2.cpp
|
||||||
|
//#include "dir1/header1.h"
|
||||||
|
//#include "dir2/header3.h"
|
||||||
|
//
|
||||||
|
//int x = 0;
|
||||||
|
//#include "dir1/header2.h"
|
||||||
|
//====================
|
||||||
|
//#include "dir2/header3.h"
|
||||||
|
//#include "dir3/dir1/header1.h"
|
||||||
|
//
|
||||||
|
//int x = 0;
|
||||||
|
//#include "dir3/dir1/header2.h"
|
||||||
|
public void testFolderMove() throws Exception {
|
||||||
|
IFolder resource = getProject().getFolder("dir1");
|
||||||
|
MoveResourcesProcessor processor = new MoveResourcesProcessor(new IResource[] { resource });
|
||||||
|
IFolder destination = getProject().getFolder("dir3");
|
||||||
|
destination.create(true, true, npm());
|
||||||
|
processor.setDestination(destination);
|
||||||
|
MoveRefactoring refactoring = new MoveRefactoring(processor);
|
||||||
|
executeRefactoring(refactoring, true);
|
||||||
|
compareFiles();
|
||||||
|
}
|
||||||
|
}
|
|
@ -604,7 +604,9 @@ preferenceKeywords.smarttyping=editor typing type close comment tabs indentation
|
||||||
historyAction.label = History...
|
historyAction.label = History...
|
||||||
createScriptAction.label = Create Script...
|
createScriptAction.label = Create Script...
|
||||||
applyScriptAction.label = Apply Script...
|
applyScriptAction.label = Apply Script...
|
||||||
renameParticipant.name = Source Folder Rename
|
renameFolderParticipant.name = Source Folder Rename
|
||||||
|
headerFileMoveParticipant.name = Header File Move
|
||||||
|
headerFileRenameParticipant.name = Header File Rename
|
||||||
|
|
||||||
FormatAction.label= &Format
|
FormatAction.label= &Format
|
||||||
IndentAction.label= Correct &Indentation
|
IndentAction.label= Correct &Indentation
|
||||||
|
|
|
@ -4396,23 +4396,55 @@
|
||||||
id="org.eclipse.cdt.internal.ui.refactoring.extractfunction.ExtractFunctionRefactoring">
|
id="org.eclipse.cdt.internal.ui.refactoring.extractfunction.ExtractFunctionRefactoring">
|
||||||
</contribution>
|
</contribution>
|
||||||
</extension>
|
</extension>
|
||||||
<extension point="org.eclipse.ltk.core.refactoring.renameParticipants">
|
<extension point="org.eclipse.ltk.core.refactoring.moveParticipants">
|
||||||
<renameParticipant id="org.eclipse.cdt.ui.RenameSourceFolder"
|
<moveParticipant id="org.eclipse.cdt.ui.headerFileMoveParticipant"
|
||||||
name="%renameParticipant.name"
|
name="%headerFileMoveParticipant.name"
|
||||||
class="org.eclipse.cdt.internal.ui.refactoring.rename.RenameSourceFolder">
|
class="org.eclipse.cdt.internal.ui.refactoring.rename.HeaderFileMoveParticipant">
|
||||||
<enablement>
|
<enablement>
|
||||||
<or>
|
<with variable="affectedNatures">
|
||||||
<with variable="affectedNatures">
|
<iterate operator="or">
|
||||||
<iterate operator="or">
|
<or>
|
||||||
<equals value="org.eclipse.cdt.core.ccnature" />
|
|
||||||
</iterate>
|
|
||||||
</with>
|
|
||||||
<with variable="affectedNatures">
|
|
||||||
<iterate operator="or">
|
|
||||||
<equals value="org.eclipse.cdt.core.cnature" />
|
<equals value="org.eclipse.cdt.core.cnature" />
|
||||||
</iterate>
|
<equals value="org.eclipse.cdt.core.ccnature" />
|
||||||
</with>
|
</or>
|
||||||
</or>
|
</iterate>
|
||||||
|
</with>
|
||||||
|
<with variable="element">
|
||||||
|
<instanceof value="org.eclipse.core.resources.IResource"/>
|
||||||
|
</with>
|
||||||
|
</enablement>
|
||||||
|
</moveParticipant>
|
||||||
|
</extension>
|
||||||
|
<extension point="org.eclipse.ltk.core.refactoring.renameParticipants">
|
||||||
|
<renameParticipant id="org.eclipse.cdt.ui.headerFileRenameParticipant"
|
||||||
|
name="%headerFileRenameParticipant.name"
|
||||||
|
class="org.eclipse.cdt.internal.ui.refactoring.rename.HeaderFileRenameParticipant">
|
||||||
|
<enablement>
|
||||||
|
<with variable="affectedNatures">
|
||||||
|
<iterate operator="or">
|
||||||
|
<or>
|
||||||
|
<equals value="org.eclipse.cdt.core.cnature" />
|
||||||
|
<equals value="org.eclipse.cdt.core.ccnature" />
|
||||||
|
</or>
|
||||||
|
</iterate>
|
||||||
|
</with>
|
||||||
|
<with variable="element">
|
||||||
|
<instanceof value="org.eclipse.core.resources.IResource"/>
|
||||||
|
</with>
|
||||||
|
</enablement>
|
||||||
|
</renameParticipant>
|
||||||
|
<renameParticipant id="org.eclipse.cdt.ui.RenameSourceFolder"
|
||||||
|
name="%renameFolderParticipant.name"
|
||||||
|
class="org.eclipse.cdt.internal.ui.refactoring.rename.SourceFolderRenameParticipant">
|
||||||
|
<enablement>
|
||||||
|
<with variable="affectedNatures">
|
||||||
|
<iterate operator="or">
|
||||||
|
<or>
|
||||||
|
<equals value="org.eclipse.cdt.core.cnature" />
|
||||||
|
<equals value="org.eclipse.cdt.core.ccnature" />
|
||||||
|
</or>
|
||||||
|
</iterate>
|
||||||
|
</with>
|
||||||
<with variable="element">
|
<with variable="element">
|
||||||
<instanceof value="org.eclipse.core.resources.IFolder" />
|
<instanceof value="org.eclipse.core.resources.IFolder" />
|
||||||
</with>
|
</with>
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.runtime.IPath;
|
import org.eclipse.core.runtime.IPath;
|
||||||
import org.eclipse.core.runtime.Path;
|
import org.eclipse.core.runtime.Path;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.model.CModelException;
|
||||||
import org.eclipse.cdt.core.model.ICProject;
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
import org.eclipse.cdt.core.parser.IScannerInfo;
|
import org.eclipse.cdt.core.parser.IScannerInfo;
|
||||||
|
@ -44,6 +45,8 @@ public class InclusionContext {
|
||||||
private final Map<IncludeInfo, IPath> fIncludeResolutionCache;
|
private final Map<IncludeInfo, IPath> fIncludeResolutionCache;
|
||||||
private final Map<IPath, IncludeInfo> fInverseIncludeResolutionCache;
|
private final Map<IPath, IncludeInfo> fInverseIncludeResolutionCache;
|
||||||
private final IncludePreferences fPreferences;
|
private final IncludePreferences fPreferences;
|
||||||
|
private String fSourceContents;
|
||||||
|
private String fLineDelimiter;
|
||||||
|
|
||||||
public InclusionContext(ITranslationUnit tu) {
|
public InclusionContext(ITranslationUnit tu) {
|
||||||
fTu = tu;
|
fTu = tu;
|
||||||
|
@ -141,7 +144,41 @@ public class InclusionContext {
|
||||||
return include;
|
return include;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncludeGroupStyle getIncludeStyle(IPath headerPath) {
|
/**
|
||||||
|
* Returns the include directive that resolves to the given header file, or {@code null} if
|
||||||
|
* the file is not on the include search path. Current directory is not considered to be a part
|
||||||
|
* of the include path by this method.
|
||||||
|
*/
|
||||||
|
public IncludeInfo getIncludeForHeaderFile(IPath fullPath, boolean isSystem) {
|
||||||
|
IncludeInfo include = fInverseIncludeResolutionCache.get(fullPath);
|
||||||
|
if (include != null)
|
||||||
|
return include;
|
||||||
|
String headerLocation = fullPath.toOSString();
|
||||||
|
String shortestInclude = null;
|
||||||
|
for (IncludeSearchPathElement pathElement : fIncludeSearchPath.getElements()) {
|
||||||
|
if (isSystem && pathElement.isForQuoteIncludesOnly())
|
||||||
|
continue;
|
||||||
|
String includeDirective = pathElement.getIncludeDirective(headerLocation);
|
||||||
|
if (includeDirective != null &&
|
||||||
|
(shortestInclude == null || shortestInclude.length() > includeDirective.length())) {
|
||||||
|
shortestInclude = includeDirective;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shortestInclude == null) {
|
||||||
|
if (fIncludeSearchPath.isInhibitUseOfCurrentFileDirectory() ||
|
||||||
|
!fCurrentDirectory.isPrefixOf(fullPath)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
shortestInclude = fullPath.setDevice(null).removeFirstSegments(fCurrentDirectory.segmentCount()).toString();
|
||||||
|
}
|
||||||
|
include = new IncludeInfo(shortestInclude, isSystem);
|
||||||
|
// Don't put an include to fullPath to fIncludeResolutionCache since it may be wrong
|
||||||
|
// if the header was included by #include_next.
|
||||||
|
fInverseIncludeResolutionCache.put(fullPath, include);
|
||||||
|
return include;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IncludeGroupStyle getIncludeStyle(IPath headerPath) {
|
||||||
IncludeKind includeKind;
|
IncludeKind includeKind;
|
||||||
IncludeInfo includeInfo = getIncludeForHeaderFile(headerPath);
|
IncludeInfo includeInfo = getIncludeForHeaderFile(headerPath);
|
||||||
if (includeInfo != null && includeInfo.isSystem()) {
|
if (includeInfo != null && includeInfo.isSystem()) {
|
||||||
|
@ -252,4 +289,22 @@ public class InclusionContext {
|
||||||
return null;
|
return null;
|
||||||
return relativePath.toString();
|
return relativePath.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSourceContents() {
|
||||||
|
if (fSourceContents == null) {
|
||||||
|
fSourceContents = new String(fTu.getContents());
|
||||||
|
}
|
||||||
|
return fSourceContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLineDelimiter() {
|
||||||
|
if (fLineDelimiter == null) {
|
||||||
|
try {
|
||||||
|
fLineDelimiter = StubUtility.getLineDelimiterUsed(fTu);
|
||||||
|
} catch (CModelException e) {
|
||||||
|
fLineDelimiter = System.getProperty("line.separator", "\n"); //$NON-NLS-1$//$NON-NLS-2$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fLineDelimiter;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -666,7 +666,7 @@ public class StubUtility {
|
||||||
return projectStore.findTemplateById(id);
|
return projectStore.findTemplateById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String generateIncludeGuardSymbol(IResource file, ICProject cproject) {
|
public static String generateIncludeGuardSymbol(IResource file, ICProject cproject) {
|
||||||
int scheme = PreferenceConstants.getPreference(
|
int scheme = PreferenceConstants.getPreference(
|
||||||
PreferenceConstants.CODE_TEMPLATES_INCLUDE_GUARD_SCHEME, cproject,
|
PreferenceConstants.CODE_TEMPLATES_INCLUDE_GUARD_SCHEME, cproject,
|
||||||
PreferenceConstants.CODE_TEMPLATES_INCLUDE_GUARD_SCHEME_FILE_NAME);
|
PreferenceConstants.CODE_TEMPLATES_INCLUDE_GUARD_SCHEME_FILE_NAME);
|
||||||
|
|
|
@ -92,6 +92,6 @@ public class StyledInclude {
|
||||||
/** For debugging only */
|
/** For debugging only */
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return header != null ? header.toPortableString() : includeInfo.toString();
|
return header != null ? header.toString() : includeInfo.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -99,7 +99,6 @@ public class AddIncludeAction extends TextEditorAction {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String lineDelimiter = getLineDelimiter(editor);
|
|
||||||
final MultiTextEdit[] holder = new MultiTextEdit[1];
|
final MultiTextEdit[] holder = new MultiTextEdit[1];
|
||||||
SharedASTJob job = new SharedASTJob(CEditorMessages.AddInclude_action, tu) {
|
SharedASTJob job = new SharedASTJob(CEditorMessages.AddInclude_action, tu) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -113,7 +112,7 @@ public class AddIncludeAction extends TextEditorAction {
|
||||||
IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_EXTENSION_FRAGMENTS_ADD_IMPORT);
|
IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_EXTENSION_FRAGMENTS_ADD_IMPORT);
|
||||||
try {
|
try {
|
||||||
index.acquireReadLock();
|
index.acquireReadLock();
|
||||||
IncludeCreator creator = new IncludeCreator(tu, index, lineDelimiter, fAmbiguityResolver);
|
IncludeCreator creator = new IncludeCreator(tu, index, fAmbiguityResolver);
|
||||||
holder[0] = creator.createInclude(ast, (ITextSelection) selection);
|
holder[0] = creator.createInclude(ast, (ITextSelection) selection);
|
||||||
return Status.OK_STATUS;
|
return Status.OK_STATUS;
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
@ -154,19 +153,6 @@ public class AddIncludeAction extends TextEditorAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getLineDelimiter(ITextEditor editor) {
|
|
||||||
try {
|
|
||||||
IEditorInput editorInput = editor.getEditorInput();
|
|
||||||
IDocument document = editor.getDocumentProvider().getDocument(editorInput);
|
|
||||||
String delim= document.getLineDelimiter(0);
|
|
||||||
if (delim != null) {
|
|
||||||
return delim;
|
|
||||||
}
|
|
||||||
} catch (BadLocationException e) {
|
|
||||||
}
|
|
||||||
return System.getProperty("line.separator", "\n"); //$NON-NLS-1$//$NON-NLS-2$
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update() {
|
public void update() {
|
||||||
ITextEditor editor = getTextEditor();
|
ITextEditor editor = getTextEditor();
|
||||||
|
|
|
@ -66,7 +66,6 @@ public class OrganizeIncludesAction extends TextEditorAction {
|
||||||
|
|
||||||
final IHeaderChooser headerChooser = new InteractiveHeaderChooser(
|
final IHeaderChooser headerChooser = new InteractiveHeaderChooser(
|
||||||
CEditorMessages.OrganizeIncludes_label, editor.getSite().getShell());
|
CEditorMessages.OrganizeIncludes_label, editor.getSite().getShell());
|
||||||
final String lineDelimiter = getLineDelimiter(editor);
|
|
||||||
final MultiTextEdit[] holder = new MultiTextEdit[1];
|
final MultiTextEdit[] holder = new MultiTextEdit[1];
|
||||||
SharedASTJob job = new SharedASTJob(CEditorMessages.OrganizeIncludes_action, tu) {
|
SharedASTJob job = new SharedASTJob(CEditorMessages.OrganizeIncludes_action, tu) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -80,7 +79,7 @@ public class OrganizeIncludesAction extends TextEditorAction {
|
||||||
IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_EXTENSION_FRAGMENTS_ADD_IMPORT);
|
IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_EXTENSION_FRAGMENTS_ADD_IMPORT);
|
||||||
try {
|
try {
|
||||||
index.acquireReadLock();
|
index.acquireReadLock();
|
||||||
IncludeOrganizer organizer = new IncludeOrganizer(tu, index, lineDelimiter, headerChooser);
|
IncludeOrganizer organizer = new IncludeOrganizer(tu, index, headerChooser);
|
||||||
holder[0] = organizer.organizeIncludes(ast);
|
holder[0] = organizer.organizeIncludes(ast);
|
||||||
return Status.OK_STATUS;
|
return Status.OK_STATUS;
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
@ -115,19 +114,6 @@ public class OrganizeIncludesAction extends TextEditorAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getLineDelimiter(ITextEditor editor) {
|
|
||||||
try {
|
|
||||||
IEditorInput editorInput = editor.getEditorInput();
|
|
||||||
IDocument document = editor.getDocumentProvider().getDocument(editorInput);
|
|
||||||
String delim= document.getLineDelimiter(0);
|
|
||||||
if (delim != null) {
|
|
||||||
return delim;
|
|
||||||
}
|
|
||||||
} catch (BadLocationException e) {
|
|
||||||
}
|
|
||||||
return System.getProperty("line.separator", "\n"); //$NON-NLS-1$//$NON-NLS-2$
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update() {
|
public void update() {
|
||||||
ITextEditor editor = getTextEditor();
|
ITextEditor editor = getTextEditor();
|
||||||
|
|
|
@ -37,7 +37,6 @@ public class IncludeCreationContext extends InclusionContext {
|
||||||
private final Set<IPath> fHeadersToInclude;
|
private final Set<IPath> fHeadersToInclude;
|
||||||
private final Set<IPath> fHeadersAlreadyIncluded;
|
private final Set<IPath> fHeadersAlreadyIncluded;
|
||||||
private final Set<IPath> fHeadersIncludedPreviously;
|
private final Set<IPath> fHeadersIncludedPreviously;
|
||||||
private String fSourceContents;
|
|
||||||
|
|
||||||
public IncludeCreationContext(ITranslationUnit tu, IIndex index) {
|
public IncludeCreationContext(ITranslationUnit tu, IIndex index) {
|
||||||
super(tu);
|
super(tu);
|
||||||
|
@ -47,13 +46,6 @@ public class IncludeCreationContext extends InclusionContext {
|
||||||
fHeadersIncludedPreviously = new HashSet<>();
|
fHeadersIncludedPreviously = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSourceContents() {
|
|
||||||
if (fSourceContents == null) {
|
|
||||||
fSourceContents = new String(getTranslationUnit().getContents());
|
|
||||||
}
|
|
||||||
return fSourceContents;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final IIndex getIndex() {
|
public final IIndex getIndex() {
|
||||||
return fIndex;
|
return fIndex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
import static org.eclipse.cdt.core.index.IndexLocationFactory.getAbsolutePath;
|
import static org.eclipse.cdt.core.index.IndexLocationFactory.getAbsolutePath;
|
||||||
import static org.eclipse.cdt.internal.ui.refactoring.includes.IncludeUtil.isContainedInRegion;
|
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
|
@ -32,7 +31,6 @@ import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
import org.eclipse.core.runtime.IPath;
|
import org.eclipse.core.runtime.IPath;
|
||||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||||
import org.eclipse.core.runtime.Path;
|
|
||||||
import org.eclipse.core.runtime.content.IContentType;
|
import org.eclipse.core.runtime.content.IContentType;
|
||||||
import org.eclipse.jface.text.IRegion;
|
import org.eclipse.jface.text.IRegion;
|
||||||
import org.eclipse.jface.text.ITextSelection;
|
import org.eclipse.jface.text.ITextSelection;
|
||||||
|
@ -98,13 +96,10 @@ import org.eclipse.cdt.internal.ui.CHelpProviderManager;
|
||||||
public class IncludeCreator {
|
public class IncludeCreator {
|
||||||
private static final Collator COLLATOR = Collator.getInstance();
|
private static final Collator COLLATOR = Collator.getInstance();
|
||||||
|
|
||||||
private final String fLineDelimiter;
|
|
||||||
private final IElementSelector fAmbiguityResolver;
|
private final IElementSelector fAmbiguityResolver;
|
||||||
private final IncludeCreationContext fContext;
|
private final IncludeCreationContext fContext;
|
||||||
|
|
||||||
public IncludeCreator(ITranslationUnit tu, IIndex index, String lineDelimiter,
|
public IncludeCreator(ITranslationUnit tu, IIndex index, IElementSelector ambiguityResolver) {
|
||||||
IElementSelector ambiguityResolver) {
|
|
||||||
fLineDelimiter = lineDelimiter;
|
|
||||||
fAmbiguityResolver = ambiguityResolver;
|
fAmbiguityResolver = ambiguityResolver;
|
||||||
fContext = new IncludeCreationContext(tu, index);
|
fContext = new IncludeCreationContext(tu, index);
|
||||||
}
|
}
|
||||||
|
@ -237,7 +232,7 @@ public class IncludeCreator {
|
||||||
NodeCommentMap commentedNodeMap = ASTCommenter.getCommentedNodeMap(ast);
|
NodeCommentMap commentedNodeMap = ASTCommenter.getCommentedNodeMap(ast);
|
||||||
String contents = fContext.getSourceContents();
|
String contents = fContext.getSourceContents();
|
||||||
IRegion includeRegion =
|
IRegion includeRegion =
|
||||||
IncludeOrganizer.getSafeIncludeReplacementRegion(contents, ast, commentedNodeMap);
|
IncludeUtil.getSafeIncludeReplacementRegion(contents, ast, commentedNodeMap);
|
||||||
|
|
||||||
IncludePreferences preferences = fContext.getPreferences();
|
IncludePreferences preferences = fContext.getPreferences();
|
||||||
|
|
||||||
|
@ -258,21 +253,8 @@ public class IncludeCreator {
|
||||||
}
|
}
|
||||||
Collections.sort(styledIncludes, preferences);
|
Collections.sort(styledIncludes, preferences);
|
||||||
|
|
||||||
// Populate list of existing includes in the include insertion region.
|
List<StyledInclude> mergedIncludes =
|
||||||
List<StyledInclude> mergedIncludes = new ArrayList<>();
|
IncludeUtil.getIncludesInRegion(existingIncludes, includeRegion, fContext);
|
||||||
for (IASTPreprocessorIncludeStatement include : existingIncludes) {
|
|
||||||
if (include.isPartOfTranslationUnitFile() && isContainedInRegion(include, includeRegion)) {
|
|
||||||
String name = new String(include.getName().getSimpleID());
|
|
||||||
IncludeInfo includeInfo = new IncludeInfo(name, include.isSystemInclude());
|
|
||||||
String path = include.getPath();
|
|
||||||
// An empty path means that the include was not resolved.
|
|
||||||
IPath header = path.isEmpty() ? null : Path.fromOSString(path);
|
|
||||||
IncludeGroupStyle style =
|
|
||||||
header != null ? fContext.getIncludeStyle(header) : fContext.getIncludeStyle(includeInfo);
|
|
||||||
StyledInclude prototype = new StyledInclude(header, includeInfo, style, include);
|
|
||||||
mergedIncludes.add(prototype);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preferences.allowReordering) {
|
if (preferences.allowReordering) {
|
||||||
// Since the order of existing include statements may not match the include order
|
// Since the order of existing include statements may not match the include order
|
||||||
|
@ -299,23 +281,23 @@ public class IncludeCreator {
|
||||||
offset = ASTNodes.skipToNextLineAfterNode(contents, previousNode);
|
offset = ASTNodes.skipToNextLineAfterNode(contents, previousNode);
|
||||||
flushEditBuffer(offset, text, rootEdit);
|
flushEditBuffer(offset, text, rootEdit);
|
||||||
if (contents.charAt(offset - 1) != '\n')
|
if (contents.charAt(offset - 1) != '\n')
|
||||||
text.append(fLineDelimiter);
|
text.append(fContext.getLineDelimiter());
|
||||||
}
|
}
|
||||||
if (include.getStyle().isBlankLineNeededAfter(previousInclude.getStyle(), preferences.includeStyles)) {
|
if (include.getStyle().isBlankLineNeededAfter(previousInclude.getStyle(), preferences.includeStyles)) {
|
||||||
if (TextUtil.isLineBlank(contents, offset)) {
|
if (TextUtil.isLineBlank(contents, offset)) {
|
||||||
offset = TextUtil.skipToNextLine(contents, offset);
|
offset = TextUtil.skipToNextLine(contents, offset);
|
||||||
} else {
|
} else {
|
||||||
text.append(fLineDelimiter);
|
text.append(fContext.getLineDelimiter());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text.append(include.getIncludeInfo().composeIncludeStatement());
|
text.append(include.getIncludeInfo().composeIncludeStatement());
|
||||||
text.append(fLineDelimiter);
|
text.append(fContext.getLineDelimiter());
|
||||||
} else {
|
} else {
|
||||||
if (previousInclude != null && previousInclude.getExistingInclude() == null &&
|
if (previousInclude != null && previousInclude.getExistingInclude() == null &&
|
||||||
include.getStyle().isBlankLineNeededAfter(previousInclude.getStyle(), preferences.includeStyles) &&
|
include.getStyle().isBlankLineNeededAfter(previousInclude.getStyle(), preferences.includeStyles) &&
|
||||||
!TextUtil.isPreviousLineBlank(contents, ASTNodes.offset(existingInclude))) {
|
!TextUtil.isPreviousLineBlank(contents, ASTNodes.offset(existingInclude))) {
|
||||||
text.append(fLineDelimiter);
|
text.append(fContext.getLineDelimiter());
|
||||||
}
|
}
|
||||||
flushEditBuffer(offset, text, rootEdit);
|
flushEditBuffer(offset, text, rootEdit);
|
||||||
}
|
}
|
||||||
|
@ -323,7 +305,7 @@ public class IncludeCreator {
|
||||||
}
|
}
|
||||||
if (includeRegion.getLength() == 0 && !TextUtil.isLineBlank(contents, includeRegion.getOffset()) &&
|
if (includeRegion.getLength() == 0 && !TextUtil.isLineBlank(contents, includeRegion.getOffset()) &&
|
||||||
!includes.isEmpty()) {
|
!includes.isEmpty()) {
|
||||||
text.append(fLineDelimiter);
|
text.append(fContext.getLineDelimiter());
|
||||||
}
|
}
|
||||||
flushEditBuffer(offset, text, rootEdit);
|
flushEditBuffer(offset, text, rootEdit);
|
||||||
|
|
||||||
|
@ -359,7 +341,7 @@ public class IncludeCreator {
|
||||||
|
|
||||||
if (mergedUsingDeclarations.isEmpty()) {
|
if (mergedUsingDeclarations.isEmpty()) {
|
||||||
offset = includeRegion.getOffset() + includeRegion.getLength();
|
offset = includeRegion.getOffset() + includeRegion.getLength();
|
||||||
text.append(fLineDelimiter); // Blank line between includes and using declarations.
|
text.append(fContext.getLineDelimiter()); // Blank line between includes and using declarations.
|
||||||
} else {
|
} else {
|
||||||
offset = commentedNodeMap.getOffsetIncludingComments(mergedUsingDeclarations.get(0).existingDeclaration);
|
offset = commentedNodeMap.getOffsetIncludingComments(mergedUsingDeclarations.get(0).existingDeclaration);
|
||||||
}
|
}
|
||||||
|
@ -382,11 +364,11 @@ public class IncludeCreator {
|
||||||
offset = ASTNodes.skipToNextLineAfterNode(contents, previousNode);
|
offset = ASTNodes.skipToNextLineAfterNode(contents, previousNode);
|
||||||
flushEditBuffer(offset, text, rootEdit);
|
flushEditBuffer(offset, text, rootEdit);
|
||||||
if (contents.charAt(offset - 1) != '\n')
|
if (contents.charAt(offset - 1) != '\n')
|
||||||
text.append(fLineDelimiter);
|
text.append(fContext.getLineDelimiter());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text.append(using.composeDirective());
|
text.append(using.composeDirective());
|
||||||
text.append(fLineDelimiter);
|
text.append(fContext.getLineDelimiter());
|
||||||
} else {
|
} else {
|
||||||
flushEditBuffer(offset, text, rootEdit);
|
flushEditBuffer(offset, text, rootEdit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,6 @@
|
||||||
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
import static org.eclipse.cdt.core.index.IndexLocationFactory.getAbsolutePath;
|
import static org.eclipse.cdt.core.index.IndexLocationFactory.getAbsolutePath;
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit.getEndingLineNumber;
|
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit.getNodeEndOffset;
|
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit.getNodeOffset;
|
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit.getStartingLineNumber;
|
|
||||||
import static org.eclipse.cdt.internal.ui.refactoring.includes.IncludeUtil.isContainedInRegion;
|
import static org.eclipse.cdt.internal.ui.refactoring.includes.IncludeUtil.isContainedInRegion;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -34,7 +30,6 @@ import org.eclipse.core.runtime.OperationCanceledException;
|
||||||
import org.eclipse.core.runtime.Path;
|
import org.eclipse.core.runtime.Path;
|
||||||
import org.eclipse.core.runtime.Platform;
|
import org.eclipse.core.runtime.Platform;
|
||||||
import org.eclipse.jface.text.IRegion;
|
import org.eclipse.jface.text.IRegion;
|
||||||
import org.eclipse.jface.text.Region;
|
|
||||||
import org.eclipse.text.edits.DeleteEdit;
|
import org.eclipse.text.edits.DeleteEdit;
|
||||||
import org.eclipse.text.edits.InsertEdit;
|
import org.eclipse.text.edits.InsertEdit;
|
||||||
import org.eclipse.text.edits.MultiTextEdit;
|
import org.eclipse.text.edits.MultiTextEdit;
|
||||||
|
@ -47,13 +42,9 @@ import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
|
||||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||||
import org.eclipse.cdt.core.dom.ast.EScopeKind;
|
import org.eclipse.cdt.core.dom.ast.EScopeKind;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTComment;
|
import org.eclipse.cdt.core.dom.ast.IASTComment;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorPragmaStatement;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
|
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
import org.eclipse.cdt.core.dom.ast.ICompositeType;
|
import org.eclipse.cdt.core.dom.ast.ICompositeType;
|
||||||
|
@ -77,10 +68,7 @@ import org.eclipse.cdt.core.index.IIndexFileSet;
|
||||||
import org.eclipse.cdt.core.index.IIndexInclude;
|
import org.eclipse.cdt.core.index.IIndexInclude;
|
||||||
import org.eclipse.cdt.core.index.IIndexName;
|
import org.eclipse.cdt.core.index.IIndexName;
|
||||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
import org.eclipse.cdt.core.parser.Keywords;
|
|
||||||
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
||||||
import org.eclipse.cdt.core.parser.util.CharArrayIntMap;
|
|
||||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
|
||||||
import org.eclipse.cdt.ui.CUIPlugin;
|
import org.eclipse.cdt.ui.CUIPlugin;
|
||||||
import org.eclipse.cdt.ui.CodeGeneration;
|
import org.eclipse.cdt.ui.CodeGeneration;
|
||||||
|
|
||||||
|
@ -88,10 +76,7 @@ import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.ASTCommenter;
|
||||||
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
|
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
|
||||||
import org.eclipse.cdt.internal.core.dom.rewrite.util.ASTNodes;
|
import org.eclipse.cdt.internal.core.dom.rewrite.util.ASTNodes;
|
||||||
import org.eclipse.cdt.internal.core.dom.rewrite.util.TextUtil;
|
import org.eclipse.cdt.internal.core.dom.rewrite.util.TextUtil;
|
||||||
import org.eclipse.cdt.internal.core.parser.scanner.CharArray;
|
|
||||||
import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver;
|
import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver;
|
||||||
import org.eclipse.cdt.internal.core.parser.scanner.IncludeGuardDetection;
|
|
||||||
import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
|
|
||||||
import org.eclipse.cdt.internal.corext.codemanipulation.IncludeInfo;
|
import org.eclipse.cdt.internal.corext.codemanipulation.IncludeInfo;
|
||||||
import org.eclipse.cdt.internal.corext.codemanipulation.StyledInclude;
|
import org.eclipse.cdt.internal.corext.codemanipulation.StyledInclude;
|
||||||
import org.eclipse.cdt.internal.formatter.ChangeFormatter;
|
import org.eclipse.cdt.internal.formatter.ChangeFormatter;
|
||||||
|
@ -182,11 +167,8 @@ public class IncludeOrganizer {
|
||||||
|
|
||||||
private final IHeaderChooser fHeaderChooser;
|
private final IHeaderChooser fHeaderChooser;
|
||||||
private final IncludeCreationContext fContext;
|
private final IncludeCreationContext fContext;
|
||||||
private final String fLineDelimiter;
|
|
||||||
|
|
||||||
public IncludeOrganizer(ITranslationUnit tu, IIndex index, String lineDelimiter,
|
public IncludeOrganizer(ITranslationUnit tu, IIndex index, IHeaderChooser headerChooser) {
|
||||||
IHeaderChooser headerChooser) {
|
|
||||||
fLineDelimiter = lineDelimiter;
|
|
||||||
fHeaderChooser = headerChooser;
|
fHeaderChooser = headerChooser;
|
||||||
fContext = new IncludeCreationContext(tu, index);
|
fContext = new IncludeCreationContext(tu, index);
|
||||||
}
|
}
|
||||||
|
@ -240,7 +222,7 @@ public class IncludeOrganizer {
|
||||||
|
|
||||||
NodeCommentMap commentedNodeMap = ASTCommenter.getCommentedNodeMap(ast);
|
NodeCommentMap commentedNodeMap = ASTCommenter.getCommentedNodeMap(ast);
|
||||||
IRegion includeReplacementRegion =
|
IRegion includeReplacementRegion =
|
||||||
getSafeIncludeReplacementRegion(fContext.getSourceContents(), ast, commentedNodeMap);
|
IncludeUtil.getSafeIncludeReplacementRegion(fContext.getSourceContents(), ast, commentedNodeMap);
|
||||||
|
|
||||||
IncludePreferences preferences = fContext.getPreferences();
|
IncludePreferences preferences = fContext.getPreferences();
|
||||||
boolean allowReordering = preferences.allowReordering || existingIncludes.length == 0;
|
boolean allowReordering = preferences.allowReordering || existingIncludes.length == 0;
|
||||||
|
@ -300,7 +282,7 @@ public class IncludeOrganizer {
|
||||||
List<IASTComment> comments = commentedNodeMap.getTrailingCommentsForNode(include);
|
List<IASTComment> comments = commentedNodeMap.getTrailingCommentsForNode(include);
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
for (IASTComment comment : comments) {
|
for (IASTComment comment : comments) {
|
||||||
buf.append(getPrecedingWhitespace(comment));
|
buf.append(ASTNodes.getPrecedingWhitespaceInLine(fContext.getSourceContents(), comment));
|
||||||
buf.append(comment.getRawSignature());
|
buf.append(comment.getRawSignature());
|
||||||
}
|
}
|
||||||
trailingComment = buf.toString();
|
trailingComment = buf.toString();
|
||||||
|
@ -318,7 +300,7 @@ public class IncludeOrganizer {
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
for (String include : includeDirectives) {
|
for (String include : includeDirectives) {
|
||||||
buf.append(include);
|
buf.append(include);
|
||||||
buf.append(fLineDelimiter);
|
buf.append(fContext.getLineDelimiter());
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = includeReplacementRegion.getOffset();
|
int offset = includeReplacementRegion.getOffset();
|
||||||
|
@ -326,7 +308,7 @@ public class IncludeOrganizer {
|
||||||
if (allowReordering) {
|
if (allowReordering) {
|
||||||
if (buf.length() != 0) {
|
if (buf.length() != 0) {
|
||||||
if (offset != 0 && !TextUtil.isPreviousLineBlank(fContext.getSourceContents(), offset))
|
if (offset != 0 && !TextUtil.isPreviousLineBlank(fContext.getSourceContents(), offset))
|
||||||
buf.insert(0, fLineDelimiter); // Blank line before.
|
buf.insert(0, fContext.getLineDelimiter()); // Blank line before.
|
||||||
}
|
}
|
||||||
|
|
||||||
String text = buf.toString();
|
String text = buf.toString();
|
||||||
|
@ -500,7 +482,7 @@ public class IncludeOrganizer {
|
||||||
|
|
||||||
for (ForwardDeclarationNode node : typeDeclarationsRoot.children) {
|
for (ForwardDeclarationNode node : typeDeclarationsRoot.children) {
|
||||||
if (pendingBlankLine) {
|
if (pendingBlankLine) {
|
||||||
buf.append(fLineDelimiter);
|
buf.append(fContext.getLineDelimiter());
|
||||||
pendingBlankLine = false;
|
pendingBlankLine = false;
|
||||||
}
|
}
|
||||||
printNode(node, buf);
|
printNode(node, buf);
|
||||||
|
@ -508,14 +490,14 @@ public class IncludeOrganizer {
|
||||||
|
|
||||||
for (ForwardDeclarationNode node : nonTypeDeclarationsRoot.children) {
|
for (ForwardDeclarationNode node : nonTypeDeclarationsRoot.children) {
|
||||||
if (pendingBlankLine) {
|
if (pendingBlankLine) {
|
||||||
buf.append(fLineDelimiter);
|
buf.append(fContext.getLineDelimiter());
|
||||||
pendingBlankLine = false;
|
pendingBlankLine = false;
|
||||||
}
|
}
|
||||||
printNode(node, buf);
|
printNode(node, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pendingBlankLine || buf.length() != 0) && !isBlankLineOrEndOfFile(offset))
|
if ((pendingBlankLine || buf.length() != 0) && !isBlankLineOrEndOfFile(offset))
|
||||||
buf.append(fLineDelimiter);
|
buf.append(fContext.getLineDelimiter());
|
||||||
|
|
||||||
if (buf.length() != 0)
|
if (buf.length() != 0)
|
||||||
rootEdit.addChild(new InsertEdit(offset, buf.toString()));
|
rootEdit.addChild(new InsertEdit(offset, buf.toString()));
|
||||||
|
@ -523,15 +505,15 @@ public class IncludeOrganizer {
|
||||||
|
|
||||||
private void printNode(ForwardDeclarationNode node, StringBuilder buf) throws CoreException {
|
private void printNode(ForwardDeclarationNode node, StringBuilder buf) throws CoreException {
|
||||||
if (node.declaration == null) {
|
if (node.declaration == null) {
|
||||||
buf.append(CodeGeneration.getNamespaceBeginContent(fContext.getTranslationUnit(), node.name, fLineDelimiter));
|
buf.append(CodeGeneration.getNamespaceBeginContent(fContext.getTranslationUnit(), node.name, fContext.getLineDelimiter()));
|
||||||
for (ForwardDeclarationNode child : node.children) {
|
for (ForwardDeclarationNode child : node.children) {
|
||||||
printNode(child, buf);
|
printNode(child, buf);
|
||||||
}
|
}
|
||||||
buf.append(CodeGeneration.getNamespaceEndContent(fContext.getTranslationUnit(), node.name, fLineDelimiter));
|
buf.append(CodeGeneration.getNamespaceEndContent(fContext.getTranslationUnit(), node.name, fContext.getLineDelimiter()));
|
||||||
} else {
|
} else {
|
||||||
buf.append(node.declaration);
|
buf.append(node.declaration);
|
||||||
}
|
}
|
||||||
buf.append(fLineDelimiter);
|
buf.append(fContext.getLineDelimiter());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createCommentOut(IASTPreprocessorIncludeStatement include, MultiTextEdit rootEdit) {
|
private void createCommentOut(IASTPreprocessorIncludeStatement include, MultiTextEdit rootEdit) {
|
||||||
|
@ -566,95 +548,6 @@ public class IncludeOrganizer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static IRegion getSafeIncludeReplacementRegion(String contents, IASTTranslationUnit ast,
|
|
||||||
NodeCommentMap commentMap) {
|
|
||||||
int maxSafeOffset = ast.getFileLocation().getNodeLength();
|
|
||||||
IASTDeclaration[] declarations = ast.getDeclarations(true);
|
|
||||||
if (declarations.length != 0)
|
|
||||||
maxSafeOffset = declarations[0].getFileLocation().getNodeOffset();
|
|
||||||
|
|
||||||
boolean topCommentSkipped = false;
|
|
||||||
int includeOffset = -1;
|
|
||||||
int includeEndOffset = -1;
|
|
||||||
int includeGuardStatementsToSkip = getNumberOfIncludeGuardStatementsToSkip(ast);
|
|
||||||
int includeGuardEndOffset = -1;
|
|
||||||
for (IASTPreprocessorStatement statement : ast.getAllPreprocessorStatements()) {
|
|
||||||
if (statement.isPartOfTranslationUnitFile()) {
|
|
||||||
IASTFileLocation fileLocation = statement.getFileLocation();
|
|
||||||
int offset = fileLocation.getNodeOffset();
|
|
||||||
if (offset >= maxSafeOffset)
|
|
||||||
break;
|
|
||||||
int endOffset = offset + fileLocation.getNodeLength();
|
|
||||||
|
|
||||||
if (includeGuardStatementsToSkip > 0) {
|
|
||||||
--includeGuardStatementsToSkip;
|
|
||||||
includeGuardEndOffset = endOffset;
|
|
||||||
if (!commentMap.getLeadingCommentsForNode(statement).isEmpty()) {
|
|
||||||
topCommentSkipped = true;
|
|
||||||
}
|
|
||||||
} else if (statement instanceof IASTPreprocessorIncludeStatement) {
|
|
||||||
if (includeOffset < 0)
|
|
||||||
includeOffset = offset;
|
|
||||||
includeEndOffset = endOffset;
|
|
||||||
includeGuardStatementsToSkip = 0; // Just in case
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (includeOffset < 0) {
|
|
||||||
if (includeGuardEndOffset >= 0) {
|
|
||||||
includeOffset = TextUtil.skipToNextLine(contents, includeGuardEndOffset);
|
|
||||||
} else {
|
|
||||||
includeOffset = 0;
|
|
||||||
}
|
|
||||||
if (!topCommentSkipped) {
|
|
||||||
// Skip the first comment block near the top of the file.
|
|
||||||
includeOffset = skipStandaloneCommentBlock(contents, includeOffset, maxSafeOffset, ast.getComments(), commentMap);
|
|
||||||
}
|
|
||||||
includeEndOffset = includeOffset;
|
|
||||||
} else {
|
|
||||||
includeEndOffset = TextUtil.skipToNextLine(contents, includeEndOffset);
|
|
||||||
}
|
|
||||||
return new Region(includeOffset, includeEndOffset - includeOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getNumberOfIncludeGuardStatementsToSkip(IASTTranslationUnit ast) {
|
|
||||||
IASTPreprocessorStatement statement = findFirstPreprocessorStatement(ast);
|
|
||||||
if (statement == null)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int num = 0;
|
|
||||||
int offset = 0;
|
|
||||||
if (isPragmaOnce(statement)) {
|
|
||||||
num++;
|
|
||||||
offset = getNodeEndOffset(statement);
|
|
||||||
}
|
|
||||||
char[] contents = ast.getRawSignature().toCharArray();
|
|
||||||
if (offset != 0)
|
|
||||||
contents = Arrays.copyOfRange(contents, offset, contents.length);
|
|
||||||
CharArrayIntMap ppKeywords= new CharArrayIntMap(40, -1);
|
|
||||||
Keywords.addKeywordsPreprocessor(ppKeywords);
|
|
||||||
if (IncludeGuardDetection.detectIncludeGuard(new CharArray(contents), new LexerOptions(), ppKeywords) != null) {
|
|
||||||
num += 2;
|
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IASTPreprocessorStatement findFirstPreprocessorStatement(IASTTranslationUnit ast) {
|
|
||||||
for (IASTPreprocessorStatement statement : ast.getAllPreprocessorStatements()) {
|
|
||||||
if (statement.isPartOfTranslationUnitFile())
|
|
||||||
return statement;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isPragmaOnce(IASTPreprocessorStatement statement) {
|
|
||||||
if (!(statement instanceof IASTPreprocessorPragmaStatement))
|
|
||||||
return false;
|
|
||||||
return CharArrayUtils.equals(((IASTPreprocessorPragmaStatement) statement).getMessage(), "once"); //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@code true} if there are no non-whitespace characters between the given
|
* Returns {@code true} if there are no non-whitespace characters between the given
|
||||||
* {@code offset} and the end of the line.
|
* {@code offset} and the end of the line.
|
||||||
|
@ -671,82 +564,6 @@ public class IncludeOrganizer {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the whitespace preceding the given node. The newline character in not considered
|
|
||||||
* whitespace for the purpose of this method.
|
|
||||||
*/
|
|
||||||
private String getPrecedingWhitespace(IASTNode node) {
|
|
||||||
int offset = getNodeOffset(node);
|
|
||||||
if (offset >= 0) {
|
|
||||||
String contents = fContext.getSourceContents();
|
|
||||||
int i = offset;
|
|
||||||
while (--i >= 0) {
|
|
||||||
char c = contents.charAt(i);
|
|
||||||
if (c == '\n' || !Character.isWhitespace(c))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
return contents.substring(i, offset);
|
|
||||||
}
|
|
||||||
return ""; //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int skipStandaloneCommentBlock(String contents, int offset, int endOffset,
|
|
||||||
IASTComment[] comments, NodeCommentMap commentMap) {
|
|
||||||
Map<IASTComment, IASTNode> inverseLeadingMap = new HashMap<>();
|
|
||||||
for (Map.Entry<IASTNode, List<IASTComment>> entry : commentMap.getLeadingMap().entrySet()) {
|
|
||||||
IASTNode node = entry.getKey();
|
|
||||||
if (getNodeOffset(node) <= endOffset) {
|
|
||||||
for (IASTComment comment : entry.getValue()) {
|
|
||||||
inverseLeadingMap.put(comment, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Map<IASTComment, IASTNode> inverseFreestandingMap = new HashMap<>();
|
|
||||||
for (Map.Entry<IASTNode, List<IASTComment>> entry : commentMap.getFreestandingMap().entrySet()) {
|
|
||||||
IASTNode node = entry.getKey();
|
|
||||||
if (getNodeEndOffset(node) < endOffset) {
|
|
||||||
for (IASTComment comment : entry.getValue()) {
|
|
||||||
inverseFreestandingMap.put(comment, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < comments.length; i++) {
|
|
||||||
IASTComment comment = comments[i];
|
|
||||||
int commentOffset = getNodeOffset(comment);
|
|
||||||
if (commentOffset >= offset) {
|
|
||||||
if (commentOffset >= endOffset)
|
|
||||||
break;
|
|
||||||
IASTNode node = inverseLeadingMap.get(comment);
|
|
||||||
if (node != null) {
|
|
||||||
List<IASTComment> leadingComments = commentMap.getLeadingMap().get(node);
|
|
||||||
IASTComment previous = leadingComments.get(0);
|
|
||||||
for (int j = 1; j < leadingComments.size(); j++) {
|
|
||||||
comment = leadingComments.get(j);
|
|
||||||
if (getStartingLineNumber(comment) > getEndingLineNumber(previous) + 1)
|
|
||||||
return ASTNodes.skipToNextLineAfterNode(contents, previous);
|
|
||||||
previous = comment;
|
|
||||||
}
|
|
||||||
if (getStartingLineNumber(node) > getEndingLineNumber(previous) + 1)
|
|
||||||
return ASTNodes.skipToNextLineAfterNode(contents, previous);
|
|
||||||
}
|
|
||||||
node = inverseFreestandingMap.get(comment);
|
|
||||||
if (node != null) {
|
|
||||||
List<IASTComment> freestandingComments = commentMap.getFreestandingMap().get(node);
|
|
||||||
IASTComment previous = freestandingComments.get(0);
|
|
||||||
for (int j = 1; j < freestandingComments.size(); j++) {
|
|
||||||
comment = freestandingComments.get(j);
|
|
||||||
if (getStartingLineNumber(comment) > getEndingLineNumber(previous) + 1)
|
|
||||||
return ASTNodes.skipToNextLineAfterNode(contents, previous);
|
|
||||||
previous = comment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<IBinding> removeBindingsDefinedInIncludedHeaders(IASTTranslationUnit ast,
|
private Set<IBinding> removeBindingsDefinedInIncludedHeaders(IASTTranslationUnit ast,
|
||||||
Set<IBinding> bindings, IIndexFileSet reachableHeaders) throws CoreException {
|
Set<IBinding> bindings, IIndexFileSet reachableHeaders) throws CoreException {
|
||||||
List<InclusionRequest> requests = createInclusionRequests(ast, bindings, true, reachableHeaders);
|
List<InclusionRequest> requests = createInclusionRequests(ast, bindings, true, reachableHeaders);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2012, 2013 Google, Inc and others.
|
* Copyright (c) 2012, 2014 Google, Inc and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -10,19 +10,45 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit.getNodeEndOffset;
|
import java.util.ArrayList;
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit.getNodeOffset;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.eclipse.core.resources.IProject;
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
import org.eclipse.core.runtime.Path;
|
||||||
import org.eclipse.core.runtime.content.IContentType;
|
import org.eclipse.core.runtime.content.IContentType;
|
||||||
import org.eclipse.jface.text.IRegion;
|
import org.eclipse.jface.text.IRegion;
|
||||||
|
import org.eclipse.jface.text.Region;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTComment;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorPragmaStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
import org.eclipse.cdt.core.index.IIndexFile;
|
import org.eclipse.cdt.core.index.IIndexFile;
|
||||||
import org.eclipse.cdt.core.index.IIndexFileLocation;
|
import org.eclipse.cdt.core.index.IIndexFileLocation;
|
||||||
import org.eclipse.cdt.core.index.IndexLocationFactory;
|
import org.eclipse.cdt.core.index.IndexLocationFactory;
|
||||||
|
import org.eclipse.cdt.core.parser.Keywords;
|
||||||
|
import org.eclipse.cdt.core.parser.util.CharArrayIntMap;
|
||||||
|
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.rewrite.util.ASTNodes;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.rewrite.util.TextUtil;
|
||||||
|
import org.eclipse.cdt.internal.core.parser.scanner.CharArray;
|
||||||
|
import org.eclipse.cdt.internal.core.parser.scanner.IncludeGuardDetection;
|
||||||
|
import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
|
||||||
|
import org.eclipse.cdt.internal.corext.codemanipulation.IncludeInfo;
|
||||||
|
import org.eclipse.cdt.internal.corext.codemanipulation.InclusionContext;
|
||||||
|
import org.eclipse.cdt.internal.corext.codemanipulation.StyledInclude;
|
||||||
|
|
||||||
public class IncludeUtil {
|
public class IncludeUtil {
|
||||||
/** Not instantiatable. All methods are static. */
|
/** Not instantiatable. All methods are static. */
|
||||||
|
@ -72,7 +98,259 @@ public class IncludeUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isContainedInRegion(IASTNode node, IRegion region) {
|
public static boolean isContainedInRegion(IASTNode node, IRegion region) {
|
||||||
return getNodeOffset(node) >= region.getOffset()
|
return ASTNodes.offset(node) >= region.getOffset()
|
||||||
&& getNodeEndOffset(node) <= region.getOffset() + region.getLength();
|
&& ASTNodes.endOffset(node) <= region.getOffset() + region.getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the region containing nothing but include statements located before the first
|
||||||
|
* statement that may depend on includes.
|
||||||
|
*
|
||||||
|
* @param contents the contents of the translation unit
|
||||||
|
* @param ast the AST
|
||||||
|
* @param commentMap comments of the translation unit
|
||||||
|
* @return the include region, possibly empty
|
||||||
|
*/
|
||||||
|
public static IRegion getSafeIncludeReplacementRegion(String contents, IASTTranslationUnit ast,
|
||||||
|
NodeCommentMap commentMap) {
|
||||||
|
int maxSafeOffset = ast.getFileLocation().getNodeLength();
|
||||||
|
IASTDeclaration[] declarations = ast.getDeclarations(true);
|
||||||
|
if (declarations.length != 0)
|
||||||
|
maxSafeOffset = declarations[0].getFileLocation().getNodeOffset();
|
||||||
|
|
||||||
|
boolean topCommentSkipped = false;
|
||||||
|
int includeOffset = -1;
|
||||||
|
int includeEndOffset = -1;
|
||||||
|
int includeGuardStatementsToSkip = getNumberOfIncludeGuardStatementsToSkip(contents, ast);
|
||||||
|
int includeGuardEndOffset = -1;
|
||||||
|
for (IASTPreprocessorStatement statement : ast.getAllPreprocessorStatements()) {
|
||||||
|
if (statement.isPartOfTranslationUnitFile()) {
|
||||||
|
IASTFileLocation fileLocation = statement.getFileLocation();
|
||||||
|
int offset = fileLocation.getNodeOffset();
|
||||||
|
if (offset >= maxSafeOffset)
|
||||||
|
break;
|
||||||
|
int endOffset = offset + fileLocation.getNodeLength();
|
||||||
|
|
||||||
|
if (includeGuardStatementsToSkip > 0) {
|
||||||
|
--includeGuardStatementsToSkip;
|
||||||
|
includeGuardEndOffset = endOffset;
|
||||||
|
if (!commentMap.getLeadingCommentsForNode(statement).isEmpty()) {
|
||||||
|
topCommentSkipped = true;
|
||||||
|
}
|
||||||
|
} else if (statement instanceof IASTPreprocessorIncludeStatement) {
|
||||||
|
if (includeOffset < 0)
|
||||||
|
includeOffset = offset;
|
||||||
|
includeEndOffset = endOffset;
|
||||||
|
includeGuardStatementsToSkip = 0; // Just in case
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (includeOffset < 0) {
|
||||||
|
if (includeGuardEndOffset >= 0) {
|
||||||
|
includeOffset = TextUtil.skipToNextLine(contents, includeGuardEndOffset);
|
||||||
|
} else {
|
||||||
|
includeOffset = 0;
|
||||||
|
}
|
||||||
|
if (!topCommentSkipped) {
|
||||||
|
// Skip the first comment block near the top of the file.
|
||||||
|
includeOffset = skipStandaloneCommentBlock(contents, includeOffset, maxSafeOffset,
|
||||||
|
ast.getComments(), commentMap);
|
||||||
|
}
|
||||||
|
includeEndOffset = includeOffset;
|
||||||
|
} else {
|
||||||
|
includeEndOffset = TextUtil.skipToNextLine(contents, includeEndOffset);
|
||||||
|
}
|
||||||
|
return new Region(includeOffset, includeEndOffset - includeOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the include statements within the given region.
|
||||||
|
*
|
||||||
|
* @param existingIncludes the include statements to choose from
|
||||||
|
* @param region the region to select includes within
|
||||||
|
* @param inclusionContext the inclusion context
|
||||||
|
* @return a list of {@link StyledInclude} objects representing the includes
|
||||||
|
*/
|
||||||
|
public static List<StyledInclude> getIncludesInRegion(IASTPreprocessorIncludeStatement[] existingIncludes,
|
||||||
|
IRegion region, InclusionContext inclusionContext) {
|
||||||
|
// Populate a list of existing includes in the include insertion region.
|
||||||
|
List<StyledInclude> includes = new ArrayList<>();
|
||||||
|
for (IASTPreprocessorIncludeStatement include : existingIncludes) {
|
||||||
|
if (include.isPartOfTranslationUnitFile() && isContainedInRegion(include, region)) {
|
||||||
|
String name = new String(include.getName().getSimpleID());
|
||||||
|
IncludeInfo includeInfo = new IncludeInfo(name, include.isSystemInclude());
|
||||||
|
String path = include.getPath();
|
||||||
|
// An empty path means that the include was not resolved.
|
||||||
|
IPath header = path.isEmpty() ? null : Path.fromOSString(path);
|
||||||
|
IncludeGroupStyle style =
|
||||||
|
header != null ? inclusionContext.getIncludeStyle(header) : inclusionContext.getIncludeStyle(includeInfo);
|
||||||
|
StyledInclude prototype = new StyledInclude(header, includeInfo, style, include);
|
||||||
|
includes.add(prototype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return includes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the include guard in the file and, if found, returns its value and occurrences
|
||||||
|
* in the file.
|
||||||
|
*
|
||||||
|
* @param contents the contents of the translation unit
|
||||||
|
* @param ast the AST
|
||||||
|
* @param includeGuardPositions the list of include guard occurrences that is populated by
|
||||||
|
* the method
|
||||||
|
* @return the include guard, or {@code null} if not found
|
||||||
|
*/
|
||||||
|
public static String findIncludeGuard(String contents, IASTTranslationUnit ast,
|
||||||
|
List<IRegion> includeGuardPositions) {
|
||||||
|
includeGuardPositions.clear();
|
||||||
|
IASTPreprocessorStatement[] preprocessorStatements = ast.getAllPreprocessorStatements();
|
||||||
|
int i = 0;
|
||||||
|
while (true) {
|
||||||
|
if (i >= preprocessorStatements.length)
|
||||||
|
return null;
|
||||||
|
if (preprocessorStatements[i].isPartOfTranslationUnitFile())
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
IASTPreprocessorStatement statement = preprocessorStatements[i];
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
if (isPragmaOnce(statement)) {
|
||||||
|
offset = ASTNodes.endOffset(statement);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
char[] guardChars = detectIncludeGuard(contents, offset);
|
||||||
|
if (guardChars == null)
|
||||||
|
return null;
|
||||||
|
String guard = new String(guardChars);
|
||||||
|
int count = 0;
|
||||||
|
IASTPreprocessorStatement lastStatement = null;
|
||||||
|
for (; i < preprocessorStatements.length; i++) {
|
||||||
|
statement = preprocessorStatements[i];
|
||||||
|
if (statement.isPartOfTranslationUnitFile()) {
|
||||||
|
if (count < 2) {
|
||||||
|
findGuardInRange(contents, guard, ASTNodes.offset(statement),
|
||||||
|
ASTNodes.endOffset(statement), includeGuardPositions);
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
lastStatement = statement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastStatement != null) {
|
||||||
|
findGuardInRange(contents, guard, ASTNodes.offset(lastStatement),
|
||||||
|
contents.length(), includeGuardPositions);
|
||||||
|
}
|
||||||
|
return guard;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getNumberOfIncludeGuardStatementsToSkip(String contents, IASTTranslationUnit ast) {
|
||||||
|
IASTPreprocessorStatement statement = findFirstPreprocessorStatement(ast);
|
||||||
|
if (statement == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int num = 0;
|
||||||
|
int offset = 0;
|
||||||
|
if (isPragmaOnce(statement)) {
|
||||||
|
num++;
|
||||||
|
offset = ASTNodes.endOffset(statement);
|
||||||
|
}
|
||||||
|
char[] guard = detectIncludeGuard(contents, offset);
|
||||||
|
if (guard != null) {
|
||||||
|
num += 2;
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static char[] detectIncludeGuard(String contents, int offset) {
|
||||||
|
char[] contentsChars = contents.toCharArray();
|
||||||
|
if (offset != 0)
|
||||||
|
contentsChars = Arrays.copyOfRange(contentsChars, offset, contentsChars.length);
|
||||||
|
CharArrayIntMap ppKeywords= new CharArrayIntMap(40, -1);
|
||||||
|
Keywords.addKeywordsPreprocessor(ppKeywords);
|
||||||
|
char[] guardChars = IncludeGuardDetection.detectIncludeGuard(
|
||||||
|
new CharArray(contentsChars), new LexerOptions(), ppKeywords);
|
||||||
|
return guardChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void findGuardInRange(String contents, String guard, int offset, int endOffset,
|
||||||
|
List<IRegion> includeGuardPositions) {
|
||||||
|
int pos = contents.indexOf(guard, offset);
|
||||||
|
if (pos >= 0 && pos + guard.length() <= endOffset) {
|
||||||
|
includeGuardPositions.add(new Region(pos, guard.length()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int skipStandaloneCommentBlock(String contents, int offset, int endOffset,
|
||||||
|
IASTComment[] comments, NodeCommentMap commentMap) {
|
||||||
|
Map<IASTComment, IASTNode> inverseLeadingMap = new HashMap<>();
|
||||||
|
for (Map.Entry<IASTNode, List<IASTComment>> entry : commentMap.getLeadingMap().entrySet()) {
|
||||||
|
IASTNode node = entry.getKey();
|
||||||
|
if (ASTNodes.offset(node) <= endOffset) {
|
||||||
|
for (IASTComment comment : entry.getValue()) {
|
||||||
|
inverseLeadingMap.put(comment, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<IASTComment, IASTNode> inverseFreestandingMap = new HashMap<>();
|
||||||
|
for (Map.Entry<IASTNode, List<IASTComment>> entry : commentMap.getFreestandingMap().entrySet()) {
|
||||||
|
IASTNode node = entry.getKey();
|
||||||
|
if (ASTNodes.endOffset(node) < endOffset) {
|
||||||
|
for (IASTComment comment : entry.getValue()) {
|
||||||
|
inverseFreestandingMap.put(comment, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < comments.length; i++) {
|
||||||
|
IASTComment comment = comments[i];
|
||||||
|
int commentOffset = ASTNodes.offset(comment);
|
||||||
|
if (commentOffset >= offset) {
|
||||||
|
if (commentOffset >= endOffset)
|
||||||
|
break;
|
||||||
|
IASTNode node = inverseLeadingMap.get(comment);
|
||||||
|
if (node != null) {
|
||||||
|
List<IASTComment> leadingComments = commentMap.getLeadingMap().get(node);
|
||||||
|
IASTComment previous = leadingComments.get(0);
|
||||||
|
for (int j = 1; j < leadingComments.size(); j++) {
|
||||||
|
comment = leadingComments.get(j);
|
||||||
|
if (ASTNodes.getStartingLineNumber(comment) > ASTNodes.getEndingLineNumber(previous) + 1)
|
||||||
|
return ASTNodes.skipToNextLineAfterNode(contents, previous);
|
||||||
|
previous = comment;
|
||||||
|
}
|
||||||
|
if (ASTNodes.getStartingLineNumber(node) > ASTNodes.getEndingLineNumber(previous) + 1)
|
||||||
|
return ASTNodes.skipToNextLineAfterNode(contents, previous);
|
||||||
|
}
|
||||||
|
node = inverseFreestandingMap.get(comment);
|
||||||
|
if (node != null) {
|
||||||
|
List<IASTComment> freestandingComments = commentMap.getFreestandingMap().get(node);
|
||||||
|
IASTComment previous = freestandingComments.get(0);
|
||||||
|
for (int j = 1; j < freestandingComments.size(); j++) {
|
||||||
|
comment = freestandingComments.get(j);
|
||||||
|
if (ASTNodes.getStartingLineNumber(comment) > ASTNodes.getEndingLineNumber(previous) + 1)
|
||||||
|
return ASTNodes.skipToNextLineAfterNode(contents, previous);
|
||||||
|
previous = comment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IASTPreprocessorStatement findFirstPreprocessorStatement(IASTTranslationUnit ast) {
|
||||||
|
for (IASTPreprocessorStatement statement : ast.getAllPreprocessorStatements()) {
|
||||||
|
if (statement.isPartOfTranslationUnitFile())
|
||||||
|
return statement;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPragmaOnce(IASTPreprocessorStatement statement) {
|
||||||
|
if (!(statement instanceof IASTPreprocessorPragmaStatement))
|
||||||
|
return false;
|
||||||
|
return CharArrayUtils.equals(((IASTPreprocessorPragmaStatement) statement).getMessage(), "once"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2014 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.rename;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IContainer;
|
||||||
|
import org.eclipse.core.resources.IFile;
|
||||||
|
import org.eclipse.core.resources.IResource;
|
||||||
|
import org.eclipse.core.resources.IResourceProxy;
|
||||||
|
import org.eclipse.core.resources.IResourceProxyVisitor;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
|
import org.eclipse.core.runtime.OperationCanceledException;
|
||||||
|
import org.eclipse.core.runtime.Path;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.ltk.core.refactoring.Change;
|
||||||
|
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
|
||||||
|
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
|
||||||
|
import org.eclipse.ltk.core.refactoring.participants.MoveArguments;
|
||||||
|
import org.eclipse.ltk.core.refactoring.participants.MoveParticipant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates include statements and include guards in response to a file or a folder move.
|
||||||
|
*/
|
||||||
|
public class HeaderFileMoveParticipant extends MoveParticipant {
|
||||||
|
private IResource movedResource;
|
||||||
|
private Change change;
|
||||||
|
|
||||||
|
public HeaderFileMoveParticipant() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean initialize(Object element) {
|
||||||
|
if (element instanceof IResource) {
|
||||||
|
this.movedResource = (IResource) element;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context)
|
||||||
|
throws OperationCanceledException {
|
||||||
|
MoveArguments args = getArguments();
|
||||||
|
if (!args.getUpdateReferences())
|
||||||
|
return null;
|
||||||
|
if (movedResource.isLinked())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Object destinationResource = args.getDestination();
|
||||||
|
if (!(destinationResource instanceof IContainer))
|
||||||
|
return null;
|
||||||
|
final IContainer destination = (IContainer) destinationResource;
|
||||||
|
final IPath destinationLocation = destination.getLocation();
|
||||||
|
if (destinationLocation.equals(movedResource.getLocation().removeLastSegments(1)))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Maps the affected files to new, not yet existing, files.
|
||||||
|
final Map<IFile, IFile> movedFiles = new HashMap<>();
|
||||||
|
if (movedResource instanceof IContainer) {
|
||||||
|
final int prefixLength = movedResource.getFullPath().segmentCount() - 1;
|
||||||
|
((IContainer) movedResource).accept(new IResourceProxyVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(IResourceProxy proxy) throws CoreException {
|
||||||
|
if (proxy.isLinked())
|
||||||
|
return false;
|
||||||
|
if (proxy.getType() == IResource.FILE) {
|
||||||
|
IFile file = (IFile) proxy.requestResource();
|
||||||
|
movedFiles.put(file, destination.getFile(file.getFullPath().removeFirstSegments(prefixLength)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}, IResource.NONE);
|
||||||
|
} else if (movedResource instanceof IFile) {
|
||||||
|
IFile file = (IFile) movedResource;
|
||||||
|
movedFiles.put(file, destination.getFile(new Path(movedResource.getName())));
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderFileReferenceAdjuster includeAdjuster = new HeaderFileReferenceAdjuster(movedFiles);
|
||||||
|
change = includeAdjuster.createChange(context, pm);
|
||||||
|
} catch (CoreException e) {
|
||||||
|
return RefactoringStatus.create(e.getStatus());
|
||||||
|
}
|
||||||
|
return RefactoringStatus.create(Status.OK_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Change createPreChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
|
||||||
|
pm.done();
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
|
||||||
|
pm.done();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return RenameMessages.HeaderFileMoveParticipant_name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,491 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2014 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.rename;
|
||||||
|
|
||||||
|
import static org.eclipse.cdt.internal.ui.editor.ASTProvider.WAIT_ACTIVE_ONLY;
|
||||||
|
import static org.eclipse.cdt.internal.ui.editor.ASTProvider.getASTProvider;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IFile;
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
|
import org.eclipse.core.resources.IResource;
|
||||||
|
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||||
|
import org.eclipse.core.resources.ResourcesPlugin;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
|
import org.eclipse.core.runtime.OperationCanceledException;
|
||||||
|
import org.eclipse.core.runtime.Platform;
|
||||||
|
import org.eclipse.core.runtime.SubMonitor;
|
||||||
|
import org.eclipse.core.runtime.preferences.IPreferencesService;
|
||||||
|
import org.eclipse.core.runtime.preferences.IScopeContext;
|
||||||
|
import org.eclipse.jface.text.IRegion;
|
||||||
|
import org.eclipse.ltk.core.refactoring.Change;
|
||||||
|
import org.eclipse.ltk.core.refactoring.CompositeChange;
|
||||||
|
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
|
||||||
|
import org.eclipse.ltk.core.refactoring.participants.ValidateEditChecker;
|
||||||
|
import org.eclipse.text.edits.DeleteEdit;
|
||||||
|
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.cdt.core.CCorePlugin;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTComment;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
|
import org.eclipse.cdt.core.index.IIndex;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexFile;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexFileLocation;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexInclude;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexManager;
|
||||||
|
import org.eclipse.cdt.core.index.IndexLocationFactory;
|
||||||
|
import org.eclipse.cdt.core.model.CoreModel;
|
||||||
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
|
import org.eclipse.cdt.core.model.IWorkingCopy;
|
||||||
|
import org.eclipse.cdt.ui.CUIPlugin;
|
||||||
|
import org.eclipse.cdt.ui.IWorkingCopyManager;
|
||||||
|
import org.eclipse.cdt.ui.PreferenceConstants;
|
||||||
|
import org.eclipse.cdt.ui.refactoring.CTextFileChange;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.ASTCommenter;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.rewrite.util.ASTNodes;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.rewrite.util.TextUtil;
|
||||||
|
import org.eclipse.cdt.internal.corext.codemanipulation.IncludeInfo;
|
||||||
|
import org.eclipse.cdt.internal.corext.codemanipulation.StubUtility;
|
||||||
|
import org.eclipse.cdt.internal.corext.codemanipulation.StyledInclude;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeCreationContext;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludePreferences;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates include statements and include guards in response to file or folder move or rename.
|
||||||
|
*/
|
||||||
|
public class HeaderFileReferenceAdjuster {
|
||||||
|
private static final int PARSE_MODE = ITranslationUnit.AST_SKIP_ALL_HEADERS
|
||||||
|
| ITranslationUnit.AST_CONFIGURE_USING_SOURCE_CONTEXT
|
||||||
|
| ITranslationUnit.AST_SKIP_FUNCTION_BODIES
|
||||||
|
| ITranslationUnit.AST_PARSE_INACTIVE_CODE;
|
||||||
|
|
||||||
|
private final Map<IFile, IFile> movedFiles;
|
||||||
|
private final Map<String, IPath> movedFilesByLocation;
|
||||||
|
private IIndex index;
|
||||||
|
private int indexLockCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param movedFiles keys are moved files, values are new, not yet existing, files
|
||||||
|
*/
|
||||||
|
public HeaderFileReferenceAdjuster(Map<IFile, IFile> movedFiles) {
|
||||||
|
this.movedFiles = movedFiles;
|
||||||
|
this.movedFilesByLocation = new HashMap<>();
|
||||||
|
for (Entry<IFile, IFile> entry : movedFiles.entrySet()) {
|
||||||
|
this.movedFilesByLocation.put(entry.getKey().getLocation().toOSString(), entry.getValue().getLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Change createChange(CheckConditionsContext context, IProgressMonitor pm)
|
||||||
|
throws CoreException, OperationCanceledException {
|
||||||
|
SubMonitor progress = SubMonitor.convert(pm, 10);
|
||||||
|
CompositeChange change = null;
|
||||||
|
Set<IFile> affectedFiles = new HashSet<>();
|
||||||
|
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
|
||||||
|
|
||||||
|
lockIndex();
|
||||||
|
try {
|
||||||
|
for (Entry<IFile, IFile> entry : movedFiles.entrySet()) {
|
||||||
|
IFile oldFile = entry.getKey();
|
||||||
|
IFile newFile = entry.getValue();
|
||||||
|
if (areIncludeGuardsAffected(oldFile, newFile))
|
||||||
|
affectedFiles.add(oldFile);
|
||||||
|
|
||||||
|
IIndexFileLocation indexFileLocation = IndexLocationFactory.getWorkspaceIFL(oldFile);
|
||||||
|
IIndexFile[] indexFiles = index.getFiles(indexFileLocation);
|
||||||
|
for (IIndexFile indexFile : indexFiles) {
|
||||||
|
IIndexInclude[] includes = index.findIncludedBy(indexFile);
|
||||||
|
for (IIndexInclude include : includes) {
|
||||||
|
IIndexFileLocation includeLocation = include.getIncludedByLocation();
|
||||||
|
String path = includeLocation.getFullPath();
|
||||||
|
if (path != null) {
|
||||||
|
IResource resource = workspaceRoot.findMember(path);
|
||||||
|
if (resource.getType() == IResource.FILE) {
|
||||||
|
IFile includer = (IFile) resource;
|
||||||
|
affectedFiles.add(includer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IWorkingCopyManager workingCopyManager = CUIPlugin.getDefault().getWorkingCopyManager();
|
||||||
|
IWorkingCopy[] workingCopies = workingCopyManager.getSharedWorkingCopies();
|
||||||
|
progress.worked(1);
|
||||||
|
progress = SubMonitor.convert(progress.newChild(9), workingCopies.length + affectedFiles.size());
|
||||||
|
|
||||||
|
List<Change> changes = new ArrayList<>();
|
||||||
|
ValidateEditChecker checker= (ValidateEditChecker) context.getChecker(ValidateEditChecker.class);
|
||||||
|
for (ITranslationUnit tu : workingCopies) {
|
||||||
|
addFileChange(tu, changes, checker, progress.newChild(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreModel coreModel = CoreModel.getDefault();
|
||||||
|
for (IFile file : affectedFiles) {
|
||||||
|
ITranslationUnit tu = (ITranslationUnit) coreModel.create(file);
|
||||||
|
if (workingCopyManager.findSharedWorkingCopy(tu) != null)
|
||||||
|
continue;
|
||||||
|
addFileChange(tu, changes, checker, progress.newChild(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changes.isEmpty()) {
|
||||||
|
change = new CompositeChange("", changes.toArray(new Change[changes.size()])); //$NON-NLS-1$
|
||||||
|
change.markAsSynthetic();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
unlockIndex();
|
||||||
|
pm.done();
|
||||||
|
}
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFileChange(ITranslationUnit tu, List<Change> changes, ValidateEditChecker checker,
|
||||||
|
IProgressMonitor pm) throws CoreException {
|
||||||
|
TextEdit edit = createEdit(tu, pm);
|
||||||
|
if (edit != null) {
|
||||||
|
CTextFileChange fileChange = new CTextFileChange(tu.getElementName(), tu);
|
||||||
|
fileChange.setEdit(edit);
|
||||||
|
changes.add(fileChange);
|
||||||
|
checker.addFile(fileChange.getFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextEdit createEdit(ITranslationUnit tu, IProgressMonitor pm)
|
||||||
|
throws CoreException, OperationCanceledException {
|
||||||
|
checkCanceled(pm);
|
||||||
|
|
||||||
|
IASTTranslationUnit sharedAst = null;
|
||||||
|
|
||||||
|
SubMonitor progress = SubMonitor.convert(pm, 2);
|
||||||
|
try {
|
||||||
|
IASTTranslationUnit ast =
|
||||||
|
getASTProvider().acquireSharedAST(tu, index, WAIT_ACTIVE_ONLY, progress.newChild(1));
|
||||||
|
if (ast == null) {
|
||||||
|
checkCanceled(pm);
|
||||||
|
ast= tu.getAST(index, PARSE_MODE);
|
||||||
|
if (ast == null)
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
sharedAst = ast;
|
||||||
|
}
|
||||||
|
return createEdit(ast, tu, progress.newChild(1));
|
||||||
|
} finally {
|
||||||
|
if (sharedAst != null) {
|
||||||
|
getASTProvider().releaseSharedAST(sharedAst);
|
||||||
|
}
|
||||||
|
pm.done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextEdit createEdit(IASTTranslationUnit ast, ITranslationUnit tu, IProgressMonitor pm)
|
||||||
|
throws CoreException, OperationCanceledException {
|
||||||
|
IncludeCreationContext context = new IncludeCreationContext(tu, index);
|
||||||
|
String contents = context.getSourceContents();
|
||||||
|
|
||||||
|
MultiTextEdit rootEdit = createIncludeGuardEdit(ast, tu, contents);
|
||||||
|
|
||||||
|
Map<IASTPreprocessorIncludeStatement, IPath> affectedIncludes = new IdentityHashMap<>();
|
||||||
|
IASTPreprocessorIncludeStatement[] existingIncludes = ast.getIncludeDirectives();
|
||||||
|
for (IASTPreprocessorIncludeStatement include : existingIncludes) {
|
||||||
|
if (include.isPartOfTranslationUnitFile()) {
|
||||||
|
String location;
|
||||||
|
if (include.isActive()) {
|
||||||
|
location = include.getPath();
|
||||||
|
if (location.isEmpty())
|
||||||
|
continue; // Unresolved include.
|
||||||
|
} else {
|
||||||
|
String name = new String(include.getName().getSimpleID());
|
||||||
|
IncludeInfo includeInfo = new IncludeInfo(name, include.isSystemInclude());
|
||||||
|
IPath path = context.resolveInclude(includeInfo);
|
||||||
|
if (path == null)
|
||||||
|
continue;
|
||||||
|
location = path.toString();
|
||||||
|
}
|
||||||
|
IPath newLocation = movedFilesByLocation.get(location);
|
||||||
|
if (newLocation != null) {
|
||||||
|
affectedIncludes.put(include, newLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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<StyledInclude> modifiedIncludes = new ArrayList<>();
|
||||||
|
// Put the changed includes into modifiedIncludes.
|
||||||
|
for (Entry<IASTPreprocessorIncludeStatement, IPath> 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<StyledInclude> mergedIncludes =
|
||||||
|
IncludeUtil.getIncludesInRegion(existingIncludes, includeRegion, context);
|
||||||
|
Deque<DeleteEdit> 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;
|
||||||
|
}
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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')
|
||||||
|
text.append(context.getLineDelimiter());
|
||||||
|
} else {
|
||||||
|
text.append(context.getLineDelimiter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text.append(include.getIncludeInfo().composeIncludeStatement());
|
||||||
|
List<IASTComment> 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, offset, ASTNodes.offset(existingInclude)) < 0) {
|
||||||
|
text.append(context.getLineDelimiter());
|
||||||
|
}
|
||||||
|
flushEditBuffer(offset, text, deletes, rootEdit);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isBlankLineNeededBetween(StyledInclude include1, StyledInclude include2,
|
||||||
|
IncludePreferences preferences) {
|
||||||
|
return include2.getStyle().isBlankLineNeededAfter(include1.getStyle(), preferences.includeStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MultiTextEdit createIncludeGuardEdit(IASTTranslationUnit ast, ITranslationUnit tu, String contents) {
|
||||||
|
IResource resource = tu.getResource();
|
||||||
|
IFile newFile = movedFiles.get(resource);
|
||||||
|
if (newFile == null)
|
||||||
|
return null;
|
||||||
|
boolean guardsAffected = areIncludeGuardsAffected((IFile) resource, newFile);
|
||||||
|
if (!guardsAffected)
|
||||||
|
return null;
|
||||||
|
List<IRegion> includeGuardPositions = new ArrayList<>();
|
||||||
|
String oldGuard = IncludeUtil.findIncludeGuard(contents, ast, includeGuardPositions);
|
||||||
|
if (oldGuard == null)
|
||||||
|
return null;
|
||||||
|
if (!oldGuard.equals(StubUtility.generateIncludeGuardSymbol(resource, tu.getCProject())))
|
||||||
|
return null;
|
||||||
|
IProject newProject = newFile.getProject();
|
||||||
|
ICProject newCProject = CoreModel.getDefault().create(newProject);
|
||||||
|
if (newCProject == null)
|
||||||
|
return null;
|
||||||
|
String guard = StubUtility.generateIncludeGuardSymbol(newFile, newCProject);
|
||||||
|
if (guard.equals(oldGuard))
|
||||||
|
return null;
|
||||||
|
MultiTextEdit rootEdit = new MultiTextEdit();
|
||||||
|
for (IRegion region : includeGuardPositions) {
|
||||||
|
rootEdit.addChild(new ReplaceEdit(region.getOffset(), region.getLength(), guard));
|
||||||
|
}
|
||||||
|
return rootEdit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void flushEditBuffer(int offset, StringBuilder text, Deque<DeleteEdit> deletes, MultiTextEdit edit) {
|
||||||
|
consumeDeletesUpTo(offset, deletes, edit);
|
||||||
|
if (text.length() != 0) {
|
||||||
|
edit.addChild(new InsertEdit(offset, text.toString()));
|
||||||
|
text.delete(0, text.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void consumeDeletesUpTo(int offset, Deque<DeleteEdit> deletes, MultiTextEdit rootEdit) {
|
||||||
|
while (!deletes.isEmpty()) {
|
||||||
|
DeleteEdit edit = deletes.peek();
|
||||||
|
if (edit.getOffset() > offset)
|
||||||
|
break;
|
||||||
|
deletes.remove();
|
||||||
|
rootEdit.addChild(edit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lockIndex() throws CoreException, OperationCanceledException {
|
||||||
|
if (indexLockCount == 0) {
|
||||||
|
if (index == null) {
|
||||||
|
ICProject[] projects= CoreModel.getDefault().getCModel().getCProjects();
|
||||||
|
index = CCorePlugin.getIndexManager().getIndex(projects,
|
||||||
|
IIndexManager.ADD_EXTENSION_FRAGMENTS_EDITOR);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
index.acquireReadLock();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indexLockCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unlockIndex() {
|
||||||
|
if (--indexLockCount <= 0) {
|
||||||
|
if (index != null) {
|
||||||
|
index.releaseReadLock();
|
||||||
|
}
|
||||||
|
index = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkCanceled(IProgressMonitor pm) throws OperationCanceledException {
|
||||||
|
if (pm != null && pm.isCanceled())
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean areIncludeGuardsAffected(IFile oldfile, IFile newFile) {
|
||||||
|
String filename = oldfile.getLocation().lastSegment();
|
||||||
|
if (!CoreModel.isValidHeaderUnitName(null, filename))
|
||||||
|
return false;
|
||||||
|
IPreferencesService preferences = Platform.getPreferencesService();
|
||||||
|
IScopeContext[] scopes = PreferenceConstants.getPreferenceScopes(oldfile.getProject());
|
||||||
|
int schema = preferences.getInt(CUIPlugin.PLUGIN_ID,
|
||||||
|
PreferenceConstants.CODE_TEMPLATES_INCLUDE_GUARD_SCHEME,
|
||||||
|
PreferenceConstants.CODE_TEMPLATES_INCLUDE_GUARD_SCHEME_FILE_NAME, scopes);
|
||||||
|
switch (schema) {
|
||||||
|
case PreferenceConstants.CODE_TEMPLATES_INCLUDE_GUARD_SCHEME_FILE_PATH:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case PreferenceConstants.CODE_TEMPLATES_INCLUDE_GUARD_SCHEME_FILE_NAME:
|
||||||
|
return !filename.equals(newFile.getName());
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2014 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.rename;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IContainer;
|
||||||
|
import org.eclipse.core.resources.IFile;
|
||||||
|
import org.eclipse.core.resources.IResource;
|
||||||
|
import org.eclipse.core.resources.IResourceProxy;
|
||||||
|
import org.eclipse.core.resources.IResourceProxyVisitor;
|
||||||
|
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
|
import org.eclipse.core.runtime.OperationCanceledException;
|
||||||
|
import org.eclipse.core.runtime.Path;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.ltk.core.refactoring.Change;
|
||||||
|
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
|
||||||
|
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
|
||||||
|
import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
|
||||||
|
import org.eclipse.ltk.core.refactoring.participants.RenameParticipant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates include statements and include guards in response to a file or a folder rename.
|
||||||
|
*/
|
||||||
|
public class HeaderFileRenameParticipant extends RenameParticipant {
|
||||||
|
private IResource renamedResource;
|
||||||
|
private Change change;
|
||||||
|
|
||||||
|
public HeaderFileRenameParticipant() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean initialize(Object element) {
|
||||||
|
if (element instanceof IResource) {
|
||||||
|
this.renamedResource = (IResource) element;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context)
|
||||||
|
throws OperationCanceledException {
|
||||||
|
RenameArguments args = getArguments();
|
||||||
|
if (!args.getUpdateReferences())
|
||||||
|
return null;
|
||||||
|
if (renamedResource.isLinked())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
String newName = args.getNewName();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Maps the affected files to new, not yet existing, files.
|
||||||
|
final Map<IFile, IFile> movedFiles = new HashMap<>();
|
||||||
|
if (renamedResource instanceof IContainer) {
|
||||||
|
final IPath oldPath = renamedResource.getFullPath();
|
||||||
|
final IPath newPath = oldPath.removeLastSegments(1).append(newName);
|
||||||
|
final IWorkspaceRoot workspaceRoot = renamedResource.getWorkspace().getRoot();
|
||||||
|
((IContainer) renamedResource).accept(new IResourceProxyVisitor() {
|
||||||
|
@Override
|
||||||
|
public boolean visit(IResourceProxy proxy) throws CoreException {
|
||||||
|
if (proxy.isLinked())
|
||||||
|
return false;
|
||||||
|
if (proxy.getType() == IResource.FILE) {
|
||||||
|
IFile file = (IFile) proxy.requestResource();
|
||||||
|
IPath path = replacePrefix(file.getFullPath(), oldPath.segmentCount(), newPath);
|
||||||
|
movedFiles.put(file, workspaceRoot.getFile(path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}, IResource.NONE);
|
||||||
|
} else if (renamedResource instanceof IFile) {
|
||||||
|
IFile file = (IFile) renamedResource;
|
||||||
|
movedFiles.put(file, file.getParent().getFile(new Path(newName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
HeaderFileReferenceAdjuster includeAdjuster = new HeaderFileReferenceAdjuster(movedFiles);
|
||||||
|
change = includeAdjuster.createChange(context, pm);
|
||||||
|
} catch (CoreException e) {
|
||||||
|
return RefactoringStatus.create(e.getStatus());
|
||||||
|
}
|
||||||
|
return RefactoringStatus.create(Status.OK_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Change createPreChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
|
||||||
|
pm.done();
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
|
||||||
|
pm.done();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return RenameMessages.HeaderFileRenameParticipant_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces first few segments of the given path by the contents of another path.
|
||||||
|
*
|
||||||
|
* @param path the original path
|
||||||
|
* @param prefixLength the number of segments of {@code path} to replace
|
||||||
|
* @param newPrefix the replacement path
|
||||||
|
* @return the modified path
|
||||||
|
* @since 5.8
|
||||||
|
*/
|
||||||
|
private static IPath replacePrefix(IPath path, int prefixLength, IPath newPrefix) {
|
||||||
|
return newPrefix.append(path.removeFirstSegments(prefixLength));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2004, 2010 Wind River Systems, Inc.
|
* Copyright (c) 2004, 2014 Wind River Systems, Inc.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -97,9 +97,11 @@ class RenameMessages extends NLS {
|
||||||
public static String CRenameTopProcessor_virtualMethod;
|
public static String CRenameTopProcessor_virtualMethod;
|
||||||
public static String CRenameTopProcessor_wizard_backup_title;
|
public static String CRenameTopProcessor_wizard_backup_title;
|
||||||
public static String CRenameTopProcessor_wizard_title;
|
public static String CRenameTopProcessor_wizard_title;
|
||||||
|
public static String HeaderFileMoveParticipant_name;
|
||||||
|
public static String HeaderFileRenameParticipant_name;
|
||||||
public static String RenameCSourceFolderChange_ErrorMsg;
|
public static String RenameCSourceFolderChange_ErrorMsg;
|
||||||
public static String RenameCSourceFolderChange_Name0;
|
public static String RenameCSourceFolderChange_Name0;
|
||||||
public static String RenameSourceFolder_0;
|
public static String SourceFolderRenameParticipant_name;
|
||||||
public static String RenameInformationPopup_delayJobName;
|
public static String RenameInformationPopup_delayJobName;
|
||||||
public static String RenameInformationPopup_EnterNewName;
|
public static String RenameInformationPopup_EnterNewName;
|
||||||
public static String RenameInformationPopup_menu;
|
public static String RenameInformationPopup_menu;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Copyright (c) 2005, 2010 IBM Corporation and others.
|
# Copyright (c) 2005, 2014 IBM Corporation and others.
|
||||||
# All rights reserved. This program and the accompanying materials
|
# All rights reserved. This program and the accompanying materials
|
||||||
# are made available under the terms of the Eclipse Public License v1.0
|
# are made available under the terms of the Eclipse Public License v1.0
|
||||||
# which accompanies this distribution, and is available at
|
# which accompanies this distribution, and is available at
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
# Markus Schorn, Wind River Systems Inc.
|
# Markus Schorn, Wind River Systems Inc.
|
||||||
# Sergey Prigogin (Google)
|
# Sergey Prigogin (Google)
|
||||||
###############################################################################
|
###############################################################################
|
||||||
ASTManager_error_macro_name_conflict=''{0}'' conflicts with the name of an existing macro!
|
ASTManager_error_macro_name_conflict=''{0}'' conflicts with the name of an existing macro.
|
||||||
ASTManager_subtask_analyzing=Analyzing {0} files
|
ASTManager_subtask_analyzing=Analyzing {0} files
|
||||||
ASTManager_task_analyze=Analyzing source code
|
ASTManager_task_analyze=Analyzing source code
|
||||||
ASTManager_task_generateAst=Generating AST
|
ASTManager_task_generateAst=Generating AST
|
||||||
|
@ -93,9 +93,11 @@ CRenameTopProcessor_type=type
|
||||||
CRenameTopProcessor_virtualMethod=virtual method
|
CRenameTopProcessor_virtualMethod=virtual method
|
||||||
CRenameTopProcessor_wizard_backup_title=Rename
|
CRenameTopProcessor_wizard_backup_title=Rename
|
||||||
CRenameTopProcessor_wizard_title=Rename ''{0}''
|
CRenameTopProcessor_wizard_title=Rename ''{0}''
|
||||||
|
HeaderFileMoveParticipant_name=Header File Move
|
||||||
|
HeaderFileRenameParticipant_name=Header File Rename
|
||||||
RenameCSourceFolderChange_ErrorMsg=Folder {0} does not exist
|
RenameCSourceFolderChange_ErrorMsg=Folder {0} does not exist
|
||||||
RenameCSourceFolderChange_Name0=Rename source folder {0} to {1}
|
RenameCSourceFolderChange_Name0=Rename source folder {0} to {1}
|
||||||
RenameSourceFolder_0=Rename C/C++ Source Folder
|
SourceFolderRenameParticipant_name=Rename C/C++ Source Folder
|
||||||
RenameInformationPopup_SnapTo=&Snap To
|
RenameInformationPopup_SnapTo=&Snap To
|
||||||
RenameInformationPopup_snap_under_left=&Under Left
|
RenameInformationPopup_snap_under_left=&Under Left
|
||||||
RenameInformationPopup_snap_under_right=U&nder Right
|
RenameInformationPopup_snap_under_right=U&nder Right
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2009 Institute for Software, HSR Hochschule fuer Technik
|
* Copyright (c) 2009, 2014 Institute for Software, HSR Hochschule fuer Technik
|
||||||
* Rapperswil, University of applied sciences and others.
|
* Rapperswil, University of applied sciences and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
@ -20,37 +20,36 @@ import org.eclipse.core.runtime.Status;
|
||||||
import org.eclipse.ltk.core.refactoring.Change;
|
import org.eclipse.ltk.core.refactoring.Change;
|
||||||
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
|
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
|
||||||
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
|
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
|
||||||
import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
|
|
||||||
import org.eclipse.ltk.core.refactoring.participants.RenameParticipant;
|
import org.eclipse.ltk.core.refactoring.participants.RenameParticipant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Updates source folders and associated filters of a C/C++ project in response to a folder rename.
|
||||||
|
*
|
||||||
* @author Emanuel Graf IFS
|
* @author Emanuel Graf IFS
|
||||||
*/
|
*/
|
||||||
public class RenameSourceFolder extends RenameParticipant {
|
public class SourceFolderRenameParticipant extends RenameParticipant {
|
||||||
private IFolder oldFolder;
|
private IFolder oldFolder;
|
||||||
private String newName;
|
|
||||||
|
|
||||||
public RenameSourceFolder() {
|
public SourceFolderRenameParticipant() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context)
|
public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context)
|
||||||
throws OperationCanceledException {
|
throws OperationCanceledException {
|
||||||
RenameArguments arg = getArguments();
|
|
||||||
newName = arg.getNewName();
|
|
||||||
return RefactoringStatus.create(Status.OK_STATUS);
|
return RefactoringStatus.create(Status.OK_STATUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
|
public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
|
||||||
IPath oldFolderPath = oldFolder.getFullPath();
|
IPath oldFolderPath = oldFolder.getFullPath();
|
||||||
IPath newFolderPath = oldFolder.getFullPath().uptoSegment(oldFolder.getFullPath().segmentCount() - 1).append(newName);
|
String newName = getArguments().getNewName();
|
||||||
|
IPath newFolderPath = oldFolderPath.removeLastSegments(1).append(newName);
|
||||||
return new RenameCSourceFolderChange(oldFolderPath, newFolderPath, oldFolder.getProject(), oldFolder);
|
return new RenameCSourceFolderChange(oldFolderPath, newFolderPath, oldFolder.getProject(), oldFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return RenameMessages.RenameSourceFolder_0;
|
return RenameMessages.SourceFolderRenameParticipant_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -2347,7 +2347,7 @@ public class PreferenceConstants {
|
||||||
|
|
||||||
// Code Templates
|
// Code Templates
|
||||||
store.setDefault(PreferenceConstants.CODE_TEMPLATES_INCLUDE_GUARD_SCHEME,
|
store.setDefault(PreferenceConstants.CODE_TEMPLATES_INCLUDE_GUARD_SCHEME,
|
||||||
CODE_TEMPLATES_INCLUDE_GUARD_SCHEME_FILE_NAME);
|
CODE_TEMPLATES_INCLUDE_GUARD_SCHEME_FILE_PATH);
|
||||||
|
|
||||||
// Name Style
|
// Name Style
|
||||||
store.setDefault(NAME_STYLE_CONSTANT_CAPITALIZATION, NAME_STYLE_CAPITALIZATION_UPPER_CASE);
|
store.setDefault(NAME_STYLE_CONSTANT_CAPITALIZATION, NAME_STYLE_CAPITALIZATION_UPPER_CASE);
|
||||||
|
|
|
@ -59,6 +59,8 @@ public class CTextFileChange extends TextFileChange {
|
||||||
public CTextFileChange(String name, ITranslationUnit tu) {
|
public CTextFileChange(String name, ITranslationUnit tu) {
|
||||||
super(name, getFile(tu));
|
super(name, getFile(tu));
|
||||||
fTranslationUnit = tu;
|
fTranslationUnit = tu;
|
||||||
|
if (tu instanceof IWorkingCopy)
|
||||||
|
fWorkingCopy = (IWorkingCopy) tu;
|
||||||
setTextType(TEXT_TYPE);
|
setTextType(TEXT_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +68,7 @@ public class CTextFileChange extends TextFileChange {
|
||||||
protected IDocument acquireDocument(IProgressMonitor pm) throws CoreException {
|
protected IDocument acquireDocument(IProgressMonitor pm) throws CoreException {
|
||||||
IDocument doc= super.acquireDocument(pm);
|
IDocument doc= super.acquireDocument(pm);
|
||||||
if (++fAcquireCount == 1) {
|
if (++fAcquireCount == 1) {
|
||||||
if (fTranslationUnit instanceof TranslationUnit && fWorkingCopy == null) {
|
if (fWorkingCopy == null && fTranslationUnit instanceof TranslationUnit) {
|
||||||
fWorkingCopy= ((TranslationUnit) fTranslationUnit).getWorkingCopy(null, DocumentAdapter.FACTORY);
|
fWorkingCopy= ((TranslationUnit) fTranslationUnit).getWorkingCopy(null, DocumentAdapter.FACTORY);
|
||||||
if (!fTranslationUnit.isOpen()) {
|
if (!fTranslationUnit.isOpen()) {
|
||||||
fTranslationUnit.open(null);
|
fTranslationUnit.open(null);
|
||||||
|
@ -89,7 +91,7 @@ public class CTextFileChange extends TextFileChange {
|
||||||
protected void releaseDocument(IDocument document, IProgressMonitor pm) throws CoreException {
|
protected void releaseDocument(IDocument document, IProgressMonitor pm) throws CoreException {
|
||||||
super.releaseDocument(document, pm);
|
super.releaseDocument(document, pm);
|
||||||
if (--fAcquireCount == 0) {
|
if (--fAcquireCount == 0) {
|
||||||
if (fWorkingCopy != null) {
|
if (fWorkingCopy != null && fWorkingCopy != fTranslationUnit) {
|
||||||
fWorkingCopy.destroy();
|
fWorkingCopy.destroy();
|
||||||
fWorkingCopy= null;
|
fWorkingCopy= null;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue