diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommentTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommentTests.java
index ca8d20b7f90..ded306768b4 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommentTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/CommentTests.java
@@ -29,14 +29,14 @@ public class CommentTests extends AST2TestBase {
return suite(CommentTests.class);
}
- public void testCountCommentsInHeaderFile() throws ParserException{
+ public void testCountCommentsInHeaderFile() throws ParserException {
IASTTranslationUnit tu = parse(getHSource(), ParserLanguage.CPP, false, true);
IASTComment[] comments = tu.getComments();
assertEquals(9, comments.length);
}
- public void testCommentsInHeaderFile() throws ParserException{
+ public void testCommentsInHeaderFile() throws ParserException {
IASTTranslationUnit tu = parse(getHSource(), ParserLanguage.CPP, false, true);
IASTComment[] comments = tu.getComments();
@@ -51,14 +51,14 @@ public class CommentTests extends AST2TestBase {
assertEquals("//Endcomment h", new String(comments[8].getComment()));
}
- public void testCountCommentsInCPPFile() throws ParserException{
+ public void testCountCommentsInCPPFile() throws ParserException {
IASTTranslationUnit tu = parse(getCppSource(), ParserLanguage.CPP, false, true);
IASTComment[] comments = tu.getComments();
assertEquals(10, comments.length);
}
- public void testCommentsInCPPFile() throws ParserException{
+ public void testCommentsInCPPFile() throws ParserException {
IASTTranslationUnit tu = parse(getCppSource(), ParserLanguage.CPP, false, true);
IASTComment[] comments = tu.getComments();
@@ -74,14 +74,14 @@ public class CommentTests extends AST2TestBase {
assertEquals("//An integer", new String(comments[9].getComment()));
}
- public void testCountCommentsInCFile() throws ParserException{
+ public void testCountCommentsInCFile() throws ParserException {
IASTTranslationUnit tu = parse(getCSource(), ParserLanguage.C, false, true);
IASTComment[] comments = tu.getComments();
assertEquals(4, comments.length);
}
- public void testCommentsInCFile() throws ParserException{
+ public void testCommentsInCFile() throws ParserException {
IASTTranslationUnit tu = parse(getCSource(), ParserLanguage.C, false, true);
IASTComment[] comments = tu.getComments();
@@ -211,7 +211,7 @@ public class CommentTests extends AST2TestBase {
}
// //comment
- public void testCommentLocation_bug186337() throws Exception{
+ public void testCommentLocation_bug186337() throws Exception {
CharSequence code= getContents(1)[0];
IASTTranslationUnit tu = parse(code.toString(), ParserLanguage.CPP, false, true);
IASTComment[] comments = tu.getComments();
@@ -234,7 +234,6 @@ public class CommentTests extends AST2TestBase {
// #ifdef WHATEVA // TODO: ignored
// #endif // TODO: ignored
// // TODO: shows up in task list
-
public void testCommentInDirectives_bug192546() throws Exception {
CharSequence code= getContents(1)[0];
IASTTranslationUnit tu = parse(code.toString(), ParserLanguage.CPP, false, false);
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/comenthandler/CommentHandlingTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/comenthandler/CommentHandlingTest.java
index cda751ea9f3..2846fdcb38c 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/comenthandler/CommentHandlingTest.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/comenthandler/CommentHandlingTest.java
@@ -30,6 +30,7 @@ import org.eclipse.cdt.core.parser.tests.rewrite.TestSourceFile;
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.ASTCommenter;
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
/**
* This test tests the behavior of the class ASTCommenter. It checks if the ASTCommenter assigns
@@ -158,15 +159,17 @@ public class CommentHandlingTest extends RewriteBaseTest {
return output.toString().trim();
}
- private String getSignature(IASTNode actNode) {
- if (actNode instanceof IASTCompositeTypeSpecifier) {
- IASTCompositeTypeSpecifier comp = (IASTCompositeTypeSpecifier) actNode;
+ private String getSignature(IASTNode node) {
+ if (node instanceof IASTCompositeTypeSpecifier) {
+ IASTCompositeTypeSpecifier comp = (IASTCompositeTypeSpecifier) node;
return comp.getName().toString();
- } else if (actNode instanceof IASTEnumerationSpecifier) {
- IASTEnumerationSpecifier comp = (IASTEnumerationSpecifier) actNode;
+ } else if (node instanceof IASTEnumerationSpecifier) {
+ IASTEnumerationSpecifier comp = (IASTEnumerationSpecifier) node;
return comp.getName().toString();
+ } else if (node instanceof IASTTranslationUnit) {
+ return Path.fromOSString(node.getFileLocation().getFileName()).lastSegment();
}
- return actNode.getRawSignature();
+ return node.getRawSignature();
}
private static String getSeparatingRegexp() {
diff --git a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
index b4de8014640..bad3554ca8a 100644
--- a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
+++ b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF
@@ -61,7 +61,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",
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTFileLocation.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTFileLocation.java
index ef76745892c..440be3149c3 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTFileLocation.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTFileLocation.java
@@ -37,25 +37,25 @@ public interface IASTFileLocation extends IASTNodeLocation {
public int getNodeLength();
/**
- * Get the starting line number. Locations obtained via the index do not have line numbers
- * and return 0.
+ * Returns the starting line number. Locations obtained via the index do not have line numbers
+ * and return {@code 0}.
*
- * @return int representing line number or 0 if not applicable
+ * @return the 1-based line number, or {@code 0} if not applicable
*/
public int getStartingLineNumber();
/**
- * Get the ending line number. Locations obtained via the index do not have line numbers
- * and return 0.
+ * Returns the ending line number. Locations obtained via the index do not have line numbers
+ * and return {@code 0}.
*
- * @return int representing line number or 0 if not applicable
+ * @return the 1-based line number, or {@code 0} if not applicable
*/
public int getEndingLineNumber();
/**
* Returns the inclusion statement that included this file, or null for
* a top-level file.
- * Also null when the file location does not belong to an AST node, e.g.
+ * Also {@code null} when the file location does not belong to an AST node, e.g.
* if it is obtained from a name in the index.
* @since 5.4
*/
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTForStatement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTForStatement.java
index e6bcf447a89..c0020387e7a 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTForStatement.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTForStatement.java
@@ -11,8 +11,8 @@
package org.eclipse.cdt.core.dom.ast;
/**
- * The for statement. The initialization clause can be an expression or a
- * declaration but not both.
+ * The 'for' statement. The initialization clause can be an expression
+ * or a declaration but not both.
*
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
@@ -57,8 +57,7 @@ public interface IASTForStatement extends IASTStatement {
* @param statement
*/
public void setInitializerStatement( IASTStatement statement );
-
-
+
/**
* Get the condition expression for the loop.
*
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTIdExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTIdExpression.java
index 9d7934fc4aa..de2a6c26ad4 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTIdExpression.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTIdExpression.java
@@ -32,7 +32,7 @@ public interface IASTIdExpression extends IASTExpression, IASTNameOwner {
public IASTName getName();
/**
- * Set the name to be used inthe expression.
+ * Sets the name to be used in the expression.
*
* @param name
*/
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java
index 0f7ce9af3f1..998f3ada3ee 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java
@@ -23,16 +23,14 @@ import org.eclipse.cdt.core.parser.ISignificantMacros;
*/
public interface IASTPreprocessorIncludeStatement extends IASTPreprocessorStatement, IFileNomination {
/**
- * INCLUDE_NAME describes the relationship between an include directive and
- * it's name.
+ * {@code INCLUDE_NAME} describes the relationship between an include directive and its name.
*/
public static final ASTNodeProperty INCLUDE_NAME = new ASTNodeProperty(
"IASTPreprocessorMacroDefinition.INCLUDE_NAME - Include Name"); //$NON-NLS-1$
-
/**
- * Returns the absolute location of the file found through #include.
- * Only valid if {@link #isResolved()} returns true.
+ * Returns the absolute location of the file found through #include, or an empty string if
+ * include was not resolved.
*/
public String getPath();
@@ -109,14 +107,14 @@ public interface IASTPreprocessorIncludeStatement extends IASTPreprocessorStatem
public boolean isErrorInIncludedFile();
/**
- * Returns true, if an attempt will be or has been made to create AST for the target
+ * Returns {@code true}, if an attempt will be or has been made to create AST for the target
* of this inclusion.
* @since 5.4
*/
public boolean createsAST();
/**
- * Returns the file from the index that this include statement has pulled in, or null
+ * Returns the file from the index that this include statement has pulled in, or {@code null}
* if the include creates AST or is unresolved or skipped.
* @since 5.4
*/
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java
index 05d283d8ef5..2b4665d6c5b 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTTranslationUnit.java
@@ -32,26 +32,37 @@ import org.eclipse.core.runtime.IAdaptable;
*/
public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomination, IAdaptable {
/**
- * OWNED_DECLARATION represents the relationship between an IASTTranslationUnit and
- * it's nested IASTDeclaration's.
+ * {@code OWNED_DECLARATION} represents the relationship between an {@code IASTTranslationUnit}
+ * and its nested {@code IASTDeclaration}'s.
*/
public static final ASTNodeProperty OWNED_DECLARATION = new ASTNodeProperty(
"IASTTranslationUnit.OWNED_DECLARATION - IASTDeclaration for IASTTranslationUnit"); //$NON-NLS-1$
/**
- * SCANNER_PROBLEM represents the relationship between an IASTTranslationUnit and
- * it's nested IASTProblem.
+ * {@code SCANNER_PROBLEM} represents the relationship between an {@code IASTTranslationUnit}
+ * and its nested {@code IASTProblem}.
*/
public static final ASTNodeProperty SCANNER_PROBLEM = new ASTNodeProperty(
"IASTTranslationUnit.SCANNER_PROBLEM - IASTProblem (scanner caused) for IASTTranslationUnit"); //$NON-NLS-1$
/**
- * PREPROCESSOR_STATEMENT represents the relationship between an IASTTranslationUnit and
- * it's nested IASTPreprocessorStatement.
+ * {@code PREPROCESSOR_STATEMENT} represents the relationship between
+ * an {@code IASTTranslationUnit} and its nested {@code IASTPreprocessorStatement}.
*/
public static final ASTNodeProperty PREPROCESSOR_STATEMENT = new ASTNodeProperty(
"IASTTranslationUnit.PREPROCESSOR_STATEMENT - IASTPreprocessorStatement for IASTTranslationUnit"); //$NON-NLS-1$
+ public static final ASTNodeProperty MACRO_EXPANSION = new ASTNodeProperty(
+ "IASTTranslationUnit.MACRO_EXPANSION - IASTPreprocessorMacroExpansion node for macro expansions."); //$NON-NLS-1$
+
+ /**
+ * @deprecated names for macro expansions are nested inside of
+ * {@link IASTPreprocessorMacroExpansion}.
+ */
+ @Deprecated
+ public static final ASTNodeProperty EXPANSION_NAME = new ASTNodeProperty(
+ "IASTTranslationUnit.EXPANSION_NAME - IASTName generated for macro expansions."); //$NON-NLS-1$
+
/**
* A translation unit contains an ordered sequence of declarations.
*
@@ -62,7 +73,7 @@ public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomi
/**
* Adds declaration to translation unit.
*
- * @param declaration IASTDeclaration
+ * @param declaration {@code IASTDeclaration}
*/
@Override
public void addDeclaration(IASTDeclaration declaration);
@@ -130,7 +141,7 @@ public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomi
* The object is suitable for working in one of the files that is part of
* the translation unit.
* @param filePath file of interest, as returned by {@link IASTFileLocation#getFileName()},
- * or null to specify the root source of the translation-unit.
+ * or {@code null} to specify the root source of the translation-unit.
* @return an IASTNodeSelector.
* @since 5.0
*/
@@ -158,8 +169,8 @@ public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomi
public IASTPreprocessorMacroDefinition[] getBuiltinMacroDefinitions();
/**
- * Returns the include directives encountered in parsing this translation unit. This will also contain directives
- * used for handling the gcc-options -imacros and -include.
+ * Returns the include directives encountered in parsing this translation unit. This will also
+ * contain directives used for handling the gcc-options -imacros and -include.
*
* In case the information for a header-file is pulled in from the index,
* include directives contained therein are not returned.
@@ -180,7 +191,7 @@ public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomi
/**
* Returns all preprocessor and scanner problems.
- * @return IASTProblem[]
+ * @return {@code IASTProblem[]}
*/
public IASTProblem[] getPreprocessorProblems();
@@ -199,21 +210,11 @@ public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomi
/**
* Flattens the node locations provided into a single file location.
*
- * @param nodeLocations IASTNodeLocations to flatten
+ * @param nodeLocations {@code IASTNodeLocation}s to flatten
* @return null if not possible, otherwise, a file location representing where the macros are.
*/
public IASTFileLocation flattenLocationsToFile(IASTNodeLocation[] nodeLocations);
- /**
- * @deprecated names for macro expansions are nested inside of {@link IASTPreprocessorMacroExpansion}.
- */
- @Deprecated
- public static final ASTNodeProperty EXPANSION_NAME = new ASTNodeProperty(
- "IASTTranslationUnit.EXPANSION_NAME - IASTName generated for macro expansions."); //$NON-NLS-1$
-
- public static final ASTNodeProperty MACRO_EXPANSION = new ASTNodeProperty(
- "IASTTranslationUnit.MACRO_EXPANSION - IASTPreprocessorMacroExpansion node for macro expansions."); //$NON-NLS-1$
-
public static interface IDependencyTree {
public String getTranslationUnitPath();
@@ -253,7 +254,7 @@ public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomi
/**
* Return the set of files that have been skipped because they have been part of the index
- * prior to creating this AST, or null if not available.
+ * prior to creating this AST, or {@code null} if not available.
* Applies only, if AST was created with an index and the option to skip headers found in
* the index.
* @since 5.1
@@ -261,7 +262,7 @@ public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomi
IIndexFileSet getIndexFileSet();
/**
- * Return the set of files in the index that are superseded by this AST, or null
+ * Return the set of files in the index that are superseded by this AST, or {@code null}
* if not available. Applies only, if AST was created with an index.
* @since 5.3
*/
@@ -271,7 +272,7 @@ public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomi
* In case the AST was created in a way that supports comment parsing, all comments of
* the translation unit are returned. Otherwise an empty array will be supplied.
*
- * @return IASTComment[]
+ * @return {@code IASTComment[]}
* @since 4.0
*/
public IASTComment[] getComments();
@@ -339,7 +340,7 @@ public interface IASTTranslationUnit extends IASTDeclarationListOwner, IFileNomi
public IASTTranslationUnit copy(CopyStyle style);
/**
- * Returns the ITranslationUnit this AST originated from, or null if the AST
+ * Returns the ITranslationUnit this AST originated from, or {@code null} if the AST
* does not correspond to an ITranslationUnit.
*
* @since 5.3
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTForStatement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTForStatement.java
index ae47d0d8b67..1b81285abbc 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTForStatement.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTForStatement.java
@@ -15,14 +15,16 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
/**
- *
+ * The C++ 'for' statement.
+ *
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface ICPPASTForStatement extends IASTForStatement {
-
- public static final ASTNodeProperty CONDITION_DECLARATION = new ASTNodeProperty( "org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement"); //$NON-NLS-1$
- public void setConditionDeclaration( IASTDeclaration d );
+ public static final ASTNodeProperty CONDITION_DECLARATION =
+ new ASTNodeProperty("org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement"); //$NON-NLS-1$
+
+ public void setConditionDeclaration(IASTDeclaration d);
public IASTDeclaration getConditionDeclaration();
/**
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPEnumeration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPEnumeration.java
index 22225a116aa..b3bff980948 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPEnumeration.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPEnumeration.java
@@ -28,7 +28,7 @@ public interface ICPPEnumeration extends IEnumeration, ICPPBinding {
boolean isScoped();
/**
- * Returns the underlying type of the enumeration if it is fixed, or null otherwise.
+ * Returns the underlying type of the enumeration if it is fixed, or {@code null} otherwise.
* The underlying type can only be fixed in C++.
*/
IType getFixedType();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayUtils.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayUtils.java
index 330878bb36c..6307942c555 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayUtils.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/CharArrayUtils.java
@@ -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;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java
index 17e83bb272a..b6b9281b02c 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java
@@ -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;
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLinkageSpecification.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLinkageSpecification.java
index 7a5b2a3c690..370ef687b8d 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLinkageSpecification.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLinkageSpecification.java
@@ -6,7 +6,7 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * John Camelon (IBM) - Initial API and implementation
+ * John Camelon (IBM) - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@@ -22,13 +22,12 @@ import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
/**
* Extern "C" construct.
*/
-public class CPPASTLinkageSpecification extends ASTNode implements
- ICPPASTLinkageSpecification, IASTAmbiguityParent {
-
+public class CPPASTLinkageSpecification extends ASTNode
+ implements ICPPASTLinkageSpecification, IASTAmbiguityParent {
private String fLiteral;
private IASTDeclaration[] fAllDeclarations;
private IASTDeclaration[] fActiveDeclarations;
- private int fLastDeclaration=-1;
+ private int fLastDeclaration = -1;
public CPPASTLinkageSpecification() {
}
@@ -45,13 +44,10 @@ public class CPPASTLinkageSpecification extends ASTNode implements
@Override
public CPPASTLinkageSpecification copy(CopyStyle style) {
CPPASTLinkageSpecification copy = new CPPASTLinkageSpecification(fLiteral);
- for (IASTDeclaration declaration : getDeclarations())
+ for (IASTDeclaration declaration : getDeclarations()) {
copy.addDeclaration(declaration == null ? null : declaration.copy(style));
- copy.setOffsetAndLength(this);
- if (style == CopyStyle.withLocations) {
- copy.setCopyLocation(this);
}
- return copy;
+ return copy(copy, style);
}
@Override
@@ -70,7 +66,7 @@ public class CPPASTLinkageSpecification extends ASTNode implements
if (decl != null) {
decl.setParent(this);
decl.setPropertyInParent(OWNED_DECLARATION);
- fAllDeclarations = ArrayUtil.appendAt( IASTDeclaration.class, fAllDeclarations, ++fLastDeclaration, decl);
+ fAllDeclarations = ArrayUtil.appendAt(IASTDeclaration.class, fAllDeclarations, ++fLastDeclaration, decl);
fActiveDeclarations= null;
}
}
@@ -99,9 +95,9 @@ public class CPPASTLinkageSpecification extends ASTNode implements
public boolean accept(ASTVisitor action) {
if (action.shouldVisitDeclarations) {
switch (action.visit(this)) {
- case ASTVisitor.PROCESS_ABORT : return false;
- case ASTVisitor.PROCESS_SKIP : return true;
- default : break;
+ case ASTVisitor.PROCESS_ABORT: return false;
+ case ASTVisitor.PROCESS_SKIP: return true;
+ default: break;
}
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenter.java
index 30dc0f59346..f78c870b83f 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2009 Institute for Software, HSR Hochschule fuer Technik
+ * Copyright (c) 2008, 2013 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -7,7 +7,8 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Institute for Software - initial API and implementation
+ * Institute for Software - initial API and implementation
+ * Sergey Prigogin (Google)
******************************************************************************/
package org.eclipse.cdt.internal.core.dom.rewrite.commenthandler;
@@ -64,7 +65,7 @@ public class ASTCommenter {
}
private int checkOffsets(IASTNode node) {
- int offset = ((ASTNode)node).getOffset();
+ int offset = ((ASTNode) node).getOffset();
int status = PROCESS_CONTINUE;
if (isCommentOnSameLine(node)
@@ -82,8 +83,8 @@ public class ASTCommenter {
}
private boolean isCommentOnSameLine(IASTNode node) {
- return commentNodeLocation.getStartingLineNumber() == node.getFileLocation()
- .getEndingLineNumber();
+ return commentNodeLocation.getStartingLineNumber() ==
+ node.getFileLocation().getEndingLineNumber();
}
@Override
@@ -168,41 +169,29 @@ public class ASTCommenter {
}
/**
- * Creates a NodeCommentMap for the given TranslationUnit. This is the only way
- * to get a NodeCommentMap which contains all the comments mapped against nodes.
+ * Creates a NodeCommentMap for the given AST. This is the only way to get a NodeCommentMap
+ * which contains all the comments mapped against nodes.
*
- * @param tu TranslationUnit
+ * @param ast the AST
* @return NodeCommentMap
*/
- public static NodeCommentMap getCommentedNodeMap(IASTTranslationUnit tu){
+ public static NodeCommentMap getCommentedNodeMap(IASTTranslationUnit ast) {
NodeCommentMap commentMap = new NodeCommentMap();
- if (tu == null) {
+ if (ast == null) {
return commentMap;
}
- IASTComment[] commentsArray = tu.getComments();
- if (commentsArray == null) {
- return commentMap;
- }
- // Note that constructing a real ArrayList is required here, since in filterNonTuComments, the
- // remove-method will be invoked on the list's iterator. Calling it on the type Arrays$ArrayList (the
- // resulting type of Arrays.asList() ) would throw a UnsupportedOperationException.
- ArrayList comments = new ArrayList(Arrays.asList(commentsArray));
- filterNonTuComments(comments);
- return addCommentsToCommentMap(tu, comments);
- }
-
- /**
- * Note that passing an ArrayList (instead of just List or Collection) is required here, since this
- * guarantees that the call to the remove-method on the list's iterator will not result in an
- * UnsupportedOperationException which might be the case for other Collection/List types.
- */
- private static void filterNonTuComments(ArrayList comments) {
- Iterator iterator = comments.iterator();
- while (iterator.hasNext()) {
- if (!iterator.next().isPartOfTranslationUnitFile()) {
- iterator.remove();
+ IASTComment[] commentsArray = ast.getComments();
+ List comments = new ArrayList(commentsArray.length);
+ for (IASTComment comment : commentsArray) {
+ if (comment.isPartOfTranslationUnitFile()) {
+ comments.add(comment);
}
}
+ assignPreprocessorComments(commentMap, comments, ast);
+ CommentHandler commentHandler = new CommentHandler(comments);
+ ASTCommenterVisitor commenter = new ASTCommenterVisitor(commentHandler, commentMap);
+ ast.accept(commenter);
+ return commentMap;
}
private static boolean isCommentDirectlyBeforePreprocessorStatement(IASTComment comment,
@@ -211,11 +200,11 @@ public class ASTCommenter {
return true;
}
IASTFileLocation commentLocation = comment.getFileLocation();
- int preprcessorOffset = statement.getFileLocation().getNodeOffset();
- if (preprcessorOffset > commentLocation.getNodeOffset()) {
- PreprocessorRangeChecker vister = new PreprocessorRangeChecker(preprcessorOffset, commentLocation);
- tu.accept(vister);
- return vister.isPreStatementComment;
+ int preprocessorOffset = statement.getFileLocation().getNodeOffset();
+ if (preprocessorOffset > commentLocation.getNodeOffset()) {
+ PreprocessorRangeChecker visitor = new PreprocessorRangeChecker(preprocessorOffset, commentLocation);
+ tu.accept(visitor);
+ return visitor.isPreStatementComment;
}
return false;
}
@@ -224,24 +213,12 @@ public class ASTCommenter {
return node.isPartOfTranslationUnitFile();
}
- private static NodeCommentMap addCommentsToCommentMap(IASTTranslationUnit tu,
- ArrayList comments){
- NodeCommentMap commentMap = new NodeCommentMap();
- CommentHandler commHandler = new CommentHandler(comments);
-
- assignPreprocessorComments(commentMap, comments, tu);
- ASTCommenterVisitor commenter = new ASTCommenterVisitor(commHandler, commentMap);
- tu.accept(commenter);
- return commentMap;
- }
-
/**
- * Note that passing an ArrayList (instead of just List or Collection) is required here, since this
- * guarantees that the call to the remove-method on the list's iterator will not result in an
- * UnsupportedOperationException which might be the case for other Collection/List types.
+ * Puts leading and trailing comments to {@code commentMap} and removes them from
+ * the {@code comments} list.
*/
private static void assignPreprocessorComments(NodeCommentMap commentMap,
- ArrayList comments, IASTTranslationUnit tu) {
+ List comments, IASTTranslationUnit tu) {
IASTPreprocessorStatement[] preprocessorStatementsArray = tu.getAllPreprocessorStatements();
if (preprocessorStatementsArray == null) {
return;
@@ -252,6 +229,7 @@ public class ASTCommenter {
return;
}
+ List freestandingComments = new ArrayList(comments.size());
Iterator statementsIter = preprocessorStatements.iterator();
Iterator commentIter = comments.iterator();
IASTPreprocessorStatement curStatement = getNextNodeInTu(statementsIter);
@@ -261,18 +239,26 @@ public class ASTCommenter {
int commentLineNr = curComment.getFileLocation().getStartingLineNumber();
if (commentLineNr == statementLineNr) {
commentMap.addTrailingCommentToNode(curStatement, curComment);
- commentIter.remove();
curComment = getNextNodeInTu(commentIter);
} else if (commentLineNr > statementLineNr) {
curStatement = getNextNodeInTu(statementsIter);
} else if (isCommentDirectlyBeforePreprocessorStatement(curComment, curStatement, tu)) {
commentMap.addLeadingCommentToNode(curStatement, curComment);
- commentIter.remove();
curComment = getNextNodeInTu(commentIter);
} else {
+ freestandingComments.add(curComment);
curComment = getNextNodeInTu(commentIter);
}
}
+ while (curComment != null) {
+ freestandingComments.add(curComment);
+ curComment = getNextNodeInTu(commentIter);
+ }
+
+ if (freestandingComments.size() != comments.size()) {
+ comments.clear();
+ comments.addAll(freestandingComments);
+ }
}
private static T getNextNodeInTu(Iterator iter) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenterVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenterVisitor.java
index a8a97e9dbb8..030b99f16d5 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenterVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenterVisitor.java
@@ -39,7 +39,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTCompositeTypeSpecifier
* @author Guido Zgraggen IFS
*/
public class ASTCommenterVisitor extends ASTVisitor {
- protected CommentHandler commHandler;
+ protected CommentHandler commentHandler;
protected NodeCommentMap commentMap;
private NodeCommenter nodeCommenter;
@@ -61,14 +61,14 @@ public class ASTCommenterVisitor extends ASTVisitor {
shouldVisitTranslationUnit = true;
}
- public ASTCommenterVisitor(CommentHandler commHandler, NodeCommentMap commentMap) {
- this.commHandler = commHandler;
+ public ASTCommenterVisitor(CommentHandler commentHandler, NodeCommentMap commentMap) {
+ this.commentHandler = commentHandler;
this.commentMap = commentMap;
init();
}
private void init() {
- nodeCommenter = new NodeCommenter(this, commHandler, commentMap);
+ nodeCommenter = new NodeCommenter(this, commentHandler, commentMap);
}
@Override
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommenter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommenter.java
index ec0d9f9afc8..589a67b2510 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommenter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommenter.java
@@ -62,13 +62,13 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTWhileStatement;
*/
public class NodeCommenter {
protected ASTVisitor visitor;
- protected CommentHandler commHandler;
+ protected CommentHandler commentHandler;
protected NodeCommentMap commentMap;
protected List children;
public NodeCommenter(ASTVisitor visitor, CommentHandler commHandler, NodeCommentMap commentMap) {
this.visitor = visitor;
- this.commHandler = commHandler;
+ this.commentHandler = commHandler;
this.commentMap = commentMap;
this.children = new ArrayList();
}
@@ -122,17 +122,17 @@ public class NodeCommenter {
private void addLeadingCommentToMap(ASTNode node, IASTComment comment) {
commentMap.addLeadingCommentToNode(node, comment);
- commHandler.allreadyAdded(comment);
+ commentHandler.allreadyAdded(comment);
}
private void addTrailingCommentToMap(ASTNode node, IASTComment comment) {
commentMap.addTrailingCommentToNode(node, comment);
- commHandler.allreadyAdded(comment);
+ commentHandler.allreadyAdded(comment);
}
private void addFreestandingCommentToMap(ASTNode node, IASTComment comment) {
commentMap.addFreestandingCommentToNode(node, comment);
- commHandler.allreadyAdded(comment);
+ commentHandler.allreadyAdded(comment);
}
private boolean isTrailing(ASTNode node, ASTNode com, int nodeLineNumber, int commentLineNumber) {
@@ -200,8 +200,8 @@ public class NodeCommenter {
}
protected int appendComments(ASTNode node) {
- while (commHandler.hasMore()) {
- IASTComment comment = commHandler.getFirst();
+ while (commentHandler.hasMore()) {
+ IASTComment comment = commentHandler.getFirst();
if (isNotSameFile(node, comment)) {
return ASTVisitor.PROCESS_SKIP;
@@ -215,8 +215,8 @@ public class NodeCommenter {
}
protected int appendFreestandingComments(ASTNode node) {
- while (commHandler.hasMore()) {
- IASTComment comment = commHandler.getFirst();
+ while (commentHandler.hasMore()) {
+ IASTComment comment = commentHandler.getFirst();
if (isNotSameFile(node, comment)) {
return ASTVisitor.PROCESS_SKIP;
@@ -234,9 +234,9 @@ public class NodeCommenter {
}
public void appendRemainingComments(IASTDeclaration declaration) {
- while (commHandler.hasMore()) {
- IASTComment comment = commHandler.getFirst();
- if (appendComment((ASTNode)declaration, comment)) {
+ while (commentHandler.hasMore()) {
+ IASTComment comment = commentHandler.getFirst();
+ if (appendComment((ASTNode) declaration, comment)) {
continue;
}
addFreestandingCommentToMap((ASTNode) declaration, comment);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java
index 43bc89e7012..993acd2402a 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java
@@ -113,6 +113,7 @@ abstract class ASTPreprocessorNode extends ASTNode {
class ASTComment extends ASTPreprocessorNode implements IASTComment {
private final boolean fIsBlockComment;
private String fFilePath;
+
public ASTComment(IASTTranslationUnit parent, String filePath, int offset, int endOffset, boolean isBlockComment) {
super(parent, IASTTranslationUnit.PREPROCESSOR_STATEMENT, offset, endOffset);
fIsBlockComment= isBlockComment;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
index 66382144eba..6d6518d4200 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java
@@ -68,8 +68,8 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
/**
- * C-Preprocessor providing tokens for the parsers. The class should not be used directly, rather than that
- * you should be using the {@link IScanner} interface.
+ * C-Preprocessor providing tokens for the parsers. The class should not be used directly,
+ * rather than that you should be using the {@link IScanner} interface.
* @since 5.0
*/
public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
@@ -87,8 +87,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
private static final char[] ONE = "1".toCharArray(); //$NON-NLS-1$
-
- // standard built-ins
+ // Standard built-ins
private static final ObjectStyleMacro __CDT_PARSER__= new ObjectStyleMacro("__CDT_PARSER__".toCharArray(), ONE); //$NON-NLS-1$
private static final ObjectStyleMacro __cplusplus = new ObjectStyleMacro("__cplusplus".toCharArray(), ONE); //$NON-NLS-1$
private static final ObjectStyleMacro __STDC__ = new ObjectStyleMacro("__STDC__".toCharArray(), ONE); //$NON-NLS-1$
@@ -374,7 +373,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
return fLocationMap;
}
- private void configureKeywords(ParserLanguage language, IScannerExtensionConfiguration configuration) {
+ private void configureKeywords(ParserLanguage language, IScannerExtensionConfiguration configuration) {
Keywords.addKeywordsPreprocessor(fPPKeywords);
if (language == ParserLanguage.C) {
Keywords.addKeywordsC(fKeywords);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeGuardDetection.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeGuardDetection.java
index 2674e80e36a..cdd034e83f8 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeGuardDetection.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeGuardDetection.java
@@ -6,9 +6,8 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Markus Schorn - initial API and implementation
+ * Markus Schorn - initial API and implementation
*******************************************************************************/
-
package org.eclipse.cdt.internal.core.parser.scanner;
import static org.eclipse.cdt.core.parser.OffsetLimitReachedException.ORIGIN_PREPROCESSOR_DIRECTIVE;
@@ -39,7 +38,7 @@ public class IncludeGuardDetection {
Token t = l.nextToken();
if (t.getType() == IToken.tIDENTIFIER) {
char[] guard= null;
- switch(ppKeywords.get(t.getCharImage())) {
+ switch (ppKeywords.get(t.getCharImage())) {
case IPreprocessorDirective.ppIfndef:
// #ifndef GUARD
t= l.nextToken();
@@ -98,7 +97,7 @@ public class IncludeGuardDetection {
Token t= l.nextDirective();
if (t.getType() == IToken.tEND_OF_INPUT)
return true;
- switch(ppKeywords.get(l.nextToken().getCharImage())) {
+ switch (ppKeywords.get(l.nextToken().getCharImage())) {
case IPreprocessorDirective.ppIf:
case IPreprocessorDirective.ppIfdef:
case IPreprocessorDirective.ppIfndef:
@@ -124,7 +123,6 @@ public class IncludeGuardDetection {
return t;
}
-
public static boolean detectIncludeEndif(Lexer l) {
l.saveState();
try {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeSearchPathElement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeSearchPathElement.java
index 458dbc3f632..8c397858cf4 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeSearchPathElement.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeSearchPathElement.java
@@ -7,11 +7,16 @@
*
* Contributors:
* Markus Schorn - initial API and implementation
+ * Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
import java.io.File;
+import org.eclipse.cdt.utils.PathUtil;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
/**
* Represents an entry of the include search path
*/
@@ -42,14 +47,14 @@ public final class IncludeSearchPathElement {
public String getLocation(String includeDirective) {
if (fIsFrameworkDirectory) {
int firstSep = firstSeparator(includeDirective);
- if (firstSep < 1) {
+ if (firstSep <= 0) {
return null;
}
String framework = includeDirective.substring(0, firstSep);
String file= includeDirective.substring(firstSep + 1);
if (file.length() == 0)
return null;
-
+
StringBuilder buf= new StringBuilder(fPath);
replace(buf, FRAMEWORK_VAR, framework);
replace(buf, FILE_VAR, file);
@@ -58,6 +63,42 @@ public final class IncludeSearchPathElement {
return ScannerUtility.createReconciledPath(fPath, includeDirective);
}
+ /**
+ * Returns the include directive for the given location satisfying the condition
+ * {@code getLocation(getIncludeDirective(location) == location}. If no such include directive
+ * without ".." exists, returns {@code null}.
+ */
+ public String getIncludeDirective(String location) {
+ IPath dirPath = new Path(fPath);
+ IPath locationPath = new Path(location);
+ if (fIsFrameworkDirectory) {
+ if (dirPath.segmentCount() != locationPath.segmentCount())
+ return null;
+ int i = PathUtil.matchingFirstSegments(dirPath, locationPath);
+ String dirSegment = dirPath.segment(i);
+ String locationSegment = locationPath.segment(i);
+ String framework = deduceVariable(FRAMEWORK_VAR, dirSegment, locationSegment);
+ if (framework == null)
+ return null;
+ i++;
+ dirPath = dirPath.removeFirstSegments(i);
+ locationPath = locationPath.removeFirstSegments(i);
+ i = PathUtil.matchingFirstSegments(dirPath, locationPath);
+ if (i < dirPath.segmentCount() - 1)
+ return null;
+ dirSegment = dirPath.segment(i);
+ locationSegment = locationPath.segment(i);
+ String file = deduceVariable(FILE_VAR, dirSegment, locationSegment);
+ if (file == null)
+ return null;
+ return framework + '/' + file;
+ }
+
+ if (!PathUtil.isPrefix(dirPath, locationPath))
+ return null;
+ return locationPath.removeFirstSegments(dirPath.segmentCount()).setDevice(null).toPortableString();
+ }
+
private int firstSeparator(String path) {
int firstSep= path.indexOf('/');
if (NON_SLASH_SEPARATOR) {
@@ -73,6 +114,20 @@ public final class IncludeSearchPathElement {
}
}
+ private String deduceVariable(String varName, String raw, String substituted) {
+ int pos = raw.indexOf(varName);
+ if (pos < 0)
+ return null;
+ int suffixLength = raw.length() - pos - varName.length();
+ if (substituted.length() <= pos + suffixLength)
+ return null;
+ for (int i = 0; i < suffixLength; i++) {
+ if (raw.charAt(raw.length() - i) != substituted.charAt(substituted.length() - i))
+ return null;
+ }
+ return substituted.substring(pos, substituted.length() - suffixLength);
+ }
+
/**
* For debugging only.
*/
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTestBase.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTestBase.java
index e1836964b4f..70109e01c1b 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTestBase.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTestBase.java
@@ -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());
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTestSuite.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTestSuite.java
index 3969debfd10..496e5c0bca4 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTestSuite.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTestSuite.java
@@ -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;
}
}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionRefactoringTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionRefactoringTest.java
index 4446a6de752..76a7edcea93 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionRefactoringTest.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionRefactoringTest.java
@@ -1,11 +1,11 @@
/*******************************************************************************
* Rapperswil, University of applied sciences 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:
+ * 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:
* Institute for Software - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
@@ -181,7 +181,6 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
assertRefactoringSuccess();
}
-
//A.h
//#ifndef A_H_
//#define A_H_
@@ -308,7 +307,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
public void testLocalVariableDeclaration_3() throws Exception {
assertRefactoringSuccess();
}
-
+
//A.h
//#ifndef A_H_
//#define A_H_
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/BindingClassifierTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/BindingClassifierTest.java
new file mode 100644
index 00000000000..c9329d20606
--- /dev/null
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/BindingClassifierTest.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * 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
+ * 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.ArrayList;
+import java.util.Arrays;
+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;
+import org.eclipse.cdt.core.index.IIndex;
+import org.eclipse.cdt.core.index.IIndexManager;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.core.testplugin.util.OneSourceMultipleHeadersTestCase;
+import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
+import org.eclipse.cdt.ui.testplugin.CTestPlugin;
+
+import org.eclipse.cdt.internal.ui.refactoring.includes.BindingClassifier;
+import org.eclipse.cdt.internal.ui.refactoring.includes.InclusionContext;
+
+public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
+ private IIndex fIndex;
+ private InclusionContext fContext;
+ private BindingClassifier fBindingClassifier;
+
+ public BindingClassifierTest() {
+ super(new TestSourceReader(CTestPlugin.getDefault().getBundle(), "ui", BindingClassifierTest.class), true);
+ }
+
+ public static TestSuite suite() {
+ return suite(BindingClassifierTest.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ IASTTranslationUnit ast = getAst();
+ fIndex = CCorePlugin.getIndexManager().getIndex(getCProject(),
+ IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_EXTENSION_FRAGMENTS_ADD_IMPORT);
+ fIndex.acquireReadLock();
+ ITranslationUnit tu = ast.getOriginatingTranslationUnit();
+ fContext = new InclusionContext(tu, fIndex);
+ fBindingClassifier = new BindingClassifier(fContext);
+ fBindingClassifier.classifyNodeContents(ast);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ fIndex.releaseReadLock();
+ super.tearDown();
+ }
+
+ private void assertDefined(String... names) {
+ assertExpectedBindings(names, fBindingClassifier.getBindingsToDefine(), "defined");
+ }
+
+ private void assertDeclared(String... names) {
+ assertExpectedBindings(names, fBindingClassifier.getBindingsToDeclare(), "declared");
+ }
+
+ private void assertExpectedBindings(String[] expectedNames, Set bindings, String verb) {
+ Set expected = new TreeSet(Arrays.asList(expectedNames));
+ Set extra = new TreeSet();
+ for (IBinding binding : bindings) {
+ extra.add(binding.getName());
+ }
+ Set missing = new TreeSet(expected);
+ missing.removeAll(extra);
+ extra.removeAll(expected);
+ if (extra.isEmpty() && missing.isEmpty())
+ return;
+ List errors = new ArrayList(2);
+ if (!missing.isEmpty()) {
+ errors.add(MessageFormat.format("{0,choice,1#Binding|1 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;
+ // typedef A* td1;
+ // typedef td1* td2;
+ // td2 f();
+
+ // A* a = *f();
+ public void testTypedef_1() throws Exception {
+ assertDefined("f");
+ assertDeclared("A");
+ }
+
+ // class A;
+ // typedef A* td1;
+ // typedef td1* td2;
+ // td2 f();
+
+ // td1 a = *f();
+ public void testTypedef_2() throws Exception {
+ assertDefined("f", "td1");
+ }
+
+ // class A { int x; };
+ // typedef A* td;
+ // td f();
+
+ // int a = f()->x;
+ 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.
+ }
+}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludesTestBase.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludesTestBase.java
new file mode 100644
index 00000000000..e4594327976
--- /dev/null
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludesTestBase.java
@@ -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 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 testFiles = new LinkedHashSet();
+
+ 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();
+ }
+}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludesTestSuite.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludesTestSuite.java
new file mode 100644
index 00000000000..cb49b4da418
--- /dev/null
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludesTestSuite.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * 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 junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class IncludesTestSuite extends TestSuite {
+
+ public static Test suite() throws Exception {
+ IncludesTestSuite suite = new IncludesTestSuite();
+ suite.addTest(BindingClassifierTest.suite());
+ suite.addTest(OrganizeIncludesTest.suite());
+ return suite;
+ }
+}
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/OrganizeIncludesTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/OrganizeIncludesTest.java
new file mode 100644
index 00000000000..50fa7d63d68
--- /dev/null
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/OrganizeIncludesTest.java
@@ -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 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 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 {};
+ //} // 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 {};
+ //} // 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();
+ }
+}
\ No newline at end of file
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/utils/DefinitionFinderTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/utils/DefinitionFinderTest.java
index 7d9ff572f11..4d08478705d 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/utils/DefinitionFinderTest.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/utils/DefinitionFinderTest.java
@@ -88,7 +88,7 @@ public class DefinitionFinderTest extends RefactoringTestBase {
for (IASTDeclaration declaration : ast.getDeclarations()) {
if (declaration instanceof IASTSimpleDeclaration) {
IASTName name = ((IASTSimpleDeclaration) declaration).getDeclarators()[0].getName();
- assertNotNull(DefinitionFinder.getDefinition(name, refactoringContext, NULL_PROGRESS_MONITOR));
+ assertNotNull(DefinitionFinder.getDefinition(name, refactoringContext, npm()));
}
}
} finally {
diff --git a/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF
index eb9c2d464a2..f06ce79399a 100644
--- a/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF
+++ b/core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF
@@ -42,6 +42,7 @@ Export-Package: org.eclipse.cdt.internal.corext;x-internal:=true,
org.eclipse.cdt.internal.ui.refactoring.gettersandsetters;x-friends:="org.eclipse.cdt.ui.tests",
org.eclipse.cdt.internal.ui.refactoring.hidemethod;x-friends:="org.eclipse.cdt.ui.tests",
org.eclipse.cdt.internal.ui.refactoring.implementmethod;x-friends:="org.eclipse.cdt.ui.tests",
+ org.eclipse.cdt.internal.ui.refactoring.includes;x-friends:="org.eclipse.cdt.ui.tests",
org.eclipse.cdt.internal.ui.refactoring.rename;x-friends:="org.eclipse.cdt.ui.tests",
org.eclipse.cdt.internal.ui.refactoring.togglefunction;x-friends:="org.eclipse.cdt.ui.tests",
org.eclipse.cdt.internal.ui.refactoring.utils;x-friends:="org.eclipse.cdt.ui.tests",
diff --git a/core/org.eclipse.cdt.ui/plugin.properties b/core/org.eclipse.cdt.ui/plugin.properties
index 18028baf180..5cdafd68387 100644
--- a/core/org.eclipse.cdt.ui/plugin.properties
+++ b/core/org.eclipse.cdt.ui/plugin.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2003, 2012 IBM Corporation, QNX Software Systems, and others.
+# Copyright (c) 2003, 2013 IBM Corporation, QNX Software Systems, 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
@@ -196,6 +196,8 @@ CPluginFileTypesPreferencePage.name=File Types
CodeStylePreferencePage.name=Code Style
codeTemplatePreferencePage.name=Code Templates
codeFormatterPreferencePage.name=Formatter
+includeStylePreferencePage.name=Include Style
+organizeIncludesPreferencePage.name=Organize Includes
nameStylePreferencePage.name=Name Style
CodeAssistPreferencePage.name=Content Assist
CodeAssistAdvancedPreferencePage.name=Advanced
@@ -274,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
@@ -566,7 +572,9 @@ preferenceKeywords.common=c cpp cplusplus cdt
preferenceKeywords.codeformatter=profile codestyle project specific comment indentation brace white space blank line new control statement wrapping tab parenthesis bracket
preferenceKeywords.codestyle=class member visibility order ordering
preferenceKeywords.codetemplates=comment code constructor method file type content
-preferenceKeywords.namestyle=name file getter setter field variable
+preferenceKeywords.namestyle=name style file getter setter field variable
+preferenceKeywords.includestyle=include includes style partner system header file system
+preferenceKeywords.organizeincludes=include includes organize
preferenceKeywords.todo=case sensitive task tag todo xxx fix fixme project comments
preferenceKeywords.indexer=index skip references type macro search build configuration cache memory performance
@@ -589,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
diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml
index f5655de04b1..901b156a59f 100644
--- a/core/org.eclipse.cdt.ui/plugin.xml
+++ b/core/org.eclipse.cdt.ui/plugin.xml
@@ -1232,6 +1232,22 @@
+
+
+
+
+
+
+
+
+
+
@@ -1862,6 +1884,13 @@
menubarPath="org.eclipse.jdt.ui.source.menu/importGroup"
id="org.eclipse.cdt.ui.actions.SortLines">
+
+
+
+
+
+
@@ -4606,6 +4647,9 @@
+
+
+
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/BusyCursorJobRunner.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/BusyCursorJobRunner.java
new file mode 100644
index 00000000000..5c4545bca92
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/BusyCursorJobRunner.java
@@ -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() {}
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICHelpContextIds.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICHelpContextIds.java
index fd83696f119..a142be73da1 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICHelpContextIds.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICHelpContextIds.java
@@ -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;
*
* This interface contains constants only; it is not intended to be implemented or extended.
*
- *
*/
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$
@@ -87,6 +88,8 @@ public interface ICHelpContextIds {
public static final String SPELLING_CONFIGURATION_BLOCK= PREFIX + "spelling_configuration_block_context"; //$NON-NLS-1$
public static final String CODE_STYLE_PREFERENCE_PAGE = PREFIX + "code_style_preference_context"; //$NON-NLS-1$
public static final String CODE_TEMPLATES_PREFERENCE_PAGE = PREFIX + "code_templates_preference_context"; //$NON-NLS-1$
+ public static final String INCLUDE_STYLE_PREFERENCE_PAGE = PREFIX + "include_style_preference_context"; //$NON-NLS-1$
+ public static final String ORGANIZE_INCLUDES_PREFERENCE_PAGE = PREFIX + "organize_includes_preference_context"; //$NON-NLS-1$
public static final String NAME_STYLE_PREFERENCE_PAGE = PREFIX + "name_style_preference_context"; //$NON-NLS-1$
// Console view
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java
index 1338d9d257a..4894e4aa2c8 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorActionContributor.java
@@ -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);
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java
index 9c27d36db58..5d0e53a8d03 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java
@@ -36,6 +36,15 @@ public final class CEditorMessages extends NLS {
public static String AddIncludeOnSelection_insertion_failed;
public static String AddIncludeOnSelection_help_provider_error;
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;
public static String ShowInCView_tooltip;
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties
index c189c20f1a1..62aa9c4416e 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties
@@ -1,5 +1,5 @@
#########################################
-# Copyright (c) 2005, 2011 IBM Corporation and others.
+# Copyright (c) 2005, 2012 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
@@ -12,6 +12,7 @@
# Markus Schorn (Wind River Systems)
# Sergey Prigogin (Google)
# Tomasz Wesolowski
+# Mathias Kunter
#########################################
AddIncludeOnSelection_label=Add Include
@@ -21,6 +22,16 @@ AddIncludeOnSelection_insertion_failed=Adding include statements failed
AddIncludeOnSelection_help_provider_error=Help provider error
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
ShowInCView_label=Show in C/C++ Projects
ShowInCView_tooltip=Show current resource in C/C++ Projects view
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties
index d020935426b..bd462477db4 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties
@@ -18,6 +18,10 @@ AddIncludeOnSelection.label=A&dd Include
AddIncludeOnSelection.description=Add include statement for selected name
AddIncludeOnSelection.tooltip=Adds an include statement for selected name
+OrganizeIncludes.label=Or&ganize Includes
+OrganizeIncludes.tooltip=Evaluate All Required Includes and Replace the Current Ones
+OrganizeIncludes.description=Evaluates all required includes and replaces the current ones
+
SortLines.label=Sort Lines
SortLines.tooltip=Sort Selected Lines Alphabetically
SortLines.description=Sorts selected lines alphabetically
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java
index 33fd516ea1f..9808ef10801 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ICEditorActionDefinitionIds.java
@@ -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 "org.eclipse.cdt.ui.edit.text.c.organize.includes").
+ */
+ 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 "org.eclipse.cdt.ui.edit.opendecl").
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InteractiveHeaderChooser.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InteractiveHeaderChooser.java
new file mode 100644
index 00000000000..4adcddebc56
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/InteractiveHeaderChooser.java
@@ -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, IPath> userChoiceCache;
+
+ public InteractiveHeaderChooser(Shell shell) {
+ this.shell = shell;
+ userChoiceCache = new HashMap, IPath>();
+ }
+
+ @Override
+ public IPath chooseHeader(final String bindingName, Collection headers) {
+ if (headers.isEmpty())
+ return null;
+ if (headers.size() == 1)
+ return headers.iterator().next();
+
+ Set cacheKey = new HashSet(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);
+ }
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/OrganizeIncludesAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/OrganizeIncludesAction.java
new file mode 100644
index 00000000000..72dcc7d6c5e
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/OrganizeIncludesAction.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Mathias Kunter 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:
+ * 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;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.index.IIndex;
+import org.eclipse.cdt.core.index.IIndexManager;
+import org.eclipse.cdt.core.model.ILanguage;
+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;
+
+/**
+ * Organizes the include directives and forward declarations of a source or header file.
+ */
+public class OrganizeIncludesAction extends TextEditorAction {
+ /**
+ * Constructor
+ * @param editor The editor on which this organize includes action should operate.
+ */
+ public OrganizeIncludesAction(ITextEditor editor) {
+ super(CEditorMessages.getBundleForConstructedKeys(), "OrganizeIncludes.", editor); //$NON-NLS-1$
+ 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 edits = new ArrayList();
+ 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);
+ }
+
+ /**
+ * Returns the translation unit of the given editor.
+ * @param editor The editor.
+ * @return The translation unit.
+ */
+ private static ITranslationUnit getTranslationUnit(ITextEditor editor) {
+ if (editor == null) {
+ return null;
+ }
+ return CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editor.getEditorInput());
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/IncludeCategoriesBlock.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/IncludeCategoriesBlock.java
new file mode 100644
index 00000000000..70aa8b24166
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/IncludeCategoriesBlock.java
@@ -0,0 +1,293 @@
+/*******************************************************************************
+ * 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.preferences;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jface.layout.PixelConverter;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
+
+import org.eclipse.cdt.internal.ui.dialogs.IStatusChangeListener;
+import org.eclipse.cdt.internal.ui.dialogs.StatusInfo;
+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.wizards.dialogfields.DialogField;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.ITreeListAdapter;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.TreeListDialogField;
+
+/**
+ * The preference block for configuring styles of different categories of include statements.
+ */
+public class IncludeCategoriesBlock extends OptionsConfigurationBlock {
+ private final List styles;
+ private final Map categories = new HashMap();
+ private TreeListDialogField categoryTree;
+ private PixelConverter pixelConverter;
+ private StackLayout editorAreaStack;
+ private Category selectedCategory;
+
+ public IncludeCategoriesBlock(IStatusChangeListener context, IProject project,
+ IWorkbenchPreferenceContainer container, List styles) {
+ super(context, project, new Key[0], container);
+ this.styles = styles;
+ createCategories();
+ }
+
+ private void createCategories() {
+ createCategory(IncludeKind.RELATED);
+ createCategory(IncludeKind.PARTNER);
+ createCategory(IncludeKind.IN_SAME_FOLDER);
+ createCategory(IncludeKind.IN_SUBFOLDER);
+ createCategory(IncludeKind.SYSTEM);
+ createCategory(IncludeKind.SYSTEM_WITH_EXTENSION);
+ createCategory(IncludeKind.SYSTEM_WITHOUT_EXTENSION);
+ createCategory(IncludeKind.OTHER);
+ createCategory(IncludeKind.IN_SAME_PROJECT);
+ createCategory(IncludeKind.IN_OTHER_PROJECT);
+ createCategory(IncludeKind.EXTERNAL);
+ }
+
+ private Category createCategory(IncludeKind includeKind) {
+ Category parentCategory = categories.get(includeKind.parent);
+ Category category = new Category(includeKind, parentCategory);
+ categories.put(category.getIncludeKind(), category);
+ return category;
+ }
+
+ public void postSetSelection(Object element) {
+ categoryTree.postSetSelection(new StructuredSelection(element));
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ pixelConverter = new PixelConverter(parent);
+
+ setShell(parent.getShell());
+
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setFont(parent.getFont());
+
+ GridLayout layout = new GridLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ composite.setLayout(layout);
+
+ IncludeStyleAdapter adapter = new IncludeStyleAdapter();
+ categoryTree = new TreeListDialogField(adapter, null, new IncludeStyleLabelProvider());
+ categoryTree.setDialogFieldListener(adapter);
+ categoryTree.setLabelText(PreferencesMessages.IncludeCategoriesBlock_header_categories);
+ categoryTree.setViewerComparator(adapter);
+
+ for (Category category : categories.values()) {
+ if (category.parent == null)
+ categoryTree.addElement(category);
+ }
+
+ Label label = categoryTree.getLabelControl(composite);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false));
+
+ Control tree = categoryTree.getTreeControl(composite);
+ GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.widthHint = pixelConverter.convertWidthInCharsToPixels(50);
+ gd.heightHint = pixelConverter.convertHeightInCharsToPixels(2);
+ tree.setLayoutData(gd);
+
+ createCategoryEditors(composite);
+
+ categoryTree.setTreeExpansionLevel(2);
+ categoryTree.selectFirstElement();
+
+ updateControls();
+ return composite;
+ }
+
+ private void createCategoryEditors(Composite parent) {
+ Composite editorArea = new Composite(parent, SWT.NONE);
+ editorArea.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false));
+ editorArea.setFont(parent.getFont());
+ editorAreaStack = new StackLayout();
+ editorArea.setLayout(editorAreaStack);
+ Map stylesByKind = new HashMap();
+ for (IncludeGroupStyle style : styles) {
+ if (style.getIncludeKind() != IncludeKind.MATCHING_PATTERN)
+ stylesByKind.put(style.getIncludeKind(), style);
+ }
+
+ for (Category category : categories.values()) {
+ IncludeGroupStyleBlock block = new IncludeGroupStyleBlock(fContext, fProject, fContainer,
+ category.getDescription());
+ IncludeGroupStyle style = stylesByKind.get(category.getIncludeKind());
+ block.setStyle(style);
+ Control composite = block.createContents(editorArea);
+ category.setEditor(block, composite);
+ }
+ }
+
+ @Override
+ protected void updateControls() {
+ super.updateControls();
+ // Refresh
+ categoryTree.refresh();
+ updateConfigurationBlock(categoryTree.getSelectedElements());
+ for (Category category : categories.values()) {
+ category.getEditor().updateControls();
+ }
+ }
+
+ private void updateConfigurationBlock(List