Browse Source

Moved most TypeInfo module validation logic from CommandService.

pull/1399/head
LtLi0n 5 years ago
parent
commit
c39e65ea33
1 changed files with 97 additions and 0 deletions
  1. +97
    -0
      src/Discord.Net.Commands/Extensions/TypeInfoExtensions.cs

+ 97
- 0
src/Discord.Net.Commands/Extensions/TypeInfoExtensions.cs View File

@@ -0,0 +1,97 @@
using Discord.Logging;
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace Discord.Commands
{
internal static class TypeInfoExtensions
{
public static async Task<bool> IsValidModuleType(this TypeInfo typeInfo, bool autoLoadable = false, Logger logger = null)
{
if(IsOuterSubTypeCandidate(typeInfo, out Type parentType))
{
return await IsValidOuterSubTypeAsync(typeInfo, parentType, autoLoadable, logger);
}
else
{
return await IsModuleAsync(typeInfo, logger, autoLoadable);
}
}

public static bool IsOuterSubTypeCandidate(this TypeInfo typeInfo, out Type parentType)
{
var groupAttr = typeInfo.GetCustomAttribute<GroupAttribute>();
if (groupAttr != null)
{
if (groupAttr.ParentModule != null)
{
parentType = groupAttr.ParentModule;
return true;
}
}
parentType = null;
return false;
}


/// <param name="autoLoadable">If true, must not contain [DontAutoLoad] or will return false.</param>
public static async Task<bool> IsValidOuterSubTypeAsync(this TypeInfo typeInfo, Type parentType, bool autoLoadable = false, Logger logger = null)
{
TypeInfo parentTypeInfo = parentType.GetTypeInfo();

bool targetValid = await IsModuleAsync(typeInfo, logger, autoLoadable);
if (targetValid)
{
bool parentValid = await IsModuleAsync(parentTypeInfo, logger, autoLoadable);
if (!parentValid)
{
if (logger != null)
{
await logger.WarningAsync($"Parent Class {parentTypeInfo.FullName} is not a module. Group module {typeInfo.FullName} was not loaded.").ConfigureAwait(false);
}
return false;
}
}
return targetValid;
}

private static async Task<bool> IsModuleAsync(TypeInfo typeInfo, Logger logger, bool autoLoadable)
{
if(IsValidModuleDefinition(typeInfo))
{
if (autoLoadable)
{
if (typeInfo.IsPublic || typeInfo.IsNestedPublic)
{
return !typeInfo.IsDefined(typeof(DontAutoLoadAttribute));
}
else if (IsAutoLoadableModuleCandidate(typeInfo))
{
if(logger != null)
{
await logger.WarningAsync($"Class {typeInfo.FullName} is not public and cannot be loaded. To suppress this message, mark the class with {nameof(DontAutoLoadAttribute)}.").ConfigureAwait(false);
}
}
}
else
{
return true;
}
}

return false;
}

internal static bool IsValidModuleDefinition(this TypeInfo typeInfo) =>
ModuleClassBuilder.ModuleTypeInfo.IsAssignableFrom(typeInfo) &&
!typeInfo.IsAbstract &&
!typeInfo.ContainsGenericParameters;

private static bool IsAutoLoadableModuleCandidate(TypeInfo typeInfo) =>
typeInfo.DeclaredMethods.Any(
x => x.GetCustomAttribute<CommandAttribute>() != null) &&
typeInfo.GetCustomAttribute<DontAutoLoadAttribute>() == null;
}
}

Loading…
Cancel
Save