diff --git a/eng/Common.globalconfig b/eng/Common.globalconfig
index 49de8011d44..c75fbec9493 100644
--- a/eng/Common.globalconfig
+++ b/eng/Common.globalconfig
@@ -253,7 +253,7 @@ dotnet_diagnostic.CA1805.severity = none
dotnet_diagnostic.CA1806.severity = none
# Initialize reference type static fields inline
-dotnet_diagnostic.CA1810.severity = suggestion
+dotnet_diagnostic.CA1810.severity = warning
# Avoid uninstantiated internal classes
dotnet_diagnostic.CA1812.severity = none
diff --git a/src/Build/BackEnd/Components/RequestBuilder/IntrinsicTasks/ItemGroupLoggingHelper.cs b/src/Build/BackEnd/Components/RequestBuilder/IntrinsicTasks/ItemGroupLoggingHelper.cs
index c1679d38212..4f67ed79862 100644
--- a/src/Build/BackEnd/Components/RequestBuilder/IntrinsicTasks/ItemGroupLoggingHelper.cs
+++ b/src/Build/BackEnd/Components/RequestBuilder/IntrinsicTasks/ItemGroupLoggingHelper.cs
@@ -44,7 +44,9 @@ internal static class ItemGroupLoggingHelper
/// to materialize the Message as that's a declaration assembly. We inject the logic
/// here.
///
+#pragma warning disable CA1810 // Initialize reference type static fields inline
static ItemGroupLoggingHelper()
+#pragma warning restore CA1810 // Initialize reference type static fields inline
{
BuildEventArgs.ResourceStringFormatter = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword;
TaskParameterEventArgs.MessageGetter = GetTaskParameterText;
diff --git a/src/Build/Evaluation/ProjectRootElementCache.cs b/src/Build/Evaluation/ProjectRootElementCache.cs
index bb85186e17c..17ecae43227 100644
--- a/src/Build/Evaluation/ProjectRootElementCache.cs
+++ b/src/Build/Evaluation/ProjectRootElementCache.cs
@@ -71,14 +71,13 @@ internal class ProjectRootElementCache : ProjectRootElementCacheBase
/// If this number is increased much higher, the datastructure may
/// need to be changed from a linked list, since it's currently O(n).
///
-#pragma warning disable CA1802 // Use literals where appropriate
- private static readonly int s_maximumStrongCacheSize = 200;
-#pragma warning restore CA1802 // Use literals where appropriate
+ private static readonly int s_maximumStrongCacheSize =
+ int.TryParse(Environment.GetEnvironmentVariable("MSBUILDPROJECTROOTELEMENTCACHESIZE"), out int cacheSize) ? cacheSize : 200;
///
/// Whether the cache should log activity to the Debug.Out stream
///
- private static bool s_debugLogCacheActivity;
+ private static bool s_debugLogCacheActivity = Environment.GetEnvironmentVariable("MSBUILDDEBUGXMLCACHE") == "1";
///
/// Whether the cache should check file content for cache entry invalidation.
@@ -86,7 +85,7 @@ internal class ProjectRootElementCache : ProjectRootElementCacheBase
///
/// Value shall be true only in case of testing. Outside QA tests it shall be false.
///
- private static bool s_сheckFileContent;
+ private static bool s_сheckFileContent = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("MSBUILDCACHECHECKFILECONTENT"));
#if DEBUG
///
@@ -123,24 +122,6 @@ internal class ProjectRootElementCache : ProjectRootElementCacheBase
///
private Object _locker = new Object();
- ///
- /// Static constructor to choose cache size.
- ///
- static ProjectRootElementCache()
- {
- // Configurable in case a customer has related perf problems after shipping and so that
- // we can measure different values for perf easily.
- string userSpecifiedSize = Environment.GetEnvironmentVariable("MSBUILDPROJECTROOTELEMENTCACHESIZE");
- if (!String.IsNullOrEmpty(userSpecifiedSize))
- {
- // Not catching as this is an undocumented setting
- s_maximumStrongCacheSize = Convert.ToInt32(userSpecifiedSize, NumberFormatInfo.InvariantInfo);
- }
-
- s_debugLogCacheActivity = Environment.GetEnvironmentVariable("MSBUILDDEBUGXMLCACHE") == "1";
- s_сheckFileContent = !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("MSBUILDCACHECHECKFILECONTENT"));
- }
-
///
/// Creates an empty cache.
///
diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs
index 3ef0dabb711..7fec6c6b1f4 100644
--- a/src/MSBuild/XMake.cs
+++ b/src/MSBuild/XMake.cs
@@ -127,7 +127,9 @@ public enum ExitType
///
/// Static constructor
///
+#pragma warning disable CA1810 // Initialize reference type static fields inline
static MSBuildApp()
+#pragma warning restore CA1810 // Initialize reference type static fields inline
{
try
{
diff --git a/src/Shared/ExceptionHandling.cs b/src/Shared/ExceptionHandling.cs
index f4ebaa3bc9c..fcd48395a31 100644
--- a/src/Shared/ExceptionHandling.cs
+++ b/src/Shared/ExceptionHandling.cs
@@ -36,12 +36,7 @@ namespace Microsoft.Build.Shared
///
internal static class ExceptionHandling
{
- private static readonly string s_debugDumpPath;
-
- static ExceptionHandling()
- {
- s_debugDumpPath = GetDebugDumpPath();
- }
+ private static readonly string s_debugDumpPath = GetDebugDumpPath();
///
/// Gets the location of the directory used for diagnostic log files.
diff --git a/src/Shared/FrameworkLocationHelper.cs b/src/Shared/FrameworkLocationHelper.cs
index 135c2aa2b49..01ff320cf7d 100644
--- a/src/Shared/FrameworkLocationHelper.cs
+++ b/src/Shared/FrameworkLocationHelper.cs
@@ -33,7 +33,7 @@ internal enum DotNetFrameworkArchitecture
///
/// Indicates the 64-bit .NET Framework
///
- Bitness64 = 2
+ Bitness64 = 2,
}
///
@@ -72,7 +72,7 @@ internal static class FrameworkLocationHelper
internal static readonly Version visualStudioVersion170 = new Version(17, 0);
// keep this up-to-date; always point to the latest visual studio version.
- internal static readonly Version visualStudioVersionLatest = visualStudioVersion160;
+ internal static readonly Version visualStudioVersionLatest = visualStudioVersion170;
private const string dotNetFrameworkRegistryPath = "SOFTWARE\\Microsoft\\.NETFramework";
private const string dotNetFrameworkSetupRegistryPath = "SOFTWARE\\Microsoft\\NET Framework Setup\\NDP";
@@ -145,7 +145,7 @@ internal static class FrameworkLocationHelper
///
/// List the supported .net versions.
///
- private static readonly DotNetFrameworkSpec[] s_dotNetFrameworkSpecs =
+ private static DotNetFrameworkSpec[] DotNetFrameworkSpecs() => new DotNetFrameworkSpec[]
{
// v1.1
new DotNetFrameworkSpecLegacy(
@@ -225,7 +225,7 @@ internal static class FrameworkLocationHelper
///
/// The items must be ordered by the version, because some methods depend on that fact to find the previous visual studio version.
///
- private static readonly VisualStudioSpec[] s_visualStudioSpecs =
+ private static readonly Lazy VisualStudioSpecs = new(() => new VisualStudioSpec[]
{
// VS10
new VisualStudioSpec(visualStudioVersion100, "Windows\\v7.0A", null, null, new []
@@ -255,7 +255,7 @@ internal static class FrameworkLocationHelper
dotNetFrameworkVersion40,
dotNetFrameworkVersion45,
dotNetFrameworkVersion451,
- dotNetFrameworkVersion452
+ dotNetFrameworkVersion452,
}),
// VS14
@@ -269,7 +269,7 @@ internal static class FrameworkLocationHelper
dotNetFrameworkVersion451,
dotNetFrameworkVersion452,
dotNetFrameworkVersion46,
- dotNetFrameworkVersion461
+ dotNetFrameworkVersion461,
}),
// VS15
@@ -328,7 +328,7 @@ internal static class FrameworkLocationHelper
dotNetFrameworkVersion472,
dotNetFrameworkVersion48,
}),
- };
+ });
#if FEATURE_WIN32_REGISTRY
///
@@ -373,20 +373,14 @@ private static readonly (Version, Version)[,] s_explicitFallbackRulesForPathToDo
{ (dotNetFrameworkVersion471, visualStudioVersion160), (dotNetFrameworkVersion47, visualStudioVersion160) },
{ (dotNetFrameworkVersion472, visualStudioVersion160), (dotNetFrameworkVersion471, visualStudioVersion160) },
{ (dotNetFrameworkVersion48, visualStudioVersion160), (dotNetFrameworkVersion472, visualStudioVersion160) },
- };
+ };
#endif // FEATURE_WIN32_REGISTRY
- private static readonly IReadOnlyDictionary s_dotNetFrameworkSpecDict;
- private static readonly IReadOnlyDictionary s_visualStudioSpecDict;
+ private static readonly Lazy> DotNetFrameworkSpecDict = new(() => DotNetFrameworkSpecs().ToDictionary(spec => spec.Version));
+ private static readonly Lazy> VisualStudioSpecDict = new(() => VisualStudioSpecs.Value.ToDictionary(spec => spec.Version));
#endregion // Static member variables
- static FrameworkLocationHelper()
- {
- s_dotNetFrameworkSpecDict = s_dotNetFrameworkSpecs.ToDictionary(spec => spec.Version);
- s_visualStudioSpecDict = s_visualStudioSpecs.ToDictionary(spec => spec.Version);
- }
-
#region Static properties
internal static string PathToDotNetFrameworkV11
@@ -1118,13 +1112,13 @@ private static string FindRegistryValueUnderKey
private static VisualStudioSpec GetVisualStudioSpec(Version version)
{
- ErrorUtilities.VerifyThrowArgument(s_visualStudioSpecDict.TryGetValue(version, out VisualStudioSpec spec), "FrameworkLocationHelper.UnsupportedVisualStudioVersion", version);
+ ErrorUtilities.VerifyThrowArgument(VisualStudioSpecDict.Value.TryGetValue(version, out VisualStudioSpec spec), "FrameworkLocationHelper.UnsupportedVisualStudioVersion", version);
return spec;
}
private static DotNetFrameworkSpec GetDotNetFrameworkSpec(Version version)
{
- ErrorUtilities.VerifyThrowArgument(s_dotNetFrameworkSpecDict.TryGetValue(version, out DotNetFrameworkSpec spec), "FrameworkLocationHelper.UnsupportedFrameworkVersion", version);
+ ErrorUtilities.VerifyThrowArgument(DotNetFrameworkSpecDict.Value.TryGetValue(version, out DotNetFrameworkSpec spec), "FrameworkLocationHelper.UnsupportedFrameworkVersion", version);
return spec;
}
@@ -1473,11 +1467,11 @@ public virtual string GetPathToDotNetFrameworkSdkTools(VisualStudioSpec visualSt
// i.e. fallback to v110 if the current visual studio version is v120.
if (!foundExplicitRule)
{
- int index = Array.IndexOf(s_visualStudioSpecs, visualStudioSpec);
+ int index = Array.IndexOf(VisualStudioSpecs.Value, visualStudioSpec);
if (index > 0)
{
// The items in the array "visualStudioSpecs" must be ordered by version. That would allow us to fallback to the previous visual studio version easily.
- VisualStudioSpec fallbackVisualStudioSpec = s_visualStudioSpecs[index - 1];
+ VisualStudioSpec fallbackVisualStudioSpec = VisualStudioSpecs.Value[index - 1];
generatedPathToDotNetFrameworkSdkTools = FallbackToPathToDotNetFrameworkSdkToolsInPreviousVersion(
this.Version,
fallbackVisualStudioSpec.Version);
@@ -1570,10 +1564,8 @@ public virtual string GetPathToWindowsSdk()
#if FEATURE_WIN32_REGISTRY
private static string FallbackToPathToDotNetFrameworkSdkToolsInPreviousVersion(Version dotNetFrameworkVersion, Version visualStudioVersion)
{
- VisualStudioSpec visualStudioSpec;
- DotNetFrameworkSpec dotNetFrameworkSpec;
- if (s_visualStudioSpecDict.TryGetValue(visualStudioVersion, out visualStudioSpec)
- && s_dotNetFrameworkSpecDict.TryGetValue(dotNetFrameworkVersion, out dotNetFrameworkSpec)
+ if (VisualStudioSpecDict.Value.TryGetValue(visualStudioVersion, out VisualStudioSpec visualStudioSpec)
+ && DotNetFrameworkSpecDict.Value.TryGetValue(dotNetFrameworkVersion, out DotNetFrameworkSpec dotNetFrameworkSpec)
&& visualStudioSpec.SupportedDotNetFrameworkVersions.Contains(dotNetFrameworkVersion))
{
return dotNetFrameworkSpec.GetPathToDotNetFrameworkSdkTools(visualStudioSpec);
diff --git a/src/Shared/MSBuildNameIgnoreCaseComparer.cs b/src/Shared/MSBuildNameIgnoreCaseComparer.cs
index 47beaffd08c..f02c8c5cada 100644
--- a/src/Shared/MSBuildNameIgnoreCaseComparer.cs
+++ b/src/Shared/MSBuildNameIgnoreCaseComparer.cs
@@ -22,16 +22,7 @@ internal class MSBuildNameIgnoreCaseComparer : IConstrainedEqualityComparer
/// The processor architecture on which we are running, but default it will be x86
///
- private static readonly NativeMethodsShared.ProcessorArchitectures s_runningProcessorArchitecture;
-
- ///
- /// We need a static constructor to retrieve the running ProcessorArchitecture that way we can
- /// avoid using optimized code that will not run correctly on IA64 due to alignment issues
- ///
- static MSBuildNameIgnoreCaseComparer()
- {
- s_runningProcessorArchitecture = NativeMethodsShared.ProcessorArchitecture;
- }
+ private static readonly NativeMethodsShared.ProcessorArchitectures s_runningProcessorArchitecture = NativeMethodsShared.ProcessorArchitecture;
///
/// The default immutable comparer instance.
diff --git a/src/Shared/TypeLoader.cs b/src/Shared/TypeLoader.cs
index d296c8c7547..fe5ea680c49 100644
--- a/src/Shared/TypeLoader.cs
+++ b/src/Shared/TypeLoader.cs
@@ -23,7 +23,7 @@ internal class TypeLoader
///
/// AssemblyContextLoader used to load DLLs outside of msbuild.exe directory
///
- private static readonly CoreClrAssemblyLoader s_coreClrAssemblyLoader;
+ private static readonly CoreClrAssemblyLoader s_coreClrAssemblyLoader = new CoreClrAssemblyLoader();
#endif
///
@@ -41,13 +41,6 @@ internal class TypeLoader
///
private Func _isDesiredType;
-#if FEATURE_ASSEMBLYLOADCONTEXT
- static TypeLoader()
- {
- s_coreClrAssemblyLoader = new CoreClrAssemblyLoader();
- }
-#endif
-
///
/// Constructor.
///
diff --git a/src/Tasks/CultureInfoCache.cs b/src/Tasks/CultureInfoCache.cs
index 4955e8a766e..a5c52d41275 100644
--- a/src/Tasks/CultureInfoCache.cs
+++ b/src/Tasks/CultureInfoCache.cs
@@ -19,35 +19,34 @@ namespace Microsoft.Build.Tasks
///
internal static class CultureInfoCache
{
- private static readonly HashSet ValidCultureNames;
+ private static readonly HashSet ValidCultureNames = InitializeValidCultureNames();
- static CultureInfoCache()
+ static HashSet InitializeValidCultureNames()
{
- ValidCultureNames = new HashSet(StringComparer.OrdinalIgnoreCase);
-
#if !FEATURE_CULTUREINFO_GETCULTURES
if (!AssemblyUtilities.CultureInfoHasGetCultures())
{
- ValidCultureNames = HardcodedCultureNames;
- return;
+ return HardcodedCultureNames;
}
#endif
-
+ HashSet validCultureNames = new(StringComparer.OrdinalIgnoreCase);
foreach (CultureInfo cultureName in AssemblyUtilities.GetAllCultures())
{
- ValidCultureNames.Add(cultureName.Name);
+ validCultureNames.Add(cultureName.Name);
}
// https://docs.microsoft.com/en-gb/windows/desktop/Intl/using-pseudo-locales-for-localization-testing
// These pseudo-locales are available in versions of Windows from Vista and later.
// However, from Windows 10, version 1803, they are not returned when enumerating the
// installed cultures, even if the registry keys are set. Therefore, add them to the list manually.
- var pseudoLocales = new[] { "qps-ploc", "qps-ploca", "qps-plocm", "qps-Latn-x-sh" };
+ string[] pseudoLocales = new[] { "qps-ploc", "qps-ploca", "qps-plocm", "qps-Latn-x-sh" };
foreach (string pseudoLocale in pseudoLocales)
{
- ValidCultureNames.Add(pseudoLocale);
+ validCultureNames.Add(pseudoLocale);
}
+
+ return validCultureNames;
}
///
diff --git a/src/Tasks/GenerateResource.cs b/src/Tasks/GenerateResource.cs
index e5cb2b89c17..8d14a11f700 100644
--- a/src/Tasks/GenerateResource.cs
+++ b/src/Tasks/GenerateResource.cs
@@ -546,29 +546,6 @@ public GenerateResource()
// do nothing
}
-#if FEATURE_COM_INTEROP
- ///
- /// Static constructor checks the registry opt-out for mark-of-the-web rejection.
- ///
- static GenerateResource()
- {
- if (!NativeMethodsShared.IsWindows)
- {
- allowMOTW = true;
- return;
- }
- try
- {
- object allowUntrustedFiles = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\SDK", "AllowProcessOfUntrustedResourceFiles", null);
- if (allowUntrustedFiles is string allowUntrustedFilesString)
- {
- allowMOTW = allowUntrustedFilesString.Equals("true", StringComparison.OrdinalIgnoreCase);
- }
- }
- catch { }
- }
-#endif
-
///
/// Logs a Resgen.exe command line that indicates what parameters were
/// passed to this task. Since this task is replacing Resgen, and we used
@@ -931,7 +908,7 @@ public override bool Execute()
}
#if FEATURE_COM_INTEROP
- private static bool allowMOTW;
+ private static readonly bool AllowMOTW = !NativeMethodsShared.IsWindows || (Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\SDK", "AllowProcessOfUntrustedResourceFiles", null) is string allowUntrustedFiles && allowUntrustedFiles.Equals("true", StringComparison.OrdinalIgnoreCase));
private const string CLSID_InternetSecurityManager = "7b8a2d94-0ac9-11d1-896c-00c04fb6bfc4";
private const uint ZoneInternet = 3;
@@ -942,7 +919,7 @@ public override bool Execute()
private bool IsDangerous(String filename)
{
// If they are opted out, there's no work to do
- if (allowMOTW)
+ if (AllowMOTW)
{
return false;
}
diff --git a/src/Tasks/GetFrameworkPath.cs b/src/Tasks/GetFrameworkPath.cs
index 999bd44f434..5793e004a7c 100644
--- a/src/Tasks/GetFrameworkPath.cs
+++ b/src/Tasks/GetFrameworkPath.cs
@@ -14,26 +14,6 @@ namespace Microsoft.Build.Tasks
///
public class GetFrameworkPath : TaskExtension
{
- static GetFrameworkPath()
- {
- s_path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Latest));
- s_version11Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version11));
- s_version20Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version20));
- s_version30Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version30));
- s_version35Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version35));
- s_version40Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version40));
- s_version45Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version45));
- s_version451Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version451));
- s_version452Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version452));
- s_version46Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version46));
- s_version461Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version461));
- s_version462Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version462));
- s_version47Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version47));
- s_version471Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version471));
- s_version472Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version472));
- s_version48Path = new Lazy(() => ToolLocationHelper.GetPathToDotNetFramework(TargetDotNetFrameworkVersion.Version48));
- }
-
#region ITask Members
///
@@ -52,23 +32,22 @@ public override bool Execute()
// it still seems to give an advantage perhaps because there is one less string copy.
// In a large build, this adds up.
// PERF NOTE: We also only find paths we are actually asked for (via