#region Copyright & License Information /* * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. For more * information, see COPYING. */ #endregion using System; using System.Linq; using System.Reflection; using OpenRA.Traits; namespace OpenRA.Mods.Common.UtilityCommands { public class CheckExplicitInterfacesCommand : IUtilityCommand { string IUtilityCommand.Name { get { return "--check-explicit-interfaces"; } } bool IUtilityCommand.ValidateArguments(string[] args) { return args.Length == 1; } int violationCount; [Desc("Check for explicit interface implementation violations in all assemblies referenced by the specified mod.")] void IUtilityCommand.Run(Utility utility, string[] args) { var types = utility.ModData.ObjectCreator.GetTypes(); foreach (var implementingType in types.Where(t => !t.IsInterface)) { if (implementingType.IsEnum) continue; var interfaces = implementingType.GetInterfaces(); foreach (var interfaceType in interfaces) { if (!interfaceType.HasAttribute()) continue; var interfaceMembers = interfaceType.GetMembers(); foreach (var interfaceMember in interfaceMembers) { if (interfaceMember.Name.StartsWith("get_") || interfaceMember.Name.StartsWith("set_")) continue; var interfaceMethod = interfaceMember as MethodInfo; if (interfaceMethod != null) { var interfaceMethodParams = interfaceMethod.GetParameters(); foreach (var implementingMethod in implementingType.GetMethods()) { if (implementingMethod.Name != interfaceMethod.Name || implementingMethod.ReturnType != interfaceMethod.ReturnType) continue; var implementingMethodParams = implementingMethod.GetParameters(); var lenImpl = implementingMethodParams.Length; if (lenImpl != interfaceMethodParams.Length) continue; var allMatch = true; for (var i = 0; i < lenImpl; i++) { var implementingParam = implementingMethodParams[i]; var interfaceParam = interfaceMethodParams[i]; if (implementingParam.ParameterType != interfaceParam.ParameterType || implementingParam.Name != interfaceParam.Name || implementingParam.IsOut != interfaceParam.IsOut) { allMatch = false; break; } } // Explicitly implemented methods are never public in C#. if (allMatch && implementingMethod.IsPublic) OnViolation(implementingType, interfaceType, implementingMethod); } } var interfaceProperty = interfaceMember as PropertyInfo; if (interfaceProperty != null) { var implementingProperties = implementingType.GetProperties(); foreach (var implementingProperty in implementingProperties) { if (implementingProperty.PropertyType != interfaceProperty.PropertyType || implementingProperty.Name != interfaceProperty.Name) continue; if (!IsExplicitInterfaceProperty(implementingProperty)) OnViolation(implementingType, interfaceType, implementingProperty); } } } } } if (violationCount > 0) { Console.WriteLine("Explicit interface violations: {0}", violationCount); Environment.Exit(1); } } static bool IsExplicitInterfaceProperty(PropertyInfo pi) { return pi.Name.Contains("."); } void OnViolation(Type implementor, Type interfaceType, MemberInfo violator) { Console.WriteLine("{0} must explicitly implement the interface member {1}.{2}", implementor.Name, interfaceType.Name, violator.Name); violationCount++; } } }