diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD010MainThreadUsageAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD010MainThreadUsageAnalyzer.cs index 4d69aba2c..6c2a6bdea 100644 --- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD010MainThreadUsageAnalyzer.cs +++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD010MainThreadUsageAnalyzer.cs @@ -443,7 +443,7 @@ private bool AnalyzeMemberWithinContext(ITypeSymbol type, ISymbol? symbol, Synta throw new ArgumentNullException(nameof(type)); } - bool requiresUIThread = (type.TypeKind == TypeKind.Interface || type.TypeKind == TypeKind.Class) + bool requiresUIThread = (type.TypeKind == TypeKind.Interface || type.TypeKind == TypeKind.Class || type.TypeKind == TypeKind.Struct) && this.MembersRequiringMainThread.Contains(type, symbol); if (requiresUIThread) diff --git a/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/AdditionalFiles/vs-threading.MembersRequiringMainThread.mocks.txt b/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/AdditionalFiles/vs-threading.MembersRequiringMainThread.mocks.txt index 46cfd3576..51a33f56b 100644 --- a/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/AdditionalFiles/vs-threading.MembersRequiringMainThread.mocks.txt +++ b/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/AdditionalFiles/vs-threading.MembersRequiringMainThread.mocks.txt @@ -1,4 +1,5 @@ [TestNS.*] +[TestNS.SomeStruct] ![TestNS.FreeThreadedType] ![TestNS2.FreeThreadedType] [TestNS2.*] diff --git a/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/VSTHRD010MainThreadUsageAnalyzerTests.cs b/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/VSTHRD010MainThreadUsageAnalyzerTests.cs index 80636a126..05cec43fc 100644 --- a/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/VSTHRD010MainThreadUsageAnalyzerTests.cs +++ b/test/Microsoft.VisualStudio.Threading.Analyzers.Tests/VSTHRD010MainThreadUsageAnalyzerTests.cs @@ -970,7 +970,7 @@ public async Task CastToManagedType_ProducesNoDiagnostic() namespace TestNS { class SomeClass { } - class SomeInterface { } + interface SomeInterface { } } class Test { @@ -1053,7 +1053,7 @@ public async Task CastToManagedTypeViaAs_ProducesNoDiagnostic() namespace TestNS { class SomeClass { } - class SomeInterface { } + interface SomeInterface { } } class Test { @@ -1096,7 +1096,7 @@ public async Task CastToManagedTypeViaIs_ProducesNoDiagnostic() namespace TestNS { class SomeClass { } - class SomeInterface { } + interface SomeInterface { } } class Test { @@ -1864,6 +1864,46 @@ async void SecondAsync() await Verify.VerifyAnalyzerAsync(test, expect); } + [Fact] + public async Task StructMembers() + { + var test = @" +namespace TestNS +{ + struct SomeStruct + { + public static void DoSomething() + { + } + + public string Name { get; set; } + } +} + +namespace Foo +{ + class MyProgram + { + static void Main() + { + TestNS.SomeStruct.DoSomething(); + + var st = new TestNS.SomeStruct(); + st.Name = ""TheValue""; + string val = st.Name; + } + } +} +"; + var expect = new DiagnosticResult[] + { + Verify.Diagnostic(DescriptorSync).WithSpan(20, 31, 20, 42).WithArguments("SomeStruct", "Test.VerifyOnUIThread"), + Verify.Diagnostic(DescriptorSync).WithSpan(23, 16, 23, 20).WithArguments("SomeStruct", "Test.VerifyOnUIThread"), + Verify.Diagnostic(DescriptorSync).WithSpan(24, 29, 24, 33).WithArguments("SomeStruct", "Test.VerifyOnUIThread"), + }; + await Verify.VerifyAnalyzerAsync(test, expect); + } + private static class CodeFixIndex { public const int SwitchToMainThreadAsync = 0;