Skip to content

Commit

Permalink
Make a way to suppress MA0003 (#3)
Browse files Browse the repository at this point in the history
I add a test to allow:

    new UITextField().EditingDidBegin += _proxy.OnEditingDidBegin;

    // This should warn, because it is NSObject
    class UITextFieldProxy : NSObject
    {
        // But then we suppressed the warning
        [UnconditionalSuppressMessage("Memory", "MA0003")]
        public void OnEditingDidBegin(object sender, EventArgs e) { }
    }

I added code to look up the attribute on the method from this statement:

    new UITextField().EditingDidBegin += _proxy.OnEditingDidBegin;

This also uncovered a bug in the analyzer:

    --if (attribute.AttributeClass.ContainingNamespace.Name != "System.Diagnostics.CodeAnalysis")
    ++if (attribute.AttributeClass.ContainingNamespace.ToString() != "System.Diagnostics.CodeAnalysis")

In this example `Name` was just `"CodeAnalysis"`. I have no idea why,
but using `.ToString()` instead was successful. All tests pass with this
change, so I'm going with it.
  • Loading branch information
jonathanpeppers committed Aug 10, 2023
1 parent 3699191 commit 464abe8
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 2 deletions.
36 changes: 35 additions & 1 deletion MemoryAnalyzers/MemoryAnalyzers.Test/MemoryAnalyzersUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ class MyView : UIView

public MyView()
{
new UITextField().EditingDidBegin += _proxy.{|#0:OnEditingDidBegin|};;
new UITextField().EditingDidBegin += _proxy.{|#0:OnEditingDidBegin|};
}

// This should warn, because it is NSObject
Expand All @@ -572,5 +572,39 @@ class UITextFieldProxy : NSObject
var expected = VerifyCS.Diagnostic("MA0003").WithLocation(0).WithArguments("OnEditingDidBegin");
await VerifyCS.VerifyAnalyzerAsync(test, expected);
}

[TestMethod]
public async Task SubscriptionForProxyClass_Suppressed()
{
var test = """
[Register(Name = "UITextField", IsWrapper = true)]
class UITextField
{
[UnconditionalSuppressMessage("Memory", "MA0001")]
public event EventHandler EditingDidBegin;
}

class MyView : UIView
{
[UnconditionalSuppressMessage("Memory", "MA0002")]
readonly UITextFieldProxy _proxy = new();

public MyView()
{
new UITextField().EditingDidBegin += _proxy.OnEditingDidBegin;
}

// This should warn, because it is NSObject
class UITextFieldProxy : NSObject
{
// But then we suppressed the warning
[UnconditionalSuppressMessage("Memory", "MA0003")]
public void OnEditingDidBegin(object sender, EventArgs e) { }
}
}
""";

await VerifyCS.VerifyAnalyzerAsync(test);
}
}
}
4 changes: 3 additions & 1 deletion MemoryAnalyzers/MemoryAnalyzers/MemoryAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ static void AnalyzeSubscription(SyntaxNodeAnalysisContext context)
var rightInfo = context.SemanticModel.GetSymbolInfo(assignment.Right);
if (rightInfo.Symbol is not IMethodSymbol methodSymbol || methodSymbol.IsStatic)
return; // static methods are fine
if (HasUnconditionalSuppressMessage(methodSymbol, MA0003))
return; // Method has [UnconditionalSuppressMessage]
if (!IsNSObjectSubclass(methodSymbol.ContainingType))
return; // If the method is on a non-NSObject subclass, it's fine

Expand All @@ -203,7 +205,7 @@ static bool HasUnconditionalSuppressMessage(ISymbol symbol, string expectedCode)
{
if (attribute.AttributeClass is null)
continue;
if (attribute.AttributeClass.ContainingNamespace.Name != "System.Diagnostics.CodeAnalysis")
if (attribute.AttributeClass.ContainingNamespace.ToString() != "System.Diagnostics.CodeAnalysis")
continue;
if (attribute.AttributeClass.Name != "UnconditionalSuppressMessageAttribute")
continue;
Expand Down

0 comments on commit 464abe8

Please sign in to comment.