mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 45203. Initial commit for Organize Includes feature.
This commit is contained in:
parent
53012d05af
commit
0a75ee2b57
20 changed files with 3644 additions and 14 deletions
|
@ -7,11 +7,16 @@
|
||||||
*
|
*
|
||||||
* Contributors:
|
* Contributors:
|
||||||
* Markus Schorn - initial API and implementation
|
* Markus Schorn - initial API and implementation
|
||||||
|
* Sergey Prigogin (Google)
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.internal.core.parser.scanner;
|
package org.eclipse.cdt.internal.core.parser.scanner;
|
||||||
|
|
||||||
import java.io.File;
|
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
|
* Represents an entry of the include search path
|
||||||
*/
|
*/
|
||||||
|
@ -42,14 +47,14 @@ public final class IncludeSearchPathElement {
|
||||||
public String getLocation(String includeDirective) {
|
public String getLocation(String includeDirective) {
|
||||||
if (fIsFrameworkDirectory) {
|
if (fIsFrameworkDirectory) {
|
||||||
int firstSep = firstSeparator(includeDirective);
|
int firstSep = firstSeparator(includeDirective);
|
||||||
if (firstSep < 1) {
|
if (firstSep <= 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String framework = includeDirective.substring(0, firstSep);
|
String framework = includeDirective.substring(0, firstSep);
|
||||||
String file= includeDirective.substring(firstSep + 1);
|
String file= includeDirective.substring(firstSep + 1);
|
||||||
if (file.length() == 0)
|
if (file.length() == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
StringBuilder buf= new StringBuilder(fPath);
|
StringBuilder buf= new StringBuilder(fPath);
|
||||||
replace(buf, FRAMEWORK_VAR, framework);
|
replace(buf, FRAMEWORK_VAR, framework);
|
||||||
replace(buf, FILE_VAR, file);
|
replace(buf, FILE_VAR, file);
|
||||||
|
@ -58,6 +63,42 @@ public final class IncludeSearchPathElement {
|
||||||
return ScannerUtility.createReconciledPath(fPath, includeDirective);
|
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) {
|
private int firstSeparator(String path) {
|
||||||
int firstSep= path.indexOf('/');
|
int firstSep= path.indexOf('/');
|
||||||
if (NON_SLASH_SEPARATOR) {
|
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.
|
* For debugging only.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2012 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.ui.tests.refactoring.includes;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
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, 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<IBinding> bindings, String verb) {
|
||||||
|
Set<String> remaining = new HashSet<String>(Arrays.asList(expectedNames));
|
||||||
|
for (IBinding binding : bindings) {
|
||||||
|
String name = binding.getName();
|
||||||
|
if (!remaining.remove(name)) {
|
||||||
|
fail("Binding \"" + name + "\" should not be " + verb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!remaining.isEmpty())
|
||||||
|
fail("Binding \"" + remaining.iterator().next() + "\" is not " + verb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.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.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.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.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.togglefunction;x-friends:="org.eclipse.cdt.ui.tests",
|
||||||
org.eclipse.cdt.internal.ui.refactoring.utils;x-friends:="org.eclipse.cdt.ui.tests",
|
org.eclipse.cdt.internal.ui.refactoring.utils;x-friends:="org.eclipse.cdt.ui.tests",
|
||||||
|
|
|
@ -36,6 +36,13 @@ public final class CEditorMessages extends NLS {
|
||||||
public static String AddIncludeOnSelection_insertion_failed;
|
public static String AddIncludeOnSelection_insertion_failed;
|
||||||
public static String AddIncludeOnSelection_help_provider_error;
|
public static String AddIncludeOnSelection_help_provider_error;
|
||||||
public static String AddIncludesOperation_description;
|
public static String AddIncludesOperation_description;
|
||||||
|
public static String OrganizeIncludes_label;
|
||||||
|
public static String OrganizeIncludes_description;
|
||||||
|
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 OrganizeIncludesOperation_description;
|
||||||
public static String ShowInCView_description;
|
public static String ShowInCView_description;
|
||||||
public static String ShowInCView_label;
|
public static String ShowInCView_label;
|
||||||
public static String ShowInCView_tooltip;
|
public static String ShowInCView_tooltip;
|
||||||
|
|
|
@ -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
|
# All rights reserved. This program and the accompanying materials
|
||||||
# are made available under the terms of the Eclipse Public License v1.0
|
# are made available under the terms of the Eclipse Public License v1.0
|
||||||
# which accompanies this distribution, and is available at
|
# which accompanies this distribution, and is available at
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
# Markus Schorn (Wind River Systems)
|
# Markus Schorn (Wind River Systems)
|
||||||
# Sergey Prigogin (Google)
|
# Sergey Prigogin (Google)
|
||||||
# Tomasz Wesolowski
|
# Tomasz Wesolowski
|
||||||
|
# Mathias Kunter
|
||||||
#########################################
|
#########################################
|
||||||
|
|
||||||
AddIncludeOnSelection_label=Add Include
|
AddIncludeOnSelection_label=Add Include
|
||||||
|
@ -21,6 +22,14 @@ AddIncludeOnSelection_insertion_failed=Adding include statements failed
|
||||||
AddIncludeOnSelection_help_provider_error=Help provider error
|
AddIncludeOnSelection_help_provider_error=Help provider error
|
||||||
AddIncludesOperation_description=Adding include statement
|
AddIncludesOperation_description=Adding include statement
|
||||||
|
|
||||||
|
OrganizeIncludes_label=Organize Includes
|
||||||
|
OrganizeIncludes_description=Organize includes for current file
|
||||||
|
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
|
||||||
|
OrganizeIncludesOperation_description=Organizing include statements
|
||||||
|
|
||||||
ShowInCView_description=Show the current resource in the C/C++ Projects view
|
ShowInCView_description=Show the current resource in the C/C++ Projects view
|
||||||
ShowInCView_label=Show in C/C++ Projects
|
ShowInCView_label=Show in C/C++ Projects
|
||||||
ShowInCView_tooltip=Show current resource in C/C++ Projects view
|
ShowInCView_tooltip=Show current resource in C/C++ Projects view
|
||||||
|
|
|
@ -18,6 +18,10 @@ AddIncludeOnSelection.label=A&dd Include
|
||||||
AddIncludeOnSelection.description=Add include statement for selected name
|
AddIncludeOnSelection.description=Add include statement for selected name
|
||||||
AddIncludeOnSelection.tooltip=Adds an 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.label=Sort Lines
|
||||||
SortLines.tooltip=Sort Selected Lines Alphabetically
|
SortLines.tooltip=Sort Selected Lines Alphabetically
|
||||||
SortLines.description=Sorts selected lines alphabetically
|
SortLines.description=Sorts selected lines alphabetically
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.editor;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
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.ICHelpContextIds;
|
||||||
|
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) {
|
||||||
|
// TODO Fix ID's
|
||||||
|
super(CEditorMessages.getBundleForConstructedKeys(), "OrganizeIncludes.", editor); //$NON-NLS-1$
|
||||||
|
CUIPlugin.getDefault().getWorkbench().getHelpSystem().setHelp(this, ICHelpContextIds.ADD_INCLUDE_ON_SELECTION_ACTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final ITextEditor editor = getTextEditor();
|
||||||
|
final ITranslationUnit tu = getTranslationUnit(editor);
|
||||||
|
if (tu == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (!validateEditorInputState()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedASTJob job = new SharedASTJob(CEditorMessages.OrganizeIncludes_label, tu) {
|
||||||
|
@Override
|
||||||
|
public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) throws CoreException {
|
||||||
|
IIndex index= CCorePlugin.getIndexManager().getIndex(tu.getCProject(),
|
||||||
|
IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_EXTENSION_FRAGMENTS_ADD_IMPORT);
|
||||||
|
try {
|
||||||
|
index.acquireReadLock();
|
||||||
|
IncludeOrganizer organizer = new IncludeOrganizer(editor, tu, index);
|
||||||
|
organizer.organizeIncludes(ast);
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return Status.CANCEL_STATUS;
|
||||||
|
} finally {
|
||||||
|
index.releaseReadLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
job.schedule();
|
||||||
|
job.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
ITextEditor editor = getTextEditor();
|
||||||
|
setEnabled(editor != null && getTranslationUnit(editor) != null);
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,713 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2012 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IFile;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.index.IIndexFile;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexInclude;
|
||||||
|
import org.eclipse.cdt.core.index.IndexLocationFactory;
|
||||||
|
import org.eclipse.cdt.ui.CUIPlugin;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
|
||||||
|
|
||||||
|
public class HeaderSubstitutor {
|
||||||
|
IncludeMap[] INCLUDE_MAPS = {
|
||||||
|
cIncludeMap, cIncludeMapWeak, cppIncludeMap, cppIncludeMapWeak,
|
||||||
|
google3IncludeMap, google3IncludeMapWeak
|
||||||
|
};
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
private static final IncludeMap symbolIncludeMap = new IncludeMap(false, false, new String[] {
|
||||||
|
"EOF", "<stdio.h>",
|
||||||
|
"EOF", "<libio.h>",
|
||||||
|
"NULL", "<stddef.h>",
|
||||||
|
"NULL", "<cstddef>",
|
||||||
|
"NULL", "<cstdio>",
|
||||||
|
"NULL", "<cstdlib>",
|
||||||
|
"NULL", "<cstring>",
|
||||||
|
"NULL", "<ctime>",
|
||||||
|
"NULL", "<cwchar>",
|
||||||
|
"NULL", "<locale.h>",
|
||||||
|
"NULL", "<stdio.h>",
|
||||||
|
"NULL", "<stdlib.h>",
|
||||||
|
"NULL", "<string.h>",
|
||||||
|
"NULL", "<time.h>",
|
||||||
|
"NULL", "<wchar.h>",
|
||||||
|
"blkcnt_t", "<sys/stat.h>",
|
||||||
|
"blkcnt_t", "<sys/types.h>",
|
||||||
|
"blksize_t", "<sys/types.h>",
|
||||||
|
"blksize_t", "<sys/stat.h>",
|
||||||
|
"calloc", "<stdlib.h>",
|
||||||
|
"daddr_t", "<sys/types.h>",
|
||||||
|
"daddr_t", "<rpc/types.h>",
|
||||||
|
"dev_t", "<sys/types.h>",
|
||||||
|
"dev_t", "<sys/stat.h>",
|
||||||
|
"error_t", "<errno.h>",
|
||||||
|
"error_t", "<argp.h>",
|
||||||
|
"error_t", "<argz.h>",
|
||||||
|
"free", "<stdlib.h>",
|
||||||
|
"fsblkcnt_t", "<sys/types.h>",
|
||||||
|
"fsblkcnt_t", "<sys/statvfs.h>",
|
||||||
|
"fsfilcnt_t", "<sys/types.h>",
|
||||||
|
"fsfilcnt_t", "<sys/statvfs.h>",
|
||||||
|
"gid_t", "<sys/types.h>",
|
||||||
|
"gid_t", "<grp.h>",
|
||||||
|
"gid_t", "<pwd.h>",
|
||||||
|
"gid_t", "<stropts.h>",
|
||||||
|
"gid_t", "<sys/ipc.h>",
|
||||||
|
"gid_t", "<sys/stat.h>",
|
||||||
|
"gid_t", "<unistd.h>",
|
||||||
|
"id_t", "<sys/types.h>",
|
||||||
|
"id_t", "<sys/resource.h>",
|
||||||
|
"ino64_t", "<sys/types.h>",
|
||||||
|
"ino64_t", "<dirent.h>",
|
||||||
|
"ino_t", "<sys/types.h>",
|
||||||
|
"ino_t", "<dirent.h>",
|
||||||
|
"ino_t", "<sys/stat.h>",
|
||||||
|
"int8_t", "<sys/types.h>",
|
||||||
|
"int8_t", "<stdint.h>",
|
||||||
|
"intptr_t", "<stdint.h>",
|
||||||
|
"intptr_t", "<unistd.h>",
|
||||||
|
"key_t", "<sys/types.h>",
|
||||||
|
"key_t", "<sys/ipc.h>",
|
||||||
|
"malloc", "<stdlib.h>",
|
||||||
|
"mode_t", "<sys/types.h>",
|
||||||
|
"mode_t", "<sys/stat.h>",
|
||||||
|
"mode_t", "<sys/ipc.h>",
|
||||||
|
"mode_t", "<sys/mman.h>",
|
||||||
|
"nlink_t", "<sys/types.h>",
|
||||||
|
"nlink_t", "<sys/stat.h>",
|
||||||
|
"off64_t", "<sys/types.h>",
|
||||||
|
"off64_t", "<unistd.h>",
|
||||||
|
"off_t", "<sys/types.h>",
|
||||||
|
"off_t", "<unistd.h>",
|
||||||
|
"off_t", "<sys/stat.h>",
|
||||||
|
"off_t", "<sys/mman.h>",
|
||||||
|
"pid_t", "<sys/types.h>",
|
||||||
|
"pid_t", "<unistd.h>",
|
||||||
|
"pid_t", "<signal.h>",
|
||||||
|
"pid_t", "<sys/msg.h>",
|
||||||
|
"pid_t", "<sys/shm.h>",
|
||||||
|
"pid_t", "<termios.h>",
|
||||||
|
"pid_t", "<time.h>",
|
||||||
|
"pid_t", "<utmpx.h>",
|
||||||
|
"realloc", "<stdlib.h>",
|
||||||
|
"sigset_t", "<signal.h>",
|
||||||
|
"sigset_t", "<sys/epoll.h>",
|
||||||
|
"sigset_t", "<sys/select.h>",
|
||||||
|
"size_t", "<stddef.h>",
|
||||||
|
"socklen_t", "<bits/socket.h>",
|
||||||
|
"socklen_t", "<unistd.h>",
|
||||||
|
"socklen_t", "<arpa/inet.h>",
|
||||||
|
"ssize_t", "<sys/types.h>",
|
||||||
|
"ssize_t", "<unistd.h>",
|
||||||
|
"ssize_t", "<monetary.h>",
|
||||||
|
"ssize_t", "<sys/msg.h>",
|
||||||
|
"std::allocator", "<memory>",
|
||||||
|
"std::allocator", "<string>",
|
||||||
|
"std::allocator", "<vector>",
|
||||||
|
"std::allocator", "<map>",
|
||||||
|
"std::allocator", "<set>",
|
||||||
|
"std::char_traits", "<string>",
|
||||||
|
"std::char_traits", "<ostream>",
|
||||||
|
"std::char_traits", "<istream>",
|
||||||
|
"suseconds_t", "<sys/types.h>",
|
||||||
|
"suseconds_t", "<sys/time.h>",
|
||||||
|
"suseconds_t", "<sys/select.h>",
|
||||||
|
"u_char", "<sys/types.h>",
|
||||||
|
"u_char", "<rpc/types.h>",
|
||||||
|
"uid_t", "<sys/types.h>",
|
||||||
|
"uid_t", "<unistd.h>",
|
||||||
|
"uid_t", "<pwd.h>",
|
||||||
|
"uid_t", "<signal.h>",
|
||||||
|
"uid_t", "<stropts.h>",
|
||||||
|
"uid_t", "<sys/ipc.h>",
|
||||||
|
"uid_t", "<sys/stat.h>",
|
||||||
|
"useconds_t", "<sys/types.h>",
|
||||||
|
"useconds_t", "<unistd.h>",
|
||||||
|
"va_list", "<stdarg.h>",
|
||||||
|
});
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
private static final IncludeMap cIncludeMap = new IncludeMap(true, false, new String[] {
|
||||||
|
"<asm/errno-base.h>", "<errno.h>",
|
||||||
|
"<asm/errno.h>", "<errno.h>",
|
||||||
|
"<asm/ioctls.h>", "<sys/ioctl.h>",
|
||||||
|
"<asm/posix_types_32.h>", "<asm/posix_types.h>",
|
||||||
|
"<asm/posix_types_64.h>", "<asm/posix_types.h>",
|
||||||
|
"<asm/ptrace-abi.h>", "<asm/ptrace.h>",
|
||||||
|
"<asm/socket.h>", "<sys/socket.h>",
|
||||||
|
"<asm/unistd.h>", "<syscall.h>",
|
||||||
|
"<asm/unistd_32.h>", "<syscall.h>",
|
||||||
|
"<asm/unistd_64.h>", "<syscall.h>",
|
||||||
|
"<bits/a.out.h>", "<a.out.h>",
|
||||||
|
"<bits/byteswap.h>", "<byteswap.h>",
|
||||||
|
"<bits/cmathcalls.h>", "<complex.h>",
|
||||||
|
"<bits/confname.h>", "<unistd.h>",
|
||||||
|
"<bits/dirent.h>", "<dirent.h>",
|
||||||
|
"<bits/dlfcn.h>", "<dlfcn.h>",
|
||||||
|
"<bits/elfclass.h>", "<link.h>",
|
||||||
|
"<bits/endian.h>", "<endian.h>",
|
||||||
|
"<bits/environments.h>", "<unistd.h>",
|
||||||
|
"<bits/errno.h>", "<errno.h>",
|
||||||
|
"<bits/error.h>", "<error.h>",
|
||||||
|
"<bits/fcntl.h>", "<fcntl.h>",
|
||||||
|
"<bits/fcntl2.h>", "<fcntl.h>",
|
||||||
|
"<bits/fenv.h>", "<fenv.h>",
|
||||||
|
"<bits/fenvinline.h>", "<fenv.h>",
|
||||||
|
"<bits/huge_val.h>", "<math.h>",
|
||||||
|
"<bits/huge_valf.h>", "<math.h>",
|
||||||
|
"<bits/huge_vall.h>", "<math.h>",
|
||||||
|
"<bits/in.h>", "<netinet/in.h>",
|
||||||
|
"<bits/inf.h>", "<math.h>",
|
||||||
|
"<bits/ioctl-types.h>", "<sys/ioctl.h>",
|
||||||
|
"<bits/ioctls.h>", "<sys/ioctl.h>",
|
||||||
|
"<bits/ipc.h>", "<sys/ipc.h>",
|
||||||
|
"<bits/ipctypes.h>", "<sys/ipc.h>",
|
||||||
|
"<bits/libio-ldbl.h>", "<libio.h>",
|
||||||
|
"<bits/link.h>", "<link.h>",
|
||||||
|
"<bits/locale.h>", "<locale.h>",
|
||||||
|
"<bits/mathcalls.h>", "<math.h>",
|
||||||
|
"<bits/mathdef.h>", "<math.h>",
|
||||||
|
"<bits/mathinline.h>", "<math.h>",
|
||||||
|
"<bits/mman.h>", "<sys/mman.h>",
|
||||||
|
"<bits/monetary-ldbl.h>", "<monetary.h>",
|
||||||
|
"<bits/mqueue.h>", "<mqueue.h>",
|
||||||
|
"<bits/mqueue2.h>", "<mqueue.h>",
|
||||||
|
"<bits/msq.h>", "<sys/msg.h>",
|
||||||
|
"<bits/nan.h>", "<math.h>",
|
||||||
|
"<bits/netdb.h>", "<netdb.h>",
|
||||||
|
"<bits/poll.h>", "<poll.h>",
|
||||||
|
"<bits/posix1_lim.h>", "<limits.h>",
|
||||||
|
"<bits/posix2_lim.h>", "<limits.h>",
|
||||||
|
"<bits/posix_opt.h>", "<unistd.h>",
|
||||||
|
"<bits/predefs.h>", "<features.h>",
|
||||||
|
"<bits/printf-ldbl.h>", "<printf.h>",
|
||||||
|
"<bits/pthreadtypes.h>", "<pthread.h>",
|
||||||
|
"<bits/resource.h>", "<sys/resource.h>",
|
||||||
|
"<bits/sched.h>", "<sched.h>",
|
||||||
|
"<bits/select.h>", "<sys/select.h>",
|
||||||
|
"<bits/sem.h>", "<sys/sem.h>",
|
||||||
|
"<bits/semaphore.h>", "<semaphore.h>",
|
||||||
|
"<bits/setjmp.h>", "<setjmp.h>",
|
||||||
|
"<bits/shm.h>", "<sys/shm.h>",
|
||||||
|
"<bits/sigaction.h>", "<signal.h>",
|
||||||
|
"<bits/sigcontext.h>", "<signal.h>",
|
||||||
|
"<bits/siginfo.h>", "<signal.h>",
|
||||||
|
"<bits/signum.h>", "<signal.h>",
|
||||||
|
"<bits/sigset.h>", "<signal.h>",
|
||||||
|
"<bits/sigstack.h>", "<signal.h>",
|
||||||
|
"<bits/sigthread.h>", "<signal.h>",
|
||||||
|
"<bits/sockaddr.h>", "<sys/un.h>",
|
||||||
|
"<bits/socket.h>", "<sys/socket.h>",
|
||||||
|
"<bits/stab.def>", "<stab.h>",
|
||||||
|
"<bits/stat.h>", "<sys/stat.h>",
|
||||||
|
"<bits/statfs.h>", "<sys/statfs.h>",
|
||||||
|
"<bits/statvfs.h>", "<sys/statvfs.h>",
|
||||||
|
"<bits/stdio-ldbl.h>", "<stdio.h>",
|
||||||
|
"<bits/stdio-lock.h>", "<libio.h>",
|
||||||
|
"<bits/stdio.h>", "<stdio.h>",
|
||||||
|
"<bits/stdio2.h>", "<stdio.h>",
|
||||||
|
"<bits/stdio_lim.h>", "<stdio.h>",
|
||||||
|
"<bits/stdlib-ldbl.h>", "<stdlib.h>",
|
||||||
|
"<bits/stdlib.h>", "<stdlib.h>",
|
||||||
|
"<bits/string.h>", "<string.h>",
|
||||||
|
"<bits/string2.h>", "<string.h>",
|
||||||
|
"<bits/string3.h>", "<string.h>",
|
||||||
|
"<bits/stropts.h>", "<stropts.h>",
|
||||||
|
"<bits/sys_errlist.h>", "<stdio.h>",
|
||||||
|
"<bits/syscall.h>", "<syscall.h>",
|
||||||
|
"<bits/syslog-ldbl.h>", "<syslog.h>",
|
||||||
|
"<bits/syslog-path.h>", "<syslog.h>",
|
||||||
|
"<bits/syslog.h>", "<syslog.h>",
|
||||||
|
"<bits/termios.h>", "<termios.h>",
|
||||||
|
"<bits/time.h>", "<sys/time.h>",
|
||||||
|
"<bits/types.h>", "<sys/types.h>",
|
||||||
|
"<bits/uio.h>", "<sys/uio.h>",
|
||||||
|
"<bits/unistd.h>", "<unistd.h>",
|
||||||
|
"<bits/ustat.h>", "<ustat.h>",
|
||||||
|
"<bits/utmp.h>", "<utmp.h>",
|
||||||
|
"<bits/utmpx.h>", "<utmpx.h>",
|
||||||
|
"<bits/utsname.h>", "<sys/utsname.h>",
|
||||||
|
"<bits/waitflags.h>", "<sys/wait.h>",
|
||||||
|
"<bits/waitstatus.h>", "<sys/wait.h>",
|
||||||
|
"<bits/wchar-ldbl.h>", "<wchar.h>",
|
||||||
|
"<bits/wchar.h>", "<wchar.h>",
|
||||||
|
"<bits/wchar2.h>", "<wchar.h>",
|
||||||
|
"<bits/xopen_lim.h>", "<limits.h>",
|
||||||
|
"<bits/xtitypes.h>", "<stropts.h>",
|
||||||
|
"<linux/errno.h>", "<errno.h>",
|
||||||
|
"<linux/limits.h>", "<limits.h>",
|
||||||
|
"<linux/socket.h>", "<sys/socket.h>",
|
||||||
|
"<sys/poll.h>", "<poll.h>",
|
||||||
|
"<sys/syscall.h>", "<syscall.h>",
|
||||||
|
"<sys/syslog.h>", "<syslog.h>",
|
||||||
|
"<sys/ucontext.h>", "<ucontext.h>",
|
||||||
|
"<sys/ustat.h>", "<ustat.h>",
|
||||||
|
"<wait.h>", "<sys/wait.h>",
|
||||||
|
});
|
||||||
|
|
||||||
|
private static final IncludeMap cIncludeMapWeak = new IncludeMap(false, false, new String[] {
|
||||||
|
});
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
private static final IncludeMap cppIncludeMap = new IncludeMap(true, true, new String[] {
|
||||||
|
"<auto_ptr.h>", "<memory>",
|
||||||
|
"<backward/auto_ptr.h>", "<memory>",
|
||||||
|
"<backward/binders.h>", "<functional>",
|
||||||
|
"<backward/hash_fun.h>", "<hash_map>",
|
||||||
|
"<backward/hash_fun.h>", "<hash_set>",
|
||||||
|
"<backward/hashtable.h>", "<hash_map>",
|
||||||
|
"<backward/hashtable.h>", "<hash_set>",
|
||||||
|
"<backward/strstream>", "<strstream>",
|
||||||
|
"<binders.h>", "<functional>",
|
||||||
|
"<bits/algorithmfwd.h>", "<algorithm>",
|
||||||
|
"<bits/allocator.h>", "<memory>",
|
||||||
|
"<bits/atomic_word.h>", "<ext/atomicity.h>",
|
||||||
|
"<bits/basic_file.h>", "<fstream>",
|
||||||
|
"<bits/basic_ios.h>", "<ios>",
|
||||||
|
"<bits/basic_string.h>", "<string>",
|
||||||
|
"<bits/basic_string.tcc>", "<string>",
|
||||||
|
"<bits/boost_concept_check.h>", "<bits/concept_check.h>",
|
||||||
|
"<bits/boost_sp_shared_count.h>", "<memory>",
|
||||||
|
"<bits/c++allocator.h>", "<memory>",
|
||||||
|
"<bits/c++config.h>", "<cstddef>",
|
||||||
|
"<bits/c++io.h>", "<ext/stdio_sync_filebuf.h>",
|
||||||
|
"<bits/char_traits.h>", "<string>",
|
||||||
|
"<bits/cmath.tcc>", "<cmath>",
|
||||||
|
"<bits/codecvt.h>", "<fstream>",
|
||||||
|
"<bits/codecvt.h>", "<locale>",
|
||||||
|
"<bits/ctype_base.h>", "<locale>",
|
||||||
|
"<bits/ctype_base.h>", "<ios>",
|
||||||
|
"<bits/ctype_inline.h>", "<locale>",
|
||||||
|
"<bits/ctype_inline.h>", "<ios>",
|
||||||
|
"<bits/cxxabi_tweaks.h>", "<cxxabi.h>",
|
||||||
|
"<bits/deque.tcc>", "<deque>",
|
||||||
|
"<bits/exception_defines.h>", "<exception>",
|
||||||
|
"<bits/fstream.tcc>", "<fstream>",
|
||||||
|
"<bits/functexcept.h>", "<algorithm>",
|
||||||
|
"<bits/functional_hash.h>", "<unordered_map>",
|
||||||
|
"<bits/gslice.h>", "<valarray>",
|
||||||
|
"<bits/gslice_array.h>", "<valarray>",
|
||||||
|
"<bits/hashtable.h>", "<unordered_map>",
|
||||||
|
"<bits/hashtable.h>", "<unordered_set>",
|
||||||
|
"<bits/indirect_array.h>", "<valarray>",
|
||||||
|
"<bits/ios_base.h>", "<iostream>",
|
||||||
|
"<bits/ios_base.h>", "<ios>",
|
||||||
|
"<bits/ios_base.h>", "<iomanip>",
|
||||||
|
"<bits/istream.tcc>", "<istream>",
|
||||||
|
"<bits/list.tcc>", "<list>",
|
||||||
|
"<bits/locale_classes.h>", "<locale>",
|
||||||
|
"<bits/locale_classes.h>", "<ios>",
|
||||||
|
"<bits/locale_classes.tcc>", "<locale>",
|
||||||
|
"<bits/locale_classes.tcc>", "<ios>",
|
||||||
|
"<bits/locale_facets.h>", "<locale>",
|
||||||
|
"<bits/locale_facets.h>", "<ios>",
|
||||||
|
"<bits/locale_facets.tcc>", "<locale>",
|
||||||
|
"<bits/locale_facets.tcc>", "<ios>",
|
||||||
|
"<bits/locale_facets_nonio.h>", "<locale>",
|
||||||
|
"<bits/locale_facets_nonio.tcc>", "<locale>",
|
||||||
|
"<bits/localefwd.h>", "<locale>",
|
||||||
|
"<bits/mask_array.h>", "<valarray>",
|
||||||
|
"<bits/messages_members.h>", "<locale>",
|
||||||
|
"<bits/move.h>", "<algorithm>",
|
||||||
|
"<bits/ostream.tcc>", "<ostream>",
|
||||||
|
"<bits/ostream_insert.h>", "<ostream>",
|
||||||
|
"<bits/postypes.h>", "<iostream>",
|
||||||
|
"<bits/postypes.h>", "<string>",
|
||||||
|
"<bits/slice_array.h>", "<valarray>",
|
||||||
|
"<bits/sstream.tcc>", "<sstream>",
|
||||||
|
"<bits/stl_algo.h>", "<algorithm>",
|
||||||
|
"<bits/stl_algobase.h>", "<algorithm>",
|
||||||
|
"<bits/stl_bvector.h>", "<vector>",
|
||||||
|
"<bits/stl_construct.h>", "<memory>",
|
||||||
|
"<bits/stl_deque.h>", "<deque>",
|
||||||
|
"<bits/stl_function.h>", "<functional>",
|
||||||
|
"<bits/stl_heap.h>", "<queue>",
|
||||||
|
"<bits/stl_iterator.h>", "<iterator>",
|
||||||
|
"<bits/stl_iterator_base_funcs.h>", "<iterator>",
|
||||||
|
"<bits/stl_iterator_base_types.h>", "<iterator>",
|
||||||
|
"<bits/stl_list.h>", "<list>",
|
||||||
|
"<bits/stl_map.h>", "<map>",
|
||||||
|
"<bits/stl_move.h>", "<algorithm>",
|
||||||
|
"<bits/stl_multimap.h>", "<map>",
|
||||||
|
"<bits/stl_multiset.h>", "<set>",
|
||||||
|
"<bits/stl_numeric.h>", "<numeric>",
|
||||||
|
"<bits/stl_pair.h>", "<utility>",
|
||||||
|
"<bits/stl_pair.h>", "<tr1/utility>",
|
||||||
|
"<bits/stl_queue.h>", "<queue>",
|
||||||
|
"<bits/stl_raw_storage_iter.h>", "<memory>",
|
||||||
|
"<bits/stl_relops.h>", "<utility>",
|
||||||
|
"<bits/stl_set.h>", "<set>",
|
||||||
|
"<bits/stl_stack.h>", "<stack>",
|
||||||
|
"<bits/stl_tempbuf.h>", "<memory>",
|
||||||
|
"<bits/stl_tree.h>", "<map>",
|
||||||
|
"<bits/stl_tree.h>", "<set>",
|
||||||
|
"<bits/stl_uninitialized.h>", "<memory>",
|
||||||
|
"<bits/stl_vector.h>", "<vector>",
|
||||||
|
"<bits/stream_iterator.h>", "<iterator>",
|
||||||
|
"<bits/streambuf.tcc>", "<streambuf>",
|
||||||
|
"<bits/streambuf_iterator.h>", "<iterator>",
|
||||||
|
"<bits/streambuf_iterator.h>", "<ios>",
|
||||||
|
"<bits/stringfwd.h>", "<string>",
|
||||||
|
"<bits/valarray_after.h>", "<valarray>",
|
||||||
|
"<bits/valarray_array.h>", "<valarray>",
|
||||||
|
"<bits/valarray_array.tcc>", "<valarray>",
|
||||||
|
"<bits/valarray_before.h>", "<valarray>",
|
||||||
|
"<bits/vector.tcc>", "<vector>",
|
||||||
|
"<debug/safe_iterator.tcc>", "<debug/safe_iterator.h>",
|
||||||
|
"<exception_defines.h>", "<exception>",
|
||||||
|
"<ext/algorithm>", "<algorithm>",
|
||||||
|
"<ext/functional>", "<functional>",
|
||||||
|
"<ext/hash_map>", "<hash_map>",
|
||||||
|
"<ext/hash_set>", "<hash_set>",
|
||||||
|
"<ext/numeric>", "<numeric>",
|
||||||
|
"<ext/slist>", "<slist>",
|
||||||
|
"<ext/sso_string_base.h>", "<string>",
|
||||||
|
"<ext/vstring.h>", "<string>",
|
||||||
|
"<ext/vstring.tcc>", "<string>",
|
||||||
|
"<ext/vstring_fwd.h>", "<string>",
|
||||||
|
"<hash_fun.h>", "<hash_map>",
|
||||||
|
"<hash_fun.h>", "<hash_set>",
|
||||||
|
"<hashtable.h>", "<hash_map>",
|
||||||
|
"<hashtable.h>", "<hash_set>",
|
||||||
|
"<tr1/bessel_function.tcc>", "<tr1/cmath>",
|
||||||
|
"<tr1/beta_function.tcc>", "<tr1/cmath>",
|
||||||
|
"<tr1/ell_integral.tcc>", "<tr1/cmath>",
|
||||||
|
"<tr1/exp_integral.tcc>", "<tr1/cmath>",
|
||||||
|
"<tr1/gamma.tcc>", "<tr1/cmath>",
|
||||||
|
"<tr1/hypergeometric.tcc>", "<tr1/cmath>",
|
||||||
|
"<tr1/legendre_function.tcc>", "<tr1/cmath>",
|
||||||
|
"<tr1/modified_bessel_func.tcc>", "<tr1/cmath>",
|
||||||
|
"<tr1/poly_hermite.tcc>", "<tr1/cmath>",
|
||||||
|
"<tr1/poly_laguerre.tcc>", "<tr1/cmath>",
|
||||||
|
"<tr1/riemann_zeta.tcc>", "<tr1/cmath>",
|
||||||
|
"<tr1_impl/array>", "<array>",
|
||||||
|
"<tr1_impl/array>", "<tr1/array>",
|
||||||
|
"<tr1_impl/boost_shared_ptr.h>", "<memory>",
|
||||||
|
"<tr1_impl/boost_shared_ptr.h>", "<tr1/memory>",
|
||||||
|
"<tr1_impl/boost_sp_counted_base.h>", "<memory>",
|
||||||
|
"<tr1_impl/boost_sp_counted_base.h>", "<tr1/memory>",
|
||||||
|
"<tr1_impl/cctype>", "<cctype>",
|
||||||
|
"<tr1_impl/cctype>", "<tr1/cctype>",
|
||||||
|
"<tr1_impl/cfenv>", "<cfenv>",
|
||||||
|
"<tr1_impl/cfenv>", "<tr1/cfenv>",
|
||||||
|
"<tr1_impl/cinttypes>", "<cinttypes>",
|
||||||
|
"<tr1_impl/cinttypes>", "<tr1/cinttypes>",
|
||||||
|
"<tr1_impl/cmath>", "<cmath>",
|
||||||
|
"<tr1_impl/cmath>", "<tr1/cmath>",
|
||||||
|
"<tr1_impl/complex>", "<complex>",
|
||||||
|
"<tr1_impl/complex>", "<tr1/complex>",
|
||||||
|
"<tr1_impl/cstdint>", "<cstdint>",
|
||||||
|
"<tr1_impl/cstdint>", "<tr1/cstdint>",
|
||||||
|
"<tr1_impl/cstdio>", "<cstdio>",
|
||||||
|
"<tr1_impl/cstdio>", "<tr1/cstdio>",
|
||||||
|
"<tr1_impl/cstdlib>", "<cstdlib>",
|
||||||
|
"<tr1_impl/cstdlib>", "<tr1/cstdlib>",
|
||||||
|
"<tr1_impl/cwchar>", "<cwchar>",
|
||||||
|
"<tr1_impl/cwchar>", "<tr1/cwchar>",
|
||||||
|
"<tr1_impl/cwctype>", "<cwctype>",
|
||||||
|
"<tr1_impl/cwctype>", "<tr1/cwctype>",
|
||||||
|
"<tr1_impl/functional>", "<functional>",
|
||||||
|
"<tr1_impl/functional>", "<tr1/functional>",
|
||||||
|
"<tr1_impl/functional_hash.h>", "<tr1/functional_hash.h>",
|
||||||
|
"<tr1_impl/hashtable>", "<tr1/hashtable.h>",
|
||||||
|
"<tr1_impl/random.tcc>", "<random>",
|
||||||
|
"<tr1_impl/random.tcc>", "<tr1/random>",
|
||||||
|
"<tr1_impl/random>", "<random>",
|
||||||
|
"<tr1_impl/random>", "<tr1/random>",
|
||||||
|
"<tr1_impl/regex>", "<regex>",
|
||||||
|
"<tr1_impl/regex>", "<tr1/regex>",
|
||||||
|
"<tr1_impl/type_traits>", "<tr1/type_traits>",
|
||||||
|
"<tr1_impl/type_traits>", "<type_traits>",
|
||||||
|
"<tr1_impl/unordered_map>", "<tr1/unordered_map>",
|
||||||
|
"<tr1_impl/unordered_map>", "<unordered_map>",
|
||||||
|
"<tr1_impl/unordered_set>", "<tr1/unordered_set>",
|
||||||
|
"<tr1_impl/unordered_set>", "<unordered_set>",
|
||||||
|
"<tr1_impl/utility>", "<tr1/utility>",
|
||||||
|
"<tr1_impl/utility>", "<utility>",
|
||||||
|
});
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
private static final IncludeMap cppIncludeMapWeak = new IncludeMap(false, true, new String[] {
|
||||||
|
"<assert.h>", "<cassert>",
|
||||||
|
"<complex.h>", "<ccomplex>",
|
||||||
|
"<ctype.h>", "<cctype>",
|
||||||
|
"<errno.h>", "<cerrno>",
|
||||||
|
"<fenv.h>", "<cfenv>",
|
||||||
|
"<float.h>", "<cfloat>",
|
||||||
|
"<inttypes.h>", "<cinttypes>",
|
||||||
|
"<iso646.h>", "<ciso646>",
|
||||||
|
"<limits.h>", "<climits>",
|
||||||
|
"<locale.h>", "<clocale>",
|
||||||
|
"<math.h>", "<cmath>",
|
||||||
|
"<setjmp.h>", "<csetjmp>",
|
||||||
|
"<signal.h>", "<csignal>",
|
||||||
|
"<stdarg.h>", "<cstdarg>",
|
||||||
|
"<stdbool.h>", "<cstdbool>",
|
||||||
|
"<stddef.h>", "<cstddef>",
|
||||||
|
"<stdint.h>", "<cstdint>",
|
||||||
|
"<stdio.h>", "<cstdio>",
|
||||||
|
"<stdlib.h>", "<cstdlib>",
|
||||||
|
"<string.h>", "<cstring>",
|
||||||
|
"<tgmath.h>", "<ctgmath>",
|
||||||
|
"<time.h>", "<ctime>",
|
||||||
|
"<wchar.h>", "<cwchar>",
|
||||||
|
"<wctype.h>", "<cwctype>",
|
||||||
|
"<ios>", "<istream>",
|
||||||
|
"<ios>", "<ostream>",
|
||||||
|
"<iosfwd>", "<ios>",
|
||||||
|
"<iosfwd>", "<streambuf>",
|
||||||
|
"<istream>", "<fstream>",
|
||||||
|
"<istream>", "<iostream>",
|
||||||
|
"<istream>", "<sstream>",
|
||||||
|
"<ostream>", "<fstream>",
|
||||||
|
"<ostream>", "<iostream>",
|
||||||
|
"<ostream>", "<istream>",
|
||||||
|
"<ostream>", "<sstream>",
|
||||||
|
"<streambuf>", "<ios>",
|
||||||
|
});
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
private static final IncludeMap google3IncludeMap = new IncludeMap(true, true, new String[] {
|
||||||
|
"<ios>", "base/logging.h",
|
||||||
|
"<ios>", "base/logging.h",
|
||||||
|
"<iosfwd>", "base/logging.h",
|
||||||
|
"<iosfwd>", "base/logging.h",
|
||||||
|
"<istream>", "base/logging.h",
|
||||||
|
"<istream>", "base/logging.h",
|
||||||
|
"<istream>", "base/logging.h",
|
||||||
|
"<ostream>", "base/logging.h",
|
||||||
|
"<ostream>", "base/logging.h",
|
||||||
|
"<ostream>", "base/logging.h",
|
||||||
|
"<ostream>", "base/logging.h",
|
||||||
|
"<streambuf>", "base/logging.h",
|
||||||
|
"base/vlog_is_on.h", "base/logging.h"
|
||||||
|
});
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
private static final IncludeMap google3IncludeMapWeak = new IncludeMap(false, true, new String[] {
|
||||||
|
"base/commandlineflags_declare.h", "base/commandlineflags.h"
|
||||||
|
});
|
||||||
|
|
||||||
|
private final InclusionContext fContext;
|
||||||
|
|
||||||
|
private List<IncludeMap> fIncludeMaps;
|
||||||
|
|
||||||
|
public HeaderSubstitutor(InclusionContext context) {
|
||||||
|
fContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the header file to be appear in the {@code #include} statement given the header file
|
||||||
|
* that needs to be included. Returns absolute path for the header if it can be uniquely
|
||||||
|
* determined, or {@code null} otherwise. The header is determined uniquely if there are no
|
||||||
|
* optional replacement headers for it, and there are no more that one forced replacement.
|
||||||
|
* @param path absolute path of the header to be included directly or indirectly
|
||||||
|
* @return absolute path of the header to be included directly
|
||||||
|
*/
|
||||||
|
public IPath getUniqueRepresentativeHeader(IPath path) {
|
||||||
|
IncludeInfo includeInfo = fContext.getIncludeForHeaderFile(path);
|
||||||
|
if (includeInfo == null)
|
||||||
|
return null;
|
||||||
|
List<IncludeMap> maps = getAllIncludeMaps();
|
||||||
|
for (IncludeMap map : maps) {
|
||||||
|
if (map.isForcedReplacement()) {
|
||||||
|
List<IncludeInfo> replacements = map.getMapping(includeInfo);
|
||||||
|
if (replacements.size() == 1) {
|
||||||
|
includeInfo = replacements.get(0);
|
||||||
|
} else if (replacements.size() > 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (IncludeMap map : maps) {
|
||||||
|
if (!map.isForcedReplacement()) {
|
||||||
|
if (!map.getMapping(includeInfo).isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fContext.resolveInclude(includeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPath getPreferredRepresentativeHeader(IPath path) {
|
||||||
|
IncludeInfo includeInfo = fContext.getIncludeForHeaderFile(path);
|
||||||
|
if (includeInfo == null)
|
||||||
|
return path;
|
||||||
|
// TODO(sprigogin): Take symbolIncludeMap into account.
|
||||||
|
List<IncludeInfo> candidates = new ArrayList<IncludeInfo>();
|
||||||
|
candidates.add(includeInfo);
|
||||||
|
List<IncludeMap> maps = getAllIncludeMaps();
|
||||||
|
for (IncludeMap map : maps) {
|
||||||
|
for (int i = 0; i < candidates.size();) {
|
||||||
|
IncludeInfo candidate = candidates.get(i);
|
||||||
|
List<IncludeInfo> replacements = map.getMapping(candidate);
|
||||||
|
int increment = 1;
|
||||||
|
if (!replacements.isEmpty()) {
|
||||||
|
if (map.isForcedReplacement()) {
|
||||||
|
candidates.remove(i);
|
||||||
|
increment = 0;
|
||||||
|
}
|
||||||
|
candidates.addAll(i, replacements);
|
||||||
|
increment += replacements.size();
|
||||||
|
}
|
||||||
|
i += increment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IPath firstResolved = null;
|
||||||
|
for (IncludeInfo candidate : candidates) {
|
||||||
|
IPath header = fContext.resolveInclude(candidate);
|
||||||
|
if (header != null) {
|
||||||
|
if (fContext.isIncluded(header))
|
||||||
|
return header;
|
||||||
|
if (firstResolved == null)
|
||||||
|
firstResolved = header;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return firstResolved != null ? firstResolved : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs heuristic header substitution.
|
||||||
|
*/
|
||||||
|
public IPath getPreferredRepresentativeHeaderByHeuristic(InclusionRequest request) {
|
||||||
|
Set<IIndexFile> indexFiles = request.getDeclaringFiles().keySet();
|
||||||
|
String symbolName = request.getBinding().getName();
|
||||||
|
ArrayDeque<IIndexFile> front = new ArrayDeque<IIndexFile>();
|
||||||
|
HashSet<IIndexFile> processed = new HashSet<IIndexFile>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Look for headers without an extension and a matching name.
|
||||||
|
if (fContext.isCXXLanguage()) {
|
||||||
|
front.addAll(indexFiles);
|
||||||
|
processed.addAll(indexFiles);
|
||||||
|
|
||||||
|
while (!front.isEmpty()) {
|
||||||
|
IIndexFile file = front.remove();
|
||||||
|
|
||||||
|
String path = IncludeUtil.getPath(file);
|
||||||
|
|
||||||
|
if (!hasExtension(path) && getFilename(path).equalsIgnoreCase(symbolName)) {
|
||||||
|
// A C++ header without an extension and with a name which matches the name
|
||||||
|
// of the symbol which should be declared is a perfect candidate for inclusion.
|
||||||
|
return IndexLocationFactory.getAbsolutePath(file.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the next level of the include hierarchy.
|
||||||
|
IIndexInclude[] includes = fContext.getIndex().findIncludedBy(file, 0);
|
||||||
|
for (IIndexInclude include : includes) {
|
||||||
|
IIndexFile includer = include.getIncludedBy();
|
||||||
|
if (!processed.contains(includer)) {
|
||||||
|
front.add(includer);
|
||||||
|
processed.add(includer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeat the process, this time only looking for headers without an extension.
|
||||||
|
front.clear();
|
||||||
|
front.addAll(indexFiles);
|
||||||
|
processed.clear();
|
||||||
|
processed.addAll(indexFiles);
|
||||||
|
|
||||||
|
while (!front.isEmpty()) {
|
||||||
|
IIndexFile file = front.remove();
|
||||||
|
|
||||||
|
String path = IncludeUtil.getPath(file);
|
||||||
|
|
||||||
|
if (fContext.isCXXLanguage() && !hasExtension(path)) {
|
||||||
|
// A C++ header without an extension is still a very good candidate for inclusion.
|
||||||
|
return IndexLocationFactory.getAbsolutePath(file.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the next level of the include hierarchy.
|
||||||
|
IIndexInclude[] includes = fContext.getIndex().findIncludedBy(file, 0);
|
||||||
|
for (IIndexInclude include : includes) {
|
||||||
|
IIndexFile includer = include.getIncludedBy();
|
||||||
|
if (!processed.contains(includer)) {
|
||||||
|
URI uri = includer.getLocation().getURI();
|
||||||
|
if (IncludeUtil.isSource(includer, fContext.getProject()) || isWorkspaceFile(uri)) {
|
||||||
|
return IndexLocationFactory.getAbsolutePath(file.getLocation());
|
||||||
|
}
|
||||||
|
front.add(includer);
|
||||||
|
processed.add(includer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (CoreException e) {
|
||||||
|
CUIPlugin.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return request.getCandidatePaths().iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<IncludeMap> getAllIncludeMaps() {
|
||||||
|
if (fIncludeMaps == null) {
|
||||||
|
fIncludeMaps = new ArrayList<IncludeMap>();
|
||||||
|
for (IncludeMap map : INCLUDE_MAPS) {
|
||||||
|
if (fContext.isCXXLanguage() || !map.isCppOnly())
|
||||||
|
fIncludeMaps.add(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fIncludeMaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given URI is an URI within the workspace
|
||||||
|
* @param uri
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static boolean isWorkspaceFile(URI uri) {
|
||||||
|
for (IFile file : ResourceLookup.findFilesForLocationURI(uri)) {
|
||||||
|
if (file.exists()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given path has a file suffix, or not.
|
||||||
|
* @param path
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static boolean hasExtension(String path) {
|
||||||
|
return path.indexOf('.', path.lastIndexOf('/') + 1) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the filename of the given path, without extension.
|
||||||
|
* @param path
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static String getFilename(String path) {
|
||||||
|
int startPos = path.lastIndexOf('/') + 1;
|
||||||
|
int endPos = path.lastIndexOf('.');
|
||||||
|
if (endPos > startPos) {
|
||||||
|
return path.substring(startPos, endPos);
|
||||||
|
} else {
|
||||||
|
return path.substring(startPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2012 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
|
public class IncludeInfo {
|
||||||
|
private final String name;
|
||||||
|
private final boolean isSystem;
|
||||||
|
|
||||||
|
public IncludeInfo(String name, boolean isSystem) {
|
||||||
|
if (name == null || name.isEmpty())
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
this.name = name;
|
||||||
|
this.isSystem = isSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IncludeInfo(String includeText) {
|
||||||
|
if (includeText == null || includeText.isEmpty())
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
boolean isSystem = false;
|
||||||
|
int begin = 0;
|
||||||
|
switch (includeText.charAt(0)) {
|
||||||
|
case '<':
|
||||||
|
isSystem = true;
|
||||||
|
//$FALL-THROUGH$
|
||||||
|
case '"':
|
||||||
|
++begin;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int end = includeText.length();
|
||||||
|
switch (includeText.charAt(end - 1)) {
|
||||||
|
case '>':
|
||||||
|
case '"':
|
||||||
|
--end;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (begin >= end)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
|
||||||
|
this.name = includeText.substring(begin, end);
|
||||||
|
this.isSystem = isSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isSystem() {
|
||||||
|
return isSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return name.hashCode() * 31 + (isSystem ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
IncludeInfo other = (IncludeInfo) obj;
|
||||||
|
return name.equals(other.name) && isSystem == other.isSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the include string as it appears in an {@code #include} statement.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return (isSystem ? '<' : '"') + name + (isSystem ? '>' : '"');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2012 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
class IncludeMap {
|
||||||
|
private final boolean forcedReplacement;
|
||||||
|
private final Map<IncludeInfo, List<IncludeInfo>> map;
|
||||||
|
private final boolean cppOnly;
|
||||||
|
|
||||||
|
public IncludeMap(boolean forcedReplacement, boolean cppOnly) {
|
||||||
|
this.forcedReplacement = forcedReplacement;
|
||||||
|
this.cppOnly = cppOnly;
|
||||||
|
this.map = new HashMap<IncludeInfo, List<IncludeInfo>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param keysAndValues an array of keys and values: [key1, value1, key2, value2, ...].
|
||||||
|
* Keys and values may be optionally surrounded by double quotes or angle brackets.
|
||||||
|
* Angle brackets indicate a system include.
|
||||||
|
*/
|
||||||
|
public IncludeMap(boolean forcedReplacement, boolean cppOnly, String[] keysAndValues) {
|
||||||
|
if (keysAndValues.length % 2 != 0)
|
||||||
|
throw new IllegalArgumentException("More keys than values"); //$NON-NLS-1$
|
||||||
|
this.forcedReplacement = forcedReplacement;
|
||||||
|
this.cppOnly = cppOnly;
|
||||||
|
this.map = new HashMap<IncludeInfo, List<IncludeInfo>>(keysAndValues.length / 2);
|
||||||
|
for (int i = 0; i < keysAndValues.length;) {
|
||||||
|
String key = keysAndValues[i++];
|
||||||
|
addMapping(key, keysAndValues[i++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that header file {@code to} should be used instead of {@code from}.
|
||||||
|
*
|
||||||
|
* @param from The header file to be replaced.
|
||||||
|
* @param to The header file to be used.
|
||||||
|
*/
|
||||||
|
protected void addMapping(IncludeInfo from, IncludeInfo to) {
|
||||||
|
List<IncludeInfo> list = map.get(from);
|
||||||
|
if (list == null) {
|
||||||
|
list = new ArrayList<IncludeInfo>(2);
|
||||||
|
map.put(from, list);
|
||||||
|
}
|
||||||
|
list.add(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that header file {@code to} should be used instead of {@code from}.
|
||||||
|
|
||||||
|
* @param from The header file to be replaced. The header is represented by an include name
|
||||||
|
* optionally surrounded by double quotes or angle brackets. Angle brackets indicate
|
||||||
|
* a system include.
|
||||||
|
* @param to The header file to be used. The header is represented by an include name optionally
|
||||||
|
* surrounded by double quotes or angle brackets. Angle brackets indicate a system include.
|
||||||
|
*/
|
||||||
|
public void addMapping(String from, String to) {
|
||||||
|
addMapping(new IncludeInfo(from), new IncludeInfo(to));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns header files that should be used instead of the given one.
|
||||||
|
*
|
||||||
|
* @param from The header file to be replaced. A system header has to match exactly.
|
||||||
|
* A non-system header matches both, non-system and system headers.
|
||||||
|
* @return The list of header files ordered by decreasing preference.
|
||||||
|
*/
|
||||||
|
public List<IncludeInfo> getMapping(IncludeInfo from) {
|
||||||
|
List<IncludeInfo> list = map.get(from);
|
||||||
|
if (list == null) {
|
||||||
|
if (!from.isSystem())
|
||||||
|
list = map.get(new IncludeInfo(from.getName(), true));
|
||||||
|
if (list == null)
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns header files that should be used instead of the given one.
|
||||||
|
*
|
||||||
|
* @param from The header file to be replaced. A system header has to match exactly.
|
||||||
|
* A non-system header matches both, non-system and system headers.
|
||||||
|
* @return The list of header files ordered by decreasing preference.
|
||||||
|
*/
|
||||||
|
public List<IncludeInfo> getMapping(String from) {
|
||||||
|
return getMapping(new IncludeInfo(from));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IncludeInfo getPreferredMapping(IncludeInfo from) {
|
||||||
|
List<IncludeInfo> list = getMapping(from);
|
||||||
|
return list == null ? null : list.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForcedReplacement() {
|
||||||
|
return forcedReplacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCppOnly() {
|
||||||
|
return cppOnly;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,704 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2012 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
* Mathias Kunter
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IAdaptable;
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
import org.eclipse.core.runtime.OperationCanceledException;
|
||||||
|
import org.eclipse.core.runtime.Path;
|
||||||
|
import org.eclipse.jface.text.BadLocationException;
|
||||||
|
import org.eclipse.jface.text.IDocument;
|
||||||
|
import org.eclipse.jface.viewers.LabelProvider;
|
||||||
|
import org.eclipse.jface.window.Window;
|
||||||
|
import org.eclipse.osgi.util.NLS;
|
||||||
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
|
||||||
|
import org.eclipse.ui.texteditor.ITextEditor;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.IName;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.EScopeKind;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.ICompositeType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IEnumeration;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IFunction;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IFunctionType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IParameter;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IScope;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
|
||||||
|
import org.eclipse.cdt.core.index.IIndex;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexFile;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexFileLocation;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexFileSet;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexInclude;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexName;
|
||||||
|
import org.eclipse.cdt.core.index.IndexLocationFactory;
|
||||||
|
import org.eclipse.cdt.core.model.IBuffer;
|
||||||
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
|
import org.eclipse.cdt.ui.CUIPlugin;
|
||||||
|
import org.eclipse.cdt.utils.PathUtil;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.core.resources.PathCanonicalizationStrategy;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.ui.editor.CEditorMessages;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludePreferences.IncludeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Organizes the include directives and forward declarations of a source or header file.
|
||||||
|
*/
|
||||||
|
public class IncludeOrganizer {
|
||||||
|
// TODO(sprigogin): Move to a preference.
|
||||||
|
private static final String[] PARTNER_FILE_SUFFIXES = { "test", "unittest" }; //$NON-NLS-1$//$NON-NLS-2$
|
||||||
|
|
||||||
|
private final ITextEditor fEditor;
|
||||||
|
private final InclusionContext fContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param editor The editor on which this organize includes action should operate.
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
public IncludeOrganizer(ITextEditor editor, ITranslationUnit tu, IIndex index) {
|
||||||
|
fEditor = editor;
|
||||||
|
fContext = new InclusionContext(tu, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Organizes the includes for a given translation unit.
|
||||||
|
* @param ast The AST translation unit to process.
|
||||||
|
* @throws CoreException
|
||||||
|
*/
|
||||||
|
public void organizeIncludes(IASTTranslationUnit ast) throws CoreException {
|
||||||
|
// Process the given translation unit with the inclusion resolver.
|
||||||
|
BindingClassifier resolver = new BindingClassifier(fContext, ast);
|
||||||
|
Set<IBinding> bindingsToDefine = resolver.getBindingsToDefine();
|
||||||
|
|
||||||
|
HeaderSubstitutor headerSubstitutor = new HeaderSubstitutor(fContext);
|
||||||
|
// Create the list of header files which have to be included by examining the list of
|
||||||
|
// bindings which have to be defined.
|
||||||
|
IIndexFileSet reachableHeaders = ast.getIndexFileSet();
|
||||||
|
|
||||||
|
List<InclusionRequest> requests = createInclusionRequests(bindingsToDefine, reachableHeaders);
|
||||||
|
processInclusionRequests(requests, headerSubstitutor);
|
||||||
|
|
||||||
|
// Stores the forward declarations for composite types and enumerations as text.
|
||||||
|
List<String> forwardDeclarations = new ArrayList<String>();
|
||||||
|
|
||||||
|
// Stores the forward declarations for C-style functions as text.
|
||||||
|
List<String> functionForwardDeclarations = new ArrayList<String>();
|
||||||
|
|
||||||
|
// Create the forward declarations by examining the list of bindings which have to be
|
||||||
|
// declared.
|
||||||
|
Set<IBinding> bindings = removeBindingsDefinedInIncludedHeaders(resolver.getBindingsToDeclare(), reachableHeaders);
|
||||||
|
for (IBinding binding : bindings) {
|
||||||
|
// Create the text of the forward declaration of this binding.
|
||||||
|
StringBuilder declarationText = new StringBuilder();
|
||||||
|
|
||||||
|
// Consider the namespace(s) of the binding.
|
||||||
|
List<IName> scopeNames = new ArrayList<IName>();
|
||||||
|
try {
|
||||||
|
IScope scope = binding.getScope();
|
||||||
|
while (scope != null && scope.getKind() == EScopeKind.eNamespace) {
|
||||||
|
IName scopeName = scope.getScopeName();
|
||||||
|
if (scopeName != null) {
|
||||||
|
scopeNames.add(scopeName);
|
||||||
|
}
|
||||||
|
scope = scope.getParent();
|
||||||
|
}
|
||||||
|
} catch (DOMException e) {
|
||||||
|
}
|
||||||
|
Collections.reverse(scopeNames);
|
||||||
|
for (IName scopeName : scopeNames) {
|
||||||
|
declarationText.append("namespace "); //$NON-NLS-1$
|
||||||
|
declarationText.append(scopeName.toString());
|
||||||
|
declarationText.append(" { "); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the list which should be used to store the declaration.
|
||||||
|
List<String> forwardDeclarationListToUse = forwardDeclarations;
|
||||||
|
|
||||||
|
// Check the type of the binding and create a corresponding forward declaration text.
|
||||||
|
if (binding instanceof ICompositeType) {
|
||||||
|
// Forward declare a composite type.
|
||||||
|
ICompositeType compositeType = (ICompositeType) binding;
|
||||||
|
|
||||||
|
// Check whether this is a template type.
|
||||||
|
ICPPTemplateDefinition templateDefinition = null;
|
||||||
|
if (compositeType instanceof ICPPTemplateDefinition) {
|
||||||
|
templateDefinition = (ICPPTemplateDefinition) compositeType;
|
||||||
|
} else if (compositeType instanceof ICPPTemplateInstance) {
|
||||||
|
templateDefinition = ((ICPPTemplateInstance) compositeType).getTemplateDefinition();
|
||||||
|
}
|
||||||
|
if (templateDefinition != null) {
|
||||||
|
// Create the template text.
|
||||||
|
declarationText.append("template "); //$NON-NLS-1$
|
||||||
|
ICPPTemplateParameter[] templateParameters = templateDefinition.getTemplateParameters();
|
||||||
|
for (int i = 0; i < templateParameters.length; i++) {
|
||||||
|
ICPPTemplateParameter templateParameter = templateParameters[i];
|
||||||
|
if (i == 0) {
|
||||||
|
declarationText.append("<"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
declarationText.append("typename "); //$NON-NLS-1$
|
||||||
|
declarationText.append(templateParameter.getName());
|
||||||
|
if (i != templateParameters.length - 1) {
|
||||||
|
declarationText.append(", "); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (templateParameters.length > 0) {
|
||||||
|
declarationText.append("> "); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the corresponding keyword.
|
||||||
|
switch (compositeType.getKey()) {
|
||||||
|
case ICPPClassType.k_class:
|
||||||
|
declarationText.append("class"); //$NON-NLS-1$
|
||||||
|
break;
|
||||||
|
case ICompositeType.k_struct:
|
||||||
|
declarationText.append("struct"); //$NON-NLS-1$
|
||||||
|
break;
|
||||||
|
case ICompositeType.k_union:
|
||||||
|
declarationText.append("union"); //$NON-NLS-1$
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the name of the composite type.
|
||||||
|
declarationText.append(' ');
|
||||||
|
declarationText.append(binding.getName());
|
||||||
|
|
||||||
|
// Append the semicolon.
|
||||||
|
declarationText.append(';');
|
||||||
|
} else if (binding instanceof IEnumeration) {
|
||||||
|
// Forward declare an enumeration class (C++11 syntax).
|
||||||
|
declarationText.append("enum class "); //$NON-NLS-1$
|
||||||
|
declarationText.append(binding.getName());
|
||||||
|
declarationText.append(';');
|
||||||
|
} else if (binding instanceof IFunction && !(binding instanceof ICPPMethod)) {
|
||||||
|
// Forward declare a C-style function.
|
||||||
|
IFunction function = (IFunction) binding;
|
||||||
|
|
||||||
|
// Append return type and function name.
|
||||||
|
IFunctionType functionType = function.getType();
|
||||||
|
// TODO(sprigogin) Improper use of IType.toString();
|
||||||
|
declarationText.append(functionType.getReturnType().toString());
|
||||||
|
declarationText.append(' ');
|
||||||
|
declarationText.append(function.getName());
|
||||||
|
declarationText.append('(');
|
||||||
|
|
||||||
|
// Append parameter types and names.
|
||||||
|
IType[] parameterTypes = functionType.getParameterTypes();
|
||||||
|
IParameter[] parameters = function.getParameters();
|
||||||
|
for (int i = 0; i < parameterTypes.length && i < parameters.length; i++) {
|
||||||
|
// TODO(sprigogin) Improper use of IType.toString();
|
||||||
|
declarationText.append(parameterTypes[i].toString());
|
||||||
|
char lastChar = declarationText.charAt(declarationText.length() - 1);
|
||||||
|
if (lastChar != '*' && lastChar != '&') {
|
||||||
|
// Append a space to separate the type name from the parameter name.
|
||||||
|
declarationText.append(' ');
|
||||||
|
}
|
||||||
|
declarationText.append(parameters[i].getName());
|
||||||
|
if (i != parameterTypes.length - 1 && i != parameters.length - 1) {
|
||||||
|
declarationText.append(", "); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declarationText.append(");"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
// Add this forward declaration to the separate function forward declaration list.
|
||||||
|
forwardDeclarationListToUse = functionForwardDeclarations;
|
||||||
|
} else {
|
||||||
|
// We don't handle forward declarations for those types of bindings. Ignore it.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the closing curly brackets from the namespaces (if any).
|
||||||
|
for (int i = 0; i < scopeNames.size(); i++) {
|
||||||
|
declarationText.append(" }"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the forward declaration to the corresponding list.
|
||||||
|
forwardDeclarationListToUse.add(declarationText.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtain the final lists of library, project, and relative headers.
|
||||||
|
List<String> relativeIncludeDirectives = new ArrayList<String>();
|
||||||
|
List<String> projectIncludeDirectives = new ArrayList<String>();
|
||||||
|
List<String> libraryIncludeDirectives = new ArrayList<String>();
|
||||||
|
List<String> allIncludeDirectives = new ArrayList<String>();
|
||||||
|
IncludePreferences preferences = fContext.getPreferences();
|
||||||
|
for (IPath file : fContext.getHeadersToInclude()) {
|
||||||
|
if (preferences.allowReordering && preferences.sortByHeaderLocation) {
|
||||||
|
// Add the created include directives to different lists.
|
||||||
|
createIncludeDirective(file, relativeIncludeDirectives, projectIncludeDirectives, libraryIncludeDirectives);
|
||||||
|
} else {
|
||||||
|
// Add all created include directives to the same list, making sure that no sort
|
||||||
|
// order is applied.
|
||||||
|
createIncludeDirective(file, allIncludeDirectives, allIncludeDirectives, allIncludeDirectives);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the source code to insert into the editor.
|
||||||
|
IBuffer fBuffer = fContext.getTranslationUnit().getBuffer();
|
||||||
|
String lineSep = getLineSeparator(fBuffer);
|
||||||
|
String insertText = new String();
|
||||||
|
|
||||||
|
if (preferences.allowReordering) {
|
||||||
|
if (preferences.removeUnusedIncludes) {
|
||||||
|
// Remove *all* existing includes and forward declarations. Those which are required
|
||||||
|
// will be added again right afterwards.
|
||||||
|
|
||||||
|
// TODO implement this
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preferences.sortByHeaderLocation) {
|
||||||
|
// Sort by header file location.
|
||||||
|
|
||||||
|
// Process the different types of include directives separately.
|
||||||
|
for (IncludeType includeType : preferences.groupOrder) {
|
||||||
|
List<String> stringList = null;
|
||||||
|
|
||||||
|
if (includeType == IncludeType.RELATIVE_HEADER) {
|
||||||
|
stringList = relativeIncludeDirectives;
|
||||||
|
} else if (includeType == IncludeType.PROJECT_HEADER) {
|
||||||
|
stringList = projectIncludeDirectives;
|
||||||
|
} else if (includeType == IncludeType.LIBRARY_HEADER) {
|
||||||
|
stringList = libraryIncludeDirectives;
|
||||||
|
} else if (includeType == IncludeType.FORWARD_DECLARATION) {
|
||||||
|
stringList = forwardDeclarations;
|
||||||
|
} else if (includeType == IncludeType.FUNCTION_FORWARD_DECLARATION) {
|
||||||
|
stringList = functionForwardDeclarations;
|
||||||
|
}
|
||||||
|
if (stringList == null || stringList.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort alphabetically
|
||||||
|
if (preferences.sortAlphabetically) {
|
||||||
|
Collections.sort(stringList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the actual text.
|
||||||
|
for (String str : stringList) {
|
||||||
|
insertText += str + lineSep;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert blank line
|
||||||
|
if (preferences.separateIncludeBlocks) {
|
||||||
|
insertText += lineSep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Don't sort by header file location.
|
||||||
|
|
||||||
|
// Sort alphabetically
|
||||||
|
if (preferences.sortAlphabetically) {
|
||||||
|
Collections.sort(allIncludeDirectives);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the actual text.
|
||||||
|
for (String str : allIncludeDirectives) {
|
||||||
|
insertText += str + lineSep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Existing include directives must not be reordered.
|
||||||
|
|
||||||
|
// Compare the list of existing include directives with the list of required include directives.
|
||||||
|
// TODO: Implement this. The following code template may be used for that:
|
||||||
|
/*for (IInclude includeDirective : fTu.getIncludes()) {
|
||||||
|
if (!allIncludeDirectives.contains(includeDirective)) {
|
||||||
|
// This include directive from the editor isn't present within the list of required includes and is therefore unused.
|
||||||
|
// Remove it from the editor, if enabled within the preferences.
|
||||||
|
if (OrganizeIncludesPreferences.getPreferenceStore().getBoolean(PREF_REMOVE_UNUSED_INCLUDES)) {
|
||||||
|
removeIncludeDirective(fTu, includeDirective);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This include directive from the editor is required. Remove it from the list of required includes.
|
||||||
|
allIncludeDirectives.remove(includeDirective);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// Insert those includes which still remain within the list of required includes (i.e. those include directives which have
|
||||||
|
// been added now).
|
||||||
|
for (String str : allIncludeDirectives) {
|
||||||
|
insertText += str + lineSep;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert forward declarations.
|
||||||
|
for (String str : forwardDeclarations) {
|
||||||
|
insertText += str + lineSep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!insertText.isEmpty()) {
|
||||||
|
// Insert the text plus a separating blank line into the editor.
|
||||||
|
insertText = insertText.trim() + lineSep + lineSep;
|
||||||
|
fBuffer.replace(0, 0, insertText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<IBinding> removeBindingsDefinedInIncludedHeaders(Set<IBinding> bindings,
|
||||||
|
IIndexFileSet reachableHeaders) throws CoreException {
|
||||||
|
Set<IBinding> filteredBindings = new HashSet<IBinding>(bindings);
|
||||||
|
|
||||||
|
List<InclusionRequest> requests = createInclusionRequests(bindings, reachableHeaders);
|
||||||
|
Set<IPath> allIncludedHeaders = new HashSet<IPath>();
|
||||||
|
allIncludedHeaders.addAll(fContext.getHeadersAlreadyIncluded());
|
||||||
|
allIncludedHeaders.addAll(fContext.getHeadersToInclude());
|
||||||
|
|
||||||
|
for (InclusionRequest request : requests) {
|
||||||
|
if (isSatisfiedByIncludedHeaders(request, allIncludedHeaders))
|
||||||
|
filteredBindings.remove(request.getBinding());
|
||||||
|
}
|
||||||
|
return filteredBindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isSatisfiedByIncludedHeaders(InclusionRequest request, Set<IPath> includedHeaders)
|
||||||
|
throws CoreException {
|
||||||
|
for (IIndexFile file : request.getDeclaringFiles().keySet()) {
|
||||||
|
IIndexInclude[] includedBy = fContext.getIndex().findIncludedBy(file, IIndex.DEPTH_INFINITE);
|
||||||
|
for (IIndexInclude include : includedBy) {
|
||||||
|
IPath path = getPath(include.getIncludedByLocation());
|
||||||
|
if (includedHeaders.contains(path)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processInclusionRequests(List<InclusionRequest> requests,
|
||||||
|
HeaderSubstitutor headerSubstitutor) {
|
||||||
|
// Add partner header if necessary.
|
||||||
|
HashSet<IIndexFile> partnerIndexFiles = new HashSet<IIndexFile>();
|
||||||
|
for (InclusionRequest request : requests) {
|
||||||
|
List<IPath> candidatePaths = request.getCandidatePaths();
|
||||||
|
if (candidatePaths.size() == 1) {
|
||||||
|
IPath path = candidatePaths.iterator().next();
|
||||||
|
if (isPartnerFile(path)) {
|
||||||
|
request.resolve(path);
|
||||||
|
fContext.addHeaderToInclude(path);
|
||||||
|
try {
|
||||||
|
IIndexFile indexFile = request.getDeclaringFiles().keySet().iterator().next();
|
||||||
|
if (!partnerIndexFiles.contains(indexFile)) {
|
||||||
|
for (IIndexInclude include : indexFile.getIncludes()) {
|
||||||
|
fContext.addHeaderAlreadyIncluded(getPath(include.getIncludesLocation()));
|
||||||
|
}
|
||||||
|
partnerIndexFiles.add(indexFile);
|
||||||
|
}
|
||||||
|
} catch (CoreException e) {
|
||||||
|
CUIPlugin.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process headers that are either indirectly included or have unique representatives.
|
||||||
|
for (InclusionRequest request : requests) {
|
||||||
|
if (!request.isResolved()) {
|
||||||
|
List<IPath> candidatePaths = request.getCandidatePaths();
|
||||||
|
Set<IPath> representativeHeaders = new HashSet<IPath>();
|
||||||
|
boolean allRepresented = true;
|
||||||
|
for (IPath path : candidatePaths) {
|
||||||
|
if (fContext.isIncluded(path)) {
|
||||||
|
request.resolve(path);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
IPath header = headerSubstitutor.getUniqueRepresentativeHeader(path);
|
||||||
|
if (header != null) {
|
||||||
|
representativeHeaders.add(header);
|
||||||
|
} else {
|
||||||
|
allRepresented = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!request.isResolved() && allRepresented && representativeHeaders.size() == 1) {
|
||||||
|
IPath path = representativeHeaders.iterator().next();
|
||||||
|
request.resolve(path);
|
||||||
|
if (!fContext.isAlreadyIncluded(path))
|
||||||
|
fContext.addHeaderToInclude(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process remaining unambiguous inclusion requests.
|
||||||
|
for (InclusionRequest request : requests) {
|
||||||
|
if (!request.isResolved()) {
|
||||||
|
List<IPath> candidatePaths = request.getCandidatePaths();
|
||||||
|
if (candidatePaths.size() == 1) {
|
||||||
|
IPath path = candidatePaths.iterator().next();
|
||||||
|
if (fContext.isIncluded(path)) {
|
||||||
|
request.resolve(path);
|
||||||
|
} else {
|
||||||
|
IPath header = headerSubstitutor.getPreferredRepresentativeHeader(path);
|
||||||
|
if (header.equals(path) && fContext.getPreferences().heuristicHeaderSubstitution) {
|
||||||
|
header = headerSubstitutor.getPreferredRepresentativeHeaderByHeuristic(request);
|
||||||
|
}
|
||||||
|
request.resolve(header);
|
||||||
|
if (!fContext.isAlreadyIncluded(header))
|
||||||
|
fContext.addHeaderToInclude(header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve ambiguous inclusion requests.
|
||||||
|
|
||||||
|
// Maps a set of header files presented to the user to the file selected by the user.
|
||||||
|
HashMap<Collection<IPath>, IPath> userChoiceCache = new HashMap<Collection<IPath>, IPath>();
|
||||||
|
|
||||||
|
for (InclusionRequest request : requests) {
|
||||||
|
if (!request.isResolved()) {
|
||||||
|
List<IPath> candidatePaths = request.getCandidatePaths();
|
||||||
|
for (IPath path : candidatePaths) {
|
||||||
|
if (fContext.isIncluded(path)) {
|
||||||
|
request.resolve(path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IPath header = askUserToSelectHeader(request.getBinding(), candidatePaths, userChoiceCache);
|
||||||
|
request.resolve(header);
|
||||||
|
if (!fContext.isAlreadyIncluded(header))
|
||||||
|
fContext.addHeaderToInclude(header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IPath getPath(IIndexFileLocation location) {
|
||||||
|
return IndexLocationFactory.getAbsolutePath(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given path points to a partner header of the current translation unit.
|
||||||
|
* A header is considered a partner if its name without extension is the same as the name of
|
||||||
|
* the translation unit, or the name of the translation unit differs by one of the suffixes
|
||||||
|
* used for test files.
|
||||||
|
*/
|
||||||
|
private boolean isPartnerFile(IPath path) {
|
||||||
|
String headerName = path.removeFileExtension().lastSegment();
|
||||||
|
String sourceName = fContext.getTranslationUnit().getLocation().removeFileExtension().lastSegment();
|
||||||
|
if (headerName.equals(sourceName))
|
||||||
|
return true;
|
||||||
|
if (sourceName.startsWith(headerName)) {
|
||||||
|
int pos = headerName.length();
|
||||||
|
while (pos < sourceName.length() && !Character.isLetterOrDigit(sourceName.charAt(pos))) {
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
if (pos == sourceName.length())
|
||||||
|
return true;
|
||||||
|
String suffix = sourceName.substring(pos);
|
||||||
|
for (String s : PARTNER_FILE_SUFFIXES) {
|
||||||
|
if (suffix.equalsIgnoreCase(s))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<InclusionRequest> createInclusionRequests(Set<IBinding> bindingsToDefine,
|
||||||
|
IIndexFileSet reachableHeaders) throws CoreException {
|
||||||
|
List<InclusionRequest> requests = new ArrayList<InclusionRequest>(bindingsToDefine.size());
|
||||||
|
IIndex index = fContext.getIndex();
|
||||||
|
|
||||||
|
binding_loop: for (IBinding binding : bindingsToDefine) {
|
||||||
|
IIndexName[] indexNames;
|
||||||
|
if (binding instanceof IFunction) {
|
||||||
|
// For functions we need to include the declaration.
|
||||||
|
indexNames = index.findDeclarations(binding);
|
||||||
|
} else {
|
||||||
|
// For all other bindings we need to include the definition.
|
||||||
|
indexNames = index.findDefinitions(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indexNames.length != 0) {
|
||||||
|
// Check whether the index name is (also) present within the current file.
|
||||||
|
// If yes, we don't need to include anything.
|
||||||
|
for (IIndexName indexName : indexNames) {
|
||||||
|
IIndexFile indexFile = indexName.getFile();
|
||||||
|
if (indexFile.getLocation().getURI().equals(fContext.getTranslationUnit().getLocationURI())) {
|
||||||
|
continue binding_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<IIndexFile, IPath> declaringHeaders = new HashMap<IIndexFile, IPath>();
|
||||||
|
Map<IIndexFile, IPath> reachableDeclaringHeaders = new HashMap<IIndexFile, IPath>();
|
||||||
|
for (IIndexName indexName : indexNames) {
|
||||||
|
IIndexFile indexFile = indexName.getFile();
|
||||||
|
if (IncludeUtil.isSource(indexFile, fContext.getProject()) &&
|
||||||
|
index.findIncludedBy(indexFile, 0).length == 0) {
|
||||||
|
// The target is a source file which isn't included by any other files.
|
||||||
|
// Don't include it.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
IPath path = getPath(indexFile.getLocation());
|
||||||
|
declaringHeaders.put(indexFile, path);
|
||||||
|
if (reachableHeaders.contains(indexFile))
|
||||||
|
reachableDeclaringHeaders.put(indexFile, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!declaringHeaders.isEmpty()) {
|
||||||
|
boolean reachable = false;
|
||||||
|
if (!reachableDeclaringHeaders.isEmpty()) {
|
||||||
|
reachable = true;
|
||||||
|
declaringHeaders = reachableDeclaringHeaders;
|
||||||
|
}
|
||||||
|
requests.add(new InclusionRequest(binding, declaringHeaders, reachable));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return requests;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the line separator for the given buffer.
|
||||||
|
* @param fBuffer
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String getLineSeparator(IBuffer fBuffer) {
|
||||||
|
try {
|
||||||
|
if (fBuffer instanceof IAdaptable) {
|
||||||
|
IDocument doc= (IDocument) ((IAdaptable) fBuffer).getAdapter(IDocument.class);
|
||||||
|
if (doc != null) {
|
||||||
|
String delim= doc.getLineDelimiter(0);
|
||||||
|
if (delim != null) {
|
||||||
|
return delim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
}
|
||||||
|
return System.getProperty("line.separator", "\n"); //$NON-NLS-1$//$NON-NLS-2$
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Picks a suitable header file that should be used to include the given binding.
|
||||||
|
*
|
||||||
|
* @param binding The binding which should be resolved.
|
||||||
|
* @param headers The available header files to pick from.
|
||||||
|
* @param userChoiceCache the cache of previous user choices
|
||||||
|
* @return The chosen header file.
|
||||||
|
*/
|
||||||
|
private IPath askUserToSelectHeader(IBinding binding, Collection<IPath> headers,
|
||||||
|
HashMap<Collection<IPath>, IPath> userChoiceCache) {
|
||||||
|
if (headers.isEmpty())
|
||||||
|
return null;
|
||||||
|
if (headers.size() == 1)
|
||||||
|
return headers.iterator().next();
|
||||||
|
|
||||||
|
// Check the decision cache. If the cache doesn't help, ask the user.
|
||||||
|
// Query the cache.
|
||||||
|
if (userChoiceCache.containsKey(headers)) {
|
||||||
|
return userChoiceCache.get(headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ask the user.
|
||||||
|
final IPath[] elemArray = headers.toArray(new IPath[headers.size()]);
|
||||||
|
final IPath[] selectedElement = new IPath[1];
|
||||||
|
final String bindingName = binding.getName();
|
||||||
|
runInUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
ElementListSelectionDialog dialog =
|
||||||
|
new ElementListSelectionDialog(fEditor.getSite().getShell(), new LabelProvider());
|
||||||
|
dialog.setElements(elemArray);
|
||||||
|
dialog.setTitle(CEditorMessages.OrganizeIncludes_label);
|
||||||
|
dialog.setMessage(NLS.bind(Messages.IncludeOrganizer_ChooseHeader, bindingName));
|
||||||
|
if (dialog.open() == Window.OK) {
|
||||||
|
selectedElement[0] = (IPath) dialog.getFirstResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
IPath selectedHeader = selectedElement[0];
|
||||||
|
|
||||||
|
if (selectedHeader == null)
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
|
||||||
|
userChoiceCache.put(headers, selectedHeader); // Remember user's choice.
|
||||||
|
return selectedHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runInUIThread(Runnable runnable) {
|
||||||
|
if (Display.getCurrent() != null) {
|
||||||
|
runnable.run();
|
||||||
|
} else {
|
||||||
|
Display.getDefault().syncExec(runnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an include directive.
|
||||||
|
* @param headerFile The header file which should be included.
|
||||||
|
* @param relativeIncludeDirectives Out parameter. The list of relative headers to include.
|
||||||
|
* @param projectIncludeDirectives Out parameter. The list of project headers to include.
|
||||||
|
* @param libraryIncludeDirectives Out parameter. The list of library headers to include.
|
||||||
|
* @throws CoreException
|
||||||
|
*/
|
||||||
|
private void createIncludeDirective(IPath headerFile,
|
||||||
|
Collection<String> relativeIncludeDirectives,
|
||||||
|
Collection<String> projectIncludeDirectives,
|
||||||
|
Collection<String> libraryIncludeDirectives) throws CoreException {
|
||||||
|
IPath targetLocation = headerFile;
|
||||||
|
IPath targetDirectory = targetLocation.removeLastSegments(1);
|
||||||
|
targetDirectory = new Path(PathCanonicalizationStrategy.getCanonicalPath(targetDirectory.toFile()));
|
||||||
|
IPath sourceDirectory = fContext.getCurrentDirectory();
|
||||||
|
sourceDirectory = new Path(PathCanonicalizationStrategy.getCanonicalPath(sourceDirectory.toFile()));
|
||||||
|
|
||||||
|
IncludePreferences preferences = fContext.getPreferences();
|
||||||
|
boolean relativeToSource = false;
|
||||||
|
if (preferences.relativeHeaderInSameDir &&
|
||||||
|
PathUtil.equalPath(sourceDirectory, targetDirectory)) {
|
||||||
|
// The header is located within the same directory as the source file.
|
||||||
|
relativeToSource = true;
|
||||||
|
} else if (preferences.relativeHeaderInSubdir &&
|
||||||
|
PathUtil.isPrefix(sourceDirectory, targetLocation)) {
|
||||||
|
// The header is located within a subdirectory of the source file's directory.
|
||||||
|
relativeToSource = true;
|
||||||
|
} else if (preferences.relativeHeaderInParentDir &&
|
||||||
|
PathUtil.isPrefix(targetDirectory, sourceDirectory)) {
|
||||||
|
// The header is located within a parent directory of the source file's directory.
|
||||||
|
relativeToSource = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
IncludeInfo includeInfo = null;
|
||||||
|
if (!relativeToSource)
|
||||||
|
includeInfo = fContext.getIncludeForHeaderFile(targetLocation);
|
||||||
|
Collection<String> headerList;
|
||||||
|
if (includeInfo != null) {
|
||||||
|
headerList = includeInfo.isSystem() ? libraryIncludeDirectives : projectIncludeDirectives;
|
||||||
|
} else {
|
||||||
|
// Include the header relative to the source file.
|
||||||
|
includeInfo = new IncludeInfo(PathUtil.makeRelativePath(targetLocation, sourceDirectory).toPortableString());
|
||||||
|
// Add this header to the relative headers.
|
||||||
|
headerList = relativeIncludeDirectives;
|
||||||
|
}
|
||||||
|
|
||||||
|
headerList.add("#include " + includeInfo.toString()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,319 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2012 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jface.preference.IPreferenceStore;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
|
import org.eclipse.cdt.ui.PreferenceConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preferences for managing of includes.
|
||||||
|
*/
|
||||||
|
public class IncludePreferences {
|
||||||
|
public final boolean allowReordering;
|
||||||
|
public final boolean forwardDeclareCompositeTypes;
|
||||||
|
public final boolean forwardDeclareEnums;
|
||||||
|
public final boolean forwardDeclareFunctions;
|
||||||
|
public final boolean forwardDeclareNamespaceElements;
|
||||||
|
public final boolean relativeHeaderInSameDir;
|
||||||
|
public final boolean relativeHeaderInSubdir;
|
||||||
|
public final boolean relativeHeaderInParentDir;
|
||||||
|
public final boolean heuristicHeaderSubstitution;
|
||||||
|
public final boolean separateIncludeBlocks;
|
||||||
|
public final boolean sortAlphabetically;
|
||||||
|
public final boolean removeUnusedIncludes;
|
||||||
|
public final boolean commentOutUnusedIncludes;
|
||||||
|
public final boolean sortByHeaderLocation;
|
||||||
|
public final List<IncludeType> groupOrder; // TODO(sprigogin): Change to IncludeGroupOrder
|
||||||
|
|
||||||
|
public static enum IncludeGroupType {
|
||||||
|
SIBLING_HEADER, HEADERS_IN_SAME_FOLDER, HEADERS_IN_SUBFOLDERS,
|
||||||
|
SYSTEM_HEADERS, SYSTEM_C_HEADERS, SYSTEM_CPP_HEADERS,
|
||||||
|
PROJECT_HEADERS, EXTERNAL_HEADERS, SPECIAL_HEADERS,
|
||||||
|
TYPE_FORWARD_DECLARATIONS, FUNCTION_FORWARD_DECLARATIONS, USING_DECLARATIONS
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GroupStyle {
|
||||||
|
public boolean useRelativePath;
|
||||||
|
public boolean useAngleBrackets;
|
||||||
|
public boolean separateByBlankLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IncludePreferences(ICProject project) {
|
||||||
|
forwardDeclareCompositeTypes = PreferenceConstants.getPreference(
|
||||||
|
PREF_FORWARD_DECLARE_COMPOSITE_TYPES, project, true);
|
||||||
|
forwardDeclareEnums = PreferenceConstants.getPreference(
|
||||||
|
PREF_FORWARD_DECLARE_ENUMS, project, false);
|
||||||
|
forwardDeclareFunctions = PreferenceConstants.getPreference(
|
||||||
|
PREF_FORWARD_DECLARE_FUNCTIONS, project, false);
|
||||||
|
forwardDeclareNamespaceElements = PreferenceConstants.getPreference(
|
||||||
|
PREF_FORWARD_DECLARE_NAMESPACE_ELEMENTS, project, true);
|
||||||
|
|
||||||
|
// Relative headers preferences
|
||||||
|
relativeHeaderInSameDir = PreferenceConstants.getPreference(
|
||||||
|
PREF_RELATIVE_HEADER_IN_SAME_DIR, project, false);
|
||||||
|
relativeHeaderInSubdir = PreferenceConstants.getPreference(
|
||||||
|
PREF_RELATIVE_HEADER_IN_SUB_DIR, project, false);
|
||||||
|
relativeHeaderInParentDir = PreferenceConstants.getPreference(
|
||||||
|
PREF_RELATIVE_HEADER_IN_PARENT_DIR, project, false);
|
||||||
|
|
||||||
|
// Header resolution preferences
|
||||||
|
heuristicHeaderSubstitution = PreferenceConstants.getPreference(
|
||||||
|
PREF_HEURISTIC_HEADER_SUBSTITUTION, project, true);
|
||||||
|
|
||||||
|
// Header sort order preferences
|
||||||
|
allowReordering = PreferenceConstants.getPreference(
|
||||||
|
PREF_ALLOW_TO_REORDER_INCLUDES, project, true);
|
||||||
|
sortByHeaderLocation = PreferenceConstants.getPreference(
|
||||||
|
PREF_SORT_BY_HEADER_LOCATION, project, true);
|
||||||
|
String order = PreferenceConstants.getPreference(
|
||||||
|
PREF_HEADER_LOCATION_SORT_ORDER, project,
|
||||||
|
IncludeType.RELATIVE_HEADER.toString() + ',' +
|
||||||
|
IncludeType.LIBRARY_HEADER.toString() + ',' +
|
||||||
|
IncludeType.PROJECT_HEADER.toString() + ',' +
|
||||||
|
IncludeType.FORWARD_DECLARATION.toString() + ',' +
|
||||||
|
IncludeType.FUNCTION_FORWARD_DECLARATION.toString());
|
||||||
|
String[] textSortOrder = order.split(","); //$NON-NLS-1$
|
||||||
|
List<IncludeType> list = new ArrayList<IncludeType>(textSortOrder.length);
|
||||||
|
for (String type : textSortOrder) {
|
||||||
|
list.add(IncludeType.valueOf(type));
|
||||||
|
}
|
||||||
|
groupOrder = Collections.unmodifiableList(list);
|
||||||
|
|
||||||
|
separateIncludeBlocks = PreferenceConstants.getPreference(
|
||||||
|
PREF_SEPARATE_INCLUDE_BLOCKS, project, true);
|
||||||
|
sortAlphabetically = PreferenceConstants.getPreference(
|
||||||
|
PREF_SORT_ALPHABETICALLY, project, true);
|
||||||
|
|
||||||
|
// Unused include handling preferences
|
||||||
|
removeUnusedIncludes = PreferenceConstants.getPreference(
|
||||||
|
PREF_REMOVE_UNUSED_INCLUDES, project, false);
|
||||||
|
commentOutUnusedIncludes = PreferenceConstants.getPreference(
|
||||||
|
PREF_COMMENT_OUT_UNUSED_INCLUDES, project, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(sprigogin): Move the constants and defaults to PreferenceConstants.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumerates the different types of code constructs which the organize includes action can
|
||||||
|
* generate.
|
||||||
|
*/
|
||||||
|
public enum IncludeType {
|
||||||
|
/**
|
||||||
|
* A header which is located within the current file's directory.
|
||||||
|
*/
|
||||||
|
RELATIVE_HEADER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A header which is located within the current file's project directory.
|
||||||
|
*/
|
||||||
|
PROJECT_HEADER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A (library) header which is located outside of the current file's project directory.
|
||||||
|
*/
|
||||||
|
LIBRARY_HEADER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A forward declaration.
|
||||||
|
*/
|
||||||
|
FORWARD_DECLARATION,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A forward declaration of a function.
|
||||||
|
*/
|
||||||
|
FUNCTION_FORWARD_DECLARATION,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A problem like e.g. an unresolved symbol.
|
||||||
|
*/
|
||||||
|
FOUND_PROBLEM
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumerates the different options for having a protection against multiple header file
|
||||||
|
* inclusion.
|
||||||
|
*/
|
||||||
|
public enum MultipleInclusionProtectionType {
|
||||||
|
/**
|
||||||
|
* No protection against multiple header file inclusion.
|
||||||
|
*/
|
||||||
|
NONE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use include guards to avoid multiple header file inclusion.
|
||||||
|
*/
|
||||||
|
INCLUDE_GUARDS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use pragma once to avoid multiple header file inclusion.
|
||||||
|
*/
|
||||||
|
PRAGMA_ONCE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether composite types should be forward declared if possible.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* class X;
|
||||||
|
* struct Y;
|
||||||
|
* union Z;
|
||||||
|
*/
|
||||||
|
public static final String PREF_FORWARD_DECLARE_COMPOSITE_TYPES = "forward_declare_composite_types"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether C++11-style enums should be forward declared if possible.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* enum class X;
|
||||||
|
*/
|
||||||
|
public static final String PREF_FORWARD_DECLARE_ENUMS = "forward_declare_enums"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether C-style functions should be forward declared if possible.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* void foo();
|
||||||
|
*/
|
||||||
|
public static final String PREF_FORWARD_DECLARE_FUNCTIONS = "forward_declare_functions"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether elements nested within namespaces should be forward declared if possible.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* namespace N { class X; }
|
||||||
|
*/
|
||||||
|
public static final String PREF_FORWARD_DECLARE_NAMESPACE_ELEMENTS = "forward_declare_namespace_elements"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether headers located within the same directory as the source file should always
|
||||||
|
* be included relative to the source file.
|
||||||
|
*/
|
||||||
|
public static final String PREF_RELATIVE_HEADER_IN_SAME_DIR = "relative_header_in_same_dir"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether headers located within a subdirectory of the source file's directory should always
|
||||||
|
* be included relative to the source file.
|
||||||
|
*/
|
||||||
|
public static final String PREF_RELATIVE_HEADER_IN_SUB_DIR = "relative_header_in_sub_dir"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether headers located within a parent directory of the source file's directory should
|
||||||
|
* always be included relative to the source file.
|
||||||
|
*/
|
||||||
|
public static final String PREF_RELATIVE_HEADER_IN_PARENT_DIR = "relative_header_in_parent_dir"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a heuristic approach should be used to resolve C++ header files. The heuristic
|
||||||
|
* prefers headers which have no file extension and / or are named like the symbol which should
|
||||||
|
* be defined. This often works out nicely since it's a commonly used naming convention for C++
|
||||||
|
* (library) headers.
|
||||||
|
*/
|
||||||
|
public static final String PREF_HEURISTIC_HEADER_SUBSTITUTION = "heuristic_header_resolution"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether it's allowed to reorder existing include directives. If this is set to false,
|
||||||
|
* the original order is kept as far as possible. This may be necessary to avoid breaking code
|
||||||
|
* which makes assumptions about the order of the include directives. If this is set to true,
|
||||||
|
* a different sort order can be applied. Also see the other sort order preferences for further
|
||||||
|
* details.
|
||||||
|
*/
|
||||||
|
public static final String PREF_ALLOW_TO_REORDER_INCLUDES = "allow_to_reorder_includes"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the include directives should be sorted by header file location. Ignored if
|
||||||
|
* PREF_ALLOW_TO_REORDER_INCLUDES is false.
|
||||||
|
*/
|
||||||
|
public static final String PREF_SORT_BY_HEADER_LOCATION = "sort_by_header_location"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the header location sort order. Ignored if either PREF_ALLOW_TO_REORDER_INCLUDES or
|
||||||
|
* PREF_SORT_BY_HEADER_LOCATION is false. An example location sort order would be:
|
||||||
|
* Relative headers > Project headers > Library headers > Forward declarations
|
||||||
|
*/
|
||||||
|
public static final String PREF_HEADER_LOCATION_SORT_ORDER = "header_location_sort_order"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the different blocks of include directives should be separated by a blank line.
|
||||||
|
* Ignored if either PREF_ALLOW_TO_REORDER_INCLUDES or PREF_SORT_BY_HEADER_LOCATION is false.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* // Relative headers
|
||||||
|
* #include "..."
|
||||||
|
*
|
||||||
|
* // Project headers
|
||||||
|
* #include "..."
|
||||||
|
*
|
||||||
|
* // Library headers
|
||||||
|
* #include <...>
|
||||||
|
*
|
||||||
|
* // Forward declarations
|
||||||
|
* class ...;
|
||||||
|
*/
|
||||||
|
public static final String PREF_SEPARATE_INCLUDE_BLOCKS = "separate_include_blocks"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the include directives should be sorted alphabetically. Ignored if
|
||||||
|
* PREF_ALLOW_TO_REORDER_INCLUDES is false.
|
||||||
|
*/
|
||||||
|
public static final String PREF_SORT_ALPHABETICALLY = "sort_alphabetically"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether any unused include directives and forward declarations should be removed. It might be
|
||||||
|
* helpful to disable this if some include directives tend to become removed incorrectly, as it
|
||||||
|
* might happen when using e.g. conditional compilations.
|
||||||
|
*/
|
||||||
|
public static final String PREF_REMOVE_UNUSED_INCLUDES = "remove_unused_includes"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
public static final String PREF_COMMENT_OUT_UNUSED_INCLUDES = "comment_out_unused_includes"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the given preference store with the default values.
|
||||||
|
*
|
||||||
|
* @param store the preference store to be initialized
|
||||||
|
*/
|
||||||
|
public static void initializeDefaultValues(IPreferenceStore store) {
|
||||||
|
store.setDefault(PREF_FORWARD_DECLARE_COMPOSITE_TYPES, true);
|
||||||
|
store.setDefault(PREF_FORWARD_DECLARE_ENUMS, false);
|
||||||
|
store.setDefault(PREF_FORWARD_DECLARE_FUNCTIONS, false);
|
||||||
|
store.setDefault(PREF_FORWARD_DECLARE_NAMESPACE_ELEMENTS, true);
|
||||||
|
|
||||||
|
// Relative headers preferences
|
||||||
|
store.setDefault(PREF_RELATIVE_HEADER_IN_SAME_DIR, false);
|
||||||
|
store.setDefault(PREF_RELATIVE_HEADER_IN_SUB_DIR, false);
|
||||||
|
store.setDefault(PREF_RELATIVE_HEADER_IN_PARENT_DIR, false);
|
||||||
|
|
||||||
|
// Header resolution preferences
|
||||||
|
store.setDefault(PREF_HEURISTIC_HEADER_SUBSTITUTION, true);
|
||||||
|
|
||||||
|
// Header sort order preferences
|
||||||
|
store.setDefault(PREF_ALLOW_TO_REORDER_INCLUDES, true);
|
||||||
|
store.setDefault(PREF_SORT_BY_HEADER_LOCATION, true);
|
||||||
|
store.setDefault(PREF_HEADER_LOCATION_SORT_ORDER,
|
||||||
|
IncludeType.RELATIVE_HEADER.toString() + ' ' +
|
||||||
|
IncludeType.LIBRARY_HEADER.toString() + ' ' +
|
||||||
|
IncludeType.PROJECT_HEADER.toString() + ' ' +
|
||||||
|
IncludeType.FORWARD_DECLARATION.toString() + ' ' +
|
||||||
|
IncludeType.FUNCTION_FORWARD_DECLARATION.toString() + ' ' +
|
||||||
|
IncludeType.FOUND_PROBLEM.toString());
|
||||||
|
store.setDefault(PREF_SEPARATE_INCLUDE_BLOCKS, true);
|
||||||
|
store.setDefault(PREF_SORT_ALPHABETICALLY, true);
|
||||||
|
|
||||||
|
// Unused include handling preferences
|
||||||
|
store.setDefault(PREF_REMOVE_UNUSED_INCLUDES, true);
|
||||||
|
store.setDefault(PREF_COMMENT_OUT_UNUSED_INCLUDES, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2012 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.content.IContentType;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexFile;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexFileLocation;
|
||||||
|
import org.eclipse.cdt.core.index.IndexLocationFactory;
|
||||||
|
|
||||||
|
public class IncludeUtil {
|
||||||
|
/** Not instantiatable. All methods are static. */
|
||||||
|
private IncludeUtil() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a file is a source file (.c, .cpp, .cc, etc). Header files are not considered
|
||||||
|
* source files.
|
||||||
|
* @return Returns {@code true} if the the file is a source file.
|
||||||
|
*/
|
||||||
|
public static boolean isSource(IIndexFile file, IProject project) throws CoreException {
|
||||||
|
return isSource(getPath(file), project);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a file is a source file (.c, .cpp, .cc, etc). Header files are not considered
|
||||||
|
* source files.
|
||||||
|
* @return Returns {@code true} if the the file is a source file.
|
||||||
|
*/
|
||||||
|
public static boolean isSource(String filename, IProject project) {
|
||||||
|
IContentType ct= CCorePlugin.getContentType(project, filename);
|
||||||
|
if (ct != null) {
|
||||||
|
String id = ct.getId();
|
||||||
|
if (CCorePlugin.CONTENT_TYPE_CSOURCE.equals(id) || CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path of the given index file.
|
||||||
|
* @param file The index file.
|
||||||
|
* @return The path.
|
||||||
|
*/
|
||||||
|
public static String getPath(IIndexFile file) throws CoreException {
|
||||||
|
return getPath(file.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path of the given index file.
|
||||||
|
* @param fileLocation The index file location.
|
||||||
|
* @return The path.
|
||||||
|
*/
|
||||||
|
public static String getPath(IIndexFileLocation fileLocation) {
|
||||||
|
return IndexLocationFactory.getAbsolutePath(fileLocation).toOSString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,186 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2012 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
import org.eclipse.core.runtime.Path;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.index.IIndex;
|
||||||
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
|
import org.eclipse.cdt.core.parser.IScannerInfo;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
|
||||||
|
import org.eclipse.cdt.internal.core.parser.scanner.IncludeSearchPath;
|
||||||
|
import org.eclipse.cdt.internal.core.parser.scanner.IncludeSearchPathElement;
|
||||||
|
import org.eclipse.cdt.internal.core.parser.scanner.ScannerUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context for managing include statements.
|
||||||
|
*/
|
||||||
|
public class InclusionContext {
|
||||||
|
private static final IPath UNRESOLVED_INCLUDE = new Path(""); //$NON-NLS-1$
|
||||||
|
|
||||||
|
private final ITranslationUnit fTu;
|
||||||
|
private final IProject fProject;
|
||||||
|
private final IPath fCurrentDirectory;
|
||||||
|
private final IncludePreferences fPreferences;
|
||||||
|
private final IncludeSearchPath fIncludeSearchPath;
|
||||||
|
private final Map<IncludeInfo, IPath> fIncludeResolutionCache;
|
||||||
|
private final Map<IPath, IncludeInfo> fInverseIncludeResolutionCache;
|
||||||
|
private final IIndex fIndex;
|
||||||
|
private final Set<IPath> fHeadersToInclude;
|
||||||
|
private final Set<IPath> fHeadersAlreadyIncluded;
|
||||||
|
|
||||||
|
public InclusionContext(ITranslationUnit tu, IIndex index) {
|
||||||
|
fTu = tu;
|
||||||
|
fIndex = index;
|
||||||
|
ICProject cProject = fTu.getCProject();
|
||||||
|
fPreferences = new IncludePreferences(cProject);
|
||||||
|
fProject = cProject.getProject();
|
||||||
|
fCurrentDirectory = fTu.getResource().getParent().getLocation();
|
||||||
|
IScannerInfo scannerInfo = fTu.getScannerInfo(true);
|
||||||
|
fIncludeSearchPath = CPreprocessor.configureIncludeSearchPath(fCurrentDirectory.toFile(), scannerInfo);
|
||||||
|
fIncludeResolutionCache = new HashMap<IncludeInfo, IPath>();
|
||||||
|
fInverseIncludeResolutionCache = new HashMap<IPath, IncludeInfo>();
|
||||||
|
fHeadersToInclude = new HashSet<IPath>();
|
||||||
|
fHeadersAlreadyIncluded = new HashSet<IPath>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITranslationUnit getTranslationUnit() {
|
||||||
|
return fTu;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IIndex getIndex() {
|
||||||
|
return fIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IProject getProject() {
|
||||||
|
return fProject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IncludePreferences getPreferences() {
|
||||||
|
return fPreferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCXXLanguage() {
|
||||||
|
return fTu.isCXXLanguage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPath getCurrentDirectory() {
|
||||||
|
return fCurrentDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPath resolveInclude(IncludeInfo include) {
|
||||||
|
IPath path = fIncludeResolutionCache.get(include);
|
||||||
|
if (path == null) {
|
||||||
|
String directory = fCurrentDirectory.toOSString();
|
||||||
|
String filePath = CPreprocessor.getAbsoluteInclusionPath(include.getName(), directory);
|
||||||
|
if (filePath != null) {
|
||||||
|
path = new Path(filePath);
|
||||||
|
} else if (!include.isSystem() && !fIncludeSearchPath.isInhibitUseOfCurrentFileDirectory()) {
|
||||||
|
// Check to see if we find a match in the current directory.
|
||||||
|
filePath = ScannerUtility.createReconciledPath(directory, include.getName());
|
||||||
|
if (fileExists(filePath)) {
|
||||||
|
path = new Path(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path == null) {
|
||||||
|
for (IncludeSearchPathElement pathElement : fIncludeSearchPath.getElements()) {
|
||||||
|
if (include.isSystem() && pathElement.isForQuoteIncludesOnly())
|
||||||
|
continue;
|
||||||
|
filePath = pathElement.getLocation(include.getName());
|
||||||
|
if (fileExists(filePath)) {
|
||||||
|
path = new Path(filePath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (path == null)
|
||||||
|
path = UNRESOLVED_INCLUDE;
|
||||||
|
fIncludeResolutionCache.put(include, path);
|
||||||
|
fInverseIncludeResolutionCache.put(path, include);
|
||||||
|
}
|
||||||
|
return path == UNRESOLVED_INCLUDE ? null : path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the include directive that resolves to the given header file, or {@code null} if
|
||||||
|
* the file is not on the include search path. Current directory is not considered to be a part
|
||||||
|
* of the include path by this method.
|
||||||
|
*/
|
||||||
|
public IncludeInfo getIncludeForHeaderFile(IPath fullPath) {
|
||||||
|
IncludeInfo include = fInverseIncludeResolutionCache.get(fullPath);
|
||||||
|
if (include != null)
|
||||||
|
return include;
|
||||||
|
String headerLocation = fullPath.toOSString();
|
||||||
|
String shortestInclude = null;
|
||||||
|
boolean isSystem = false;
|
||||||
|
int count = 0; //XXX
|
||||||
|
for (IncludeSearchPathElement pathElement : fIncludeSearchPath.getElements()) {
|
||||||
|
String includeDirective = pathElement.getIncludeDirective(headerLocation);
|
||||||
|
if (includeDirective != null &&
|
||||||
|
(shortestInclude == null || shortestInclude.length() > includeDirective.length())) {
|
||||||
|
shortestInclude = includeDirective;
|
||||||
|
isSystem = !pathElement.isForQuoteIncludesOnly();
|
||||||
|
if (count < 1) //XXX
|
||||||
|
isSystem = false; //XXX Hack to introduce non-system includes
|
||||||
|
}
|
||||||
|
count++; //XXX
|
||||||
|
}
|
||||||
|
if (shortestInclude == null)
|
||||||
|
return null;
|
||||||
|
include = new IncludeInfo(shortestInclude, isSystem);
|
||||||
|
fIncludeResolutionCache.put(include, fullPath);
|
||||||
|
fInverseIncludeResolutionCache.put(fullPath, include);
|
||||||
|
return include;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean fileExists(String absolutePath) {
|
||||||
|
return new File(absolutePath).exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<IPath> getHeadersToInclude() {
|
||||||
|
return fHeadersToInclude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void addHeaderToInclude(IPath header) {
|
||||||
|
fHeadersToInclude.add(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isToBeIncluded(IPath header) {
|
||||||
|
return fHeadersToInclude.contains(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<IPath> getHeadersAlreadyIncluded() {
|
||||||
|
return fHeadersAlreadyIncluded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void addHeaderAlreadyIncluded(IPath header) {
|
||||||
|
fHeadersAlreadyIncluded.add(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isAlreadyIncluded(IPath header) {
|
||||||
|
return fHeadersAlreadyIncluded.contains(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isIncluded(IPath header) {
|
||||||
|
return fHeadersAlreadyIncluded.contains(header) || fHeadersToInclude.contains(header);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2012 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
|
import org.eclipse.cdt.core.index.IIndexFile;
|
||||||
|
|
||||||
|
class InclusionRequest {
|
||||||
|
private final IBinding fBinding;
|
||||||
|
private final Map<IIndexFile, IPath> fDeclaringFiles;
|
||||||
|
private final boolean fReachable;
|
||||||
|
private List<IPath> fCandidatePaths;
|
||||||
|
private IPath fResolvedPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param binding the binding that requires inclusion
|
||||||
|
* @param declaringHeaders headers that can be included to declare the binding and paths
|
||||||
|
* that can be used to include them
|
||||||
|
* @param reachable indicates whether the headers were previously included or not
|
||||||
|
*/
|
||||||
|
public InclusionRequest(IBinding binding, Map<IIndexFile, IPath> declaringHeaders,
|
||||||
|
boolean reachable) {
|
||||||
|
fBinding = binding;
|
||||||
|
fDeclaringFiles = Collections.unmodifiableMap(declaringHeaders);
|
||||||
|
fReachable = reachable;
|
||||||
|
fCandidatePaths = new ArrayList<IPath>(new HashSet<IPath>(fDeclaringFiles.values()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IBinding getBinding() {
|
||||||
|
return fBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<IIndexFile, IPath> getDeclaringFiles() {
|
||||||
|
return fDeclaringFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<IPath> getCandidatePaths() {
|
||||||
|
return fCandidatePaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCandidatePaths(List<IPath> paths) {
|
||||||
|
fCandidatePaths = paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReachable() {
|
||||||
|
return fReachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resolve(IPath path) {
|
||||||
|
if (fResolvedPath != null)
|
||||||
|
throw new IllegalStateException();
|
||||||
|
fResolvedPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPath getResolvedPath() {
|
||||||
|
return fResolvedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isResolved() {
|
||||||
|
return fResolvedPath != null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2012 Google, Inc and others.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
|
import org.eclipse.osgi.util.NLS;
|
||||||
|
|
||||||
|
final class Messages extends NLS {
|
||||||
|
public static String IncludeOrganizer_ChooseHeader;
|
||||||
|
|
||||||
|
static {
|
||||||
|
NLS.initializeMessages(Messages.class.getName(), Messages.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not instantiate
|
||||||
|
private Messages() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
###############################################################################
|
||||||
|
# Copyright (c) 2012 Google, Inc and others.
|
||||||
|
# All rights reserved. This program and the accompanying materials
|
||||||
|
# are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
# which accompanies this distribution, and is available at
|
||||||
|
# http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
#
|
||||||
|
# Contributors:
|
||||||
|
# Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
###############################################################################
|
||||||
|
IncludeOrganizer_ChooseHeader=Choose a header file to include for symbol ''{0}''
|
|
@ -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
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -2232,7 +2232,7 @@ public class PreferenceConstants {
|
||||||
* the workspace setting should be taken. Note that passing {@code null} should
|
* the workspace setting should be taken. Note that passing {@code null} should
|
||||||
* be avoided.
|
* be avoided.
|
||||||
* @param defaultValue The default value if not specified in the preferences.
|
* @param defaultValue The default value if not specified in the preferences.
|
||||||
* @return Returns the current value for the string.
|
* @return Returns the current value of the preference.
|
||||||
* @since 5.1
|
* @since 5.1
|
||||||
*/
|
*/
|
||||||
public static int getPreference(String key, ICProject project, int defaultValue) {
|
public static int getPreference(String key, ICProject project, int defaultValue) {
|
||||||
|
@ -2245,7 +2245,7 @@ public class PreferenceConstants {
|
||||||
* @param project The current context or {@code null} if no context is available and
|
* @param project The current context or {@code null} if no context is available and
|
||||||
* the workspace setting should be taken. Note that passing {@code null} should be avoided.
|
* the workspace setting should be taken. Note that passing {@code null} should be avoided.
|
||||||
* @param defaultValue The default value if not specified in the preferences.
|
* @param defaultValue The default value if not specified in the preferences.
|
||||||
* @return Returns the current value for the string.
|
* @return Returns the current value of the preference.
|
||||||
* @since 5.1
|
* @since 5.1
|
||||||
*/
|
*/
|
||||||
public static boolean getPreference(String key, ICProject project, boolean defaultValue) {
|
public static boolean getPreference(String key, ICProject project, boolean defaultValue) {
|
||||||
|
|
|
@ -52,6 +52,7 @@ import org.eclipse.cdt.internal.ui.actions.CDTQuickMenuCreator;
|
||||||
import org.eclipse.cdt.internal.ui.editor.AddIncludeOnSelectionAction;
|
import org.eclipse.cdt.internal.ui.editor.AddIncludeOnSelectionAction;
|
||||||
import org.eclipse.cdt.internal.ui.editor.CEditor;
|
import org.eclipse.cdt.internal.ui.editor.CEditor;
|
||||||
import org.eclipse.cdt.internal.ui.editor.ICEditorActionDefinitionIds;
|
import org.eclipse.cdt.internal.ui.editor.ICEditorActionDefinitionIds;
|
||||||
|
import org.eclipse.cdt.internal.ui.editor.OrganizeIncludesAction;
|
||||||
import org.eclipse.cdt.internal.ui.editor.SortLinesAction;
|
import org.eclipse.cdt.internal.ui.editor.SortLinesAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,7 +129,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
// private ExternalizeStringsAction fExternalizeStrings;
|
// private ExternalizeStringsAction fExternalizeStrings;
|
||||||
// private CleanUpAction fCleanUp;
|
// private CleanUpAction fCleanUp;
|
||||||
//
|
//
|
||||||
// private OrganizeIncludesAction fOrganizeIncludes;
|
private OrganizeIncludesAction fOrganizeIncludes;
|
||||||
// private SortMembersAction fSortMembers;
|
// private SortMembersAction fSortMembers;
|
||||||
private SortLinesAction fSortLines;
|
private SortLinesAction fSortLines;
|
||||||
private FormatAllAction fFormatAll;
|
private FormatAllAction fFormatAll;
|
||||||
|
@ -158,10 +159,10 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
fAddInclude.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_INCLUDE);
|
fAddInclude.setActionDefinitionId(ICEditorActionDefinitionIds.ADD_INCLUDE);
|
||||||
editor.setAction("AddIncludeOnSelection", fAddInclude); //$NON-NLS-1$
|
editor.setAction("AddIncludeOnSelection", fAddInclude); //$NON-NLS-1$
|
||||||
|
|
||||||
// fOrganizeIncludes= new OrganizeIncludesAction(editor);
|
fOrganizeIncludes= new OrganizeIncludesAction(editor);
|
||||||
// fOrganizeIncludes.setActionDefinitionId(ICEditorActionDefinitionIds.ORGANIZE_INCLUDES);
|
// TODO: fOrganizeIncludes.setActionDefinitionId(ICEditorActionDefinitionIds.ORGANIZE_INCLUDES);
|
||||||
// editor.setAction("OrganizeIncludes", fOrganizeIncludes); //$NON-NLS-1$
|
editor.setAction("OrganizeIncludes", fOrganizeIncludes); //$NON-NLS-1$
|
||||||
//
|
|
||||||
// fSortMembers= new SortMembersAction(editor);
|
// fSortMembers= new SortMembersAction(editor);
|
||||||
// fSortMembers.setActionDefinitionId(ICEditorActionDefinitionIds.SORT_MEMBERS);
|
// fSortMembers.setActionDefinitionId(ICEditorActionDefinitionIds.SORT_MEMBERS);
|
||||||
// editor.setAction("SortMembers", fSortMembers); //$NON-NLS-1$
|
// editor.setAction("SortMembers", fSortMembers); //$NON-NLS-1$
|
||||||
|
@ -431,7 +432,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
added+= addEditorAction(source, "Format"); //$NON-NLS-1$
|
added+= addEditorAction(source, "Format"); //$NON-NLS-1$
|
||||||
source.add(new Separator(GROUP_ORGANIZE));
|
source.add(new Separator(GROUP_ORGANIZE));
|
||||||
added+= addAction(source, fAddInclude);
|
added+= addAction(source, fAddInclude);
|
||||||
// added+= addAction(source, fOrganizeIncludes);
|
added+= addAction(source, fOrganizeIncludes);
|
||||||
// added+= addAction(source, fSortMembers);
|
// added+= addAction(source, fSortMembers);
|
||||||
added+= addAction(source, fSortLines);
|
added+= addAction(source, fSortLines);
|
||||||
// added+= addAction(source, fCleanUp);
|
// added+= addAction(source, fCleanUp);
|
||||||
|
@ -457,7 +458,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
added+= addAction(source, fFormatAll);
|
added+= addAction(source, fFormatAll);
|
||||||
source.add(new Separator(GROUP_ORGANIZE));
|
source.add(new Separator(GROUP_ORGANIZE));
|
||||||
added+= addAction(source, fAddInclude);
|
added+= addAction(source, fAddInclude);
|
||||||
// added+= addAction(source, fOrganizeIncludes);
|
added+= addAction(source, fOrganizeIncludes);
|
||||||
// added+= addAction(source, fSortMembers);
|
// added+= addAction(source, fSortMembers);
|
||||||
// added+= addAction(source, fCleanUp);
|
// added+= addAction(source, fCleanUp);
|
||||||
source.add(new Separator(GROUP_GENERATE));
|
source.add(new Separator(GROUP_GENERATE));
|
||||||
|
@ -506,7 +507,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
// actionBar.setGlobalActionHandler(CdtActionConstants.ADD_CPP_DOC_COMMENT, fAddCppDocStub);
|
// actionBar.setGlobalActionHandler(CdtActionConstants.ADD_CPP_DOC_COMMENT, fAddCppDocStub);
|
||||||
// actionBar.setGlobalActionHandler(CdtActionConstants.EXTERNALIZE_STRINGS, fExternalizeStrings);
|
// actionBar.setGlobalActionHandler(CdtActionConstants.EXTERNALIZE_STRINGS, fExternalizeStrings);
|
||||||
// actionBar.setGlobalActionHandler(CdtActionConstants.CLEAN_UP, fCleanUp);
|
// actionBar.setGlobalActionHandler(CdtActionConstants.CLEAN_UP, fCleanUp);
|
||||||
// actionBar.setGlobalActionHandler(CdtActionConstants.ORGANIZE_INCLUDES, fOrganizeIncludes);
|
// TODO: actionBar.setGlobalActionHandler(CdtActionConstants.ORGANIZE_INCLUDES, fOrganizeIncludes);
|
||||||
// actionBar.setGlobalActionHandler(CdtActionConstants.SORT_MEMBERS, fSortMembers);
|
// actionBar.setGlobalActionHandler(CdtActionConstants.SORT_MEMBERS, fSortMembers);
|
||||||
if (!isEditorOwner()) {
|
if (!isEditorOwner()) {
|
||||||
// editor provides its own implementation of these actions.
|
// editor provides its own implementation of these actions.
|
||||||
|
|
Loading…
Add table
Reference in a new issue