Skip to content
This repository has been archived by the owner on Oct 16, 2020. It is now read-only.

Commit

Permalink
Handle await expressions in find references.
Browse files Browse the repository at this point in the history
  • Loading branch information
erik-kallen committed Sep 25, 2012
1 parent 66f51bf commit 8d5536e
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 0 deletions.
43 changes: 43 additions & 0 deletions ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs
Expand Up @@ -244,6 +244,8 @@ public IList<IFindReferenceSearchScope> GetSearchScopes(IEntity entity)
scope = FindMemberReferences(entity, m => new FindPropertyReferences((IProperty)m));
if (entity.Name == "Current")
additionalScope = FindEnumeratorCurrentReferences((IProperty)entity);
else if (entity.Name == "IsCompleted")
additionalScope = FindAwaiterIsCompletedReferences((IProperty)entity);
break;
case EntityType.Event:
scope = FindMemberReferences(entity, m => new FindEventReferences((IEvent)m));
Expand Down Expand Up @@ -661,6 +663,15 @@ SearchScope FindEnumeratorCurrentReferences(IProperty property)
return imported != null ? new FindEnumeratorCurrentReferencesNavigator(imported) : null;
});
}

SearchScope FindAwaiterIsCompletedReferences(IProperty property)
{
return new SearchScope(
delegate(ICompilation compilation) {
IProperty imported = compilation.Import(property);
return imported != null ? new FindAwaiterIsCompletedReferencesNavigator(imported) : null;
});
}

sealed class FindEnumeratorCurrentReferencesNavigator : FindReferenceNavigator
{
Expand All @@ -682,6 +693,27 @@ internal override bool IsMatch(ResolveResult rr)
return ferr != null && ferr.CurrentProperty != null && findReferences.IsMemberMatch(property, ferr.CurrentProperty, true);
}
}

sealed class FindAwaiterIsCompletedReferencesNavigator : FindReferenceNavigator
{
IProperty property;

public FindAwaiterIsCompletedReferencesNavigator(IProperty property)
{
this.property = property;
}

internal override bool CanMatch(AstNode node)
{
return node is UnaryOperatorExpression;
}

internal override bool IsMatch(ResolveResult rr)
{
AwaitResolveResult arr = rr as AwaitResolveResult;
return arr != null && arr.IsCompletedProperty != null && findReferences.IsMemberMatch(property, arr.IsCompletedProperty, true);
}
}
#endregion

#region Find Method References
Expand Down Expand Up @@ -724,6 +756,11 @@ SearchScope GetSearchScopeForMethod(IMethod method)
case "MoveNext":
specialNodeType = typeof(ForeachStatement);
break;
case "GetAwaiter":
case "GetResult":
case "OnCompleted":
specialNodeType = typeof(UnaryOperatorExpression);
break;
default:
specialNodeType = null;
break;
Expand Down Expand Up @@ -794,6 +831,12 @@ internal override bool IsMatch(ResolveResult rr)
return IsMatch(ferr.GetEnumeratorCall)
|| (ferr.MoveNextMethod != null && findReferences.IsMemberMatch(method, ferr.MoveNextMethod, true));
}
var arr = rr as AwaitResolveResult;
if (arr != null) {
return IsMatch(arr.GetAwaiterInvocation)
|| (arr.GetResultMethod != null && findReferences.IsMemberMatch(method, arr.GetResultMethod, true))
|| (arr.OnCompletedMethod != null && findReferences.IsMemberMatch(method, arr.OnCompletedMethod, true));
}
}
var mrr = rr as MemberResolveResult;
return mrr != null && findReferences.IsMemberMatch(method, mrr.Member, mrr.IsVirtualCall);
Expand Down
58 changes: 58 additions & 0 deletions ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs
Expand Up @@ -211,5 +211,63 @@ public void InheritanceTest3()
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 9 && r is InvocationExpression));
}
#endregion

#region Await
const string awaitTest = @"using System;
class MyAwaiter {
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation) {}
public int GetResult() { return 0; }
}
class MyAwaitable {
public MyAwaiter GetAwaiter() { return null; }
}
public class C {
public async void M() {
MyAwaitable x = null;
int i = await x;
}
}";

[Test]
public void GetAwaiterReferenceInAwaitExpressionIsFound() {
Init(awaitTest);
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "MyAwaitable");
var method = test.Methods.Single(m => m.Name == "GetAwaiter");
var actual = FindReferences(method).ToList();
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 8 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 13 && r is UnaryOperatorExpression));
}

[Test]
public void GetResultReferenceInAwaitExpressionIsFound() {
Init(awaitTest);
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "MyAwaiter");
var method = test.Methods.Single(m => m.Name == "GetResult");
var actual = FindReferences(method).ToList();
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 5 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 13 && r is UnaryOperatorExpression));
}

[Test]
public void OnCompletedReferenceInAwaitExpressionIsFound() {
Init(awaitTest);
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "MyAwaiter");
var method = test.Methods.Single(m => m.Name == "OnCompleted");
var actual = FindReferences(method).ToList();
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 4 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 13 && r is UnaryOperatorExpression));
}

[Test]
public void IsCompletedReferenceInAwaitExpressionIsFound() {
Init(awaitTest);
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "MyAwaiter");
var property = test.Properties.Single(m => m.Name == "IsCompleted");
var actual = FindReferences(property).ToList();
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 3 && r is PropertyDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 13 && r is UnaryOperatorExpression));
}
#endregion
}
}

0 comments on commit 8d5536e

Please sign in to comment.