Skip to content

Commit

Permalink
Merge pull request #907 from amcasey/EventAssignment
Browse files Browse the repository at this point in the history
Extend member access analysis to events
  • Loading branch information
AArnott committed Sep 10, 2021
2 parents a640462 + 2a3b2a4 commit 4e61fc7
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 4 deletions.
Expand Up @@ -6,7 +6,7 @@
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.8.2" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.0.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
Expand Down
Expand Up @@ -148,6 +148,9 @@ public override void Initialize(AnalysisContext context)
compilationStartContext.RegisterOperationAction(Utils.DebuggableWrapper(c => this.AddToCallerCalleeMap(c, callerToCalleeMap)), OperationKind.Invocation);
compilationStartContext.RegisterOperationAction(Utils.DebuggableWrapper(c => this.AddToCallerCalleeMap(c, callerToCalleeMap)), OperationKind.PropertyReference);
// Strictly speaking, this will miss access to the underlying field, but there's no method to put in the map in that case
compilationStartContext.RegisterOperationAction(Utils.DebuggableWrapper(c => this.AddToCallerCalleeMap(c, callerToCalleeMap)), OperationKind.EventAssignment);
compilationStartContext.RegisterCompilationEndAction(compilationEndContext =>
{
Dictionary<IMethodSymbol, List<CallInfo>>? calleeToCallerMap = CreateCalleeToCallerMap(callerToCalleeMap);
Expand Down Expand Up @@ -253,6 +256,17 @@ private void AddToCallerCalleeMap(OperationAnalysisContext context, Dictionary<I
break;
case IPropertyReferenceOperation propertyReference:
targetMethod = GetPropertyAccessor(propertyReference.Property);
break;
case IEventAssignmentOperation eventAssignmentOperation:
IOperation eventReferenceOp = eventAssignmentOperation.EventReference;
if (eventReferenceOp is IEventReferenceOperation eventReference)
{
targetMethod = eventAssignmentOperation.Adds
? eventReference.Event.AddMethod
: eventReference.Event.RemoveMethod;
locationToBlame = eventReference.Syntax;
}

break;
}

Expand Down Expand Up @@ -374,6 +388,14 @@ internal void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context)
{
this.AnalyzeMemberWithinContext(property.ContainingType, property, context, memberAccessSyntax.Name.GetLocation());
}
else
{
var @event = context.SemanticModel.GetSymbolInfo(context.Node).Symbol as IEventSymbol;
if (@event is object)
{
this.AnalyzeMemberWithinContext(@event.ContainingType, @event, context, memberAccessSyntax.Name.GetLocation());
}
}
}

internal void AnalyzeCast(SyntaxNodeAnalysisContext context)
Expand Down
Expand Up @@ -32,7 +32,7 @@
</ItemDefinitionGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="2.8.2" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="2.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.0.0" PrivateAssets="all" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
Expand Down
Expand Up @@ -6,7 +6,7 @@
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="2.8.2" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="2.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.0.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
Expand Down
Expand Up @@ -22,7 +22,7 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="2.8.2" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="2.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.0.0" PrivateAssets="all" />
<PackageReference Include="Nullable" Version="1.3.0">
<PrivateAssets>all</PrivateAssets>
Expand Down
Expand Up @@ -1630,6 +1630,39 @@ void Foo()
await Verify.VerifyAnalyzerAsync(test, expected);
}

[Fact]
public async Task Events()
{
var test = @"
namespace TestNS
{
interface SomeInterface
{
event System.Action UIEventName;
}
}
class A
{
void Handler()
{
}
void Test(TestNS.SomeInterface i)
{
i.UIEventName += this.Handler;
i.UIEventName -= this.Handler;
}
}
";
DiagnosticResult[] expected =
{
Verify.Diagnostic(DescriptorSync).WithSpan(18, 11, 18, 22).WithArguments("SomeInterface", "Test.VerifyOnUIThread"),
Verify.Diagnostic(DescriptorSync).WithSpan(19, 11, 19, 22).WithArguments("SomeInterface", "Test.VerifyOnUIThread"),
};
await Verify.VerifyAnalyzerAsync(test, expected);
}

/// <summary>
/// Field initializers should never have thread affinity since the thread cannot be enforced before the code is executed,
/// since initializers run before the user-defined constructor.
Expand Down

0 comments on commit 4e61fc7

Please sign in to comment.