Increase severity of some rules and fix instances (#1305)
Increase severity of some rules and fix instances
This commit is contained in:
@@ -87,6 +87,20 @@ dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:warning
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
# CA1805: Do not initialize unnecessarily
|
||||
dotnet_diagnostic.CA1805.severity = warning
|
||||
# IDE0063: Use simple 'using' statement
|
||||
dotnet_diagnostic.IDE0063.severity = warning
|
||||
# IDE0057: Use range operator
|
||||
dotnet_diagnostic.IDE0057.severity = warning
|
||||
# IDE0075: Simplify conditional expression
|
||||
dotnet_diagnostic.IDE0075.severity = warning
|
||||
# IDE0071: Simplify interpolation
|
||||
dotnet_diagnostic.IDE0071.severity = warning
|
||||
# CA1829: Use Length/Count property instead of Count() when available
|
||||
dotnet_diagnostic.CA1829.severity = warning
|
||||
# CA1827: Do not use Count() or LongCount() when Any() can be used
|
||||
dotnet_diagnostic.CA1827.severity = warning
|
||||
###############################
|
||||
# Naming Conventions #
|
||||
###############################
|
||||
@@ -114,6 +128,10 @@ dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
|
||||
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
|
||||
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
|
||||
# IDE1006: Naming Styles
|
||||
dotnet_diagnostic.IDE1006.severity = warning
|
||||
# IDE0090: Use 'new(...)'
|
||||
dotnet_diagnostic.IDE0090.severity = warning
|
||||
###############################
|
||||
# C# Coding Conventions #
|
||||
###############################
|
||||
|
||||
@@ -163,17 +163,15 @@ namespace Coverlet.Collector.DataCollection
|
||||
// Get coverage reports
|
||||
IEnumerable<(string report, string fileName)> coverageReports = _coverageManager?.GetCoverageReports();
|
||||
|
||||
if (coverageReports != null && coverageReports.Count() > 0)
|
||||
if (coverageReports != null && coverageReports.Any())
|
||||
{
|
||||
// Send result attachments to test platform.
|
||||
using (var attachmentManager = new AttachmentManager(_dataSink, _dataCollectionContext, _logger, _eqtTrace, _countDownEventFactory.Create(coverageReports.Count(), TimeSpan.FromSeconds(30))))
|
||||
{
|
||||
using var attachmentManager = new AttachmentManager(_dataSink, _dataCollectionContext, _logger, _eqtTrace, _countDownEventFactory.Create(coverageReports.Count(), TimeSpan.FromSeconds(30)));
|
||||
foreach ((string report, string fileName) in coverageReports)
|
||||
{
|
||||
attachmentManager.SendCoverageReport(report, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_eqtTrace.Verbose("{0}: No coverage reports specified", CoverletConstants.DataCollectorName);
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="testModules">Test modules</param>
|
||||
/// <returns>Test module</returns>
|
||||
private string ParseTestModule(IEnumerable<string> testModules)
|
||||
private static string ParseTestModule(IEnumerable<string> testModules)
|
||||
{
|
||||
// Validate if at least one source present.
|
||||
if (testModules == null || !testModules.Any())
|
||||
@@ -86,7 +86,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>Report formats</returns>
|
||||
private string[] ParseReportFormats(XmlElement configurationElement)
|
||||
private static string[] ParseReportFormats(XmlElement configurationElement)
|
||||
{
|
||||
string[] formats = Array.Empty<string>();
|
||||
if (configurationElement != null)
|
||||
@@ -103,7 +103,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>Filters to include</returns>
|
||||
private string[] ParseIncludeFilters(XmlElement configurationElement)
|
||||
private static string[] ParseIncludeFilters(XmlElement configurationElement)
|
||||
{
|
||||
XmlElement includeFiltersElement = configurationElement[CoverletConstants.IncludeFiltersElementName];
|
||||
return SplitElement(includeFiltersElement);
|
||||
@@ -114,7 +114,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>Directories to include</returns>
|
||||
private string[] ParseIncludeDirectories(XmlElement configurationElement)
|
||||
private static string[] ParseIncludeDirectories(XmlElement configurationElement)
|
||||
{
|
||||
XmlElement includeDirectoriesElement = configurationElement[CoverletConstants.IncludeDirectoriesElementName];
|
||||
return SplitElement(includeDirectoriesElement);
|
||||
@@ -125,7 +125,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>Filters to exclude</returns>
|
||||
private string[] ParseExcludeFilters(XmlElement configurationElement)
|
||||
private static string[] ParseExcludeFilters(XmlElement configurationElement)
|
||||
{
|
||||
var excludeFilters = new List<string> { CoverletConstants.DefaultExcludeFilter };
|
||||
|
||||
@@ -147,7 +147,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>Source files to exclude</returns>
|
||||
private string[] ParseExcludeSourceFiles(XmlElement configurationElement)
|
||||
private static string[] ParseExcludeSourceFiles(XmlElement configurationElement)
|
||||
{
|
||||
XmlElement excludeSourceFilesElement = configurationElement[CoverletConstants.ExcludeSourceFilesElementName];
|
||||
return SplitElement(excludeSourceFilesElement);
|
||||
@@ -158,7 +158,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>Attributes to exclude</returns>
|
||||
private string[] ParseExcludeAttributes(XmlElement configurationElement)
|
||||
private static string[] ParseExcludeAttributes(XmlElement configurationElement)
|
||||
{
|
||||
XmlElement excludeAttributesElement = configurationElement[CoverletConstants.ExcludeAttributesElementName];
|
||||
return SplitElement(excludeAttributesElement);
|
||||
@@ -169,7 +169,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>Merge with attribute</returns>
|
||||
private string ParseMergeWith(XmlElement configurationElement)
|
||||
private static string ParseMergeWith(XmlElement configurationElement)
|
||||
{
|
||||
XmlElement mergeWithElement = configurationElement[CoverletConstants.MergeWithElementName];
|
||||
return mergeWithElement?.InnerText;
|
||||
@@ -180,7 +180,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>Use source link flag</returns>
|
||||
private bool ParseUseSourceLink(XmlElement configurationElement)
|
||||
private static bool ParseUseSourceLink(XmlElement configurationElement)
|
||||
{
|
||||
XmlElement useSourceLinkElement = configurationElement[CoverletConstants.UseSourceLinkElementName];
|
||||
bool.TryParse(useSourceLinkElement?.InnerText, out bool useSourceLink);
|
||||
@@ -192,7 +192,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>Single hit flag</returns>
|
||||
private bool ParseSingleHit(XmlElement configurationElement)
|
||||
private static bool ParseSingleHit(XmlElement configurationElement)
|
||||
{
|
||||
XmlElement singleHitElement = configurationElement[CoverletConstants.SingleHitElementName];
|
||||
bool.TryParse(singleHitElement?.InnerText, out bool singleHit);
|
||||
@@ -204,7 +204,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>ParseDeterministicReport flag</returns>
|
||||
private bool ParseDeterministicReport(XmlElement configurationElement)
|
||||
private static bool ParseDeterministicReport(XmlElement configurationElement)
|
||||
{
|
||||
XmlElement deterministicReportElement = configurationElement[CoverletConstants.DeterministicReport];
|
||||
bool.TryParse(deterministicReportElement?.InnerText, out bool deterministicReport);
|
||||
@@ -216,7 +216,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>Include Test Assembly Flag</returns>
|
||||
private bool ParseIncludeTestAssembly(XmlElement configurationElement)
|
||||
private static bool ParseIncludeTestAssembly(XmlElement configurationElement)
|
||||
{
|
||||
XmlElement includeTestAssemblyElement = configurationElement[CoverletConstants.IncludeTestAssemblyElementName];
|
||||
bool.TryParse(includeTestAssemblyElement?.InnerText, out bool includeTestAssembly);
|
||||
@@ -228,7 +228,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>Include Test Assembly Flag</returns>
|
||||
private bool ParseSkipAutoProps(XmlElement configurationElement)
|
||||
private static bool ParseSkipAutoProps(XmlElement configurationElement)
|
||||
{
|
||||
XmlElement skipAutoPropsElement = configurationElement[CoverletConstants.SkipAutoProps];
|
||||
bool.TryParse(skipAutoPropsElement?.InnerText, out bool skipAutoProps);
|
||||
@@ -240,7 +240,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="configurationElement">Configuration element</param>
|
||||
/// <returns>DoesNotReturn attributes</returns>
|
||||
private string[] ParseDoesNotReturnAttributes(XmlElement configurationElement)
|
||||
private static string[] ParseDoesNotReturnAttributes(XmlElement configurationElement)
|
||||
{
|
||||
XmlElement doesNotReturnAttributesElement = configurationElement[CoverletConstants.DoesNotReturnAttributesElementName];
|
||||
return SplitElement(doesNotReturnAttributesElement);
|
||||
@@ -251,7 +251,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </summary>
|
||||
/// <param name="element">The element to split</param>
|
||||
/// <returns>An array of the values in the element</returns>
|
||||
private string[] SplitElement(XmlElement element)
|
||||
private static string[] SplitElement(XmlElement element)
|
||||
{
|
||||
return element?.InnerText?.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Where(value => !string.IsNullOrWhiteSpace(value)).Select(value => value.Trim()).ToArray();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Coverlet.Collector.DataCollection
|
||||
public class CoverletInProcDataCollector : InProcDataCollection
|
||||
{
|
||||
private TestPlatformEqtTrace _eqtTrace;
|
||||
private bool _enableExceptionLog = false;
|
||||
private bool _enableExceptionLog;
|
||||
|
||||
private void AttachDebugger()
|
||||
{
|
||||
|
||||
@@ -9,7 +9,8 @@ namespace Coverlet.Console.Logging
|
||||
{
|
||||
class ConsoleLogger : ILogger
|
||||
{
|
||||
private static readonly object _sync = new object();
|
||||
private static readonly object s_sync = new();
|
||||
|
||||
public LogLevel Level { get; set; } = LogLevel.Normal;
|
||||
|
||||
public void LogError(string message) => Log(LogLevel.Quiet, message, ConsoleColor.Red);
|
||||
@@ -26,7 +27,7 @@ namespace Coverlet.Console.Logging
|
||||
{
|
||||
if (level < Level) return;
|
||||
|
||||
lock (_sync)
|
||||
lock (s_sync)
|
||||
{
|
||||
ConsoleColor currentForegroundColor;
|
||||
if (color != (currentForegroundColor = ForegroundColor))
|
||||
|
||||
@@ -330,7 +330,7 @@ namespace Coverlet.Core
|
||||
return false;
|
||||
}
|
||||
|
||||
private Method GetMethodWithSameLineInSameDocument(Classes documentClasses, string compilerGeneratedClassName, int branchLine)
|
||||
private static Method GetMethodWithSameLineInSameDocument(Classes documentClasses, string compilerGeneratedClassName, int branchLine)
|
||||
{
|
||||
foreach (KeyValuePair<string, Methods> @class in documentClasses)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Coverlet.Core.Helpers
|
||||
internal class InstrumentationHelper : IInstrumentationHelper
|
||||
{
|
||||
private const int RetryAttempts = 12;
|
||||
private readonly ConcurrentDictionary<string, string> _backupList = new ConcurrentDictionary<string, string>();
|
||||
private readonly ConcurrentDictionary<string, string> _backupList = new();
|
||||
private readonly IRetryHelper _retryHelper;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ISourceRootTranslator _sourceRootTranslator;
|
||||
@@ -83,9 +83,8 @@ namespace Coverlet.Core.Helpers
|
||||
public bool HasPdb(string module, out bool embedded)
|
||||
{
|
||||
embedded = false;
|
||||
using (Stream moduleStream = _fileSystem.OpenRead(module))
|
||||
using (var peReader = new PEReader(moduleStream))
|
||||
{
|
||||
using Stream moduleStream = _fileSystem.OpenRead(module);
|
||||
using var peReader = new PEReader(moduleStream);
|
||||
foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory())
|
||||
{
|
||||
if (entry.Type == DebugDirectoryEntryType.CodeView)
|
||||
@@ -104,7 +103,6 @@ namespace Coverlet.Core.Helpers
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool EmbeddedPortablePdbHasLocalSource(string module, out string firstNotFoundDocument)
|
||||
{
|
||||
@@ -116,8 +114,7 @@ namespace Coverlet.Core.Helpers
|
||||
{
|
||||
if (entry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb)
|
||||
{
|
||||
using (MetadataReaderProvider embeddedMetadataProvider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(entry))
|
||||
{
|
||||
using MetadataReaderProvider embeddedMetadataProvider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(entry);
|
||||
MetadataReader metadataReader = embeddedMetadataProvider.GetMetadataReader();
|
||||
|
||||
(bool allDocumentsMatch, string notFoundDocument) = MatchDocumentsWithSources(metadataReader);
|
||||
@@ -130,7 +127,6 @@ namespace Coverlet.Core.Helpers
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have EmbeddedPortablePdb entry return true, for instance empty dll
|
||||
// We should call this method only on embedded pdb module
|
||||
@@ -388,7 +384,7 @@ namespace Coverlet.Core.Helpers
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private bool IsTypeFilterMatch(string module, string type, string[] filters)
|
||||
private static bool IsTypeFilterMatch(string module, string type, string[] filters)
|
||||
{
|
||||
Debug.Assert(module != null);
|
||||
Debug.Assert(filters != null);
|
||||
@@ -408,7 +404,7 @@ namespace Coverlet.Core.Helpers
|
||||
return false;
|
||||
}
|
||||
|
||||
private string GetBackupPath(string module, string identifier)
|
||||
private static string GetBackupPath(string module, string identifier)
|
||||
{
|
||||
return Path.Combine(
|
||||
Path.GetTempPath(),
|
||||
@@ -428,14 +424,14 @@ namespace Coverlet.Core.Helpers
|
||||
return retryStrategy;
|
||||
}
|
||||
|
||||
private string WildcardToRegex(string pattern)
|
||||
private static string WildcardToRegex(string pattern)
|
||||
{
|
||||
return "^" + Regex.Escape(pattern).
|
||||
Replace("\\*", ".*").
|
||||
Replace("\\?", "?") + "$";
|
||||
}
|
||||
|
||||
private bool IsAssembly(string filePath)
|
||||
private static bool IsAssembly(string filePath)
|
||||
{
|
||||
Debug.Assert(filePath != null);
|
||||
|
||||
@@ -453,7 +449,7 @@ namespace Coverlet.Core.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsUnknownModuleInFSharpAssembly(Guid languageGuid, string docName)
|
||||
private static bool IsUnknownModuleInFSharpAssembly(Guid languageGuid, string docName)
|
||||
{
|
||||
// https://github.com/dotnet/runtime/blob/main/docs/design/specs/PortablePdb-Metadata.md#document-table-0x30
|
||||
return languageGuid.Equals(new Guid("ab4f38c9-b6e6-43ba-be3b-58080b2ccce3"))
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Coverlet.Core.Helpers
|
||||
_sourceToDeterministicPathMapping = LoadSourceToDeterministicPathMapping(_sourceRootMapping);
|
||||
}
|
||||
|
||||
private Dictionary<string, List<string>> LoadSourceToDeterministicPathMapping(Dictionary<string, List<SourceRootMapping>> sourceRootMapping)
|
||||
private static Dictionary<string, List<string>> LoadSourceToDeterministicPathMapping(Dictionary<string, List<SourceRootMapping>> sourceRootMapping)
|
||||
{
|
||||
if (sourceRootMapping is null)
|
||||
{
|
||||
|
||||
@@ -39,10 +39,10 @@ namespace Coverlet.Core.Instrumentation
|
||||
/// </summary>
|
||||
internal class NetstandardAwareAssemblyResolver : DefaultAssemblyResolver
|
||||
{
|
||||
private static readonly System.Reflection.Assembly _netStandardAssembly;
|
||||
private static readonly string _name;
|
||||
private static readonly byte[] _publicKeyToken;
|
||||
private static readonly AssemblyDefinition _assemblyDefinition;
|
||||
private static readonly System.Reflection.Assembly s_netStandardAssembly;
|
||||
private static readonly string s_name;
|
||||
private static readonly byte[] s_publicKeyToken;
|
||||
private static readonly AssemblyDefinition s_assemblyDefinition;
|
||||
|
||||
private readonly string _modulePath;
|
||||
private readonly Lazy<CompositeCompilationAssemblyResolver> _compositeResolver;
|
||||
@@ -53,11 +53,11 @@ namespace Coverlet.Core.Instrumentation
|
||||
try
|
||||
{
|
||||
// To be sure to load information of "real" runtime netstandard implementation
|
||||
_netStandardAssembly = System.Reflection.Assembly.LoadFile(Path.Combine(Path.GetDirectoryName(typeof(object).Assembly.Location), "netstandard.dll"));
|
||||
System.Reflection.AssemblyName name = _netStandardAssembly.GetName();
|
||||
_name = name.Name;
|
||||
_publicKeyToken = name.GetPublicKeyToken();
|
||||
_assemblyDefinition = AssemblyDefinition.ReadAssembly(_netStandardAssembly.Location);
|
||||
s_netStandardAssembly = System.Reflection.Assembly.LoadFile(Path.Combine(Path.GetDirectoryName(typeof(object).Assembly.Location), "netstandard.dll"));
|
||||
System.Reflection.AssemblyName name = s_netStandardAssembly.GetName();
|
||||
s_name = name.Name;
|
||||
s_publicKeyToken = name.GetPublicKeyToken();
|
||||
s_assemblyDefinition = AssemblyDefinition.ReadAssembly(s_netStandardAssembly.Location);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
@@ -82,26 +82,26 @@ namespace Coverlet.Core.Instrumentation
|
||||
}
|
||||
|
||||
// Check name and public key but not version that could be different
|
||||
private bool CheckIfSearchingNetstandard(AssemblyNameReference name)
|
||||
private static bool CheckIfSearchingNetstandard(AssemblyNameReference name)
|
||||
{
|
||||
if (_netStandardAssembly is null)
|
||||
if (s_netStandardAssembly is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_name != name.Name)
|
||||
if (s_name != name.Name)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (name.PublicKeyToken.Length != _publicKeyToken.Length)
|
||||
if (name.PublicKeyToken.Length != s_publicKeyToken.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < name.PublicKeyToken.Length; i++)
|
||||
{
|
||||
if (_publicKeyToken[i] != name.PublicKeyToken[i])
|
||||
if (s_publicKeyToken[i] != name.PublicKeyToken[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -114,7 +114,7 @@ namespace Coverlet.Core.Instrumentation
|
||||
{
|
||||
if (CheckIfSearchingNetstandard(name))
|
||||
{
|
||||
return _assemblyDefinition;
|
||||
return s_assemblyDefinition;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -136,7 +136,7 @@ namespace Coverlet.Core.Instrumentation
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsDotNetCore()
|
||||
private static bool IsDotNetCore()
|
||||
{
|
||||
// object for .NET Framework is inside mscorlib.dll
|
||||
return Path.GetFileName(typeof(object).Assembly.Location) == "System.Private.CoreLib.dll";
|
||||
@@ -202,7 +202,7 @@ namespace Coverlet.Core.Instrumentation
|
||||
catch (Exception ex)
|
||||
{
|
||||
// if we don't find a lib go on
|
||||
_logger.LogVerbose($"TryWithCustomResolverOnDotNetCore exception: {ex.ToString()}");
|
||||
_logger.LogVerbose($"TryWithCustomResolverOnDotNetCore exception: {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,8 +218,8 @@ namespace Coverlet.Core.Instrumentation
|
||||
|
||||
internal class AspNetCoreSharedFrameworkResolver : ICompilationAssemblyResolver
|
||||
{
|
||||
private readonly string[] _aspNetSharedFrameworkDirs = null;
|
||||
private readonly ILogger _logger = null;
|
||||
private readonly string[] _aspNetSharedFrameworkDirs;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public AspNetCoreSharedFrameworkResolver(ILogger logger)
|
||||
{
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Coverlet.Core.Instrumentation
|
||||
private readonly string[] _doesNotReturnAttributes;
|
||||
private ReachabilityHelper _reachabilityHelper;
|
||||
|
||||
public bool SkipModule { get; set; } = false;
|
||||
public bool SkipModule { get; set; }
|
||||
|
||||
public Instrumenter(
|
||||
string module,
|
||||
@@ -185,9 +185,8 @@ namespace Coverlet.Core.Instrumentation
|
||||
// locking issues if we do it while writing.
|
||||
private void CreateReachabilityHelper()
|
||||
{
|
||||
using (Stream stream = _fileSystem.NewFileStream(_module, FileMode.Open, FileAccess.Read))
|
||||
using (var resolver = new NetstandardAwareAssemblyResolver(_module, _logger))
|
||||
{
|
||||
using Stream stream = _fileSystem.NewFileStream(_module, FileMode.Open, FileAccess.Read);
|
||||
using var resolver = new NetstandardAwareAssemblyResolver(_module, _logger);
|
||||
resolver.AddSearchDirectory(Path.GetDirectoryName(_module));
|
||||
var parameters = new ReaderParameters { ReadSymbols = true, AssemblyResolver = resolver };
|
||||
if (_isCoreLibrary)
|
||||
@@ -195,20 +194,16 @@ namespace Coverlet.Core.Instrumentation
|
||||
parameters.MetadataImporterProvider = new CoreLibMetadataImporterProvider();
|
||||
}
|
||||
|
||||
using (var module = ModuleDefinition.ReadModule(stream, parameters))
|
||||
{
|
||||
using var module = ModuleDefinition.ReadModule(stream, parameters);
|
||||
_reachabilityHelper = ReachabilityHelper.CreateForModule(module, _doesNotReturnAttributes, _logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InstrumentModule()
|
||||
{
|
||||
CreateReachabilityHelper();
|
||||
|
||||
using (Stream stream = _fileSystem.NewFileStream(_module, FileMode.Open, FileAccess.ReadWrite))
|
||||
using (var resolver = new NetstandardAwareAssemblyResolver(_module, _logger))
|
||||
{
|
||||
using Stream stream = _fileSystem.NewFileStream(_module, FileMode.Open, FileAccess.ReadWrite);
|
||||
using var resolver = new NetstandardAwareAssemblyResolver(_module, _logger);
|
||||
resolver.AddSearchDirectory(Path.GetDirectoryName(_module));
|
||||
var parameters = new ReaderParameters { ReadSymbols = true, AssemblyResolver = resolver };
|
||||
if (_isCoreLibrary)
|
||||
@@ -216,8 +211,7 @@ namespace Coverlet.Core.Instrumentation
|
||||
parameters.MetadataImporterProvider = new CoreLibMetadataImporterProvider();
|
||||
}
|
||||
|
||||
using (var module = ModuleDefinition.ReadModule(stream, parameters))
|
||||
{
|
||||
using var module = ModuleDefinition.ReadModule(stream, parameters);
|
||||
foreach (CustomAttribute customAttribute in module.Assembly.CustomAttributes)
|
||||
{
|
||||
if (IsExcludeAttribute(customAttribute))
|
||||
@@ -336,8 +330,6 @@ namespace Coverlet.Core.Instrumentation
|
||||
|
||||
module.Write(stream, new WriterParameters { WriteSymbols = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCustomModuleTrackerToModule(ModuleDefinition module)
|
||||
{
|
||||
@@ -864,52 +856,52 @@ namespace Coverlet.Core.Instrumentation
|
||||
|
||||
private class CoreLibMetadataImporter : IMetadataImporter
|
||||
{
|
||||
private readonly ModuleDefinition module;
|
||||
private readonly DefaultMetadataImporter defaultMetadataImporter;
|
||||
private readonly ModuleDefinition _module;
|
||||
private readonly DefaultMetadataImporter _defaultMetadataImporter;
|
||||
|
||||
public CoreLibMetadataImporter(ModuleDefinition module)
|
||||
{
|
||||
this.module = module;
|
||||
defaultMetadataImporter = new DefaultMetadataImporter(module);
|
||||
_module = module;
|
||||
_defaultMetadataImporter = new DefaultMetadataImporter(module);
|
||||
}
|
||||
|
||||
public AssemblyNameReference ImportReference(AssemblyNameReference reference)
|
||||
{
|
||||
return defaultMetadataImporter.ImportReference(reference);
|
||||
return _defaultMetadataImporter.ImportReference(reference);
|
||||
}
|
||||
|
||||
public TypeReference ImportReference(TypeReference type, IGenericParameterProvider context)
|
||||
{
|
||||
TypeReference importedRef = defaultMetadataImporter.ImportReference(type, context);
|
||||
importedRef.GetElementType().Scope = module.TypeSystem.CoreLibrary;
|
||||
TypeReference importedRef = _defaultMetadataImporter.ImportReference(type, context);
|
||||
importedRef.GetElementType().Scope = _module.TypeSystem.CoreLibrary;
|
||||
return importedRef;
|
||||
}
|
||||
|
||||
public FieldReference ImportReference(FieldReference field, IGenericParameterProvider context)
|
||||
{
|
||||
FieldReference importedRef = defaultMetadataImporter.ImportReference(field, context);
|
||||
importedRef.FieldType.GetElementType().Scope = module.TypeSystem.CoreLibrary;
|
||||
FieldReference importedRef = _defaultMetadataImporter.ImportReference(field, context);
|
||||
importedRef.FieldType.GetElementType().Scope = _module.TypeSystem.CoreLibrary;
|
||||
return importedRef;
|
||||
}
|
||||
|
||||
public MethodReference ImportReference(MethodReference method, IGenericParameterProvider context)
|
||||
{
|
||||
MethodReference importedRef = defaultMetadataImporter.ImportReference(method, context);
|
||||
importedRef.DeclaringType.GetElementType().Scope = module.TypeSystem.CoreLibrary;
|
||||
MethodReference importedRef = _defaultMetadataImporter.ImportReference(method, context);
|
||||
importedRef.DeclaringType.GetElementType().Scope = _module.TypeSystem.CoreLibrary;
|
||||
|
||||
foreach (ParameterDefinition parameter in importedRef.Parameters)
|
||||
{
|
||||
if (parameter.ParameterType.Scope == module.TypeSystem.CoreLibrary)
|
||||
if (parameter.ParameterType.Scope == _module.TypeSystem.CoreLibrary)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
parameter.ParameterType.GetElementType().Scope = module.TypeSystem.CoreLibrary;
|
||||
parameter.ParameterType.GetElementType().Scope = _module.TypeSystem.CoreLibrary;
|
||||
}
|
||||
|
||||
if (importedRef.ReturnType.Scope != module.TypeSystem.CoreLibrary)
|
||||
if (importedRef.ReturnType.Scope != _module.TypeSystem.CoreLibrary)
|
||||
{
|
||||
importedRef.ReturnType.GetElementType().Scope = module.TypeSystem.CoreLibrary;
|
||||
importedRef.ReturnType.GetElementType().Scope = _module.TypeSystem.CoreLibrary;
|
||||
}
|
||||
|
||||
return importedRef;
|
||||
|
||||
@@ -26,8 +26,8 @@ namespace Coverlet.Core.Instrumentation
|
||||
public static int[] HitsArray;
|
||||
public static bool SingleHit;
|
||||
public static bool FlushHitFile;
|
||||
private static readonly bool _enableLog = int.TryParse(Environment.GetEnvironmentVariable("COVERLET_ENABLETRACKERLOG"), out int result) ? result == 1 : false;
|
||||
private static readonly string _sessionId = Guid.NewGuid().ToString();
|
||||
private static readonly bool s_enableLog = int.TryParse(Environment.GetEnvironmentVariable("COVERLET_ENABLETRACKERLOG"), out int result) && result == 1;
|
||||
private static readonly string s_sessionId = Guid.NewGuid().ToString();
|
||||
|
||||
static ModuleTrackerTemplate()
|
||||
{
|
||||
@@ -83,8 +83,7 @@ namespace Coverlet.Core.Instrumentation
|
||||
{
|
||||
// The same module can be unloaded multiple times in the same process via different app domains.
|
||||
// Use a global mutex to ensure no concurrent access.
|
||||
using (var mutex = new Mutex(true, Path.GetFileNameWithoutExtension(HitsFilePath) + "_Mutex", out bool createdNew))
|
||||
{
|
||||
using var mutex = new Mutex(true, Path.GetFileNameWithoutExtension(HitsFilePath) + "_Mutex", out bool createdNew);
|
||||
if (!createdNew)
|
||||
{
|
||||
mutex.WaitOne();
|
||||
@@ -103,16 +102,14 @@ namespace Coverlet.Core.Instrumentation
|
||||
bool failedToCreateNewHitsFile = false;
|
||||
try
|
||||
{
|
||||
using (var fs = new FileStream(HitsFilePath, FileMode.CreateNew))
|
||||
using (var bw = new BinaryWriter(fs))
|
||||
{
|
||||
using var fs = new FileStream(HitsFilePath, FileMode.CreateNew);
|
||||
using var bw = new BinaryWriter(fs);
|
||||
bw.Write(hitsArray.Length);
|
||||
foreach (int hitCount in hitsArray)
|
||||
{
|
||||
bw.Write(hitCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteLog($"Failed to create new hits file '{HitsFilePath}' -> '{ex.Message}'");
|
||||
@@ -123,10 +120,9 @@ namespace Coverlet.Core.Instrumentation
|
||||
{
|
||||
// Update the number of hits by adding value on disk with the ones on memory.
|
||||
// This path should be triggered only in the case of multiple AppDomain unloads.
|
||||
using (var fs = new FileStream(HitsFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
||||
using (var br = new BinaryReader(fs))
|
||||
using (var bw = new BinaryWriter(fs))
|
||||
{
|
||||
using var fs = new FileStream(HitsFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
|
||||
using var br = new BinaryReader(fs);
|
||||
using var bw = new BinaryWriter(fs);
|
||||
int hitsLength = br.ReadInt32();
|
||||
WriteLog($"Current hits found '{hitsLength}'");
|
||||
|
||||
@@ -149,7 +145,6 @@ namespace Coverlet.Core.Instrumentation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WriteHits(sender);
|
||||
|
||||
@@ -167,16 +162,15 @@ namespace Coverlet.Core.Instrumentation
|
||||
// this case is relevant when instrumenting corelib since multiple processes can be running against the same instrumented dll.
|
||||
mutex.ReleaseMutex();
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteHits(object sender)
|
||||
{
|
||||
if (_enableLog)
|
||||
if (s_enableLog)
|
||||
{
|
||||
var currentAssembly = Assembly.GetExecutingAssembly();
|
||||
var location = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(currentAssembly.Location), "TrackersHitsLog"));
|
||||
location.Create();
|
||||
string logFile = Path.Combine(location.FullName, $"{Path.GetFileName(currentAssembly.Location)}_{DateTime.UtcNow.Ticks}_{_sessionId}.txt");
|
||||
string logFile = Path.Combine(location.FullName, $"{Path.GetFileName(currentAssembly.Location)}_{DateTime.UtcNow.Ticks}_{s_sessionId}.txt");
|
||||
using (var fs = new FileStream(HitsFilePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
||||
using (var log = new FileStream(logFile, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None))
|
||||
using (var logWriter = new StreamWriter(log))
|
||||
@@ -195,12 +189,12 @@ namespace Coverlet.Core.Instrumentation
|
||||
|
||||
private static void WriteLog(string logText)
|
||||
{
|
||||
if (_enableLog)
|
||||
if (s_enableLog)
|
||||
{
|
||||
// We don't set path as global var to keep benign possible errors inside try/catch
|
||||
// I'm not sure that location will be ok in every scenario
|
||||
string location = Assembly.GetExecutingAssembly().Location;
|
||||
File.AppendAllText(Path.Combine(Path.GetDirectoryName(location), Path.GetFileName(location) + "_tracker.txt"), $"[{DateTime.UtcNow} S:{_sessionId} T:{Thread.CurrentThread.ManagedThreadId}]{logText}{Environment.NewLine}");
|
||||
File.AppendAllText(Path.Combine(Path.GetDirectoryName(location), Path.GetFileName(location) + "_tracker.txt"), $"[{DateTime.UtcNow} S:{s_sessionId} T:{Thread.CurrentThread.ManagedThreadId}]{logText}{Environment.NewLine}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,9 +100,9 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
/// <summary>
|
||||
/// Returns true if this branch has multiple targets.
|
||||
/// </summary>
|
||||
public bool HasMultiTargets => _TargetOffset == -1;
|
||||
public bool HasMultiTargets => _targetOffset == -1;
|
||||
|
||||
private readonly int _TargetOffset;
|
||||
private readonly int _targetOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Target of the branch, assuming it has a single target.
|
||||
@@ -118,11 +118,11 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
throw new InvalidOperationException($"{HasMultiTargets} is true");
|
||||
}
|
||||
|
||||
return _TargetOffset;
|
||||
return _targetOffset;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly ImmutableArray<int> _TargetOffsets;
|
||||
private readonly ImmutableArray<int> _targetOffsets;
|
||||
|
||||
/// <summary>
|
||||
/// Targets of the branch, assuming it has multiple targets.
|
||||
@@ -138,15 +138,15 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
throw new InvalidOperationException($"{HasMultiTargets} is false");
|
||||
}
|
||||
|
||||
return _TargetOffsets;
|
||||
return _targetOffsets;
|
||||
}
|
||||
}
|
||||
|
||||
public BranchInstruction(int offset, int targetOffset)
|
||||
{
|
||||
Offset = offset;
|
||||
_TargetOffset = targetOffset;
|
||||
_TargetOffsets = ImmutableArray<int>.Empty;
|
||||
_targetOffset = targetOffset;
|
||||
_targetOffsets = ImmutableArray<int>.Empty;
|
||||
}
|
||||
|
||||
public BranchInstruction(int offset, ImmutableArray<int> targetOffset)
|
||||
@@ -157,8 +157,8 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
}
|
||||
|
||||
Offset = offset;
|
||||
_TargetOffset = -1;
|
||||
_TargetOffsets = targetOffset;
|
||||
_targetOffset = -1;
|
||||
_targetOffsets = targetOffset;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@@ -169,7 +169,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
/// OpCodes that transfer control code, even if they do not
|
||||
/// introduce branch points.
|
||||
/// </summary>
|
||||
private static readonly ImmutableHashSet<OpCode> BRANCH_OPCODES =
|
||||
private static readonly ImmutableHashSet<OpCode> s_branchOpCodes =
|
||||
ImmutableHashSet.CreateRange(
|
||||
new[]
|
||||
{
|
||||
@@ -224,7 +224,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
/// OpCodes that unconditionally transfer control, so there
|
||||
/// is not "fall through" branch target.
|
||||
/// </summary>
|
||||
private static readonly ImmutableHashSet<OpCode> UNCONDITIONAL_BRANCH_OPCODES =
|
||||
private static readonly ImmutableHashSet<OpCode> s_unconditionalBranchOpCodes =
|
||||
ImmutableHashSet.CreateRange(
|
||||
new[]
|
||||
{
|
||||
@@ -235,11 +235,11 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
}
|
||||
);
|
||||
|
||||
private readonly ImmutableHashSet<MetadataToken> DoesNotReturnMethods;
|
||||
private readonly ImmutableHashSet<MetadataToken> _doesNotReturnMethods;
|
||||
|
||||
private ReachabilityHelper(ImmutableHashSet<MetadataToken> doesNotReturnMethods)
|
||||
{
|
||||
DoesNotReturnMethods = doesNotReturnMethods;
|
||||
_doesNotReturnMethods = doesNotReturnMethods;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -372,7 +372,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
}
|
||||
|
||||
// no known methods that do not return, so everything is reachable by definition
|
||||
if (DoesNotReturnMethods.IsEmpty)
|
||||
if (_doesNotReturnMethods.IsEmpty)
|
||||
{
|
||||
return ImmutableArray<UnreachableRange>.Empty;
|
||||
}
|
||||
@@ -406,7 +406,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
{
|
||||
containsDoesNotReturnCall = containsDoesNotReturnCall || DoesNotReturn(i);
|
||||
|
||||
if (BRANCH_OPCODES.Contains(i.OpCode))
|
||||
if (s_branchOpCodes.Contains(i.OpCode))
|
||||
{
|
||||
(int? singleTargetOffset, ImmutableArray<int> multiTargetOffsets) = GetInstructionTargets(i, exceptionHandlers);
|
||||
|
||||
@@ -453,7 +453,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
{
|
||||
// it's any of the B.*(_S)? or Leave(_S)? instructions
|
||||
|
||||
if (UNCONDITIONAL_BRANCH_OPCODES.Contains(i.OpCode))
|
||||
if (s_unconditionalBranchOpCodes.Contains(i.OpCode))
|
||||
{
|
||||
multiTargetOffsets = ImmutableArray<int>.Empty;
|
||||
singleTargetOffset = targetInstr.Offset;
|
||||
@@ -527,7 +527,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
/// <summary>
|
||||
/// Calculates which ranges of IL are unreachable, given blocks which have head and tail reachability calculated.
|
||||
/// </summary>
|
||||
private ImmutableArray<UnreachableRange> DetermineUnreachableRanges(ImmutableArray<BasicBlock> blocks, int lastInstructionOffset)
|
||||
private static ImmutableArray<UnreachableRange> DetermineUnreachableRanges(ImmutableArray<BasicBlock> blocks, int lastInstructionOffset)
|
||||
{
|
||||
ImmutableArray<UnreachableRange>.Builder ret = ImmutableArray.CreateBuilder<UnreachableRange>();
|
||||
|
||||
@@ -580,7 +580,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
///
|
||||
/// "Tail reachability" will have already been determined in CreateBlocks.
|
||||
/// </summary>
|
||||
private void DetermineHeadReachability(ImmutableArray<BasicBlock> blocks)
|
||||
private static void DetermineHeadReachability(ImmutableArray<BasicBlock> blocks)
|
||||
{
|
||||
var blockLookup = blocks.ToImmutableDictionary(b => b.StartOffset);
|
||||
|
||||
@@ -791,7 +791,7 @@ namespace Coverlet.Core.Instrumentation.Reachability
|
||||
return false;
|
||||
}
|
||||
|
||||
return DoesNotReturnMethods.Contains(mtd.MetadataToken);
|
||||
return _doesNotReturnMethods.Contains(mtd.MetadataToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Toni Solarin-Sodara
|
||||
// Copyright (c) Toni Solarin-Sodara
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
@@ -111,7 +111,7 @@ namespace Coverlet.Core.Reporters
|
||||
{
|
||||
var condition = new XElement("condition");
|
||||
condition.Add(new XAttribute("number", entry.Key));
|
||||
condition.Add(new XAttribute("type", entry.Value.Count() > 2 ? "switch" : "jump")); // Just guessing here
|
||||
condition.Add(new XAttribute("type", entry.Value.Count > 2 ? "switch" : "jump")); // Just guessing here
|
||||
condition.Add(new XAttribute("coverage", $"{summary.CalculateBranchCoverage(entry.Value).Percent.ToString(CultureInfo.InvariantCulture)}%"));
|
||||
conditions.Add(condition);
|
||||
}
|
||||
@@ -119,7 +119,6 @@ namespace Coverlet.Core.Reporters
|
||||
line.Add(conditions);
|
||||
}
|
||||
|
||||
|
||||
lines.Add(line);
|
||||
classLines.Add(line);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Coverlet.Core.Reporters
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
private void OutputLineCoverage(CoverageDetails coverageDetails, StringBuilder builder)
|
||||
private static void OutputLineCoverage(CoverageDetails coverageDetails, StringBuilder builder)
|
||||
{
|
||||
// The number of covered lines
|
||||
OutputTeamCityServiceMessage("CodeCoverageAbsLCovered", coverageDetails.Covered, builder);
|
||||
@@ -48,7 +48,7 @@ namespace Coverlet.Core.Reporters
|
||||
OutputTeamCityServiceMessage("CodeCoverageAbsLTotal", coverageDetails.Total, builder);
|
||||
}
|
||||
|
||||
private void OutputBranchCoverage(CoverageDetails coverageDetails, StringBuilder builder)
|
||||
private static void OutputBranchCoverage(CoverageDetails coverageDetails, StringBuilder builder)
|
||||
{
|
||||
// The number of covered branches
|
||||
OutputTeamCityServiceMessage("CodeCoverageAbsBCovered", coverageDetails.Covered, builder);
|
||||
@@ -57,7 +57,7 @@ namespace Coverlet.Core.Reporters
|
||||
OutputTeamCityServiceMessage("CodeCoverageAbsBTotal", coverageDetails.Total, builder);
|
||||
}
|
||||
|
||||
private void OutputMethodCoverage(CoverageDetails coverageDetails, StringBuilder builder)
|
||||
private static void OutputMethodCoverage(CoverageDetails coverageDetails, StringBuilder builder)
|
||||
{
|
||||
// The number of covered methods
|
||||
OutputTeamCityServiceMessage("CodeCoverageAbsMCovered", coverageDetails.Covered, builder);
|
||||
@@ -66,7 +66,7 @@ namespace Coverlet.Core.Reporters
|
||||
OutputTeamCityServiceMessage("CodeCoverageAbsMTotal", coverageDetails.Total, builder);
|
||||
}
|
||||
|
||||
private void OutputTeamCityServiceMessage(string key, double value, StringBuilder builder)
|
||||
private static void OutputTeamCityServiceMessage(string key, double value, StringBuilder builder)
|
||||
{
|
||||
builder.AppendLine($"##teamcity[buildStatisticValue key='{key}' value='{value.ToString("0.##", new CultureInfo("en-US"))}']");
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace Coverlet.Core.Symbols
|
||||
{
|
||||
private const int StepOverLineCode = 0xFEEFEE;
|
||||
// Create single instance, we cannot collide because we use full method name as key
|
||||
private readonly ConcurrentDictionary<string, int[]> _compilerGeneratedBranchesToExclude = new ConcurrentDictionary<string, int[]>();
|
||||
private readonly ConcurrentDictionary<string, List<int>> _sequencePointOffsetToSkip = new ConcurrentDictionary<string, List<int>>();
|
||||
private readonly ConcurrentDictionary<string, int[]> _compilerGeneratedBranchesToExclude = new();
|
||||
private readonly ConcurrentDictionary<string, List<int>> _sequencePointOffsetToSkip = new();
|
||||
|
||||
// In case of nested compiler generated classes, only the root one presents the CompilerGenerated attribute.
|
||||
// So let's search up to the outermost declaring type to find the attribute
|
||||
@@ -83,7 +83,8 @@ namespace Coverlet.Core.Symbols
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (methodDefinition.DeclaringType.CustomAttributes.Count(ca => ca.AttributeType.FullName == typeof(CompilerGeneratedAttribute).FullName) > 0)
|
||||
|
||||
if (methodDefinition.DeclaringType.CustomAttributes.Any(ca => ca.AttributeType.FullName == typeof(CompilerGeneratedAttribute).FullName))
|
||||
{
|
||||
foreach (InterfaceImplementation implementedInterface in methodDefinition.DeclaringType.Interfaces)
|
||||
{
|
||||
@@ -465,7 +466,6 @@ namespace Coverlet.Core.Symbols
|
||||
CheckIfExceptionThrown(instructions, instruction, currentIndex) ||
|
||||
CheckThrownExceptionType(instructions, instruction, currentIndex);
|
||||
|
||||
|
||||
// The pattern for the "should we stay in the loop or not?", which we don't
|
||||
// want to skip (so we have no method to try to find it), looks like this:
|
||||
//
|
||||
@@ -477,7 +477,6 @@ namespace Coverlet.Core.Symbols
|
||||
// the "call" and branch, but it's the same idea either way: branch
|
||||
// if GetResult() returned true.
|
||||
|
||||
|
||||
static bool CheckForAsyncEnumerator(List<Instruction> instructions, Instruction instruction, int currentIndex)
|
||||
{
|
||||
// We're looking for the following pattern, which checks whether a
|
||||
@@ -506,7 +505,6 @@ namespace Coverlet.Core.Symbols
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool CheckIfExceptionThrown(List<Instruction> instructions, Instruction instruction, int currentIndex)
|
||||
{
|
||||
// Here, we want to find a pattern where we're checking whether a
|
||||
@@ -564,7 +562,6 @@ namespace Coverlet.Core.Symbols
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool CheckThrownExceptionType(List<Instruction> instructions, Instruction instruction, int currentIndex)
|
||||
{
|
||||
// In this case, we're looking for a branch generated by the compiler to
|
||||
@@ -617,7 +614,6 @@ namespace Coverlet.Core.Symbols
|
||||
return CheckForSkipDisposal(instructions, instruction, currentIndex) ||
|
||||
CheckForCleanup(instructions, instruction, currentIndex);
|
||||
|
||||
|
||||
static bool CheckForSkipDisposal(List<Instruction> instructions, Instruction instruction, int currentIndex)
|
||||
{
|
||||
// The async state machine generated for an "await using" contains a branch
|
||||
@@ -727,7 +723,6 @@ namespace Coverlet.Core.Symbols
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool CheckForCleanup(List<Instruction> instructions, Instruction instruction, int currentIndex)
|
||||
{
|
||||
// The pattern we're looking for here is this:
|
||||
@@ -812,7 +807,6 @@ namespace Coverlet.Core.Symbols
|
||||
return CheckForStateSwitch(instructions, instruction, currentIndex) ||
|
||||
DisposeCheck(instructions, instruction, currentIndex);
|
||||
|
||||
|
||||
static bool CheckForStateSwitch(List<Instruction> instructions, Instruction instruction, int currentIndex)
|
||||
{
|
||||
// The pattern we're looking for here is this one:
|
||||
@@ -890,7 +884,7 @@ namespace Coverlet.Core.Symbols
|
||||
}
|
||||
}
|
||||
|
||||
private bool SkipGeneratedBranchesForEnumeratorCancellationAttribute(List<Instruction> instructions, Instruction instruction)
|
||||
private static bool SkipGeneratedBranchesForEnumeratorCancellationAttribute(List<Instruction> instructions, Instruction instruction)
|
||||
{
|
||||
// For async-enumerable methods an additional cancellation token despite the default one can be passed.
|
||||
// The EnumeratorCancellation attribute marks the parameter whose value is received by GetAsyncEnumerator(CancellationToken).
|
||||
|
||||
@@ -152,9 +152,9 @@ namespace Coverlet.MSbuild.Tasks
|
||||
if (Threshold.Contains(','))
|
||||
{
|
||||
IEnumerable<string> thresholdValues = Threshold.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(t => t.Trim());
|
||||
if (thresholdValues.Count() != thresholdTypeFlagQueue.Count())
|
||||
if (thresholdValues.Count() != thresholdTypeFlagQueue.Count)
|
||||
{
|
||||
throw new Exception($"Threshold type flag count ({thresholdTypeFlagQueue.Count()}) and values count ({thresholdValues.Count()}) doesn't match");
|
||||
throw new Exception($"Threshold type flag count ({thresholdTypeFlagQueue.Count}) and values count ({thresholdValues.Count()}) doesn't match");
|
||||
}
|
||||
|
||||
foreach (string threshold in thresholdValues)
|
||||
|
||||
@@ -112,14 +112,10 @@ namespace Coverlet.MSbuild.Tasks
|
||||
|
||||
CoveragePrepareResult prepareResult = coverage.PrepareModules();
|
||||
InstrumenterState = new TaskItem(System.IO.Path.GetTempFileName());
|
||||
using (Stream instrumentedStateFile = fileSystem.NewFileStream(InstrumenterState.ItemSpec, FileMode.Open, FileAccess.Write))
|
||||
{
|
||||
using (Stream serializedState = CoveragePrepareResult.Serialize(prepareResult))
|
||||
{
|
||||
using Stream instrumentedStateFile = fileSystem.NewFileStream(InstrumenterState.ItemSpec, FileMode.Open, FileAccess.Write);
|
||||
using Stream serializedState = CoveragePrepareResult.Serialize(prepareResult);
|
||||
serializedState.CopyTo(instrumentedStateFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex);
|
||||
|
||||
@@ -188,14 +188,14 @@ namespace Coverlet.Collector.Tests
|
||||
Assert.Equal(defaultFormat, coverletSettings.ReportFormats[0]);
|
||||
}
|
||||
|
||||
private void CreateCoverletNodes(XmlDocument doc, XmlElement configElement, string nodeSetting, string nodeValue)
|
||||
private static void CreateCoverletNodes(XmlDocument doc, XmlElement configElement, string nodeSetting, string nodeValue)
|
||||
{
|
||||
XmlNode node = doc.CreateNode("element", nodeSetting, string.Empty);
|
||||
node.InnerText = nodeValue;
|
||||
configElement.AppendChild(node);
|
||||
}
|
||||
|
||||
private void CreateCoverletNullInnerTextNodes(XmlDocument doc, XmlElement configElement, string nodeSetting)
|
||||
private static void CreateCoverletNullInnerTextNodes(XmlDocument doc, XmlElement configElement, string nodeSetting)
|
||||
{
|
||||
XmlNode node = doc.CreateNode("element", nodeSetting, string.Empty);
|
||||
node.InnerText = null;
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Coverlet.Core.Tests
|
||||
{
|
||||
public partial class CoverageTests
|
||||
{
|
||||
private readonly Mock<ILogger> _mockLogger = new Mock<ILogger>();
|
||||
private readonly Mock<ILogger> _mockLogger = new();
|
||||
|
||||
[Fact]
|
||||
public void TestCoverage()
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Coverlet.Core.Tests
|
||||
{
|
||||
static class TestInstrumentationHelper
|
||||
{
|
||||
private static IServiceProvider _processWideContainer;
|
||||
private static IServiceProvider s_processWideContainer;
|
||||
|
||||
/// <summary>
|
||||
/// caller sample: TestInstrumentationHelper.GenerateHtmlReport(result, sourceFileFilter: @"+**\Samples\Instrumentation.cs");
|
||||
@@ -64,9 +64,9 @@ namespace Coverlet.Core.Tests
|
||||
{
|
||||
Assert.DoesNotContain("not found for module: ", message);
|
||||
});
|
||||
_processWideContainer.GetRequiredService<IInstrumentationHelper>().SetLogger(logger.Object);
|
||||
s_processWideContainer.GetRequiredService<IInstrumentationHelper>().SetLogger(logger.Object);
|
||||
var coveragePrepareResultLoaded = CoveragePrepareResult.Deserialize(result);
|
||||
var coverage = new Coverage(coveragePrepareResultLoaded, logger.Object, _processWideContainer.GetService<IInstrumentationHelper>(), new FileSystem(), new SourceRootTranslator(new Mock<ILogger>().Object, new FileSystem()));
|
||||
var coverage = new Coverage(coveragePrepareResultLoaded, logger.Object, s_processWideContainer.GetService<IInstrumentationHelper>(), new FileSystem(), new SourceRootTranslator(new Mock<ILogger>().Object, new FileSystem()));
|
||||
return coverage.GetCoverageResult();
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace Coverlet.Core.Tests
|
||||
|
||||
// Instrument module
|
||||
var coverage = new Coverage(newPath, parameters, new Logger(logFile),
|
||||
_processWideContainer.GetService<IInstrumentationHelper>(), _processWideContainer.GetService<IFileSystem>(), _processWideContainer.GetService<ISourceRootTranslator>(), _processWideContainer.GetService<ICecilSymbolHelper>());
|
||||
s_processWideContainer.GetService<IInstrumentationHelper>(), s_processWideContainer.GetService<IFileSystem>(), s_processWideContainer.GetService<ISourceRootTranslator>(), s_processWideContainer.GetService<ICecilSymbolHelper>());
|
||||
CoveragePrepareResult prepareResult = coverage.PrepareModules();
|
||||
|
||||
Assert.Single(prepareResult.Results);
|
||||
@@ -153,7 +153,7 @@ namespace Coverlet.Core.Tests
|
||||
|
||||
private static void SetTestContainer(string testModule = null, bool disableRestoreModules = false)
|
||||
{
|
||||
LazyInitializer.EnsureInitialized(ref _processWideContainer, () =>
|
||||
LazyInitializer.EnsureInitialized(ref s_processWideContainer, () =>
|
||||
{
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection.AddTransient<IRetryHelper, CustomRetryHelper>();
|
||||
@@ -291,7 +291,7 @@ namespace Coverlet.Core.Tests
|
||||
|
||||
public abstract class ExternalProcessExecutionTest
|
||||
{
|
||||
protected FunctionExecutor FunctionExecutor = new FunctionExecutor(
|
||||
protected FunctionExecutor FunctionExecutor = new(
|
||||
o =>
|
||||
{
|
||||
o.StartInfo.RedirectStandardError = true;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Coverlet.Core.Helpers.Tests
|
||||
public class InstrumentationHelperTests
|
||||
{
|
||||
private readonly InstrumentationHelper _instrumentationHelper =
|
||||
new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock<ILogger>().Object, new SourceRootTranslator(typeof(InstrumentationHelperTests).Assembly.Location, new Mock<ILogger>().Object, new FileSystem()));
|
||||
new(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock<ILogger>().Object, new SourceRootTranslator(typeof(InstrumentationHelperTests).Assembly.Location, new Mock<ILogger>().Object, new FileSystem()));
|
||||
|
||||
[Fact]
|
||||
public void TestGetDependencies()
|
||||
|
||||
@@ -26,12 +26,12 @@ namespace Coverlet.Core.Instrumentation.Tests
|
||||
{
|
||||
public class InstrumenterTests : IDisposable
|
||||
{
|
||||
private readonly Mock<ILogger> _mockLogger = new Mock<ILogger>();
|
||||
private Action disposeAction;
|
||||
private readonly Mock<ILogger> _mockLogger = new();
|
||||
private Action _disposeAction;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
disposeAction?.Invoke();
|
||||
_disposeAction?.Invoke();
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
@@ -192,9 +192,7 @@ namespace Coverlet.Core.Instrumentation.Tests
|
||||
|
||||
Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs");
|
||||
Assert.NotNull(doc);
|
||||
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
bool found = doc.Lines.Values.Any(l => l.Method.Equals($"System.String Coverlet.Core.Samples.Tests.{testClassName}::Method(System.String)"));
|
||||
#pragma warning restore CS0612 // Type or member is obsolete
|
||||
Assert.False(found, "Method decorated with with exclude attribute should be excluded");
|
||||
|
||||
instrumenterTest.Directory.Delete(true);
|
||||
@@ -211,14 +209,10 @@ namespace Coverlet.Core.Instrumentation.Tests
|
||||
|
||||
Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs");
|
||||
Assert.NotNull(doc);
|
||||
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
bool getFound = doc.Lines.Values.Any(l => l.Method.Equals($"System.String Coverlet.Core.Samples.Tests.{testClassName}::get_Property()"));
|
||||
#pragma warning restore CS0612 // Type or member is obsolete
|
||||
Assert.False(getFound, "Property getter decorated with with exclude attribute should be excluded");
|
||||
|
||||
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
bool setFound = doc.Lines.Values.Any(l => l.Method.Equals($"System.String Coverlet.Core.Samples.Tests.{testClassName}::set_Property()"));
|
||||
#pragma warning restore CS0612 // Type or member is obsolete
|
||||
Assert.False(setFound, "Property setter decorated with with exclude attribute should be excluded");
|
||||
|
||||
instrumenterTest.Directory.Delete(true);
|
||||
@@ -587,7 +581,7 @@ public class SampleClass
|
||||
|
||||
string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
Directory.CreateDirectory(tempDirectory);
|
||||
disposeAction = () => Directory.Delete(tempDirectory, true);
|
||||
_disposeAction = () => Directory.Delete(tempDirectory, true);
|
||||
|
||||
var partialMockFileSystem = new Mock<FileSystem>();
|
||||
partialMockFileSystem.CallBase = true;
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Coverlet.Core.Tests.Instrumentation
|
||||
|
||||
public class ModuleTrackerTemplateTests : ExternalProcessExecutionTest
|
||||
{
|
||||
private static readonly Task<int> _success = Task.FromResult(0);
|
||||
private static readonly Task<int> s_success = Task.FromResult(0);
|
||||
|
||||
[Fact]
|
||||
public void HitsFileCorrectlyWritten()
|
||||
@@ -44,7 +44,7 @@ namespace Coverlet.Core.Tests.Instrumentation
|
||||
int[] expectedHitsArray = new[] { 1, 2, 0, 3 };
|
||||
Assert.Equal(expectedHitsArray, ReadHitsFile());
|
||||
|
||||
return _success;
|
||||
return s_success;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Coverlet.Core.Tests.Instrumentation
|
||||
WriteHitsFile(new[] { 1, 2, 3 });
|
||||
ModuleTrackerTemplate.HitsArray = new[] { 1 };
|
||||
Assert.Throws<InvalidOperationException>(() => ModuleTrackerTemplate.UnloadModule(null, null));
|
||||
return _success;
|
||||
return s_success;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace Coverlet.Core.Tests.Instrumentation
|
||||
}
|
||||
}
|
||||
|
||||
return _success;
|
||||
return s_success;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Coverlet.Core.Tests.Instrumentation
|
||||
int[] expectedHitsArray = new[] { 0, 4, 4, 4 };
|
||||
Assert.Equal(expectedHitsArray, ReadHitsFile());
|
||||
|
||||
return _success;
|
||||
return s_success;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -149,24 +149,21 @@ namespace Coverlet.Core.Tests.Instrumentation
|
||||
|
||||
}
|
||||
|
||||
private void WriteHitsFile(int[] hitsArray)
|
||||
{
|
||||
using (var fs = new FileStream(ModuleTrackerTemplate.HitsFilePath, FileMode.Create))
|
||||
using (var bw = new BinaryWriter(fs))
|
||||
private static void WriteHitsFile(int[] hitsArray)
|
||||
{
|
||||
using var fs = new FileStream(ModuleTrackerTemplate.HitsFilePath, FileMode.Create);
|
||||
using var bw = new BinaryWriter(fs);
|
||||
bw.Write(hitsArray.Length);
|
||||
foreach (int hitCount in hitsArray)
|
||||
{
|
||||
bw.Write(hitCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int[] ReadHitsFile()
|
||||
{
|
||||
using (var fs = new FileStream(ModuleTrackerTemplate.HitsFilePath, FileMode.Open))
|
||||
using (var br = new BinaryReader(fs))
|
||||
private static int[] ReadHitsFile()
|
||||
{
|
||||
using var fs = new FileStream(ModuleTrackerTemplate.HitsFilePath, FileMode.Open);
|
||||
using var br = new BinaryReader(fs);
|
||||
int[] hitsArray = new int[br.ReadInt32()];
|
||||
for (int i = 0; i < hitsArray.Length; ++i)
|
||||
{
|
||||
@@ -176,5 +173,4 @@ namespace Coverlet.Core.Tests.Instrumentation
|
||||
return hitsArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Coverlet.Core.Symbols.Tests
|
||||
|
||||
// assert
|
||||
Assert.NotNull(points);
|
||||
Assert.Equal(2, points.Count());
|
||||
Assert.Equal(2, points.Count);
|
||||
Assert.Equal(points[0].Offset, points[1].Offset);
|
||||
Assert.Equal(0, points[0].Path);
|
||||
Assert.Equal(1, points[1].Path);
|
||||
@@ -61,7 +61,7 @@ namespace Coverlet.Core.Symbols.Tests
|
||||
// act
|
||||
System.Collections.Generic.IReadOnlyList<BranchPoint> points = _cecilSymbolHelper.GetBranchPoints(method);
|
||||
|
||||
Assert.Equal(2, points.Count());
|
||||
Assert.Equal(2, points.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -89,7 +89,7 @@ namespace Coverlet.Core.Symbols.Tests
|
||||
|
||||
// assert
|
||||
Assert.NotNull(points);
|
||||
Assert.Equal(4, points.Count());
|
||||
Assert.Equal(4, points.Count);
|
||||
Assert.Equal(points[0].Offset, points[1].Offset);
|
||||
Assert.Equal(points[2].Offset, points[3].Offset);
|
||||
Assert.Equal(28, points[0].StartLine);
|
||||
@@ -108,7 +108,7 @@ namespace Coverlet.Core.Symbols.Tests
|
||||
|
||||
// assert
|
||||
Assert.NotNull(points);
|
||||
Assert.Equal(2, points.Count());
|
||||
Assert.Equal(2, points.Count);
|
||||
Assert.Equal(points[0].Offset, points[1].Offset);
|
||||
Assert.Equal(35, points[0].StartLine);
|
||||
Assert.Equal(35, points[1].StartLine);
|
||||
@@ -127,7 +127,7 @@ namespace Coverlet.Core.Symbols.Tests
|
||||
|
||||
// assert
|
||||
Assert.NotNull(points);
|
||||
Assert.Equal(4, points.Count());
|
||||
Assert.Equal(4, points.Count);
|
||||
Assert.Equal(points[0].Offset, points[1].Offset);
|
||||
Assert.Equal(points[0].Offset, points[2].Offset);
|
||||
Assert.Equal(3, points[3].Path);
|
||||
@@ -150,7 +150,7 @@ namespace Coverlet.Core.Symbols.Tests
|
||||
|
||||
// assert
|
||||
Assert.NotNull(points);
|
||||
Assert.Equal(4, points.Count());
|
||||
Assert.Equal(4, points.Count);
|
||||
Assert.Equal(points[0].Offset, points[1].Offset);
|
||||
Assert.Equal(points[0].Offset, points[2].Offset);
|
||||
Assert.Equal(3, points[3].Path);
|
||||
@@ -173,7 +173,7 @@ namespace Coverlet.Core.Symbols.Tests
|
||||
|
||||
// assert
|
||||
Assert.NotNull(points);
|
||||
Assert.Equal(4, points.Count());
|
||||
Assert.Equal(4, points.Count);
|
||||
Assert.Equal(points[0].Offset, points[1].Offset);
|
||||
Assert.Equal(points[0].Offset, points[2].Offset);
|
||||
Assert.Equal(3, points[3].Path);
|
||||
@@ -196,7 +196,7 @@ namespace Coverlet.Core.Symbols.Tests
|
||||
|
||||
// assert
|
||||
Assert.NotNull(points);
|
||||
Assert.Equal(4, points.Count());
|
||||
Assert.Equal(4, points.Count);
|
||||
Assert.Equal(points[0].Offset, points[1].Offset);
|
||||
Assert.Equal(points[0].Offset, points[2].Offset);
|
||||
Assert.Equal(points[0].Offset, points[3].Offset);
|
||||
@@ -351,7 +351,7 @@ namespace Coverlet.Core.Symbols.Tests
|
||||
// We do expect there to be a two-way branch (stay in the loop or not?) on
|
||||
// the line containing "await foreach".
|
||||
Assert.NotNull(points);
|
||||
Assert.Equal(2, points.Count());
|
||||
Assert.Equal(2, points.Count);
|
||||
Assert.Equal(points[0].Offset, points[1].Offset);
|
||||
Assert.Equal(204, points[0].StartLine);
|
||||
Assert.Equal(204, points[1].StartLine);
|
||||
@@ -375,7 +375,7 @@ namespace Coverlet.Core.Symbols.Tests
|
||||
// containing "await foreach" and the other being the "if" statement inside
|
||||
// the loop.
|
||||
Assert.NotNull(points);
|
||||
Assert.Equal(4, points.Count());
|
||||
Assert.Equal(4, points.Count);
|
||||
Assert.Equal(points[0].Offset, points[1].Offset);
|
||||
Assert.Equal(points[2].Offset, points[3].Offset);
|
||||
Assert.Equal(219, points[0].StartLine);
|
||||
@@ -399,7 +399,7 @@ namespace Coverlet.Core.Symbols.Tests
|
||||
// assert
|
||||
// We do expect the "for" loop to be a branch with two branch points, but that's it.
|
||||
Assert.NotNull(points);
|
||||
Assert.Equal(2, points.Count());
|
||||
Assert.Equal(2, points.Count);
|
||||
Assert.Equal(237, points[0].StartLine);
|
||||
Assert.Equal(237, points[1].StartLine);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Coverlet.Integration.Tests
|
||||
|
||||
public abstract class BaseTest
|
||||
{
|
||||
private static int _folderSuffix = 0;
|
||||
private static int s_folderSuffix;
|
||||
|
||||
protected BuildConfiguration GetAssemblyBuildConfiguration()
|
||||
{
|
||||
@@ -67,7 +67,7 @@ namespace Coverlet.Integration.Tests
|
||||
|
||||
private protected ClonedTemplateProject CloneTemplateProject(bool cleanupOnDispose = true, string testSDKVersion = "16.5.0")
|
||||
{
|
||||
DirectoryInfo finalRoot = Directory.CreateDirectory($"{Guid.NewGuid().ToString("N").Substring(0, 6)}{Interlocked.Increment(ref _folderSuffix)}");
|
||||
DirectoryInfo finalRoot = Directory.CreateDirectory($"{Guid.NewGuid().ToString("N")[..6]}{Interlocked.Increment(ref s_folderSuffix)}");
|
||||
foreach (string file in (Directory.GetFiles($"../../../../coverlet.integration.template", "*.cs")
|
||||
.Union(Directory.GetFiles($"../../../../coverlet.integration.template", "*.csproj")
|
||||
.Union(Directory.GetFiles($"../../../../coverlet.integration.template", "nuget.config")))))
|
||||
|
||||
Reference in New Issue
Block a user