dotnet/runtime
GitHub で見るAnalyzer: Replace occurrences of TypeInfo with Type and GetTypeInfo() with GetType()
Open
#61,122 opened on 2021年11月2日
api-approvedarea-System.Reflectioncode-analyzercode-fixerhelp wanted
Repository metrics
- Stars
- (17,886 stars)
- PR merge metrics
- (平均マージ 12d 11h) (30d で 661 merged PRs)
説明
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