Browse Source

Add support for automatically fixing issues.

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
90608407a4
  1. 2
      src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj
  2. 5
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/EditorScript.cs
  3. 10
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs
  4. 101
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesCommand.cs
  5. 1
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesDialog.xaml.cs
  6. 2
      src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs
  7. 4
      src/AddIns/Misc/SearchAndReplace/Project/Engine/SearchManager.cs
  8. 8
      src/Main/SharpDevelop/Workbench/FileService.cs

2
src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj

@ -80,7 +80,7 @@ @@ -80,7 +80,7 @@
<Compile Include="Src\Refactoring\IssueManager.cs" />
<Compile Include="Src\Refactoring\IssueOptionsViewModel.cs" />
<Compile Include="Src\Refactoring\SDRedundantUsingIssue.cs" />
<Compile Include="Src\Refactoring\SDScript.cs" />
<Compile Include="Src\Refactoring\EditorScript.cs" />
<Compile Include="Src\Refactoring\SearchForIssuesCommand.cs" />
<Compile Include="Src\Refactoring\SearchForIssuesDialog.xaml.cs">
<DependentUpon>SearchForIssuesDialog.xaml</DependentUpon>

5
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDScript.cs → src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/EditorScript.cs

@ -21,13 +21,14 @@ namespace CSharpBinding.Refactoring @@ -21,13 +21,14 @@ namespace CSharpBinding.Refactoring
/// <summary>
/// Refactoring change script.
/// </summary>
sealed class SDScript : DocumentScript
sealed class EditorScript : DocumentScript
{
readonly ITextEditor editor;
readonly TextSegmentCollection<TextSegment> textSegmentCollection;
readonly SDRefactoringContext context;
public SDScript(ITextEditor editor, SDRefactoringContext context) : base(editor.Document, FormattingOptionsFactory.CreateSharpDevelop(), context.TextEditorOptions)
public EditorScript(ITextEditor editor, SDRefactoringContext context, CSharpFormattingOptions formattingOptions)
: base(editor.Document, formattingOptions, context.TextEditorOptions)
{
this.editor = editor;
this.context = context;

10
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs

@ -60,9 +60,13 @@ namespace CSharpBinding.Refactoring @@ -60,9 +60,13 @@ namespace CSharpBinding.Refactoring
public Script StartScript()
{
if (editor == null)
throw new InvalidOperationException("Cannot start a script in IsAvailable().");
return new SDScript(editor, this);
var formattingOptions = FormattingOptionsFactory.CreateSharpDevelop();
if (editor != null)
return new EditorScript(editor, this, formattingOptions);
else if (document == null || document is ReadOnlyDocument)
throw new InvalidOperationException("Cannot start a script in a read-only context");
else
return new DocumentScript(document, formattingOptions, this.TextEditorOptions);
}
public override TextLocation Location {

101
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesCommand.cs

@ -4,17 +4,21 @@ @@ -4,17 +4,21 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CSharpBinding.Parser;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.Editor;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Editor;
using ICSharpCode.SharpDevelop.Editor.Search;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Project;
namespace CSharpBinding.Refactoring
@ -26,13 +30,30 @@ namespace CSharpBinding.Refactoring @@ -26,13 +30,30 @@ namespace CSharpBinding.Refactoring
SearchForIssuesDialog dlg = new SearchForIssuesDialog();
dlg.Owner = SD.Workbench.MainWindow;
if (dlg.ShowDialog() == true) {
string title = "Issue Search";
var providers = dlg.SelectedProviders.ToList();
var fileNames = GetFilesToSearch(dlg.Target).ToList();
if (dlg.FixIssues) {
int fixedIssueCount = 0;
IReadOnlyList<SearchResultMatch> remainingIssues = null;
AsynchronousWaitDialog.RunInCancellableWaitDialog(
title, null,
monitor => {
remainingIssues = FindAndFixIssues(fileNames, providers, monitor, out fixedIssueCount);
});
string message = string.Format(
"{0} issues were fixed automatically." +
"{1} issues are remaining (no automatic fix available).",
fixedIssueCount, remainingIssues.Count);
SearchResultsPad.Instance.ShowSearchResults(title, remainingIssues);
MessageService.ShowMessage(message, title);
} else {
var monitor = SD.StatusBar.CreateProgressMonitor();
var observable = ReactiveExtensions.CreateObservable<SearchedFile>(
(m, c) => SearchForIssuesAsync(fileNames, providers, c, m),
monitor);
SearchResultsPad.Instance.ShowSearchResults("Issue Search", observable);
SearchResultsPad.Instance.ShowSearchResults(title, observable);
}
}
}
@ -117,6 +138,82 @@ namespace CSharpBinding.Refactoring @@ -117,6 +138,82 @@ namespace CSharpBinding.Refactoring
else
return null;
}
IReadOnlyList<SearchResultMatch> FindAndFixIssues(List<FileName> fileNames, List<IssueManager.IssueProvider> providers, IProgressMonitor progress, out int fixedIssueCount)
{
fixedIssueCount = 0;
List<SearchResultMatch> remainingIssues = new List<SearchResultMatch>();
for (int i = 0; i < fileNames.Count; i++) {
remainingIssues.AddRange(FindAndFixIssues(fileNames[i], providers, progress.CancellationToken, ref fixedIssueCount));
progress.Report((double)i / fileNames.Count);
}
return remainingIssues;
}
IEnumerable<SearchResultMatch> FindAndFixIssues(FileName fileName, List<IssueManager.IssueProvider> providers, CancellationToken cancellationToken, ref int fixedIssueCount)
{
cancellationToken.ThrowIfCancellationRequested();
var openedFile = SD.FileService.GetOpenedFile(fileName);
bool documentWasLoadedFromDisk = false;
IDocument document = null;
if (openedFile != null && openedFile.CurrentView != null) {
var provider = openedFile.CurrentView.GetService<IFileDocumentProvider>();
if (provider != null)
document = provider.GetDocumentForFile(openedFile);
}
if (document == null) {
documentWasLoadedFromDisk = true;
document = new TextDocument(SD.FileService.GetFileContent(fileName));
}
var parseInfo = SD.ParserService.Parse(fileName, document, cancellationToken: cancellationToken) as CSharpFullParseInformation;
if (parseInfo == null)
return Enumerable.Empty<SearchResultMatch>();
var compilation = SD.ParserService.GetCompilationForFile(fileName);
var resolver = parseInfo.GetResolver(compilation);
var context = new SDRefactoringContext(document, resolver, new TextLocation(0, 0), 0, 0, cancellationToken);
List<CodeIssue> allIssues = new List<CodeIssue>();
bool documentWasChanged = false;
foreach (var provider in providers) {
cancellationToken.ThrowIfCancellationRequested();
var issues = provider.GetIssues(context).ToList();
// Fix issues, if possible:
if (issues.Any(i => i.Actions.Count > 0)) {
using (var script = context.StartScript()) {
foreach (var issue in issues) {
if (issue.Actions.Count > 0) {
fixedIssueCount++;
issue.Actions[0].Run(script);
}
}
}
documentWasChanged = true;
// Update parseInfo etc. now that we've modified the document
parseInfo = SD.ParserService.Parse(fileName, document, cancellationToken: cancellationToken) as CSharpFullParseInformation;
if (parseInfo == null)
return Enumerable.Empty<SearchResultMatch>();
compilation = SD.ParserService.GetCompilationForFile(fileName);
resolver = parseInfo.GetResolver(compilation);
context = new SDRefactoringContext(document, resolver, new TextLocation(0, 0), 0, 0, cancellationToken);
// Find remaining issues:
allIssues.AddRange(provider.GetIssues(context));
} else {
allIssues.AddRange(issues);
}
}
if (documentWasChanged && documentWasLoadedFromDisk) {
// Save changes back to disk
using (var writer = new StreamWriter(fileName, false, SD.FileService.DefaultFileEncoding)) {
document.WriteTextTo(writer);
}
}
if (allIssues.Count > 0) {
var highlighter = SD.EditorControlService.CreateHighlighter(document);
return allIssues.Select(issue => SearchResultMatch.Create(document, issue.Start, issue.End, highlighter));
} else {
return Enumerable.Empty<SearchResultMatch>();
}
}
}
public enum SearchForIssuesTarget

1
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SearchForIssuesDialog.xaml.cs

@ -26,6 +26,7 @@ namespace CSharpBinding.Refactoring @@ -26,6 +26,7 @@ namespace CSharpBinding.Refactoring
InitializeComponent();
FixCheckBox_Unchecked(null, null);
treeView.Root = new RootTreeNode(IssueManager.IssueProviders);
searchInRBG.SelectedValue = SearchForIssuesTarget.WholeSolution;
}
public SearchForIssuesTarget Target {

2
src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs

@ -363,7 +363,7 @@ namespace ICSharpCode.AvalonEdit.AddIn @@ -363,7 +363,7 @@ namespace ICSharpCode.AvalonEdit.AddIn
// don't use TextEditor.Save here because that would touch the Modified flag,
// but OpenedFile is already managing IsDirty
using (StreamWriter writer = new StreamWriter(stream, primaryTextEditor.Encoding ?? Encoding.UTF8)) {
writer.Write(primaryTextEditor.Text);
primaryTextEditor.Document.WriteTextTo(writer);
}
}

4
src/AddIns/Misc/SearchAndReplace/Project/Engine/SearchManager.cs

@ -54,9 +54,9 @@ namespace SearchAndReplace @@ -54,9 +54,9 @@ namespace SearchAndReplace
static ITextSource ReadFile(FileName fileName)
{
OpenedFile openedFile = SD.FileService.GetOpenedFile(fileName);
if (openedFile == null)
if (openedFile == null || openedFile.CurrentView == null)
return null;
IFileDocumentProvider provider = FileService.GetOpenFile(fileName) as IFileDocumentProvider;
var provider = openedFile.CurrentView.GetService<IFileDocumentProvider>();
if (provider == null)
return null;
IDocument doc = provider.GetDocumentForFile(openedFile);

8
src/Main/SharpDevelop/Workbench/FileService.cs

@ -111,13 +111,15 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -111,13 +111,15 @@ namespace ICSharpCode.SharpDevelop.Workbench
delegate {
OpenedFile file = this.GetOpenedFile(fileName);
if (file != null) {
IFileDocumentProvider p = file.CurrentView as IFileDocumentProvider;
if (p != null) {
IDocument document = p.GetDocumentForFile(file);
if (file.CurrentView != null) {
IFileDocumentProvider provider = file.CurrentView.GetService<IFileDocumentProvider>();
if (provider != null) {
IDocument document = provider.GetDocumentForFile(file);
if (document != null) {
return document.CreateSnapshot();
}
}
}
using (Stream s = file.OpenRead()) {
// load file

Loading…
Cancel
Save