Browse Source

Fixed completion bug.

newNRvisualizers
Mike Krüger 14 years ago
parent
commit
bb27ef5132
  1. 141
      ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs
  2. 40
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs
  3. 38
      ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs

141
ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs

@ -498,7 +498,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -498,7 +498,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return HandleEnumContext();
var wrapper = new CompletionDataWrapper(this);
AddTypesAndNamespaces(wrapper, GetState(), null, t => currentType != null ? !currentType.ReflectionName.Equals(t.ReflectionName) : true);
AddTypesAndNamespaces(wrapper, GetState(), null, t => currentType != null && !currentType.ReflectionName.Equals(t.ReflectionName) ? t : null);
return wrapper.Result;
}
return null;
@ -1052,11 +1052,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -1052,11 +1052,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
}
}
Predicate<IType> typePred = null;
Func<IType, IType> typePred = null;
if (IsAttributeContext(node)) {
var attribute = Compilation.FindType(KnownTypeCode.Attribute);
typePred = t => {
return t.GetAllBaseTypeDefinitions().Any(bt => bt.Equals(attribute));
return t.GetAllBaseTypeDefinitions().Any(bt => bt.Equals(attribute)) ? t : null;
};
}
AddTypesAndNamespaces(wrapper, state, node, typePred);
@ -1130,18 +1130,22 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -1130,18 +1130,22 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return false;
}
void AddTypesAndNamespaces(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Predicate<IType> typePred = null, Predicate<IMember> memberPred = null)
void AddTypesAndNamespaces(CompletionDataWrapper wrapper, CSharpResolver state, AstNode node, Func<IType, IType> typePred = null, Predicate<IMember> memberPred = null)
{
if (currentType != null) {
for (var ct = currentType; ct != null; ct = ct.DeclaringTypeDefinition) {
foreach (var nestedType in ct.NestedTypes) {
if (typePred == null || typePred(nestedType.Resolve(ctx))) {
string name = nestedType.Name;
if (IsAttributeContext(node) && name.EndsWith("Attribute") && name.Length > "Attribute".Length) {
name = name.Substring(0, name.Length - "Attribute".Length);
}
string name = nestedType.Name;
if (IsAttributeContext(node) && name.EndsWith("Attribute") && name.Length > "Attribute".Length)
name = name.Substring(0, name.Length - "Attribute".Length);
if (typePred == null) {
wrapper.AddType(nestedType, name);
continue;
}
wrapper.AddType(typePred(nestedType.Resolve(ctx)), name);
continue;
}
}
if (this.currentMember != null && !(node is AstType)) {
@ -1184,19 +1188,21 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -1184,19 +1188,21 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
}
foreach (var u in n.Usings) {
foreach (var type in u.Types) {
if (typePred == null || typePred(type)) {
IType addType = typePred != null ? typePred(type) : type;
if (addType != null) {
string name = type.Name;
if (IsAttributeContext(node) && name.EndsWith("Attribute") && name.Length > "Attribute".Length) {
name = name.Substring(0, name.Length - "Attribute".Length);
}
wrapper.AddType(type, name);
wrapper.AddType(addType, name);
}
}
}
foreach (var type in n.Namespace.Types) {
if (typePred == null || typePred(type)) {
wrapper.AddType(type, type.Name);
IType addType = typePred != null ? typePred(type) : type;
if (addType != null) {
wrapper.AddType(addType, addType.Name);
}
}
@ -1225,7 +1231,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -1225,7 +1231,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return null;
}
var wrapper = new CompletionDataWrapper(this);
AddTypesAndNamespaces(wrapper, GetState(), null, t => false);
AddTypesAndNamespaces(wrapper, GetState(), null, t => null);
return wrapper.Result;
case "case":
return CreateCaseCompletionData(location);
@ -1309,7 +1315,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -1309,7 +1315,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
}
var isAsWrapper = new CompletionDataWrapper(this);
var def = isAsType != null ? isAsType.GetDefinition() : null;
AddTypesAndNamespaces(isAsWrapper, GetState(), null, t => t.GetDefinition() == null || def == null || t.GetDefinition().IsDerivedFrom(def), m => false);
AddTypesAndNamespaces(isAsWrapper, GetState(), null, t => t.GetDefinition() == null || def == null || t.GetDefinition().IsDerivedFrom(def) ? t : null, m => false);
return isAsWrapper.Result;
// {
// CompletionDataList completionList = new ProjectDomCompletionDataList ();
@ -1515,25 +1521,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -1515,25 +1521,6 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
}
return CreateTypeCompletionData(hintType, hintTypeAst);
// IType callingType = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new TextLocation (document.Caret.Line, document.Caret.Column));
// ExpressionContext newExactContext = new NewCSharpExpressionFinder (dom).FindExactContextForNewCompletion (document, Document.CompilationUnit, Document.FileName, callingType);
// if (newExactContext is ExpressionContext.TypeExpressionContext)
// return CreateTypeCompletionData (location, callingType, newExactContext, ((ExpressionContext.TypeExpressionContext)newExactContext).Type, ((ExpressionContext.TypeExpressionContext)newExactContext).UnresolvedType);
// if (newExactContext == null) {
// int j = offset - 4;
//
// string yieldToken = GetPreviousToken (ref j, true);
// if (token == "return") {
// NRefactoryResolver resolver = CreateResolver ();
// resolver.SetupResolver (new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
// IReturnType returnType = resolver.CallingMember.ReturnType;
// if (yieldToken == "yield" && returnType.GenericArguments.Count > 0)
// returnType = returnType.GenericArguments [0];
// if (resolver.CallingMember != null)
// return CreateTypeCompletionData (location, callingType, newExactContext, null, returnType);
// }
// }
// return CreateCtrlSpaceCompletionData (completionContext, null);
case "yield":
var yieldDataList = new CompletionDataWrapper(this);
DefaultCompletionString = "return";
@ -1548,38 +1535,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -1548,38 +1535,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
AddContextCompletion(inList, rr != null ? rr.Item2 : GetState(), expr.Node, Unit);
return inList.Result;
// case "where":
// CompletionDataList whereDataList = new CompletionDataList ();
// NRefactoryResolver constraintResolver = CreateResolver ();
// constraintResolver.SetupResolver (new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
// if (constraintResolver.CallingMember is IMethod) {
// foreach (ITypeParameter tp in ((IMethod)constraintResolver.CallingMember).TypeParameters) {
// whereDataList.Add (tp.Name, "md-keyword");
// }
// } else {
// if (constraintResolver.CallingType != null) {
// foreach (ITypeParameter tp in constraintResolver.CallingType.TypeParameters) {
// whereDataList.Add (tp.Name, "md-keyword");
// }
// }
// }
//
// return whereDataList;
}
// if (IsInLinqContext (result)) {
// if (linqKeywords.Contains (word)) {
// if (word == "from") // after from no auto code completion.
// return null;
// result.Expression = "";
// return CreateCtrlSpaceCompletionData (completionContext, result);
// }
// CompletionDataList dataList = new ProjectDomCompletionDataList ();
// CompletionDataCollector col = new CompletionDataCollector (this, dom, dataList, Document.CompilationUnit, null, new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset));
// foreach (string kw in linqKeywords) {
// col.Add (kw, "md-keyword");
// }
// return dataList;
// }
}
return null;
}
@ -1606,42 +1562,55 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -1606,42 +1562,55 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
}
return "";
}
static CSharpAmbience amb = new CSharpAmbience ();
IEnumerable<ICompletionData> CreateTypeCompletionData(IType hintType, AstType hintTypeAst)
{
var wrapper = new CompletionDataWrapper (this);
var wrapper = new CompletionDataWrapper(this);
var state = GetState();
Predicate<IType> pred = null;
Func<IType, IType> pred = null;
if (hintType != null) {
if (hintType.Kind != TypeKind.Unknown) {
var lookup = new MemberLookup (ctx.CurrentTypeDefinition, Compilation.MainAssembly);
var lookup = new MemberLookup(ctx.CurrentTypeDefinition, Compilation.MainAssembly);
pred = t => {
// check if type is in inheritance tree.
if (hintType.GetDefinition() != null && !t.GetDefinition().IsDerivedFrom(hintType.GetDefinition())) {
return false;
return null;
}
if (t.Kind == TypeKind.Interface && hintType.Kind != TypeKind.Array) {
return false;
return null;
}
// check for valid constructors
if (t.GetConstructors().Count() == 0) {
return true;
if (t.GetConstructors().Count() > 0) {
bool isProtectedAllowed = currentType != null ? currentType.Resolve(ctx).GetDefinition().IsDerivedFrom(t.GetDefinition()) : false;
if (!t.GetConstructors().Any(m => lookup.IsAccessible(m, isProtectedAllowed)))
return null;
}
bool isProtectedAllowed = currentType != null ? currentType.Resolve(ctx).GetDefinition().IsDerivedFrom(t.GetDefinition()) : false;
return t.GetConstructors().Any(m => lookup.IsAccessible(m, isProtectedAllowed));
var typeInference = new TypeInference(Compilation);
typeInference.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults;
var inferedType = typeInference.FindTypeInBounds(new [] { t }, new [] { hintType });
wrapper.AddType(inferedType, amb.ConvertType(inferedType));
return null;
};
if (!(hintType.Kind == TypeKind.Interface && hintType.Kind != TypeKind.Array)) {
DefaultCompletionString = GetShortType(hintType, GetState());
wrapper.AddType(hintType, DefaultCompletionString);
}
if (hintType is ParameterizedType && hintType.TypeParameterCount == 1 && hintType.FullName == "System.Collections.Generic.IEnumerable") {
var arg = ((ParameterizedType)hintType).TypeArguments.FirstOrDefault();
var array = new ArrayTypeReference(arg.ToTypeReference(), 1).Resolve(ctx);
wrapper.AddType(array, amb.ConvertType(array));
}
} else {
DefaultCompletionString = hintTypeAst.ToString();
wrapper.AddType(hintType, DefaultCompletionString);
}
}
AddTypesAndNamespaces(wrapper, state, null, pred, m => false);
AddKeywords(wrapper, primitiveTypesKeywords.Where(k => k != "void"));
if (hintType == null || hintType == SpecialType.UnknownType)
AddKeywords(wrapper, primitiveTypesKeywords.Where(k => k != "void"));
CloseOnSquareBrackets = true;
AutoCompleteEmptyMatch = true;
return wrapper.Result;
@ -1985,9 +1954,9 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -1985,9 +1954,9 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
IEnumerable<ICompletionData> CreateParameterCompletion(MethodGroupResolveResult resolveResult, CSharpResolver state, AstNode invocation, CompilationUnit unit, int parameter, bool controlSpace)
{
var result = new CompletionDataWrapper (this);
var addedEnums = new HashSet<string> ();
var addedDelegates = new HashSet<string> ();
var result = new CompletionDataWrapper(this);
var addedEnums = new HashSet<string>();
var addedDelegates = new HashSet<string>();
foreach (var method in resolveResult.Methods) {
if (method.Parameters.Count <= parameter) {
@ -2001,13 +1970,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -2001,13 +1970,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
addedEnums.Add(resolvedType.ReflectionName);
AddEnumMembers(result, resolvedType, state);
} else if (resolvedType.Kind == TypeKind.Delegate) {
// if (addedDelegates.Contains (resolvedType.DecoratedFullName))
// continue;
// addedDelegates.Add (resolvedType.DecoratedFullName);
// string parameterDefinition = AddDelegateHandlers (completionList, resolvedType, false, addedDelegates.Count == 1);
// string varName = "Handle" + method.Parameters [parameter].ReturnType.Name + method.Parameters [parameter].Name;
// result.Add (new EventCreationCompletionData (document, varName, resolvedType, null, parameterDefinition, resolver.Unit.GetMemberAt (location), resolvedType) { AddSemicolon = false });
if (addedDelegates.Contains(resolvedType.ReflectionName))
continue;
string parameterDefinition = AddDelegateHandlers(result, resolvedType);
string varName = "Handle" + method.Parameters [parameter].Type.Name + method.Parameters [parameter].Name;
result.Result.Add(factory.CreateEventCreationCompletionData(varName, resolvedType, null, parameterDefinition, currentMember, currentType));
}
}
if (!controlSpace) {

40
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs

@ -95,13 +95,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -95,13 +95,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return -1;
}
static IEnumerable<IType> GetAllValidTypesFromInvokation(RefactoringContext context, InvocationExpression invoke, AstNode parameter)
static IEnumerable<IType> GetAllValidTypesFromInvokation(CSharpAstResolver resolver, InvocationExpression invoke, AstNode parameter)
{
int index = GetArgumentIndex(invoke.Arguments, parameter);
if (index < 0)
yield break;
var targetResult = context.Resolve(invoke.Target);
var targetResult = resolver.Resolve(invoke.Target);
if (targetResult is MethodGroupResolveResult) {
foreach (var method in ((MethodGroupResolveResult)targetResult).Methods) {
if (index < method.Parameters.Count) {
@ -111,13 +111,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -111,13 +111,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
}
static IEnumerable<IType> GetAllValidTypesFromObjectCreation(RefactoringContext context, ObjectCreateExpression invoke, AstNode parameter)
static IEnumerable<IType> GetAllValidTypesFromObjectCreation(CSharpAstResolver resolver, ObjectCreateExpression invoke, AstNode parameter)
{
int index = GetArgumentIndex(invoke.Arguments, parameter);
if (index < 0)
yield break;
var targetResult = context.Resolve(invoke.Type);
var targetResult = resolver.Resolve(invoke.Type);
if (targetResult is TypeResolveResult) {
var type = ((TypeResolveResult)targetResult).Type;
if (type.Kind == TypeKind.Delegate && index == 0) {
@ -131,13 +131,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -131,13 +131,13 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}
}
internal static IEnumerable<IType> GetValidTypes(RefactoringContext context, Expression expr)
internal static IEnumerable<IType> GetValidTypes(CSharpAstResolver resolver, Expression expr)
{
if (expr.Parent is DirectionExpression) {
var parent = expr.Parent.Parent;
if (parent is InvocationExpression) {
var invoke = (InvocationExpression)parent;
return GetAllValidTypesFromInvokation(context, invoke, expr.Parent);
return GetAllValidTypesFromInvokation(resolver, invoke, expr.Parent);
}
}
@ -145,7 +145,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -145,7 +145,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var parent = expr.Parent;
if (parent is ObjectCreateExpression) {
var invoke = (ObjectCreateExpression)parent;
return GetAllValidTypesFromObjectCreation(context, invoke, expr);
return GetAllValidTypesFromObjectCreation(resolver, invoke, expr);
}
}
@ -153,45 +153,45 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -153,45 +153,45 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var parent = expr.Parent;
if (parent is InvocationExpression) {
var invoke = (InvocationExpression)parent;
return GetAllValidTypesFromInvokation(context, invoke, expr);
return GetAllValidTypesFromInvokation(resolver, invoke, expr);
}
}
if (expr.Parent is VariableInitializer) {
var initializer = (VariableInitializer)expr.Parent;
return new [] { context.Resolve(initializer).Type };
return new [] { resolver.Resolve(initializer).Type };
}
if (expr.Parent is CastExpression) {
var cast = (CastExpression)expr.Parent;
return new [] { context.Resolve(cast.Type).Type };
return new [] { resolver.Resolve(cast.Type).Type };
}
if (expr.Parent is AsExpression) {
var cast = (AsExpression)expr.Parent;
return new [] { context.Resolve(cast.Type).Type };
return new [] { resolver.Resolve(cast.Type).Type };
}
if (expr.Parent is AssignmentExpression) {
var assign = (AssignmentExpression)expr.Parent;
var other = assign.Left == expr ? assign.Right : assign.Left;
return new [] { context.Resolve(other).Type };
return new [] { resolver.Resolve(other).Type };
}
if (expr.Parent is BinaryOperatorExpression) {
var assign = (BinaryOperatorExpression)expr.Parent;
var other = assign.Left == expr ? assign.Right : assign.Left;
return new [] { context.Resolve(other).Type };
return new [] { resolver.Resolve(other).Type };
}
if (expr.Parent is ReturnStatement) {
var state = context.GetResolverStateBefore(expr);
var state = resolver.GetResolverStateBefore(expr);
if (state != null)
return new [] { state.CurrentMember.ReturnType };
}
if (expr.Parent is YieldReturnStatement) {
var state = context.GetResolverStateBefore(expr);
var state = resolver.GetResolverStateBefore(expr);
if (state != null && (state.CurrentMember.ReturnType is ParameterizedType)) {
var pt = (ParameterizedType)state.CurrentMember.ReturnType;
if (pt.FullName == "System.Collections.Generic.IEnumerable") {
@ -204,14 +204,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -204,14 +204,14 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var uop = (UnaryOperatorExpression)expr.Parent;
switch (uop.Operator) {
case UnaryOperatorType.Not:
return new [] { context.Compilation.FindType(KnownTypeCode.Boolean) };
return new [] { resolver.Compilation.FindType(KnownTypeCode.Boolean) };
case UnaryOperatorType.Minus:
case UnaryOperatorType.Plus:
case UnaryOperatorType.Increment:
case UnaryOperatorType.Decrement:
case UnaryOperatorType.PostIncrement:
case UnaryOperatorType.PostDecrement:
return new [] { context.Compilation.FindType(KnownTypeCode.Int32) };
return new [] { resolver.Compilation.FindType(KnownTypeCode.Int32) };
}
}
return Enumerable.Empty<IType>();
@ -219,7 +219,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -219,7 +219,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
static readonly IType[] emptyTypes = new IType[0];
internal static AstType GuessAstType(RefactoringContext context, Expression expr)
{
var type = GetValidTypes(context, expr).ToArray();
var type = GetValidTypes(context.Resolver, expr).ToArray();
var typeInference = new TypeInference(context.Compilation);
typeInference.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults;
var inferedType = typeInference.FindTypeInBounds(type, emptyTypes);
@ -230,7 +230,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -230,7 +230,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
internal static IType GuessType(RefactoringContext context, Expression expr)
{
var type = GetValidTypes(context, expr).ToArray();
var type = GetValidTypes(context.Resolver, expr).ToArray();
var typeInference = new TypeInference(context.Compilation);
typeInference.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults;
var inferedType = typeInference.FindTypeInBounds(type, emptyTypes);

38
ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs

@ -924,7 +924,7 @@ class Test{ @@ -924,7 +924,7 @@ class Test{
}
}");
Assert.IsNotNull (provider, "provider not found.");
Assert.IsNotNull (provider.Find ("string"), "type string not found.");
Assert.IsNotNull (provider.Find ("string[]"), "type string not found.");
}
/// <summary>
@ -4706,9 +4706,9 @@ class MainClass @@ -4706,9 +4706,9 @@ class MainClass
}
[Test()]
public void TestInterfaceReturnType ()
public void TestInterfaceReturnType()
{
var provider = CreateProvider (
var provider = CreateProvider(
@"using System;
using System.Collections.Generic;
@ -4720,9 +4720,10 @@ class MainClass @@ -4720,9 +4720,10 @@ class MainClass
}
}
");
Assert.IsNotNull (provider.Find ("string"), "'string' not found.");
Assert.IsNotNull (provider.Find ("List"), "'List' not found.");
Assert.IsNull (provider.Find ("IEnumerable"), "'IEnumerable' found.");
Assert.IsNotNull(provider.Find("string[]"), "'string[]' not found.");
Assert.IsNotNull(provider.Find("List<string>"), "'List<string>' not found.");
Assert.IsNull(provider.Find("IEnumerable"), "'IEnumerable' found.");
Assert.IsNull(provider.Find("IEnumerable<string>"), "'IEnumerable<string>' found.");
Assert.IsNull (provider.Find ("Console"), "'Console' found.");
}
@ -4989,5 +4990,30 @@ public class Test @@ -4989,5 +4990,30 @@ public class Test
}
/// <summary>
/// Bug 1051 - Code completion can't handle interface return types properly
/// </summary>
[Test()]
public void TestBug1051()
{
CombinedProviderTest(
@"using System;
using System.Collections.Generic;
public class Test
{
IEnumerable<string> TestFoo()
{
$return new $
}
}
", provider => {
Assert.IsNull(provider.Find("IEnumerable<string>"), "'IEnumerable<string>' found.");
Assert.IsNotNull(provider.Find("List<string>"), "'List<string>' not found.");
Assert.IsNotNull(provider.Find("string[]"), "'string[]' not found.");
});
}
}
}

Loading…
Cancel
Save