Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider flag platform specific constructor called implicitly in derived types #4404

Closed
buyaa-n opened this issue Nov 3, 2020 · 7 comments
Closed
Assignees
Labels
Area-Microsoft.CodeAnalysis.NetAnalyzers Enhancement Priority:3 Nice to have (suitable for disabled by default rules and ported FxCop rules)
Milestone

Comments

@buyaa-n
Copy link
Member

buyaa-n commented Nov 3, 2020

Platform attributes not derived by design, this means when A has platform-specific attribute and B derived from A is not counted as platform-specific. But if B's constructor is implicitly calling the base default constructor then it might need to flag that, especially when the base constructor does any platform-specific operation. As shown below example if derived type calls any platform-specific API from the base it would warn, including explicit call to the base constructor, but implicit call will not be caught

    [SupportedOSPlatform("windows")]
    class A
    {
        public A() 
       {
            // some platform specific operation
        } 
        public void M1() { }
    }

    class B : A
    {
        public void Test()
        {
            A a = new A(); // warns as expected
            B b = new B(); // not warn, but could warn as it will call base constructor implicitly

            a.M1(); // warns as expected
            b.M1(); // warns as expected
        }
    }

I could propose 2 way of covering this:

  1. If the child constructor has no explicit call to parent platform-specific type check if the parent default constructor is implemented and warn if it is doing any platform-specific operation. This solution will do more computation but might eliminate false positives.
  2. If the child constructor has no explicit call to parent platform-specific type warn unconditionally. This solution will be easier but might cause false positives

cc @jeffhandley @terrajobst

When we cover this scenario we also could consider to flag generic type constructors @mavasani suggested such as below:

using System.Runtime.Versioning;

class GenericClass<T>
{
}

[SupportedOSPlatform("windows")]
class WindowsOnlyType { }

class DerivedWindowsOnlyType : GenericClass<WindowsOnlyType> { }
class Test
{
    void M<T>()
    {
        var t = new DerivedWindowsOnlyType();  // Should be flagged
    }
}

Originally posted by @mavasani in #4390 (comment)

@terrajobst
Copy link
Member

We should also consider warning on the inverse, i.e. when someone adds platform-specific annotations on derived types because one could argue that polymorphism breaks the analysis.

For example, if I derive from a non-platform specific type (or interface) and add platform-specific functionality callers might not get any warnings when they consume the type through the base. Same applies to overrides.

Maybe we should warn when a user adds platform constraints to overrides or interface implementations and instead tell them to mark the constructor of that type as platform specific. This ensures that someone, somewhere will get a warning. And for polymorphic types the constructor/factory method/static singleton property seems to be the appropriate place for that.

@buyaa-n
Copy link
Member Author

buyaa-n commented Nov 3, 2020

We should also consider warning on the inverse, i.e. when someone adds platform-specific annotations on derived types because one could argue that polymorphism breaks the analysis.

For example, if I derive from a non-platform specific type (or interface) and add platform-specific functionality callers might not get any warnings when they consume the type through the base. Same applies to overrides.

Good point

Maybe we should warn when a user adds platform constraints to overrides or interface implementations and instead tell them to mark the constructor of that type as platform specific.

I think if we suggest to mark constructor instead of the overridden method it would be the same as marking the entire type platform-specific, which would bad if the type has other APIs not platform-specific. Isn't it better to suggest to mark the base type method instead of suggesting to mark constructor?

    interface A {
        [SupportedOSPlatform("windows")]
        public void M1();
        public void M2();  // maybe suggest to mark this one? 
    }
    class D : A
    {
        public void M1() { }
        [SupportedOSPlatform("windows")]
        public void M2() { }
        public void Test()
        {
            A a = new D(); // not warn, you mean we could warn here?
            D d = new D(); // not warn, and here?
            a.M1(); // warns as expected
            d.M1(); // not warns as expected
            a.M2(); // not warn, for me, it would be great if we could warn here instead of constructor
            d.M2(); // warns as expected
        }
    }

@terrajobst
Copy link
Member

terrajobst commented Nov 3, 2020

Isn't it better to suggest to mark the base type method instead of suggesting to mark constructor?

In principle yes, but that's not always actionable because I may not own the type. For example, let's say I need to implement a framework provided abstraction like IComparable<T> or TextWriter.

@buyaa-n
Copy link
Member Author

buyaa-n commented Nov 3, 2020

In principle yes, but that's not always actionable because I may not own the type. For example, let's say I need to implement a framework provided abstraction like IComparable or TextWriter.

Makes sense, if we decide to suggest to move the attribute to the constructor that could be covered with the other analyzer for platform attributes consistency

@buyaa-n buyaa-n changed the title Consider flag plarform specific constractor called implicitly in derived types Consider flag plarform specific constructor called implicitly in derived types Nov 9, 2020
@buyaa-n buyaa-n changed the title Consider flag plarform specific constructor called implicitly in derived types Consider flag platform specific constructor called implicitly in derived types Nov 9, 2020
@jeffhandley jeffhandley added the Priority:2 Moderately important label Nov 20, 2020
@jeffhandley jeffhandley added this to the .NET 6.x milestone Jan 13, 2021
@jeffhandley jeffhandley self-assigned this Jan 14, 2021
@jeffhandley jeffhandley added Priority:3 Nice to have (suitable for disabled by default rules and ported FxCop rules) Enhancement Cost:S and removed Priority:2 Moderately important labels Jan 21, 2021
@jeffhandley
Copy link
Member

We've not seen many hits of this; I'm tempted to close it out. @buyaa-n -- any objections?

@buyaa-n
Copy link
Member Author

buyaa-n commented Aug 3, 2021

We've not seen many hits of this; I'm tempted to close it out. @buyaa-n -- any objections?

Not sure if we should close it, probably haven't seen many hits because it is an edge case, but I think it is a valid case that need to be covered, maybe move to 7.0?

Tagging @terrajobst for his opinion

@buyaa-n buyaa-n modified the milestones: .NET 6.x, vNext Aug 5, 2021
@jeffhandley
Copy link
Member

Since this is a rare corner case that we haven't seen more hits of, I don't expect we'll make time for it in .NET 7. I'm going to go ahead and close it out. If folks stumble upon this behavior in the future, please file a new issue presenting the scenario in which you encountered it, and we can reconsider.

@jmarolf jmarolf modified the milestones: vNext, .NET 7.x Nov 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Microsoft.CodeAnalysis.NetAnalyzers Enhancement Priority:3 Nice to have (suitable for disabled by default rules and ported FxCop rules)
Projects
None yet
Development

No branches or pull requests

4 participants