dotnet/runtime

Analyzer: Replace occurrences of TypeInfo with Type and GetTypeInfo() with GetType()

Open

#61,122 opened on Nov 2, 2021

View on GitHub
 (3 comments) (0 reactions) (0 assignees)C# (5,445 forks)batch import
api-approvedarea-System.Reflectioncode-analyzercode-fixerhelp wanted

Repository metrics

Stars
 (17,886 stars)
PR merge metrics
 (Avg merge 12d 11h) (661 merged PRs in 30d)

Description

Related to https://github.com/dotnet/runtime/issues/53217#issuecomment-885962507 For obsoleting TypeInfo/GetTypeInfo we need an analyzer/code fixer that replaces GetTypeInfo() with calls to GetType(), and occurrences of TypeInfo with Type. A heavy reflection code base that migrated to Windows 8/was written for the Windows 8 era, would have had widely used both. The key would be making it easier for folks to replace them when the type is obsolete.

class DerivedClass : TypeInfo // Do not flag base types
{
   //  ...
}
class MyClass
{
    // I guess we don't want to warn/fix return type of a public/protected methods (maybe make it configurable)
    // flag/fix return type only for private methods by default
    // flag fix all local variables including the parameters
    TypeInfo GetTypeInfo(TypeInfo ti) => null;
    // flag/fix only private properties by default
    TypeInfo TypeInfo => null;
    // flag/fix only private fields by default
    private TypeInfo typeInfo = null;

    void ExampleBeforeFix()
    {
        TypeInfo ti = typeof(MyClass).GetTypeInfo();
        TypeInfo anotherInfo = GetTypeInfo(null); // TypeInfo comes from other API

        // possible references needs updated:
        IEnumerable<ConstructorInfo> constructors = ti.DeclaredConstructors;
        IEnumerable<EventInfo> events = ti.DeclaredEvents;
        IEnumerable<FieldInfo> fields = ti.DeclaredFields;
        IEnumerable<MemberInfo> memebrs = ti.DeclaredMembers;
        IEnumerable<MethodInfo> methods = ti.DeclaredMethods;
        IEnumerable<TypeInfo> nTypes = ti.DeclaredNestedTypes;
        IEnumerable<PropertyInfo> properties = ti.DeclaredProperties;
        Type[] genTypeParams = ti.GenericTypeParameters;
        IEnumerable<Type> interfaces = ti.ImplementedInterfaces;
        Type t = ti.AsType();
        EventInfo ei = ti.GetDeclaredEvent(name);
        FieldInfo fi = ti.GetDeclaredField(name);
        MethodInfo mi = ti.GetDeclaredMethod(name);
        IEnumerable<MethodInfo> mInfos = ti.GetDeclaredMethods(name);
        TypeInfo tInfo = ti.GetDeclaredNestedType(name);
        PropertyInfo pi = ti.GetDeclaredProperty(name);
        if (ti.IsAssignableFrom(anotherInfo));
        TypeInfo ati = ti.GetTypeInfo();
    }

    void ExampleAfterFix()
    {
        Type ti = typeof(MyClass);
        Type anotherInfo = GetTypeInfo(null); // TypeInfo comes from custom method

        // possible fixes for references
        IEnumerable<ConstructorInfo> constructors = ti.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
        IEnumerable<EventInfo> events = ti.GetEvents(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
        IEnumerable<FieldInfo> fields = ti.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
        IEnumerable<MemberInfo> memebrs = ti.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
        IEnumerable<MethodInfo> methods = ti.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
        // Should we cast the result to IEnumerable or change the type of the variable into array of Type? (IEnumerable<TypeInfo> nTypes = ti.DeclaredNestedTypes;)
        IEnumerable<TypeInfo> nTypes = (IEnumerable<TypeInfo>)ti.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
        IEnumerable<PropertyInfo> properties = ti.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); ;
        Type[] genTypeParams = ti.GetGenericArguments(); // or use: IsGenericTypeDefinition ? GetGenericArguments() : Type.EmptyTypes;
        IEnumerable<Type> interfaces = ti.GetInterfaces(); // before: ti.ImplementedInterfaces;
        Type t = ti; // before:  ti.AsType();
        EventInfo ei = ti.GetEvent(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
        FieldInfo fi = ti.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
        MethodInfo mi = ti.GetMethod(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
        // IEnumerable<MethodInfo> mInfos = ti.GetDeclaredMethods(name); No direct replacement, we might want to add correspodning method to the Type
        // Below type of tInfo changed from TypeInfo to Type 
        Type tInfo = ti.GetNestedType(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
        PropertyInfo pi = ti.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
        if (ti.IsAssignableFrom(anotherInfo)); // no change needed
        Type ati = ti.GetType(); // or just Type ati = ti; in case analyzer update type of ti
    }

    // we might want to add this const to Type and use for the arguments
    public const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;

    private string name = "name";
 }

Category: Maintainability or Design Severity: Info

cc @terrajobst @carlossanlop

Contributor guide