From 0f48a9788333a8e1289604fdaee9d264423b10f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Reis?= Date: Mon, 11 Nov 2013 23:42:16 +0000 Subject: [PATCH 01/29] Investigating auto-async issue failing on Windows. Issue turned out to be related to Tasks with no parameters. Added a new unit test showing the same problem on Linux. --- .../CSharp/CodeIssues/AutoAsyncTests.cs | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AutoAsyncTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AutoAsyncTests.cs index 43dfe154e..02b92631b 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AutoAsyncTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AutoAsyncTests.cs @@ -1,4 +1,4 @@ -// +// // AutoAsyncTests.cs // // Author: @@ -221,7 +221,6 @@ public async Task TestMethod () }"); } - [Ignore("Broken on windows")] [Test] public void TestContinueWithUsingPrecedent() { Test(@" @@ -259,6 +258,43 @@ public async Task TestMethod () }"); } + [Test] + public void TestContinueWithUsingPrecedentTaskWithNoParameters() { + Test(@" +using System.Threading.Tasks; +class TestClass +{ + public Task Foo () + { + return null; + } + public Task $TestMethod () + { + var tcs = new TaskCompletionSource (); + Foo ().ContinueWith (precedent => { + Console.WriteLine (precedent.IsFaulted); + tcs.SetResult (0); + }); + return tcs.Task; + } +}", @" +using System.Threading.Tasks; +class TestClass +{ + public Task Foo () + { + return null; + } + public async Task TestMethod () + { + Task precedent1 = Foo (); + await precedent1; + Console.WriteLine (precedent1.IsFaulted); + return 0; + } +}"); + } + [Test] public void TestBasicContinueWithExtraName() { Test(@" @@ -588,7 +624,6 @@ class TestClass }"); } - [Ignore("Broken on windows")] [Test] public void TestInvalidContinue() { Test(@" @@ -620,7 +655,6 @@ public async Task TestMethod () }"); } - [Ignore("Broken on windows")] [Test] public void TestLongInvalidContinue() { Test(@" From 8e52920737e26a7351263d330be437b16cc848b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Reis?= Date: Tue, 12 Nov 2013 13:26:51 +0000 Subject: [PATCH 02/29] AutoAsyncIssue now handles parameter-less Tasks better. Auto-async issue still not fully working on Windows. --- .../Uncategorized/AutoAsyncIssue.cs | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Uncategorized/AutoAsyncIssue.cs b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Uncategorized/AutoAsyncIssue.cs index 20d360ed0..426537fc5 100644 --- a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Uncategorized/AutoAsyncIssue.cs +++ b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Uncategorized/AutoAsyncIssue.cs @@ -473,27 +473,28 @@ void TransformBody(List validInvocations, bool isVoid, boo var awaitedExpression = new UnaryOperatorExpression(UnaryOperatorType.Await, target); var replacements = new List(); var lambdaExpression = originalInvocation.Arguments.First(); - var continuationLambdaResolveResult = ctx.Resolve(lambdaExpression) as LambdaResolveResult; + var continuationLambdaResolveResult = (LambdaResolveResult) ctx.Resolve(lambdaExpression); - if (!continuationLambdaResolveResult.HasParameterList || - !continuationLambdaResolveResult.Parameters.First().Type.IsParameterized) + if (!continuationLambdaResolveResult.HasParameterList) { - //Either precedent is of type Task or the result is not used + //Lambda has no parameter, so creating a variable for the argument is not needed + // (since you can't use an argument that doesn't exist). replacements.Add(new ExpressionStatement(awaitedExpression)); } else { - //Precedent is of type Task - var lambdaParameter = continuationLambdaResolveResult.Parameters.First(); - var precedentTaskType = lambdaParameter.Type; - var precedentResultType = precedentTaskType.TypeArguments.First(); + //Lambda has a parameter, which can either be a Task or a Task. - //We might need to separate the task creation and awaiting - var taskIdentifiers = lambdaExpression.Descendants.OfType().Where(identifier => { + var lambdaParameter = continuationLambdaResolveResult.Parameters[0]; + bool isTaskIdentifierUsed = lambdaExpression.Descendants.OfType().Any(identifier => { if (identifier.Identifier != lambdaParameter.Name) return false; var identifierMre = identifier.Parent as MemberReferenceExpression; return identifierMre == null || identifierMre.MemberName != "Result"; }); - if (taskIdentifiers.Any()) { + + var precedentTaskType = lambdaParameter.Type; + + //We might need to separate the task creation and awaiting + if (isTaskIdentifierUsed) { //Create new task variable var taskExpression = awaitedExpression.Expression; taskExpression.Detach(); @@ -503,7 +504,14 @@ void TransformBody(List validInvocations, bool isVoid, boo awaitedExpression.Expression = new IdentifierExpression(effectiveTaskName); } - replacements.Add(new VariableDeclarationStatement(CreateShortType(originalInvocation, precedentResultType), resultName, awaitedExpression)); + if (precedentTaskType.IsParameterized) { + //precedent is Task + var precedentResultType = precedentTaskType.TypeArguments.First(); + replacements.Add(new VariableDeclarationStatement(CreateShortType(originalInvocation, precedentResultType), resultName, awaitedExpression)); + } else { + //precedent is Task + replacements.Add(awaitedExpression); + } } var parentStatement = continuation.GetParent(); From b4cde42903e0c4c20191991afb84ea3e90ba558f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Reis?= Date: Wed, 13 Nov 2013 12:40:30 +0000 Subject: [PATCH 03/29] Fixed AutoAsyncTests on Windows. --- .../CSharp/CodeIssues/AutoAsyncTests.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AutoAsyncTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AutoAsyncTests.cs index 02b92631b..b96d18251 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AutoAsyncTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/AutoAsyncTests.cs @@ -224,6 +224,7 @@ public async Task TestMethod () [Test] public void TestContinueWithUsingPrecedent() { Test(@" +using System; using System.Threading.Tasks; class TestClass { @@ -241,6 +242,7 @@ public Task Foo () return tcs.Task; } }", @" +using System; using System.Threading.Tasks; class TestClass { @@ -612,6 +614,7 @@ public Task Foo () {} [Test] public void TestInvalidInLambda() { TestWrongContext(@" +using System; using System.Threading.Tasks; class TestClass { @@ -627,6 +630,7 @@ class TestClass [Test] public void TestInvalidContinue() { Test(@" +using System; using System.Threading.Tasks; class TestClass { @@ -641,6 +645,7 @@ class TestClass return tcs.Task; } }", @" +using System; using System.Threading.Tasks; class TestClass { @@ -658,6 +663,7 @@ public async Task TestMethod () [Test] public void TestLongInvalidContinue() { Test(@" +using System; using System.Threading.Tasks; class TestClass { @@ -674,6 +680,7 @@ class TestClass return tcs.Task; } }", @" +using System; using System.Threading.Tasks; class TestClass { From 2044ea36d3cf831cac1c0c9bf6df0efdce0230b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 15 Nov 2013 07:36:21 +0100 Subject: [PATCH 04/29] Fixed indentation bug. --- .../IndentEngine/IndentState.cs | 1 + .../IndentationTests/BlockTest.cs | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs index 47dfb46eb..01de1df5f 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs @@ -621,6 +621,7 @@ public virtual void OnStatementExit() NextLineIndent.PopWhile(IndentType.Continuation); CurrentStatement = Statement.None; + NextBody = Body.None; LastBlockIndent = null; } diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs index a440ce1ce..cc40018d3 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs @@ -895,5 +895,28 @@ Foo [new int[] { Assert.AreEqual("\t\t\t", indent.ThisLineIndent); Assert.AreEqual("\t\t\t", indent.NextLineIndent); } + + + /// + /// Bug 16231 - smart indent broken in 4.2.0 + /// + [Test] + public void TestBug16231() + { + var policy = FormattingOptionsFactory.CreateMono(); + + var indent = Helper.CreateEngine(@" +class Foo +{ + void Test () + { + switch (foo) { + } + if (true) { + $ +", policy); + Assert.AreEqual("\t\t\t", indent.ThisLineIndent); + Assert.AreEqual("\t\t\t", indent.NextLineIndent); + } } } From 467dd748019eaf040485d7bfb163ea0383d28a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Sat, 16 Nov 2013 07:21:34 +0100 Subject: [PATCH 05/29] Fixed bug in string encoding. --- .../IndentEngine/TextPasteIndentEngine.cs | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs index 2778395b8..eb6833937 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs @@ -440,19 +440,32 @@ protected StringLiteralPasteStrategy() #endregion - Dictionary> encodeReplace = new Dictionary> { + static readonly Dictionary> encodeReplace = new Dictionary> { { '\"', "\\\"" }, { '\\', "\\\\" }, { '\n', "\\n" }, { '\r', "\\r" }, { '\t', "\\t" }, + { '\a', "\\a" }, + { '\b', "\\b" }, + { '\v', "\\v" }, + { '\f', "\\f" }, + { '\0', "\\0" }, + { '\'', "\\'" } }; - Dictionary decodeReplace = new Dictionary { + + static readonly Dictionary decodeReplace = new Dictionary { { '"', '"' }, { '\\', '\\' }, { 'n', '\n' }, { 'r', '\r' }, { 't', '\t' }, + { 'a', '\a' }, + { 'b', '\b' }, + { 'v', '\v' }, + { 'f', '\f' }, + { '0', '\0' }, + { '\'', '\'' } }; /// @@ -466,21 +479,26 @@ public string Decode(string text) { var result = new StringBuilder(); bool isEscaped = false; - + foreach (var ch in text) { if (isEscaped) { if (decodeReplace.ContainsKey(ch)) { result.Append(decodeReplace [ch]); } else { - result.Append('\\', ch); + result.Append('\\'); + result.Append(ch); } - } else if (ch != '\\') { + isEscaped = false; + continue; + } + + if (ch != '\\') { result.Append(ch); + } else { + isEscaped = true; } - - isEscaped = !isEscaped && ch == '\\'; } - + return result.ToString(); } @@ -513,7 +531,7 @@ protected VerbatimStringPasteStrategy() #endregion - Dictionary> encodeReplace = new Dictionary> { + static readonly Dictionary> encodeReplace = new Dictionary> { { '\"', "\"\"" }, }; From ea75bac3f374061ba3c28ae00f7b965189f93f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 18 Nov 2013 10:45:26 +0100 Subject: [PATCH 06/29] Fixed string literal paste strategy encode/decode. --- .../IndentEngine/TextPasteIndentEngine.cs | 137 +++++++++++++----- .../IndentationTests/StringTests.cs | 14 ++ 2 files changed, 113 insertions(+), 38 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs index eb6833937..11218c2b1 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs @@ -440,38 +440,10 @@ protected StringLiteralPasteStrategy() #endregion - static readonly Dictionary> encodeReplace = new Dictionary> { - { '\"', "\\\"" }, - { '\\', "\\\\" }, - { '\n', "\\n" }, - { '\r', "\\r" }, - { '\t', "\\t" }, - { '\a', "\\a" }, - { '\b', "\\b" }, - { '\v', "\\v" }, - { '\f', "\\f" }, - { '\0', "\\0" }, - { '\'', "\\'" } - }; - - static readonly Dictionary decodeReplace = new Dictionary { - { '"', '"' }, - { '\\', '\\' }, - { 'n', '\n' }, - { 'r', '\r' }, - { 't', '\t' }, - { 'a', '\a' }, - { 'b', '\b' }, - { 'v', '\v' }, - { 'f', '\f' }, - { '0', '\0' }, - { '\'', '\'' } - }; - /// public string Encode(string text) { - return string.Concat(text.SelectMany(c => encodeReplace.ContainsKey(c) ? encodeReplace [c] : new[] { c })); + return CSharpOutputVisitor.ConvertString(text); } /// @@ -480,21 +452,74 @@ public string Decode(string text) var result = new StringBuilder(); bool isEscaped = false; - foreach (var ch in text) { + for (int i = 0; i < text.Length; i++) { + var ch = text[i]; if (isEscaped) { - if (decodeReplace.ContainsKey(ch)) { - result.Append(decodeReplace [ch]); - } else { - result.Append('\\'); - result.Append(ch); + switch (ch) { + case 'a': + result.Append('\a'); + break; + case 'b': + result.Append('\b'); + break; + case 'n': + result.Append('\n'); + break; + case 't': + result.Append('\t'); + break; + case 'v': + result.Append('\v'); + break; + case 'r': + result.Append('\r'); + break; + case '\\': + result.Append('\\'); + break; + case 'f': + result.Append('\f'); + break; + case '0': + result.Append(0); + break; + case '"': + result.Append('"'); + break; + case '\'': + result.Append('\''); + break; + case 'x': + char r; + if (TryGetHex(text, -1, ref i, out r)) { + result.Append(r); + break; + } + goto default; + case 'u': + if (TryGetHex(text, 4, ref i, out r)) { + result.Append(r); + break; + } + goto default; + case 'U': + if (TryGetHex(text, 8, ref i, out r)) { + result.Append(r); + break; + } + goto default; + default: + result.Append('\\'); + result.Append(ch); + break; } isEscaped = false; continue; - } - + } if (ch != '\\') { result.Append(ch); - } else { + } + else { isEscaped = true; } } @@ -502,6 +527,42 @@ public string Decode(string text) return result.ToString(); } + static bool TryGetHex(string text, int count, ref int idx, out char r) + { + int i; + int total = 0; + int top = count != -1 ? count : 4; + + for (i = 0; i < top; i++) { + int c = text[idx + 1 + i]; + + if (c >= '0' && c <= '9') + c = (int) c - (int) '0'; + else if (c >= 'A' && c <= 'F') + c = (int) c - (int) 'A' + 10; + else if (c >= 'a' && c <= 'f') + c = (int) c - (int) 'a' + 10; + else { + r = '\0'; + return false; + } + total = (total * 16) + c; + } + + if (top == 8) { + if (total > 0x0010FFFF) { + r = '\0'; + return false; + } + + if (total >= 0x00010000) + total = ((total - 0x00010000) / 0x0400 + 0xD800); + } + r = (char)total; + idx += top; + return true; + } + /// public PasteStrategy Type { get { return PasteStrategy.StringLiteral; } diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/StringTests.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/StringTests.cs index 3d5d02a62..16e4bea75 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/StringTests.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/StringTests.cs @@ -169,5 +169,19 @@ namespace Foo { Assert.AreEqual("\t", indent.ThisLineIndent); Assert.AreEqual("\t\t", indent.NextLineIndent); } + + [Test] + public void TestStringLiteralPasteStrategyUnicodeDecode() + { + var s = ICSharpCode.NRefactory.CSharp.TextPasteUtils.StringLiteralPasteStrategy.Instance.Decode(@"\u0066"); + Assert.AreEqual("\u0066", s); + + s = ICSharpCode.NRefactory.CSharp.TextPasteUtils.StringLiteralPasteStrategy.Instance.Decode(@"\U00000066"); + Assert.AreEqual("\U00000066", s); + + s = ICSharpCode.NRefactory.CSharp.TextPasteUtils.StringLiteralPasteStrategy.Instance.Decode(@"\xAFFE"); + Assert.AreEqual("\xAFFE", s); + + } } } From 6509e7648f605649dcf01f826c96a57c4a55569b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Thu, 21 Nov 2013 08:00:08 +0100 Subject: [PATCH 07/29] Improved #region formatting. --- .../Formatter/FormattingVisitor_Global.cs | 13 ++++++++++--- .../FormattingTests/TestBlankLineFormatting.cs | 17 +++++++++-------- .../FormattingTests/TestTypeLevelIndentation.cs | 10 ---------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Formatter/FormattingVisitor_Global.cs b/ICSharpCode.NRefactory.CSharp/Formatter/FormattingVisitor_Global.cs index a8720aa0a..09f4c4142 100644 --- a/ICSharpCode.NRefactory.CSharp/Formatter/FormattingVisitor_Global.cs +++ b/ICSharpCode.NRefactory.CSharp/Formatter/FormattingVisitor_Global.cs @@ -256,17 +256,24 @@ int GetTypeLevelNewLinesFor(AstNode child) var nextSibling = child.GetNextSibling(NoWhitespacePredicate); if (child is PreProcessorDirective) { var directive = (PreProcessorDirective)child; - if (directive.Type == PreProcessorDirectiveType.Region) + if (directive.Type == PreProcessorDirectiveType.Region) { blankLines += policy.BlankLinesInsideRegion; - if (directive.Type == PreProcessorDirectiveType.Endregion) + } + if (directive.Type == PreProcessorDirectiveType.Endregion) { + if (child.GetNextSibling(NoWhitespacePredicate) is CSharpTokenNode) + return 1; blankLines += policy.BlankLinesAroundRegion; + } return blankLines; } if (nextSibling is PreProcessorDirective) { var directive = (PreProcessorDirective)nextSibling; - if (directive.Type == PreProcessorDirectiveType.Region) + if (directive.Type == PreProcessorDirectiveType.Region) { + if (child is CSharpTokenNode) + return 1; blankLines += policy.BlankLinesAroundRegion; + } if (directive.Type == PreProcessorDirectiveType.Endregion) blankLines += policy.BlankLinesInsideRegion; if (directive.Type == PreProcessorDirectiveType.Endif) diff --git a/ICSharpCode.NRefactory.Tests/FormattingTests/TestBlankLineFormatting.cs b/ICSharpCode.NRefactory.Tests/FormattingTests/TestBlankLineFormatting.cs index eab9aae66..35b5e0f23 100644 --- a/ICSharpCode.NRefactory.Tests/FormattingTests/TestBlankLineFormatting.cs +++ b/ICSharpCode.NRefactory.Tests/FormattingTests/TestBlankLineFormatting.cs @@ -293,10 +293,11 @@ void AMethod () } #endregion + void BMethod () + { + } }", @"class Test { - - #region FooBar void AMethod () @@ -306,6 +307,9 @@ void AMethod () #endregion + void BMethod () + { + } }", FormattingMode.Intrusive); policy.BlankLinesAroundRegion = 0; @@ -318,6 +322,9 @@ void AMethod () } #endregion + void BMethod () + { + } }", FormattingMode.Intrusive); } @@ -328,16 +335,13 @@ public void TestBlankLinesInsideRegion () policy.BlankLinesInsideRegion = 2; var adapter = Test (policy, @"class Test { - #region FooBar void AMethod () { } #endregion - }", @"class Test { - #region FooBar @@ -347,19 +351,16 @@ void AMethod () #endregion - }", FormattingMode.Intrusive); policy.BlankLinesInsideRegion = 0; Continue (policy, adapter, @"class Test { - #region FooBar void AMethod () { } #endregion - }", FormattingMode.Intrusive); } diff --git a/ICSharpCode.NRefactory.Tests/FormattingTests/TestTypeLevelIndentation.cs b/ICSharpCode.NRefactory.Tests/FormattingTests/TestTypeLevelIndentation.cs index c49ea16bd..ca4914e49 100644 --- a/ICSharpCode.NRefactory.Tests/FormattingTests/TestTypeLevelIndentation.cs +++ b/ICSharpCode.NRefactory.Tests/FormattingTests/TestTypeLevelIndentation.cs @@ -70,19 +70,15 @@ public void TestPreProcessorIndenting() Test(policy, @" class Test { - #region FooBar #endregion - }", @" class Test { - #region FooBar #endregion - }"); } @@ -956,11 +952,9 @@ public void TestIndentPreprocessorStatementsAdd() #endregion }", @"class Test { - #region DEBUG #endregion - }"); } @@ -973,18 +967,14 @@ public void TestIndentPreprocessorStatementsRemove() Test(policy, @"class Test { - #region DEBUG #endregion - }", @"class Test { - #region DEBUG #endregion - }"); } From 526223b15ed9b9ea0b62560afd4bcaa113d5fc24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 22 Nov 2013 05:58:04 +0100 Subject: [PATCH 08/29] Added some parameter checks. --- ICSharpCode.NRefactory/TypeSystem/TypeSystemExtensions.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ICSharpCode.NRefactory/TypeSystem/TypeSystemExtensions.cs b/ICSharpCode.NRefactory/TypeSystem/TypeSystemExtensions.cs index 8a1c82583..b7215c0eb 100644 --- a/ICSharpCode.NRefactory/TypeSystem/TypeSystemExtensions.cs +++ b/ICSharpCode.NRefactory/TypeSystem/TypeSystemExtensions.cs @@ -507,6 +507,8 @@ public static IList Resolve(this IList constantVa #region GetSubTypeDefinitions public static IEnumerable GetSubTypeDefinitions (this IType baseType) { + if (baseType == null) + throw new ArgumentNullException ("baseType"); var def = baseType.GetDefinition (); if (def == null) return Enumerable.Empty (); @@ -518,6 +520,8 @@ public static IEnumerable GetSubTypeDefinitions (this IType bas /// public static IEnumerable GetSubTypeDefinitions (this ITypeDefinition baseType) { + if (baseType == null) + throw new ArgumentNullException ("baseType"); foreach (var contextType in baseType.Compilation.GetAllTypeDefinitions ()) { if (contextType.IsDerivedFrom (baseType)) yield return contextType; From 59d92095ccad0d17821e46360256df62d5de2b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 22 Nov 2013 07:19:44 +0100 Subject: [PATCH 09/29] Added support for de indent anonymous method bodies. VS.NET does that with their default formatting settings - I guess it's an allman style thing. Maybe a new option should be introduced for that ? --- .../IndentEngine/IndentState.cs | 11 ++++--- .../IndentationTests/BlockTest.cs | 32 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs index 01de1df5f..fd48a58f7 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs @@ -478,7 +478,8 @@ public override char ClosedBracket public BracesBodyState(CSharpIndentEngine engine, IndentState parent = null) : base(engine, parent) - { } + { + } public BracesBodyState(BracesBodyState prototype, CSharpIndentEngine engine) : base(prototype, engine) @@ -1081,9 +1082,11 @@ public override void Push(char ch) { if (ch == Engine.newLineChar) { - if (NextLineIndent.PopIf(IndentType.Continuation)) - { - NextLineIndent.Push(IndentType.Block); + if (Engine.formattingOptions.AnonymousMethodBraceStyle == BraceStyle.EndOfLine || + Engine.formattingOptions.AnonymousMethodBraceStyle == BraceStyle.EndOfLineWithoutSpace) { + if (NextLineIndent.PopIf(IndentType.Continuation)) { + NextLineIndent.Push(IndentType.Block); + } } } else if (!IsSomethingPushed) diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs index cc40018d3..82201664d 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs @@ -842,6 +842,38 @@ void Test () Assert.AreEqual("\t\t\t", indent.NextLineIndent); } + [Test] + public void TestBrackets_AnonymousMethodOpenBracketAlignment() + { + var policy = FormattingOptionsFactory.CreateAllman(); + var indent = Helper.CreateEngine(@" +class Foo +{ + void Test () + { + Foo (delegate + {$ +", policy); + Assert.AreEqual("\t\t", indent.ThisLineIndent); + Assert.AreEqual("\t\t\t", indent.NextLineIndent); + } + + [Test] + public void TestBrackets_AnonymousMethodCloseingBracketAlignment() + { + var policy = FormattingOptionsFactory.CreateAllman(); + var indent = Helper.CreateEngine(@" +class Foo +{ + void Test () + { + Foo (delegate + { + }$ +", policy); + Assert.AreEqual("\t\t", indent.ThisLineIndent); + } + [Test] public void TestBrackets_ArrayCreationAsFirstParameterWithoutAlignment() { From 1c10a1c210a2065513b0cf5795aaf3a859ec1b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 25 Nov 2013 08:51:25 +0100 Subject: [PATCH 10/29] Removed duplicate code issue --- ...thodOverloadHidesOptionalParameterIssue.cs | 85 ------------------ ...verloadHidesOptionalParameterIssueTests.cs | 87 ------------------- ...OverloadWithOptionalParameterIssueTests.cs | 53 +++++++++++ .../ICSharpCode.NRefactory.Tests.csproj | 2 - 4 files changed, 53 insertions(+), 174 deletions(-) delete mode 100644 ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Uncategorized/MethodOverloadHidesOptionalParameterIssue.cs delete mode 100644 ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadHidesOptionalParameterIssueTests.cs diff --git a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Uncategorized/MethodOverloadHidesOptionalParameterIssue.cs b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Uncategorized/MethodOverloadHidesOptionalParameterIssue.cs deleted file mode 100644 index 1c7469a48..000000000 --- a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Uncategorized/MethodOverloadHidesOptionalParameterIssue.cs +++ /dev/null @@ -1,85 +0,0 @@ -// -// MethodOverloadHidesOptionalParameterIssue.cs -// -// Author: -// Mansheng Yang -// -// Copyright (c) 2012 Mansheng Yang -// -// 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.Collections.Generic; -using System.Linq; -using ICSharpCode.NRefactory.Semantics; -using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.Refactoring; - -namespace ICSharpCode.NRefactory.CSharp.Refactoring -{ - [IssueDescription("Method with optional parameter is hidden by overload", - Description = "Method with optional parameter is hidden by overload", - Category = IssueCategories.CodeQualityIssues, - Severity = Severity.Warning, - AnalysisDisableKeyword = "MethodOverloadWithOptionalParameter")] - public class MethodOverloadHidesOptionalParameterIssue : GatherVisitorCodeIssueProvider - { - protected override IGatherVisitor CreateVisitor(BaseRefactoringContext context) - { - return new GatherVisitor(context); - } - - class GatherVisitor : GatherVisitorBase - { - public GatherVisitor(BaseRefactoringContext ctx) - : base(ctx) - { - } - - public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) - { - base.VisitMethodDeclaration(methodDeclaration); - - var resolveResult = ctx.Resolve(methodDeclaration) as MemberResolveResult; - if (resolveResult == null) - return; - var method = resolveResult.Member as IMethod; - if (method == null) - return; - - if (method.Parameters.Count == 0 || !method.Parameters.Last().IsOptional) - return; - - var overloads = method.DeclaringType.GetMethods(m => m.Name == method.Name && m.TypeParameters.Count == method.TypeParameters.Count) - .ToArray(); - - var parameterNodes = methodDeclaration.Parameters.ToArray(); - var parameters = new List(); - for (int i = 0; i < method.Parameters.Count; i++) { - if (method.Parameters[i].IsOptional && - overloads.Any(m => ParameterListComparer.Instance.Equals(parameters, m.Parameters))) { - AddIssue(new CodeIssue(parameterNodes[i].StartLocation, parameterNodes.Last().EndLocation, - ctx.TranslateString("Method with optional parameter is hidden by overload"))); - break; - } - parameters.Add(method.Parameters[i]); - } - } - } - } -} diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadHidesOptionalParameterIssueTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadHidesOptionalParameterIssueTests.cs deleted file mode 100644 index 5c72a57ee..000000000 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadHidesOptionalParameterIssueTests.cs +++ /dev/null @@ -1,87 +0,0 @@ -// -// MethodOverloadHidesOptionalParameterIssueTests.cs -// -// Author: -// Mansheng Yang -// -// Copyright (c) 2012 Mansheng Yang -// -// 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 ICSharpCode.NRefactory.CSharp.Refactoring; -using NUnit.Framework; - -namespace ICSharpCode.NRefactory.CSharp.CodeIssues -{ - [TestFixture] - public class MethodOverloadHidesOptionalParameterIssueTests : InspectionActionTestBase - { - [Test] - public void Test () - { - var input = @" -class TestClass -{ - void TestMethod (int a) - { } - void TestMethod (int a, int b = 1) - { } -}"; - Test (input, 1); - } - - [Test] - public void Test2 () - { - var input = @" -class TestClass -{ - void TestMethod (int a, int b) - { } - void TestMethod (int a, int b = 1, int c = 1) - { } -}"; - Test (input, 1); - } - - [Test] - public void TestNoIssue () - { - var input = @" -class TestClass -{ - void TestMethod (int a, int b = 1, int c = 1) - { } -}"; - Test (input, 0); - } - - [Test] - public void TestNoIssue_Generics () - { - var input = @" -class TestClass -{ - void TestMethod (object obj) { } - void TestMethod (object obj, int arg = 0) { } -}"; - Test (input, 0); - } - } -} diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadWithOptionalParameterIssueTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadWithOptionalParameterIssueTests.cs index 4525b3e9b..0cab8e01c 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadWithOptionalParameterIssueTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/MethodOverloadWithOptionalParameterIssueTests.cs @@ -120,6 +120,59 @@ private void Print(string message, string messageDelimiter = ""==="") } "); } + + [Test] + public void Test () + { + var input = @" +class TestClass +{ + void TestMethod (int a) + { } + void TestMethod (int a, int b = 1) + { } +}"; + Test (input, 1); + } + + [Test] + public void Test2 () + { + var input = @" +class TestClass +{ + void TestMethod (int a, int b) + { } + void TestMethod (int a, int b = 1, int c = 1) + { } +}"; + Test (input, 1); + } + + [Test] + public void TestNoIssue () + { + var input = @" +class TestClass +{ + void TestMethod (int a, int b = 1, int c = 1) + { } +}"; + Test (input, 0); + } + + [Test] + public void TestNoIssue_Generics () + { + var input = @" +class TestClass +{ + void TestMethod (object obj) { } + void TestMethod (object obj, int arg = 0) { } +}"; + Test (input, 0); + } + } } diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index 005628ea3..d1d2c8e27 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -131,7 +131,6 @@ - @@ -618,7 +617,6 @@ {D68133BD-1E63-496E-9EDE-4FBDBF77B486} Mono.Cecil - True {53DCA265-3C3C-42F9-B647-F72BA678122B} From b39f2cb6d8ab1937d8b1fd5ef55a2c55ba95e9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 25 Nov 2013 08:51:36 +0100 Subject: [PATCH 11/29] Fixed some issue descriptions. --- .../CodeQuality/MethodOverloadWithOptionalParameterIssue.cs | 2 +- .../CodeQuality/PossibleAssignmentToReadonlyFieldIssue.cs | 4 ++-- .../RedundanciesInCode/RedundantExplicitArrayCreationIssue.cs | 4 ++-- .../RedundantToStringCallForValueTypesIssue.cs | 2 +- .../ICSharpCode.NRefactory.CSharp.Refactoring.csproj | 1 - 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/CodeQuality/MethodOverloadWithOptionalParameterIssue.cs b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/CodeQuality/MethodOverloadWithOptionalParameterIssue.cs index 1aafa2d88..beb91ae5d 100644 --- a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/CodeQuality/MethodOverloadWithOptionalParameterIssue.cs +++ b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/CodeQuality/MethodOverloadWithOptionalParameterIssue.cs @@ -89,7 +89,7 @@ public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) return; CheckParameters (method, method.DeclaringType.GetMethods(m => - m.Name == method.Name).Cast().ToList(), + m.Name == method.Name && m.TypeParameters.Count == method.TypeParameters.Count).Cast().ToList(), methodDeclaration.Parameters.ToList() ); diff --git a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/CodeQuality/PossibleAssignmentToReadonlyFieldIssue.cs b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/CodeQuality/PossibleAssignmentToReadonlyFieldIssue.cs index 7e5afce5d..ac7b51769 100644 --- a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/CodeQuality/PossibleAssignmentToReadonlyFieldIssue.cs +++ b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/CodeQuality/PossibleAssignmentToReadonlyFieldIssue.cs @@ -32,8 +32,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring { [IssueDescription ( - "Check if a namespace corresponds to a file location", - Description = "Check if a namespace corresponds to a file location", + "Possible assignment to readonly field", + Description = "Check if a readonly field is used as assignment target", Category = IssueCategories.CodeQualityIssues, Severity = Severity.Warning, AnalysisDisableKeyword = "PossibleAssignmentToReadonlyField")] diff --git a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/RedundanciesInCode/RedundantExplicitArrayCreationIssue.cs b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/RedundanciesInCode/RedundantExplicitArrayCreationIssue.cs index 979d511f8..b86cedfe4 100644 --- a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/RedundanciesInCode/RedundantExplicitArrayCreationIssue.cs +++ b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/RedundanciesInCode/RedundantExplicitArrayCreationIssue.cs @@ -32,8 +32,8 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring { [IssueDescription( - "Redundant explicit size in array creation", - Description = "Redundant explicit size in array creation", + "Redundant explicit type in array creation", + Description = "Redundant explicit type in array creation", Category = IssueCategories.RedundanciesInCode, Severity = Severity.Warning, AnalysisDisableKeyword = "RedundantExplicitArrayCreation")] diff --git a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/RedundanciesInCode/RedundantToStringCallForValueTypesIssue.cs b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/RedundanciesInCode/RedundantToStringCallForValueTypesIssue.cs index 227bc6924..5c3b74d4f 100644 --- a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/RedundanciesInCode/RedundantToStringCallForValueTypesIssue.cs +++ b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeIssues/Synced/RedundanciesInCode/RedundantToStringCallForValueTypesIssue.cs @@ -35,7 +35,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring { [IssueDescription("Redundant 'object.ToString()' call for value types", - Description = "Finds calls to ToString() which would be generated automatically by the compiler.", + Description = "Finds value type calls to ToString() which would be generated automatically by the compiler.", Category = IssueCategories.RedundanciesInCode, Severity = Severity.Hint)] public class RedundantToStringCallForValueTypesIssue : GatherVisitorCodeIssueProvider diff --git a/ICSharpCode.NRefactory.CSharp.Refactoring/ICSharpCode.NRefactory.CSharp.Refactoring.csproj b/ICSharpCode.NRefactory.CSharp.Refactoring/ICSharpCode.NRefactory.CSharp.Refactoring.csproj index f5d2ae1d5..0f70e17b1 100644 --- a/ICSharpCode.NRefactory.CSharp.Refactoring/ICSharpCode.NRefactory.CSharp.Refactoring.csproj +++ b/ICSharpCode.NRefactory.CSharp.Refactoring/ICSharpCode.NRefactory.CSharp.Refactoring.csproj @@ -314,7 +314,6 @@ - From 132fb46096b9f4ce71d05e9906f7fee2cecd550d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 25 Nov 2013 15:33:01 +0100 Subject: [PATCH 12/29] Fixed text paste bug. --- .../IndentEngine/CSharpIndentEngine.cs | 9 +++++++++ .../IndentEngine/CacheIndentEngine.cs | 7 +++++++ .../IndentEngine/IDocumentIndentEngine.cs | 6 ++++++ .../IndentEngine/IndentState.cs | 2 +- .../IndentEngine/NullIStateMachineIndentEngine.cs | 6 ++++++ .../IndentEngine/TextPasteIndentEngine.cs | 9 ++++++++- .../TextPasteIndentEngineTests.cs | 15 +++++++++++++++ 7 files changed, 52 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/CSharpIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/CSharpIndentEngine.cs index d961f335b..038d6b973 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/CSharpIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/CSharpIndentEngine.cs @@ -196,6 +196,14 @@ public bool EnableCustomIndentLevels set; } + /// + /// If this is true, the engine tries to better readjust clipboard contents. + /// + public bool InClipboardFormatMode { + get; + set; + } + #endregion #region Fields @@ -327,6 +335,7 @@ public CSharpIndentEngine(CSharpIndentEngine prototype) this.ifDirectiveEvalResult = new Stack(prototype.ifDirectiveEvalResult.Reverse()); this.EnableCustomIndentLevels = prototype.EnableCustomIndentLevels; + this.InClipboardFormatMode = prototype.InClipboardFormatMode; } #endregion diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/CacheIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/CacheIndentEngine.cs index b19f38868..9143f1593 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/CacheIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/CacheIndentEngine.cs @@ -122,6 +122,13 @@ public bool EnableCustomIndentLevels set { currentEngine.EnableCustomIndentLevels = value; } } + /// + public bool InClipboardFormatMode + { + get { return currentEngine.InClipboardFormatMode; } + set { currentEngine.InClipboardFormatMode = value; } + } + /// public void Push(char ch) { diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/IDocumentIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/IDocumentIndentEngine.cs index 821aa0bc8..5b1d9ef46 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/IDocumentIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/IDocumentIndentEngine.cs @@ -74,6 +74,12 @@ public interface IDocumentIndentEngine : ICloneable /// bool EnableCustomIndentLevels { get; set; } + /// + /// If this is true, the engine tries to better readjust clipboard contents. + /// + bool InClipboardFormatMode { get; set; } + + /// /// Pushes a new char into the engine which calculates the new /// indentation levels. diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs index fd48a58f7..612b5558a 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs @@ -1701,7 +1701,7 @@ public class LineCommentState : IndentState public LineCommentState(CSharpIndentEngine engine, IndentState parent = null) : base(engine, parent) { - if (engine.formattingOptions.KeepCommentsAtFirstColumn && engine.column == 2) + if (engine.formattingOptions.KeepCommentsAtFirstColumn && engine.column == 2 && !engine.InClipboardFormatMode) ThisLineIndent.Reset(); } diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/NullIStateMachineIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/NullIStateMachineIndentEngine.cs index b62932e5b..a39d5dbe1 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/NullIStateMachineIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/NullIStateMachineIndentEngine.cs @@ -202,6 +202,12 @@ public bool EnableCustomIndentLevels set { } } + /// + public bool InClipboardFormatMode + { + get { return false; } + set { } + } #endregion #region ICloneable implementation diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs index 11218c2b1..6177ab30e 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs @@ -128,6 +128,7 @@ string ITextPasteHandler.FormatPlainText(int offset, string text, byte[] copyDat var indentedText = new StringBuilder(); var curLine = new StringBuilder(); var clonedEngine = engine.Clone(); + clonedEngine.InClipboardFormatMode = true; bool isNewLine = false, gotNewLine = false; for (int i = 0; i < text.Length; i++) { var ch = text [i]; @@ -241,7 +242,13 @@ public bool EnableCustomIndentLevels { get { return engine.EnableCustomIndentLevels; } set { engine.EnableCustomIndentLevels = value; } } - + + /// + public bool InClipboardFormatMode { + get { return engine.InClipboardFormatMode; } + set { engine.InClipboardFormatMode = value; } + } + /// public void Push(char ch) { diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs index bcef892f9..a8169cfef 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs @@ -348,6 +348,21 @@ public void PasteInTerminatedVerbatimString () var text = handler.FormatPlainText(indent.Offset, "Hi \" + username;", null); Assert.AreEqual("Hi \"\" + username;", text); } + + + /// + /// Bug 16415 - Formatter - Copy paste comments + /// + [Test] + public void TestBug16415 () + { + var opt = FormattingOptionsFactory.CreateMono(); + var indent = CreateEngine("class Foo\n{\n\tpublic static void Main (string[] args)\n\t{\n\t\tConsole.WriteLine ();$\n\t}\n}\n", opt); + ITextPasteHandler handler = new TextPasteIndentEngine(indent, CreateInvariantOptions (), opt); + var text = handler.FormatPlainText(indent.Offset, "// Line 1\n// Line 2\n// Line 3", null); + Assert.AreEqual("// Line 1\n\t\t// Line 2\n\t\t// Line 3", text); + } + } } From 8ca5b14cd028a4a2952411dd3eed31ae95f87aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 25 Nov 2013 16:52:54 +0100 Subject: [PATCH 13/29] Revert "Fixed text paste bug." This reverts commit 132fb46096b9f4ce71d05e9906f7fee2cecd550d. --- .../IndentEngine/CSharpIndentEngine.cs | 9 --------- .../IndentEngine/CacheIndentEngine.cs | 7 ------- .../IndentEngine/IDocumentIndentEngine.cs | 6 ------ .../IndentEngine/IndentState.cs | 2 +- .../IndentEngine/NullIStateMachineIndentEngine.cs | 6 ------ .../IndentEngine/TextPasteIndentEngine.cs | 9 +-------- .../TextPasteIndentEngineTests.cs | 15 --------------- 7 files changed, 2 insertions(+), 52 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/CSharpIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/CSharpIndentEngine.cs index 038d6b973..d961f335b 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/CSharpIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/CSharpIndentEngine.cs @@ -196,14 +196,6 @@ public bool EnableCustomIndentLevels set; } - /// - /// If this is true, the engine tries to better readjust clipboard contents. - /// - public bool InClipboardFormatMode { - get; - set; - } - #endregion #region Fields @@ -335,7 +327,6 @@ public CSharpIndentEngine(CSharpIndentEngine prototype) this.ifDirectiveEvalResult = new Stack(prototype.ifDirectiveEvalResult.Reverse()); this.EnableCustomIndentLevels = prototype.EnableCustomIndentLevels; - this.InClipboardFormatMode = prototype.InClipboardFormatMode; } #endregion diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/CacheIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/CacheIndentEngine.cs index 9143f1593..b19f38868 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/CacheIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/CacheIndentEngine.cs @@ -122,13 +122,6 @@ public bool EnableCustomIndentLevels set { currentEngine.EnableCustomIndentLevels = value; } } - /// - public bool InClipboardFormatMode - { - get { return currentEngine.InClipboardFormatMode; } - set { currentEngine.InClipboardFormatMode = value; } - } - /// public void Push(char ch) { diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/IDocumentIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/IDocumentIndentEngine.cs index 5b1d9ef46..821aa0bc8 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/IDocumentIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/IDocumentIndentEngine.cs @@ -74,12 +74,6 @@ public interface IDocumentIndentEngine : ICloneable /// bool EnableCustomIndentLevels { get; set; } - /// - /// If this is true, the engine tries to better readjust clipboard contents. - /// - bool InClipboardFormatMode { get; set; } - - /// /// Pushes a new char into the engine which calculates the new /// indentation levels. diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs index 612b5558a..fd48a58f7 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs @@ -1701,7 +1701,7 @@ public class LineCommentState : IndentState public LineCommentState(CSharpIndentEngine engine, IndentState parent = null) : base(engine, parent) { - if (engine.formattingOptions.KeepCommentsAtFirstColumn && engine.column == 2 && !engine.InClipboardFormatMode) + if (engine.formattingOptions.KeepCommentsAtFirstColumn && engine.column == 2) ThisLineIndent.Reset(); } diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/NullIStateMachineIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/NullIStateMachineIndentEngine.cs index a39d5dbe1..b62932e5b 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/NullIStateMachineIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/NullIStateMachineIndentEngine.cs @@ -202,12 +202,6 @@ public bool EnableCustomIndentLevels set { } } - /// - public bool InClipboardFormatMode - { - get { return false; } - set { } - } #endregion #region ICloneable implementation diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs index 6177ab30e..11218c2b1 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs @@ -128,7 +128,6 @@ string ITextPasteHandler.FormatPlainText(int offset, string text, byte[] copyDat var indentedText = new StringBuilder(); var curLine = new StringBuilder(); var clonedEngine = engine.Clone(); - clonedEngine.InClipboardFormatMode = true; bool isNewLine = false, gotNewLine = false; for (int i = 0; i < text.Length; i++) { var ch = text [i]; @@ -242,13 +241,7 @@ public bool EnableCustomIndentLevels { get { return engine.EnableCustomIndentLevels; } set { engine.EnableCustomIndentLevels = value; } } - - /// - public bool InClipboardFormatMode { - get { return engine.InClipboardFormatMode; } - set { engine.InClipboardFormatMode = value; } - } - + /// public void Push(char ch) { diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs index a8169cfef..bcef892f9 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs @@ -348,21 +348,6 @@ public void PasteInTerminatedVerbatimString () var text = handler.FormatPlainText(indent.Offset, "Hi \" + username;", null); Assert.AreEqual("Hi \"\" + username;", text); } - - - /// - /// Bug 16415 - Formatter - Copy paste comments - /// - [Test] - public void TestBug16415 () - { - var opt = FormattingOptionsFactory.CreateMono(); - var indent = CreateEngine("class Foo\n{\n\tpublic static void Main (string[] args)\n\t{\n\t\tConsole.WriteLine ();$\n\t}\n}\n", opt); - ITextPasteHandler handler = new TextPasteIndentEngine(indent, CreateInvariantOptions (), opt); - var text = handler.FormatPlainText(indent.Offset, "// Line 1\n// Line 2\n// Line 3", null); - Assert.AreEqual("// Line 1\n\t\t// Line 2\n\t\t// Line 3", text); - } - } } From 8e5f884ea8a109b059cce0d61bb34c75fd1e647e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 25 Nov 2013 16:55:36 +0100 Subject: [PATCH 14/29] Found better fix for the problem. --- .../IndentEngine/IndentState.cs | 4 ++-- .../IndentationTests/AlignmentTests.cs | 1 + .../IndentationTests/CommentTests.cs | 1 + .../IndentationTests/TextPasteIndentEngineTests.cs | 14 ++++++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs index fd48a58f7..92410407a 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs @@ -1701,8 +1701,8 @@ public class LineCommentState : IndentState public LineCommentState(CSharpIndentEngine engine, IndentState parent = null) : base(engine, parent) { - if (engine.formattingOptions.KeepCommentsAtFirstColumn && engine.column == 2) - ThisLineIndent.Reset(); + /* if (engine.formattingOptions.KeepCommentsAtFirstColumn && engine.column == 2) + ThisLineIndent.Reset();*/ } public LineCommentState(LineCommentState prototype, CSharpIndentEngine engine) diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/AlignmentTests.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/AlignmentTests.cs index ee68dbde9..5ab86b579 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/AlignmentTests.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/AlignmentTests.cs @@ -233,6 +233,7 @@ class Foo Assert.AreEqual("\t", indent.NextLineIndent); } + [Ignore ("Should not be respected")] [Test] public void TestFormatFirstLineKeepTrue() { diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/CommentTests.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/CommentTests.cs index 5ed67a599..9f1faa618 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/CommentTests.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/CommentTests.cs @@ -123,6 +123,7 @@ line 2 Assert.AreEqual("\t", indent.NextLineIndent); } + [Ignore ("Should not be respected")] [Test] public void TestCommentBug() { diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs index bcef892f9..9ea04a792 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs @@ -348,6 +348,20 @@ public void PasteInTerminatedVerbatimString () var text = handler.FormatPlainText(indent.Offset, "Hi \" + username;", null); Assert.AreEqual("Hi \"\" + username;", text); } + + + /// + /// Bug 16415 - Formatter - Copy paste comments + /// + [Test] + public void TestBug16415 () + { + var opt = FormattingOptionsFactory.CreateMono(); + var indent = CreateEngine("class Foo\n{\n\tpublic static void Main (string[] args)\n\t{\n\t\tConsole.WriteLine ();$\n\t}\n}\n", opt); + ITextPasteHandler handler = new TextPasteIndentEngine(indent, CreateInvariantOptions (), opt); + var text = handler.FormatPlainText(indent.Offset, "// Line 1\n// Line 2\n// Line 3", null); + Assert.AreEqual("// Line 1\n\t\t// Line 2\n\t\t// Line 3", text); + } } } From bc5a68be5e17c74812c91548dda7d400c622ec61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Tue, 26 Nov 2013 07:04:56 +0100 Subject: [PATCH 15/29] Fixed bug in RemoveBackingStoreAction --- .../CodeActions/RemoveBackingStoreAction.cs | 14 ++++++++- .../CodeActions/RemoveBackingStoreTests.cs | 29 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeActions/RemoveBackingStoreAction.cs b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeActions/RemoveBackingStoreAction.cs index 4074394aa..44ebc6d72 100644 --- a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeActions/RemoveBackingStoreAction.cs +++ b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeActions/RemoveBackingStoreAction.cs @@ -53,7 +53,19 @@ public override IEnumerable GetActions(RefactoringContext context) yield return new CodeAction(context.TranslateString("Convert to auto property"), script => { script.Rename((IEntity)field, newProperty.Name); - script.Remove (context.RootNode.GetNodeAt (field.Region.Begin)); + var oldField = context.RootNode.GetNodeAt(field.Region.Begin); + if (oldField.Variables.Count == 1) { + script.Remove(oldField); + } else { + var newField = (FieldDeclaration)oldField.Clone(); + foreach (var init in newField.Variables) { + if (init.Name == field.Name) { + init.Remove(); + break; + } + } + script.Replace(oldField, newField); + } script.Replace (property, newProperty); }, property.NameToken); } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/RemoveBackingStoreTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/RemoveBackingStoreTests.cs index e3ffdfe43..bded3ebed 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/RemoveBackingStoreTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/RemoveBackingStoreTests.cs @@ -174,7 +174,34 @@ class MyClass } "); } - + + + /// + /// Bug 16447 - Convert to Auto Property removes multiple variable if declared inline + /// + [Test] + public void TestBug16447 () + { + Test(@" +public class Foo +{ + int _bpm = 120, _index = 1, _count; + int $Count { + get { return _count; } + set { _count = value; } + } +} +", @" +public class Foo +{ + int _bpm = 120, _index = 1; + int Count { + get; + set; + } +} +"); + } } } From 8c56bf6171ef616fdcaf16d19055c529eefab5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Tue, 26 Nov 2013 07:35:02 +0100 Subject: [PATCH 16/29] Fixed bug in 'ConvertToAutoPropertyIssue'. --- .../CodeActions/RemoveBackingStoreAction.cs | 3 ++ .../ConvertToAutoPropertyIssueTests.cs | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeActions/RemoveBackingStoreAction.cs b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeActions/RemoveBackingStoreAction.cs index 44ebc6d72..504294d0b 100644 --- a/ICSharpCode.NRefactory.CSharp.Refactoring/CodeActions/RemoveBackingStoreAction.cs +++ b/ICSharpCode.NRefactory.CSharp.Refactoring/CodeActions/RemoveBackingStoreAction.cs @@ -147,6 +147,9 @@ internal static IField ScanSetter (BaseRefactoringContext context, PropertyDecla var assignment = setAssignment != null ? setAssignment.Expression as AssignmentExpression : null; if (assignment == null || assignment.Operator != AssignmentOperatorType.Assign) return null; + var idExpr = assignment.Right as IdentifierExpression; + if (idExpr == null || idExpr.Identifier != "value") + return null; if (!IsPossibleExpression(assignment.Left)) return null; var result = context.Resolve (assignment.Left); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ConvertToAutoPropertyIssueTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ConvertToAutoPropertyIssueTests.cs index 3fbedb259..ca3b939a1 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ConvertToAutoPropertyIssueTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeIssues/ConvertToAutoPropertyIssueTests.cs @@ -134,6 +134,34 @@ int A { } "); } + + + /// + /// Bug 16448 - Refactor incorrectly suggesting "Convert to Auto Property" on property containing custom logic + /// + [Test] + public void TestBug16448() + { + TestWrongContext(@" +using System; + +public class Foo +{ + int _bpm; + + public int BPM + { + get { return _bpm; } + set + { + _bpm = Math.Min(Math.Max(60, value), 180); + } + } +} +"); + } + + } } From 35931becf9416b5cd3eb25b198760306316769b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Fri, 29 Nov 2013 07:52:16 +0100 Subject: [PATCH 17/29] Fixed completion bug. --- .../Completion/CSharpCompletionEngine.cs | 21 +++++++++++++----- .../CSharp/CodeCompletion/NameContextTests.cs | 22 +++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index c36fb5fb1..3f688aa0d 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -983,6 +983,7 @@ IEnumerable MagicKeyCompletion(char completionChar, bool contro if (!(char.IsLetter(completionChar) || completionChar == '_') && (!controlSpace || identifierStart == null)) { return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null; } + if (identifierStart != null) { if (identifierStart.Node is TypeParameterDeclaration) { return null; @@ -1577,7 +1578,10 @@ IEnumerable DefaultControlSpaceItems(ExpressionResult xp = null return wrapper.Result; } } - + var pDecl = node as ParameterDeclaration; + if (pDecl != null && pDecl.Parent is LambdaExpression) { + return null; + } /* if (Unit != null && (node == null || node is TypeDeclaration)) { var constructor = Unit.GetNodeAt( location.Line, @@ -3277,10 +3281,7 @@ ExpressionResult GetExpressionAtCursor() if (expr == null) expr = baseUnit.GetNodeAt(location.Line, location.Column - 1); // try insertStatement - if (expr == null && baseUnit.GetNodeAt( - location.Line, - location.Column - ) != null) { + if (expr == null && baseUnit.GetNodeAt(location.Line, location.Column) != null) { tmpUnit = baseUnit = ParseStub("a();", false); expr = baseUnit.GetNodeAt( location.Line, @@ -3382,9 +3383,17 @@ ExpressionResult GetExpressionAtCursor() } } + // try lambda if (expr == null) { - return null; + baseUnit = ParseStub(") => {}", false); + expr = baseUnit.GetNodeAt( + location.Line, + location.Column + ); } + + if (expr == null) + return null; return new ExpressionResult(expr, baseUnit); } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/NameContextTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/NameContextTests.cs index a417a8c7d..e0a421fa1 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/NameContextTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/NameContextTests.cs @@ -267,6 +267,28 @@ public static void Main (string[] args) } ", provider => Assert.AreEqual(0, provider.Count, "provider needs to be empty")); } + + /// + /// Bug 16491 - Wrong completion on multiple parameter lambdas + /// + [Test] + public void TestBug16491 () + { + CodeCompletionBugTests.CombinedProviderTest (@" +using System; +using System.IO; + +class Foo +{ + public static void Main (string[] args) + { + $new Action ((x, y$ + } +} +", provider => Assert.AreEqual(0, provider.Count, "provider needs to be empty")); + + } + } } From 2f652d670176f67bdda747a2120143e5b4081cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 2 Dec 2013 13:55:26 +0100 Subject: [PATCH 18/29] Fixed text paste bug. --- .../IndentEngine/TextPasteIndentEngine.cs | 1 + .../IndentationTests/TextPasteIndentEngineTests.cs | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs index 11218c2b1..9170b029f 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/TextPasteIndentEngine.cs @@ -171,6 +171,7 @@ string ITextPasteHandler.FormatPlainText(int offset, string text, byte[] copyDat pasteAtLineStart = false; indentedText.Append(curLine); curLine.Length = 0; + gotNewLine = false; continue; } } diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs index 9ea04a792..2997990f5 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/TextPasteIndentEngineTests.cs @@ -245,6 +245,15 @@ public void PasteVerbatimStringBug3() Assert.AreEqual("\t\tSystem.Console.WriteLine(@\"\");\n\t\t", text); } + [Test] + public void PasteVerbatimStringBug4() + { + var indent = CreateEngine("\nclass Foo\n{\n\tvoid Bar ()\n\t{\n$\n\t}\n}"); + ITextPasteHandler handler = new TextPasteIndentEngine(indent, CreateInvariantOptions (), FormattingOptionsFactory.CreateMono()); + + var text = handler.FormatPlainText(indent.Offset, "var str1 = \n@\"hello\";", null); + Assert.AreEqual("\t\tvar str1 = \n\t\t\t@\"hello\";", text); + } [Test] public void TestPasteComments() From cc2a30a92d0e4a692960eafd2a241260ba3fb4e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 2 Dec 2013 14:06:05 +0100 Subject: [PATCH 19/29] Added some failing formatting tests. --- .../Formatter/CSharpFormattingOptions.cs | 7 +++ .../IndentationTests/BlockTest.cs | 44 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/ICSharpCode.NRefactory.CSharp/Formatter/CSharpFormattingOptions.cs b/ICSharpCode.NRefactory.CSharp/Formatter/CSharpFormattingOptions.cs index 458531c7c..9ee084422 100644 --- a/ICSharpCode.NRefactory.CSharp/Formatter/CSharpFormattingOptions.cs +++ b/ICSharpCode.NRefactory.CSharp/Formatter/CSharpFormattingOptions.cs @@ -160,6 +160,13 @@ public bool AlignEmbeddedIfStatements { // tested set; } + public bool AlignElseInIfStatements { + get; + set; + } + + + public PropertyFormatting AutoPropertyFormatting { // tested get; set; diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs index 82201664d..9f97a7559 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs @@ -950,5 +950,49 @@ void Test () Assert.AreEqual("\t\t\t", indent.ThisLineIndent); Assert.AreEqual("\t\t\t", indent.NextLineIndent); } + + [Ignore("Fixme")] + [Test] + public void TestComplexIfElseElsePlacement_AlignmentOff() + { + var policy = FormattingOptionsFactory.CreateMono(); + policy.AlignElseInIfStatements = false; + var indent = Helper.CreateEngine(@" +class Foo +{ + void Test () + { + if (1 > 0) + a = 1; + else + if (2 < 10) + a = 2; + else$ +", policy); + Assert.AreEqual("\t\t\t", indent.ThisLineIndent); + Assert.AreEqual("\t\t\t", indent.NextLineIndent); + } + + [Ignore("Fixme")] + [Test] + public void TestComplexIfElseElsePlacement_AlignmentOn() + { + var policy = FormattingOptionsFactory.CreateMono(); + policy.AlignElseInIfStatements = true; + var indent = Helper.CreateEngine(@" +class Foo +{ + void Test () + { + if (1 > 0) + a = 1; + else + if (2 < 10) + a = 2; + else$ +", policy); + Assert.AreEqual("\t\t", indent.ThisLineIndent); + Assert.AreEqual("\t\t\t", indent.NextLineIndent); + } } } From 4f31fc502d365469473ecd330ea58de381714a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Mikle=C4=8Di=C4=87?= Date: Mon, 2 Dec 2013 15:31:49 +0100 Subject: [PATCH 20/29] TestComplexIfElseElsePlacement. --- ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs | 3 ++- .../IndentationTests/BlockTest.cs | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs index 92410407a..8104e898f 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs @@ -783,7 +783,8 @@ public override void CheckKeyword(string keyword) // else statement is handled differently if (CurrentStatement == Statement.Else) { - if (NestedIfStatementLevels.Count > 0) + // OPTION: CSharpFormattingOptions.AlignElseInIfStatements + if (!Engine.formattingOptions.AlignElseInIfStatements && NestedIfStatementLevels.Count > 0) { ThisLineIndent = NestedIfStatementLevels.Pop().Clone(); NextLineIndent = ThisLineIndent.Clone(); diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs index 9f97a7559..2ae5c46c1 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs @@ -951,7 +951,6 @@ void Test () Assert.AreEqual("\t\t\t", indent.NextLineIndent); } - [Ignore("Fixme")] [Test] public void TestComplexIfElseElsePlacement_AlignmentOff() { @@ -967,13 +966,12 @@ void Test () else if (2 < 10) a = 2; - else$ + else $ ", policy); Assert.AreEqual("\t\t\t", indent.ThisLineIndent); - Assert.AreEqual("\t\t\t", indent.NextLineIndent); + Assert.AreEqual("\t\t\t\t", indent.NextLineIndent); } - [Ignore("Fixme")] [Test] public void TestComplexIfElseElsePlacement_AlignmentOn() { @@ -989,7 +987,7 @@ void Test () else if (2 < 10) a = 2; - else$ + else $ ", policy); Assert.AreEqual("\t\t", indent.ThisLineIndent); Assert.AreEqual("\t\t\t", indent.NextLineIndent); From 3f4fa3c177c3def47269bfc8a1f1281a01c6f506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Mikle=C4=8Di=C4=87?= Date: Mon, 2 Dec 2013 17:40:36 +0100 Subject: [PATCH 21/29] TestComplexIfElseElsePlacement v2. --- .../IndentEngine/IndentState.cs | 97 ++++++++++++++----- .../IndentationTests/BlockTest.cs | 7 +- 2 files changed, 77 insertions(+), 27 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs index 8104e898f..968f6d3ff 100644 --- a/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs +++ b/ICSharpCode.NRefactory.CSharp/IndentEngine/IndentState.cs @@ -210,6 +210,21 @@ public virtual void Push(char ch) public virtual void CheckKeyword(string keyword) { } + /// + /// When derived, checks if the given sequence of chars form + /// a valid keyword or variable name, depending on the state. + /// + /// + /// A possible keyword. + /// + /// + /// This method should be called from . + /// It is left to derived classes to call this method because of + /// performance issues. + /// + public virtual void CheckKeywordOnPush(string keyword) + { } + #endregion } @@ -557,6 +572,11 @@ public override void Push(char ch) ThisLineIndent.Push(IndentType.Continuation); } + if (Engine.wordToken.ToString() == "else") + { + CheckKeywordOnPush("else"); + } + base.Push(ch); } @@ -679,7 +699,7 @@ public enum Statement static readonly Dictionary statements = new Dictionary { { "if", Statement.If }, - { "else", Statement.Else }, + // { "else", Statement.Else }, // should be handled in CheckKeywordAtPush { "do", Statement.Do }, { "while", Statement.While }, { "for", Statement.For }, @@ -720,6 +740,39 @@ public enum Statement "struct" }; + /// + /// Checks if the given string is a keyword and sets the + /// and the + /// variables appropriately. + /// + /// + /// A possible keyword. + /// + /// + /// This method is called from + /// + public override void CheckKeywordOnPush(string keyword) + { + if (keyword == "else") + { + CurrentStatement = Statement.Else; + + // OPTION: CSharpFormattingOptions.AlignElseInIfStatements + if (!Engine.formattingOptions.AlignElseInIfStatements && NestedIfStatementLevels.Count > 0) + { + ThisLineIndent = NestedIfStatementLevels.Pop().Clone(); + NextLineIndent = ThisLineIndent.Clone(); + } + + NextLineIndent.Push(IndentType.Continuation); + } + + if (blocks.Contains(keyword) && Engine.NeedsReindent) + { + LastBlockIndent = Indent.ConvertFrom(Engine.CurrentIndent, ThisLineIndent, Engine.textEditorOptions); + } + } + /// /// Checks if the given string is a keyword and sets the /// and the @@ -780,30 +833,15 @@ public override void CheckKeyword(string keyword) NextLineIndent.PopIf(IndentType.Continuation); } - // else statement is handled differently - if (CurrentStatement == Statement.Else) + // only add continuation for 'else' in 'else if' statement. + if (!(CurrentStatement == Statement.If && previousStatement == Statement.Else && !Engine.isLineStartBeforeWordToken)) { - // OPTION: CSharpFormattingOptions.AlignElseInIfStatements - if (!Engine.formattingOptions.AlignElseInIfStatements && NestedIfStatementLevels.Count > 0) - { - ThisLineIndent = NestedIfStatementLevels.Pop().Clone(); - NextLineIndent = ThisLineIndent.Clone(); - } - NextLineIndent.Push(IndentType.Continuation); } - else - { - // only add continuation for 'else' in 'else if' statement. - if (!(CurrentStatement == Statement.If && previousStatement == Statement.Else && !Engine.isLineStartBeforeWordToken)) - { - NextLineIndent.Push(IndentType.Continuation); - } - if (CurrentStatement == Statement.If) - { - NestedIfStatementLevels.Push(ThisLineIndent); - } + if (CurrentStatement == Statement.If) + { + NestedIfStatementLevels.Push(ThisLineIndent); } } @@ -1269,7 +1307,7 @@ public override void Push(char ch) // happen, we check for "endregion" on every push. if (Engine.wordToken.ToString() == "endregion") { - ThisLineIndent = Parent.NextLineIndent.Clone(); + CheckKeywordOnPush("endregion"); } base.Push(ch); @@ -1372,7 +1410,7 @@ public override void InitializeState() { "else", PreProcessorDirective.Else }, { "endif", PreProcessorDirective.Endif }, { "region", PreProcessorDirective.Region }, - { "endregion", PreProcessorDirective.Region }, + { "endregion", PreProcessorDirective.Endregion }, { "pragma", PreProcessorDirective.Pragma }, { "warning", PreProcessorDirective.Warning }, { "error", PreProcessorDirective.Error }, @@ -1381,6 +1419,15 @@ public override void InitializeState() { "undef", PreProcessorDirective.Undef } }; + public override void CheckKeywordOnPush(string keyword) + { + if (keyword == "endregion") + { + DirectiveType = PreProcessorDirective.Endregion; + ThisLineIndent = Parent.NextLineIndent.Clone(); + } + } + public override void CheckKeyword(string keyword) { // check if the directive type has already been set @@ -1393,7 +1440,7 @@ public override void CheckKeyword(string keyword) { DirectiveType = preProcessorDirectives[keyword]; - // adjust the indentation for the region/endregion directives + // adjust the indentation for the region directive if (DirectiveType == PreProcessorDirective.Region) { ThisLineIndent = Parent.NextLineIndent.Clone(); @@ -1417,7 +1464,7 @@ public enum PreProcessorDirective Else, Endif, Region, - // EndRegion, // use Region instead + Endregion, Pragma, Warning, Error, diff --git a/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs b/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs index 2ae5c46c1..6ac89954b 100644 --- a/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs +++ b/ICSharpCode.NRefactory.Tests/IndentationTests/BlockTest.cs @@ -532,6 +532,7 @@ public void TestBrackets_StackedIfElse_AlignElseToCorrectIf() { CSharpFormattingOptions fmt = FormattingOptionsFactory.CreateMono(); fmt.AlignEmbeddedIfStatements = false; + fmt.AlignElseInIfStatements = false; var indent = Helper.CreateEngine(@" class Foo { void Test () @@ -549,6 +550,7 @@ public void TestBrackets_StackedIfElse_AlignElseToCorrectIf2() { CSharpFormattingOptions fmt = FormattingOptionsFactory.CreateMono(); fmt.AlignEmbeddedIfStatements = false; + fmt.AlignElseInIfStatements = false; var indent = Helper.CreateEngine(@" class Foo { void Test () @@ -590,6 +592,7 @@ public void TestBrackets_StackedIfElse_ElseIf() { CSharpFormattingOptions fmt = FormattingOptionsFactory.CreateMono(); fmt.AlignEmbeddedIfStatements = false; + fmt.AlignElseInIfStatements = false; var indent = Helper.CreateEngine(@" class Foo { void Test () @@ -966,7 +969,7 @@ void Test () else if (2 < 10) a = 2; - else $ + else$ ", policy); Assert.AreEqual("\t\t\t", indent.ThisLineIndent); Assert.AreEqual("\t\t\t\t", indent.NextLineIndent); @@ -987,7 +990,7 @@ void Test () else if (2 < 10) a = 2; - else $ + else$ ", policy); Assert.AreEqual("\t\t", indent.ThisLineIndent); Assert.AreEqual("\t\t\t", indent.NextLineIndent); From 3d46a4a110e97c28edbc1a7467e803035b7a593b Mon Sep 17 00:00:00 2001 From: Lucas Meijer Date: Wed, 4 Dec 2013 15:50:51 +0100 Subject: [PATCH 22/29] Implement support for Script.InsertAfter() to work after ParameterDeclarations --- .../Refactoring/Script.cs | 48 ++++++++++-- .../CSharp/Refactoring/ScriptTests.cs | 74 +++++++++++++++++++ 2 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 ICSharpCode.NRefactory.Tests/CSharp/Refactoring/ScriptTests.cs diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs index bf298d081..c19ea6fd9 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs @@ -25,12 +25,15 @@ // THE SOFTWARE. using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.TypeSystem; using System.Threading.Tasks; using System.Linq; using System.Text; +using Mono.CSharp; +using ITypeDefinition = ICSharpCode.NRefactory.TypeSystem.ITypeDefinition; namespace ICSharpCode.NRefactory.CSharp.Refactoring { @@ -163,18 +166,51 @@ public void InsertBefore(AstNode node, AstNode newNode) public void InsertAfter(AstNode node, AstNode newNode) { - var indentOffset = GetCurrentOffset(new TextLocation(node.StartLocation.Line, 1)); - var output = OutputNode (GetIndentLevelAt (indentOffset), newNode); - string text = output.Text; - if (!(newNode is Expression || newNode is AstType)) - text = Options.EolMarker + text; + var indentLevel = IndentLevelFor(node); + var output = OutputNode(indentLevel, newNode); + string text = PrefixFor(node, newNode) + output.Text; + var insertOffset = GetCurrentOffset(node.EndLocation); InsertText(insertOffset, text); output.RegisterTrackedSegments(this, insertOffset); CorrectFormatting (node, newNode); } - public void AddTo(BlockStatement bodyStatement, AstNode newNode) + private int IndentLevelFor(AstNode node) + { + if (!DoesInsertingAfterRequireNewline(node)) + return 0; + + return GetIndentLevelAt(GetCurrentOffset(new TextLocation(node.StartLocation.Line, 1))); + } + + bool DoesInsertingAfterRequireNewline(AstNode node) + { + if (node is Expression) + return false; + + if (node is AstType) + return false; + + if (node is ParameterDeclaration) + return false; + + return true; + } + + private string PrefixFor(AstNode node, AstNode newNode) + { + if (DoesInsertingAfterRequireNewline(node)) + return Options.EolMarker; + + if (newNode is ParameterDeclaration && node is ParameterDeclaration) + //todo: worry about adding characters to the document without matching AstNode's. + return ", "; + + return String.Empty; + } + + public void AddTo(BlockStatement bodyStatement, AstNode newNode) { var startOffset = GetCurrentOffset(bodyStatement.LBraceToken.EndLocation); var output = OutputNode(1 + GetIndentLevelAt(startOffset), newNode, true); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/ScriptTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/ScriptTests.cs new file mode 100644 index 000000000..3d46e0f2a --- /dev/null +++ b/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/ScriptTests.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ICSharpCode.NRefactory.Editor; +using NUnit.Framework; + +namespace ICSharpCode.NRefactory.CSharp.Refactoring +{ + [TestFixture] + public class ScriptTests + { + [Test] + public void InsertAfterStatementIndentsLikeStatement() + { + var input =@" +public class Test +{ + void DoublyIndented() + { + System.Console.WriteLine(""hello""); + } +}"; + var expected = @" +public class Test +{ + void DoublyIndented() + { + System.Console.WriteLine(""hello""); + return; + } +}"; + + DoInsertAfterTest(input, expected, (syntaxTree, script) => + { + var nodeToInsert = new ReturnStatement(); + var nodeToInsertAfter = syntaxTree.DescendantsAndSelf.OfType().Single(); + script.InsertAfter(nodeToInsertAfter,nodeToInsert); + }); + } + + [Test] + public void InsertParameterDeclarationDoesNotIndent() + { + var input =@" +public class Test +{ + void Test(int a) + { + } +}"; + var expected = @" +public class Test +{ + void Test(int a, int b) + { + } +}"; + DoInsertAfterTest(input, expected, (syntaxTree, script) => + { + var nodeToInsert = new ParameterDeclaration(new PrimitiveType("int"),"b"); + var nodeToInsertAfter = syntaxTree.DescendantsAndSelf.OfType().Single(); + script.InsertAfter(nodeToInsertAfter,nodeToInsert); + }); + } + + private static void DoInsertAfterTest(string s, string expected, Action doInsertion) + { + var script = new DocumentScript(new StringBuilderDocument(s), FormattingOptionsFactory.CreateEmpty(), new TextEditorOptions()); + doInsertion(new CSharpParser().Parse(s), script); + Assert.AreEqual(expected, script.CurrentDocument.Text); + } + } +} From f9ee154edebc5f073fccacd866a3753912aa5f0c Mon Sep 17 00:00:00 2001 From: Lucas Meijer Date: Wed, 4 Dec 2013 15:56:29 +0100 Subject: [PATCH 23/29] add support for using InsertAfter() on the left parenthesis of a methoddeclaration --- .../Refactoring/Script.cs | 4 +++ .../CSharp/Refactoring/ScriptTests.cs | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs index c19ea6fd9..b1691b956 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs @@ -195,6 +195,10 @@ bool DoesInsertingAfterRequireNewline(AstNode node) if (node is ParameterDeclaration) return false; + var token = node as CSharpTokenNode; + if (token != null && token.Role == Roles.LPar) + return false; + return true; } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/ScriptTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/ScriptTests.cs index 3d46e0f2a..f15d584ec 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/ScriptTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Refactoring/ScriptTests.cs @@ -64,6 +64,31 @@ void Test(int a, int b) }); } + [Test] + public void InsertFirstParameterDeclarationIntoMethod() + { + var input =@" +public class Test +{ + void Test() + { + } +}"; + var expected = @" +public class Test +{ + void Test(int a) + { + } +}"; + DoInsertAfterTest(input, expected, (syntaxTree, script) => + { + var nodeToInsert = new ParameterDeclaration(new PrimitiveType("int"),"a"); + var nodeToInsertAfter = syntaxTree.DescendantsAndSelf.OfType().Single().LParToken; + script.InsertAfter(nodeToInsertAfter,nodeToInsert); + }); + } + private static void DoInsertAfterTest(string s, string expected, Action doInsertion) { var script = new DocumentScript(new StringBuilderDocument(s), FormattingOptionsFactory.CreateEmpty(), new TextEditorOptions()); From 91fee8851fb1dddb8d601ce190654017fea222f0 Mon Sep 17 00:00:00 2001 From: Lucas Meijer Date: Wed, 4 Dec 2013 16:05:54 +0100 Subject: [PATCH 24/29] fix unintended whitespace changes --- ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs index b1691b956..d2bfb3dc4 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/Script.cs @@ -166,14 +166,14 @@ public void InsertBefore(AstNode node, AstNode newNode) public void InsertAfter(AstNode node, AstNode newNode) { - var indentLevel = IndentLevelFor(node); + var indentLevel = IndentLevelFor(node); var output = OutputNode(indentLevel, newNode); - string text = PrefixFor(node, newNode) + output.Text; + string text = PrefixFor(node, newNode) + output.Text; - var insertOffset = GetCurrentOffset(node.EndLocation); - InsertText(insertOffset, text); - output.RegisterTrackedSegments(this, insertOffset); - CorrectFormatting (node, newNode); + var insertOffset = GetCurrentOffset(node.EndLocation); + InsertText(insertOffset, text); + output.RegisterTrackedSegments(this, insertOffset); + CorrectFormatting (node, newNode); } private int IndentLevelFor(AstNode node) From baa14649b9d205a18d33c5b483c066ce9de36466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Mon, 9 Dec 2013 08:17:11 +0100 Subject: [PATCH 25/29] Fixed bug in CreateEnumValue/improved type guessing. --- .../Refactoring/TypeGuessing.cs | 8 +++ .../CodeActions/CreateEnumValueTests.cs | 67 ++++++++++++++++++- .../CodeActions/TestRefactoringContext.cs | 2 +- 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/TypeGuessing.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/TypeGuessing.cs index 6a08cc5d2..f43e3ece4 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/TypeGuessing.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/TypeGuessing.cs @@ -146,6 +146,14 @@ public static IEnumerable GetValidTypes(CSharpAstResolver resolver, AstNo return new [] { resolver.Compilation.FindType (KnownTypeCode.Boolean) }; } + var mref = expr as MemberReferenceExpression; + if (mref != null) { + // case: guess enum when trying to access not existent enum member + var rr = resolver.Resolve(mref.Target); + if (!rr.IsError && rr.Type.Kind == TypeKind.Enum) + return new [] { rr.Type }; + } + if (expr.Parent is ParenthesizedExpression || expr.Parent is NamedArgumentExpression) { return GetValidTypes(resolver, expr.Parent); } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/CreateEnumValueTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/CreateEnumValueTests.cs index b91f1f58b..3521540b7 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/CreateEnumValueTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/CreateEnumValueTests.cs @@ -76,8 +76,73 @@ public void Main () } } "); - } + } + + /// + /// Bug 16663 - Enum constants with Flags are not recognized + /// + [Test] + public void TestBug16663() + { + Test(@" +public enum MyEnum +{ +} + +class Test +{ + static void Main () + { + var e = MyEnum.$NotDefinedYetValue; + } +} +",@" +public enum MyEnum +{ + NotDefinedYetValue +} + +class Test +{ + static void Main () + { + var e = MyEnum.NotDefinedYetValue; + } +} +"); + } + + [Test] + public void TestBug16663_Case2() + { + Test(@" +public enum MyEnum +{ +} + +class Test +{ + static void Main () + { + var e = MyEnum.$NotDefinedYetValue | MyEnum.Foo; + } +} +",@" +public enum MyEnum +{ + NotDefinedYetValue +} + +class Test +{ + static void Main () + { + var e = MyEnum.NotDefinedYetValue | MyEnum.Foo; + } +} +"); } + } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs index 40090574d..05b3f95af 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/TestRefactoringContext.cs @@ -137,7 +137,7 @@ public override Task