diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index 355d4575a3..b5614a1224 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -225,6 +225,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion var methodGroup = invocationResult.Item1 as MethodGroupResolveResult; if (methodGroup != null) return CreateParameterCompletion (methodGroup, invocationResult.Item2, invoke.Item2, 0, controlSpace); + + if (controlSpace) + return DefaultControlSpaceItems (invoke); + return null; case '=': return controlSpace ? DefaultControlSpaceItems () : null; @@ -420,10 +424,10 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return null; if (identifierStart != null && identifierStart.Item2 is VariableInitializer && location <= ((VariableInitializer)identifierStart.Item2).NameToken.EndLocation) { - return controlSpace ? HandleAccessorContext () ?? DefaultControlSpaceItems () : null; + return controlSpace ? HandleAccessorContext () ?? DefaultControlSpaceItems (identifierStart) : null; } if (!(char.IsLetter (completionChar) || completionChar == '_') && (!controlSpace || identifierStart == null || !(identifierStart.Item2 is ArrayInitializerExpression))) { - return controlSpace ? HandleAccessorContext () ?? DefaultControlSpaceItems () : null; + return controlSpace ? HandleAccessorContext () ?? DefaultControlSpaceItems (identifierStart) : null; } char prevCh = offset > 2 ? document.GetCharAt (offset - 2) : ';'; char nextCh = offset < document.TextLength ? document.GetCharAt (offset) : ' '; @@ -640,7 +644,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return contextList.Result; } - IEnumerable DefaultControlSpaceItems () + IEnumerable DefaultControlSpaceItems (Tuple xp = null) { var wrapper = new CompletionDataWrapper (this); if (offset >= document.TextLength) @@ -649,7 +653,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion offset--; } location = document.GetLocation (offset); - var xp = GetExpressionAtCursor (); + if (xp == null) + xp = GetExpressionAtCursor (); AstNode node; Tuple rr; if (xp != null) { @@ -659,6 +664,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion node = Unit.GetNodeAt (location); rr = ResolveExpression (CSharpParsedFile, node, Unit); } + if (node is Identifier && node.Parent is ForeachStatement) { var foreachStmt = (ForeachStatement)node.Parent; foreach (var possibleName in GenerateNameProposals (foreachStmt.VariableType)) { @@ -684,9 +690,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion wrapper.AddVariable (variable); } } - - if (ctx.CurrentMember is IParameterizedMember) { - var param = (IParameterizedMember)ctx.CurrentMember; + if (currentMember is IUnresolvedParameterizedMember) { + var param = (IParameterizedMember)currentMember.CreateResolved (ctx); foreach (var p in param.Parameters) { wrapper.AddVariable (p); } @@ -1668,12 +1673,9 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } } else { - var baseTypes = new List (type.GetAllBaseTypes ()); - var conv = new Conversions (Compilation); - for (var n = state.CurrentUsingScope; n != null; n = n.Parent) { - AddExtensionMethods (result, conv, baseTypes, n.Namespace.FullName); - foreach (var u in n.Usings) { - AddExtensionMethods (result, conv, baseTypes, u.FullName); + foreach (var meths in state.GetAllExtensionMethods (type)) { + foreach (var m in meths) { + result.AddMember (m); } } } @@ -1702,21 +1704,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return result.Result; } - void AddExtensionMethods (CompletionDataWrapper result, Conversions conv, List baseTypes, string namespaceName) - { - if (ctx.CurrentUsingScope == null || ctx.CurrentUsingScope.AllExtensionMethods == null) - return; - foreach (var meths in ctx.CurrentUsingScope.AllExtensionMethods) { - foreach (var m in meths) { - var pt = m.Parameters.First ().Type; - string reflectionName = pt is ParameterizedType ? ((ParameterizedType)pt).GetDefinition ().ReflectionName : pt.ReflectionName; - if (baseTypes.Any (bt => (bt is ParameterizedType ? ((ParameterizedType)bt).GetDefinition ().ReflectionName : bt.ReflectionName) == reflectionName)) { - result.AddMember (m); - } - } - } - } - IEnumerable CreateCaseCompletionData (TextLocation location) { var unit = ParseStub ("a: break;"); @@ -1836,6 +1823,12 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (expr == null) expr = baseUnit.GetNodeAt (location.Line, location.Column - 1); + // try insertStatement + if (expr == null && baseUnit.GetNodeAt (location.Line, location.Column) != null) { + tmpUnit = baseUnit = ParseStub ("a();", false); + expr = baseUnit.GetNodeAt (location.Line, location.Column + 1); + } + if (expr == null) { baseUnit = ParseStub ("()"); expr = baseUnit.GetNodeAt (location.Line, location.Column - 1); diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs index d7addc49e0..4e8fe5be47 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs @@ -71,6 +71,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion IUnresolvedTypeDefinition FindInnerType (IUnresolvedTypeDefinition parent, TextLocation location) { + if (parent == null) + return null; var currentType = parent; foreach (var type in parent.NestedTypes) { if (type.Region.Begin < location && location < type.Region.End) @@ -79,6 +81,64 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return currentType; } + + bool IsInsideType (IUnresolvedTypeDefinition currentType, TextLocation location) + { + int startOffset = document.GetOffset (currentType.Region.Begin); + int endOffset = document.GetOffset (location); + bool foundEndBracket = false; + + var bracketStack = new Stack (); + + bool isInString = false, isInChar = false; + bool isInLineComment = false, isInBlockComment = false; + + for (int i = startOffset; i < endOffset; i++) { + char ch = document.GetCharAt (i); + switch (ch) { + case '(': + case '[': + case '{': + if (!isInString && !isInChar && !isInLineComment && !isInBlockComment) + bracketStack.Push (ch); + break; + case ')': + case ']': + case '}': + if (!isInString && !isInChar && !isInLineComment && !isInBlockComment) + if (bracketStack.Count > 0) + bracketStack.Pop (); + break; + case '\r': + case '\n': + isInLineComment = false; + break; + case '/': + if (isInBlockComment) { + if (i > 0 && document.GetCharAt (i - 1) == '*') + isInBlockComment = false; + } else if (!isInString && !isInChar && i + 1 < document.TextLength) { + char nextChar = document.GetCharAt (i + 1); + if (nextChar == '/') + isInLineComment = true; + if (!isInLineComment && nextChar == '*') + isInBlockComment = true; + } + break; + case '"': + if (!(isInChar || isInLineComment || isInBlockComment)) + isInString = !isInString; + break; + case '\'': + if (!(isInString || isInLineComment || isInBlockComment)) + isInChar = !isInChar; + break; + default : + break; + } + } + return bracketStack.Any (t => t == '{'); + } protected void SetOffset (int offset) { Reset (); @@ -94,6 +154,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion } currentType = FindInnerType (currentType, location); + // location is beyond last reported end region, now we need to check, if the end region changed + if (currentType != null && currentType.Region.End < location) { + if (!IsInsideType (currentType, location)) + currentType = null; + } this.currentMember = null; if (this.currentType != null) { foreach (var member in currentType.Members) { @@ -405,7 +470,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return Tuple.Create (CSharpParsedFile, (AstNode)attr, Unit); } } - if (currentMember == null && currentType == null) { return null; } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/EnumContextTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/EnumContextTests.cs index ebf8a31351..e496e16af0 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/EnumContextTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/EnumContextTests.cs @@ -46,6 +46,21 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion }); } + [Test()] + public void Test2142Case2 () + { + CodeCompletionBugTests.CombinedProviderTest ( +@"enum Name { + Foo, + Bar, + $p$ +} +", provider => { + Assert.AreEqual (0, provider.Count); + }); + } + + [Test()] public void TestEnumAssignment () {