From 0729800650a9e220369a9f7b1a21a9cbc4dfec22 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 20 Nov 2006 16:11:36 +0000 Subject: [PATCH] Fixed SD2-1180: Changed event inserted at wrong position git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2062 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/Src/Lexer/CSharp/Lexer.cs | 2 +- .../NRefactory/Project/Src/Location.cs | 7 ++- .../Project/Src/Parser/CSharp/Parser.cs | 2 +- .../Project/Src/Parser/CSharp/cs.ATG | 2 +- .../Output/VBNet/CSharpToVBConverterTest.cs | 2 + .../TypeLevel/PropertyDeclarationTests.cs | 32 ++++++++++ .../Refactoring/NRefactoryCodeGenerator.cs | 58 +++++++++++++++++++ 7 files changed, 101 insertions(+), 4 deletions(-) diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs index 0062c3de09..9220c2d249 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs @@ -825,7 +825,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp break; case '}': if (--braceCount < 0) { - curToken = new Token(Tokens.CloseCurlyBrace, Col, Line); + curToken = new Token(Tokens.CloseCurlyBrace, Col - 1, Line); return; } break; diff --git a/src/Libraries/NRefactory/Project/Src/Location.cs b/src/Libraries/NRefactory/Project/Src/Location.cs index ccd537ee6a..6d0ae993ce 100644 --- a/src/Libraries/NRefactory/Project/Src/Location.cs +++ b/src/Libraries/NRefactory/Project/Src/Location.cs @@ -12,7 +12,7 @@ namespace ICSharpCode.NRefactory /// /// A line/column position. /// - public struct Location : IComparable + public struct Location : IComparable, IEquatable { public static readonly Location Empty = new Location(-1, -1); @@ -64,6 +64,11 @@ namespace ICSharpCode.NRefactory return (Location)obj == this; } + public bool Equals(Location other) + { + return this == other; + } + public static bool operator ==(Location a, Location b) { return a.x == b.x && a.y == b.y; diff --git a/src/Libraries/NRefactory/Project/Src/Parser/CSharp/Parser.cs b/src/Libraries/NRefactory/Project/Src/Parser/CSharp/Parser.cs index 036941804b..b547d201dd 100644 --- a/src/Libraries/NRefactory/Project/Src/Parser/CSharp/Parser.cs +++ b/src/Libraries/NRefactory/Project/Src/Parser/CSharp/Parser.cs @@ -2476,7 +2476,7 @@ out Statement stmt) { #line 1205 "cs.ATG" BlockStatement blockStmt = new BlockStatement(); - blockStmt.StartLocation = t.EndLocation; + blockStmt.StartLocation = t.Location; compilationUnit.BlockStart(blockStmt); if (!ParseMethodBodies) lexer.SkipCurrentBlock(0); diff --git a/src/Libraries/NRefactory/Project/Src/Parser/CSharp/cs.ATG b/src/Libraries/NRefactory/Project/Src/Parser/CSharp/cs.ATG index f06820a3aa..8f394bcbbe 100644 --- a/src/Libraries/NRefactory/Project/Src/Parser/CSharp/cs.ATG +++ b/src/Libraries/NRefactory/Project/Src/Parser/CSharp/cs.ATG @@ -1203,7 +1203,7 @@ VariableDeclarator fieldDeclaration> Block /* not BlockStatement because of EmbeddedStatement */ = "{" (. BlockStatement blockStmt = new BlockStatement(); - blockStmt.StartLocation = t.EndLocation; + blockStmt.StartLocation = t.Location; compilationUnit.BlockStart(blockStmt); if (!ParseMethodBodies) lexer.SkipCurrentBlock(0); .) diff --git a/src/Libraries/NRefactory/Test/Output/VBNet/CSharpToVBConverterTest.cs b/src/Libraries/NRefactory/Test/Output/VBNet/CSharpToVBConverterTest.cs index 072fb99c09..c856415033 100644 --- a/src/Libraries/NRefactory/Test/Output/VBNet/CSharpToVBConverterTest.cs +++ b/src/Libraries/NRefactory/Test/Output/VBNet/CSharpToVBConverterTest.cs @@ -212,6 +212,7 @@ namespace ICSharpCode.NRefactory.Tests.PrettyPrinter "End Sub"); } + /* [Test, Ignore("NRefactory cannot guess the anonymous method's return type")] public void AnonymousMethodInVarDeclaration() { @@ -223,6 +224,7 @@ namespace ICSharpCode.NRefactory.Tests.PrettyPrinter "\tReturn argument * 2\n" + "End Function"); } + */ [Test] public void RegisterEvent() diff --git a/src/Libraries/NRefactory/Test/Parser/TypeLevel/PropertyDeclarationTests.cs b/src/Libraries/NRefactory/Test/Parser/TypeLevel/PropertyDeclarationTests.cs index e30e4e5cfb..56d125ea90 100644 --- a/src/Libraries/NRefactory/Test/Parser/TypeLevel/PropertyDeclarationTests.cs +++ b/src/Libraries/NRefactory/Test/Parser/TypeLevel/PropertyDeclarationTests.cs @@ -6,6 +6,7 @@ // using System; +using System.IO; using ICSharpCode.NRefactory.Ast; using NUnit.Framework; @@ -51,6 +52,37 @@ namespace ICSharpCode.NRefactory.Tests.Ast Assert.IsTrue(pd.HasSetRegion); } + void CSharpPropertyRegionTest(bool parseMethodBodies) + { + const string code = "class T {\n\tint Prop {\n\t\tget { return f; }\n\t\tset { f = value; }\n\t}\n}\n"; + int line2Pos = code.IndexOf("\tint Prop"); + int line3Pos = code.IndexOf("\t\tget"); + int line4Pos = code.IndexOf("\t\tset"); + + IParser p = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(code)); + p.ParseMethodBodies = parseMethodBodies; + p.Parse(); + PropertyDeclaration pd = (PropertyDeclaration)p.CompilationUnit.Children[0].Children[0]; + Assert.AreEqual(new Location(code.IndexOf("{\n\t\tget") - line2Pos + 1, 2), pd.BodyStart); + Assert.AreEqual(new Location(3, 5), pd.BodyEnd); + Assert.AreEqual(new Location(code.IndexOf("{ return") - line3Pos + 1, 3), pd.GetRegion.Block.StartLocation); + Assert.AreEqual(new Location(code.IndexOf("}\n\t\tset") + 1 - line3Pos + 1, 3), pd.GetRegion.Block.EndLocation); + Assert.AreEqual(new Location(code.IndexOf("{ f =") - line4Pos + 1, 4), pd.SetRegion.Block.StartLocation); + Assert.AreEqual(new Location(code.IndexOf("}\n\t}") + 1 - line4Pos + 1, 4), pd.SetRegion.Block.EndLocation); + } + + [Test] + public void CSharpPropertyRegionTest() + { + CSharpPropertyRegionTest(true); + } + + [Test] + public void CSharpPropertyRegionTestSkipParseMethodBodies() + { + CSharpPropertyRegionTest(false); + } + [Test] public void CSharpPropertyImplementingInterfaceTest() { diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/NRefactoryCodeGenerator.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/NRefactoryCodeGenerator.cs index d59763a536..ab98deb347 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/NRefactoryCodeGenerator.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/NRefactoryCodeGenerator.cs @@ -44,6 +44,64 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring { return new CSharpOutputVisitor(); } + + /// + /// Ensure that code is inserted correctly in {} code blocks - SD2-1180 + /// + public override void InsertCodeAtEnd(DomRegion region, IDocument document, params AbstractNode[] nodes) + { + string beginLineIndentation = GetIndentation(document, region.BeginLine); + int insertionLine = region.EndLine - 1; + + IDocumentLine endLine = document.GetLine(region.EndLine); + string endLineText = endLine.Text; + int originalPos = region.EndColumn - 2; // -1 for column coordinate => offset, -1 because EndColumn is after the '}' + int pos = originalPos; + if (pos >= endLineText.Length || endLineText[pos] != '}') { + LoggingService.Warn("CSharpCodeGenerator.InsertCodeAtEnd: position is invalid (not pointing to '}')" + + " endLineText=" + endLineText + ", pos=" + pos); + } else { + for (pos--; pos >= 0; pos--) { + if (!char.IsWhiteSpace(endLineText[pos])) { + // range before '}' is not empty: we cannot simply insert in the line before the '}', so + // + pos++; // set pos to first whitespace character / the '{' character + if (pos < originalPos) { + // remove whitespace between last non-white character and the '}' + document.Remove(endLine.Offset + pos, originalPos - pos); + } + // insert newline and same indentation as used in beginLine before the '}' + document.Insert(endLine.Offset + pos, Environment.NewLine + beginLineIndentation); + insertionLine++; + + pos = region.BeginColumn - 1; + if (region.BeginLine == region.EndLine && pos >= 1 && pos < endLineText.Length) { + // The whole block was in on a single line, e.g. "get { return field; }". + // Insert an additional newline after the '{'. + + originalPos = pos = endLineText.IndexOf('{', pos); + if (pos >= 0 && pos < region.EndColumn - 1) { + // find next non-whitespace after originalPos + originalPos++; // point to insertion position for newline after { + for (pos++; pos < endLineText.Length; pos++) { + if (!char.IsWhiteSpace(endLineText[pos])) { + // remove all between originalPos and pos + if (originalPos < pos) { + document.Remove(endLine.Offset + originalPos, pos - originalPos); + } + document.Insert(endLine.Offset + originalPos, Environment.NewLine + beginLineIndentation + '\t'); + insertionLine++; + break; + } + } + } + } + break; + } + } + } + InsertCodeAfter(insertionLine, document, beginLineIndentation + '\t', nodes); + } } public class VBNetCodeGenerator : NRefactoryCodeGenerator