Weaver: Logger as interface with MemberReference variants to avoid static Error/Warning methods

This commit is contained in:
vis2k 2021-08-19 22:25:30 +08:00
parent 1da0744875
commit a018f5dc37
14 changed files with 91 additions and 88 deletions

View File

@ -23,20 +23,6 @@ public static class CompilationFinishedHook
// controls weather Weaver errors are reported direct to the Unity console (tests enable this)
public static bool UnityLogEnabled = true;
// warning message handler that also calls OnWarningMethod delegate
static void HandleWarning(string msg)
{
if (UnityLogEnabled) Debug.LogWarning(msg);
OnWeaverWarning?.Invoke(msg);
}
// error message handler that also calls OnErrorMethod delegate
static void HandleError(string msg)
{
if (UnityLogEnabled) Debug.LogError(msg);
OnWeaverError?.Invoke(msg);
}
[InitializeOnLoadMethod]
public static void OnInitializeOnLoad()
{
@ -139,7 +125,7 @@ static void OnCompilationFinished(string assemblyPath, CompilerMessage[] message
dependencyPaths.Add(Path.GetDirectoryName(unityEngineCoreModuleDLL));
// set up weaver logging
Weaver.Log = new Logger(HandleWarning, HandleError);
Weaver.Log = new CompilationFinishedLogger();
if (!WeaveFromFile(assemblyPath, dependencyPaths.ToArray()))
{

View File

@ -0,0 +1,28 @@
// logger for compilation finished hook.
// where we need a callback and Debug.Log.
using Mono.CecilX;
using UnityEngine;
namespace Mirror.Weaver
{
public class CompilationFinishedLogger : Logger
{
public void Warning(string message) => Warning(message, null);
public void Warning(string message, MemberReference mr)
{
if (mr != null) message = $"{message} (at {mr})";
if (CompilationFinishedHook.UnityLogEnabled) Debug.LogWarning(message);
CompilationFinishedHook.OnWeaverWarning?.Invoke(message);
}
public void Error(string message) => Error(message, null);
public void Error(string message, MemberReference mr)
{
if (mr != null) message = $"{message} (at {mr})";
if (CompilationFinishedHook.UnityLogEnabled) Debug.LogError(message);
CompilationFinishedHook.OnWeaverError?.Invoke(message);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 47026732f0fa475c94bd1dd41f1de559
timeCreated: 1629379868

View File

@ -1,17 +1,13 @@
using System;
using Mono.CecilX;
namespace Mirror.Weaver
{
// not static, because ILPostProcessor is multithreaded
public class Logger
public interface Logger
{
public Action<string> Warning;
public Action<string> Error;
public Logger(Action<string> Warning, Action<string>Error)
{
this.Warning = Warning;
this.Error = Error;
}
public void Warning(string message);
public void Warning(string message, MemberReference mr);
public void Error(string message);
public void Error(string message, MemberReference mr);
}
}

View File

@ -95,14 +95,14 @@ public static void FixRemoteCallToBaseMethod(TypeDefinition type, MethodDefiniti
if (baseMethod == null)
{
Weaver.Error($"Could not find base method for {callName}", method);
Weaver.Log.Error($"Could not find base method for {callName}", method);
Weaver.WeavingFailed = true;
return;
}
if (!baseMethod.IsVirtual)
{
Weaver.Error($"Could not find base method that was virutal {callName}", method);
Weaver.Log.Error($"Could not find base method that was virutal {callName}", method);
Weaver.WeavingFailed = true;
return;
}

View File

@ -18,13 +18,13 @@ static void ProcessSyncVars(TypeDefinition td)
{
if (fd.HasCustomAttribute<SyncVarAttribute>())
{
Weaver.Error($"SyncVar {fd.Name} must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd);
Weaver.Log.Error($"SyncVar {fd.Name} must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd);
Weaver.WeavingFailed = true;
}
if (SyncObjectInitializer.ImplementsSyncObject(fd.FieldType))
{
Weaver.Error($"{fd.Name} is a SyncObject and must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd);
Weaver.Log.Error($"{fd.Name} is a SyncObject and must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd);
Weaver.WeavingFailed = true;
}
}
@ -37,17 +37,17 @@ static void ProcessMethods(TypeDefinition td)
{
if (md.HasCustomAttribute<CommandAttribute>())
{
Weaver.Error($"Command {md.Name} must be declared inside a NetworkBehaviour", md);
Weaver.Log.Error($"Command {md.Name} must be declared inside a NetworkBehaviour", md);
Weaver.WeavingFailed = true;
}
if (md.HasCustomAttribute<ClientRpcAttribute>())
{
Weaver.Error($"ClientRpc {md.Name} must be declared inside a NetworkBehaviour", md);
Weaver.Log.Error($"ClientRpc {md.Name} must be declared inside a NetworkBehaviour", md);
Weaver.WeavingFailed = true;
}
if (md.HasCustomAttribute<TargetRpcAttribute>())
{
Weaver.Error($"TargetRpc {md.Name} must be declared inside a NetworkBehaviour", md);
Weaver.Log.Error($"TargetRpc {md.Name} must be declared inside a NetworkBehaviour", md);
Weaver.WeavingFailed = true;
}
}

View File

@ -65,7 +65,7 @@ public bool Process()
if (netBehaviourSubclass.HasGenericParameters)
{
Weaver.Error($"{netBehaviourSubclass.Name} cannot have generic parameters", netBehaviourSubclass);
Weaver.Log.Error($"{netBehaviourSubclass.Name} cannot have generic parameters", netBehaviourSubclass);
Weaver.WeavingFailed = true;
// originally Process returned true in every case, except if already processed.
// maybe return false here in the future.
@ -187,7 +187,7 @@ public static bool WriteArguments(ILProcessor worker, MethodDefinition method, R
MethodReference writeFunc = ReaderWriterProcessor.writers.GetWriteFunc(param.ParameterType);
if (writeFunc == null)
{
Weaver.Error($"{method.Name} has invalid parameter {param}", method);
Weaver.Log.Error($"{method.Name} has invalid parameter {param}", method);
Weaver.WeavingFailed = true;
return false;
}
@ -245,7 +245,7 @@ void GenerateConstants()
}
else
{
Weaver.Error($"{netBehaviourSubclass.Name} has invalid class constructor", cctor);
Weaver.Log.Error($"{netBehaviourSubclass.Name} has invalid class constructor", cctor);
Weaver.WeavingFailed = true;
return;
}
@ -267,7 +267,7 @@ void GenerateConstants()
if (ctor == null)
{
Weaver.Error($"{netBehaviourSubclass.Name} has invalid constructor", netBehaviourSubclass);
Weaver.Log.Error($"{netBehaviourSubclass.Name} has invalid constructor", netBehaviourSubclass);
Weaver.WeavingFailed = true;
return;
}
@ -279,7 +279,7 @@ void GenerateConstants()
}
else
{
Weaver.Error($"{netBehaviourSubclass.Name} has invalid constructor", ctor);
Weaver.Log.Error($"{netBehaviourSubclass.Name} has invalid constructor", ctor);
Weaver.WeavingFailed = true;
return;
}
@ -420,7 +420,7 @@ void GenerateSerialization()
}
else
{
Weaver.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
Weaver.Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
Weaver.WeavingFailed = true;
return;
}
@ -476,7 +476,7 @@ void GenerateSerialization()
}
else
{
Weaver.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
Weaver.Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
Weaver.WeavingFailed = true;
return;
}
@ -738,7 +738,7 @@ void DeserializeNormalField(WeaverTypes weaverTypes, FieldDefinition syncVar, IL
MethodReference readFunc = ReaderWriterProcessor.readers.GetReadFunc(syncVar.FieldType);
if (readFunc == null)
{
Weaver.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
Weaver.Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
Weaver.WeavingFailed = true;
return;
}
@ -919,7 +919,7 @@ public static bool ReadArguments(MethodDefinition method, ILProcessor worker, Re
if (readFunc == null)
{
Weaver.Error($"{method.Name} has invalid parameter {param}. Unsupported type {param.ParameterType}, use a supported Mirror type instead", method);
Weaver.Log.Error($"{method.Name} has invalid parameter {param}. Unsupported type {param.ParameterType}, use a supported Mirror type instead", method);
Weaver.WeavingFailed = true;
return false;
}
@ -953,7 +953,7 @@ public static bool ValidateRemoteCallAndParameters(MethodDefinition method, Remo
{
if (method.IsStatic)
{
Weaver.Error($"{method.Name} must not be static", method);
Weaver.Log.Error($"{method.Name} must not be static", method);
Weaver.WeavingFailed = true;
return false;
}
@ -967,19 +967,19 @@ static bool ValidateFunction(MethodReference md)
{
if (md.ReturnType.Is<System.Collections.IEnumerator>())
{
Weaver.Error($"{md.Name} cannot be a coroutine", md);
Weaver.Log.Error($"{md.Name} cannot be a coroutine", md);
Weaver.WeavingFailed = true;
return false;
}
if (!md.ReturnType.Is(typeof(void)))
{
Weaver.Error($"{md.Name} cannot return a value. Make it void instead", md);
Weaver.Log.Error($"{md.Name} cannot return a value. Make it void instead", md);
Weaver.WeavingFailed = true;
return false;
}
if (md.HasGenericParameters)
{
Weaver.Error($"{md.Name} cannot have generic parameters", md);
Weaver.Log.Error($"{md.Name} cannot have generic parameters", md);
Weaver.WeavingFailed = true;
return false;
}
@ -1008,7 +1008,7 @@ static bool ValidateParameter(MethodReference method, ParameterDefinition param,
if (param.IsOut)
{
Weaver.Error($"{method.Name} cannot have out parameters", method);
Weaver.Log.Error($"{method.Name} cannot have out parameters", method);
Weaver.WeavingFailed = true;
return false;
}
@ -1019,11 +1019,11 @@ static bool ValidateParameter(MethodReference method, ParameterDefinition param,
{
if (callType == RemoteCallType.Command)
{
Weaver.Error($"{method.Name} has invalid parameter {param}, Cannot pass NetworkConnections. Instead use 'NetworkConnectionToClient conn = null' to get the sender's connection on the server", method);
Weaver.Log.Error($"{method.Name} has invalid parameter {param}, Cannot pass NetworkConnections. Instead use 'NetworkConnectionToClient conn = null' to get the sender's connection on the server", method);
}
else
{
Weaver.Error($"{method.Name} has invalid parameter {param}. Cannot pass NetworkConnections", method);
Weaver.Log.Error($"{method.Name} has invalid parameter {param}. Cannot pass NetworkConnections", method);
}
Weaver.WeavingFailed = true;
return false;
@ -1032,7 +1032,7 @@ static bool ValidateParameter(MethodReference method, ParameterDefinition param,
// sender connection can be optional
if (param.IsOptional && !isSenderConnection)
{
Weaver.Error($"{method.Name} cannot have optional parameters", method);
Weaver.Log.Error($"{method.Name} cannot have optional parameters", method);
Weaver.WeavingFailed = true;
return false;
}
@ -1089,7 +1089,7 @@ void ProcessClientRpc(HashSet<string> names, MethodDefinition md, CustomAttribut
{
if (md.IsAbstract)
{
Weaver.Error("Abstract ClientRpc are currently not supported, use virtual method instead", md);
Weaver.Log.Error("Abstract ClientRpc are currently not supported, use virtual method instead", md);
Weaver.WeavingFailed = true;
return;
}
@ -1101,7 +1101,7 @@ void ProcessClientRpc(HashSet<string> names, MethodDefinition md, CustomAttribut
if (names.Contains(md.Name))
{
Weaver.Error($"Duplicate ClientRpc name {md.Name}", md);
Weaver.Log.Error($"Duplicate ClientRpc name {md.Name}", md);
Weaver.WeavingFailed = true;
return;
}
@ -1130,7 +1130,7 @@ void ProcessTargetRpc(HashSet<string> names, MethodDefinition md, CustomAttribut
{
if (md.IsAbstract)
{
Weaver.Error("Abstract TargetRpc are currently not supported, use virtual method instead", md);
Weaver.Log.Error("Abstract TargetRpc are currently not supported, use virtual method instead", md);
Weaver.WeavingFailed = true;
return;
}
@ -1140,7 +1140,7 @@ void ProcessTargetRpc(HashSet<string> names, MethodDefinition md, CustomAttribut
if (names.Contains(md.Name))
{
Weaver.Error($"Duplicate Target Rpc name {md.Name}", md);
Weaver.Log.Error($"Duplicate Target Rpc name {md.Name}", md);
Weaver.WeavingFailed = true;
return;
}
@ -1160,7 +1160,7 @@ void ProcessCommand(HashSet<string> names, MethodDefinition md, CustomAttribute
{
if (md.IsAbstract)
{
Weaver.Error("Abstract Commands are currently not supported, use virtual method instead", md);
Weaver.Log.Error("Abstract Commands are currently not supported, use virtual method instead", md);
Weaver.WeavingFailed = true;
return;
}
@ -1170,7 +1170,7 @@ void ProcessCommand(HashSet<string> names, MethodDefinition md, CustomAttribute
if (names.Contains(md.Name))
{
Weaver.Error($"Duplicate Command name {md.Name}", md);
Weaver.Log.Error($"Duplicate Command name {md.Name}", md);
Weaver.WeavingFailed = true;
return;
}

View File

@ -32,7 +32,7 @@ static bool ProcessSiteMethod(WeaverTypes weaverTypes, MethodDefinition md)
{
if (HasServerClientAttribute(md))
{
Weaver.Error("Server or Client Attributes can't be added to abstract method. Server and Client Attributes are not inherited so they need to be applied to the override methods instead.", md);
Weaver.Log.Error("Server or Client Attributes can't be added to abstract method. Server and Client Attributes are not inherited so they need to be applied to the override methods instead.", md);
Weaver.WeavingFailed = true;
}
return false;

View File

@ -17,7 +17,7 @@ public static List<FieldDefinition> FindSyncObjectsFields(TypeDefinition td)
{
if (fd.IsStatic)
{
Weaver.Error($"{fd.Name} cannot be static", fd);
Weaver.Log.Error($"{fd.Name} cannot be static", fd);
Weaver.WeavingFailed = true;
continue;
}

View File

@ -50,7 +50,7 @@ MethodDefinition FindHookMethod(TypeDefinition td, FieldDefinition syncVar, stri
if (methodsWith2Param.Count == 0)
{
Weaver.Error($"Could not find hook for '{syncVar.Name}', hook name '{hookFunctionName}'. " +
Weaver.Log.Error($"Could not find hook for '{syncVar.Name}', hook name '{hookFunctionName}'. " +
$"Method signature should be {HookParameterMessage(hookFunctionName, syncVar.FieldType)}",
syncVar);
Weaver.WeavingFailed = true;
@ -66,7 +66,7 @@ MethodDefinition FindHookMethod(TypeDefinition td, FieldDefinition syncVar, stri
}
}
Weaver.Error($"Wrong type for Parameter in hook for '{syncVar.Name}', hook name '{hookFunctionName}'. " +
Weaver.Log.Error($"Wrong type for Parameter in hook for '{syncVar.Name}', hook name '{hookFunctionName}'. " +
$"Method signature should be {HookParameterMessage(hookFunctionName, syncVar.FieldType)}",
syncVar);
Weaver.WeavingFailed = true;
@ -368,21 +368,21 @@ public void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, Dictionary<Fie
{
if ((fd.Attributes & FieldAttributes.Static) != 0)
{
Weaver.Error($"{fd.Name} cannot be static", fd);
Weaver.Log.Error($"{fd.Name} cannot be static", fd);
Weaver.WeavingFailed = true;
continue;
}
if (fd.FieldType.IsArray)
{
Weaver.Error($"{fd.Name} has invalid type. Use SyncLists instead of arrays", fd);
Weaver.Log.Error($"{fd.Name} has invalid type. Use SyncLists instead of arrays", fd);
Weaver.WeavingFailed = true;
continue;
}
if (SyncObjectInitializer.ImplementsSyncObject(fd.FieldType))
{
Weaver.Warning($"{fd.Name} has [SyncVar] attribute. SyncLists should not be marked with SyncVar", fd);
Weaver.Log.Warning($"{fd.Name} has [SyncVar] attribute. SyncLists should not be marked with SyncVar", fd);
}
else
{
@ -393,7 +393,7 @@ public void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, Dictionary<Fie
if (dirtyBitCounter == SyncVarLimit)
{
Weaver.Error($"{td.Name} has too many SyncVars. Consider refactoring your class into multiple components", td);
Weaver.Log.Error($"{td.Name} has too many SyncVars. Consider refactoring your class into multiple components", td);
Weaver.WeavingFailed = true;
continue;
}

View File

@ -71,7 +71,7 @@ MethodReference GenerateReader(TypeReference variableReference)
{
if (variableReference.IsMultidimensionalArray())
{
Weaver.Error($"{variableReference.Name} is an unsupported type. Multidimensional arrays are not supported", variableReference);
Weaver.Log.Error($"{variableReference.Name} is an unsupported type. Multidimensional arrays are not supported", variableReference);
Weaver.WeavingFailed = true;
return null;
}
@ -84,14 +84,14 @@ MethodReference GenerateReader(TypeReference variableReference)
// check if the type is completely invalid
if (variableDefinition == null)
{
Weaver.Error($"{variableReference.Name} is not a supported type", variableReference);
Weaver.Log.Error($"{variableReference.Name} is not a supported type", variableReference);
Weaver.WeavingFailed = true;
return null;
}
else if (variableReference.IsByReference)
{
// error??
Weaver.Error($"Cannot pass type {variableReference.Name} by reference", variableReference);
Weaver.Log.Error($"Cannot pass type {variableReference.Name} by reference", variableReference);
Weaver.WeavingFailed = true;
return null;
}
@ -120,37 +120,37 @@ MethodReference GenerateReader(TypeReference variableReference)
// check if reader generation is applicable on this type
if (variableDefinition.IsDerivedFrom<UnityEngine.Component>())
{
Weaver.Error($"Cannot generate reader for component type {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.Log.Error($"Cannot generate reader for component type {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.WeavingFailed = true;
return null;
}
if (variableReference.Is<UnityEngine.Object>())
{
Weaver.Error($"Cannot generate reader for {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.Log.Error($"Cannot generate reader for {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.WeavingFailed = true;
return null;
}
if (variableReference.Is<UnityEngine.ScriptableObject>())
{
Weaver.Error($"Cannot generate reader for {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.Log.Error($"Cannot generate reader for {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.WeavingFailed = true;
return null;
}
if (variableDefinition.HasGenericParameters)
{
Weaver.Error($"Cannot generate reader for generic variable {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.Log.Error($"Cannot generate reader for generic variable {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.WeavingFailed = true;
return null;
}
if (variableDefinition.IsInterface)
{
Weaver.Error($"Cannot generate reader for interface {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.Log.Error($"Cannot generate reader for interface {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.WeavingFailed = true;
return null;
}
if (variableDefinition.IsAbstract)
{
Weaver.Error($"Cannot generate reader for abstract class {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.Log.Error($"Cannot generate reader for abstract class {variableReference.Name}. Use a supported type or provide a custom reader", variableReference);
Weaver.WeavingFailed = true;
return null;
}
@ -311,7 +311,7 @@ void CreateNew(TypeReference variable, ILProcessor worker, TypeDefinition td)
MethodDefinition ctor = Resolvers.ResolveDefaultPublicCtor(variable);
if (ctor == null)
{
Weaver.Error($"{variable.Name} can't be deserialized because it has no default constructor", variable);
Weaver.Log.Error($"{variable.Name} can't be deserialized because it has no default constructor", variable);
Weaver.WeavingFailed = true;
return;
}
@ -338,7 +338,7 @@ void ReadAllFields(TypeReference variable, ILProcessor worker)
}
else
{
Weaver.Error($"{field.Name} has an unsupported type", field);
Weaver.Log.Error($"{field.Name} has an unsupported type", field);
Weaver.WeavingFailed = true;
}
FieldReference fieldRef = assembly.MainModule.ImportReference(field);

View File

@ -21,7 +21,7 @@ public static MethodReference ResolveMethod(TypeReference tr, AssemblyDefinition
MethodReference method = ResolveMethod(tr, scriptDef, m => m.Name == name);
if (method == null)
{
Weaver.Error($"Method not found with name {name} in type {tr.Name}", tr);
Weaver.Log.Error($"Method not found with name {name} in type {tr.Name}", tr);
Weaver.WeavingFailed = true;
}
return method;
@ -37,7 +37,7 @@ public static MethodReference ResolveMethod(TypeReference t, AssemblyDefinition
}
}
Weaver.Error($"Method not found in type {t.Name}", t);
Weaver.Log.Error($"Method not found in type {t.Name}", t);
Weaver.WeavingFailed = true;
return null;
}

View File

@ -24,16 +24,6 @@ internal static class Weaver
// multi threaded logging.
public static Logger Log;
public static void Error(string message, MemberReference mr)
{
Log.Error($"{message} (at {mr})");
}
public static void Warning(string message, MemberReference mr)
{
Log.Warning($"{message} (at {mr})");
}
static bool WeaveNetworkBehavior(TypeDefinition td)
{
if (!td.IsClass)

View File

@ -64,7 +64,7 @@ public MethodReference GetWriteFunc(TypeReference variable)
}
catch (GenerateWriterException e)
{
Weaver.Error(e.Message, e.MemberReference);
Weaver.Log.Error(e.Message, e.MemberReference);
Weaver.WeavingFailed = true;
return null;
}
@ -279,7 +279,7 @@ MethodDefinition GenerateCollectionWriter(TypeReference variable, TypeReference
// need this null check till later PR when GetWriteFunc throws exception instead
if (elementWriteFunc == null)
{
Weaver.Error($"Cannot generate writer for {variable}. Use a supported type or provide a custom writer", variable);
Weaver.Log.Error($"Cannot generate writer for {variable}. Use a supported type or provide a custom writer", variable);
Weaver.WeavingFailed = true;
return writerFunc;
}