1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Add Include fixes. Bugs 284669 and 295174.

This commit is contained in:
Sergey Prigogin 2009-11-16 06:27:14 +00:00
parent 760126e883
commit 3f8ba3ef71
2 changed files with 210 additions and 199 deletions

View file

@ -25,86 +25,103 @@ import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion; import org.eclipse.text.edits.InsertEdit;
import org.eclipse.jface.text.Region;
import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.IBuffer; import org.eclipse.cdt.core.model.IBuffer;
import org.eclipse.cdt.core.model.ICElement; 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.ISourceRange;
import org.eclipse.cdt.core.model.ISourceReference;
import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.model.IUsing;
import org.eclipse.cdt.ui.IRequiredInclude; import org.eclipse.cdt.ui.IRequiredInclude;
import org.eclipse.cdt.internal.ui.editor.CEditorMessages; import org.eclipse.cdt.internal.ui.editor.CEditorMessages;
/** /**
* Add includes to a translation unit. * Adds includes and 'using' declarations 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.
* If the translation unit is open in an editor, be sure to pass over its working copy. * If the translation unit is open in an editor, be sure to pass over its working copy.
*/ */
public class AddIncludesOperation implements IWorkspaceRunnable { public class AddIncludesOperation implements IWorkspaceRunnable {
private ITranslationUnit fTranslationUnit; private final ITranslationUnit fTranslationUnit;
private IRequiredInclude[] fIncludes; private final int fBeforeOffset;
private String[] fUsings; private final IRequiredInclude[] fIncludes;
private final String fNewLine; private final String[] fUsings;
private IRegion insertedIncludes; private String fNewLine;
private IBuffer fBuffer;
private List<ICElement> fExistingIncludes;
private List<ICElement> 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) { public AddIncludesOperation(ITranslationUnit tu, int beforeOffset, IRequiredInclude[] includes,
this(tu, includes, null, save); String[] usings) {
} fTranslationUnit = tu;
fBeforeOffset = beforeOffset;
/**
* Generate include statements for the passed c elements
*/
public AddIncludesOperation(ITranslationUnit tu, IRequiredInclude[] includes, String[] usings,
boolean save) {
super();
fIncludes= includes; fIncludes= includes;
fUsings = usings; fUsings = usings;
fTranslationUnit = tu;
fNewLine= getNewLine(tu);
} }
private String getNewLine(ITranslationUnit tu) { /**
* @return Returns the scheduling rule for this operation
*/
public ISchedulingRule getSchedulingRule() {
return ResourcesPlugin.getWorkspace().getRoot();
}
public void run(IProgressMonitor monitor) throws CoreException {
if (monitor == null) {
monitor= new NullProgressMonitor();
}
try { try {
IBuffer buf= tu.getBuffer(); monitor.beginTask(CEditorMessages.AddIncludesOperation_description, 3);
if (buf instanceof IAdaptable) {
IDocument doc= (IDocument) ((IAdaptable) buf).getAdapter(IDocument.class); fBuffer = fTranslationUnit.getBuffer();
if (doc != null) { fNewLine= getLineSeparator();
String delim= doc.getLineDelimiter(0); fExistingIncludes = fTranslationUnit.getChildrenOfType(ICElement.C_INCLUDE);
if (delim != null) { fIncludesInsert = getIncludesInsert();
return delim; 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();
} }
} catch (CModelException e) { fBuffer.replace(offset, 0, fUsingsInsert.getText());
} catch (BadLocationException e) { }
monitor.worked(1);
} finally {
monitor.done();
} }
return System.getProperty("line.separator", "\n"); //$NON-NLS-1$//$NON-NLS-2$
} }
private void insertIncludes(IProgressMonitor monitor) throws CoreException { private InsertEdit getIncludesInsert() throws CoreException {
// Sanity
if (fIncludes == null || fIncludes.length == 0) { if (fIncludes == null || fIncludes.length == 0) {
return; return null;
} }
if (fTranslationUnit != null) {
ArrayList<IRequiredInclude> toAdd = new ArrayList<IRequiredInclude>(); ArrayList<IRequiredInclude> toAdd = new ArrayList<IRequiredInclude>();
monitor.beginTask(CEditorMessages.AddIncludesOperation_description, 2);
List<ICElement> elements = fTranslationUnit.getChildrenOfType(ICElement.C_INCLUDE);
for (IRequiredInclude include : fIncludes) { for (IRequiredInclude include : fIncludes) {
String name = include.getIncludeName(); String name = include.getIncludeName();
boolean found = false; boolean found = false;
for (ICElement element : elements) { for (ICElement element : fExistingIncludes) {
ISourceRange range = ((ISourceReference) element).getSourceRange();
if (range.getStartPos() + range.getLength() > fBeforeOffset) {
break;
}
if (name.equals(element.getElementName())) { if (name.equals(element.getElementName())) {
found = true; found = true;
break; break;
@ -114,8 +131,10 @@ public class AddIncludesOperation implements IWorkspaceRunnable {
toAdd.add(include); toAdd.add(include);
} }
} }
if (toAdd.isEmpty()) {
return null;
}
if (!toAdd.isEmpty()) {
// So we have our list. Now insert. // So we have our list. Now insert.
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
for (IRequiredInclude include : toAdd) { for (IRequiredInclude include : toAdd) {
@ -126,35 +145,23 @@ public class AddIncludesOperation implements IWorkspaceRunnable {
} }
} }
int pos = 0; int pos = getOffsetAfterLast(fExistingIncludes);
if (!elements.isEmpty()) { return new InsertEdit(pos, buf.toString());
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 { private InsertEdit getUsingsInsert() throws CoreException {
// Sanity
if (fUsings == null || fUsings.length == 0) { if (fUsings == null || fUsings.length == 0) {
return; return null;
} }
if (fTranslationUnit != null) {
ArrayList<String> toAdd = new ArrayList<String>(fUsings.length); ArrayList<String> toAdd = new ArrayList<String>(fUsings.length);
monitor.beginTask(CEditorMessages.AddIncludesOperation_description, 2);
List<ICElement> elements = fTranslationUnit.getChildrenOfType(ICElement.C_USING);
for (String name : fUsings) { for (String name : fUsings) {
boolean found = false; boolean found = false;
for (ICElement element : elements) { for (ICElement element : fExistingUsings) {
ISourceRange range = ((ISourceReference) element).getSourceRange();
if (range.getStartPos() + range.getLength() > fBeforeOffset) {
break;
}
if (name.equals(element.getElementName())) { if (name.equals(element.getElementName())) {
found = true; found = true;
break; break;
@ -164,72 +171,67 @@ public class AddIncludesOperation implements IWorkspaceRunnable {
toAdd.add(name); toAdd.add(name);
} }
} }
if (toAdd.isEmpty()) {
return null;
}
if (!toAdd.isEmpty()) {
// So we have our list. Now insert. // So we have our list. Now insert.
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
for (String using : toAdd) { for (String using : toAdd) {
buf.append("using ").append(using).append(';').append(fNewLine); //$NON-NLS-1$ buf.append("using ").append(using).append(';').append(fNewLine); //$NON-NLS-1$
} }
int pos = 0; int pos = getOffsetAfterLast(fExistingUsings);
if (!elements.isEmpty()) { int pos2 = getOffsetAfterLast(fExistingIncludes);
IUsing lastUsing = (IUsing) elements.get(elements.size() - 1); if (pos <= pos2) {
ISourceRange range = lastUsing.getSourceRange(); pos = pos2;
pos = range.getStartPos() + range.getLength(); buf.insert(0, fNewLine); // Add a blank line between #include and using statements.
} else {
List<ICElement> 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); return new InsertEdit(pos, buf.toString());
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();
}
} }
/** /**
* @return Returns the scheduling rule for this operation * 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
*/ */
public ISchedulingRule getSchedulingRule() { private int getOffsetAfterLast(List<ICElement> elements) throws CModelException {
return ResourcesPlugin.getWorkspace().getRoot(); 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$
} }
} }

View file

@ -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.ICPPASTUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective; 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.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.ICPPNamespace;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndex;
@ -112,8 +113,8 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
ICHelpContextIds.ADD_INCLUDE_ON_SELECTION_ACTION); ICHelpContextIds.ADD_INCLUDE_ON_SELECTION_ACTION);
} }
private void insertInclude(IRequiredInclude[] includes, String[] usings) { private void insertInclude(IRequiredInclude[] includes, String[] usings, int beforeOffset) {
AddIncludesOperation op= new AddIncludesOperation(fTu, includes, usings, false); AddIncludesOperation op= new AddIncludesOperation(fTu, beforeOffset, includes, usings);
try { try {
PlatformUI.getWorkbench().getProgressService().runInUI( PlatformUI.getWorkbench().getProgressService().runInUI(
PlatformUI.getWorkbench().getProgressService(), PlatformUI.getWorkbench().getProgressService(),
@ -190,7 +191,7 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
} }
if (fRequiredIncludes != null && fRequiredIncludes.length >= 0) { if (fRequiredIncludes != null && fRequiredIncludes.length >= 0) {
insertInclude(fRequiredIncludes, fUsingDeclarations); insertInclude(fRequiredIncludes, fUsingDeclarations, ((ITextSelection) selection).getOffset());
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@ -237,6 +238,14 @@ public class AddIncludeOnSelectionAction extends TextEditorAction {
index.findBindings(nameChars, false, filter, new NullProgressMonitor()); index.findBindings(nameChars, false, filter, new NullProgressMonitor());
for (IIndexBinding indexBinding : bindings) { 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; IIndexName[] definitions= null;
// class, struct, union, enum // class, struct, union, enum
if (indexBinding instanceof ICompositeType || indexBinding instanceof IEnumeration) { if (indexBinding instanceof ICompositeType || indexBinding instanceof IEnumeration) {