diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemBinding.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemBinding.java
index d5975b3125e..539a53ca79b 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemBinding.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemBinding.java
@@ -29,6 +29,7 @@ import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.Linkage;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.parser.ParserMessages;
import org.eclipse.core.runtime.PlatformObject;
@@ -230,7 +231,7 @@ public class ProblemBinding extends PlatformObject implements IProblemBinding, I
}
public IBinding getOwner() throws DOMException {
- return null;
+ return node instanceof IASTName ? CPPVisitor.findNameOwner((IASTName) node, true) : null;
}
public void setASTNode(IASTName name) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
index cbe9944b9f6..4c4c0515e0a 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
@@ -2010,10 +2010,17 @@ public class CPPVisitor extends ASTQueries {
while (node instanceof IASTName) {
if (node instanceof ICPPASTQualifiedName) {
IASTName[] qn= ((ICPPASTQualifiedName) node).getNames();
- if (qn.length < 2)
- return null;
- return qn[qn.length - 2].resolveBinding();
+ int i = qn.length;
+ while (--i >= 0) {
+ if (qn[i] == name) {
+ break;
+ }
+ }
+ if (--i < 0)
+ break;
+ return qn[i].resolveBinding();
}
+ name = (IASTName) node;
node= node.getParent();
}
return findDeclarationOwner(node, allowFunction);
diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/PathUtil.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/PathUtil.java
index 91b10214c11..feee6716ac9 100644
--- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/PathUtil.java
+++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/PathUtil.java
@@ -9,6 +9,7 @@
* QNX Software Systems - initial API and implementation
* Markus Schorn (Wind River Systems)
* Ed Swartz (Nokia)
+ * Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.utils;
@@ -23,6 +24,7 @@ import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
@@ -65,8 +67,8 @@ public class PathUtil {
IWorkspaceRoot workspaceRoot = getWorkspaceRoot();
if (workspaceRoot != null) {
IPath workspaceLocation = workspaceRoot.getLocation();
- if (workspaceLocation != null && workspaceLocation.isPrefixOf(fullPath)) {
- int segments = fullPath.matchingFirstSegments(workspaceLocation);
+ if (workspaceLocation != null && isPrefix(workspaceLocation, fullPath)) {
+ int segments = matchingFirstSegments(fullPath, workspaceLocation);
IPath relPath = fullPath.setDevice(null).removeFirstSegments(segments);
return new Path("").addTrailingSeparator().append(relPath); //$NON-NLS-1$
}
@@ -76,11 +78,11 @@ public class PathUtil {
public static IPath getProjectRelativePath(IPath fullPath, IProject project) {
IPath projectPath = project.getFullPath();
- if (projectPath.isPrefixOf(fullPath)) {
+ if (isPrefix(projectPath, fullPath)) {
return fullPath.removeFirstSegments(projectPath.segmentCount());
}
projectPath = project.getLocation();
- if (projectPath.isPrefixOf(fullPath)) {
+ if (isPrefix(projectPath, fullPath)) {
return fullPath.removeFirstSegments(projectPath.segmentCount());
}
return getWorkspaceRelativePath(fullPath);
@@ -94,7 +96,7 @@ public class PathUtil {
IWorkspaceRoot workspaceRoot = getWorkspaceRoot();
if (workspaceRoot != null && wsRelativePath != null) {
IPath workspaceLocation = workspaceRoot.getLocation();
- if (workspaceLocation != null && !workspaceLocation.isPrefixOf(wsRelativePath)) {
+ if (workspaceLocation != null && !isPrefix(workspaceLocation, wsRelativePath)) {
return workspaceLocation.append(wsRelativePath);
}
}
@@ -102,7 +104,7 @@ public class PathUtil {
}
public static IPath makeRelativePath(IPath path, IPath relativeTo) {
- int segments = relativeTo.matchingFirstSegments(path);
+ int segments = matchingFirstSegments(relativeTo, path);
if (segments > 0) {
IPath prefix = relativeTo.removeFirstSegments(segments);
IPath suffix = path.removeFirstSegments(segments);
@@ -131,8 +133,8 @@ public class PathUtil {
int mostSegments = 0;
for (int i = 0; i < includePaths.length; ++i) {
IPath includePath = new Path(includePaths[i]);
- if (includePath.isPrefixOf(fullPath)) {
- int segments = includePath.matchingFirstSegments(fullPath);
+ if (isPrefix(includePath, fullPath)) {
+ int segments = includePath.segmentCount();
if (segments > mostSegments) {
relativePath = fullPath.removeFirstSegments(segments).setDevice(null);
mostSegments = segments;
@@ -171,4 +173,104 @@ public class PathUtil {
}
return null;
}
+
+ /**
+ * Checks whether path1 is the same as path2.
+ * @return true
if path1 is the same as path2, and false
otherwise
+ *
+ * Similar to IPath.equals(Object obj), but takes case sensitivity of the file system
+ * into account.
+ * @since 5.1
+ */
+ public boolean equal(IPath path1, IPath path2) {
+ // Check leading separators
+ if (path1.isAbsolute() != path2.isAbsolute() || path1.isUNC() != path2.isUNC()) {
+ return false;
+ }
+ int i = path1.segmentCount();
+ // Check segment count
+ if (i != path2.segmentCount())
+ return false;
+ // Check segments in reverse order - later segments more likely to differ
+ while (--i >= 0) {
+ if (!path1.segment(i).equals(path2.segment(i)))
+ return false;
+ }
+ // Check device last (least likely to differ)
+ if (path1.getDevice() == null) {
+ return path2.getDevice() == null;
+ } else {
+ return path1.getDevice().equalsIgnoreCase(path2.getDevice());
+ }
+ }
+
+ /**
+ * Checks whether path1 is a prefix of path2. To be a prefix, path1's segments
+ * must appear in path1 in the same order, and their device ids must match.
+ *
+ * An empty path is a prefix of all paths with the same device; a root path is a prefix of
+ * all absolute paths with the same device.
+ *
+ * @return true
if path1 is a prefix of path2, and false
otherwise
+ *
+ * Similar to IPath.isPrefixOf(IPath anotherPath), but takes case sensitivity of the file system
+ * into account.
+ * @since 5.1
+ */
+ public static boolean isPrefix(IPath path1, IPath path2) {
+ if (path1.getDevice() == null) {
+ if (path2.getDevice() != null) {
+ return false;
+ }
+ } else {
+ if (!path1.getDevice().equalsIgnoreCase(path2.getDevice())) {
+ return false;
+ }
+ }
+ if (path1.isEmpty() || (path1.isRoot() && path2.isAbsolute())) {
+ return true;
+ }
+ int len1 = path1.segmentCount();
+ if (len1 > path2.segmentCount()) {
+ return false;
+ }
+ boolean caseSensitive = !isWindowsFileSystem();
+ for (int i = 0; i < len1; i++) {
+ if (!(caseSensitive ?
+ path1.segment(i).equals(path2.segment(i)) :
+ path1.segment(i).equalsIgnoreCase(path2.segment(i)))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the number of segments which match in path1 and path2
+ * (device ids are ignored), comparing in increasing segment number order.
+ *
+ * @return the number of matching segments
+
+ * Similar to IPath.matchingFirstSegments(IPath anotherPath), but takes case sensitivity
+ * of the file system into account.
+ * @since 5.1
+ */
+ public static int matchingFirstSegments(IPath path1, IPath path2) {
+ Assert.isNotNull(path1);
+ Assert.isNotNull(path2);
+ int len1 = path1.segmentCount();
+ int len2 = path2.segmentCount();
+ int max = Math.min(len1, len2);
+ int count = 0;
+ boolean caseSensitive = !isWindowsFileSystem();
+ for (int i = 0; i < max; i++) {
+ if (!(caseSensitive ?
+ path1.segment(i).equals(path2.segment(i)) :
+ path1.segment(i).equalsIgnoreCase(path2.segment(i)))) {
+ return count;
+ }
+ count++;
+ }
+ return count;
+ }
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/codemanipulation/AddIncludesOperation.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/codemanipulation/AddIncludesOperation.java
index 6e5b3426872..d4600020e3f 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/codemanipulation/AddIncludesOperation.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/corext/codemanipulation/AddIncludesOperation.java
@@ -8,6 +8,7 @@
* Contributors:
* IBM Corporation - initial API and implementation
* QNX Software Systems
+ * Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.corext.codemanipulation;
@@ -24,6 +25,8 @@ import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.IBuffer;
@@ -43,26 +46,27 @@ import org.eclipse.cdt.internal.ui.editor.CEditorMessages;
* If the translation unit is open in an editor, be sure to pass over its working copy.
*/
public class AddIncludesOperation implements IWorkspaceRunnable {
-
private ITranslationUnit fTranslationUnit;
private IRequiredInclude[] fIncludes;
private String[] fUsings;
private final String fNewLine;
+ private IRegion insertedIncludes;
/**
* Generate include statements for the passed java elements
*/
public AddIncludesOperation(ITranslationUnit tu, IRequiredInclude[] includes, boolean save) {
- this (tu, includes, null, save);
+ this(tu, includes, null, save);
}
/**
* Generate include statements for the passed c elements
*/
- public AddIncludesOperation(ITranslationUnit tu, IRequiredInclude[] includes, String[] using, boolean save) {
+ public AddIncludesOperation(ITranslationUnit tu, IRequiredInclude[] includes, String[] usings,
+ boolean save) {
super();
fIncludes= includes;
- fUsings = using;
+ fUsings = usings;
fTranslationUnit = tu;
fNewLine= getNewLine(tu);
}
@@ -82,10 +86,10 @@ public class AddIncludesOperation implements IWorkspaceRunnable {
} catch (CModelException e) {
} catch (BadLocationException e) {
}
- return System.getProperty("line.separator", "\n"); //$NON-NLS-1$//$NON-NLS-2$ }
+ return System.getProperty("line.separator", "\n"); //$NON-NLS-1$//$NON-NLS-2$
}
- public void executeIncludes(IProgressMonitor monitor) throws CoreException {
+ private void insertIncludes(IProgressMonitor monitor) throws CoreException {
// Sanity
if (fIncludes == null || fIncludes.length == 0) {
return;
@@ -96,122 +100,118 @@ public class AddIncludesOperation implements IWorkspaceRunnable {
monitor.beginTask(CEditorMessages.AddIncludesOperation_description, 2);
- List> elements = fTranslationUnit.getChildrenOfType(ICElement.C_INCLUDE);
- for (int i = 0; i < fIncludes.length; ++i) {
- String name = fIncludes[i].getIncludeName();
+ List elements = fTranslationUnit.getChildrenOfType(ICElement.C_INCLUDE);
+ for (IRequiredInclude include : fIncludes) {
+ String name = include.getIncludeName();
boolean found = false;
- for (int j = 0; j < elements.size(); ++j) {
- IInclude include = (IInclude)elements.get(j);
- if (name.equals(include.getElementName())) {
+ for (ICElement element : elements) {
+ if (name.equals(element.getElementName())) {
found = true;
break;
}
}
if (!found) {
- toAdd.add(fIncludes[i]);
+ toAdd.add(include);
}
}
- if (toAdd.size() > 0) {
+ if (!toAdd.isEmpty()) {
// So we have our list. Now insert.
- StringBuffer insert = new StringBuffer(""); //$NON-NLS-1$
- for(int j = 0; j < toAdd.size(); j++) {
- IRequiredInclude req = toAdd.get(j);
- if (req.isStandard()) {
- insert.append("#include <" + req.getIncludeName() + ">").append(fNewLine); //$NON-NLS-1$ //$NON-NLS-2$
+ StringBuilder buf = new StringBuilder();
+ for (IRequiredInclude include : toAdd) {
+ if (include.isStandard()) {
+ buf.append("#include <" + include.getIncludeName() + ">").append(fNewLine); //$NON-NLS-1$ //$NON-NLS-2$
} else {
- insert.append("#include \"" + req.getIncludeName() + "\"").append(fNewLine); //$NON-NLS-1$ //$NON-NLS-2$
+ buf.append("#include \"" + include.getIncludeName() + "\"").append(fNewLine); //$NON-NLS-1$ //$NON-NLS-2$
}
}
- int pos;
- if (elements.size() > 0) {
- IInclude lastInclude = (IInclude)elements.get(elements.size() - 1);
+ int pos = 0;
+ if (!elements.isEmpty()) {
+ IInclude lastInclude = (IInclude) elements.get(elements.size() - 1);
ISourceRange range = lastInclude.getSourceRange();
pos = range.getStartPos() + range.getLength();
- } else {
- pos = 0;
}
monitor.worked(1);
- replace(pos, insert.toString());
+ replace(pos, buf.toString());
+ insertedIncludes = new Region(pos, buf.length());
monitor.worked(1);
}
}
}
- public void executeUsings(IProgressMonitor monitor) throws CoreException {
+ private void insertUsings(IProgressMonitor monitor) throws CoreException {
// Sanity
if (fUsings == null || fUsings.length == 0) {
return;
}
if (fTranslationUnit != null) {
- ArrayList toAdd = new ArrayList();
-
+ ArrayList toAdd = new ArrayList(fUsings.length);
+
monitor.beginTask(CEditorMessages.AddIncludesOperation_description, 2);
-
- List> elements = fTranslationUnit.getChildrenOfType(ICElement.C_USING);
- for (int i = 0; i < fUsings.length; ++i) {
- String name = fUsings[i];
+
+ List elements = fTranslationUnit.getChildrenOfType(ICElement.C_USING);
+ for (String name : fUsings) {
boolean found = false;
- for (int j = 0; j < elements.size(); ++j) {
- IUsing using = (IUsing)elements.get(j);
- if (name.equals(using.getElementName())) {
+ for (ICElement element : elements) {
+ if (name.equals(element.getElementName())) {
found = true;
break;
}
}
if (!found) {
- toAdd.add(fUsings[i]);
+ toAdd.add(name);
}
}
-
- if (toAdd.size() > 0) {
+
+ if (!toAdd.isEmpty()) {
// So we have our list. Now insert.
- StringBuffer insert = new StringBuffer(""); //$NON-NLS-1$
- for(int j = 0; j < toAdd.size(); j++) {
- String using = toAdd.get(j);
- insert.append("using namespace " + using + ";").append(fNewLine); //$NON-NLS-1$ //$NON-NLS-2$
+ StringBuilder buf = new StringBuilder();
+ for (String using : toAdd) {
+ buf.append("using ").append(using).append(';').append(fNewLine); //$NON-NLS-1$
}
-
- int pos;
- List> includes = fTranslationUnit.getChildrenOfType(ICElement.C_INCLUDE);
- if (includes.size() > 0) {
- IInclude lastInclude = (IInclude)includes.get(includes.size() - 1);
- ISourceRange range = lastInclude.getSourceRange();
- pos = range.getStartPos() + range.getLength();
- } else if (elements.size() > 0) {
- IUsing lastUsing = (IUsing)includes.get(includes.size() - 1);
+
+ int pos = 0;
+ if (!elements.isEmpty()) {
+ IUsing lastUsing = (IUsing) elements.get(elements.size() - 1);
ISourceRange range = lastUsing.getSourceRange();
pos = range.getStartPos() + range.getLength();
} else {
- pos = 0;
+ List includes = fTranslationUnit.getChildrenOfType(ICElement.C_INCLUDE);
+ if (!includes.isEmpty()) {
+ IInclude lastInclude = (IInclude) includes.get(includes.size() - 1);
+ ISourceRange range = lastInclude.getSourceRange();
+ pos = range.getStartPos() + range.getLength();
+ }
+ if (!includes.isEmpty() || insertedIncludes != null) {
+ buf.insert(0, fNewLine);
+ }
}
-
+ if (insertedIncludes != null && pos >= insertedIncludes.getOffset()) {
+ pos += insertedIncludes.getLength();
+ }
+
monitor.worked(1);
- replace(pos, insert.toString());
+ replace(pos, buf.toString());
monitor.worked(1);
}
}
}
- void replace(int pos, String s) {
- try {
- IBuffer buffer = fTranslationUnit.getBuffer();
- // Now find the next newline and insert after that
- if (pos > 0) {
- while (buffer.getChar(pos) != '\n') {
- pos++;
- }
- if (buffer.getChar(pos) == '\r') {
- pos++;
- }
+ private void replace(int pos, String s) throws CModelException {
+ IBuffer buffer = fTranslationUnit.getBuffer();
+ // Now find the next newline and insert after that
+ if (pos > 0) {
+ while (buffer.getChar(pos) != '\n') {
pos++;
}
- buffer.replace(pos, 0, s);
- } catch (Exception e) {
- // ignore; should we log ?
+ if (buffer.getChar(pos) == '\r') {
+ pos++;
+ }
+ pos++;
}
+ buffer.replace(pos, 0, s);
}
public void run(IProgressMonitor monitor) throws CoreException {
@@ -219,8 +219,8 @@ public class AddIncludesOperation implements IWorkspaceRunnable {
monitor= new NullProgressMonitor();
}
try {
- executeUsings(monitor);
- executeIncludes(monitor);
+ insertIncludes(monitor);
+ insertUsings(monitor);
} finally {
monitor.done();
}
@@ -229,7 +229,7 @@ public class AddIncludesOperation implements IWorkspaceRunnable {
/**
* @return Returns the scheduling rule for this operation
*/
- public ISchedulingRule getScheduleRule() {
+ public ISchedulingRule getSchedulingRule() {
return ResourcesPlugin.getWorkspace().getRoot();
}
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/AddIncludeOnSelectionAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/AddIncludeOnSelectionAction.java
index 8f8aed567cd..9dcc7c41bda 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/AddIncludeOnSelectionAction.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/AddIncludeOnSelectionAction.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -9,341 +9,406 @@
* IBM Corporation - initial API and implementation
* QNX Software Systems
* Markus Schorn (Wind River Systems)
+ * Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.editor;
-
+import java.io.File;
import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jface.operation.IRunnableWithProgress;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.ui.texteditor.ITextEditor;
-import org.eclipse.ui.texteditor.IUpdate;
+import org.eclipse.ui.texteditor.TextEditorAction;
import org.eclipse.cdt.core.CCorePlugin;
-import org.eclipse.cdt.core.browser.IQualifiedTypeName;
-import org.eclipse.cdt.core.browser.QualifiedTypeName;
+import org.eclipse.cdt.core.dom.ast.DOMException;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
+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.IProblemBinding;
+import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexBinding;
-import org.eclipse.cdt.core.index.IIndexManager;
+import org.eclipse.cdt.core.index.IIndexFile;
+import org.eclipse.cdt.core.index.IIndexInclude;
+import org.eclipse.cdt.core.index.IIndexMacro;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.index.IndexFilter;
+import org.eclipse.cdt.core.model.ILanguage;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.IScannerInfo;
import org.eclipse.cdt.core.parser.IScannerInfoProvider;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.IFunctionSummary;
import org.eclipse.cdt.ui.IRequiredInclude;
-import org.eclipse.cdt.ui.browser.typeinfo.TypeInfoLabelProvider;
import org.eclipse.cdt.ui.text.ICHelpInvocationContext;
+import org.eclipse.cdt.ui.text.SharedASTJob;
import org.eclipse.cdt.utils.PathUtil;
+import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
+import org.eclipse.cdt.internal.core.resources.ResourceLookup;
import org.eclipse.cdt.internal.corext.codemanipulation.AddIncludesOperation;
import org.eclipse.cdt.internal.ui.CHelpProviderManager;
import org.eclipse.cdt.internal.ui.ICHelpContextIds;
import org.eclipse.cdt.internal.ui.actions.WorkbenchRunnableAdapter;
-import org.eclipse.cdt.internal.ui.text.CWordFinder;
import org.eclipse.cdt.internal.ui.util.ExceptionHandler;
-// TODO this is a big TODO.
-public class AddIncludeOnSelectionAction extends Action implements IUpdate {
-
- private ITextEditor fEditor;
+/**
+ * Adds an include statement and, optionally, a 'using' declaration for the currently
+ * selected name.
+ */
+public class AddIncludeOnSelectionAction extends TextEditorAction {
+ private ITranslationUnit fTu;
+ private IProject fProject;
+ private String[] fIncludePath;
private IRequiredInclude[] fRequiredIncludes;
- private String[] fUsings;
-
- class RequiredIncludes implements IRequiredInclude {
- String name;
- boolean isStandard;
-
- RequiredIncludes(String n) {
- name = n;
- isStandard = true;
- }
-
- RequiredIncludes(String n, boolean isStandard) {
- name = n;
- this.isStandard = isStandard;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.cdt.ui.IRequiredInclude#getIncludeName()
- */
- public String getIncludeName() {
- return name;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.cdt.ui.IRequiredInclude#isStandard()
- */
- public boolean isStandard() {
- return isStandard;
- }
- }
+ private String[] fUsingDeclarations;
public AddIncludeOnSelectionAction(ITextEditor editor) {
- super(CEditorMessages.AddIncludeOnSelection_label);
- setToolTipText(CEditorMessages.AddIncludeOnSelection_tooltip);
- setDescription(CEditorMessages.AddIncludeOnSelection_description);
+ super(CEditorMessages.getBundleForConstructedKeys(), "AddIncludeOnSelection.", editor); //$NON-NLS-1$
- fEditor= editor;
- CUIPlugin.getDefault().getWorkbench().getHelpSystem().setHelp(this, ICHelpContextIds.ADD_INCLUDE_ON_SELECTION_ACTION);
+ CUIPlugin.getDefault().getWorkbench().getHelpSystem().setHelp(this,
+ ICHelpContextIds.ADD_INCLUDE_ON_SELECTION_ACTION);
}
- private void addInclude(ITranslationUnit tu) {
- AddIncludesOperation op= new AddIncludesOperation(tu, fRequiredIncludes, fUsings, false);
+ private void insertInclude(IRequiredInclude[] includes, String[] usings) {
+ AddIncludesOperation op= new AddIncludesOperation(fTu, includes, usings, false);
try {
PlatformUI.getWorkbench().getProgressService().runInUI(
PlatformUI.getWorkbench().getProgressService(),
- new WorkbenchRunnableAdapter(op), op.getScheduleRule());
+ new WorkbenchRunnableAdapter(op), op.getSchedulingRule());
} catch (InvocationTargetException e) {
- ExceptionHandler.handle(e, getShell(), CEditorMessages.AddIncludeOnSelection_error_message1, null);
+ ExceptionHandler.handle(e, getShell(), CEditorMessages.AddIncludeOnSelection_error_title,
+ CEditorMessages.AddIncludeOnSelection_insertion_failed);
} catch (InterruptedException e) {
// Do nothing. Operation has been canceled.
}
}
- protected ITranslationUnit getTranslationUnit () {
- ITranslationUnit unit = null;
- if (fEditor != null) {
- IEditorInput editorInput= fEditor.getEditorInput();
- unit = CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editorInput);
+ private static ITranslationUnit getTranslationUnit(ITextEditor editor) {
+ if (editor == null) {
+ return null;
}
- return unit;
+ return CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editor.getEditorInput());
}
private Shell getShell() {
- return fEditor.getSite().getShell();
+ return getTextEditor().getSite().getShell();
}
@Override
public void run() {
- ITranslationUnit tu= getTranslationUnit();
- if (tu == null) {
+ fTu = getTranslationUnit(getTextEditor());
+ if (fTu == null) {
return;
}
- IIndex index;
+ fProject = fTu.getCProject().getProject();
+ IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(fProject);
+ fIncludePath = null;
+ if (provider != null) {
+ IScannerInfo info = provider.getScannerInformation(fTu.getResource());
+ if (info != null) {
+ fIncludePath = info.getIncludePaths();
+ }
+ }
+ if (fIncludePath == null) {
+ fIncludePath = new String[0];
+ }
+
try {
- index = CCorePlugin.getIndexManager().getIndex(tu.getCProject(), IIndexManager.ADD_DEPENDENCIES);
- index.acquireReadLock();
- try {
- extractIncludes(fEditor, index);
- addInclude(tu);
- } finally {
- index.releaseReadLock();
+ final ISelection selection= getTextEditor().getSelectionProvider().getSelection();
+ if (selection.isEmpty() || !(selection instanceof ITextSelection)) {
+ return;
+ }
+ if (!validateEditorInputState()) {
+ return;
+ }
+
+ final String[] lookupName = new String[1];
+
+ SharedASTJob job = new SharedASTJob(CEditorMessages.AddIncludeOnSelection_label, fTu) {
+ @Override
+ public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) throws CoreException {
+ deduceInclude((ITextSelection) selection, ast, lookupName);
+ return Status.OK_STATUS;
+ }
+ };
+ job.schedule();
+ job.join();
+
+ if (fRequiredIncludes == null || fRequiredIncludes.length == 0 && lookupName[0].length() > 0) {
+ // Try contribution from plugins.
+ IFunctionSummary fs = findContribution(lookupName[0]);
+ if (fs != null) {
+ fRequiredIncludes = fs.getIncludes();
+ String ns = fs.getNamespace();
+ if (ns != null && ns.length() > 0) {
+ fUsingDeclarations = new String[] { fs.getNamespace() };
+ }
+ }
+
+ }
+ if (fRequiredIncludes != null && fRequiredIncludes.length >= 0) {
+ insertInclude(fRequiredIncludes, fUsingDeclarations);
}
- } catch (CoreException e) {
- CUIPlugin.log(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
- fUsings = null;
- fRequiredIncludes = null;
}
- /**
- * To be used by ElementListSelectionDialog for user to choose which declarations/
- * definitions for "add include" when there are more than one to choose from.
- */
- private static class DisplayName extends Object {
- private IIndexName name;
- private IIndexBinding binding;
-
- public DisplayName(IIndexName name, IIndexBinding binding) {
- this.name = name;
- this.binding= binding;
- }
-
- @Override
- public String toString() {
- try {
- if (binding != null) {
- return getBindingQualifiedName(binding) + " - " + name.getFileLocation().getFileName(); //$NON-NLS-1$
- }
- return null;
- } catch (CoreException e) {
- CUIPlugin.log(e);
- return null;
- }
- }
-
- public IIndexName getName() {
- return name;
- }
-
- public IIndexBinding getBinding() {
- return binding;
- }
- }
-
/**
* Extract the includes for the given selection. This can be both used to perform
- * the work as well as being invoked when there is a change. The actual results
- * can and should be cached as the lookup process could be potentially costly.
+ * the work as well as being invoked when there is a change.
* @param index
*/
- private void extractIncludes(ITextEditor editor, IIndex index) {
- if (editor == null) {
+ private void deduceInclude(ITextSelection selection, IASTTranslationUnit ast, String[] lookupName)
+ throws CoreException {
+ IASTNodeSelector selector = ast.getNodeSelector(fTu.getLocation().toOSString());
+ IASTName name = selector.findEnclosingName(selection.getOffset(), selection.getLength());
+ if (name == null) {
return;
}
+ char[] nameChars = name.toCharArray();
+ IBinding binding = name.resolveBinding();
+ try {
+ if (binding instanceof ICPPVariable) {
+ IType type = ((ICPPVariable) binding).getType();
+ type = SemanticUtil.getNestedType(type,
+ SemanticUtil.CVQ | SemanticUtil.PTR | SemanticUtil.ARRAY | SemanticUtil.REF);
+ if (type instanceof IBinding) {
+ binding = (IBinding) type;
+ nameChars = binding.getNameCharArray();
+ }
+ }
+ } catch (DOMException e) {
+ CUIPlugin.log(e);
+ }
+ if (nameChars.length == 0) {
+ return;
+ }
+
+ IIndex index = ast.getIndex();
+ final IndexFilter filter = IndexFilter.getDeclaredBindingFilter(ast.getLinkage().getLinkageID(), false);
+ IIndexBinding[] bindings= index.findBindings(nameChars, false, filter, new NullProgressMonitor());
+ final Map candidatesMap= new HashMap();
+ for (IIndexBinding indexBinding : bindings) {
+ IIndexName[] definitions= null;
+ // class, struct, union, enum
+ if (indexBinding instanceof ICompositeType || indexBinding instanceof IEnumeration) {
+ definitions= index.findDefinitions(indexBinding);
+ } else if (indexBinding instanceof ITypedef ||
+ (indexBinding instanceof IFunction && !(indexBinding instanceof ICPPMethod))) {
+ definitions= index.findDeclarations(indexBinding);
+ }
+ if (definitions != null) {
+ for (IIndexName definition : definitions) {
+ considerForInclusion(definition, indexBinding, index, candidatesMap);
+ }
+ }
+ }
+ IIndexMacro[] macros = index.findMacros(nameChars, filter, new NullProgressMonitor());
+ for (IIndexMacro macro : macros) {
+ IIndexName definition = macro.getDefinition();
+ considerForInclusion(definition, macro, index, candidatesMap);
+ }
- ISelection s= editor.getSelectionProvider().getSelection();
- IDocument doc= editor.getDocumentProvider().getDocument(editor.getEditorInput());
-
- if (s.isEmpty() || !(s instanceof ITextSelection) || doc == null) {
- return;
- }
-
- ITextSelection selection= (ITextSelection) s;
- try {
- IRegion region = CWordFinder.findWord(doc, selection.getOffset());
- if (region == null || region.getLength() == 0) {
- return;
- }
- String name = doc.get(region.getOffset(), region.getLength());
- if (name.length() == 0) {
- return;
- }
-
- // Try contribution from plugins.
- IFunctionSummary fs = findContribution(name);
- if (fs != null) {
- fRequiredIncludes = fs.getIncludes();
- String ns = fs.getNamespace();
- if (ns != null && ns.length() > 0) {
- fUsings = new String[] { fs.getNamespace() };
- }
- }
-
- try {
- IndexFilter filter= IndexFilter.ALL_DECLARED_OR_IMPLICIT;
- IIndexBinding[] bindings= index.findBindings(name.toCharArray(), false, filter,
- new NullProgressMonitor());
- ArrayList pdomNames= new ArrayList();
- for (int i = 0; i < bindings.length; ++i) {
- IIndexBinding binding= bindings[i];
- IIndexName[] defs= null;
- // class, struct union, enumeration
- if (binding instanceof ICompositeType || binding instanceof IEnumeration) {
- defs= index.findDefinitions(binding);
- } else if (binding instanceof ITypedef || binding instanceof IFunction) {
- defs= index.findDeclarations(binding);
- }
- if (defs != null) {
- for (IIndexName def : defs) {
- pdomNames.add(new DisplayName(def, binding));
- }
- }
- }
-
- if (pdomNames.size() > 1) {
- ElementListSelectionDialog dialog= new ElementListSelectionDialog(getShell(), new TypeInfoLabelProvider(TypeInfoLabelProvider.SHOW_NAME_ONLY));
- dialog.setElements(pdomNames.toArray());
+ final ArrayList candidates = new ArrayList(candidatesMap.values());
+ if (candidates.size() > 1) {
+ runInUIThread(new Runnable() {
+ public void run() {
+ ElementListSelectionDialog dialog=
+ new ElementListSelectionDialog(getShell(), new LabelProvider());
+ dialog.setElements(candidates.toArray());
dialog.setTitle(CEditorMessages.AddIncludeOnSelection_label);
dialog.setMessage(CEditorMessages.AddIncludeOnSelection_description);
if (dialog.open() == Window.OK) {
- //get selection
- Object[] selects = dialog.getResult();
-
- fRequiredIncludes = new IRequiredInclude[selects.length];
- List usings = new ArrayList(selects.length);
- for (int i = 0; i < fRequiredIncludes.length; i++) {
- IRequiredInclude include = getRequiredInclude(
- ((DisplayName)selects[i]).getName().getFileLocation().getFileName(), getTranslationUnit());
- if (include != null) {
- fRequiredIncludes[i] = include;
- IIndexBinding binding = ((DisplayName)selects[i]).getBinding();
- if (binding instanceof ICPPBinding)
- {
- //find the enclosing namespace, if there's one
- IQualifiedTypeName qualifiedName = new QualifiedTypeName(getBindingQualifiedName(binding));
- String qualifiedEnclosingName = (new QualifiedTypeName(qualifiedName.getEnclosingNames())).getFullyQualifiedName();
- if (!qualifiedEnclosingName.equals("")) //$NON-NLS-1$
- usings.add(qualifiedEnclosingName);
- }
- }
- }
- if (usings.size() > 0)
- {
- fUsings = new String[usings.size()];
- for (int i = 0; i < usings.size(); i++)
- {
- fUsings[i] = usings.get(i);
- }
- }
- }
- } else if (pdomNames.size() == 1) {
- // we should use the IIndexName.getLocation here rather than getFileLocation
- String fileName = (pdomNames.get(0)).getName().getFileLocation().getFileName();
- fRequiredIncludes = new IRequiredInclude[] {getRequiredInclude(fileName, getTranslationUnit())};
- IIndexBinding binding = (pdomNames.get(0)).getBinding();
-
- if (binding instanceof ICPPBinding) {
- //find the enclosing namespace, if there's one
- IQualifiedTypeName qualifiedName = new QualifiedTypeName(getBindingQualifiedName(binding));
- String qualifiedEnclosingName = new QualifiedTypeName(qualifiedName.getEnclosingNames()).getFullyQualifiedName();
- if (!qualifiedEnclosingName.equals("")) //$NON-NLS-1$
- fUsings = new String[] {qualifiedEnclosingName};
+ candidates.clear();
+ candidates.add((IncludeCandidate) dialog.getFirstResult());
}
}
- } catch (CoreException e) {
- e.printStackTrace();
- }
-
- // Try the type caching.
- if (fRequiredIncludes == null && fUsings == null) {
- }
+ });
+ }
- // Do a full search
- if (fRequiredIncludes == null && fUsings == null) {
+ fRequiredIncludes = null;
+ fUsingDeclarations = null;
+ if (candidates.size() == 1) {
+ IncludeCandidate candidate = candidates.get(0);
+ fRequiredIncludes = new IRequiredInclude[] { candidate.getInclude() };
+ IIndexBinding indexBinding = candidate.getBinding();
+
+ if (indexBinding instanceof ICPPBinding && !(indexBinding instanceof IIndexMacro)) {
+ // Decide what 'using' declaration should be added along with the include.
+ if (binding == null) {
+ binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_NAME_NOT_FOUND);
+ }
+ String usingDeclaration = deduceUsingDeclaration(binding, indexBinding);
+ if (usingDeclaration != null)
+ fUsingDeclarations = new String[] { usingDeclaration };
}
- } catch (BadLocationException e) {
- MessageDialog.openError(getShell(), CEditorMessages.AddIncludeOnSelection_error_message3,
- CEditorMessages.AddIncludeOnSelection_error_message4 + e.getMessage());
}
}
- private IFunctionSummary findContribution (final String name) {
+ /**
+ * Adds an include candidate to the candidates
map if the file containing
+ * the definition is suitable for inclusion.
+ */
+ private void considerForInclusion(IIndexName definition, IIndexBinding binding,
+ IIndex index, Map candidates) throws CoreException {
+ IIndexFile file = definition.getFile();
+ // Consider the file for inclusion only if it is not a source file,
+ // or a source file that was already included by some other file.
+ if (!isSource(getPath(file)) || index.findIncludedBy(file, 0).length > 0) {
+ IIndexFile representativeFile = getRepresentativeFile(file, index);
+ IRequiredInclude include = getRequiredInclude(representativeFile, index);
+ IncludeCandidate candidate = new IncludeCandidate(binding, include);
+ if (!candidates.containsKey(candidate.toString())) {
+ candidates.put(candidate.toString(), candidate);
+ }
+ }
+ }
+
+ private String deduceUsingDeclaration(IBinding source, IBinding target) {
+ if (source.equals(target)) {
+ return null; // No using declaration is needed.
+ }
+ ArrayList targetChain = getUsingChain(target);
+ if (targetChain.size() <= 1) {
+ return null; // Target is not in a namespace
+ }
+ ArrayList sourceChain = getUsingChain(source);
+ if (sourceChain.size() >= targetChain.size()) {
+ int j = targetChain.size();
+ for (int i = sourceChain.size(); --j >= 1 && --i >= 1;) {
+ if (!sourceChain.get(i).equals(targetChain.get(j))) {
+ break;
+ }
+ }
+ if (j <= 0) {
+ return null; // Source is in the target's namespace
+ }
+ }
+ StringBuilder buf = new StringBuilder();
+ for (int i = targetChain.size(); --i >= 0;) {
+ if (buf.length() > 0) {
+ buf.append("::"); //$NON-NLS-1$
+ }
+ buf.append(targetChain.get(i));
+ }
+ return buf.toString();
+ }
+
+ private ArrayList getUsingChain(IBinding binding) {
+ ArrayList chain = new ArrayList(4);
+ try {
+ for (; binding != null; binding = binding.getOwner()) {
+ String name = binding.getName();
+ if (binding instanceof ICPPNamespace) {
+ if (name.length() == 0) {
+ continue;
+ }
+ } else {
+ chain.clear();
+ }
+ chain.add(name);
+ }
+ } catch (DOMException e) {
+ CUIPlugin.log(e);
+ }
+ return chain;
+ }
+
+ /**
+ * Given a header file, decides if this header file should be included directly or
+ * through another header file. For example, bits/stl_map.h
is not supposed
+ * to be included directly, but should be represented by map
.
+ * @return the header file to include.
+ */
+ private IIndexFile getRepresentativeFile(IIndexFile headerFile, IIndex index) {
+ try {
+ if (ResourceLookup.findFilesForLocationURI(headerFile.getLocation().getURI()).length > 0) {
+ return headerFile;
+ }
+ // TODO(sprigogin): Change to ArrayDeque when Java 5 support is no longer needed.
+ LinkedList front = new LinkedList();
+ front.add(headerFile);
+ HashSet processed = new HashSet();
+ processed.add(headerFile);
+ while (!front.isEmpty()) {
+ IIndexFile file = front.remove();
+ // A header without an extension is a good candidate for inclusion into a C++ source file.
+ if (fTu.isCXXLanguage() && !hasExtension(getPath(file))) {
+ return file;
+ }
+ IIndexInclude[] includes = index.findIncludedBy(file, 0);
+ for (IIndexInclude include : includes) {
+ IIndexFile includer = include.getIncludedBy();
+ if (!processed.contains(includer)) {
+ URI uri = includer.getLocation().getURI();
+ if (isSource(uri.getPath()) || ResourceLookup.findFilesForLocationURI(uri).length > 0) {
+ return file;
+ }
+ front.add(includer);
+ processed.add(includer);
+ }
+ }
+ }
+ } catch (CoreException e) {
+ CUIPlugin.log(e);
+ }
+ return headerFile;
+ }
+
+ private boolean hasExtension(String path) {
+ return path.indexOf('.', path.lastIndexOf('/') + 1) >= 0;
+ }
+
+ private IFunctionSummary findContribution(final String name) {
final IFunctionSummary[] fs = new IFunctionSummary[1];
IRunnableWithProgress op = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
ICHelpInvocationContext context = new ICHelpInvocationContext() {
-
public IProject getProject() {
- ITranslationUnit u = getTranslationUnit();
- if (u != null) {
- return u.getCProject().getProject();
- }
- return null;
+ return fProject;
}
public ITranslationUnit getTranslationUnit() {
- return AddIncludeOnSelectionAction.this.getTranslationUnit();
+ return fTu;
}
};
@@ -353,91 +418,204 @@ public class AddIncludeOnSelectionAction extends Action implements IUpdate {
try {
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(op);
} catch (InvocationTargetException e) {
- ExceptionHandler.handle(e, getShell(), CEditorMessages.AddIncludeOnSelection_error_message1, null);
+ ExceptionHandler.handle(e, getShell(), CEditorMessages.AddIncludeOnSelection_error_title,
+ CEditorMessages.AddIncludeOnSelection_help_provider_error);
} catch (InterruptedException e) {
// Do nothing. Operation has been canceled.
}
return fs[0];
}
- public void setContentEditor(ITextEditor editor) {
- fEditor= editor;
+ private void runInUIThread(Runnable runnable) {
+ if (Display.getCurrent() != null) {
+ runnable.run();
+ } else {
+ Display.getDefault().syncExec(runnable);
+ }
}
-
+
+ @Override
public void update() {
- setEnabled(getTranslationUnit() != null);
+ ITextEditor editor = getTextEditor();
+ setEnabled(editor != null && getTranslationUnit(editor) != null);
+ }
+
+ /**
+ * Checks if a file is a source file (.c, .cpp, .cc, etc). Header files are not considered source files.
+ * @return Returns true
if the the file is a source file.
+ */
+ private boolean isSource(String filename) {
+ IContentType ct= CCorePlugin.getContentType(fProject, 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;
+ }
+
+ private static String getPath(IIndexFile file) throws CoreException {
+ return file.getLocation().getURI().getPath();
}
/**
* Returns the RequiredInclude object to be added to the include list
* @param path - the full path of the file to include
- * @param tu - the translation unit which requires the include
* @return the required include
+ * @throws CoreException
*/
- private IRequiredInclude getRequiredInclude(String path, ITranslationUnit tu) {
- if (path != null) {
- IPath typeLocation = new Path(path);
- IProject project = tu.getCProject().getProject();
- IPath projectLocation = project.getLocation();
- IPath workspaceLocation = project.getWorkspace().getRoot().getLocation();
- IPath headerLocation = tu.getResource().getLocation();
- boolean isSystemIncludePath = false;
+ private IRequiredInclude getRequiredInclude(IIndexFile file, IIndex index) throws CoreException {
+ IIndexInclude[] includes;
+ includes = index.findIncludedBy(file);
+ if (includes.length > 0) {
+ // Let the existing includes vote. To be eligible to vote, an include
+ // has to be resolvable in the context of the current translation unit.
+ int systemIncludeVotes = 0;
+ String[] ballotBox = new String[includes.length];
+ for (int i = 0; i < includes.length; i++) {
+ IIndexInclude include = includes[i];
+ if (isResolvable(include)) {
+ ballotBox[i] = include.getFullName();
+ if (include.isSystemInclude()) {
+ systemIncludeVotes++;
+ }
+ }
+ }
+ Arrays.sort(ballotBox);
+ String contender = ballotBox[0];
+ int votes = 1;
+ String winner = contender;
+ int winnerVotes = votes;
+ for (int i = 1; i < ballotBox.length; i++) {
+ if (!ballotBox[i].equals(contender)) {
+ contender = ballotBox[i];
+ votes = 1;
+ }
+ votes++;
+ if (votes > winnerVotes) {
+ winner = contender;
+ winnerVotes = votes;
+ }
+ }
+ return new RequiredInclude(winner, systemIncludeVotes * 2 >= includes.length);
+ }
- IPath includePath = makeRelativePathToProjectIncludes(typeLocation, tu);
- if (includePath != null && !projectLocation.isPrefixOf(typeLocation)) {
- isSystemIncludePath = true;
- }
- //create a relative path - the include file is in the same project as the file we're currently at
- else if (projectLocation.isPrefixOf(typeLocation)
- && projectLocation.isPrefixOf(headerLocation)) {
- includePath = PathUtil.makeRelativePath(typeLocation, headerLocation.removeLastSegments(1));
- }
- //create a relative path - the include file is in the same workspace as the file we're currently at
- else if (workspaceLocation.isPrefixOf(typeLocation))
- {
- includePath = PathUtil.makeRelativePath(typeLocation, projectLocation);
- }
- if (includePath == null)
- includePath = typeLocation; //the full path
- return new RequiredIncludes(includePath.toString(), isSystemIncludePath);
+ // The file has never been included before.
+ IPath targetLocation = PathUtil.getCanonicalPath(new Path(file.getLocation().getURI().getPath()));
+ IPath sourceLocation = PathUtil.getCanonicalPath(fTu.getResource().getLocation());
+ boolean isSystemIncludePath = false;
+
+ IPath path = PathUtil.makeRelativePathToIncludes(targetLocation, fIncludePath);
+ if (path != null &&
+ ResourceLookup.findFilesForLocationURI(URI.create(targetLocation.toString())).length == 0) {
+ // A header file in the include path but outside the workspace is included with angle brackets.
+ isSystemIncludePath = true;
}
- return null;
+ if (path == null) {
+ IPath sourceDirectory = sourceLocation.removeLastSegments(1);
+ if (PathUtil.isPrefix(sourceDirectory, targetLocation)) {
+ path = targetLocation.removeFirstSegments(sourceDirectory.segmentCount());
+ } else {
+ path = targetLocation;
+ }
+ }
+ return new RequiredInclude(path.toString(), isSystemIncludePath);
}
-
+
/**
- * Create a relative path to the project includes.
- * @param fullPath the full path to the project
- * @param tu a translation unit in the project
- * @return IPath corresponding to a relative path to the project includes
+ * Returns true
if the given include can be resolved in the context of
+ * the current translation unit.
*/
- private static IPath makeRelativePathToProjectIncludes(IPath fullPath, ITranslationUnit tu) {
- IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(tu.getCProject().getProject());
- if (provider != null) {
- IScannerInfo info = provider.getScannerInformation(tu.getResource());
- if (info != null) {
- return PathUtil.makeRelativePathToIncludes(fullPath, info.getIncludePaths());
- }
- }
- return null;
- }
-
+ private boolean isResolvable(IIndexInclude include) {
+ try {
+ File target = new File(include.getIncludesLocation().getURI().getPath());
+ String includeName = include.getFullName();
+ for (String dir : fIncludePath) {
+ if (target.equals(new File(dir, includeName))) {
+ return true;
+ }
+ }
+ if (include.isSystemInclude()) {
+ return false;
+ }
+ return target.equals(new File(new File(fTu.getLocationURI().getPath()).getParent(), includeName));
+ } catch (CoreException e) {
+ CUIPlugin.log(e);
+ return false;
+ }
+ }
+
/**
- * Get the fully qualified name for a given PDOMBinding
- * @param pdomBinding
+ * Get the fully qualified name for a given index binding.
+ * @param binding
* @return binding's fully qualified name
* @throws CoreException
*/
private static String getBindingQualifiedName(IIndexBinding binding) throws CoreException {
- StringBuffer buf = new StringBuffer();
String[] qname= binding.getQualifiedName();
- for (int i = 0; i < qname.length; i++) {
- if (i > 0) {
- buf.append("::"); //$NON-NLS-1$
- }
- buf.append(qname[i]);
+ return CPPVisitor.renderQualifiedName(qname);
+ }
+
+ /**
+ * To be used by ElementListSelectionDialog for user to choose which declarations/
+ * definitions for "add include" when there are more than one to choose from.
+ */
+ private static class IncludeCandidate {
+ private final IIndexBinding binding;
+ private final IRequiredInclude include;
+ private final String label;
+
+ public IncludeCandidate(IIndexBinding binding, IRequiredInclude include) throws CoreException {
+ this.binding = binding;
+ this.include = include;
+ this.label = getBindingQualifiedName(binding) + " - " + include.toString(); //$NON-NLS-1$
+ }
+
+ public IIndexBinding getBinding() {
+ return binding;
+ }
+
+ public IRequiredInclude getInclude() {
+ return include;
+ }
+
+ @Override
+ public String toString() {
+ return label;
+ }
+ }
+
+ private static class RequiredInclude implements IRequiredInclude {
+ final String includeName;
+ final boolean isSystem;
+
+ RequiredInclude(String includeName, boolean isSystem) {
+ this.includeName = includeName;
+ this.isSystem = isSystem;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.ui.IRequiredInclude#getIncludeName()
+ */
+ public String getIncludeName() {
+ return includeName;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.ui.IRequiredInclude#isStandard()
+ */
+ public boolean isStandard() {
+ return isSystem;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder(includeName.length() + 2);
+ buf.append(isSystem ? '<' : '"');
+ buf.append(includeName);
+ buf.append(isSystem ? '>' : '"');
+ return buf.toString();
}
- return buf.toString();
}
}
-
-
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java
index 70895cedb8b..99bc805413a 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java
@@ -10,22 +10,36 @@
*******************************************************************************/
package org.eclipse.cdt.internal.ui.editor;
+import java.util.ResourceBundle;
+
import org.eclipse.osgi.util.NLS;
public final class CEditorMessages extends NLS {
+ private static final String BUNDLE_FOR_CONSTRUCTED_KEYS=
+ "org.eclipse.cdt.internal.ui.editor.ConstructedCEditorMessages"; //$NON-NLS-1$
+ private static ResourceBundle fgBundleForConstructedKeys= ResourceBundle.getBundle(BUNDLE_FOR_CONSTRUCTED_KEYS);
- private static final String BUNDLE_NAME = "org.eclipse.cdt.internal.ui.editor.CEditorMessages";//$NON-NLS-1$
+ /**
+ * Returns the message bundle which contains constructed keys.
+ *
+ * @return the message bundle
+ * @since 5.1
+ */
+ public static ResourceBundle getBundleForConstructedKeys() {
+ return fgBundleForConstructedKeys;
+ }
+
+ private static final String BUNDLE_NAME = CEditorMessages.class.getName();
private CEditorMessages() {
// Do not instantiate
}
- public static String AddIncludeOnSelection_description;
- public static String AddIncludeOnSelection_error_message1;
- public static String AddIncludeOnSelection_error_message3;
- public static String AddIncludeOnSelection_error_message4;
public static String AddIncludeOnSelection_label;
- public static String AddIncludeOnSelection_tooltip;
+ public static String AddIncludeOnSelection_description;
+ public static String AddIncludeOnSelection_error_title;
+ public static String AddIncludeOnSelection_insertion_failed;
+ public static String AddIncludeOnSelection_help_provider_error;
public static String AddIncludesOperation_description;
public static String ShowInCView_description;
public static String ShowInCView_label;
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties
index 4a53257d545..64fe222180b 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties
@@ -10,14 +10,14 @@
# QNX Software System
# Anton Leherbauer (Wind River Systems)
# Markus Schorn (Wind River Systems)
+# Sergey Prigogin (Google)
#########################################
-AddIncludeOnSelection_description=Add include statement on selection
-AddIncludeOnSelection_error_message1=Adding include statements failed
-AddIncludeOnSelection_error_message3=Error
-AddIncludeOnSelection_error_message4=BadLocationException:
AddIncludeOnSelection_label=Add Include
-AddIncludeOnSelection_tooltip=Add Include Statement on Selection
+AddIncludeOnSelection_description=Add include statement for selected name
+AddIncludeOnSelection_error_title=Error Adding Include
+AddIncludeOnSelection_insertion_failed=Adding include statements failed
+AddIncludeOnSelection_help_provider_error=Help provider error
AddIncludesOperation_description=Adding include statement
ShowInCView_description=Show the current resource in the C/C++ Projects view
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties
index f41715b402b..c56e97640d3 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ConstructedCEditorMessages.properties
@@ -10,11 +10,12 @@
# QNX Software System
# Anton Leherbauer (Wind River Systems)
# Markus Schorn (Wind River Systems)
+# Sergey Prigogin (Google)
#########################################
-AddIncludeOnSelection.description=Add include statement on selection
+AddIncludeOnSelection.description=Add include statement for selected name
AddIncludeOnSelection.label=Add Include
-AddIncludeOnSelection.tooltip=Add Include Statement on Selection
+AddIncludeOnSelection.tooltip=Add Include Statement for Selected Name
OpenOutline.label= Quick Out&line
OpenOutline.tooltip= Shows the Quick Outline of Editor Input