From 3f8ba3ef7187bcba0fdcd76b5890d5b459121199 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Mon, 16 Nov 2009 06:27:14 +0000 Subject: [PATCH] Add Include fixes. Bugs 284669 and 295174. --- .../AddIncludesOperation.java | 362 +++++++++--------- .../editor/AddIncludeOnSelectionAction.java | 47 ++- 2 files changed, 210 insertions(+), 199 deletions(-) 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 5cdc383ef4b..a9f5b5a969f 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 @@ -25,205 +25,46 @@ 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.text.edits.InsertEdit; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.IBuffer; import org.eclipse.cdt.core.model.ICElement; -import org.eclipse.cdt.core.model.IInclude; import org.eclipse.cdt.core.model.ISourceRange; +import org.eclipse.cdt.core.model.ISourceReference; import org.eclipse.cdt.core.model.ITranslationUnit; -import org.eclipse.cdt.core.model.IUsing; import org.eclipse.cdt.ui.IRequiredInclude; import org.eclipse.cdt.internal.ui.editor.CEditorMessages; /** - * Add includes to a translation unit. - * The input is an array of full qualified type names. No elimination of unnecessary - * includes is not done. Duplicates are eliminated. + * Adds includes and 'using' declarations to a translation unit. * 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; + private final ITranslationUnit fTranslationUnit; + private final int fBeforeOffset; + private final IRequiredInclude[] fIncludes; + private final String[] fUsings; + private String fNewLine; + private IBuffer fBuffer; + private List fExistingIncludes; + private List fExistingUsings; + private InsertEdit fIncludesInsert; + private InsertEdit fUsingsInsert; /** - * Generate include statements for the passed java elements + * @param tu a translation unit. + * @param beforeOffset includes and 'using' declarations have to be inserted before this offset. + * @param includes '#include' statements to insert. + * @param usings 'using' statements to insert. */ - public AddIncludesOperation(ITranslationUnit tu, IRequiredInclude[] includes, boolean save) { - this(tu, includes, null, save); - } - - /** - * Generate include statements for the passed c elements - */ - public AddIncludesOperation(ITranslationUnit tu, IRequiredInclude[] includes, String[] usings, - boolean save) { - super(); + public AddIncludesOperation(ITranslationUnit tu, int beforeOffset, IRequiredInclude[] includes, + String[] usings) { + fTranslationUnit = tu; + fBeforeOffset = beforeOffset; fIncludes= includes; fUsings = usings; - fTranslationUnit = tu; - fNewLine= getNewLine(tu); - } - - private String getNewLine(ITranslationUnit tu) { - try { - IBuffer buf= tu.getBuffer(); - if (buf instanceof IAdaptable) { - IDocument doc= (IDocument) ((IAdaptable) buf).getAdapter(IDocument.class); - if (doc != null) { - String delim= doc.getLineDelimiter(0); - if (delim != null) { - return delim; - } - } - } - } catch (CModelException e) { - } catch (BadLocationException e) { - } - return System.getProperty("line.separator", "\n"); //$NON-NLS-1$//$NON-NLS-2$ - } - - private void insertIncludes(IProgressMonitor monitor) throws CoreException { - // Sanity - if (fIncludes == null || fIncludes.length == 0) { - return; - } - - if (fTranslationUnit != null) { - ArrayList toAdd = new ArrayList(); - - monitor.beginTask(CEditorMessages.AddIncludesOperation_description, 2); - - List elements = fTranslationUnit.getChildrenOfType(ICElement.C_INCLUDE); - for (IRequiredInclude include : fIncludes) { - String name = include.getIncludeName(); - boolean found = false; - for (ICElement element : elements) { - if (name.equals(element.getElementName())) { - found = true; - break; - } - } - if (!found) { - toAdd.add(include); - } - } - - if (!toAdd.isEmpty()) { - // So we have our list. Now insert. - 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 { - buf.append("#include \"" + include.getIncludeName() + "\"").append(fNewLine); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - int pos = 0; - if (!elements.isEmpty()) { - IInclude lastInclude = (IInclude) elements.get(elements.size() - 1); - ISourceRange range = lastInclude.getSourceRange(); - pos = range.getStartPos() + range.getLength(); - } - monitor.worked(1); - replace(pos, buf.toString()); - insertedIncludes = new Region(pos, buf.length()); - monitor.worked(1); - } - } - } - - private void insertUsings(IProgressMonitor monitor) throws CoreException { - // Sanity - if (fUsings == null || fUsings.length == 0) { - return; - } - - if (fTranslationUnit != null) { - ArrayList toAdd = new ArrayList(fUsings.length); - - monitor.beginTask(CEditorMessages.AddIncludesOperation_description, 2); - - List elements = fTranslationUnit.getChildrenOfType(ICElement.C_USING); - for (String name : fUsings) { - boolean found = false; - for (ICElement element : elements) { - if (name.equals(element.getElementName())) { - found = true; - break; - } - } - if (!found) { - toAdd.add(name); - } - } - - if (!toAdd.isEmpty()) { - // So we have our list. Now insert. - StringBuilder buf = new StringBuilder(); - for (String using : toAdd) { - buf.append("using ").append(using).append(';').append(fNewLine); //$NON-NLS-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 { - 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, buf.toString()); - monitor.worked(1); - } - } - } - - 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++; - } - if (buffer.getChar(pos) == '\r') { - pos++; - } - pos++; - } - buffer.replace(pos, 0, s); - } - - public void run(IProgressMonitor monitor) throws CoreException { - if (monitor == null) { - monitor= new NullProgressMonitor(); - } - try { - insertIncludes(monitor); - insertUsings(monitor); - } finally { - monitor.done(); - } } /** @@ -232,4 +73,165 @@ public class AddIncludesOperation implements IWorkspaceRunnable { public ISchedulingRule getSchedulingRule() { return ResourcesPlugin.getWorkspace().getRoot(); } + + public void run(IProgressMonitor monitor) throws CoreException { + if (monitor == null) { + monitor= new NullProgressMonitor(); + } + try { + monitor.beginTask(CEditorMessages.AddIncludesOperation_description, 3); + + fBuffer = fTranslationUnit.getBuffer(); + fNewLine= getLineSeparator(); + fExistingIncludes = fTranslationUnit.getChildrenOfType(ICElement.C_INCLUDE); + fIncludesInsert = getIncludesInsert(); + monitor.worked(1); + if (fUsings != null && fUsings.length > 0) { + fExistingUsings = fTranslationUnit.getChildrenOfType(ICElement.C_USING); + } + fUsingsInsert = getUsingsInsert(); + monitor.worked(1); + + if (fIncludesInsert != null) { + fBuffer.replace(fIncludesInsert.getOffset(), 0, fIncludesInsert.getText()); + } + if (fUsingsInsert != null) { + int offset = fUsingsInsert.getOffset(); + if (fIncludesInsert != null && offset >= fIncludesInsert.getOffset()) { + offset += fIncludesInsert.getText().length(); + } + fBuffer.replace(offset, 0, fUsingsInsert.getText()); + } + monitor.worked(1); + } finally { + monitor.done(); + } + } + + private InsertEdit getIncludesInsert() throws CoreException { + if (fIncludes == null || fIncludes.length == 0) { + return null; + } + + ArrayList toAdd = new ArrayList(); + for (IRequiredInclude include : fIncludes) { + String name = include.getIncludeName(); + boolean found = false; + for (ICElement element : fExistingIncludes) { + ISourceRange range = ((ISourceReference) element).getSourceRange(); + if (range.getStartPos() + range.getLength() > fBeforeOffset) { + break; + } + if (name.equals(element.getElementName())) { + found = true; + break; + } + } + if (!found) { + toAdd.add(include); + } + } + if (toAdd.isEmpty()) { + return null; + } + + // So we have our list. Now insert. + 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 { + buf.append("#include \"" + include.getIncludeName() + "\"").append(fNewLine); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + int pos = getOffsetAfterLast(fExistingIncludes); + return new InsertEdit(pos, buf.toString()); + } + + private InsertEdit getUsingsInsert() throws CoreException { + if (fUsings == null || fUsings.length == 0) { + return null; + } + + ArrayList toAdd = new ArrayList(fUsings.length); + for (String name : fUsings) { + boolean found = false; + for (ICElement element : fExistingUsings) { + ISourceRange range = ((ISourceReference) element).getSourceRange(); + if (range.getStartPos() + range.getLength() > fBeforeOffset) { + break; + } + if (name.equals(element.getElementName())) { + found = true; + break; + } + } + if (!found) { + toAdd.add(name); + } + } + if (toAdd.isEmpty()) { + return null; + } + + // So we have our list. Now insert. + StringBuilder buf = new StringBuilder(); + for (String using : toAdd) { + buf.append("using ").append(using).append(';').append(fNewLine); //$NON-NLS-1$ + } + + int pos = getOffsetAfterLast(fExistingUsings); + int pos2 = getOffsetAfterLast(fExistingIncludes); + if (pos <= pos2) { + pos = pos2; + buf.insert(0, fNewLine); // Add a blank line between #include and using statements. + } + + return new InsertEdit(pos, buf.toString()); + } + + /** + * Find the last of elements located before fBeforeOffset and returns offset of the following line. + * @param elements source elements to consider. + * @return offset of the line after the last of elements located before fBeforeOffset, or + * zero, if there is no such element. + * @throws CModelException + */ + private int getOffsetAfterLast(List elements) throws CModelException { + for (int i = elements.size(); --i >= 0;) { + ISourceRange range = ((ISourceReference) elements.get(i)).getSourceRange(); + int end = range.getStartPos() + range.getLength(); + if (end <= fBeforeOffset) { + return findNewLine(range.getStartPos() + range.getLength()); + } + } + return 0; + } + + private int findNewLine(int pos) { + while (fBuffer.getChar(pos) != '\n') { + pos++; + } + if (fBuffer.getChar(pos) == '\r') { + pos++; + } + return pos + 1; + } + + private String getLineSeparator() { + 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$ + } } 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 3625b8508fe..b545618c750 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 @@ -62,6 +62,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; 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; @@ -97,7 +98,7 @@ import org.eclipse.cdt.internal.ui.util.ExceptionHandler; * selected name. */ public class AddIncludeOnSelectionAction extends TextEditorAction { - public static boolean sIsJUnitTest = false; + public static boolean sIsJUnitTest = false; private ITranslationUnit fTu; private IProject fProject; @@ -105,15 +106,15 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { private IRequiredInclude[] fRequiredIncludes; private String[] fUsingDeclarations; - public AddIncludeOnSelectionAction(ITextEditor editor) { + public AddIncludeOnSelectionAction(ITextEditor editor) { super(CEditorMessages.getBundleForConstructedKeys(), "AddIncludeOnSelection.", editor); //$NON-NLS-1$ - + CUIPlugin.getDefault().getWorkbench().getHelpSystem().setHelp(this, ICHelpContextIds.ADD_INCLUDE_ON_SELECTION_ACTION); } - - private void insertInclude(IRequiredInclude[] includes, String[] usings) { - AddIncludesOperation op= new AddIncludesOperation(fTu, includes, usings, false); + + private void insertInclude(IRequiredInclude[] includes, String[] usings, int beforeOffset) { + AddIncludesOperation op= new AddIncludesOperation(fTu, beforeOffset, includes, usings); try { PlatformUI.getWorkbench().getProgressService().runInUI( PlatformUI.getWorkbench().getProgressService(), @@ -125,14 +126,14 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { // Do nothing. Operation has been canceled. } } - + private static ITranslationUnit getTranslationUnit(ITextEditor editor) { if (editor == null) { return null; } return CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editor.getEditorInput()); } - + private Shell getShell() { return getTextEditor().getSite().getShell(); } @@ -166,7 +167,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { } final String[] lookupName = new String[1]; - + SharedASTJob job = new SharedASTJob(CEditorMessages.AddIncludeOnSelection_label, fTu) { @Override public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) throws CoreException { @@ -176,7 +177,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { }; job.schedule(); job.join(); - + if (fRequiredIncludes == null || fRequiredIncludes.length == 0 && lookupName[0].length() > 0) { // Try contribution from plugins. IFunctionSummary fs = findContribution(lookupName[0]); @@ -190,13 +191,13 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { } if (fRequiredIncludes != null && fRequiredIncludes.length >= 0) { - insertInclude(fRequiredIncludes, fUsingDeclarations); + insertInclude(fRequiredIncludes, fUsingDeclarations, ((ITextSelection) selection).getOffset()); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } - + /** * 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. @@ -237,6 +238,14 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { index.findBindings(nameChars, false, filter, new NullProgressMonitor()); for (IIndexBinding indexBinding : bindings) { + // Replace ctor with the class itself. + if (indexBinding instanceof ICPPConstructor) { + try { + indexBinding = indexBinding.getOwner(); + } catch (DOMException e) { + continue; + } + } IIndexName[] definitions= null; // class, struct, union, enum if (indexBinding instanceof ICompositeType || indexBinding instanceof IEnumeration) { @@ -255,7 +264,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { IIndexName definition = macro.getDefinition(); considerForInclusion(definition, macro, index, candidatesMap); } - + final ArrayList candidates = new ArrayList(candidatesMap.values()); if (candidates.size() > 1) { if (sIsJUnitTest) { @@ -287,7 +296,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { // Decide what 'using' declaration, if any, should be added along with the include. String usingDeclaration = deduceUsingDeclaration(binding, indexBinding, ast); if (usingDeclaration != null) - fUsingDeclarations = new String[] { usingDeclaration }; + fUsingDeclarations = new String[] { usingDeclaration }; } } } @@ -366,7 +375,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { } return buf.toString(); } - + private boolean match(IASTName name, ArrayList usingChain, boolean excludeLast) { IASTName[] names; if (name instanceof ICPPASTQualifiedName) { @@ -465,7 +474,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { public ITranslationUnit getTranslationUnit() { return fTu; - } + } }; fs[0] = CHelpProviderManager.getDefault().getFunctionInfo(context, name); @@ -514,7 +523,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { 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 @@ -637,7 +646,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { 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; @@ -680,7 +689,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction { public boolean isStandard() { return isSystem; } - + @Override public String toString() { StringBuilder buf = new StringBuilder(includeName.length() + 2);