From e7cbc86bf9db0ba4fa547a1ec58ccc2073bbd8a1 Mon Sep 17 00:00:00 2001 From: Michael Mayr Date: Wed, 7 Mar 2018 05:34:57 +0100 Subject: [ILVerify] Fix include/exclude pattern matching by using fully qualified method name and added some verbose output (#5416) * Fix include/exclude pattern matching by using fully qualified method name and added some verbose output * Added missing file * fix stringification of FieldDesc, MethodDesc and TypeDesc * Print progress as it goes * Handle empty namespace in GetQualifiedMethodName * Use simple counters for statistics and incorporated additional PR feedback * Removed ProcessedMethodTracker class and do all counting/printing logic directly in the VerifyAssembly method --- src/ILVerification/src/ILVerification.csproj | 12 +++ src/ILVerify/src/Program.cs | 105 ++++++++++++++++++++++----- 2 files changed, 97 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/ILVerification/src/ILVerification.csproj b/src/ILVerification/src/ILVerification.csproj index efa6e5349..95d759c45 100644 --- a/src/ILVerification/src/ILVerification.csproj +++ b/src/ILVerification/src/ILVerification.csproj @@ -77,6 +77,9 @@ TypeSystem\Common\ExceptionStringID.cs + + Utilities\DebugNameFormatter.cs + TypeSystem\Common\FieldForInstantiatedType.cs @@ -86,6 +89,9 @@ TypeSystem\Common\FieldDesc.FieldLayout.cs + + TypeSystem\Common\FieldDesc.ToString.cs + TypeSystem\Common\FieldLayoutAlgorithm.cs @@ -167,6 +173,9 @@ TypeSystem\Common\MethodDesc.cs + + TypeSystem\Common\MethodDesc.ToString.cs + TypeSystem\Common\StandardVirtualMethodAlgorithm.cs @@ -176,6 +185,9 @@ TypeSystem\Common\TypeDesc.Interfaces.cs + + TypeSystem\Common\TypeDesc.ToString.cs + TypeSystem\Common\DefType.cs diff --git a/src/ILVerify/src/Program.cs b/src/ILVerify/src/Program.cs index d748084b8..3f39ae75b 100644 --- a/src/ILVerify/src/Program.cs +++ b/src/ILVerify/src/Program.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; +using System.Text; using System.Text.RegularExpressions; using Internal.CommandLine; using Internal.TypeSystem.Ecma; @@ -20,6 +21,8 @@ namespace ILVerify class Program : ResolverBase { private bool _help; + private bool _verbose; + private bool _printStatistics; private AssemblyName _systemModule = new AssemblyName("mscorlib"); private Dictionary _inputFilePaths = new Dictionary(StringComparer.OrdinalIgnoreCase); // map of simple name to file path @@ -73,6 +76,8 @@ namespace ILVerify syntax.DefineOption("include-file", ref includeFile, "Same as --include, but the regular expression(s) are declared line by line in the specified file."); syntax.DefineOptionList("e|exclude", ref excludePatterns, "Skip methods/types/namespaces, which match the given regular expression(s)"); syntax.DefineOption("exclude-file", ref excludeFile, "Same as --exclude, but the regular expression(s) are declared line by line in the specified file."); + syntax.DefineOption("statistics", ref _printStatistics, "Print verification statistics"); + syntax.DefineOption("v|verbose", ref _verbose, "Verbose output"); syntax.DefineParameterList("in", ref inputFiles, "Input file(s)"); }); @@ -99,6 +104,25 @@ namespace ILVerify } _excludePatterns = StringPatternsToRegexList(excludePatterns); + if (_verbose) + { + WriteLine(); + foreach (var path in _inputFilePaths) + WriteLine($"Using input file '{path.Value}'"); + + WriteLine(); + foreach (var path in _referenceFilePaths) + WriteLine($"Using reference file '{path.Value}'"); + + WriteLine(); + foreach (var pattern in _includePatterns) + WriteLine($"Using include pattern '{pattern}'"); + + WriteLine(); + foreach (var pattern in _excludePatterns) + WriteLine($"Using exclude pattern '{pattern}'"); + } + return argSyntax; } @@ -119,19 +143,7 @@ namespace ILVerify foreach (var kvp in _inputFilePaths) { - var results = VerifyAssembly(new AssemblyName(kvp.Key), out EcmaModule module); - int numErrors = 0; - - foreach (var result in results) - { - numErrors++; - PrintResult(result, module, kvp.Value); - } - - if (numErrors > 0) - WriteLine(numErrors + " Error(s) Verifying " + kvp.Value); - else - WriteLine("All Classes and Methods in " + kvp.Value + " Verified."); + VerifyAssembly(new AssemblyName(kvp.Key), kvp.Value); } return 0; @@ -216,31 +228,84 @@ namespace ILVerify Write(")"); } - private IEnumerable VerifyAssembly(AssemblyName name, out EcmaModule module) + private void VerifyAssembly(AssemblyName name, string path) { PEReader peReader = Resolve(name); - module = _verifier.GetModule(peReader); + EcmaModule module = _verifier.GetModule(peReader); - return VerifyAssembly(peReader); + VerifyAssembly(peReader, module, path); } - private IEnumerable VerifyAssembly(PEReader peReader) + private void VerifyAssembly(PEReader peReader, EcmaModule module, string path) { + int numErrors = 0; + int verifiedMethodCounter = 0; + int methodCounter = 0; + MetadataReader metadataReader = peReader.GetMetadataReader(); foreach (var methodHandle in metadataReader.MethodDefinitions) { - var methodName = metadataReader.GetString(metadataReader.GetMethodDefinition(methodHandle).Name); - if (ShouldVerifyMethod(methodName)) + // get fully qualified method name + var methodName = GetQualifiedMethodName(metadataReader, methodHandle); + + bool verifying = ShouldVerifyMethod(methodName); + if (_verbose) + { + Write(verifying ? "Verifying " : "Skipping "); + WriteLine(methodName); + } + + if (verifying) { var results = _verifier.Verify(peReader, methodHandle); foreach (var result in results) { - yield return result; + PrintResult(result, module, path); + numErrors++; } + + verifiedMethodCounter++; } + + methodCounter++; + } + + if (numErrors > 0) + WriteLine(numErrors + " Error(s) Verifying " + path); + else + WriteLine("All Classes and Methods in " + path + " Verified."); + + if (_printStatistics) + { + WriteLine($"Methods found: {methodCounter}"); + WriteLine($"Methods verified: {verifiedMethodCounter}"); } } + /// + /// This method returns the fully qualified method name by concatenating assembly, type and method name. + /// This method exists to avoid additional assembly resolving, which might be triggered by calling + /// MethodDesc.ToString(). + /// + private string GetQualifiedMethodName(MetadataReader metadataReader, MethodDefinitionHandle methodHandle) + { + var methodDef = metadataReader.GetMethodDefinition(methodHandle); + var typeDef = metadataReader.GetTypeDefinition(methodDef.GetDeclaringType()); + + var methodName = metadataReader.GetString(metadataReader.GetMethodDefinition(methodHandle).Name); + var typeName = metadataReader.GetString(typeDef.Name); + var namespaceName = metadataReader.GetString(typeDef.Namespace); + var assemblyName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name); + + StringBuilder builder = new StringBuilder(); + builder.Append($"[{assemblyName}]"); + if (!string.IsNullOrEmpty(namespaceName)) + builder.Append($"{namespaceName}."); + builder.Append($"{typeName}.{methodName}"); + + return builder.ToString(); + } + private bool ShouldVerifyMethod(string methodName) { if (_includePatterns.Count > 0 && !_includePatterns.Any(p => p.IsMatch(methodName))) -- cgit v1.2.3