diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin
index 6cbab75ecc..d676838507 100644
--- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin
@@ -146,7 +146,7 @@
displayName = "Introduce local variable"
class = "ICSharpCode.NRefactory.CSharp.Refactoring.CreateLocalVariable" />
= version;
}
- public override NodeOutputAction CreateNodeOutputAction(int offset, int removedChars, NodeOutput output)
- {
- return new SDScript.SDNodeOutputAction(document, offset, removedChars, output);
- }
-
public override Script StartScript()
{
if (editor == null)
throw new InvalidOperationException("Cannot start a script in IsAvailable().");
- return new SDScript(editor, this);
+ return new SDScript(editor, this.EolMarker);
+ }
+
+ public override TextLocation Location {
+ get { return location; }
}
public override int SelectionStart {
@@ -95,17 +89,6 @@ namespace CSharpBinding.Refactoring
}
}
- public override ResolveResult Resolve(AstNode expression)
- {
- lock (resolver)
- return resolver.Resolve(expression, cancellationToken);
- }
-
- public override void ReplaceReferences(IMember member, MemberDeclaration replaceWidth)
- {
- throw new NotImplementedException();
- }
-
public override bool IsSomethingSelected {
get {
return selectionLength > 0;
@@ -131,17 +114,11 @@ namespace CSharpBinding.Refactoring
return document.GetLocation(offset);
}
- public override CSharpFormattingOptions FormattingOptions {
- get {
- return new CSharpFormattingOptions();
- }
- }
-
public override string EolMarker {
get {
if (document == null)
document = new ReadOnlyDocument(textSource);
- return DocumentUtilitites.GetLineTerminator(document, 1);
+ return DocumentUtilitites.GetLineTerminator(document, location.Line);
}
}
diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDScript.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDScript.cs
index 31df894785..db855b390c 100644
--- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDScript.cs
+++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDScript.cs
@@ -3,9 +3,12 @@
using System;
using System.Collections.Generic;
+using ICSharpCode.AvalonEdit.Document;
+using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.Editor;
+using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Editor;
namespace CSharpBinding.Refactoring
@@ -15,69 +18,95 @@ namespace CSharpBinding.Refactoring
///
sealed class SDScript : Script
{
+ int indentationSize = 4;
readonly ITextEditor editor;
+ readonly TextSegmentCollection textSegmentCollection = new TextSegmentCollection();
+ readonly OffsetChangeMap offsetChangeMap = new OffsetChangeMap();
+ readonly List actions = new List();
- public SDScript(ITextEditor editor, SDRefactoringContext context) : base(context)
+ public SDScript(ITextEditor editor, string eolMarker) : base(eolMarker, new CSharpFormattingOptions())
{
this.editor = editor;
}
- public static void RunActions (IList actions, Script script)
+ public override int GetCurrentOffset(TextLocation originalDocumentLocation)
{
- for (int i = 0; i < actions.Count; i++) {
- actions [i].Perform (script);
- var replaceChange = actions [i] as TextReplaceAction;
- if (replaceChange == null)
- continue;
- for (int j = 0; j < actions.Count; j++) {
- if (i == j)
- continue;
- var change = actions [j] as TextReplaceAction;
- if (change == null)
- continue;
- if (replaceChange.Offset >= 0 && change.Offset >= 0) {
- if (replaceChange.Offset < change.Offset) {
- change.Offset -= replaceChange.RemovedChars;
- if (!string.IsNullOrEmpty (replaceChange.InsertedText))
- change.Offset += replaceChange.InsertedText.Length;
- } else if (replaceChange.Offset < change.Offset + change.RemovedChars) {
- change.RemovedChars = Math.Max (0, change.RemovedChars - replaceChange.RemovedChars);
- change.Offset = replaceChange.Offset + (!string.IsNullOrEmpty (replaceChange.InsertedText) ? replaceChange.InsertedText.Length : 0);
- }
+ int offset = editor.Document.GetOffset(originalDocumentLocation);
+ return offsetChangeMap.GetNewOffset(offset, AnchorMovementType.Default);
+ }
+
+ public override int GetCurrentOffset(int originalDocumentOffset)
+ {
+ return offsetChangeMap.GetNewOffset(originalDocumentOffset, AnchorMovementType.Default);
+ }
+
+ public override void Replace(int offset, int length, string newText)
+ {
+ var changeMapEntry = new OffsetChangeMapEntry(offset, length, newText.Length);
+ textSegmentCollection.UpdateOffsets(changeMapEntry);
+ offsetChangeMap.Add(changeMapEntry);
+
+ actions.Add(delegate { editor.Document.Replace(offset, length, newText); });
+ }
+
+ protected override ISegment CreateTrackedSegment(int offset, int length)
+ {
+ var segment = new TextSegment();
+ segment.StartOffset = offset;
+ segment.Length = length;
+ textSegmentCollection.Add(segment);
+ return segment;
+ }
+
+ protected override int GetIndentLevelAt(int offset)
+ {
+ int oldOffset = offsetChangeMap.Invert().GetNewOffset(offset, AnchorMovementType.Default);
+ var line = editor.Document.GetLineByOffset(oldOffset);
+ int spaces = 0;
+ int indentationLevel = 0;
+ for (int i = line.Offset; i < offset; i++) {
+ char c = editor.Document.GetCharAt(i);
+ if (c == '\t') {
+ spaces = 0;
+ indentationLevel++;
+ } else if (c == ' ') {
+ spaces++;
+ if (spaces == indentationSize) {
+ spaces = 0;
+ indentationLevel++;
}
+ } else {
+ break;
}
}
+ return indentationLevel;
}
- public override void Dispose ()
+ public override void Rename(IEntity entity, string name)
{
- using (editor.Document.OpenUndoGroup ()) {
- RunActions (changes, this);
- }
}
public override void InsertWithCursor(string operation, AstNode node, InsertPosition defaultPosition)
{
- throw new NotImplementedException();
}
- internal class SDNodeOutputAction : NodeOutputAction
+ public override void FormatText(int offset, int length)
{
- IDocument doc;
-
- public SDNodeOutputAction(IDocument doc, int offset, int removedChars, NodeOutput output) : base (offset, removedChars, output)
- {
- if (doc == null)
- throw new ArgumentNullException ("doc");
- if (output == null)
- throw new ArgumentNullException ("output");
- this.doc = doc;
- }
-
- public override void Perform (Script script)
- {
- doc.Replace (Offset, RemovedChars, NodeOutput.Text);
- }
+ }
+
+ public override void Select(int offset, int length)
+ {
+ actions.Add(delegate { editor.Select(offset, length); });
+ }
+
+ public override void Link(params AstNode[] nodes)
+ {
+ }
+
+ public override void Dispose()
+ {
+ foreach (var action in actions)
+ action();
}
}
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs
index 7a23404139..1661d0d148 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/TextDocument.cs
@@ -345,6 +345,14 @@ namespace ICSharpCode.AvalonEdit.Document
}
}
+ ///
+ /// Creates an immutable snapshot of this document.
+ ///
+ public IDocument CreateDocumentSnapshot()
+ {
+ return new ReadOnlyDocument(this);
+ }
+
///
/// Creates a snapshot of the current text.
/// Additionally, creates a checkpoint that allows tracking document changes.
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs
index d4f7fef6ea..a73bc2aef5 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Formatter/AstFormattingVisitor.cs
@@ -37,8 +37,8 @@ namespace ICSharpCode.NRefactory.CSharp
{
CSharpFormattingOptions policy;
IDocument document;
- IActionFactory factory;
- List changes = new List ();
+ Script script;
+ //List changes = new List ();
Indent curIndent = new Indent ();
public int IndentLevel {
@@ -55,10 +55,6 @@ namespace ICSharpCode.NRefactory.CSharp
set;
}
- public List Changes {
- get { return this.changes; }
- }
-
public bool CorrectBlankLines {
get;
set;
@@ -71,16 +67,19 @@ namespace ICSharpCode.NRefactory.CSharp
public string EolMarker { get; set; }
- public AstFormattingVisitor (CSharpFormattingOptions policy, IDocument document, IActionFactory factory,
- bool tabsToSpaces = false, int indentationSize = 4)
+ public AstFormattingVisitor (CSharpFormattingOptions policy, IDocument document, Script script, bool tabsToSpaces = false, int indentationSize = 4)
{
- if (factory == null)
- throw new ArgumentNullException ("factory");
+ if (policy == null)
+ throw new ArgumentNullException("policy");
+ if (document == null)
+ throw new ArgumentNullException("document");
+ if (script == null)
+ throw new ArgumentNullException("script");
this.policy = policy;
this.document = document;
+ this.script = script;
this.curIndent.TabsToSpaces = tabsToSpaces;
this.curIndent.TabSize = indentationSize;
- this.factory = factory;
this.EolMarker = Environment.NewLine;
CorrectBlankLines = true;
}
@@ -972,34 +971,35 @@ namespace ICSharpCode.NRefactory.CSharp
void AddChange (int offset, int removedChars, string insertedText)
{
- if (changes.Any (c => c.Offset == offset && c.RemovedChars == removedChars
- && c.InsertedText == insertedText))
- return;
- string currentText = document.GetText (offset, removedChars);
- if (currentText == insertedText)
- return;
- if (currentText.Any (c => !(char.IsWhiteSpace (c) || c == '\r' || c == '\t' || c == '{' || c == '}')))
- throw new InvalidOperationException ("Tried to remove non ws chars: '" + currentText + "'");
- foreach (var change in changes) {
- if (change.Offset == offset) {
- if (removedChars > 0 && insertedText == change.InsertedText) {
- change.RemovedChars = removedChars;
+ script.Replace(offset, removedChars, insertedText);
+// if (changes.Any (c => c.Offset == offset && c.RemovedChars == removedChars
+// && c.InsertedText == insertedText))
+// return;
+// string currentText = document.GetText (offset, removedChars);
+// if (currentText == insertedText)
+// return;
+// if (currentText.Any (c => !(char.IsWhiteSpace (c) || c == '\r' || c == '\t' || c == '{' || c == '}')))
+// throw new InvalidOperationException ("Tried to remove non ws chars: '" + currentText + "'");
+// foreach (var change in changes) {
+// if (change.Offset == offset) {
+// if (removedChars > 0 && insertedText == change.InsertedText) {
+// change.RemovedChars = removedChars;
+//// change.InsertedText = insertedText;
+// return;
+// }
+// if (!string.IsNullOrEmpty (change.InsertedText)) {
+// change.InsertedText += insertedText;
+// } else {
// change.InsertedText = insertedText;
- return;
- }
- if (!string.IsNullOrEmpty (change.InsertedText)) {
- change.InsertedText += insertedText;
- } else {
- change.InsertedText = insertedText;
- }
- change.RemovedChars = System.Math.Max (removedChars, change.RemovedChars);
- return;
- }
- }
- //Console.WriteLine ("offset={0}, removedChars={1}, insertedText={2}", offset, removedChars, insertedText == null ? "" : insertedText.Replace ("\n", "\\n").Replace ("\r", "\\r").Replace ("\t", "\\t").Replace (" ", "."));
- //Console.WriteLine (Environment.StackTrace);
-
- changes.Add (factory.CreateTextReplaceAction (offset, removedChars, insertedText));
+// }
+// change.RemovedChars = System.Math.Max (removedChars, change.RemovedChars);
+// return;
+// }
+// }
+// //Console.WriteLine ("offset={0}, removedChars={1}, insertedText={2}", offset, removedChars, insertedText == null ? "" : insertedText.Replace ("\n", "\\n").Replace ("\r", "\\r").Replace ("\t", "\\t").Replace (" ", "."));
+// //Console.WriteLine (Environment.StackTrace);
+//
+// changes.Add (factory.CreateTextReplaceAction (offset, removedChars, insertedText));
}
public bool IsLineIsEmptyUpToEol (TextLocation startLocation)
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
index ef5aa7d947..ba7894c277 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
@@ -243,7 +243,6 @@
-
@@ -267,15 +266,9 @@
-
-
-
-
-
-
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Action.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Action.cs
deleted file mode 100644
index fa3cd7f703..0000000000
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Action.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// Change.cs
-//
-// Author:
-// Mike Krüger
-//
-// Copyright (c) 2011 Mike Krüger
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-using System;
-
-namespace ICSharpCode.NRefactory.CSharp.Refactoring
-{
- ///
- /// This is the base class for all refactoring operations that are performed.
- ///
- public abstract class Action
- {
- ///
- /// Gets or sets the description.
- ///
- ///
- /// A brief description of the refactoring change.
- ///
- public string Description {
- get;
- set;
- }
-
- ///
- /// Performs the change.
- ///
- public abstract void Perform (Script script);
- }
-}
-
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/AddAnotherAccessor.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/AddAnotherAccessor.cs
index 8b112a5cd9..f35f8ad068 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/AddAnotherAccessor.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/AddAnotherAccessor.cs
@@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
using (var script = context.StartScript ()) {
script.InsertBefore (pdecl.RBraceToken, accessor);
script.Select (accessorStatement);
- script.FormatText (ctx => GetPropertyDeclaration (context));
+ script.FormatText (pdecl);
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateEventInvocator.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateEventInvocator.cs
index 0fa5fa5650..ee17410331 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateEventInvocator.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateEventInvocator.cs
@@ -75,7 +75,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
ReturnType = new PrimitiveType ("void"),
Modifiers = ICSharpCode.NRefactory.CSharp.Modifiers.Protected | ICSharpCode.NRefactory.CSharp.Modifiers.Virtual,
Body = new BlockStatement () {
- new VariableDeclarationStatement (context.CreateShortType (eventDeclaration.ReturnType), handlerName, new MemberReferenceExpression (new ThisReferenceExpression (), initializer.Name)),
+ new VariableDeclarationStatement (eventDeclaration.ReturnType.Clone (), handlerName, new MemberReferenceExpression (new ThisReferenceExpression (), initializer.Name)),
new IfElseStatement () {
Condition = new BinaryOperatorExpression (new IdentifierExpression (handlerName), BinaryOperatorType.InEquality, new PrimitiveExpression (null)),
TrueStatement = new ExpressionStatement (new InvocationExpression (new IdentifierExpression (handlerName), arguments))
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateField.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateField.cs
index 831dfe121e..be506a7e51 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateField.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/CreateField.cs
@@ -1,4 +1,4 @@
-//
+//
// CreateField.cs
//
// Author:
@@ -63,7 +63,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (identifier.Parent is AssignmentExpression) {
var assign = (AssignmentExpression)identifier.Parent;
var other = assign.Left == identifier ? assign.Right : assign.Left;
- return context.Resolve (other).Type.ConvertToAstType ();
+ return context.CreateShortType (context.Resolve (other).Type);
}
return null;
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/InvertIf.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/InvertIf.cs
index 79a59c32ae..ccea15c562 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/InvertIf.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/InvertIf.cs
@@ -1,4 +1,4 @@
-//
+//
// InvertIf.cs
//
// Author:
@@ -46,7 +46,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
script.Replace (ifStatement.Condition, CSharpUtil.InvertCondition (ifStatement.Condition));
script.Replace (ifStatement.TrueStatement, ifStatement.FalseStatement);
script.Replace (ifStatement.FalseStatement, ifStatement.TrueStatement);
- script.FormatText (ctx => GetIfElseStatement (ctx));
+ script.FormatText (ifStatement);
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/RemoveBackingStore.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/RemoveBackingStore.cs
index 1e9282e691..8db470897e 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/RemoveBackingStore.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/RemoveBackingStore.cs
@@ -43,16 +43,15 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var property = context.GetNode ();
var field = GetBackingField (context);
- context.ReplaceReferences (field, property);
-
// create new auto property
var newProperty = (PropertyDeclaration)property.Clone ();
newProperty.Getter.Body = BlockStatement.Null;
newProperty.Setter.Body = BlockStatement.Null;
using (var script = context.StartScript ()) {
- script.Remove (context.Unit.GetNodeAt (field.Region.BeginLine, field.Region.BeginColumn));
+ script.Remove (context.RootNode.GetNodeAt (field.Region.BeginLine, field.Region.BeginColumn));
script.Replace (property, newProperty);
+ script.Rename (field, newProperty.Name);
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/RemoveBraces.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/RemoveBraces.cs
index 9d78086cf4..5aad476947 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/RemoveBraces.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextAction/RemoveBraces.cs
@@ -1,4 +1,4 @@
-//
+//
// RemoveBraces.cs
//
// Author:
@@ -42,7 +42,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
using (var script = context.StartScript ()) {
script.Remove (block.LBraceToken);
script.Remove (block.RBraceToken);
- script.FormatText (ctx => ctx.Unit.GetNodeAt (block.Parent.StartLocation));
+ script.FormatText (block.Parent);
}
}
@@ -53,7 +53,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return null;
if (!(block.Parent is Statement))
return null;
- if (block.Statements.Count () != 1)
+ if (block.Statements.Count != 1)
return null;
return block;
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CreateLinkAction.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CreateLinkAction.cs
deleted file mode 100644
index 11212a1c9a..0000000000
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/CreateLinkAction.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// CreateLinkAction.cs
-//
-// Author:
-// Mike Krüger
-//
-// Copyright (c) 2011 Mike Krüger
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-using System;
-using System.Collections.Generic;
-
-namespace ICSharpCode.NRefactory.CSharp.Refactoring
-{
- public abstract class CreateLinkAction : Action
- {
- public IEnumerable Linked {
- get;
- private set;
- }
-
- public CreateLinkAction (IEnumerable linked)
- {
- this.Linked = linked;
- }
- }
-}
-
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/FormatTextAction.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/FormatTextAction.cs
deleted file mode 100644
index 8b7fde6615..0000000000
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/FormatTextAction.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// FormatTextAction.cs
-//
-// Author:
-// Mike Krüger
-//
-// Copyright (c) 2011 Mike Krüger
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-using System;
-
-namespace ICSharpCode.NRefactory.CSharp.Refactoring
-{
- public abstract class FormatTextAction : Action
- {
- public Func Callback { get; private set; }
-
- public FormatTextAction (Func callback)
- {
- this.Callback = callback;
- }
- }
-}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/IActionFactory.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/IActionFactory.cs
deleted file mode 100644
index f801a1c9b9..0000000000
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/IActionFactory.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-// IChangeFactory.cs
-//
-// Author:
-// Mike Krüger
-//
-// Copyright (c) 2011 Mike Krüger
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.Collections.Generic;
-
-namespace ICSharpCode.NRefactory.CSharp.Refactoring
-{
- ///
- /// A factory that creates the changes.
- ///
- public interface IActionFactory
- {
- TextReplaceAction CreateTextReplaceAction (int offset, int removedChars, string insertedText);
- NodeOutputAction CreateNodeOutputAction (int offset, int removedChars, NodeOutput output);
- NodeSelectionAction CreateNodeSelectionAction (AstNode node);
- FormatTextAction CreateFormatTextAction (Func callback);
- CreateLinkAction CreateLinkAction (IEnumerable linkedNodes);
- }
-
- public abstract class AbstractActionFactory : IActionFactory
- {
- #region IActionFactory implementation
- public virtual TextReplaceAction CreateTextReplaceAction (int offset, int removedChars, string insertedText)
- {
- throw new NotImplementedException ();
- }
-
- public virtual NodeOutputAction CreateNodeOutputAction (int offset, int removedChars, NodeOutput output)
- {
- throw new NotImplementedException ();
- }
-
- public virtual NodeSelectionAction CreateNodeSelectionAction (AstNode node)
- {
- throw new NotImplementedException ();
- }
-
- public virtual FormatTextAction CreateFormatTextAction (Func callback)
- {
- throw new NotImplementedException ();
- }
-
- public virtual CreateLinkAction CreateLinkAction (IEnumerable linkedNodes)
- {
- throw new NotImplementedException ();
- }
- #endregion
-
- }
-
-}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/IContextAction.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/IContextAction.cs
index 8c2b64ce23..586df389c2 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/IContextAction.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/IContextAction.cs
@@ -1,4 +1,4 @@
-//
+//
// ContextAction.cs
//
// Author:
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/NodeOutputAction.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/NodeOutputAction.cs
deleted file mode 100644
index 911ec67ccd..0000000000
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/NodeOutputAction.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-//
-// NodeOutputChange.cs
-//
-// Author:
-// Mike Krüger
-//
-// Copyright (c) 2011 Mike Krüger
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.Collections.Generic;
-using ICSharpCode.NRefactory.Editor;
-
-namespace ICSharpCode.NRefactory.CSharp.Refactoring
-{
- ///
- /// This is the node that should be outputted at a position.
- ///
- public class NodeOutput
- {
- public readonly Dictionary NodeSegments = new Dictionary ();
-
- public string Text {
- get;
- set;
- }
-
- public void Trim ()
- {
- for (int i = 0; i < Text.Length; i++) {
- char ch = Text [i];
- if (ch != ' ' && ch != '\t') {
- if (i > 0) {
- Text = Text.Substring (i);
- foreach (var seg in NodeSegments.Values) {
- seg.Offset -= i;
- }
- }
- break;
- }
- }
- }
-
- public class Segment : ISegment
- {
- public int Offset {
- get;
- internal set;
- }
-
- public int Length {
- get;
- internal set;
- }
-
- public int EndOffset {
- get {
- return Offset + Length;
- }
- }
-
- public Segment (int offset)
- {
- this.Offset = offset;
- }
-
- public override string ToString ()
- {
- return string.Format ("[NodeOutput.Segment: Offset={0}, Length={1}, EndOffset={2}]", Offset, Length, EndOffset);
- }
- }
- }
-
-
- ///
- /// Outputs an Ast node at a specific offset.
- ///
- public abstract class NodeOutputAction : TextReplaceAction
- {
- public NodeOutput NodeOutput {
- get;
- private set;
- }
-
- public override string InsertedText {
- get {
- return NodeOutput.Text;
- }
- set {
- throw new NotSupportedException ("Changing text with this propery is not supported on NodeOutputChange.");
- }
- }
-
- public NodeOutputAction (int offset, int removedChars, NodeOutput output) : base (offset, removedChars)
- {
- if (output == null)
- throw new ArgumentNullException ("output");
- this.NodeOutput = output;
- }
- }
-}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/NodeSelectionAction.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/NodeSelectionAction.cs
deleted file mode 100644
index b7df34b951..0000000000
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/NodeSelectionAction.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// SelectionAction.cs
-//
-// Author:
-// Mike Krüger
-//
-// Copyright (c) 2011 Mike Krüger
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-using System;
-
-namespace ICSharpCode.NRefactory.CSharp.Refactoring
-{
- public abstract class NodeSelectionAction : Action
- {
- public AstNode AstNode { get; private set; }
-
- public NodeSelectionAction (AstNode astNode)
- {
- this.AstNode = astNode;
- }
- }
-}
-
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs
index 450d950a68..f7b301d6ad 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/RefactoringContext.cs
@@ -25,37 +25,51 @@
// THE SOFTWARE.
using System;
using System.Linq;
+using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver;
+using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
- public abstract class RefactoringContext : AbstractActionFactory
+ public abstract class RefactoringContext
{
- public CompilationUnit Unit {
- get;
- protected set;
+ readonly CSharpAstResolver resolver;
+ readonly CancellationToken cancellationToken;
+
+ public RefactoringContext(CSharpAstResolver resolver, CancellationToken cancellationToken)
+ {
+ this.resolver = resolver;
+ this.cancellationToken = cancellationToken;
}
-
- public TextLocation Location {
- get;
- protected set;
+
+ public CancellationToken CancellationToken {
+ get { return cancellationToken; }
}
- public abstract bool Supports(Version version);
+ public virtual AstNode RootNode {
+ get { return resolver.RootNode; }
+ }
+
+ public abstract TextLocation Location { get; }
+
+ public virtual bool Supports(Version version)
+ {
+ return true;
+ }
public ICompilation Compilation {
- get;
- protected set;
+ get { return resolver.Compilation; }
}
- public abstract CSharpFormattingOptions FormattingOptions {
- get;
+ public virtual AstType CreateShortType (IType fullType)
+ {
+ var csResolver = resolver.GetResolverStateBefore(GetNode());
+ var builder = new TypeSystemAstBuilder(csResolver);
+ return builder.ConvertType(fullType);
}
-
- public abstract AstType CreateShortType (IType fullType);
public AstType CreateShortType (string ns, string name, int typeParameterCount = 0)
{
@@ -68,34 +82,38 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return new MemberType (new SimpleType (ns), name);
}
- public virtual AstType CreateShortType (AstType fullType)
- {
- return CreateShortType (Resolve (fullType).Type);
- }
-
-// public abstract IType GetDefinition (AstType resolvedType);
-
- public abstract void ReplaceReferences (IMember member, MemberDeclaration replaceWidth);
-
public AstNode GetNode ()
{
- return Unit.GetNodeAt (Location);
+ return RootNode.GetNodeAt (Location);
}
public T GetNode () where T : AstNode
{
- return Unit.GetNodeAt (Location);
+ return RootNode.GetNodeAt (Location);
}
- public abstract Script StartScript ();
-
#region Text stuff
- public abstract string EolMarker { get; }
- public abstract bool IsSomethingSelected { get; }
- public abstract string SelectedText { get; }
- public abstract int SelectionStart { get; }
- public abstract int SelectionEnd { get; }
- public abstract int SelectionLength { get; }
+ public virtual string EolMarker {
+ get { return Environment.NewLine; }
+ }
+
+ public virtual bool IsSomethingSelected {
+ get { return this.SelectionLength > 0; }
+ }
+
+ public virtual string SelectedText {
+ get { return string.Empty; }
+ }
+
+ public virtual int SelectionStart {
+ get { return 0; }
+ }
+ public virtual int SelectionEnd {
+ get { return 0; }
+ }
+ public virtual int SelectionLength {
+ get { return 0; }
+ }
public abstract int GetOffset (TextLocation location);
public int GetOffset (int line, int col)
{
@@ -106,10 +124,28 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
#endregion
#region Resolving
- public abstract ResolveResult Resolve (AstNode expression);
+ public ResolveResult Resolve (AstNode node)
+ {
+ return resolver.Resolve (node, cancellationToken);
+ }
+
+ public IType ResolveType (AstType type)
+ {
+ return resolver.Resolve (type, cancellationToken).Type;
+ }
+
+ public IType GetExpectedType (Expression expression)
+ {
+ return resolver.GetExpectedType(expression, cancellationToken);
+ }
+
+ public Conversion GetConversion (Expression expression)
+ {
+ return resolver.GetConversion(expression, cancellationToken);
+ }
#endregion
- public string GetNameProposal (string name, bool camelCase = true)
+ public virtual string GetNameProposal (string name, bool camelCase = true)
{
string baseName = (camelCase ? char.ToLower (name [0]) : char.ToUpper (name [0])) + name.Substring (1);
@@ -129,17 +165,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
return baseName + (number > 0 ? (number + 1).ToString () : "");
}
- }
-
- public static class RefactoringExtensions
- {
- #region ConvertTypes
- public static ICSharpCode.NRefactory.CSharp.AstType ConvertToAstType (this IType type)
- {
- var builder = new TypeSystemAstBuilder ();
- return builder.ConvertType (type);
- }
- #endregion
+
+ public abstract Script StartScript();
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs
index 8500f04341..6db950abee 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs
@@ -1,6 +1,6 @@
//
// Script.cs
-//
+//
// Author:
// Mike Krüger
//
@@ -27,106 +27,175 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
+using ICSharpCode.NRefactory.Editor;
+using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
+ ///
+ /// Class for creating change scripts.
+ /// 'Original document' = document without the change script applied.
+ /// 'Current document' = document with the change script (as far as it is already created) applies.
+ ///
public abstract class Script : IDisposable
{
- public RefactoringContext Context {
- get;
- private set;
- }
-
- protected readonly List changes = new List ();
-
- public IEnumerable Actions {
- get {
- return changes;
+ internal struct Segment : ISegment
+ {
+ readonly int offset;
+ readonly int length;
+
+ public int Offset {
+ get { return offset; }
+ }
+
+ public int Length {
+ get { return length; }
+ }
+
+ public int EndOffset {
+ get { return Offset + Length; }
+ }
+
+ public Segment (int offset, int length)
+ {
+ this.offset = offset;
+ this.length = length;
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("[Script.Segment: Offset={0}, Length={1}, EndOffset={2}]", Offset, Length, EndOffset);
}
}
- public Script (RefactoringContext context)
- {
- if (context == null)
- throw new ArgumentNullException ("context");
- this.Context = context;
- }
+ readonly string eolMarker;
+ readonly CSharpFormattingOptions formattingOptions;
+ Dictionary segmentsForInsertedNodes = new Dictionary();
- public void Queue (Action change)
+ protected Script(string eolMarker, CSharpFormattingOptions formattingOptions)
{
- changes.Add (change);
+ if (eolMarker == null)
+ throw new ArgumentNullException("eolMarker");
+ if (formattingOptions == null)
+ throw new ArgumentNullException("formattingOptions");
+ this.eolMarker = eolMarker;
+ this.formattingOptions = formattingOptions;
}
- public void InsertText (int offset, string text)
- {
- Queue (Context.CreateTextReplaceAction (offset, 0, text));
- }
+ ///
+ /// Given an offset in the original document (at the start of script execution),
+ /// returns the offset in the current document.
+ ///
+ public abstract int GetCurrentOffset(int originalDocumentOffset);
- public void InsertBefore (AstNode node, AstNode insertNode)
- {
- var startOffset = Context.GetOffset (node.StartLocation.Line, 1);
- var output = OutputNode (GetIndentLevelAt (startOffset), insertNode);
-
- if (!(insertNode is Expression || insertNode is AstType))
- output.Text += Context.EolMarker;
-
- Queue (Context.CreateNodeOutputAction (startOffset, 0, output));
- }
-
- public void AddTo (BlockStatement bodyStatement, AstNode insertNode)
+ ///
+ /// Given an offset in the original document (at the start of script execution),
+ /// returns the offset in the current document.
+ ///
+ public abstract int GetCurrentOffset(TextLocation originalDocumentLocation);
+
+ ///
+ /// Creates a tracked segment for the specified (offset,length)-segment.
+ /// Offset is interpreted to be an offset in the current document.
+ ///
+ ///
+ /// A segment that initially has the specified values, and updates
+ /// on every call.
+ ///
+ protected abstract ISegment CreateTrackedSegment(int offset, int length);
+
+ protected ISegment GetSegment(AstNode node)
{
- var startOffset = Context.GetOffset (bodyStatement.LBraceToken.StartLocation) + 1;
- var output = OutputNode (GetIndentLevelAt (startOffset), insertNode, true);
- Queue (Context.CreateNodeOutputAction (startOffset, 0, output));
+ ISegment segment;
+ if (segmentsForInsertedNodes.TryGetValue(node, out segment))
+ return segment;
+ if (node.StartLocation.IsEmpty || node.EndLocation.IsEmpty) {
+ throw new InvalidOperationException("Trying to get the position of a node that is not part of the original document and was not inserted");
+ }
+ int startOffset = GetCurrentOffset(node.StartLocation);
+ int endOffset = GetCurrentOffset(node.EndLocation);
+ return new Segment(startOffset, endOffset - startOffset);
}
- public void Link (params AstNode[] nodes)
+ ///
+ /// Replaces text.
+ ///
+ /// The starting offset of the text to be replaced.
+ /// The length of the text to be replaced.
+ /// The new text.
+ public abstract void Replace (int offset, int length, string newText);
+
+ public void InsertText(int offset, string newText)
{
- Queue (Context.CreateLinkAction (nodes));
+ Replace(offset, 0, newText);
}
- public void Link (IEnumerable nodes)
- {
- Queue (Context.CreateLinkAction (nodes));
+ public CSharpFormattingOptions FormattingOptions {
+ get { return formattingOptions; }
}
public void Remove (AstNode node)
{
- var startOffset = Context.GetOffset (node.StartLocation);
- var endOffset = Context.GetOffset (node.EndLocation);
- Remove (startOffset, endOffset - startOffset);
+ var segment = GetSegment(node);
+ Replace(segment.Offset, segment.Length, string.Empty);
}
- void Remove (int offset, int length)
+ public void InsertBefore (AstNode node, AstNode insertNode)
{
- Queue (Context.CreateTextReplaceAction (offset, length, null));
+ var startOffset = GetCurrentOffset (new TextLocation(node.StartLocation.Line, 1));
+ var output = OutputNode (GetIndentLevelAt (startOffset), insertNode);
+ string text = output.Text;
+ if (!(insertNode is Expression || insertNode is AstType))
+ text += eolMarker;
+ InsertText(startOffset, text);
+ output.RegisterTrackedSegments(this, startOffset);
+ }
+
+ public void AddTo (BlockStatement bodyStatement, AstNode insertNode)
+ {
+ var startOffset = GetCurrentOffset (bodyStatement.LBraceToken.EndLocation);
+ var output = OutputNode (1 + GetIndentLevelAt (startOffset), insertNode, true);
+ InsertText (startOffset, output.Text);
+ output.RegisterTrackedSegments (this, startOffset);
}
- void Replace (int offset, int length, string text)
+ public virtual void Link (params AstNode[] nodes)
{
- Queue (Context.CreateTextReplaceAction (offset, length, text));
+ // Default implementation: do nothing
+ // Derived classes are supposed to enter the text editor's linked state.
}
public void Replace (AstNode node, AstNode replaceWith)
{
- var startOffset = Context.GetOffset (node.StartLocation);
- var endOffset = Context.GetOffset (node.EndLocation);
+ var segment = GetSegment (node);
+ int startOffset = segment.Offset;
int level = 0;
if (!(replaceWith is Expression) && !(replaceWith is AstType))
level = GetIndentLevelAt (startOffset);
NodeOutput output = OutputNode (level, replaceWith);
- output.Trim ();
- Queue (Context.CreateNodeOutputAction (startOffset, endOffset - startOffset, output));
+ output.TrimStart ();
+ Replace (startOffset, segment.Length, output.Text);
+ output.RegisterTrackedSegments(this, startOffset);
}
-
- public void FormatText (Func callback)
+
+ public void FormatText (AstNode node)
{
- Queue (Context.CreateFormatTextAction (callback));
+ var segment = GetSegment(node);
+ FormatText(segment.Offset, segment.Length);
}
+ public abstract void FormatText (int offset, int length);
+
public void Select (AstNode node)
{
- Queue (Context.CreateNodeSelectionAction (node));
+ var segment = GetSegment(node);
+ Select(segment.Offset, segment.Length);
+ }
+
+ public virtual void Select (int offset, int length)
+ {
+ // default implementation: do nothing
+ // Derived classes are supposed to set the text editor's selection
}
public enum InsertPosition {
@@ -138,65 +207,101 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
public abstract void InsertWithCursor (string operation, AstNode node, InsertPosition defaultPosition);
- protected int GetIndentLevelAt (int offset)
+ protected virtual int GetIndentLevelAt (int offset)
{
- var node = Context.Unit.GetNodeAt (Context.GetLocation (offset));
- int level = 0;
- while (node != null) {
- if (node is BlockStatement || node is TypeDeclaration || node is NamespaceDeclaration)
- level++;
- node = node.Parent;
- }
- return level;
+ return 0;
}
sealed class SegmentTrackingOutputFormatter : TextWriterOutputFormatter
{
- readonly NodeOutput result;
+ internal List> NewSegments = new List>();
+ Stack startOffsets = new Stack();
readonly StringWriter stringWriter;
- public SegmentTrackingOutputFormatter(NodeOutput result, StringWriter stringWriter)
+ public SegmentTrackingOutputFormatter(StringWriter stringWriter)
: base(stringWriter)
{
- this.result = result;
this.stringWriter = stringWriter;
}
public override void StartNode(AstNode node)
{
base.StartNode(node);
- result.NodeSegments [node] = new NodeOutput.Segment (stringWriter.GetStringBuilder ().Length);
+ startOffsets.Push(stringWriter.GetStringBuilder ().Length);
}
public override void EndNode(AstNode node)
{
- var nodeSegment = result.NodeSegments [node];
- nodeSegment.Length = stringWriter.GetStringBuilder ().Length - nodeSegment.Offset;
+ int startOffset = startOffsets.Pop();
+ int endOffset = stringWriter.GetStringBuilder ().Length;
+ NewSegments.Add(new KeyValuePair(node, new Segment(startOffset, endOffset - startOffset)));
base.EndNode(node);
}
}
- protected NodeOutput OutputNode (int indentLevel, AstNode node, bool startWithNewLine = false)
+ protected NodeOutput OutputNode(int indentLevel, AstNode node, bool startWithNewLine = false)
{
- var result = new NodeOutput ();
var stringWriter = new StringWriter ();
- var formatter = new SegmentTrackingOutputFormatter (result, stringWriter);
+ var formatter = new SegmentTrackingOutputFormatter (stringWriter);
formatter.Indentation = indentLevel;
- stringWriter.NewLine = Context.EolMarker;
+ stringWriter.NewLine = eolMarker;
if (startWithNewLine)
formatter.NewLine ();
- var visitor = new CSharpOutputVisitor (formatter, Context.FormattingOptions);
+ var visitor = new CSharpOutputVisitor (formatter, formattingOptions);
node.AcceptVisitor (visitor, null);
- result.Text = stringWriter.ToString ().TrimEnd ();
+ string text = stringWriter.ToString().TrimEnd();
+
if (node is FieldDeclaration)
- result.Text += Context.EolMarker;
-
- return result;
+ text += eolMarker;
+ return new NodeOutput(text, formatter.NewSegments);
}
-
- #region IDisposable implementation
- public abstract void Dispose ();
- #endregion
+
+ protected class NodeOutput
+ {
+ string text;
+ List> newSegments;
+ int trimmedLength;
+
+ internal NodeOutput(string text, List> newSegments)
+ {
+ this.text = text;
+ this.newSegments = newSegments;
+ }
+
+ public string Text {
+ get { return text; }
+ }
+
+ public void TrimStart()
+ {
+ for (int i = 0; i < text.Length; i++) {
+ char ch = text [i];
+ if (ch != ' ' && ch != '\t') {
+ if (i > 0) {
+ text = text.Substring (i);
+ trimmedLength = i;
+ }
+ break;
+ }
+ }
+ }
+
+ public void RegisterTrackedSegments(Script script, int insertionOffset)
+ {
+ foreach (var pair in newSegments) {
+ int offset = insertionOffset + pair.Value.Offset - trimmedLength;
+ ISegment trackedSegment = script.CreateTrackedSegment(offset, pair.Value.Length);
+ script.segmentsForInsertedNodes.Add(pair.Key, trackedSegment);
+ }
+ }
+ }
+
+ ///
+ /// Performs a rename refactoring.
+ ///
+ public abstract void Rename(IEntity entity, string name);
+
+ public abstract void Dispose();
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TextReplaceAction.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TextReplaceAction.cs
deleted file mode 100644
index bbe6234d28..0000000000
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TextReplaceAction.cs
+++ /dev/null
@@ -1,134 +0,0 @@
-//
-// TextReplaceChange.cs
-//
-// Author:
-// Mike Krüger
-//
-// Copyright (c) 2011 Mike Krüger
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-
-namespace ICSharpCode.NRefactory.CSharp.Refactoring
-{
- ///
- /// This is the base action for changes in a text document.
- ///
- public abstract class TextReplaceAction : Action
- {
- ///
- /// Gets or sets the offset.
- ///
- ///
- /// The offset of the replace.
- ///
- public int Offset {
- get;
- set;
- }
-
- int removedChars;
- ///
- /// Gets or sets the numer of chars to removed.
- ///
- ///
- /// The numer of chars to remove.
- ///
- ///
- /// Is thrown when an argument passed to a method is invalid because it is outside the allowable range of values as
- /// specified by the method.
- ///
- public int RemovedChars {
- get {
- return removedChars;
- }
- set {
- if (value < 0)
- throw new ArgumentOutOfRangeException ("RemovedChars", "needs to be >= 0");
- removedChars = value;
- }
- }
-
- ///
- /// Gets or sets the inserted text.
- ///
- ///
- /// The text to insert.
- ///
- public virtual string InsertedText {
- get;
- set;
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The offset of the replace.
- ///
- ///
- /// The numer of chars to remove.
- ///
- ///
- /// Is thrown when an argument passed to a method is invalid because it is outside the allowable range of values as
- /// specified by the method.
- ///
- protected TextReplaceAction (int offset, int removedChars)
- {
- if (removedChars < 0)
- throw new ArgumentOutOfRangeException ("removedChars", "removedChars needs to be >= 0");
- if (offset < 0)
- throw new ArgumentOutOfRangeException ("offset", "offset needs to be >= 0");
- this.removedChars = removedChars;
- this.Offset = offset;
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The offset of the replace.
- ///
- ///
- /// The numer of chars to remove.
- ///
- ///
- /// The text to insert.
- ///
- ///
- /// Is thrown when an argument passed to a method is invalid because it is outside the allowable range of values as
- /// specified by the method.
- public TextReplaceAction (int offset, int removedChars, string insertedText) : this (offset, removedChars)
- {
- this.InsertedText = insertedText;
- }
-
- ///
- /// Returns a that represents the current .
- ///
- ///
- /// A that represents the current .
- ///
- public override string ToString ()
- {
- return string.Format ("[TextReplaceAction: Offset={0}, RemovedChars={1}, InsertedText={2}]", Offset, RemovedChars, InsertedText == null ? "" : InsertedText.Replace ("\t", "\\t").Replace ("\n", "\\n").Replace ("\r", "\\r"));
- }
- }
-}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs
index fcc31d9e9f..b1f485d670 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpAstResolver.cs
@@ -28,6 +28,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
///
/// Resolves C# AST nodes.
///
+ /// This class is thread-safe.
public class CSharpAstResolver
{
readonly CSharpResolver initialResolverState;
@@ -120,17 +121,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (navigator == null)
throw new ArgumentNullException("navigator");
- if (resolverInitialized)
- throw new InvalidOperationException("Applying a navigator is only valid as the first operation on the CSharpAstResolver.");
-
- resolverInitialized = true;
- resolveVisitor.cancellationToken = cancellationToken;
- resolveVisitor.SetNavigator(navigator);
- try {
- resolveVisitor.Scan(rootNode);
- } finally {
- resolveVisitor.SetNavigator(null);
- resolveVisitor.cancellationToken = CancellationToken.None;
+ lock (resolveVisitor) {
+ if (resolverInitialized)
+ throw new InvalidOperationException("Applying a navigator is only valid as the first operation on the CSharpAstResolver.");
+
+ resolverInitialized = true;
+ resolveVisitor.cancellationToken = cancellationToken;
+ resolveVisitor.SetNavigator(navigator);
+ try {
+ resolveVisitor.Scan(rootNode);
+ } finally {
+ resolveVisitor.SetNavigator(null);
+ resolveVisitor.cancellationToken = CancellationToken.None;
+ }
}
}
@@ -141,14 +144,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (node == null || node.IsNull || IsUnresolvableNode(node))
return ErrorResolveResult.UnknownError;
- InitResolver();
- resolveVisitor.cancellationToken = cancellationToken;
- try {
- ResolveResult rr = resolveVisitor.GetResolveResult(node);
- Debug.Assert(rr != null);
- return rr;
- } finally {
- resolveVisitor.cancellationToken = CancellationToken.None;
+ lock (resolveVisitor) {
+ InitResolver();
+ resolveVisitor.cancellationToken = cancellationToken;
+ try {
+ ResolveResult rr = resolveVisitor.GetResolveResult(node);
+ Debug.Assert(rr != null);
+ return rr;
+ } finally {
+ resolveVisitor.cancellationToken = CancellationToken.None;
+ }
}
}
@@ -168,14 +173,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (node == null || node.IsNull)
throw new ArgumentNullException("node");
- InitResolver();
- resolveVisitor.cancellationToken = cancellationToken;
- try {
- CSharpResolver resolver = resolveVisitor.GetResolverStateBefore(node);
- Debug.Assert(resolver != null);
- return resolver;
- } finally {
- resolveVisitor.cancellationToken = CancellationToken.None;
+ lock (resolveVisitor) {
+ InitResolver();
+ resolveVisitor.cancellationToken = cancellationToken;
+ try {
+ CSharpResolver resolver = resolveVisitor.GetResolverStateBefore(node);
+ Debug.Assert(resolver != null);
+ return resolver;
+ } finally {
+ resolveVisitor.cancellationToken = CancellationToken.None;
+ }
}
}
@@ -191,14 +198,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
node = node.Parent;
if (node == null)
return initialResolverState;
- InitResolver();
- resolveVisitor.cancellationToken = cancellationToken;
- try {
- CSharpResolver resolver = resolveVisitor.GetResolverStateAfter(node);
- Debug.Assert(resolver != null);
- return resolver;
- } finally {
- resolveVisitor.cancellationToken = CancellationToken.None;
+ lock (resolveVisitor) {
+ InitResolver();
+ resolveVisitor.cancellationToken = cancellationToken;
+ try {
+ CSharpResolver resolver = resolveVisitor.GetResolverStateAfter(node);
+ Debug.Assert(resolver != null);
+ return resolver;
+ } finally {
+ resolveVisitor.cancellationToken = CancellationToken.None;
+ }
}
}
@@ -206,12 +215,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (expr == null || expr.IsNull)
throw new ArgumentNullException("expr");
- InitResolver();
- resolveVisitor.cancellationToken = cancellationToken;
- try {
- return resolveVisitor.GetConversionWithTargetType(expr);
- } finally {
- resolveVisitor.cancellationToken = CancellationToken.None;
+ lock (resolveVisitor) {
+ InitResolver();
+ resolveVisitor.cancellationToken = cancellationToken;
+ try {
+ return resolveVisitor.GetConversionWithTargetType(expr);
+ } finally {
+ resolveVisitor.cancellationToken = CancellationToken.None;
+ }
}
}
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
index 8ac05c8575..3fac874ea9 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
@@ -35,6 +35,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
///
/// Contains the main resolver logic.
///
+ ///
+ /// Despite being immutable, this class is not thread-safe. (due to caches)
+ /// TODO: fix this, it's very hard for NR users to tell whether two CSharpResolvers share the same caches
+ ///
public class CSharpResolver
{
static readonly ResolveResult ErrorResult = ErrorResolveResult.UnknownError;
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/IDocument.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/IDocument.cs
index 07057cdb34..ade9ea8081 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/IDocument.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/IDocument.cs
@@ -27,6 +27,11 @@ namespace ICSharpCode.NRefactory.Editor
///
public interface IDocument : ITextSource, IServiceProvider
{
+ ///
+ /// Creates an immutable snapshot of this document.
+ ///
+ IDocument CreateDocumentSnapshot();
+
///
/// Gets/Sets the text of the whole document..
///
diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/ReadOnlyDocument.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/ReadOnlyDocument.cs
index 5120fd2e32..4912ccd2d9 100644
--- a/src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/ReadOnlyDocument.cs
+++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory/Editor/ReadOnlyDocument.cs
@@ -324,6 +324,12 @@ namespace ICSharpCode.NRefactory.Editor
return textSource.CreateSnapshot(offset, length);
}
+ ///
+ public IDocument CreateDocumentSnapshot()
+ {
+ return this; // ReadOnlyDocument is immutable
+ }
+
///
public System.IO.TextReader CreateReader()
{
diff --git a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs
index d6e8e81c77..f8f4a6b383 100644
--- a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs
+++ b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs
@@ -77,7 +77,15 @@ namespace ICSharpCode.SharpDevelop
///
public static void FireAndForget(this Task task)
{
- task.ContinueWith(t => { if (t.Exception != null) Core.MessageService.ShowException(t.Exception); });
+ task.ContinueWith(
+ t => {
+ if (t.Exception != null) {
+ if (t.Exception.InnerExceptions.Count == 1)
+ Core.MessageService.ShowException(t.Exception.InnerExceptions[0]);
+ else
+ Core.MessageService.ShowException(t.Exception);
+ }
+ });
}
///