private static void PostBuildCheck(IPostBuildReporter rep) { Lingo.PostBuildStep <Translation>(rep, Assembly.GetExecutingAssembly()); Classify.PostBuildStep <Settings>(rep); Classify.PostBuildStep <Style>(rep); Classify.PostBuildStep <GameVersionConfig>(rep); }
/// <summary> /// Performs safety checks to ensure that a settings object conforms to various requirements imposed by /// SettingsUtil methods. Run this method as a post-build step to ensure reliability of execution. For an example /// of use, see <see cref="PostBuildChecker.RunPostBuildChecks"/>. This method is available only in DEBUG mode.</summary> /// <typeparam name="TSettings"> /// The type of the settings object, derived from <see cref="SettingsBase"/>, which would be passed to /// SettingsUtil methods at normal run-time.</typeparam> /// <param name="rep"> /// Object to report post-build errors to.</param> public static void PostBuildStep <TSettings>(IPostBuildReporter rep) where TSettings : SettingsBase { SettingsAttribute attr; try { attr = GetAttribute(typeof(TSettings)); } catch (Exception e) { rep.Error(e.Message, "class", typeof(TSettings).Name); return; } switch (attr.Serializer) { case SettingsSerializer.DotNetBinary: break; case SettingsSerializer.ClassifyXml: case SettingsSerializer.ClassifyJson: case SettingsSerializer.ClassifyBinary: Classify.PostBuildStep <TSettings>(rep); break; } }
private static void PostBuildCheck(IPostBuildReporter rep) { foreach (var pair in _keyBindingsRaw.UniquePairs()) { if (pair.Item1.Mode == pair.Item2.Mode && pair.Item1.Key == pair.Item2.Key && pair.Item1.Modifiers == pair.Item2.Modifiers) { var tok = "EditMode.{0}, {1}, ConsoleKey.{2}".Fmt(pair.Item1.Mode, pair.Item1.Modifiers == 0 ? "0" : "ConsoleModifiers." + pair.Item1.Modifiers, pair.Item1.Key); rep.Error(@"There are two key bindings for {0} in mode {1}.".Fmt( pair.Item1.Modifiers == 0 ? pair.Item1.Key.ToString() : pair.Item1.Modifiers + "+" + pair.Item1.Key, pair.Item1.Mode ), "_keyBindingsRaw", tok); rep.Error(@" -- Second use is here.", "_keyBindingsRaw", tok, tok); } } }
private static void PostBuildCheck(IPostBuildReporter rep) { try { initInstructionsDictionary(); } catch (DuplicateCharacterException e) { rep.Error(e.Message, "enum instruction", e.Character.ToString()); return; } foreach (var instrKvp in _instructionTypes) { if (instrKvp.Value == NodeType.BlockHead) { try { BlockNode.Create(instrKvp.Key, _instructions[instrKvp.Key], 0, 0, null, null, false); } catch { rep.Error(@"Block instruction ""{0}"" is not processed.".Fmt(instrKvp), "blockNode createBlockNode", "default"); } } else if (instrKvp.Value == NodeType.FunctionExecutionNode) { try { ExecuteFunction.Create(_instructions[instrKvp.Key], 0, 0); } catch { rep.Error(@"Function execution instruction ""{0}"" is not processed.".Fmt(instrKvp), "executeFunction createFunctionExecutionNode", "default"); } } } }
/// <summary>Checks that the enum values declared in the specified enum type and the TrString fields declared in the specified translation type match exactly.</summary> private static void checkEnumTranslation(IPostBuildReporter rep, Type enumType, Type translationType) { var set = translationType.GetAllFields().Where(f => f.FieldType == typeof(TrString)).Select(f => f.Name).ToHashSet(); foreach (var enumValue in Enum.GetValues(enumType)) { if (!set.Contains(enumValue.ToString())) { rep.Error(@"The translation type ""{0}"" does not contain a field of type {1} with the name ""{2}"" declared in enum type ""{3}"".".Fmt(translationType.FullName, typeof(TrString).Name, enumValue, enumType.FullName), "class " + translationType.Name); rep.Error(@"---- Enum type is here.", "enum " + enumType.Name); } } foreach (var value in set) { try { Enum.Parse(enumType, value, ignoreCase: false); } catch (ArgumentException) { rep.Error(@"The enum type ""{0}"" does not contain a value with the name ""{1}"" declared in translation type ""{2}"".".Fmt(enumType.FullName, value, translationType.FullName), "enum " + enumType.Name); rep.Error(@"---- Translation type is here.", "class " + translationType.Name); } } }
private static void PostBuildCheck(IPostBuildReporter rep) { SettingsUtil.PostBuildStep<Settings>(rep); }
public static void PostBuildCheck(IPostBuildReporter rep) { CommandLineParser.PostBuildStep <CommandLineBase>(rep, null); }
/// <summary>Checks the specified assemblies for any obvious Lingo-related problems, including unused strings, mismatched enum translations.</summary> /// <typeparam name="TTranslation">The type of the translation class.</typeparam> /// <param name="rep">Post-build step reporter.</param> /// <param name="assemblies">A list of assemblies to check. The Lingo assembly is included automatically to ensure correct operation.</param> public static void PostBuildStep <TTranslation>(IPostBuildReporter rep, params Assembly[] assemblies) { if (!assemblies.Contains(Assembly.GetExecutingAssembly())) { assemblies = assemblies.Concat(Assembly.GetExecutingAssembly()).ToArray(); } // Check that all enum translations are sensible var allEnumTrs = allEnumTranslations(assemblies).ToList(); foreach (var tr in allEnumTrs) { checkEnumTranslation(rep, tr.EnumType, tr.TranslationType); } // Check all component model member translations foreach (var type in assemblies.SelectMany(a => a.GetTypes())) { // All functions returning MemberTr and accepting a TranslationBase descendant must conform var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(p => p.Name).ToHashSet(); foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) { if (method.ReturnType == typeof(MemberTr) && method.GetParameters().Length == 1 && typeof(TranslationBase).IsAssignableFrom(method.GetParameters()[0].ParameterType)) { if (!method.IsStatic) { rep.Error("A member translation method must be static. Translation method: {0}".Fmt(method.DeclaringType.FullName + "." + method.Name), "class " + method.DeclaringType.Name, typeof(MemberTr).Name + " " + method.Name); } if (!method.Name.EndsWith("Tr")) { rep.Error("The name of a member translation method must end with the letters \"Tr\". Translation method: {0}".Fmt(method.DeclaringType.FullName + "." + method.Name), "class " + method.DeclaringType.Name, typeof(MemberTr).Name + " " + method.Name); } var propertyName = method.Name.Substring(0, method.Name.Length - 2); if (!properties.Contains(propertyName)) { rep.Error("Member translation method has no corresponding property named \"{1}\". Translation method: {0}".Fmt(method.DeclaringType.FullName + "." + method.Name, propertyName), "class " + method.DeclaringType.Name, typeof(MemberTr).Name + " " + method.Name); } } } } // Find unused strings var fields = new HashSet <FieldInfo>(); addAllLingoRelevantFields(typeof(TTranslation), fields); // Treat all fields used for enum translations as used foreach (var f in allEnumTrs.SelectMany(et => et.TranslationType.GetAllFields())) { fields.Remove(f); } // Treat all fields that occur in a ldfld / ldflda instruction as used foreach (var mod in assemblies.SelectMany(a => a.GetModules(false))) { foreach (var typ in mod.GetTypes()) { foreach (var meth in typ.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance).Where(m => m.DeclaringType == typ).Cast <MethodBase>().Concat( typ.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance).Where(c => c.DeclaringType == typ).Cast <MethodBase>())) { foreach (var instr in ILReader.ReadIL(meth, typ)) { if (instr.OpCode == OpCodes.Ldfld || instr.OpCode == OpCodes.Ldflda) { fields.Remove((FieldInfo)instr.Operand); if (fields.Count == 0) { goto done; // don't have to break the loop early, but there's really no point in searching the rest of the code now } } } } } } // Report warnings for all unused strings (not errors so that the developer can test things in the presence of unused strings) done: foreach (var field in fields) { rep.Warning("Unused Lingo field: " + field.DeclaringType.FullName + "." + field.Name, "class " + field.DeclaringType.Name, field.FieldType.Name, field.Name); } }
private static void PostBuildCheck(IPostBuildReporter rep) { CommandLineParser.PostBuildStep <CmdLine>(rep, null); }
private static void PostBuildCheck(IPostBuildReporter rep) { SettingsUtil.PostBuildStep <Settings>(rep); }
private static void PostBuildCheck(IPostBuildReporter rep) { Classify.PostBuildStep(typeof(Settings), rep); Classify.PostBuildStep(typeof(Cloud), rep); }
private static void PostBuildCheck(IPostBuildReporter rep) { }
private static void PostBuildCheck(IPostBuildReporter rep) { if (Characters.Length != Engrish.Length) rep.Error("listStringElementNode: Number of characters ({0}) does not equal number of Engrish terms ({1}).".Fmt(Characters.Length, Engrish.Length), "class listStringElementNode", "Characters"); var numInstr = EnumStrong.GetValues<ListStringInstruction>().Length; if (Characters.Length != 20 * numInstr) rep.Error("listStringElementNode: Number of characters ({0}) does not equal 20 times the number of list/string instructions ({1}).".Fmt(Characters.Length, numInstr), "class listStringElementNode", "Engrish"); }
private static void PostBuildCheck(IPostBuildReporter rep) { foreach (var field in typeof(Instruction).GetFields(BindingFlags.Public | BindingFlags.Static)) { var attr = field.GetCustomAttributes<InstructionAttribute>().First(); var instr = (Instruction) field.GetValue(null); if (attr.Type == NodeType.SingularNode && !field.IsDefined<SingularListStringInstructionAttribute>()) { try { getMethod(instr); } catch { rep.Error(@"Instruction ""{0}"" has no method.".Fmt(instr), "singularNode", "getMethod", "default"); } } } }
private static void PostBuildCheck(IPostBuildReporter rep) { Classify.PostBuildStep <Settings>(rep); }