1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-12 10:45:37 +02:00

Bug 45203. Major milestone - Organize Includes command is ready for

alpha testing.
This commit is contained in:
Sergey Prigogin 2013-03-14 17:20:22 -07:00
parent 8691f9784c
commit 7ac4d43010
38 changed files with 2665 additions and 1232 deletions

View file

@ -59,7 +59,7 @@ Export-Package: org.eclipse.cdt.core,
org.eclipse.cdt.internal.core.dom.rewrite;x-friends:="org.eclipse.cdt.core.tests,org.eclipse.cdt.ui",
org.eclipse.cdt.internal.core.dom.rewrite.astwriter;x-friends:="org.eclipse.cdt.ui",
org.eclipse.cdt.internal.core.dom.rewrite.changegenerator;x-internal:=true,
org.eclipse.cdt.internal.core.dom.rewrite.commenthandler;x-internal:=true,
org.eclipse.cdt.internal.core.dom.rewrite.commenthandler;x-friends:="org.eclipse.cdt.ui",
org.eclipse.cdt.internal.core.dom.rewrite.util;x-internal:=true,
org.eclipse.cdt.internal.core.envvar;x-friends:="org.eclipse.cdt.ui,org.eclipse.cdt.managedbuilder.core",
org.eclipse.cdt.internal.core.index;x-friends:="org.eclipse.cdt.ui",

View file

@ -74,6 +74,21 @@ public class CharArrayUtils {
return true;
}
/**
* Returns {@code true} if the contents of a section of a character array are the same as
* contents of a string.
* @since 5.5
*/
public static final boolean equals(char[] str1, int start1, int length1, String str2) {
if (length1 != str2.length() || str1.length < length1 + start1)
return false;
for (int i = 0; i < length1; ++i) {
if (str1[start1++] != str2.charAt(i))
return false;
}
return true;
}
/**
* Returns {@code true} if a prefix of the character array is the same as contents
* of a string.
@ -117,6 +132,10 @@ public class CharArrayUtils {
return str1.length - str2.length;
}
/**
* Returns {@code true} if the contents of a section of a character array are the same as
* contents of another character array.
*/
public static final boolean equals(char[] str1, int start1, int length1, char[] str2) {
if (length1 != str2.length || str1.length < length1 + start1)
return false;

View file

@ -485,4 +485,52 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat
}
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;
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 Google, Inc and others.
* Copyright (c) 2012, 2013 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
@ -22,7 +22,6 @@ import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.TextSelection;
@ -56,8 +55,6 @@ import org.eclipse.cdt.internal.ui.refactoring.CRefactoringContext;
* Common base for refactoring tests.
*/
public abstract class RefactoringTestBase extends BaseTestCase {
protected static final NullProgressMonitor NULL_PROGRESS_MONITOR = new NullProgressMonitor();
/** Allows empty files to be created during test setup. */
protected boolean createEmptyFiles = true;
/** See {@link PreferenceConstants.CLASS_MEMBER_ASCENDING_VISIBILITY_ORDER} */
@ -137,7 +134,7 @@ public abstract class RefactoringTestBase extends BaseTestCase {
public void tearDown() throws Exception {
if (cproject != null) {
cproject.getProject().delete(IResource.FORCE | IResource.ALWAYS_DELETE_PROJECT_CONTENT,
NULL_PROGRESS_MONITOR);
npm());
}
resetPreferences();
super.tearDown();
@ -175,7 +172,7 @@ public abstract class RefactoringTestBase extends BaseTestCase {
protected void executeRefactoring(Refactoring refactoring, RefactoringContext context,
boolean withUserInput, boolean expectedSuccess) throws CoreException, Exception {
try {
RefactoringStatus initialStatus = refactoring.checkInitialConditions(NULL_PROGRESS_MONITOR);
RefactoringStatus initialStatus = refactoring.checkInitialConditions(npm());
if (!expectedSuccess) {
assertStatusFatalError(initialStatus);
return;
@ -190,7 +187,7 @@ public abstract class RefactoringTestBase extends BaseTestCase {
if (withUserInput)
simulateUserInput();
RefactoringStatus finalStatus = refactoring.checkFinalConditions(NULL_PROGRESS_MONITOR);
RefactoringStatus finalStatus = refactoring.checkFinalConditions(npm());
if (expectedFinalWarnings != 0) {
assertStatusWarning(finalStatus, expectedFinalWarnings);
} else if (expectedFinalInfos != 0) {
@ -198,8 +195,8 @@ public abstract class RefactoringTestBase extends BaseTestCase {
} else {
assertStatusOk(finalStatus);
}
Change change = refactoring.createChange(NULL_PROGRESS_MONITOR);
change.perform(NULL_PROGRESS_MONITOR);
Change change = refactoring.createChange(npm());
change.perform(npm());
} finally {
if (context != null)
context.dispose();
@ -212,7 +209,7 @@ public abstract class RefactoringTestBase extends BaseTestCase {
RefactoringHistory history = RefactoringHistoryService.getInstance().readRefactoringHistory(
new ByteArrayInputStream(scriptSource.getBytes()), 0);
for (RefactoringDescriptorProxy proxy : history.getDescriptors()) {
RefactoringDescriptor descriptor = proxy.requestDescriptor(NULL_PROGRESS_MONITOR);
RefactoringDescriptor descriptor = proxy.requestDescriptor(npm());
RefactoringStatus status = new RefactoringStatus();
RefactoringContext context = descriptor.createRefactoringContext(status);
assertTrue(status.isOK());

View file

@ -22,6 +22,7 @@ import org.eclipse.cdt.ui.tests.refactoring.extractlocalvariable.ExtractLocalVar
import org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest;
import org.eclipse.cdt.ui.tests.refactoring.hidemethod.HideMethodRefactoringTest;
import org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest;
import org.eclipse.cdt.ui.tests.refactoring.includes.IncludesTestSuite;
import org.eclipse.cdt.ui.tests.refactoring.rename.RenameRegressionTests;
import org.eclipse.cdt.ui.tests.refactoring.togglefunction.ToggleRefactoringTest;
import org.eclipse.cdt.ui.tests.refactoring.utils.UtilTestSuite;
@ -42,6 +43,7 @@ public class RefactoringTestSuite extends TestSuite {
suite.addTest(ImplementMethodRefactoringTest.suite());
suite.addTest(ExtractLocalVariableRefactoringTest.suite());
suite.addTest(ToggleRefactoringTest.suite());
suite.addTest(IncludesTestSuite.suite());
return suite;
}
}

View file

@ -181,7 +181,6 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
assertRefactoringSuccess();
}
//A.h
//#ifndef A_H_
//#define A_H_

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 Google, Inc and others.
* Copyright (c) 2012, 2013 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
@ -10,12 +10,16 @@
*******************************************************************************/
package org.eclipse.cdt.ui.tests.refactoring.includes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import junit.framework.TestSuite;
import com.ibm.icu.text.MessageFormat;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
@ -51,7 +55,8 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
fIndex.acquireReadLock();
ITranslationUnit tu = ast.getOriginatingTranslationUnit();
fContext = new InclusionContext(tu, fIndex);
fBindingClassifier = new BindingClassifier(fContext, ast);
fBindingClassifier = new BindingClassifier(fContext);
fBindingClassifier.classifyNodeContents(ast);
}
@Override
@ -69,15 +74,36 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
}
private void assertExpectedBindings(String[] expectedNames, Set<IBinding> bindings, String verb) {
Set<String> remaining = new HashSet<String>(Arrays.asList(expectedNames));
Set<String> expected = new TreeSet<String>(Arrays.asList(expectedNames));
Set<String> extra = new TreeSet<String>();
for (IBinding binding : bindings) {
String name = binding.getName();
if (!remaining.remove(name)) {
fail("Binding \"" + name + "\" should not be " + verb);
extra.add(binding.getName());
}
Set<String> missing = new TreeSet<String>(expected);
missing.removeAll(extra);
extra.removeAll(expected);
if (extra.isEmpty() && missing.isEmpty())
return;
List<String> errors = new ArrayList<String>(2);
if (!missing.isEmpty()) {
errors.add(MessageFormat.format("{0,choice,1#Binding|1<Bindings} \"{1}\" {0,choice,1#is|1<are} not {2}.",
missing.size(), join(missing, "\", \""), verb));
}
if (!remaining.isEmpty())
fail("Binding \"" + remaining.iterator().next() + "\" is not " + verb);
if (!extra.isEmpty()) {
errors.add(MessageFormat.format("{0,choice,1#Binding|1<Bindings} \"{1}\" should not be {2}.",
extra.size(), join(extra, "\", \""), verb));
}
fail(join(errors, " "));
}
private String join(Iterable<String> strings, String delimiter) {
StringBuilder buf = new StringBuilder();
for (String str : strings) {
if (buf.length() != 0)
buf.append(delimiter);
buf.append(str);
}
return buf.toString();
}
// class A;
@ -109,4 +135,46 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
public void testClassMember() throws Exception {
assertDefined("f", "A");
}
// class A { void m(); };
// void test(A* a) {
// a->m();
// }
public void testMethodCall() throws Exception {
assertDefined("A");
}
// struct A {};
// struct B {};
// struct C {
// A a;
// static B b;
// };
public void testFieldReference() throws Exception {
assertDefined("A");
assertDeclared("B");
}
// int a;
// void test() {
// void* x = &a;
// }
public void testVariableReference() throws Exception {
assertDefined("a"); // Forward declaration of variables is not allowed by default.
}
// struct A {
// void operator()(int p);
// };
// const A a;
// void test() {
// a(1);
// }
public void testCallOperator() throws Exception {
assertDefined("A", "a"); // Forward declaration of variables is not allowed by default.
}
}

View file

@ -0,0 +1,176 @@
/*******************************************************************************
* Copyright (c) 2013 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.includes;
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.preference.IPreferenceStore;
import org.osgi.framework.Bundle;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.IPDOMManager;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.index.IIndex;
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.testplugin.CProjectHelper;
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.testplugin.CTestPlugin;
import org.eclipse.cdt.ui.tests.refactoring.TestSourceFile;
import org.eclipse.cdt.internal.ui.refactoring.includes.IHeaderChooser;
/**
* Common base for include-related tests.
*/
public abstract class IncludesTestBase extends BaseTestCase {
protected final String LINE_DELIMITER = "\n";
protected static class FirstHeaderChooser implements IHeaderChooser {
@Override
public IPath chooseHeader(String bindingName, Collection<IPath> headers) {
return headers.isEmpty() ? null : headers.iterator().next();
}
}
/** Expected counts of errors, warnings and info messages */
protected int expectedInitialErrors;
protected int expectedInitialWarnings;
protected int expectedFinalWarnings;
protected int expectedFinalInfos;
protected IIndex index;
protected ICProject cproject;
protected IASTTranslationUnit ast;
protected TestSourceFile selectedFile;
private StringBuilder[] testData;
private boolean cpp = true;
private final Set<TestSourceFile> testFiles = new LinkedHashSet<TestSourceFile>();
protected IncludesTestBase() {
super();
}
protected IncludesTestBase(String name) {
super(name);
}
@Override
public void setUp() throws Exception {
super.setUp();
resetPreferences();
cproject = cpp ?
CProjectHelper.createCCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER) :
CProjectHelper.createCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER);
Bundle bundle = CTestPlugin.getDefault().getBundle();
CharSequence[] testData = TestSourceReader.getContentsForTest(bundle, "ui", getClass(), getName(), 0);
IFile sourceFile = null;
for (CharSequence contents : testData) {
TestSourceFile testFile = null;
boolean expectedResult = false;
BufferedReader reader = new BufferedReader(new StringReader(contents.toString()));
String line;
while ((line = reader.readLine()) != null) {
String trimmedLine = line.trim();
if (testFile == null) {
assertTrue("Invalid file name \"" + trimmedLine + "\"", trimmedLine.matches("^(\\w+/)*\\w+\\.\\w+$"));
testFile = new TestSourceFile(trimmedLine);
} else if (isResultDelimiter(trimmedLine)) {
expectedResult = true;
} else if (expectedResult) {
testFile.addLineToExpectedSource(line);
} else {
testFile.addLineToSource(line);
}
}
reader.close();
sourceFile = TestSourceReader.createFile(cproject.getProject(), new Path(testFile.getName()),
testFile.getSource());
testFiles.add(testFile);
selectedFile = testFile;
}
CCorePlugin.getIndexManager().setIndexerId(cproject, IPDOMManager.ID_FAST_INDEXER);
waitForIndexer(cproject);
index= CCorePlugin.getIndexManager().getIndex(cproject);
index.acquireReadLock();
ast = TestSourceReader.createIndexBasedAST(index, cproject, sourceFile);
}
@Override
public void tearDown() throws Exception {
if (cproject != null) {
cproject.getProject().delete(IResource.FORCE | IResource.ALWAYS_DELETE_PROJECT_CONTENT, npm());
}
resetPreferences();
super.tearDown();
}
protected ICProject getCProject() {
return cproject;
}
protected TestSourceFile getSelectedTestFile() {
return selectedFile;
}
protected IFile getSelectedFile() {
if (selectedFile == null)
return null;
return cproject.getProject().getFile(new Path(selectedFile.getName()));
}
protected ITranslationUnit getSelectedTranslationUnit() {
IFile file = getSelectedFile();
if (file == null)
return null;
return (ITranslationUnit) CoreModel.getDefault().create(file);
}
protected boolean isCpp() {
return cpp;
}
protected void setCpp(boolean cpp) {
this.cpp = cpp;
}
private boolean isResultDelimiter(String str) {
if (str.isEmpty())
return false;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) != '=')
return false;
}
return true;
}
protected void resetPreferences() {
}
protected IPreferenceStore getPreferenceStore() {
return CUIPlugin.getDefault().getPreferenceStore();
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 Google, Inc and others.
* Copyright (c) 2013 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
@ -8,18 +8,17 @@
* Contributors:
* Sergey Prigogin (Google) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.includes;
package org.eclipse.cdt.ui.tests.refactoring.includes;
import org.eclipse.osgi.util.NLS;
import junit.framework.Test;
import junit.framework.TestSuite;
final class Messages extends NLS {
public static String IncludeOrganizer_ChooseHeader;
public class IncludesTestSuite extends TestSuite {
static {
NLS.initializeMessages(Messages.class.getName(), Messages.class);
}
// Do not instantiate
private Messages() {
public static Test suite() throws Exception {
IncludesTestSuite suite = new IncludesTestSuite();
suite.addTest(BindingClassifierTest.suite());
suite.addTest(OrganizeIncludesTest.suite());
return suite;
}
}

View file

@ -0,0 +1,298 @@
/*******************************************************************************
* Copyright (c) 2013 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.includes;
import java.util.List;
import junit.framework.Test;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.ui.PreferenceConstants;
import org.eclipse.cdt.internal.ui.refactoring.includes.IHeaderChooser;
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeOrganizer;
/**
* Tests for Extract Function refactoring.
*/
public class OrganizeIncludesTest extends IncludesTestBase {
public OrganizeIncludesTest() {
super();
}
public OrganizeIncludesTest(String name) {
super(name);
}
public static Test suite() {
return suite(OrganizeIncludesTest.class);
}
@Override
protected void resetPreferences() {
super.resetPreferences();
getPreferenceStore().setToDefault(PreferenceConstants.INCLUDES_UNUSED_STATEMENTS_DISPOSITION);
getPreferenceStore().setToDefault(PreferenceConstants.FORWARD_DECLARE_COMPOSITE_TYPES);
getPreferenceStore().setToDefault(PreferenceConstants.FORWARD_DECLARE_ENUMS);
getPreferenceStore().setToDefault(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS);
getPreferenceStore().setToDefault(PreferenceConstants.FORWARD_DECLARE_TEMPLATES);
getPreferenceStore().setToDefault(PreferenceConstants.FORWARD_DECLARE_NAMESPACE_ELEMENTS);
getPreferenceStore().setToDefault(PreferenceConstants.INCLUDES_ALLOW_REORDERING);
}
private void assertExpectedResults() throws Exception {
String actual = organizeIncludes(ast.getOriginatingTranslationUnit());
assertEquals(selectedFile.getExpectedSource(), actual);
}
/**
* Invokes include organizer and returns the new contents of the translation unit.
*/
private String organizeIncludes(ITranslationUnit tu) throws Exception {
IHeaderChooser headerChooser = new FirstHeaderChooser();
IncludeOrganizer organizer = new IncludeOrganizer(tu, index, LINE_DELIMITER, headerChooser);
List<TextEdit> edits = organizer.organizeIncludes(ast);
IDocument document = new Document(new String(tu.getContents()));
if (!edits.isEmpty()) {
// Apply text edits.
MultiTextEdit edit = new MultiTextEdit();
edit.addChildren(edits.toArray(new TextEdit[edits.size()]));
edit.apply(document);
}
return document.get();
}
//h1.h
//typedef int my_type;
//A.h
//class A {
// my_type m1();
//};
//A.cpp
//// Comment line 1
//// Comment line 2
//
//// Comment for m1
//my_type A::m1() {
// return 0;
//}
//====================
//// Comment line 1
//// Comment line 2
//
//#include "A.h"
//
//#include "h1.h"
//
//// Comment for m1
//my_type A::m1() {
// return 0;
//}
public void testNoExistingIncludes() throws Exception {
assertExpectedResults();
}
//B.h
//class B {};
//C.h
//class C {};
//A.h
//#if !defined(INCLUDE_GUARD)
//#define INCLUDE_GUARD
//// Comment line 1
//// Comment line 2
//
//// Comment for A
//class A {
// B f;
// C m();
//};
//#endif // INCLUDE_GUARD
//====================
//#if !defined(INCLUDE_GUARD)
//#define INCLUDE_GUARD
//// Comment line 1
//// Comment line 2
//
//#include "B.h"
//
//class C;
//
//// Comment for A
//class A {
// B f;
// C m();
//};
//#endif // INCLUDE_GUARD
public void testIncludeGuards() throws Exception {
assertExpectedResults();
}
//B.h
//template <typename T> class B {};
//C.h
//class C {};
//A.h
//#pragma once
//namespace ns {
//// Comment line 1
//// Comment line 2
//
//// Comment for A
//class A : public B<C> {};
//} // namespace ns
//====================
//#pragma once
//
//#include "B.h"
//#include "C.h"
//
//namespace ns {
//// Comment line 1
//// Comment line 2
//
//// Comment for A
//class A : public B<C> {};
//} // namespace ns
public void testPragmaOnce() throws Exception {
assertExpectedResults();
}
//h1.h
//typedef int Type1;
//h2.h
//class Type2 {};
//h3.h
//enum Type3 { ONE, TWO };
//h4.h
//class Unrelated {};
//A.h
//#include "h1.h"
//class Type2;
//enum class Type3;
//extern Type1 f1();
//extern Type2 f2();
//extern Type3 f3();
//A.cpp
//// Comment
//
//#include "h2.h" /* Required */ // another comment
//#include "h1.h" // Unused
//#include "h3.h"
//#include "h5.h" // Unresolved includes are preserved
//#ifdef SOME_OTHER_TIME
//#include "h4.h" // Unused but unsafe to remove
//#endif
//
//void test() {
// f1();
// f2();
// f3();
//}
//====================
//// Comment
//
//#include "A.h"
//
////#include "h1.h" // Unused
//#include "h2.h" /* Required */ // another comment
//#include "h3.h"
//#include "h5.h" // Unresolved includes are preserved
//
//#ifdef SOME_OTHER_TIME
//#include "h4.h" // Unused but unsafe to remove
//#endif
//
//void test() {
// f1();
// f2();
// f3();
//}
public void testExistingIncludes() throws Exception {
assertExpectedResults();
}
//h1.h
//typedef int Type1;
//h2.h
//class Type2 {};
//h3.h
//enum class Type3 { ONE, TWO };
//h4.h
//class Unrelated {};
//A.h
//#include "h1.h"
//class Type2;
//enum class Type3;
//extern Type1 f1();
//extern Type2 f2();
//extern Type3 f3();
//A.cpp
//// Comment
//
//#include "h2.h" /* Required */ // another comment
//#include "h1.h" // Unused
//#include "h3.h"
//#include "h5.h" // Unresolved includes are preserved
//#ifdef SOME_OTHER_TIME
//#include "h4.h" // Unused but unsafe to remove
//#endif
//
//void test() {
// f1();
// f2();
// f3();
//}
//====================
//// Comment
//
//#include "h2.h" /* Required */ // another comment
////#include "h1.h" // Unused
//#include "h3.h"
//#include "h5.h" // Unresolved includes are preserved
//#include "A.h"
//
//#ifdef SOME_OTHER_TIME
//#include "h4.h" // Unused but unsafe to remove
//#endif
//
//void test() {
// f1();
// f2();
// f3();
//}
public void testExistingIncludesNoReordering() throws Exception {
getPreferenceStore().setValue(PreferenceConstants.INCLUDES_ALLOW_REORDERING, false);
assertExpectedResults();
}
}

View file

@ -276,6 +276,10 @@ ActionDefinition.openType.description= Open an element in an Editor
ActionDefinition.addInclude.name= Add Include
ActionDefinition.addInclude.description= Create include statement on selection
#Organize Includes
ActionDefinition.addInclude.name= Organize Includes
ActionDefinition.addInclude.description= Evaluates all required includes and replaces the current includes
#Sort Lines
ActionDefinition.sortLines.name= Sort Lines
ActionDefinition.sortLines.description= Sort selected lines alphabetically
@ -593,6 +597,7 @@ renameParticipant.name = Source Folder Rename
FormatAction.label= &Format
IndentAction.label= Correct &Indentation
OrganizeIncludesAction.label= Or&ganize Includes
AddIncludeAction.label= A&dd Include
SortLinesAction.label= Sor&t Lines
CommentAction.label= Co&mment

View file

@ -1884,6 +1884,13 @@
menubarPath="org.eclipse.jdt.ui.source.menu/importGroup"
id="org.eclipse.cdt.ui.actions.SortLines">
</action>
<action
definitionId="org.eclipse.cdt.ui.edit.text.c.organize.includes"
label="%OrganizeIncludesAction.label"
retarget="true"
menubarPath="org.eclipse.jdt.ui.source.menu/importGroup"
id="org.eclipse.cdt.ui.actions.OrganizeIncludes">
</action>
<action
definitionId="org.eclipse.cdt.ui.edit.text.c.add.include"
label="%AddIncludeAction.label"
@ -2451,6 +2458,11 @@
contextId="org.eclipse.cdt.ui.cViewScope"
commandId="org.eclipse.cdt.ui.navigate.open.type.in.hierarchy"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
<key
sequence="M1+M2+O"
contextId="org.eclipse.cdt.ui.cEditorScope"
commandId="org.eclipse.cdt.ui.edit.text.c.organize.includes"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
<key
sequence="M1+M2+N"
contextId="org.eclipse.cdt.ui.cEditorScope"
@ -2952,6 +2964,12 @@
categoryId="org.eclipse.cdt.ui.category.source"
id="org.eclipse.cdt.ui.edit.text.c.add.include">
</command>
<command
name="%ActionDefinition.organizeIncludes.name"
description="%ActionDefinition.OrganizeIncludes.description"
categoryId="org.eclipse.cdt.ui.category.source"
id="org.eclipse.cdt.ui.edit.text.c.organize.includes">
</command>
<command
name="%ActionDefinition.sortLines.name"
description="%ActionDefinition.sortLines.description"
@ -4606,6 +4624,7 @@
<key name="removeTrailingWhitespaceEditedLines"/>
<key name="Refactoring.savealleditors"/>
<key name="Refactor.lightweight"/>
<key name="organizeIncludes." match="prefix"/>
<key name="spelling_" match="prefix"/>
<key name="org.eclipse.cdt.ui.add_comments"/>
<key name="codetemplates.includeGuardGenerationScheme"/>
@ -4628,6 +4647,9 @@
<entry node="org.eclipse.cdt.ui">
<key name="codetemplates." match="prefix"/>
<key name="nameStyle." match="prefix"/>
<key name="includeStyle." match="prefix"/>
<key name="forwardDeclare." match="prefix"/>
<key name="includes.partnerFileSuffixes"/>
<key name="formatter_profile"/>
<key name="class_member_ascending_visibility_order"/>
<key name="function_output_parameters_before_input"/>

View file

@ -0,0 +1,145 @@
/*******************************************************************************
* Copyright (c) 2013 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;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.IProgressService;
import org.eclipse.cdt.ui.CUIPlugin;
/**
* Synchronously executes a {@link Job} while allowing user to cancel it if it takes too long.
*/
public final class BusyCursorJobRunner {
/**
* Adapts a {@link Job} to be an {@link IRunnableWithProgress}.
*/
private static class JobRunnableWithProgressAdapter implements IRunnableWithProgress {
private final Job job;
/**
* Creates the {@link IRunnableWithProgress} from the {@link Job}.
*/
public JobRunnableWithProgressAdapter(Job job) {
this.job = job;
}
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
IStatus result;
try {
monitor.beginTask(job.getName(), IProgressMonitor.UNKNOWN);
result = executeAndWait(job, monitor);
} catch (RuntimeException e) {
throw new InvocationTargetException(e);
}
switch (result.getSeverity()) {
case IStatus.CANCEL:
throw new InterruptedException();
case IStatus.ERROR:
if (result.getException() instanceof OperationCanceledException) {
throw new InterruptedException();
}
throw new InvocationTargetException(new CoreException(result));
}
}
}
/**
* Runs the given job and waits for it to finish. If executing in the UI thread, sets the cursor
* to busy while the job is being executed.
*
* @param job the job to execute
* @return the status reflecting the result of the job execution
*/
public static IStatus execute(Job job) {
boolean inUiThread = Thread.currentThread() == Display.getDefault().getThread();
if (inUiThread) {
return busyCursorWhile(job);
}
return executeAndWait(job, new NullProgressMonitor());
}
private static IStatus busyCursorWhile(Job job) {
try {
IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
progressService.busyCursorWhile(new JobRunnableWithProgressAdapter(job));
} catch (InterruptedException e) {
return Status.CANCEL_STATUS; // Operation was cancelled.
} catch (InvocationTargetException e) {
Throwable targetException = e.getTargetException();
if (targetException instanceof CoreException) {
return ((CoreException) targetException).getStatus();
}
return new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, e.getMessage(), e);
}
return Status.OK_STATUS;
}
private static IStatus executeAndWait(final Job job, IProgressMonitor monitor) {
final IStatus[] statusHolder = new IStatus[1];
IJobManager jobManager = Job.getJobManager();
JobChangeAdapter listener = new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
super.done(event);
if (event.getJob() == job) {
synchronized (statusHolder) {
statusHolder[0] = event.getResult();
statusHolder.notifyAll();
}
}
}
};
jobManager.addJobChangeListener(listener);
job.schedule();
try {
synchronized (statusHolder) {
while (statusHolder[0] == null) {
try {
statusHolder.wait(100);
if (monitor.isCanceled()) {
job.cancel();
}
} catch (InterruptedException e) {
job.cancel();
return Status.CANCEL_STATUS;
}
}
return statusHolder[0];
}
} finally {
monitor.done();
jobManager.removeJobChangeListener(listener);
}
}
private BusyCursorJobRunner() {}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2010 IBM Corporation and others.
* Copyright (c) 2006, 2013 IBM Corporation 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
@ -9,6 +9,7 @@
* IBM Corporation - initial API and implementation
* QNX Software System
* Anton Leherbauer (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.ui;
@ -19,7 +20,6 @@ import org.eclipse.cdt.ui.CUIPlugin;
* <p>
* This interface contains constants only; it is not intended to be implemented or extended.
* </p>
*
*/
public interface ICHelpContextIds {
public static final String PREFIX = CUIPlugin.PLUGIN_ID + "."; //$NON-NLS-1$
@ -33,9 +33,10 @@ public interface ICHelpContextIds {
public static final String OPEN_PROJECT_WIZARD_ACTION = PREFIX + "open_project_wizard_action"; //$NON-NLS-1$
public static final String CONVERT_TO_CCPP_WIZARD_PAGE = PREFIX + "cdt_t_conv_proj_context"; //$NON-NLS-1$
public static final String NEW_C_FILE_WIZARD_PAGE = PREFIX + "cdt_creating_cpp_file_context"; //$NON-NLS-1$
// Actions
// Actions
public static final String ADD_INCLUDE_ON_SELECTION_ACTION = PREFIX + "add_includes_on_selection_action_context"; //$NON-NLS-1$;
public static final String ORGANIZE_INCLUDES_ACTION = PREFIX + "organize_includes_action"; //$NON-NLS-1$;
public static final String FILTER_PUBLIC_ACTION= PREFIX + "filter_public_action"; //$NON-NLS-1$
public static final String FILTER_FIELDS_ACTION= PREFIX + "filter_fields_action"; //$NON-NLS-1$
public static final String FILTER_STATIC_ACTION= PREFIX + "filter_static_action"; //$NON-NLS-1$

View file

@ -33,14 +33,14 @@ import org.eclipse.ui.texteditor.RetargetTextEditorAction;
import org.eclipse.cdt.ui.actions.CdtActionConstants;
import org.eclipse.cdt.internal.ui.IContextMenuConstants;
import org.eclipse.cdt.internal.ui.actions.FindWordAction;
import org.eclipse.cdt.internal.ui.actions.GoToNextPreviousMemberAction;
import org.eclipse.cdt.internal.ui.actions.GotoNextBookmarkAction;
import org.eclipse.cdt.internal.ui.actions.StructureSelectEnclosingAction;
import org.eclipse.cdt.internal.ui.actions.StructureSelectHistoryAction;
import org.eclipse.cdt.internal.ui.actions.StructureSelectNextAction;
import org.eclipse.cdt.internal.ui.actions.StructureSelectPreviousAction;
import org.eclipse.cdt.internal.ui.actions.StructureSelectionAction;
import org.eclipse.cdt.internal.ui.actions.StructureSelectEnclosingAction;
import org.eclipse.cdt.internal.ui.actions.FindWordAction;
import org.eclipse.cdt.internal.ui.actions.GoToNextPreviousMemberAction;
import org.eclipse.cdt.internal.ui.actions.GotoNextBookmarkAction;
public class CEditorActionContributor extends TextEditorActionContributor {
@ -229,6 +229,7 @@ public class CEditorActionContributor extends TextEditorActionContributor {
bars.setGlobalActionHandler(CdtActionConstants.REMOVE_BLOCK_COMMENT, getAction(textEditor, "RemoveBlockComment")); //$NON-NLS-1$
bars.setGlobalActionHandler(CdtActionConstants.INDENT, getAction(textEditor, "Indent")); //$NON-NLS-1$
bars.setGlobalActionHandler(CdtActionConstants.ADD_INCLUDE, getAction(textEditor, "AddIncludeOnSelection")); //$NON-NLS-1$
bars.setGlobalActionHandler(CdtActionConstants.ORGANIZE_INCLUDES, getAction(textEditor, "OrganizeIncludes")); //$NON-NLS-1$
bars.setGlobalActionHandler(CdtActionConstants.SORT_LINES, getAction(textEditor, "SortLines")); //$NON-NLS-1$
IAction action= getAction(textEditor, ITextEditorActionConstants.REFRESH);

View file

@ -38,10 +38,12 @@ public final class CEditorMessages extends NLS {
public static String AddIncludesOperation_description;
public static String OrganizeIncludes_label;
public static String OrganizeIncludes_description;
public static String OrganizeIncludes_action;
public static String OrganizeIncludes_error_title;
public static String OrganizeIncludes_insertion_failed;
public static String OrganizeIncludes_help_provider_error;
public static String OrganizeIncludes_failed;
public static String OrganizeIncludes_choose_header;
public static String OrganizeIncludesOperation_description;
public static String ShowInCView_description;
public static String ShowInCView_label;

View file

@ -24,10 +24,12 @@ AddIncludesOperation_description=Adding include statement
OrganizeIncludes_label=Organize Includes
OrganizeIncludes_description=Organize includes for current file
OrganizeIncludes_action=Organizing includes
OrganizeIncludes_error_title=Error Organizing Includes
OrganizeIncludes_insertion_failed=Adding include statements failed
OrganizeIncludes_help_provider_error=Help provider error
OrganizeIncludes_failed=Organize Includes operation failed
OrganizeIncludes_choose_header=Choose a header file to include for symbol ''{0}''
OrganizeIncludesOperation_description=Organizing include statements
ShowInCView_description=Show the current resource in the C/C++ Projects view

View file

@ -72,6 +72,12 @@ public interface ICEditorActionDefinitionIds extends ITextEditorActionDefinition
*/
public static final String ADD_INCLUDE= "org.eclipse.cdt.ui.edit.text.c.add.include"; //$NON-NLS-1$
/**
* Action definition ID of the source -> organize includes action
* (value <code>"org.eclipse.cdt.ui.edit.text.c.organize.includes"</code>).
*/
public static final String ORGANIZE_INCLUDES= "org.eclipse.cdt.ui.edit.text.c.organize.includes"; //$NON-NLS-1$
/**
* Action definition ID of the open declaration action
* (value <code>"org.eclipse.cdt.ui.edit.opendecl"</code>).

View file

@ -0,0 +1,87 @@
/*******************************************************************************
* Copyright (c) 2013 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.editor;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.cdt.internal.ui.refactoring.includes.IHeaderChooser;
/**
* Dialog-based header chooser.
*/
public class InteractiveHeaderChooser implements IHeaderChooser {
private final Shell shell;
Map<Collection<IPath>, IPath> userChoiceCache;
public InteractiveHeaderChooser(Shell shell) {
this.shell = shell;
userChoiceCache = new HashMap<Collection<IPath>, IPath>();
}
@Override
public IPath chooseHeader(final String bindingName, Collection<IPath> headers) {
if (headers.isEmpty())
return null;
if (headers.size() == 1)
return headers.iterator().next();
Set<IPath> cacheKey = new HashSet<IPath>(headers);
// Check the decision cache. If the cache doesn't help, ask the user.
// Query the cache.
if (userChoiceCache.containsKey(cacheKey)) {
return userChoiceCache.get(cacheKey);
}
// Ask the user.
final IPath[] elemArray = headers.toArray(new IPath[headers.size()]);
final IPath[] selectedElement = new IPath[1];
runInUIThread(new Runnable() {
@Override
public void run() {
if (!shell.isDisposed()) {
ElementListSelectionDialog dialog =
new ElementListSelectionDialog(shell, new LabelProvider());
dialog.setElements(elemArray);
dialog.setTitle(CEditorMessages.OrganizeIncludes_label);
dialog.setMessage(NLS.bind(CEditorMessages.OrganizeIncludes_choose_header, bindingName));
if (dialog.open() == Window.OK) {
selectedElement[0] = (IPath) dialog.getFirstResult();
}
}
}
});
IPath selectedHeader = selectedElement[0];
if (selectedHeader != null)
userChoiceCache.put(headers, selectedHeader); // Remember user's choice.
return selectedHeader;
}
private void runInUIThread(Runnable runnable) {
if (Display.getCurrent() != null) {
runnable.run();
} else {
Display.getDefault().syncExec(runnable);
}
}
}

View file

@ -7,12 +7,25 @@
*
* Contributors:
* Mathias Kunter - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.editor;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.text.undo.DocumentUndoManagerRegistry;
import org.eclipse.text.undo.IDocumentUndoManager;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.TextEditorAction;
@ -25,7 +38,9 @@ import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.text.SharedASTJob;
import org.eclipse.cdt.internal.ui.BusyCursorJobRunner;
import org.eclipse.cdt.internal.ui.ICHelpContextIds;
import org.eclipse.cdt.internal.ui.refactoring.includes.IHeaderChooser;
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeOrganizer;
/**
@ -37,9 +52,84 @@ public class OrganizeIncludesAction extends TextEditorAction {
* @param editor The editor on which this organize includes action should operate.
*/
public OrganizeIncludesAction(ITextEditor editor) {
// TODO Fix ID's
super(CEditorMessages.getBundleForConstructedKeys(), "OrganizeIncludes.", editor); //$NON-NLS-1$
CUIPlugin.getDefault().getWorkbench().getHelpSystem().setHelp(this, ICHelpContextIds.ADD_INCLUDE_ON_SELECTION_ACTION);
CUIPlugin.getDefault().getWorkbench().getHelpSystem().setHelp(this, ICHelpContextIds.ORGANIZE_INCLUDES_ACTION);
}
@Override
public void run() {
final ITextEditor editor = getTextEditor();
final ITranslationUnit tu = getTranslationUnit(editor);
if (tu == null) {
return;
}
if (!validateEditorInputState()) {
return;
}
final IHeaderChooser headerChooser = new InteractiveHeaderChooser(editor.getSite().getShell());
final String lineDelimiter = getLineDelimiter(editor);
final List<TextEdit> edits = new ArrayList<TextEdit>();
SharedASTJob job = new SharedASTJob(CEditorMessages.OrganizeIncludes_action, tu) {
@Override
public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) throws CoreException {
IIndex index= CCorePlugin.getIndexManager().getIndex(tu.getCProject(),
IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_EXTENSION_FRAGMENTS_ADD_IMPORT);
try {
index.acquireReadLock();
IncludeOrganizer organizer = new IncludeOrganizer(tu, index, lineDelimiter, headerChooser);
edits.addAll(organizer.organizeIncludes(ast));
return Status.OK_STATUS;
} catch (InterruptedException e) {
return Status.CANCEL_STATUS;
} finally {
index.releaseReadLock();
}
}
};
IStatus status = BusyCursorJobRunner.execute(job);
if (status.isOK()) {
if (!edits.isEmpty()) {
// Apply text edits.
MultiTextEdit edit = new MultiTextEdit();
edit.addChildren(edits.toArray(new TextEdit[edits.size()]));
IEditorInput editorInput = editor.getEditorInput();
IDocument document = editor.getDocumentProvider().getDocument(editorInput);
IDocumentUndoManager manager= DocumentUndoManagerRegistry.getDocumentUndoManager(document);
manager.beginCompoundChange();
try {
edit.apply(document);
} catch (MalformedTreeException e) {
CUIPlugin.log(e);
} catch (BadLocationException e) {
CUIPlugin.log(e);
}
manager.endCompoundChange();
}
} else if (status.matches(IStatus.ERROR)) {
ErrorDialog.openError(editor.getEditorSite().getShell(),
CEditorMessages.OrganizeIncludes_error_title,
CEditorMessages.OrganizeIncludes_insertion_failed, status);
}
}
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
public void update() {
ITextEditor editor = getTextEditor();
setEnabled(editor != null && getTranslationUnit(editor) != null);
}
/**
@ -53,46 +143,4 @@ public class OrganizeIncludesAction extends TextEditorAction {
}
return CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editor.getEditorInput());
}
@Override
public void run() {
final ITextEditor editor = getTextEditor();
final ITranslationUnit tu = getTranslationUnit(editor);
if (tu == null) {
return;
}
try {
if (!validateEditorInputState()) {
return;
}
SharedASTJob job = new SharedASTJob(CEditorMessages.OrganizeIncludes_label, tu) {
@Override
public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) throws CoreException {
IIndex index= CCorePlugin.getIndexManager().getIndex(tu.getCProject(),
IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_EXTENSION_FRAGMENTS_ADD_IMPORT);
try {
index.acquireReadLock();
IncludeOrganizer organizer = new IncludeOrganizer(editor, tu, index);
organizer.organizeIncludes(ast);
return Status.OK_STATUS;
} catch (InterruptedException e) {
return Status.CANCEL_STATUS;
} finally {
index.releaseReadLock();
}
}
};
job.schedule();
job.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@Override
public void update() {
ITextEditor editor = getTextEditor();
setEnabled(editor != null && getTranslationUnit(editor) != null);
}
}

View file

@ -19,27 +19,28 @@ import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
import org.eclipse.cdt.ui.PreferenceConstants;
import org.eclipse.cdt.internal.ui.dialogs.IStatusChangeListener;
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle;
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle.IncludeKind;
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludePreferences;
/**
* The preference block for configuring style of include statements.
*/
public class IncludeStyleBlock extends TabConfigurationBlock {
static final Key KEY_STYLE_RELATED = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_RELATED);
static final Key KEY_STYLE_PARTNER = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_PARTNER);
static final Key KEY_STYLE_SAME_FOLDER = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_SAME_FOLDER);
static final Key KEY_STYLE_SUBFOLDER = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_SUBFOLDER);
static final Key KEY_STYLE_SYSTEM = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_SYSTEM);
static final Key KEY_STYLE_SYSTEM_WITH_EXTENSION = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_SYSTEM_WITH_EXTENSION);
static final Key KEY_STYLE_SYSTEM_WITHOUT_EXTENSION = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_SYSTEM_WITHOUT_EXTENSION);
static final Key KEY_STYLE_OTHER = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_OTHER);
static final Key KEY_STYLE_SAME_PROJECT = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_SAME_PROJECT);
static final Key KEY_STYLE_OTHER_PROJECT = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_OTHER_PROJECT);
static final Key KEY_STYLE_EXTERNAL = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_EXTERNAL);
static final Key KEY_STYLE_MATCHING_PATTERN = getCDTUIKey(IncludePreferences.PREF_INCLUDE_STYLE_MATCHING_PATTERN);
static final Key KEY_STYLE_RELATED = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_RELATED);
static final Key KEY_STYLE_PARTNER = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_PARTNER);
static final Key KEY_STYLE_SAME_FOLDER = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_SAME_FOLDER);
static final Key KEY_STYLE_SUBFOLDER = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_SUBFOLDER);
static final Key KEY_STYLE_SYSTEM = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_SYSTEM);
static final Key KEY_STYLE_SYSTEM_WITH_EXTENSION = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_SYSTEM_WITH_EXTENSION);
static final Key KEY_STYLE_SYSTEM_WITHOUT_EXTENSION = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_SYSTEM_WITHOUT_EXTENSION);
static final Key KEY_STYLE_OTHER = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_OTHER);
static final Key KEY_STYLE_SAME_PROJECT = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_SAME_PROJECT);
static final Key KEY_STYLE_OTHER_PROJECT = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_OTHER_PROJECT);
static final Key KEY_STYLE_EXTERNAL = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_EXTERNAL);
static final Key KEY_STYLE_MATCHING_PATTERN = getCDTUIKey(PreferenceConstants.INCLUDE_STYLE_MATCHING_PATTERN);
static final Map<IncludeKind, Key> KEY_MAP = createKeyMap();
static final Key[] STYLE_KEYS = KEY_MAP.values().toArray(new Key[KEY_MAP.size()]);

View file

@ -17,9 +17,10 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
import org.eclipse.cdt.ui.PreferenceConstants;
import org.eclipse.cdt.internal.ui.dialogs.IStatusChangeListener;
import org.eclipse.cdt.internal.ui.dialogs.StatusInfo;
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludePreferences;
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludePreferences.UnusedStatementDisposition;
import org.eclipse.cdt.internal.ui.wizards.dialogfields.LayoutUtil;
@ -27,13 +28,14 @@ import org.eclipse.cdt.internal.ui.wizards.dialogfields.LayoutUtil;
* The preference block for configuring Organize Includes command.
*/
public class OrganizeIncludesBlock extends OptionsConfigurationBlock {
private static final Key KEY_HEURISTIC_HEADER_SUBSTITUTION = getCDTUIKey(IncludePreferences.PREF_HEURISTIC_HEADER_SUBSTITUTION);
private static final Key KEY_INCLUDES_REORDERING = getCDTUIKey(IncludePreferences.PREF_INCLUDES_REORDERING);
private static final Key KEY_UNUSED_STATEMENTS_DISPOSITION = getCDTUIKey(IncludePreferences.PREF_UNUSED_STATEMENTS_DISPOSITION);
private static final Key KEY_FORWARD_DECLARE_COMPOSITE_TYPES = getCDTUIKey(IncludePreferences.PREF_FORWARD_DECLARE_COMPOSITE_TYPES);
private static final Key KEY_FORWARD_DECLARE_ENUMS = getCDTUIKey(IncludePreferences.PREF_FORWARD_DECLARE_ENUMS);
private static final Key KEY_FORWARD_DECLARE_FUNCTIONS = getCDTUIKey(IncludePreferences.PREF_FORWARD_DECLARE_FUNCTIONS);
private static final Key KEY_FORWARD_DECLARE_NAMESPACE_ELEMENTS = getCDTUIKey(IncludePreferences.PREF_FORWARD_DECLARE_NAMESPACE_ELEMENTS);
private static final Key KEY_HEURISTIC_HEADER_SUBSTITUTION = getCDTUIKey(PreferenceConstants.INCLUDES_HEURISTIC_HEADER_SUBSTITUTION);
private static final Key KEY_INCLUDES_REORDERING = getCDTUIKey(PreferenceConstants.INCLUDES_ALLOW_REORDERING);
private static final Key KEY_UNUSED_STATEMENTS_DISPOSITION = getCDTUIKey(PreferenceConstants.INCLUDES_UNUSED_STATEMENTS_DISPOSITION);
private static final Key KEY_FORWARD_DECLARE_COMPOSITE_TYPES = getCDTUIKey(PreferenceConstants.FORWARD_DECLARE_COMPOSITE_TYPES);
private static final Key KEY_FORWARD_DECLARE_ENUMS = getCDTUIKey(PreferenceConstants.FORWARD_DECLARE_ENUMS);
private static final Key KEY_FORWARD_DECLARE_FUNCTIONS = getCDTUIKey(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS);
private static final Key KEY_FORWARD_DECLARE_TEMPLATES = getCDTUIKey(PreferenceConstants.FORWARD_DECLARE_TEMPLATES);
private static final Key KEY_FORWARD_DECLARE_NAMESPACE_ELEMENTS = getCDTUIKey(PreferenceConstants.FORWARD_DECLARE_NAMESPACE_ELEMENTS);
private static final String[] DISPOSITION_VALUES = {
UnusedStatementDisposition.REMOVE.toString(),
@ -53,6 +55,7 @@ public class OrganizeIncludesBlock extends OptionsConfigurationBlock {
KEY_FORWARD_DECLARE_COMPOSITE_TYPES,
KEY_FORWARD_DECLARE_ENUMS,
KEY_FORWARD_DECLARE_FUNCTIONS,
KEY_FORWARD_DECLARE_TEMPLATES,
KEY_FORWARD_DECLARE_NAMESPACE_ELEMENTS,
};
@ -87,6 +90,9 @@ public class OrganizeIncludesBlock extends OptionsConfigurationBlock {
control = addCheckBox(composite, PreferencesMessages.OrganizeIncludesBlock_forward_declare_functions,
KEY_FORWARD_DECLARE_FUNCTIONS, TRUE_FALSE, 0);
LayoutUtil.setHorizontalSpan(control, 2);
control = addCheckBox(composite, PreferencesMessages.OrganizeIncludesBlock_forward_declare_templates,
KEY_FORWARD_DECLARE_TEMPLATES, TRUE_FALSE, 0);
LayoutUtil.setHorizontalSpan(control, 2);
control = addCheckBox(composite, PreferencesMessages.OrganizeIncludesBlock_forward_declare_namespace_elements,
KEY_FORWARD_DECLARE_NAMESPACE_ELEMENTS, TRUE_FALSE, 0);
LayoutUtil.setHorizontalSpan(control, 2);

View file

@ -443,6 +443,7 @@ public final class PreferencesMessages extends NLS {
public static String OrganizeIncludesBlock_forward_declare_composite_types;
public static String OrganizeIncludesBlock_forward_declare_enums;
public static String OrganizeIncludesBlock_forward_declare_functions;
public static String OrganizeIncludesBlock_forward_declare_templates;
public static String OrganizeIncludesBlock_forward_declare_namespace_elements;
public static String OrganizeIncludesBlock_heuristic_header_substitution;
public static String OrganizeIncludesBlock_unused_statements;

View file

@ -499,6 +499,7 @@ OrganizeIncludesBlock_allow_reordering= Allow &reordering of includes
OrganizeIncludesBlock_forward_declare_composite_types= Forward declare &classes, structs and unions
OrganizeIncludesBlock_forward_declare_enums= Forward declare &enums when possible
OrganizeIncludesBlock_forward_declare_functions= Forward declare &functions
OrganizeIncludesBlock_forward_declare_templates= Forward declare &templates
OrganizeIncludesBlock_forward_declare_namespace_elements= Forward declare &namespace elements
OrganizeIncludesBlock_heuristic_header_substitution= Allow &heuristic header file substitution
OrganizeIncludesBlock_unused_statements= &Unused Includes and Forward Declarations:

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 Google, Inc and others.
* Copyright (c) 2012, 2013 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

View file

@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2013 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.includes;
import java.util.Collection;
import org.eclipse.core.runtime.IPath;
/**
* Interface for selecting one of alternative headers.
*/
public interface IHeaderChooser {
/**
* Chooses one header out of multiple alternatives.
*
* @param bindingName the name of the binding for which the header is selected
* @param headers absolute file system locations of the headers defining the binding
* @return the chosen header or {@code null} if nothing was selected
*/
public IPath chooseHeader(String bindingName, Collection<IPath> headers);
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 Google, Inc and others.
* Copyright (c) 2012, 2013 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

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 Google, Inc and others.
* Copyright (c) 2012, 2013 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

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 Google, Inc and others.
* Copyright (c) 2012, 2013 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
@ -11,8 +11,13 @@
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.includes;
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 java.util.ArrayList;
import java.util.Collection;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@ -24,23 +29,29 @@ import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.text.edits.DeleteEdit;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
import com.ibm.icu.text.Collator;
import org.eclipse.cdt.core.dom.IName;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.EScopeKind;
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.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.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
@ -62,25 +73,105 @@ import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.index.IIndexInclude;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.index.IndexLocationFactory;
import org.eclipse.cdt.core.model.IBuffer;
import org.eclipse.cdt.core.model.ITranslationUnit;
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.ui.CUIPlugin;
import org.eclipse.cdt.utils.PathUtil;
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.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.core.resources.ResourceLookup;
import org.eclipse.cdt.internal.ui.editor.CEditorMessages;
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle.IncludeKind;
/**
* Organizes the include directives and forward declarations of a source or header file.
*/
public class IncludeOrganizer {
private static class IncludePrototype {
final IPath header; // null for existing unresolved includes
final IncludeInfo includeInfo; // never null
IASTPreprocessorIncludeStatement existingInclude; // null for newly added includes
final boolean required; // true if the header has to be included
final IncludeGroupStyle style;
/** Initializes an include prototype for a new include */
IncludePrototype(IPath header, IncludeInfo includeInfo, IncludeGroupStyle style) {
this.header = header;
this.includeInfo = includeInfo;
this.style = style;
this.required = true;
}
/**
* Initializes an include prototype for an existing include. {@code header} may be
* {@code null} if the include was not resolved.
*/
IncludePrototype(IASTPreprocessorIncludeStatement include, IPath header,
IncludeInfo includeInfo, IncludeGroupStyle style) {
this.existingInclude = include;
this.header = header;
this.includeInfo = includeInfo;
this.style = style;
this.required = false;
}
public void updateFrom(IncludePrototype other) {
this.existingInclude = other.existingInclude;
}
@Override
public int hashCode() {
if (header != null)
return header.hashCode(); // includeInfo is ignored if header is not null
return includeInfo.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
IncludePrototype other = (IncludePrototype) obj;
if (header != null)
return header.equals(other.header); // includeInfo is ignored if header is not null
if (other.header != null)
return false;
if (includeInfo == null) {
if (other.includeInfo != null)
return false;
}
return includeInfo.equals(other.includeInfo);
}
/** For debugging only */
@Override
public String toString() {
return header != null ? header.toPortableString() : includeInfo.toString();
}
}
private static final Collator COLLATOR = Collator.getInstance();
private static final Comparator<IPath> PATH_COMPARATOR = new Comparator<IPath>() {
private static final Comparator<IncludePrototype> INCLUDE_COMPARATOR = new Comparator<IncludePrototype>() {
@Override
public int compare(IPath path1, IPath path2) {
public int compare(IncludePrototype include1, IncludePrototype include2) {
IncludeInfo includeInfo1 = include1.includeInfo;
IncludeInfo includeInfo2 = include2.includeInfo;
if (includeInfo1.isSystem() != includeInfo2.isSystem()) {
return includeInfo1.isSystem() ? -1 : 1;
}
IPath path1 = Path.fromOSString(includeInfo1.getName());
IPath path2 = Path.fromOSString(includeInfo2.getName());
int length1 = path1.segmentCount();
int length2 = path2.segmentCount();
for (int i = 0; i < length1 && i < length2; i++) {
@ -92,16 +183,14 @@ public class IncludeOrganizer {
}
};
private final ITextEditor fEditor;
private final IHeaderChooser fHeaderChooser;
private final InclusionContext fContext;
private final String fLineDelimiter;
/**
* Constructor
* @param editor The editor on which this organize includes action should operate.
* @param index
*/
public IncludeOrganizer(ITextEditor editor, ITranslationUnit tu, IIndex index) {
fEditor = editor;
public IncludeOrganizer(ITranslationUnit tu, IIndex index, String lineDelimiter,
IHeaderChooser headerChooser) {
fLineDelimiter = lineDelimiter;
fHeaderChooser = headerChooser;
fContext = new InclusionContext(tu, index);
}
@ -110,10 +199,19 @@ public class IncludeOrganizer {
* @param ast The AST translation unit to process.
* @throws CoreException
*/
public void organizeIncludes(IASTTranslationUnit ast) throws CoreException {
public List<TextEdit> organizeIncludes(IASTTranslationUnit ast) throws CoreException {
// Process the given translation unit with the inclusion resolver.
BindingClassifier resolver = new BindingClassifier(fContext, ast);
Set<IBinding> bindingsToDefine = resolver.getBindingsToDefine();
BindingClassifier bindingClassifier = new BindingClassifier(fContext);
bindingClassifier.classifyNodeContents(ast);
Set<IBinding> bindingsToDefine = bindingClassifier.getBindingsToDefine();
// Stores the forward declarations for composite types and enumerations as text.
List<String> typeForwardDeclarations = new ArrayList<String>();
// Stores the forward declarations for C-style functions as text.
List<String> functionForwardDeclarations = new ArrayList<String>();
createForwardDeclarations(ast, bindingClassifier, typeForwardDeclarations, functionForwardDeclarations,
bindingsToDefine);
HeaderSubstitutor headerSubstitutor = new HeaderSubstitutor(fContext);
// Create the list of header files which have to be included by examining the list of
@ -123,16 +221,166 @@ public class IncludeOrganizer {
List<InclusionRequest> requests = createInclusionRequests(bindingsToDefine, reachableHeaders);
processInclusionRequests(requests, headerSubstitutor);
// Stores the forward declarations for composite types and enumerations as text.
List<String> forwardDeclarations = new ArrayList<String>();
// Use a map instead of a set to be able to retrieve existing elements using equal elements.
// Maps each element to itself.
Map<IncludePrototype, IncludePrototype> includePrototypes =
new HashMap<IncludePrototype, IncludePrototype>();
// Put the new includes into includePrototypes.
for (IPath header : fContext.getHeadersToInclude()) {
IncludeGroupStyle style = getIncludeStyle(header);
IncludeInfo includeInfo = createIncludeInfo(header, style);
IncludePrototype prototype = new IncludePrototype(header, includeInfo, style);
updateIncludePrototypes(includePrototypes, prototype);
}
// Put the existing includes into includePrototypes.
IASTPreprocessorIncludeStatement[] existingIncludes = ast.getIncludeDirectives();
for (IASTPreprocessorIncludeStatement include : existingIncludes) {
if (include.isPartOfTranslationUnitFile()) {
String name = new String(include.getName().getSimpleID());
IncludeInfo includeInfo = new IncludeInfo(name, include.isSystemInclude());
String path = include.getPath();
IPath header = path.isEmpty() ? null : Path.fromPortableString(path);
IncludeGroupStyle style =
header != null ? getIncludeStyle(header) : getIncludeStyle(includeInfo);
IncludePrototype prototype = new IncludePrototype(include, header, includeInfo, style);
updateIncludePrototypes(includePrototypes, prototype);
}
}
// Stores the forward declarations for C-style functions as text.
List<String> functionForwardDeclarations = new ArrayList<String>();
NodeCommentMap commentedNodeMap = ASTCommenter.getCommentedNodeMap(ast);
IRegion includeReplacementRegion = getSafeIncludeReplacementRegion(ast, commentedNodeMap);
// Create the forward declarations by examining the list of bindings which have to be
// declared.
IncludePreferences preferences = fContext.getPreferences();
boolean allowReordering = preferences.allowReordering || existingIncludes.length == 0;
List<TextEdit> edits = new ArrayList<TextEdit>();
@SuppressWarnings("unchecked")
List<IncludePrototype>[] groupedPrototypes =
(List<IncludePrototype>[]) new List<?>[preferences.includeStyles.size()];
for (IncludePrototype prototype : includePrototypes.keySet()) {
if (prototype.existingInclude == null
|| (allowReordering && isContainedInRegion(prototype.existingInclude, includeReplacementRegion))) {
IncludeGroupStyle groupingStyle = getGroupingStyle(prototype.style);
// If reordering is not allowed, group everything together.
int position = allowReordering ? groupingStyle.getOrder() : 0;
List<IncludePrototype> prototypes = groupedPrototypes[position];
if (prototypes == null) {
prototypes = new ArrayList<IncludePrototype>();
groupedPrototypes[position] = prototypes;
}
prototypes.add(prototype);
}
if (!allowReordering && prototype.existingInclude != null
&& !prototype.required && prototype.header != null // Unused and resolved.
&& isContainedInRegion(prototype.existingInclude, includeReplacementRegion)) {
switch (preferences.unusedStatementsDisposition) {
case REMOVE:
createDelete(prototype.existingInclude, edits);
break;
case COMMENT_OUT:
createCommentOut(prototype.existingInclude, edits);
break;
case KEEP:
break;
}
}
}
List<String> includeDirectives = new ArrayList<String>();
IncludeGroupStyle previousParentStyle = null;
for (List<IncludePrototype> prototypes : groupedPrototypes) {
if (prototypes != null && !prototypes.isEmpty()) {
Collections.sort(prototypes, INCLUDE_COMPARATOR);
IncludeGroupStyle style = prototypes.get(0).style;
IncludeGroupStyle groupingStyle = getGroupingStyle(style);
IncludeGroupStyle parentStyle = getParentStyle(groupingStyle);
boolean blankLineBefore = groupingStyle.isBlankLineBefore() ||
(parentStyle != null && parentStyle != previousParentStyle &&
parentStyle.isKeepTogether() && parentStyle.isBlankLineBefore());
previousParentStyle = parentStyle;
if (!includeDirectives.isEmpty() && blankLineBefore)
includeDirectives.add(""); // Blank line separator //$NON-NLS-1$
for (IncludePrototype prototype : prototypes) {
String trailingComment = ""; //$NON-NLS-1$
IASTPreprocessorIncludeStatement include = prototype.existingInclude;
if (include == null
|| (allowReordering && isContainedInRegion(include, includeReplacementRegion))) {
if (include != null) {
List<IASTComment> comments = commentedNodeMap.getTrailingCommentsForNode(include);
StringBuilder buf = new StringBuilder();
for (IASTComment comment : comments) {
buf.append(getPrecedingWhitespace(comment));
buf.append(comment.getRawSignature());
}
trailingComment = buf.toString();
}
String directive = createIncludeDirective(prototype, trailingComment);
if (directive != null)
includeDirectives.add(directive);
}
}
}
}
// Create the source code to insert into the editor.
StringBuilder buf = new StringBuilder();
for (String include : includeDirectives) {
buf.append(include);
buf.append(fLineDelimiter);
}
if (buf.length() != 0 && !typeForwardDeclarations.isEmpty())
buf.append(fLineDelimiter);
for (String declaration : typeForwardDeclarations) {
buf.append(declaration);
buf.append(fLineDelimiter);
}
if (buf.length() != 0 && !functionForwardDeclarations.isEmpty())
buf.append(fLineDelimiter);
for (String declaration : functionForwardDeclarations) {
buf.append(declaration);
buf.append(fLineDelimiter);
}
int offset = includeReplacementRegion.getOffset();
int length = includeReplacementRegion.getLength();
if (allowReordering) {
if (buf.length() != 0) {
if (offset != 0 && !isPreviousLineBlank(offset))
buf.insert(0, fLineDelimiter); // Blank line before.
if (!isBlankLineOrEndOfFile(offset + length))
buf.append(fLineDelimiter); // Blank line after.
}
String text = buf.toString();
// TODO(sprigogin): Add a diff algorithm and produce more narrow replacements.
if (!CharArrayUtils.equals(fContext.getTranslationUnit().getContents(), offset, length, text)) {
edits.add(new ReplaceEdit(offset, length, text));
}
} else if (buf.length() != 0) {
offset += length;
if (!isBlankLineOrEndOfFile(offset))
buf.append(fLineDelimiter); // Blank line after.
edits.add(new InsertEdit(offset, buf.toString()));
}
return edits;
}
/**
* Creates forward declarations by examining the list of bindings which have to be declared.
* Bindings that cannot be safely declared for whatever reason are added to
* {@code bindingsToDefine} set.
*/
private void createForwardDeclarations(IASTTranslationUnit ast, BindingClassifier classifier,
List<String> forwardDeclarations, List<String> functionForwardDeclarations,
Set<IBinding> bindingsToDefine) throws CoreException {
IIndexFileSet reachableHeaders = ast.getIndexFileSet();
Set<IBinding> bindings =
removeBindingsDefinedInIncludedHeaders(resolver.getBindingsToDeclare(), reachableHeaders);
removeBindingsDefinedInIncludedHeaders(classifier.getBindingsToDeclare(), reachableHeaders);
for (IBinding binding : bindings) {
// Create the text of the forward declaration of this binding.
StringBuilder declarationText = new StringBuilder();
@ -150,6 +398,7 @@ public class IncludeOrganizer {
}
} catch (DOMException e) {
}
Collections.reverse(scopeNames);
for (IName scopeName : scopeNames) {
declarationText.append("namespace "); //$NON-NLS-1$
@ -222,8 +471,7 @@ public class IncludeOrganizer {
// Append return type and function name.
IFunctionType functionType = function.getType();
// TODO(sprigogin) Improper use of IType.toString();
declarationText.append(functionType.getReturnType().toString());
declarationText.append(ASTTypeUtil.getType(functionType.getReturnType(), false));
declarationText.append(' ');
declarationText.append(function.getName());
declarationText.append('(');
@ -232,17 +480,16 @@ public class IncludeOrganizer {
IType[] parameterTypes = functionType.getParameterTypes();
IParameter[] parameters = function.getParameters();
for (int i = 0; i < parameterTypes.length && i < parameters.length; i++) {
// TODO(sprigogin) Improper use of IType.toString();
declarationText.append(parameterTypes[i].toString());
if (i != 0) {
declarationText.append(", "); //$NON-NLS-1$
}
declarationText.append(ASTTypeUtil.getType(parameterTypes[i], false));
char lastChar = declarationText.charAt(declarationText.length() - 1);
if (lastChar != '*' && lastChar != '&') {
// Append a space to separate the type name from the parameter name.
declarationText.append(' ');
}
declarationText.append(parameters[i].getName());
if (i != parameterTypes.length - 1 && i != parameters.length - 1) {
declarationText.append(", "); //$NON-NLS-1$
}
}
declarationText.append(");"); //$NON-NLS-1$
@ -250,7 +497,9 @@ public class IncludeOrganizer {
// Add this forward declaration to the separate function forward declaration list.
forwardDeclarationListToUse = functionForwardDeclarations;
} else {
// We don't handle forward declarations for those types of bindings. Ignore it.
// We can't create a forward declaration for this binding. The binding will have
// to be defined.
bindingsToDefine.add(binding);
continue;
}
@ -263,80 +512,266 @@ public class IncludeOrganizer {
forwardDeclarationListToUse.add(declarationText.toString());
}
Collections.sort(forwardDeclarations);
Collections.sort(functionForwardDeclarations);
IncludePreferences preferences = fContext.getPreferences();
Map<IPath, IncludeGroupStyle> classifiedHeaders =
new HashMap<IPath, IncludeGroupStyle>(fContext.getHeadersToInclude().size());
for (IPath file : fContext.getHeadersToInclude()) {
classifiedHeaders.put(file, getIncludeStyle(file));
}
@SuppressWarnings("unchecked")
List<IPath>[] orderedHeaders = (List<IPath>[]) new List<?>[classifiedHeaders.size()];
for (Map.Entry<IPath, IncludeGroupStyle> entry : classifiedHeaders.entrySet()) {
IPath path = entry.getKey();
IncludeGroupStyle style = entry.getValue();
IncludeGroupStyle groupingStyle = getGroupingStyle(style);
int position = groupingStyle.getOrder();
List<IPath> headers = orderedHeaders[position];
if (headers == null) {
headers = new ArrayList<IPath>();
orderedHeaders[position] = headers;
}
headers.add(path);
Collections.sort(forwardDeclarations, COLLATOR);
Collections.sort(functionForwardDeclarations, COLLATOR);
}
List<String> includeDirectives = new ArrayList<String>();
IncludeGroupStyle previousParentStyle = null;
for (List<IPath> headers : orderedHeaders) {
if (headers != null && !headers.isEmpty()) {
Collections.sort(headers, PATH_COMPARATOR);
IncludeGroupStyle style = classifiedHeaders.get(headers.get(0));
IncludeGroupStyle groupingStyle = getGroupingStyle(style);
IncludeGroupStyle parentStyle = getParentStyle(groupingStyle);
boolean blankLineBefore = groupingStyle.isBlankLineBefore() ||
(parentStyle != null && parentStyle != previousParentStyle &&
parentStyle.isKeepTogether() && parentStyle.isBlankLineBefore());
previousParentStyle = parentStyle;
if (!includeDirectives.isEmpty() && blankLineBefore)
includeDirectives.add(""); // Blank line separator //$NON-NLS-1$
for (IPath header : headers) {
style = classifiedHeaders.get(header);
includeDirectives.add(createIncludeDirective(header, style, "")); //$NON-NLS-1$
private void createCommentOut(IASTPreprocessorIncludeStatement include, List<TextEdit> edits) {
IASTFileLocation location = include.getFileLocation();
int offset = location.getNodeOffset();
if (fContext.getTranslationUnit().isCXXLanguage()) {
offset = getLineStart(offset);
edits.add(new InsertEdit(offset, "//")); //$NON-NLS-1$
} else {
edits.add(new InsertEdit(offset, "/*")); //$NON-NLS-1$
int endOffset = offset + location.getNodeLength();
edits.add(new InsertEdit(endOffset, "*/")); //$NON-NLS-1$
}
}
private void createDelete(IASTPreprocessorIncludeStatement include, List<TextEdit> edits) {
IASTFileLocation location = include.getFileLocation();
int offset = location.getNodeOffset();
int endOffset = offset + location.getNodeLength();
offset = getLineStart(offset);
endOffset = skipToNextLine(endOffset);
edits.add(new DeleteEdit(offset, endOffset - offset));
}
private void updateIncludePrototypes(Map<IncludePrototype, IncludePrototype> includePrototypes,
IncludePrototype prototype) {
IncludePrototype existing = includePrototypes.get(prototype);
if (existing == null) {
includePrototypes.put(prototype, prototype);
} else {
existing.updateFrom(prototype);
}
}
private boolean isContainedInRegion(IASTNode node, IRegion region) {
return getNodeOffset(node) >= region.getOffset()
&& getNodeEndOffset(node) <= region.getOffset() + region.getLength();
}
private IRegion getSafeIncludeReplacementRegion(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 = skipToNextLine(includeGuardEndOffset);
} else {
includeOffset = 0;
}
if (!topCommentSkipped) {
// Skip the first comment block near the top of the file.
includeOffset = skipStandaloneCommentBlock(includeOffset, maxSafeOffset, ast.getComments(), commentMap);
}
includeEndOffset = includeOffset;
} else {
includeEndOffset = skipToNextLine(includeEndOffset);
}
return new Region(includeOffset, includeEndOffset - includeOffset);
}
private 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)
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 IASTPreprocessorStatement findFirstPreprocessorStatement(IASTTranslationUnit ast) {
for (IASTPreprocessorStatement statement : ast.getAllPreprocessorStatements()) {
if (statement.isPartOfTranslationUnitFile())
return statement;
}
return null;
}
private boolean isPragmaOnce(IASTPreprocessorStatement statement) {
if (!(statement instanceof IASTPreprocessorPragmaStatement))
return false;
return CharArrayUtils.equals(((IASTPreprocessorPragmaStatement) statement).getMessage(), "once"); //$NON-NLS-1$
}
private int skipToNextLine(int offset) {
char[] contents = fContext.getTranslationUnit().getContents();
while (offset < contents.length) {
if (contents[offset++] == '\n')
break;
}
return offset;
}
private int getLineStart(int offset) {
char[] contents = fContext.getTranslationUnit().getContents();
while (--offset >= 0) {
if (contents[offset] == '\n')
break;
}
return offset + 1;
}
private int skipToNextLineAfterNode(IASTNode node) {
return skipToNextLine(getNodeEndOffset(node));
}
/**
* Returns {@code true} if there are no non-whitespace characters between the given
* {@code offset} and the end of the line.
*/
private boolean isBlankLineOrEndOfFile(int offset) {
char[] contents = fContext.getTranslationUnit().getContents();
while (offset < contents.length) {
char c = contents[offset++];
if (c == '\n')
return true;
if (!Character.isWhitespace(c))
return false;
}
return true;
}
/**
* Returns {@code true} the line prior to the line corresponding to the given {@code offset}
* does not contain non-whitespace characters.
*/
private boolean isPreviousLineBlank(int offset) {
char[] contents = fContext.getTranslationUnit().getContents();
while (--offset >= 0) {
if (contents[offset] == '\n')
break;
}
while (--offset >= 0) {
char c = contents[offset];
if (c == '\n')
return true;
if (!Character.isWhitespace(c))
return false;
}
return false;
}
/**
* 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) {
char[] contents = fContext.getTranslationUnit().getContents();
int i = offset;
while (--i >= 0) {
char c = contents[i];
if (c == '\n' || !Character.isWhitespace(c))
break;
}
i++;
return new String(contents, i, offset - i);
}
return ""; //$NON-NLS-1$
}
private int skipStandaloneCommentBlock(int offset, int endOffset, IASTComment[] comments, NodeCommentMap commentMap) {
Map<IASTComment, IASTNode> inverseLeadingMap = new HashMap<IASTComment, IASTNode>();
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<IASTComment, IASTNode>();
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);
}
}
}
// Create the source code to insert into the editor.
IBuffer fBuffer = fContext.getTranslationUnit().getBuffer();
String lineSep = getLineSeparator(fBuffer);
StringBuilder buf = new StringBuilder();
for (String include : includeDirectives) {
buf.append(include);
buf.append(lineSep);
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 skipToNextLineAfterNode(previous);
previous = comment;
}
if (buf.length() != 0 && !forwardDeclarations.isEmpty())
buf.append(lineSep);
for (String declaration : forwardDeclarations) {
buf.append(declaration);
buf.append(lineSep);
if (getStartingLineNumber(node) > getEndingLineNumber(previous) + 1)
return skipToNextLineAfterNode(previous);
}
if (buf.length() != 0 && !functionForwardDeclarations.isEmpty())
buf.append(lineSep);
for (String declaration : functionForwardDeclarations) {
buf.append(declaration);
buf.append(lineSep);
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 skipToNextLineAfterNode(previous);
previous = comment;
}
if (buf.length() != 0) {
buf.append(lineSep);
fBuffer.replace(0, 0, buf.toString());
}
}
}
return offset;
}
private IncludeGroupStyle getGroupingStyle(IncludeGroupStyle style) {
if (style.isKeepTogether())
@ -357,7 +792,7 @@ public class IncludeOrganizer {
private IncludeGroupStyle getIncludeStyle(IPath headerPath) {
IncludeKind includeKind;
IncludeInfo includeInfo = fContext.getIncludeForHeaderFile(headerPath);
if (includeInfo.isSystem()) {
if (includeInfo != null && includeInfo.isSystem()) {
if (headerPath.getFileExtension() == null) {
includeKind = IncludeKind.SYSTEM_WITHOUT_EXTENSION;
} else {
@ -389,8 +824,24 @@ public class IncludeOrganizer {
}
}
}
Map<IncludeKind, IncludeGroupStyle> styles = fContext.getPreferences().includeStyles;
return styles.get(includeKind);
return fContext.getPreferences().includeStyles.get(includeKind);
}
private IncludeGroupStyle getIncludeStyle(IncludeInfo includeInfo) {
IncludeKind includeKind;
IPath path = Path.fromPortableString(includeInfo.getName());
if (includeInfo.isSystem()) {
if (path.getFileExtension() == null) {
includeKind = IncludeKind.SYSTEM_WITHOUT_EXTENSION;
} else {
includeKind = IncludeKind.SYSTEM_WITH_EXTENSION;
}
} else if (isPartnerFile(path)) {
includeKind = IncludeKind.PARTNER;
} else {
includeKind = IncludeKind.EXTERNAL;
}
return fContext.getPreferences().includeStyles.get(includeKind);
}
private Set<IBinding> removeBindingsDefinedInIncludedHeaders(Set<IBinding> bindings,
@ -426,7 +877,8 @@ public class IncludeOrganizer {
private void processInclusionRequests(List<InclusionRequest> requests,
HeaderSubstitutor headerSubstitutor) {
// Add partner header if necessary.
HashSet<IIndexFile> partnerIndexFiles = new HashSet<IIndexFile>();
HashSet<IIndexFile> includedByPartner = fContext.getPreferences().allowPartnerIndirectInclusion ?
new HashSet<IIndexFile>() : null;
for (InclusionRequest request : requests) {
List<IPath> candidatePaths = request.getCandidatePaths();
if (candidatePaths.size() == 1) {
@ -434,13 +886,14 @@ public class IncludeOrganizer {
if (isPartnerFile(path)) {
request.resolve(path);
fContext.addHeaderToInclude(path);
if (includedByPartner != null) {
try {
IIndexFile indexFile = request.getDeclaringFiles().keySet().iterator().next();
if (!partnerIndexFiles.contains(indexFile)) {
if (!includedByPartner.contains(indexFile)) {
for (IIndexInclude include : indexFile.getIncludes()) {
fContext.addHeaderAlreadyIncluded(getPath(include.getIncludesLocation()));
}
partnerIndexFiles.add(indexFile);
includedByPartner.add(indexFile);
}
} catch (CoreException e) {
CUIPlugin.log(e);
@ -448,6 +901,7 @@ public class IncludeOrganizer {
}
}
}
}
// Process headers that are either indirectly included or have unique representatives.
for (InclusionRequest request : requests) {
@ -502,8 +956,6 @@ public class IncludeOrganizer {
// Resolve ambiguous inclusion requests.
// Maps a set of header files presented to the user to the file selected by the user.
HashMap<Collection<IPath>, IPath> userChoiceCache = new HashMap<Collection<IPath>, IPath>();
for (InclusionRequest request : requests) {
if (!request.isResolved()) {
List<IPath> candidatePaths = request.getCandidatePaths();
@ -513,7 +965,10 @@ public class IncludeOrganizer {
break;
}
}
IPath header = askUserToSelectHeader(request.getBinding(), candidatePaths, userChoiceCache);
IPath header = fHeaderChooser.chooseHeader(request.getBinding().getName(), candidatePaths);
if (header == null)
throw new OperationCanceledException();
request.resolve(header);
if (!fContext.isAlreadyIncluded(header))
fContext.addHeaderToInclude(header);
@ -606,98 +1061,48 @@ public class IncludeOrganizer {
return requests;
}
/**
* Returns the line separator for the given buffer.
* @param fBuffer
* @return
*/
private String getLineSeparator(IBuffer fBuffer) {
try {
if (fBuffer instanceof IAdaptable) {
IDocument doc= (IDocument) ((IAdaptable) fBuffer).getAdapter(IDocument.class);
if (doc != null) {
String delim= doc.getLineDelimiter(0);
if (delim != null) {
return delim;
}
}
}
} catch (BadLocationException e) {
}
return System.getProperty("line.separator", "\n"); //$NON-NLS-1$//$NON-NLS-2$
}
/**
* Picks a suitable header file that should be used to include the given binding.
*
* @param binding The binding which should be resolved.
* @param headers The available header files to pick from.
* @param userChoiceCache the cache of previous user choices
* @return The chosen header file.
*/
private IPath askUserToSelectHeader(IBinding binding, Collection<IPath> headers,
HashMap<Collection<IPath>, IPath> userChoiceCache) {
if (headers.isEmpty())
return null;
if (headers.size() == 1)
return headers.iterator().next();
// Check the decision cache. If the cache doesn't help, ask the user.
// Query the cache.
if (userChoiceCache.containsKey(headers)) {
return userChoiceCache.get(headers);
}
// Ask the user.
final IPath[] elemArray = headers.toArray(new IPath[headers.size()]);
final IPath[] selectedElement = new IPath[1];
final String bindingName = binding.getName();
runInUIThread(new Runnable() {
@Override
public void run() {
ElementListSelectionDialog dialog =
new ElementListSelectionDialog(fEditor.getSite().getShell(), new LabelProvider());
dialog.setElements(elemArray);
dialog.setTitle(CEditorMessages.OrganizeIncludes_label);
dialog.setMessage(NLS.bind(Messages.IncludeOrganizer_ChooseHeader, bindingName));
if (dialog.open() == Window.OK) {
selectedElement[0] = (IPath) dialog.getFirstResult();
}
}
});
IPath selectedHeader = selectedElement[0];
if (selectedHeader == null)
throw new OperationCanceledException();
userChoiceCache.put(headers, selectedHeader); // Remember user's choice.
return selectedHeader;
}
private void runInUIThread(Runnable runnable) {
if (Display.getCurrent() != null) {
runnable.run();
} else {
Display.getDefault().syncExec(runnable);
}
}
private String createIncludeDirective(IPath header, IncludeGroupStyle style, String lineComment) {
StringBuilder buf = new StringBuilder("#include "); //$NON-NLS-1$
buf.append(style.isAngleBrackets() ? '<' : '"');
private IncludeInfo createIncludeInfo(IPath header, IncludeGroupStyle style) {
String name = null;
if (style.isRelativePath()) {
IPath relativePath = PathUtil.makeRelativePath(header, fContext.getCurrentDirectory());
if (relativePath != null)
name = relativePath.toPortableString();
name = getRelativePath(header);
}
if (name == null) {
IncludeInfo includeInfo = fContext.getIncludeForHeaderFile(header);
if (includeInfo != null) {
name = includeInfo.getName();
} else {
name = getRelativePath(header);
}
buf.append(name);
buf.append(style.isAngleBrackets() ? '>' : '"');
if (name == null) {
name = header.toPortableString(); // Last resort.
}
}
return new IncludeInfo(name, style.isAngleBrackets());
}
private String getRelativePath(IPath header) {
IPath relativePath = PathUtil.makeRelativePath(header, fContext.getCurrentDirectory());
if (relativePath == null)
return null;
return relativePath.toPortableString();
}
private String createIncludeDirective(IncludePrototype include, String lineComment) {
StringBuilder buf = new StringBuilder();
// Unresolved includes are preserved out of caution.
if (!include.required && include.header != null) {
switch (fContext.getPreferences().unusedStatementsDisposition) {
case REMOVE:
return null;
case COMMENT_OUT:
buf.append("//"); //$NON-NLS-1$
break;
case KEEP:
break;
}
}
buf.append("#include "); //$NON-NLS-1$
buf.append(include.includeInfo.toString());
buf.append(lineComment);
return buf.toString();
}

View file

@ -34,26 +34,30 @@ public class IncludePreferences {
public final Map<IncludeKind, IncludeGroupStyle> includeStyles;
public final boolean allowReordering;
public final boolean heuristicHeaderSubstitution;
public final boolean allowPartnerIndirectInclusion;
public final boolean forwardDeclareCompositeTypes;
public final boolean forwardDeclareEnums;
public final boolean forwardDeclareFunctions;
// TODO(sprigogin): Create a preference.
public final boolean forwardDeclareExternalVariables = false;
public final boolean forwardDeclareTemplates;
public final boolean forwardDeclareNamespaceElements;
public final UnusedStatementDisposition unusedStatementsDisposition;
public final String[] partnerFileSuffixes;
public IncludePreferences(ICProject project) {
includeStyles = new HashMap<IncludeKind, IncludeGroupStyle>();
loadStyle(IncludeKind.RELATED, PREF_INCLUDE_STYLE_RELATED, project);
loadStyle(IncludeKind.PARTNER, PREF_INCLUDE_STYLE_PARTNER, project);
loadStyle(IncludeKind.IN_SAME_FOLDER, PREF_INCLUDE_STYLE_SAME_FOLDER, project);
loadStyle(IncludeKind.IN_SUBFOLDER, PREF_INCLUDE_STYLE_SUBFOLDER, project);
loadStyle(IncludeKind.SYSTEM, PREF_INCLUDE_STYLE_SYSTEM, project);
loadStyle(IncludeKind.SYSTEM_WITH_EXTENSION, PREF_INCLUDE_STYLE_SYSTEM_WITH_EXTENSION, project);
loadStyle(IncludeKind.SYSTEM_WITHOUT_EXTENSION, PREF_INCLUDE_STYLE_SYSTEM_WITHOUT_EXTENSION, project);
loadStyle(IncludeKind.OTHER, PREF_INCLUDE_STYLE_OTHER, project);
loadStyle(IncludeKind.IN_SAME_PROJECT, PREF_INCLUDE_STYLE_SAME_PROJECT, project);
loadStyle(IncludeKind.IN_OTHER_PROJECT, PREF_INCLUDE_STYLE_OTHER_PROJECT, project);
loadStyle(IncludeKind.EXTERNAL, PREF_INCLUDE_STYLE_EXTERNAL, project);
loadStyle(IncludeKind.RELATED, PreferenceConstants.INCLUDE_STYLE_RELATED, project);
loadStyle(IncludeKind.PARTNER, PreferenceConstants.INCLUDE_STYLE_PARTNER, project);
loadStyle(IncludeKind.IN_SAME_FOLDER, PreferenceConstants.INCLUDE_STYLE_SAME_FOLDER, project);
loadStyle(IncludeKind.IN_SUBFOLDER, PreferenceConstants.INCLUDE_STYLE_SUBFOLDER, project);
loadStyle(IncludeKind.SYSTEM, PreferenceConstants.INCLUDE_STYLE_SYSTEM, project);
loadStyle(IncludeKind.SYSTEM_WITH_EXTENSION, PreferenceConstants.INCLUDE_STYLE_SYSTEM_WITH_EXTENSION, project);
loadStyle(IncludeKind.SYSTEM_WITHOUT_EXTENSION, PreferenceConstants.INCLUDE_STYLE_SYSTEM_WITHOUT_EXTENSION, project);
loadStyle(IncludeKind.OTHER, PreferenceConstants.INCLUDE_STYLE_OTHER, project);
loadStyle(IncludeKind.IN_SAME_PROJECT, PreferenceConstants.INCLUDE_STYLE_SAME_PROJECT, project);
loadStyle(IncludeKind.IN_OTHER_PROJECT, PreferenceConstants.INCLUDE_STYLE_OTHER_PROJECT, project);
loadStyle(IncludeKind.EXTERNAL, PreferenceConstants.INCLUDE_STYLE_EXTERNAL, project);
// Unclassified includes are always kept together.
includeStyles.get(IncludeKind.OTHER).setKeepTogether(true);
// Normalize order property of the styles to make sure that the numbers are sequential.
@ -65,26 +69,31 @@ public class IncludePreferences {
// TODO(sprigogin): Load styles for headers matching patterns.
forwardDeclareCompositeTypes = PreferenceConstants.getPreference(
PREF_FORWARD_DECLARE_COMPOSITE_TYPES, project, true);
PreferenceConstants.FORWARD_DECLARE_COMPOSITE_TYPES, project, true);
forwardDeclareEnums = PreferenceConstants.getPreference(
PREF_FORWARD_DECLARE_ENUMS, project, false);
PreferenceConstants.FORWARD_DECLARE_ENUMS, project, false);
forwardDeclareFunctions = PreferenceConstants.getPreference(
PREF_FORWARD_DECLARE_FUNCTIONS, project, false);
PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, project, false);
forwardDeclareTemplates = PreferenceConstants.getPreference(
PreferenceConstants.FORWARD_DECLARE_TEMPLATES, project, false);
forwardDeclareNamespaceElements = PreferenceConstants.getPreference(
PREF_FORWARD_DECLARE_NAMESPACE_ELEMENTS, project, true);
PreferenceConstants.FORWARD_DECLARE_NAMESPACE_ELEMENTS, project, true);
String value = PreferenceConstants.getPreference(
PREF_PARTNER_FILE_SUFFIXES, project, DEFAULT_PARTNER_FILE_SUFFIXES);
PreferenceConstants.INCLUDES_PARTNER_FILE_SUFFIXES, project, DEFAULT_PARTNER_FILE_SUFFIXES);
partnerFileSuffixes = value.split(","); //$NON-NLS-1$
heuristicHeaderSubstitution = PreferenceConstants.getPreference(
PREF_HEURISTIC_HEADER_SUBSTITUTION, project, true);
PreferenceConstants.INCLUDES_HEURISTIC_HEADER_SUBSTITUTION, project, true);
allowReordering = PreferenceConstants.getPreference(
PREF_INCLUDES_REORDERING, project, true);
PreferenceConstants.INCLUDES_ALLOW_REORDERING, project, true);
// TODO(sprigogin): Create a preference for this.
allowPartnerIndirectInclusion = false;
// Unused include handling preferences
value = PreferenceConstants.getPreference(PREF_UNUSED_STATEMENTS_DISPOSITION, project, null);
value = PreferenceConstants.getPreference(PreferenceConstants.INCLUDES_UNUSED_STATEMENTS_DISPOSITION, project, null);
UnusedStatementDisposition disposition = null;
if (value != null)
disposition = UnusedStatementDisposition.valueOf(value);
@ -103,148 +112,6 @@ public class IncludePreferences {
includeStyles.put(includeKind, style);
}
// TODO(sprigogin): Move the constants and defaults to PreferenceConstants.
/**
* Whether composite types should be forward declared if possible.
*
* Examples:
* class X;
* struct Y;
* union Z;
*/
public static final String PREF_FORWARD_DECLARE_COMPOSITE_TYPES = "forward_declare_composite_types"; //$NON-NLS-1$
/**
* Whether C++11-style enums should be forward declared if possible.
*
* Example:
* enum class X;
*/
public static final String PREF_FORWARD_DECLARE_ENUMS = "forward_declare_enums"; //$NON-NLS-1$
/**
* Whether C-style functions should be forward declared if possible.
*
* Example:
* void foo();
*/
public static final String PREF_FORWARD_DECLARE_FUNCTIONS = "forward_declare_functions"; //$NON-NLS-1$
/**
* Whether elements nested within namespaces should be forward declared if possible.
*
* Examples:
* namespace N { class X; }
*/
public static final String PREF_FORWARD_DECLARE_NAMESPACE_ELEMENTS = "forward_declare_namespace_elements"; //$NON-NLS-1$
/**
* Defines a list of file name suffixes. A header file and the including file are considered
* partners if their file names without extensions are either identical or differ by one of
* these suffixes.
*/
public static final String PREF_PARTNER_FILE_SUFFIXES = "include_partner_file_suffixes"; //$NON-NLS-1$
/**
* Whether a heuristic approach should be used to decide which C++ header files to include.
* The heuristic prefers headers which have no file extension and / or are named like the symbol
* which should be defined. This often works out nicely since it's a commonly used naming
* convention for C++ library headers.
*/
public static final String PREF_HEURISTIC_HEADER_SUBSTITUTION = "organize_includes_heuristic_header_substitution"; //$NON-NLS-1$
/**
* Whether it's allowed to reorder existing include directives. If this preference is set to
* false, the original order is kept as far as possible. This may be necessary to avoid breaking
* code which makes assumptions about the order of the include directives. If this is set to
* true, a different sort order can be applied. Groups of includes are ordered according to
* the values returned by
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle#getOrder()} method.
* Includes within each group are ordered alphabetically.
*/
public static final String PREF_INCLUDES_REORDERING = "organize_includes_allow_reordering"; //$NON-NLS-1$
/**
* Determines what should be done with any unused include directives and forward declarations.
* This preference may have one of the three values defined by
* {@link UnusedStatementDisposition} enumeration ("REMOVE", "COMMENT_OUT", "KEEP").
*/
public static final String PREF_UNUSED_STATEMENTS_DISPOSITION = "organize_includes_unused_statements"; //$NON-NLS-1$
/**
* Include style for headers closely related to the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*/
public static final String PREF_INCLUDE_STYLE_RELATED = "include_style_related"; //$NON-NLS-1$
/**
* Include style for the header with the same name as the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*/
public static final String PREF_INCLUDE_STYLE_PARTNER = "include_style_partner"; //$NON-NLS-1$
/**
* Include style for headers in the same folder as the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*/
public static final String PREF_INCLUDE_STYLE_SAME_FOLDER = "include_style_same_folder"; //$NON-NLS-1$
/**
* Include style for headers in subfolders of the folder containing the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*/
public static final String PREF_INCLUDE_STYLE_SUBFOLDER = "include_style_subfolder"; //$NON-NLS-1$
/**
* Include style for system headers.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*/
public static final String PREF_INCLUDE_STYLE_SYSTEM = "include_style_system"; //$NON-NLS-1$
/**
* Include style for C-style system headers with a file name extension.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*/
public static final String PREF_INCLUDE_STYLE_SYSTEM_WITH_EXTENSION = "include_style_system_with_extension"; //$NON-NLS-1$
/**
* Include style for C++-style system headers without a file name extension.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*/
public static final String PREF_INCLUDE_STYLE_SYSTEM_WITHOUT_EXTENSION = "include_style_system_without_extension"; //$NON-NLS-1$
/**
* Include style for headers not closely related to the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*/
public static final String PREF_INCLUDE_STYLE_OTHER = "include_style_other"; //$NON-NLS-1$
/**
* Include style for headers in the same project as the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*/
public static final String PREF_INCLUDE_STYLE_SAME_PROJECT = "include_style_in_same_project"; //$NON-NLS-1$
/**
* Include style for headers in a different project than the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*/
public static final String PREF_INCLUDE_STYLE_OTHER_PROJECT = "include_style_in_other_project"; //$NON-NLS-1$
/**
* Include style for headers outside Eclipse workspace.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*/
public static final String PREF_INCLUDE_STYLE_EXTERNAL = "include_style_external"; //$NON-NLS-1$
/**
* Include styles for headers matching user-defined patterns.
* The value of the preference is an XML representation of one or more
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}s.
*/
public static final String PREF_INCLUDE_STYLE_MATCHING_PATTERN = "include_style_matching_pattern"; //$NON-NLS-1$
/**
* Initializes the given preference store with the default values.
*
@ -252,50 +119,51 @@ public class IncludePreferences {
*/
public static void initializeDefaultValues(IPreferenceStore store) {
IncludeGroupStyle style = new IncludeGroupStyle(IncludeKind.RELATED);
store.setDefault(PREF_INCLUDE_STYLE_RELATED, style.toString());
store.setDefault(PreferenceConstants.INCLUDE_STYLE_RELATED, style.toString());
style = new IncludeGroupStyle(IncludeKind.PARTNER);
style.setKeepTogether(true);
style.setBlankLineBefore(true);
style.setOrder(0);
store.setDefault(PREF_INCLUDE_STYLE_PARTNER, style.toString());
store.setDefault(PreferenceConstants.INCLUDE_STYLE_PARTNER, style.toString());
style = new IncludeGroupStyle(IncludeKind.IN_SAME_FOLDER);
store.setDefault(PREF_INCLUDE_STYLE_SAME_FOLDER, style.toString());
store.setDefault(PreferenceConstants.INCLUDE_STYLE_SAME_FOLDER, style.toString());
style = new IncludeGroupStyle(IncludeKind.IN_SUBFOLDER);
store.setDefault(PREF_INCLUDE_STYLE_SUBFOLDER, style.toString());
store.setDefault(PreferenceConstants.INCLUDE_STYLE_SUBFOLDER, style.toString());
style = new IncludeGroupStyle(IncludeKind.SYSTEM);
style.setKeepTogether(true);
style.setBlankLineBefore(true);
store.setDefault(PREF_INCLUDE_STYLE_SYSTEM, style.toString());
store.setDefault(PreferenceConstants.INCLUDE_STYLE_SYSTEM, style.toString());
style = new IncludeGroupStyle(IncludeKind.SYSTEM_WITH_EXTENSION);
style.setKeepTogether(true);
style.setAngleBrackets(true);
style.setOrder(1);
store.setDefault(PREF_INCLUDE_STYLE_SYSTEM_WITH_EXTENSION, style.toString());
store.setDefault(PreferenceConstants.INCLUDE_STYLE_SYSTEM_WITH_EXTENSION, style.toString());
style = new IncludeGroupStyle(IncludeKind.SYSTEM_WITHOUT_EXTENSION);
style.setKeepTogether(true);
style.setAngleBrackets(true);
style.setOrder(2);
store.setDefault(PREF_INCLUDE_STYLE_SYSTEM_WITHOUT_EXTENSION, style.toString());
store.setDefault(PreferenceConstants.INCLUDE_STYLE_SYSTEM_WITHOUT_EXTENSION, style.toString());
style = new IncludeGroupStyle(IncludeKind.OTHER);
style.setKeepTogether(true);
style.setBlankLineBefore(true);
style.setOrder(3);
store.setDefault(PREF_INCLUDE_STYLE_OTHER, style.toString());
store.setDefault(PreferenceConstants.INCLUDE_STYLE_OTHER, style.toString());
style = new IncludeGroupStyle(IncludeKind.IN_SAME_PROJECT);
store.setDefault(PREF_INCLUDE_STYLE_SAME_PROJECT, style.toString());
store.setDefault(PreferenceConstants.INCLUDE_STYLE_SAME_PROJECT, style.toString());
style = new IncludeGroupStyle(IncludeKind.IN_OTHER_PROJECT);
store.setDefault(PREF_INCLUDE_STYLE_OTHER_PROJECT, style.toString());
store.setDefault(PreferenceConstants.INCLUDE_STYLE_OTHER_PROJECT, style.toString());
style = new IncludeGroupStyle(IncludeKind.EXTERNAL);
store.setDefault(PREF_INCLUDE_STYLE_EXTERNAL, style.toString());
store.setDefault(PREF_INCLUDE_STYLE_MATCHING_PATTERN, ""); //$NON-NLS-1$
store.setDefault(PreferenceConstants.INCLUDE_STYLE_EXTERNAL, style.toString());
store.setDefault(PreferenceConstants.INCLUDE_STYLE_MATCHING_PATTERN, ""); //$NON-NLS-1$
store.setDefault(PREF_PARTNER_FILE_SUFFIXES, DEFAULT_PARTNER_FILE_SUFFIXES);
store.setDefault(PREF_HEURISTIC_HEADER_SUBSTITUTION, true);
store.setDefault(PREF_INCLUDES_REORDERING, true);
store.setDefault(PREF_FORWARD_DECLARE_COMPOSITE_TYPES, true);
store.setDefault(PREF_FORWARD_DECLARE_ENUMS, false);
store.setDefault(PREF_FORWARD_DECLARE_FUNCTIONS, false);
store.setDefault(PREF_FORWARD_DECLARE_NAMESPACE_ELEMENTS, true);
store.setDefault(PREF_UNUSED_STATEMENTS_DISPOSITION, UnusedStatementDisposition.COMMENT_OUT.toString());
store.setDefault(PreferenceConstants.INCLUDES_PARTNER_FILE_SUFFIXES, DEFAULT_PARTNER_FILE_SUFFIXES);
store.setDefault(PreferenceConstants.INCLUDES_HEURISTIC_HEADER_SUBSTITUTION, true);
store.setDefault(PreferenceConstants.INCLUDES_ALLOW_REORDERING, true);
store.setDefault(PreferenceConstants.FORWARD_DECLARE_COMPOSITE_TYPES, true);
store.setDefault(PreferenceConstants.FORWARD_DECLARE_ENUMS, false);
store.setDefault(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, false);
store.setDefault(PreferenceConstants.FORWARD_DECLARE_TEMPLATES, false);
store.setDefault(PreferenceConstants.FORWARD_DECLARE_NAMESPACE_ELEMENTS, true);
store.setDefault(PreferenceConstants.INCLUDES_UNUSED_STATEMENTS_DISPOSITION, UnusedStatementDisposition.COMMENT_OUT.toString());
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 Google, Inc and others.
* Copyright (c) 2012, 2013 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

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 Google, Inc and others.
* Copyright (c) 2012, 2013 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
@ -34,7 +34,7 @@ import org.eclipse.cdt.internal.core.parser.scanner.ScannerUtility;
* Context for managing include statements.
*/
public class InclusionContext {
private static final IPath UNRESOLVED_INCLUDE = new Path(""); //$NON-NLS-1$
private static final IPath UNRESOLVED_INCLUDE = Path.EMPTY;
private final ITranslationUnit fTu;
private final IProject fProject;
@ -132,22 +132,19 @@ public class InclusionContext {
String headerLocation = fullPath.toOSString();
String shortestInclude = null;
boolean isSystem = false;
int count = 0; //XXX
for (IncludeSearchPathElement pathElement : fIncludeSearchPath.getElements()) {
String includeDirective = pathElement.getIncludeDirective(headerLocation);
if (includeDirective != null &&
(shortestInclude == null || shortestInclude.length() > includeDirective.length())) {
shortestInclude = includeDirective;
isSystem = !pathElement.isForQuoteIncludesOnly();
if (count < 1) //XXX
isSystem = false; //XXX Hack to introduce non-system includes
}
count++; //XXX
}
if (shortestInclude == null)
return null;
include = new IncludeInfo(shortestInclude, isSystem);
fIncludeResolutionCache.put(include, fullPath);
// 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;
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012 Google, Inc and others.
* Copyright (c) 2012, 2013 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

View file

@ -1,11 +0,0 @@
###############################################################################
# Copyright (c) 2012 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
###############################################################################
IncludeOrganizer_ChooseHeader=Choose a header file to include for symbol ''{0}''

View file

@ -1953,6 +1953,197 @@ public class PreferenceConstants {
*/
public static final String FUNCTION_PASS_OUTPUT_PARAMETERS_BY_POINTER = "function_pass_output_parameters_by_pointer"; //$NON-NLS-1$
/**
* Whether composite types should be forward declared if possible.
*
* Examples:
* class X;
* struct Y;
* union Z;
*
* @since 5.6
*/
public static final String FORWARD_DECLARE_COMPOSITE_TYPES = "forwardDeclare.compositeTypes"; //$NON-NLS-1$
/**
* Whether C++11-style enums should be forward declared if possible.
*
* Example:
* enum class X;
*
* @since 5.6
*/
public static final String FORWARD_DECLARE_ENUMS = "forwardDeclare.enums"; //$NON-NLS-1$
/**
* Whether C-style functions should be forward declared if possible.
*
* Example:
* void foo();
*
* @since 5.6
*/
public static final String FORWARD_DECLARE_FUNCTIONS = "forwardDeclare.functions"; //$NON-NLS-1$
/**
* Whether C++ templates should be forward declared if possible.
*
* Examples:
* template<typename T> class foo;
* template<typename T> void bar(T p);
*
* @since 5.6
*/
public static final String FORWARD_DECLARE_TEMPLATES = "forwardDeclare.templates"; //$NON-NLS-1$
/**
* Whether elements nested within namespaces should be forward declared if possible.
*
* Examples:
* namespace N { class X; }
*
* @since 5.6
*/
public static final String FORWARD_DECLARE_NAMESPACE_ELEMENTS = "forwardDeclare.namespaceElements"; //$NON-NLS-1$
/**
* Defines a list of file name suffixes. A header file and the including file are considered
* partners if their file names without extensions are either identical or differ by one of
* these suffixes.
*
* @since 5.6
*/
public static final String INCLUDES_PARTNER_FILE_SUFFIXES = "includes.partnerFileSuffixes"; //$NON-NLS-1$
/**
* Whether a heuristic approach should be used to decide which C++ header files to include.
* The heuristic prefers headers which have no file extension and / or are named like the symbol
* which should be defined. This often works out nicely since it's a commonly used naming
* convention for C++ library headers.
*
* @since 5.6
*/
public static final String INCLUDES_HEURISTIC_HEADER_SUBSTITUTION = "organizeIncludes.heuristicHeader_substitution"; //$NON-NLS-1$
/**
* Whether it's allowed to reorder existing include directives. If this preference is set to
* false, the original order is kept as far as possible. This may be necessary to avoid breaking
* code which makes assumptions about the order of the include directives. If this is set to
* true, a different sort order can be applied. Groups of includes are ordered according to
* the values returned by
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle#getOrder()} method.
* Includes within each group are ordered alphabetically.
*
* @since 5.6
*/
public static final String INCLUDES_ALLOW_REORDERING = "organizeIncludes.allowReordering"; //$NON-NLS-1$
/**
* Determines what should be done with any unused include directives and forward declarations.
* This preference may have one of the three values defined by
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludePreferences.UnusedStatementDisposition}
* enumeration ("REMOVE", "COMMENT_OUT", "KEEP").
*
* @since 5.6
*/
public static final String INCLUDES_UNUSED_STATEMENTS_DISPOSITION = "organizeIncludes.unusedStatements"; //$NON-NLS-1$
/**
* Include style for headers closely related to the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_RELATED = "includeStyle.related"; //$NON-NLS-1$
/**
* Include style for the header with the same name as the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_PARTNER = "includeStyle.partner"; //$NON-NLS-1$
/**
* Include style for headers in the same folder as the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_SAME_FOLDER = "includeStyle.sameFolder"; //$NON-NLS-1$
/**
* Include style for headers in subfolders of the folder containing the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_SUBFOLDER = "includeStyle.subfolder"; //$NON-NLS-1$
/**
* Include style for system headers.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_SYSTEM = "includeStyle.system"; //$NON-NLS-1$
/**
* Include style for C-style system headers with a file name extension.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_SYSTEM_WITH_EXTENSION = "includeStyle.systemWithExtension"; //$NON-NLS-1$
/**
* Include style for C++-style system headers without a file name extension.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_SYSTEM_WITHOUT_EXTENSION = "includeStyle.systemWithoutExtension"; //$NON-NLS-1$
/**
* Include style for headers not closely related to the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_OTHER = "includeStyle.other"; //$NON-NLS-1$
/**
* Include style for headers in the same project as the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_SAME_PROJECT = "includeStyle.inSameProject"; //$NON-NLS-1$
/**
* Include style for headers in a different project than the including file.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_OTHER_PROJECT = "includeStyle.inOtherProject"; //$NON-NLS-1$
/**
* Include style for headers outside Eclipse workspace.
* The value of the preference is an XML representation of
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_EXTERNAL = "includeStyle.external"; //$NON-NLS-1$
/**
* Include styles for headers matching user-defined patterns.
* The value of the preference is an XML representation of one or more
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.IncludeGroupStyle}s.
*
* @since 5.6
*/
public static final String INCLUDE_STYLE_MATCHING_PATTERN = "includeStyle.matchingPattern"; //$NON-NLS-1$
/**
* Returns the CDT-UI preference store.

View file

@ -139,6 +139,13 @@ public class CdtActionConstants {
*/
public static final String ADD_INCLUDE= "org.eclipse.cdt.ui.actions.AddInclude"; //$NON-NLS-1$
/**
* Source menu: name of standard Organize Includes global action
* (value <code>"org.eclipse.cdt.ui.actions.OrganizeIncludes"</code>).
* @since 5.6
*/
public static final String ORGANIZE_INCLUDES= "org.eclipse.cdt.ui.actions.OrganizeIncludes"; //$NON-NLS-1$
/**
* Source menu: name of standard Sort Lines global action
* (value <code>"org.eclipse.cdt.ui.actions.SortLines"</code>).

View file

@ -160,7 +160,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
editor.setAction("AddIncludeOnSelection", fAddInclude); //$NON-NLS-1$
fOrganizeIncludes= new OrganizeIncludesAction(editor);
// TODO: fOrganizeIncludes.setActionDefinitionId(ICEditorActionDefinitionIds.ORGANIZE_INCLUDES);
fOrganizeIncludes.setActionDefinitionId(ICEditorActionDefinitionIds.ORGANIZE_INCLUDES);
editor.setAction("OrganizeIncludes", fOrganizeIncludes); //$NON-NLS-1$
// fSortMembers= new SortMembersAction(editor);