diff --git a/main/OpenCover.Framework/Communication/MessageHandler.cs b/main/OpenCover.Framework/Communication/MessageHandler.cs index d49a1152b..0ab052d15 100644 --- a/main/OpenCover.Framework/Communication/MessageHandler.cs +++ b/main/OpenCover.Framework/Communication/MessageHandler.cs @@ -121,7 +121,7 @@ private int HandleGetSequencePointsMessage(IntPtr pinnedMemory, IManagedCommunic { var request = _marshalWrapper.PtrToStructure(pinnedMemory); InstrumentationPoint[] origPoints; - _profilerCommunication.GetSequencePoints(request.processName, request.modulePath, request.assemblyName, + _profilerCommunication.GetSequencePoints(request.processPath, request.modulePath, request.assemblyName, request.functionToken, out origPoints); var num = origPoints.Maybe(o => o.Length); @@ -169,7 +169,7 @@ private int HandleGetBranchPointsMessage(IntPtr pinnedMemory, IManagedCommunicat { var request = _marshalWrapper.PtrToStructure(pinnedMemory); BranchPoint[] origPoints; - _profilerCommunication.GetBranchPoints(request.processName, request.modulePath, request.assemblyName, + _profilerCommunication.GetBranchPoints(request.processPath, request.modulePath, request.assemblyName, request.functionToken, out origPoints); var num = origPoints.Maybe(o => o.Length); @@ -290,7 +290,7 @@ private int HandleTrackAssemblyMessage(IntPtr pinnedMemory) try { var request = _marshalWrapper.PtrToStructure(pinnedMemory); - response.track = _profilerCommunication.TrackAssembly(request.processName, request.modulePath, request.assemblyName); + response.track = _profilerCommunication.TrackAssembly(request.processPath, request.modulePath, request.assemblyName); } catch (Exception ex) { diff --git a/main/OpenCover.Framework/Communication/Messages.cs b/main/OpenCover.Framework/Communication/Messages.cs index 49c423669..34e618dd1 100644 --- a/main/OpenCover.Framework/Communication/Messages.cs +++ b/main/OpenCover.Framework/Communication/Messages.cs @@ -96,7 +96,7 @@ public struct MSG_TrackAssembly_Request /// The path to the process /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] - public string processName; + public string processPath; /// /// The path to the module/assembly @@ -144,7 +144,7 @@ public struct MSG_GetSequencePoints_Request /// The path to the process /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] - public string processName; + public string processPath; /// /// The path to the module hosting the emthod @@ -214,7 +214,7 @@ public struct MSG_GetBranchPoints_Request /// The path to the process /// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] - public string processName; + public string processPath; /// /// The path to the module hosting the emthod diff --git a/main/OpenCover.Framework/Filter.cs b/main/OpenCover.Framework/Filter.cs index 949c021a9..129c5eb80 100644 --- a/main/OpenCover.Framework/Filter.cs +++ b/main/OpenCover.Framework/Filter.cs @@ -53,16 +53,21 @@ public Filter(bool useRegexFilters = false) /// Decides whether an assembly should be included in the instrumentation /// /// The path-name of the process being profiled - /// the name of the assembly under profile + /// The path-name of the assembly under profile /// All assemblies matching either the inclusion or exclusion filter should be included /// as it is the class that is being filtered within these unless the class filter is * - public bool UseAssembly(string processPath, string assemblyName) + public bool UseAssembly(string processPath, string assemblyPath) { var processName = string.Empty; if (processPath.IndexOfAny(Path.GetInvalidPathChars()) < 0) { // avoids ArgumentException processName = Path.GetFileNameWithoutExtension(processPath); } - var matchingExclusionFilters = ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName); + var assemblyName = string.Empty; + if (assemblyPath.IndexOfAny(Path.GetInvalidPathChars()) < 0) { // avoids ArgumentException + assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); + } + var matchingExclusionFilters = ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyPath); + if (!string.IsNullOrEmpty(assemblyName) && assemblyName != assemblyPath) { matchingExclusionFilters.AddRange (ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName)); } if (matchingExclusionFilters.Any(exclusionFilter => exclusionFilter.ClassName == ".*" && ((!string.IsNullOrEmpty(processName) && exclusionFilter.IsMatchingProcessName(processName)) || exclusionFilter.IsMatchingProcessName(processPath)))) { return false; @@ -73,7 +78,8 @@ public bool UseAssembly(string processPath, string assemblyName) return true; } - var matchingInclusionFilters = InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName); + var matchingInclusionFilters = InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyPath); + if (!string.IsNullOrEmpty(assemblyName) && assemblyName != assemblyPath) { matchingInclusionFilters.AddRange (InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName)); } if (matchingInclusionFilters.Any()) { return true; @@ -86,21 +92,26 @@ public bool UseAssembly(string processPath, string assemblyName) /// Determine if an [assemblyname]classname pair matches the current Exclusion or Inclusion filters /// /// The path-name of the process - /// the name of the assembly under profile + /// the name of the assembly under profile /// the name of the class under profile /// false - if pair matches the exclusion filter or matches no filters, true - if pair matches in the inclusion filter - public bool InstrumentClass(string processPath, string assemblyName, string className) + public bool InstrumentClass(string processPath, string assemblyPath, string className) { - if (string.IsNullOrEmpty(processPath) || string.IsNullOrEmpty(assemblyName) || string.IsNullOrEmpty(className)) + if (string.IsNullOrEmpty(processPath) || string.IsNullOrEmpty(assemblyPath) || string.IsNullOrEmpty(className)) { return false; } var processName = string.Empty; if (processPath.IndexOfAny(Path.GetInvalidPathChars()) < 0) { // avoids ArgumentException - processName = Path.GetFileNameWithoutExtension(processPath); + processName = Path.GetFileNameWithoutExtension(processPath); // can return null } - var matchingExclusionFilters = ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName); + var assemblyName = string.Empty; + if (assemblyPath.IndexOfAny(Path.GetInvalidPathChars()) < 0) { // avoids ArgumentException + assemblyName = Path.GetFileNameWithoutExtension(assemblyPath); // can return null + } + var matchingExclusionFilters = ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyPath); + if (!string.IsNullOrEmpty(assemblyName) && assemblyName != assemblyPath) { matchingExclusionFilters.AddRange (ExclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName)); } if (matchingExclusionFilters.Any(exclusionFilter => exclusionFilter.ClassName == ".*" && ((!string.IsNullOrEmpty(processName) && exclusionFilter.IsMatchingProcessName(processName)) || exclusionFilter.IsMatchingProcessName(processPath)))) { return false; @@ -113,7 +124,8 @@ public bool InstrumentClass(string processPath, string assemblyName, string clas return false; } - var matchingInclusionFilters = InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName); + var matchingInclusionFilters = InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyPath); + if (!string.IsNullOrEmpty(assemblyName) && assemblyName != assemblyPath) { matchingInclusionFilters.AddRange (InclusionFilters.GetMatchingFiltersForAssemblyName(assemblyName)); } if (matchingInclusionFilters.Any(inclusionFilter => inclusionFilter.IsMatchingClassName(className))) { return true; @@ -126,38 +138,38 @@ public bool InstrumentClass(string processPath, string assemblyName, string clas /// /// Determine if an [assemblyname]classname pair matches the current Exclusion or Inclusion filters /// - /// the name of the assembly under profile - /// the name of the class under profile + /// The path-name of the assembly under profile + /// The name of the class under profile /// false - if pair matches the exclusion filter or matches no filters, true - if pair matches in the inclusion filter - public bool InstrumentClass(string assemblyName, string className) + public bool InstrumentClass(string assemblyPath, string className) { - return InstrumentClass(Guid.NewGuid().ToString(), assemblyName, className); + return InstrumentClass(Guid.NewGuid().ToString(), assemblyPath, className); } /// /// Add a filter /// - /// A filter is of the format (+ or -)[assemblyName]className, wildcards are allowed.
+ /// Filter is of the format (+ or -)<processFilter>[assemblyFilter]classFilter, wildcards are allowed.
/// i.e. -[mscorlib], -[System.*]*, +[App.*]*, +[*]* /// - public void AddFilter(string assemblyClassName) + public void AddFilter(string processAssemblyClassFilter) { - string assemblyName; - string className; - string processName; + string _assemblyFilter; + string _classFilter; + string _processFilter; FilterType filterType; - GetAssemblyClassName(assemblyClassName, RegExFilters, out filterType, out assemblyName, out className, out processName); + GetAssemblyClassName(processAssemblyClassFilter, RegExFilters, out filterType, out _assemblyFilter, out _classFilter, out _processFilter); try { if (!RegExFilters) { - processName = (string.IsNullOrEmpty(processName) ? "*" : processName).ValidateAndEscape("<>|\""); // Path.GetInvalidPathChars except *? - assemblyName = assemblyName.ValidateAndEscape(); - className = className.ValidateAndEscape(); + _processFilter = (string.IsNullOrEmpty(_processFilter) ? "*" : _processFilter).ValidateAndEscape("<>|\""); // Path.GetInvalidPathChars except *? + _assemblyFilter = _assemblyFilter.ValidateAndEscape(); + _classFilter = _classFilter.ValidateAndEscape(); } - var filter = new AssemblyAndClassFilter(processName, assemblyName, className); + var filter = new AssemblyAndClassFilter(_processFilter, _assemblyFilter, _classFilter); if (filterType == FilterType.Inclusion) InclusionFilters.Add(filter); @@ -166,34 +178,34 @@ public void AddFilter(string assemblyClassName) } catch (Exception) { - HandleInvalidFilterFormat(assemblyClassName); + HandleInvalidFilterFormat(processAssemblyClassFilter); } } - private static void GetAssemblyClassName(string assemblyClassName, bool useRegEx, out FilterType filterType, out string assemblyName, out string className, out string processName) + private static void GetAssemblyClassName(string processAssemblyClassFilter, bool useRegEx, out FilterType filterType, out string assemblyFilter, out string classFilter, out string processFilter) { - className = string.Empty; - assemblyName = string.Empty; - processName = string.Empty; + classFilter = string.Empty; + assemblyFilter = string.Empty; + processFilter = string.Empty; filterType = FilterType.Inclusion; var regEx = new Regex(@"^(?([+-]))(<(?(.+))>)?(\[(?(.+))\])(?(.+))$"); if (useRegEx) regEx = new Regex(@"^(?([+-]))(<\((?(.+))\)>)?(\[\((?(.+))\)\])(\((?(.+))\))$"); - var match = regEx.Match(assemblyClassName); + var match = regEx.Match(processAssemblyClassFilter); if (match.Success) { filterType = match.Groups["type"].Value.ParseFilterType(); - assemblyName = match.Groups["assembly"].Value; - className = match.Groups["class"].Value; - processName = match.Groups["process"].Value; + assemblyFilter = match.Groups["assembly"].Value; + classFilter = match.Groups["class"].Value; + processFilter = match.Groups["process"].Value; - if (string.IsNullOrWhiteSpace(assemblyName)) - HandleInvalidFilterFormat(assemblyClassName); + if (string.IsNullOrWhiteSpace(assemblyFilter)) + HandleInvalidFilterFormat(processAssemblyClassFilter); } else { - HandleInvalidFilterFormat(assemblyClassName); + HandleInvalidFilterFormat(processAssemblyClassFilter); } } @@ -355,7 +367,7 @@ public bool InstrumentProcess(string processPath) processName = Path.GetFileNameWithoutExtension(processPath); } if (ExclusionFilters.Any()) { - var matchingExclusionFilters = new List(ExclusionFilters.GetMatchingFiltersForProcessName(processPath)); + var matchingExclusionFilters = ExclusionFilters.GetMatchingFiltersForProcessName(processPath); if (!string.IsNullOrWhiteSpace (processName) && processName != processPath) { matchingExclusionFilters.AddRange(ExclusionFilters.GetMatchingFiltersForProcessName(processName)); } @@ -371,7 +383,7 @@ public bool InstrumentProcess(string processPath) } if (InclusionFilters.Any()) { - var matchingInclusionFilters = new List(InclusionFilters.GetMatchingFiltersForProcessName(processPath)); + var matchingInclusionFilters = InclusionFilters.GetMatchingFiltersForProcessName(processPath); if (!string.IsNullOrWhiteSpace (processName) && processName != processPath) { matchingInclusionFilters.AddRange(InclusionFilters.GetMatchingFiltersForProcessName(processName)); } diff --git a/main/OpenCover.Framework/Filtering/AssemblyAndClassFilter.cs b/main/OpenCover.Framework/Filtering/AssemblyAndClassFilter.cs index 78101c217..8b473682a 100644 --- a/main/OpenCover.Framework/Filtering/AssemblyAndClassFilter.cs +++ b/main/OpenCover.Framework/Filtering/AssemblyAndClassFilter.cs @@ -7,38 +7,38 @@ namespace OpenCover.Framework.Filtering { internal class AssemblyAndClassFilter { - private readonly RegexFilter _processNameFilter; + private readonly RegexFilter _processFilter; - private readonly RegexFilter _assemblyNameFilter; + private readonly RegexFilter _assemblyFilter; - private readonly RegexFilter _classNameFilter; + private readonly RegexFilter _classFilter; - internal string ProcessName { get { return _processNameFilter.FilterExpression; } } + internal string ProcessName { get { return _processFilter.FilterExpression; } } - internal string AssemblyName { get { return _assemblyNameFilter.FilterExpression; } } + internal string AssemblyName { get { return _assemblyFilter.FilterExpression; } } - internal string ClassName { get { return _classNameFilter.FilterExpression; } } + internal string ClassName { get { return _classFilter.FilterExpression; } } - internal AssemblyAndClassFilter(string processName, string assemblyName, string className) + internal AssemblyAndClassFilter(string processFilter, string assemblyFilter, string classFilter) { - _processNameFilter = new RegexFilter(processName); - _assemblyNameFilter = new RegexFilter(assemblyName); - _classNameFilter = new RegexFilter(className); + _processFilter = new RegexFilter(processFilter); + _assemblyFilter = new RegexFilter(assemblyFilter); + _classFilter = new RegexFilter(classFilter); } - internal bool IsMatchingProcessName(string processName) + internal bool IsMatchingProcessName(string processPathOrName) { - return _processNameFilter.IsMatchingExpression(processName); + return _processFilter.IsMatchingExpression(processPathOrName); } - internal bool IsMatchingAssemblyName(string assemblyName) + internal bool IsMatchingAssemblyName(string assemblyPathOrName) { - return _assemblyNameFilter.IsMatchingExpression(assemblyName); + return _assemblyFilter.IsMatchingExpression(assemblyPathOrName); } internal bool IsMatchingClassName(string className) { - return _classNameFilter.IsMatchingExpression(className); + return _classFilter.IsMatchingExpression(className); } } diff --git a/main/OpenCover.Framework/Filtering/FilterHelper.cs b/main/OpenCover.Framework/Filtering/FilterHelper.cs index 12a3809e5..c0c80d49b 100644 --- a/main/OpenCover.Framework/Filtering/FilterHelper.cs +++ b/main/OpenCover.Framework/Filtering/FilterHelper.cs @@ -34,6 +34,15 @@ internal static IList GetMatchingFiltersForProcessName(t return matchingFilters; } + internal static void AddRange (this ICollection collection, IEnumerable range) { + if (collection != null && range != null) { + foreach (var item in range) + { + collection.Add(item); + } + } + } + internal static void AddFilters(this ICollection target, IEnumerable filters, bool isRegexFilter) { if (filters == null) diff --git a/main/OpenCover.Framework/IFilter.cs b/main/OpenCover.Framework/IFilter.cs index af676813f..e066df406 100644 --- a/main/OpenCover.Framework/IFilter.cs +++ b/main/OpenCover.Framework/IFilter.cs @@ -18,11 +18,11 @@ public interface IFilter /// /// Decides whether an assembly should be included in the instrumentation /// - /// The name of the process being profiled - /// the name of the assembly under profile + /// The name of the process being profiled + /// the name of the assembly under profile /// All assemblies matching either the inclusion or exclusion filter should be included /// as it is the class that is being filtered within these unless the class filter is * - bool UseAssembly(string processName, string assemblyName); + bool UseAssembly(string processPath, string assemblyPath); /// /// Decides whether an assembly should be analysed for test methods @@ -40,19 +40,19 @@ public interface IFilter /// /// Determine if an [assemblyname]classname pair matches the current Exclusion or Inclusion filters /// - /// the name of the assembly under profile + /// the name of the assembly under profile /// the name of the class under profile /// false - if pair matches the exclusion filter or matches no filters, true - if pair matches in the inclusion filter - bool InstrumentClass(string assemblyName, string className); + bool InstrumentClass(string assemblyPath, string className); /// /// Determine if an [assemblyname]classname pair matches the current Exclusion or Inclusion filters /// - /// The name of the process - /// the name of the assembly under profile + /// The path-name of the process + /// The path-name of the assembly under profile /// the name of the class under profile /// false - if pair matches the exclusion filter or matches no filters, true - if pair matches in the inclusion filter - bool InstrumentClass(string processName, string assemblyName, string className); + bool InstrumentClass(string processPath, string assemblyPath, string className); /// @@ -101,11 +101,11 @@ public interface IFilter bool RegExFilters { get; } /// - /// Should we instrument this asssembly + /// Should we instrument this process /// - /// + /// /// - bool InstrumentProcess(string processName); + bool InstrumentProcess(string processPath); } } diff --git a/main/OpenCover.Framework/Service/ProfilerCommunication.cs b/main/OpenCover.Framework/Service/ProfilerCommunication.cs index e8f01d189..21a367242 100644 --- a/main/OpenCover.Framework/Service/ProfilerCommunication.cs +++ b/main/OpenCover.Framework/Service/ProfilerCommunication.cs @@ -4,12 +4,9 @@ // This source code is released under the MIT License; see the accompanying license file. // using System; -using System.Diagnostics; using System.Linq; -using Mono.Cecil; using OpenCover.Framework.Model; using OpenCover.Framework.Persistance; -using OpenCover.Framework.Symbols; namespace OpenCover.Framework.Service { @@ -28,12 +25,14 @@ public ProfilerCommunication(IFilter filter, _instrumentationModelBuilderFactory = instrumentationModelBuilderFactory; } - public bool TrackAssembly(string processName, string modulePath, string assemblyName) + public bool TrackAssembly(string processPath, string modulePath, string assemblyName) { if (_persistance.IsTracking(modulePath)) return true; Module module = null; var builder = _instrumentationModelBuilderFactory.CreateModelBuilder(modulePath, assemblyName); - if (!_filter.UseAssembly(processName, assemblyName)) + var assemblyPath = assemblyName; + if (modulePath.Contains (assemblyName)) { assemblyPath = modulePath; } + if (!_filter.UseAssembly(processPath, assemblyPath)) { module = builder.BuildModuleModel(false); module.MarkAsSkipped(SkippedMethod.Filter); diff --git a/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs b/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs index 5504fc9b0..b9b61d16e 100644 --- a/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs +++ b/main/OpenCover.Framework/Symbols/CecilSymbolManager.cs @@ -15,6 +15,7 @@ using OpenCover.Framework.Model; using OpenCover.Framework.Strategy; using log4net; +using OpenCover.Framework.Utility; using File = OpenCover.Framework.Model.File; using SequencePoint = OpenCover.Framework.Model.SequencePoint; @@ -181,18 +182,21 @@ public Class[] GetInstrumentableTypes() if (SourceAssembly == null) return new Class[0]; var classes = new List(); IEnumerable typeDefinitions = SourceAssembly.MainModule.Types; - GetInstrumentableTypes(typeDefinitions, classes, _filter, ModuleName); + + var assemblyPath = ModuleName; + if (ModulePath.Contains (assemblyPath)) { assemblyPath = ModulePath; } + GetInstrumentableTypes(typeDefinitions, classes, _filter, assemblyPath); return classes.ToArray(); } - private static void GetInstrumentableTypes(IEnumerable typeDefinitions, List classes, IFilter filter, string moduleName) + private static void GetInstrumentableTypes(IEnumerable typeDefinitions, List classes, IFilter filter, string assemblyPath) { foreach (var typeDefinition in typeDefinitions) { if (typeDefinition.IsEnum) continue; if (typeDefinition.IsInterface && typeDefinition.IsAbstract) continue; var @class = new Class { FullName = typeDefinition.FullName }; - if (!filter.InstrumentClass(moduleName, @class.FullName)) + if (!filter.InstrumentClass(assemblyPath, @class.FullName)) { @class.MarkAsSkipped(SkippedMethod.Filter); } @@ -220,7 +224,7 @@ from instruction in methodDefinition.Body.Instructions classes.Add(@class); } if (typeDefinition.HasNestedTypes) - GetInstrumentableTypes(typeDefinition.NestedTypes, classes, filter, moduleName); + GetInstrumentableTypes(typeDefinition.NestedTypes, classes, filter, assemblyPath); } } diff --git a/main/OpenCover.Test/Framework/FilterTests.cs b/main/OpenCover.Test/Framework/FilterTests.cs index 1a02c3a21..ccc9e0f50 100644 --- a/main/OpenCover.Test/Framework/FilterTests.cs +++ b/main/OpenCover.Test/Framework/FilterTests.cs @@ -341,7 +341,7 @@ public class InstrumentClassData public void InstrumentClass_Tests( [ValueSource("_instrumentClassData")]InstrumentClassData data) { - //// arrange + // arrange var filter = new Filter(); data.Filters.ForEach(filter.AddFilter);