From a1e4b07da6a84c87a4d3b726f50a81bf204c078b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Tue, 22 May 2012 09:31:27 +0200 Subject: [PATCH 1/6] [Completion] Fixed enum completion in binary operator expressions. --- .../Completion/CSharpCompletionEngine.cs | 9 ++++++++ .../CodeCompletionAccessibleTests.cs | 23 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index aeee45d439..68f7b3d9b3 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -1118,6 +1118,15 @@ namespace ICSharpCode.NRefactory.CSharp.Completion rr = ResolveExpression(node, unit); } + if (node is Expression) { + var astResolver = new CSharpAstResolver(GetState(), xp.Unit, CSharpParsedFile); + foreach (var type in CreateFieldAction.GetValidTypes(astResolver, (Expression)node)) { + if (type.Kind == TypeKind.Enum) { + AddEnumMembers(wrapper, type, rr.Item2); + } + } + } + if (node is Identifier && node.Parent is ForeachStatement) { var foreachStmt = (ForeachStatement)node.Parent; foreach (var possibleName in GenerateNameProposals (foreachStmt.VariableType)) { diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionAccessibleTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionAccessibleTests.cs index b5f9d8fa16..eb3b25ebec 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionAccessibleTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionAccessibleTests.cs @@ -1177,7 +1177,28 @@ class TestClass Assert.IsNotNull (provider.Find ("InnerEnumTest.TestEnum.B"), "enum 'InnerEnumTest.TestEnum.B' not found."); Assert.IsNotNull (provider.Find ("InnerEnumTest.TestEnum.C"), "enum 'InnerEnumTest.TestEnum.C' not found."); } - + + [Test()] + public void TestEnumInBinaryOperatorExpression () + { + CompletionDataList provider = CodeCompletionBugTests.CreateCtrlSpaceProvider ( +@" +[Flags] +public enum TestEnum { A, B, C} + +class TestClass +{ + public void Foo () + { + $TestEnum test = TestEnum.A | $ + } +}"); + Assert.IsNotNull (provider, "provider not found."); + Assert.IsNotNull (provider.Find ("TestEnum"), "enum 'TestEnum' not found."); + Assert.IsNotNull (provider.Find ("TestEnum.A"), "enum 'TestEnum.A' not found."); + Assert.IsNotNull (provider.Find ("TestEnum.B"), "enum 'TestEnum.B' not found."); + Assert.IsNotNull (provider.Find ("TestEnum.C"), "enum 'TestEnum.C' not found."); + } [Test()] public void TestPrimimitiveTypeCompletionString () From 9e7c9be52b672075b536b1e33f73ba1396fd6c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Tue, 22 May 2012 09:47:08 +0200 Subject: [PATCH 2/6] [Completion] Fixed enum completion bug. --- .../Completion/CSharpCompletionEngine.cs | 18 ++++++++---------- .../CodeCompletionAccessibleTests.cs | 8 ++++---- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index 68f7b3d9b3..402d313904 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -640,7 +640,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion // May happen in variable names return controlSpace ? DefaultControlSpaceItems(identifierStart) : null; } - if (identifierStart.Node is VariableInitializer && location <= ((VariableInitializer)identifierStart.Node).NameToken.EndLocation) { return controlSpace ? HandleAccessorContext() ?? DefaultControlSpaceItems(identifierStart) : null; } @@ -1118,15 +1117,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion rr = ResolveExpression(node, unit); } - if (node is Expression) { - var astResolver = new CSharpAstResolver(GetState(), xp.Unit, CSharpParsedFile); - foreach (var type in CreateFieldAction.GetValidTypes(astResolver, (Expression)node)) { - if (type.Kind == TypeKind.Enum) { - AddEnumMembers(wrapper, type, rr.Item2); - } - } - } - if (node is Identifier && node.Parent is ForeachStatement) { var foreachStmt = (ForeachStatement)node.Parent; foreach (var possibleName in GenerateNameProposals (foreachStmt.VariableType)) { @@ -1290,6 +1280,14 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } } + if (node is Expression) { + var astResolver = new CSharpAstResolver(state, unit, CSharpParsedFile); + foreach (var type in CreateFieldAction.GetValidTypes(astResolver, (Expression)node)) { + if (type.Kind == TypeKind.Enum) { + AddEnumMembers(wrapper, type, state); + } + } + } } static bool IsInSwitchContext(AstNode node) diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionAccessibleTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionAccessibleTests.cs index eb3b25ebec..409112a298 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionAccessibleTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionAccessibleTests.cs @@ -1181,7 +1181,7 @@ class TestClass [Test()] public void TestEnumInBinaryOperatorExpression () { - CompletionDataList provider = CodeCompletionBugTests.CreateCtrlSpaceProvider ( + CodeCompletionBugTests.CombinedProviderTest ( @" [Flags] public enum TestEnum { A, B, C} @@ -1190,14 +1190,14 @@ class TestClass { public void Foo () { - $TestEnum test = TestEnum.A | $ + $TestEnum test = TestEnum.A | T$ } -}"); - Assert.IsNotNull (provider, "provider not found."); +}", provider => { Assert.IsNotNull (provider.Find ("TestEnum"), "enum 'TestEnum' not found."); Assert.IsNotNull (provider.Find ("TestEnum.A"), "enum 'TestEnum.A' not found."); Assert.IsNotNull (provider.Find ("TestEnum.B"), "enum 'TestEnum.B' not found."); Assert.IsNotNull (provider.Find ("TestEnum.C"), "enum 'TestEnum.C' not found."); + }); } [Test()] From 7b21777e0db9643ab39a6b4307d7cd4778a4c9fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Tue, 22 May 2012 10:02:07 +0200 Subject: [PATCH 3/6] [Completion] Fixed 'this' keyword for extension method declarations. --- .../Completion/CSharpCompletionEngine.cs | 7 ++++- .../CodeCompletion/CodeCompletionBugTests.cs | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index 402d313904..4db749dd5a 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -1223,7 +1223,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return t.GetAllBaseTypeDefinitions().Any(bt => bt.Equals(attribute)) ? t : null; }; } - AddTypesAndNamespaces(wrapper, state, node, typePred); wrapper.Result.Add(factory.CreateLiteralCompletionData("global")); @@ -1288,6 +1287,12 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } } } + + // Add 'this' keyword for first parameter (extension method case) + if (node != null && node.Parent is ParameterDeclaration && + node.Parent.PrevSibling != null && node.Parent.PrevSibling.Role == Roles.LPar) { + wrapper.AddCustom ("this"); + } } static bool IsInSwitchContext(AstNode node) diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs index f540932640..206aeae030 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs @@ -5246,5 +5246,34 @@ namespace EnumerationProblem }); } + /// + /// Bug 5191 - Creating extension method problem when typing "this" + /// + [Test()] + public void TestBug5191() + { + CombinedProviderTest( +@"using System; + +static class Ext +{ + $public static void Foo(t$ +} +", provider => { + Assert.IsNotNull(provider.Find("this"), "'this' not found."); + }); + + CombinedProviderTest( +@"using System; + +static class Ext +{ + $public static void Foo(int foo, t$ +} +", provider => { + Assert.IsNull(provider.Find("this"), "'this' found."); + }); + } + } } From 1c0b3b54d7107b147f941ead0d1ca538440677d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Tue, 22 May 2012 12:02:23 +0200 Subject: [PATCH 4/6] [Completion] Filter inaccessible classes in completion lookup. --- .../Completion/CSharpCompletionEngine.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index 4db749dd5a..d305c54f3b 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -1312,6 +1312,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion void AddTypesAndNamespaces(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Func typePred = null, Predicate memberPred = null, Action callback = null) { + var lookup = new MemberLookup( + ctx.CurrentTypeDefinition, + Compilation.MainAssembly + ); if (currentType != null) { for (var ct = currentType; ct != null; ct = ct.DeclaringTypeDefinition) { foreach (var nestedType in ct.NestedTypes) { @@ -1338,10 +1342,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (this.currentMember != null && !(node is AstType)) { var def = ctx.CurrentTypeDefinition ?? Compilation.MainAssembly.GetTypeDefinition(currentType); if (def != null) { - var lookup = new MemberLookup( - ctx.CurrentTypeDefinition, - Compilation.MainAssembly - ); bool isProtectedAllowed = true; foreach (var member in def.GetMembers ()) { if (member is IMethod && ((IMethod)member).FullName == "System.Object.Finalize") { @@ -1384,6 +1384,9 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } foreach (var u in n.Usings) { foreach (var type in u.Types) { + if (!lookup.IsAccessible(type, false)) + continue; + IType addType = typePred != null ? typePred(type) : type; if (addType != null) { string name = type.Name; @@ -1399,6 +1402,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } foreach (var type in n.Namespace.Types) { + if (!lookup.IsAccessible(type, false)) + continue; IType addType = typePred != null ? typePred(type) : type; if (addType != null) { var a2 = wrapper.AddType(addType, addType.Name); From 0cc7a4e0b7253754e172a85bb4fa0eca7bbaadea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Tue, 22 May 2012 13:19:32 +0200 Subject: [PATCH 5/6] [Completion] Fixed delegate context bug. --- .../Completion/CSharpCompletionEngine.cs | 79 ++++++++++++------- .../CodeCompletion/DelegateContextTests.cs | 25 ++++++ 2 files changed, 74 insertions(+), 30 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index d305c54f3b..e1632e8253 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -272,10 +272,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion // case 1) // check if the object is a list, if not only provide object initalizers - var list = typeof (System.Collections.IList).ToTypeReference ().Resolve (Compilation); + var list = typeof(System.Collections.IList).ToTypeReference().Resolve(Compilation); if (initializerResult.Item1.Type.Kind != TypeKind.Array && list != null) { - var def = initializerResult.Item1.Type.GetDefinition (); - if (def != null && !def.IsDerivedFrom (list.GetDefinition ())) + var def = initializerResult.Item1.Type.GetDefinition(); + if (def != null && !def.IsDerivedFrom(list.GetDefinition())) return contextList.Result; } @@ -548,7 +548,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } } if (token == "+=") { - string parameterDefinition = AddDelegateHandlers(wrapper, delegateType); + string parameterDefinition = AddDelegateHandlers( + wrapper, + delegateType + ); string varName = GetPreviousMemberReferenceExpression(tokenIndex); wrapper.Result.Add( factory.CreateEventCreationCompletionData( @@ -715,19 +718,19 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return null; } - var astResolver = new CSharpAstResolver( - GetState(), - identifierStart.Unit, - CSharpParsedFile - ); - - foreach (var type in CreateFieldAction.GetValidTypes(astResolver, (Expression)n)) { - if (type.Kind == TypeKind.Delegate) { - AddDelegateHandlers(contextList, type, false, false); - AutoSelect = false; - AutoCompleteEmptyMatch = false; - } - } +// var astResolver = new CSharpAstResolver( +// GetState(), +// identifierStart.Unit, +// CSharpParsedFile +// ); +// +// foreach (var type in CreateFieldAction.GetValidTypes(astResolver, (Expression)n)) { +// if (type.Kind == TypeKind.Delegate) { +// AddDelegateHandlers(contextList, type, false, false); +// AutoSelect = false; +// AutoCompleteEmptyMatch = false; +// } +// } } // Handle object/enumerable initialzer expressions: "new O () { P$" @@ -999,7 +1002,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion var wrapper = new CompletionDataWrapper(this); AddTypesAndNamespaces( wrapper, - GetState (), + GetState(), identifierStart.Node, typePred, m => false @@ -1059,7 +1062,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion while (null != (token = GetPreviousToken (ref offset, true)) && !IsInsideCommentStringOrDirective ()) { if (token == "from") { - return !IsInsideCommentStringOrDirective (offset); + return !IsInsideCommentStringOrDirective(offset); } if (token == ";" || token == "{") { return false; @@ -1112,11 +1115,14 @@ namespace ICSharpCode.NRefactory.CSharp.Completion rr = ResolveExpression(node, xp.Unit); unit = xp.Unit; } else { - unit = ParseStub("a", false); - node = unit.GetNodeAt(location); + unit = ParseStub("foo", false); + node = unit.GetNodeAt( + location.Line, + location.Column + 2, + n => n is Expression || n is AstType + ); rr = ResolveExpression(node, unit); } - if (node is Identifier && node.Parent is ForeachStatement) { var foreachStmt = (ForeachStatement)node.Parent; foreach (var possibleName in GenerateNameProposals (foreachStmt.VariableType)) { @@ -1185,7 +1191,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion csResolver = GetState(); } } - AddContextCompletion(wrapper, csResolver, node, unit); return wrapper.Result; @@ -1284,14 +1289,18 @@ namespace ICSharpCode.NRefactory.CSharp.Completion foreach (var type in CreateFieldAction.GetValidTypes(astResolver, (Expression)node)) { if (type.Kind == TypeKind.Enum) { AddEnumMembers(wrapper, type, state); + } else if (type.Kind == TypeKind.Delegate) { + AddDelegateHandlers(wrapper, type, true, true); + AutoSelect = false; + AutoCompleteEmptyMatch = false; } } } // Add 'this' keyword for first parameter (extension method case) if (node != null && node.Parent is ParameterDeclaration && - node.Parent.PrevSibling != null && node.Parent.PrevSibling.Role == Roles.LPar) { - wrapper.AddCustom ("this"); + node.Parent.PrevSibling != null && node.Parent.PrevSibling.Role == Roles.LPar) { + wrapper.AddCustom("this"); } } @@ -1761,7 +1770,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (!t.GetConstructors().Any(m => lookup.IsAccessible( m, isProtectedAllowed - ))) { + ) + )) { return null; } } @@ -1881,7 +1891,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion declarationBegin, method.DeclaringTypeDefinition, method - )); + ) + ); } return wrapper.Result; @@ -1929,7 +1940,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion bool foundMember = curType.GetMembers().Any(cm => SignatureComparer.Ordinal.Equals( cm, m - ) && cm.DeclaringTypeDefinition == curType.GetDefinition()); + ) && cm.DeclaringTypeDefinition == curType.GetDefinition() + ); if (foundMember) { continue; } @@ -1944,6 +1956,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion static void AddKeywords(CompletionDataWrapper wrapper, IEnumerable keywords) { foreach (string keyword in keywords) { + if (wrapper.Result.Any(data => data.DisplayText == keyword)) + continue; wrapper.AddCustom(keyword); } } @@ -2002,6 +2016,9 @@ namespace ICSharpCode.NRefactory.CSharp.Completion string delegateEndString = EolMarker + thisLineIndent + "}" + (addSemicolon ? ";" : ""); //bool containsDelegateData = completionList.Result.Any(d => d.DisplayText.StartsWith("delegate(")); if (addDefault) { + var oldDelegate = completionList.Result.FirstOrDefault(cd => cd.DisplayText == "delegate"); + if (oldDelegate != null) + completionList.Result.Remove(oldDelegate); completionList.AddCustom( "delegate", "Creates anonymous delegate.", @@ -2265,7 +2282,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion completionList.Result.Add(factory.CreateEntityCompletionData( field, typeString + "." + field.Name - )); + ) + ); } } DefaultCompletionString = typeString; @@ -2860,7 +2878,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion "seealso", "summary", "value" - }); + } + ); IEnumerable GetXmlDocumentationCompletionData() { diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/DelegateContextTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/DelegateContextTests.cs index 7a75d65b30..7a66ddea77 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/DelegateContextTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/DelegateContextTests.cs @@ -72,6 +72,31 @@ public class Test Assert.IsNotNull(provider.Find("delegate")); }); } + + /// + /// Bug 5207 - [regression] delegate completion like event completion + /// + [Test()] + public void TestBug5207() + { + // note 'string bar = new Test ().ToString ()' would be valid. + CodeCompletionBugTests.CombinedProviderTest( +@"using System; + +public class Test +{ + Action foo; + + void TestFoo() + { + $foo = d$ + } +} +", provider => { + Assert.IsFalse(provider.AutoSelect); + Assert.IsNotNull(provider.Find("(arg1, arg2)")); + }); + } } } From 2e4a49707ff6311f9ff7e4fcb9c1103c1c91b7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Tue, 22 May 2012 13:31:41 +0200 Subject: [PATCH 6/6] [Completion] Fixed GetLineIndent method. --- .../Completion/CSharpCompletionEngine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index e1632e8253..464c2e4e10 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -1712,7 +1712,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion string GetLineIndent(int lineNr) { var line = document.GetLineByNumber(lineNr); - for (int j = offset; j < line.EndOffset; j++) { + for (int j = line.Offset; j < line.EndOffset; j++) { char ch = document.GetCharAt(j); if (!char.IsWhiteSpace(ch)) { return document.GetText(line.Offset, j - line.Offset - 1);