diff --git a/.editorconfig b/.editorconfig
index 5d7c4f0d..d16dbed0 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,48 +1,125 @@
+# EditorConfig is awesome:http://EditorConfig.org
+
+# top-most EditorConfig file
root = true
# Don't use tabs for indentation.
[*]
indent_style = space
-insert_final_newline = true
-trim_trailing_whitespace = true
+
+# (Please don't specify an indent_size here; that has too many unintended consequences.)
[*.yml]
indent_size = 2
indent_style = space
-[*.{xml,targets,props}]
+# Code files
+[*.{cs,csx,vb,vbx,h,cpp,idl}]
+indent_size = 4
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+# Xml project files
+[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,runsettings}]
indent_size = 2
-[*.cs]
-indent_style = space
-indent_size = 4
+# Xml config files
+[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
+indent_size = 2
-# Make Visual Studio consistent with SA1101 (use "this" prefix), but allow StyleCop to report it
-dotnet_style_qualification_for_field = true:silent
-dotnet_style_qualification_for_property = true:silent
-dotnet_style_qualification_for_method = true:silent
-dotnet_style_qualification_for_event = true:silent
+# JSON files
+[*.json]
+indent_size = 2
-# Make Visual Studio consistent with SA1121 (use predefined type), but allow StyleCop to report it
-dotnet_style_predefined_type_for_locals_parameters_members = true:silent
-dotnet_style_predefined_type_for_member_access = true:silent
-csharp_style_var_for_built_in_types = false:silent
-
-# Additional settings to make the Visual Studio formatter follow StyleCop
+# Dotnet code style settings:
+[*.{cs,vb}]
+# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
+dotnet_style_qualification_for_field = true:warning
+dotnet_style_qualification_for_property = true:warning
+dotnet_style_qualification_for_method = true:warning
+dotnet_style_qualification_for_event = true:warning
-csharp_preserve_single_line_blocks = true
-csharp_preserve_single_line_statements = false
+# Use language keywords instead of framework type names for type references
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
-# New line preferences
-csharp_new_line_before_open_brace = all
-csharp_new_line_before_else = true
-csharp_new_line_before_catch = true
-csharp_new_line_before_finally = true
-csharp_new_line_before_members_in_object_initializers = true
-csharp_new_line_before_members_in_anonymous_types = true
-csharp_new_line_within_query_expression_clauses = true
+# Suggest more modern language features when available
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+# Non-private static fields are PascalCase
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
+
+dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
+dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected internal, private protected
+dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
+
+dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
+
+# Constants are PascalCase
+dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
+dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style
+
+dotnet_naming_symbols.constants.applicable_kinds = field, local
+dotnet_naming_symbols.constants.required_modifiers = const
+
+dotnet_naming_style.constant_style.capitalization = pascal_case
+
+# Static fields are camelCase
+dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
+dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style
+
+dotnet_naming_symbols.static_fields.applicable_kinds = field
+dotnet_naming_symbols.static_fields.required_modifiers = static
+
+dotnet_naming_style.static_field_style.capitalization = camel_case
+
+# Instance fields are camelCase
+dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
+dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
+
+dotnet_naming_symbols.instance_fields.applicable_kinds = field
+
+dotnet_naming_style.instance_field_style.capitalization = camel_case
+
+# Locals and parameters are camelCase
+dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
+dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
+
+dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
+
+dotnet_naming_style.camel_case_style.capitalization = camel_case
+
+# Local functions are PascalCase
+dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
+dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
+
+dotnet_naming_symbols.local_functions.applicable_kinds = local_function
+
+dotnet_naming_style.local_function_style.capitalization = pascal_case
+
+# By default, name items with PascalCase
+dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
+dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
+
+dotnet_naming_symbols.all_members.applicable_kinds = *
+
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+
+# CSharp code style settings:
+[*.cs]
# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
@@ -50,29 +127,64 @@ csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
-# Space preferences
-csharp_space_after_cast = false
-csharp_space_after_colon_in_inheritance_clause = true
-csharp_space_after_comma = true
-csharp_space_after_dot = false
-csharp_space_after_keywords_in_control_flow_statements = true
-csharp_space_after_semicolon_in_for_statement = true
-csharp_space_around_binary_operators = before_and_after
-csharp_space_around_declaration_statements = do_not_ignore
-csharp_space_before_colon_in_inheritance_clause = true
-csharp_space_before_comma = false
-csharp_space_before_dot = false
-csharp_space_before_open_square_brackets = false
-csharp_space_before_semicolon_in_for_statement = false
-csharp_space_between_empty_square_brackets = false
-csharp_space_between_method_call_empty_parameter_list_parentheses = false
-csharp_space_between_method_call_name_and_opening_parenthesis = false
-csharp_space_between_method_call_parameter_list_parentheses = false
-csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
-csharp_space_between_method_declaration_name_and_open_parenthesis = false
-csharp_space_between_method_declaration_parameter_list_parentheses = false
-csharp_space_between_parentheses = false
-csharp_space_between_square_brackets = false
+# Prefer "var" everywhere
+csharp_style_var_for_built_in_types = true:suggestion
+csharp_style_var_when_type_is_apparent = true:suggestion
+csharp_style_var_elsewhere = false:warning
-# RS2008: Enable analyzer release tracking
-dotnet_diagnostic.RS2008.severity = none
+# Prefer method-like constructs to have a block body
+csharp_style_expression_bodied_methods = false:none
+csharp_style_expression_bodied_constructors = false:none
+csharp_style_expression_bodied_operators = false:none
+
+# Prefer property-like constructs to have an expression-body
+csharp_style_expression_bodied_properties = true:none
+csharp_style_expression_bodied_indexers = true:none
+csharp_style_expression_bodied_accessors = true:none
+
+# Suggest more modern language features when available
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Newline settings
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+
+# Blocks are allowed
+csharp_prefer_braces = true:silent
+
+[*.cs]
+
+# SA1130: Use lambda syntax
+dotnet_diagnostic.SA1130.severity = silent
+
+# SA1404: Code analysis suppression should have justification
+dotnet_diagnostic.SA1404.severity = suggestion
+
+# SA1600: Elements should be documented
+dotnet_diagnostic.SA1600.severity = none
+
+# SA1611: Element parameters should be documented
+dotnet_diagnostic.SA1611.severity = none
+
+# SA1615: Element return value should be documented
+dotnet_diagnostic.SA1615.severity = none
+
+# SA1601: Partial elements should be documented
+dotnet_diagnostic.SA1601.severity = none
+
+# SA1133: Do not combine attributes
+dotnet_diagnostic.SA1133.severity = none
+
+# SA1108: Block statements should not contain embedded comments
+dotnet_diagnostic.SA1108.severity = suggestion
+
+[*.sln]
+indent_style = tab
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 00000000..5ef3e402
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,50 @@
+
+
+ Debug
+ $(MSBuildThisFileDirectory)
+ $(RepoRootPath)obj\$(MSBuildProjectName)\
+ $(RepoRootPath)bin\$(MSBuildProjectName)\
+ $(RepoRootPath)bin\Packages\$(Configuration)\NuGet\
+ 8.0
+ enable
+ true
+
+ Microsoft
+ Microsoft
+ © Microsoft. All rights reserved.
+ MIT
+ https://github.com/Microsoft/vs-threading
+ true
+ true
+ true
+ snupkg
+
+ 2.0.61
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ https://github.com/microsoft/vs-threading/releases/tag/v$(Version)
+
+
+
+
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 00000000..8c119d54
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,2 @@
+
+
diff --git a/src/Microsoft.VisualStudio.Threading.sln b/Microsoft.VisualStudio.Threading.sln
similarity index 81%
rename from src/Microsoft.VisualStudio.Threading.sln
rename to Microsoft.VisualStudio.Threading.sln
index 0528b0dd..6e670456 100644
--- a/src/Microsoft.VisualStudio.Threading.sln
+++ b/Microsoft.VisualStudio.Threading.sln
@@ -3,37 +3,36 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28413.118
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Analyzers", "Microsoft.VisualStudio.Threading.Analyzers\Microsoft.VisualStudio.Threading.Analyzers.csproj", "{536F3F9A-B457-43B8-BC93-CE1C16959037}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Analyzers", "src\Microsoft.VisualStudio.Threading.Analyzers\Microsoft.VisualStudio.Threading.Analyzers.csproj", "{536F3F9A-B457-43B8-BC93-CE1C16959037}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Analyzers.Tests", "Microsoft.VisualStudio.Threading.Analyzers.Tests\Microsoft.VisualStudio.Threading.Analyzers.Tests.csproj", "{620ED702-B6DA-4454-BF3E-5494D3652724}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Analyzers.Tests", "test\Microsoft.VisualStudio.Threading.Analyzers.Tests\Microsoft.VisualStudio.Threading.Analyzers.Tests.csproj", "{620ED702-B6DA-4454-BF3E-5494D3652724}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{AA091F9F-B40A-466F-B09F-22EAD115996F}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
- ..\.vsts-ci.yml = ..\.vsts-ci.yml
- ..\azure-pipelines\build.yml = ..\azure-pipelines\build.yml
+ azure-pipelines\build.yml = azure-pipelines\build.yml
Directory.Build.props = Directory.Build.props
- ..\global.json = ..\global.json
- ..\nuget.config = ..\nuget.config
+ global.json = global.json
+ nuget.config = nuget.config
stylecop.json = stylecop.json
version.json = version.json
EndProjectSection
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Tests.Win7RegistryWatcher", "Microsoft.VisualStudio.Threading.Tests.Win7RegistryWatcher\Microsoft.VisualStudio.Threading.Tests.Win7RegistryWatcher.csproj", "{4961AA84-088C-46C0-BAC0-F9E87A9F03A7}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Tests.Win7RegistryWatcher", "test\Microsoft.VisualStudio.Threading.Tests.Win7RegistryWatcher\Microsoft.VisualStudio.Threading.Tests.Win7RegistryWatcher.csproj", "{4961AA84-088C-46C0-BAC0-F9E87A9F03A7}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading", "Microsoft.VisualStudio.Threading\Microsoft.VisualStudio.Threading.csproj", "{D9BB9FB6-3833-44E8-B7A7-DE729FCE214D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading", "src\Microsoft.VisualStudio.Threading\Microsoft.VisualStudio.Threading.csproj", "{D9BB9FB6-3833-44E8-B7A7-DE729FCE214D}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Tests", "Microsoft.VisualStudio.Threading.Tests\Microsoft.VisualStudio.Threading.Tests.csproj", "{CBEDB102-ABAE-40B1-AF3F-A6226DB6713D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Tests", "test\Microsoft.VisualStudio.Threading.Tests\Microsoft.VisualStudio.Threading.Tests.csproj", "{CBEDB102-ABAE-40B1-AF3F-A6226DB6713D}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IsolatedTestHost", "IsolatedTestHost\IsolatedTestHost.csproj", "{BA4643D8-E6B2-4DED-882F-4827F3AB6AB0}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IsolatedTestHost", "test\IsolatedTestHost\IsolatedTestHost.csproj", "{BA4643D8-E6B2-4DED-882F-4827F3AB6AB0}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Analyzers.CodeFixes", "Microsoft.VisualStudio.Threading.Analyzers.CodeFixes\Microsoft.VisualStudio.Threading.Analyzers.CodeFixes.csproj", "{3BDB8F46-A39C-422B-8B0E-89E98B83073F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Analyzers.CodeFixes", "src\Microsoft.VisualStudio.Threading.Analyzers.CodeFixes\Microsoft.VisualStudio.Threading.Analyzers.CodeFixes.csproj", "{3BDB8F46-A39C-422B-8B0E-89E98B83073F}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SosThreadingTools", "SosThreadingTools\SosThreadingTools.csproj", "{7177DEEE-D14D-4A4A-BF6E-8B0CDC26B624}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SosThreadingTools", "src\SosThreadingTools\SosThreadingTools.csproj", "{7177DEEE-D14D-4A4A-BF6E-8B0CDC26B624}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Analyzers.CSharp", "Microsoft.VisualStudio.Threading.Analyzers.CSharp\Microsoft.VisualStudio.Threading.Analyzers.CSharp.csproj", "{D5A0D627-7853-43F5-9AF4-E23D062C6ABA}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Analyzers.CSharp", "src\Microsoft.VisualStudio.Threading.Analyzers.CSharp\Microsoft.VisualStudio.Threading.Analyzers.CSharp.csproj", "{D5A0D627-7853-43F5-9AF4-E23D062C6ABA}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Analyzers.VisualBasic", "Microsoft.VisualStudio.Threading.Analyzers.VisualBasic\Microsoft.VisualStudio.Threading.Analyzers.VisualBasic.csproj", "{8CDF7526-D625-4E16-A266-BAF654ABE181}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Threading.Analyzers.VisualBasic", "src\Microsoft.VisualStudio.Threading.Analyzers.VisualBasic\Microsoft.VisualStudio.Threading.Analyzers.VisualBasic.csproj", "{8CDF7526-D625-4E16-A266-BAF654ABE181}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/.vsts-ci.yml b/azure-pipelines.yml
similarity index 62%
rename from .vsts-ci.yml
rename to azure-pipelines.yml
index 85d0d1bd..b552774b 100644
--- a/.vsts-ci.yml
+++ b/azure-pipelines.yml
@@ -2,21 +2,23 @@ trigger:
branches:
include:
- master
- - 'v16.*'
+ - microbuild
- 'validate/*'
paths:
- exclude: [".github", "doc", "*.md"]
+ exclude:
+ - doc/
+ - '*.md'
+ - .vscode/
+ - .github/
variables:
TreatWarningsAsErrors: true
- UpdateXlfOnBuild: false # force build breaks if xlf files aren't updated on dev box with resx changes
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
BuildConfiguration: Release
- BuildPlatform: Any CPU
+ # codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/
NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages
jobs:
- template: azure-pipelines/build.yml
parameters:
- SignType:
ShouldSkipOptimize:
diff --git a/azure-pipelines/Convert-PDB.ps1 b/azure-pipelines/Convert-PDB.ps1
index 00549f71..a3212213 100644
--- a/azure-pipelines/Convert-PDB.ps1
+++ b/azure-pipelines/Convert-PDB.ps1
@@ -1,6 +1,6 @@
<#
.SYNOPSIS
- Builds all projects in this repo.
+ Converts between Windows PDB and Portable PDB formats.
.PARAMETER DllPath
The path to the DLL whose PDB is to be converted.
.PARAMETER PdbPath
diff --git a/azure-pipelines/Darwin.runsettings b/azure-pipelines/Darwin.runsettings
new file mode 100644
index 00000000..b444e819
--- /dev/null
+++ b/azure-pipelines/Darwin.runsettings
@@ -0,0 +1 @@
+
diff --git a/azure-pipelines/Get-ProcDump.ps1 b/azure-pipelines/Get-ProcDump.ps1
new file mode 100644
index 00000000..1493fe4b
--- /dev/null
+++ b/azure-pipelines/Get-ProcDump.ps1
@@ -0,0 +1,14 @@
+<#
+.SYNOPSIS
+Downloads 32-bit and 64-bit procdump executables and returns the path to where they were installed.
+#>
+$version = '0.0.1'
+$baseDir = "$PSScriptRoot\..\obj\tools"
+$procDumpToolPath = "$baseDir\procdump.$version\bin"
+if (-not (Test-Path $procDumpToolPath)) {
+ if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null }
+ $baseDir = (Resolve-Path $baseDir).Path # Normalize it
+ & (& $PSScriptRoot\Get-NuGetTool.ps1) install procdump -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://api.nuget.org/v3/index.json | Out-Null
+}
+
+(Resolve-Path $procDumpToolPath).Path
diff --git a/azure-pipelines/Get-TempToolsPath.ps1 b/azure-pipelines/Get-TempToolsPath.ps1
index 97c552c0..bb3da8e3 100644
--- a/azure-pipelines/Get-TempToolsPath.ps1
+++ b/azure-pipelines/Get-TempToolsPath.ps1
@@ -1,7 +1,7 @@
-if ($env:AGENT_TOOLSDIRECTORY) {
- $path = "$env:AGENT_TOOLSDIRECTORY\vs-platform\tools"
+if ($env:AGENT_TEMPDIRECTORY) {
+ $path = "$env:AGENT_TEMPDIRECTORY\$env:BUILD_BUILDID"
} elseif ($env:localappdata) {
- $path = "$env:localappdata\vs-platform\tools"
+ $path = "$env:localappdata\gitrepos\tools"
} else {
$path = "$PSScriptRoot\..\obj\tools"
}
diff --git a/azure-pipelines/Get-nbgv.ps1 b/azure-pipelines/Get-nbgv.ps1
index 925eecdd..a5be2cf7 100644
--- a/azure-pipelines/Get-nbgv.ps1
+++ b/azure-pipelines/Get-nbgv.ps1
@@ -10,11 +10,7 @@ if ($existingTool) {
return $existingTool.Path
}
-if ($env:AGENT_TEMPDIRECTORY) {
- $toolInstallDir = "$env:AGENT_TEMPDIRECTORY/$env:BUILD_BUILDID"
-} else {
- $toolInstallDir = "$PSScriptRoot/../obj/tools"
-}
+$toolInstallDir = & "$PSScriptRoot/Get-TempToolsPath.ps1"
$toolPath = "$toolInstallDir/nbgv"
if (!(Test-Path $toolInstallDir)) { New-Item -Path $toolInstallDir -ItemType Directory | Out-Null }
diff --git a/azure-pipelines/Linux.runsettings b/azure-pipelines/Linux.runsettings
new file mode 100644
index 00000000..b444e819
--- /dev/null
+++ b/azure-pipelines/Linux.runsettings
@@ -0,0 +1 @@
+
diff --git a/azure-pipelines/OptProf.yml b/azure-pipelines/OptProf.yml
index 2229935f..b2d88351 100644
--- a/azure-pipelines/OptProf.yml
+++ b/azure-pipelines/OptProf.yml
@@ -1,20 +1,21 @@
trigger: none
pr: none
schedules:
-- cron: "0 3 * * Tue" # Mon @ 8 or 9 PM Mountain Time (depending on DST)
- displayName: Weekly OptProf run
- branches:
- include:
- - 'v16.*'
- - master
- always: true # we must keep data fresh since optimizationdata drops are purged after 30 days
+ - cron: "0 3 * * Tue" # Mon @ 8 or 9 PM Mountain Time (depending on DST)
+ displayName: Weekly OptProf run
+ branches:
+ include:
+ - 'v1*'
+ - master
+ always: true # we must keep data fresh since optimizationdata drops are purged after 30 days
-resources:
- repositories:
- - repository: scripts
- type: git
- name: DeploymentScripts
- ref: refs/heads/test
+# Avoid errant CI builds: https://developercommunity.visualstudio.com/content/problem/1154409/azure-pipeline-is-triggering-due-to-events-that-ne.html
+#resources:
+# repositories:
+# - repository: scripts
+# type: git
+# name: DeploymentScripts
+# ref: refs/heads/test
variables:
- name: TreatWarningsAsErrors
@@ -31,6 +32,8 @@ variables:
value: true
- name: PublicRelease
value: false # avoid using nice version since we're building a preliminary/unoptimized package
+- name: SignType
+ value: real
- group: Library.Template
stages:
@@ -41,12 +44,11 @@ stages:
- template: build.yml
parameters:
windowsPool: VSEng-MicroBuildVS2019
- SignType: real
ShouldSkipOptimize: true
- stage: QueueVSBuild
jobs:
- job: QueueOptProf
- pool: VSEng-RMPool
+ pool: VSEng-ReleasePool
variables:
InsertPayloadName: vs-threading
InsertTopicBranch: team/VS-IDE/vs-threading-OptProf-run-$(Build.BuildId)
diff --git a/azure-pipelines/Set-EnvVars.ps1 b/azure-pipelines/Set-EnvVars.ps1
deleted file mode 100644
index 313cecff..00000000
--- a/azure-pipelines/Set-EnvVars.ps1
+++ /dev/null
@@ -1,39 +0,0 @@
-<#
-.SYNOPSIS
- Set environment variables in the environment.
- Azure Pipeline and CMD environments are considered.
-.PARAMETER Variables
- A hashtable of variables to be set.
-.OUTPUTS
- A boolean indicating whether the environment variables can be expected to propagate to the caller's environment.
-#>
-[CmdletBinding(SupportsShouldProcess=$true)]
-Param(
- [Parameter(Mandatory=$true, Position=1)]
- $Variables
-)
-
-if ($Variables.Count -eq 0) {
- return $true
-}
-
-$cmdInstructions = !$env:TF_BUILD -and $env:PS1UnderCmd -eq '1'
-if ($cmdInstructions) {
- Write-Warning "Environment variables have been set that will be lost because you're running under cmd.exe"
- Write-Host "Environment variables that must be set manually:" -ForegroundColor Blue
-}
-
-$Variables.GetEnumerator() |% {
- Set-Item -Path env:$($_.Key) -Value $_.Value
-
- # If we're running in Azure Pipelines, set these environment variables
- if ($env:TF_BUILD) {
- Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)"
- }
-
- if ($cmdInstructions) {
- Write-Host "SET $($_.Key)=$($_.Value)"
- }
-}
-
-return !$cmdInstructions
diff --git a/azure-pipelines/Windows_NT.runsettings b/azure-pipelines/Windows_NT.runsettings
new file mode 100644
index 00000000..0b43ecb0
--- /dev/null
+++ b/azure-pipelines/Windows_NT.runsettings
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+ %BUILD_ARTIFACTSTAGINGDIRECTORY%
+
+
+
+
+
diff --git a/azure-pipelines/artifacts/Variables.ps1 b/azure-pipelines/artifacts/Variables.ps1
index cfcb7df5..c6330cd3 100644
--- a/azure-pipelines/artifacts/Variables.ps1
+++ b/azure-pipelines/artifacts/Variables.ps1
@@ -2,18 +2,21 @@
# It "snaps" the values of these variables where we can compute them during the build,
# and otherwise captures the scripts to run later during an Azure Pipelines environment release.
-$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..")
-$ArtifactBasePath = "$RepoRoot\obj\_artifacts"
-$VariablesArtifactPath = "$ArtifactBasePath\variables"
+$RepoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot (Join-Path .. ..)))
+$ArtifactBasePath = Join-Path $RepoRoot (Join-Path obj _artifacts)
+$VariablesArtifactPath = Join-Path $ArtifactBasePath variables
if (-not (Test-Path $VariablesArtifactPath)) { New-Item -ItemType Directory -Path $VariablesArtifactPath | Out-Null }
# Copy variables, either by value if the value is calculable now, or by script
-Get-ChildItem -Path "$PSScriptRoot\..\variables" |% {
+Get-ChildItem -Path (Join-Path $PSScriptRoot (Join-Path .. variables)) |% {
$value = $null
if (-not $_.BaseName.StartsWith('_')) { # Skip trying to interpret special scripts
# First check the environment variables in case the variable was set in a queued build
- if (Test-Path env:$($_.BaseName)) {
- $value = Get-Content "env:$($_.BaseName)"
+ # Always use all caps for env var access because Azure Pipelines converts variables to upper-case for env vars,
+ # and on non-Windows env vars are case sensitive.
+ $envVarName = $_.BaseName.ToUpper()
+ if (Test-Path env:$envVarName) {
+ $value = Get-Content "env:$envVarName"
}
# If that didn't give us anything, try executing the script right now from its original position
@@ -32,7 +35,7 @@ Get-ChildItem -Path "$PSScriptRoot\..\variables" |% {
$value = Get-Content -Path $_.FullName
}
- Set-Content -Path "$VariablesArtifactPath\$($_.Name)" -Value $value
+ Set-Content -Path (Join-Path $VariablesArtifactPath $_.Name) -Value $value
}
@{
diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1
old mode 100644
new mode 100755
index 9b030058..efd6bdb3
--- a/azure-pipelines/artifacts/_all.ps1
+++ b/azure-pipelines/artifacts/_all.ps1
@@ -1,3 +1,5 @@
+#!/usr/bin/env pwsh
+
# This script returns all the artifacts that should be collected after a build.
#
# Each powershell artifact is expressed as an object with these properties:
@@ -22,14 +24,13 @@ Function EnsureTrailingSlash($path) {
Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse |% {
$ArtifactName = $_.BaseName
- Write-Host "Collecting files for the $ArtifactName artifact"
$fileGroups = & $_
if (!$fileGroups -or $fileGroups.Count -eq 0) {
Write-Warning "No files found for the `"$ArtifactName`" artifact."
} else {
$fileGroups.GetEnumerator() | % {
- $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key), [UriKind]::Absolute)
+ $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key.ToString()), [UriKind]::Absolute)
$_.Value | % {
if ($_.GetType() -eq [IO.FileInfo] -or $_.GetType() -eq [IO.DirectoryInfo]) {
$_ = $_.FullName
diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1
index 4e9ef21a..5bca7c6c 100644
--- a/azure-pipelines/artifacts/_pipelines.ps1
+++ b/azure-pipelines/artifacts/_pipelines.ps1
@@ -5,51 +5,6 @@ param (
[string]$ArtifactNameSuffix
)
-$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..")
-if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) {
- $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY
-} else {
- $ArtifactStagingFolder = "$RepoRoot\obj\_artifacts"
- if (Test-Path $ArtifactStagingFolder) {
- Remove-Item $ArtifactStagingFolder -Recurse -Force
- }
-}
-
-function Create-SymbolicLink {
- param (
- $Link,
- $Target
- )
-
- if ($Link -eq $Target) {
- return
- }
-
- if (Test-Path $Link) { Remove-Item $Link }
- $LinkContainer = Split-Path $Link -Parent
- if (!(Test-Path $LinkContainer)) { mkdir $LinkContainer }
- Write-Verbose "Linking $Link to $Target"
- if ($IsMacOS -or $IsLinux) {
- ln $Target $Link | Out-Null
- } else {
- cmd /c "mklink `"$Link`" `"$Target`"" | Out-Null
- }
-}
-
-# Stage all artifacts
-$Artifacts = & "$PSScriptRoot\_all.ps1"
-$Artifacts |% {
- $DestinationFolder = (Join-Path (Join-Path $ArtifactStagingFolder "$($_.ArtifactName)$ArtifactNameSuffix") $_.ContainerFolder).TrimEnd('\')
- $Name = "$(Split-Path $_.Source -Leaf)"
-
- #Write-Host "$($_.Source) -> $($_.ArtifactName)\$($_.ContainerFolder)" -ForegroundColor Yellow
-
- if (-not (Test-Path $DestinationFolder)) { New-Item -ItemType Directory -Path $DestinationFolder | Out-Null }
- if (Test-Path -PathType Leaf $_.Source) { # skip folders
- Create-SymbolicLink -Link "$DestinationFolder\$Name" -Target $_.Source
- }
-}
-
-$Artifacts |% { $_.ArtifactName } | Get-Unique |% {
- Write-Host "##vso[artifact.upload containerfolder=$_$ArtifactNameSuffix;artifactname=$_$ArtifactNameSuffix;]$ArtifactStagingFolder/$_$ArtifactNameSuffix"
+& "$PSScriptRoot/_stage_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix |% {
+ Write-Host "##vso[artifact.upload containerfolder=$($_.Name);artifactname=$($_.Name);]$($_.Path)"
}
diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1
new file mode 100644
index 00000000..4e6a6dbe
--- /dev/null
+++ b/azure-pipelines/artifacts/_stage_all.ps1
@@ -0,0 +1,59 @@
+# This script links all the artifacts described by _all.ps1
+# into a staging directory, reading for uploading to a cloud build artifact store.
+# It returns a sequence of objects with Name and Path properties.
+
+param (
+ [string]$ArtifactNameSuffix
+)
+
+$RepoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot (Join-Path .. ..)))
+if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) {
+ $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY
+} else {
+ $ArtifactStagingFolder = Join-Path $RepoRoot (Join-Path obj _artifacts)
+ if (Test-Path $ArtifactStagingFolder) {
+ Remove-Item $ArtifactStagingFolder -Recurse -Force
+ }
+}
+
+function Create-SymbolicLink {
+ param (
+ $Link,
+ $Target
+ )
+
+ if ($Link -eq $Target) {
+ return
+ }
+
+ if (Test-Path $Link) { Remove-Item $Link }
+ $LinkContainer = Split-Path $Link -Parent
+ if (!(Test-Path $LinkContainer)) { mkdir $LinkContainer }
+ Write-Verbose "Linking $Link to $Target"
+ if ($IsMacOS -or $IsLinux) {
+ ln $Target $Link | Out-Null
+ } else {
+ cmd /c "mklink `"$Link`" `"$Target`"" | Out-Null
+ }
+}
+
+# Stage all artifacts
+$Artifacts = & "$PSScriptRoot\_all.ps1"
+$Artifacts |% {
+ $DestinationFolder = (Join-Path (Join-Path $ArtifactStagingFolder "$($_.ArtifactName)$ArtifactNameSuffix") $_.ContainerFolder).TrimEnd('\')
+ $Name = "$(Split-Path $_.Source -Leaf)"
+
+ #Write-Host "$($_.Source) -> $($_.ArtifactName)\$($_.ContainerFolder)" -ForegroundColor Yellow
+
+ if (-not (Test-Path $DestinationFolder)) { New-Item -ItemType Directory -Path $DestinationFolder | Out-Null }
+ if (Test-Path -PathType Leaf $_.Source) { # skip folders
+ Create-SymbolicLink -Link (Join-Path $DestinationFolder $Name) -Target $_.Source
+ }
+}
+
+$Artifacts |% { "$($_.ArtifactName)$ArtifactNameSuffix" } | Get-Unique |% {
+ $artifact = New-Object -TypeName PSObject
+ Add-Member -InputObject $artifact -MemberType NoteProperty -Name Name -Value $_
+ Add-Member -InputObject $artifact -MemberType NoteProperty -Name Path -Value (Join-Path $ArtifactStagingFolder $_)
+ Write-Output $artifact
+}
diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1
new file mode 100644
index 00000000..1e4c4c4e
--- /dev/null
+++ b/azure-pipelines/artifacts/testResults.ps1
@@ -0,0 +1,12 @@
+if ($env:AGENT_TEMPDIRECTORY) {
+ # The DotNetCoreCLI uses an alternate location to publish these files
+ $guidRegex = '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$'
+ @{
+ $env:AGENT_TEMPDIRECTORY = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { Get-ChildItem "$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse });
+ }
+} else {
+ $testRoot = Resolve-Path "$PSScriptRoot\..\..\test"
+ @{
+ $testRoot = (Get-ChildItem "$testRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File);
+ }
+}
diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml
index 1d3b331d..b1a515cb 100644
--- a/azure-pipelines/build.yml
+++ b/azure-pipelines/build.yml
@@ -2,7 +2,6 @@ parameters:
- name: windowsPool
type: string
default: Hosted Windows 2019 with VS2019
-- name: SignType
- name: ShouldSkipOptimize
jobs:
@@ -13,13 +12,12 @@ jobs:
clean: true
- template: install-dependencies.yml
- - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud -p src'
+ - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud'
displayName: Set build number
- ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}:
- template: microbuild.before.yml
parameters:
- SignType: ${{ parameters.SignType }}
ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }}
- template: dotnet.yml
@@ -30,7 +28,7 @@ jobs:
- job: Linux
condition: ne(variables['OptProf'], 'true')
pool:
- vmImage: Ubuntu 16.04
+ vmImage: Ubuntu 18.04
steps:
- checkout: self
clean: true
@@ -53,8 +51,8 @@ jobs:
- Linux
- macOS
pool:
- vmImage: Ubuntu 16.04
- condition: ne(variables['OptProf'], 'true')
+ vmImage: Ubuntu 18.04
+ condition: succeededOrFailed()
steps:
- checkout: self
clean: true
diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml
index a0b12e54..94bfa045 100644
--- a/azure-pipelines/dotnet.yml
+++ b/azure-pipelines/dotnet.yml
@@ -1,44 +1,41 @@
steps:
-
# We use VSBuild instead of "dotnet build" on Windows where MicroBuild tasks have to run (since they don't support MSBuild Core yet).
- task: VSBuild@1
+ displayName: Build Visual Studio solution
inputs:
msbuildArgs: /t:build,pack /m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/msbuild.binlog"
platform: Any CPU
configuration: $(BuildConfiguration)
- displayName: Build Visual Studio solution
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
- script: dotnet build /t:build,pack --no-restore -c $(BuildConfiguration) /p:Platform=NonWindows /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog"
- displayName: dotnet build and pack
- workingDirectory: src
+ displayName: dotnet build & pack
condition: and(succeeded(), ne(variables['Agent.OS'], 'Windows_NT'))
- task: DotNetCoreCLI@2
displayName: dotnet test -f net472
inputs:
command: test
- arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true
+ arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings"
testRunTitle: net472-$(Agent.JobName)
- workingDirectory: src
condition: and(ne(variables['OptProf'], 'true'), eq(variables['Agent.OS'], 'Windows_NT'))
- task: DotNetCoreCLI@2
displayName: dotnet test -f netcoreapp2.1
inputs:
command: test
- arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true
+ arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings"
testRunTitle: netcoreapp2.1-$(Agent.JobName)
- workingDirectory: src/Microsoft.VisualStudio.Threading.Tests
+ workingDirectory: test/Microsoft.VisualStudio.Threading.Tests
condition: ne(variables['OptProf'], 'true')
- task: DotNetCoreCLI@2
displayName: dotnet test -f netcoreapp3.1
inputs:
command: test
- arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true
+ arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings"
testRunTitle: netcoreapp3.1-$(Agent.JobName)
- workingDirectory: src/Microsoft.VisualStudio.Threading.Tests
+ workingDirectory: test/Microsoft.VisualStudio.Threading.Tests
condition: ne(variables['OptProf'], 'true')
# We have to artifically run this script so that the extra .nupkg is produced for variables/InsertConfigValues.ps1 to notice.
@@ -46,23 +43,19 @@ steps:
displayName: Prepare VSInsertion artifact
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
-- task: PowerShell@2
- inputs:
- filePath: azure-pipelines/variables/_pipelines.ps1
- failOnStderr: true
+- powershell: azure-pipelines/variables/_pipelines.ps1
+ failOnStderr: true
displayName: Update pipeline variables based on build outputs
condition: succeededOrFailed()
-- task: PowerShell@2
- inputs:
- filePath: azure-pipelines/artifacts/_pipelines.ps1
- arguments: -ArtifactNameSuffix "-$(Agent.JobName)"
+- powershell: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)"
+ failOnStderr: true
displayName: Publish artifacts
condition: succeededOrFailed()
- task: PublishSymbols@2
inputs:
- SymbolsFolder: $(Build.ArtifactStagingDirectory)/symbols-Windows
+ SymbolsFolder: $(Build.ArtifactStagingDirectory)/symbols-$(Agent.JobName)
SearchPattern: '**/*.pdb'
IndexSources: false
SymbolServerType: TeamServices
diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml
index bef82f10..1883c125 100644
--- a/azure-pipelines/install-dependencies.yml
+++ b/azure-pipelines/install-dependencies.yml
@@ -4,7 +4,8 @@ parameters:
steps:
- powershell: |
- .\init.ps1 -AccessToken '$(System.AccessToken)' ${{ parameters['initArgs'] }}
+ $AccessToken = '$(System.AccessToken)' # Avoid specifying the access token directly on the init.ps1 command line to avoid it showing up in errors
+ .\init.ps1 -AccessToken $AccessToken ${{ parameters['initArgs'] }} -UpgradePrerequisites
dotnet --info
displayName: Install prerequisites
@@ -14,8 +15,7 @@ steps:
inputs:
versionSpec: 5.1.x
-- task: PowerShell@2
- inputs:
- filePath: azure-pipelines/variables/_pipelines.ps1
- failOnStderr: true
+- powershell: azure-pipelines/variables/_pipelines.ps1
+ failOnStderr: true
displayName: Set pipeline variables based on source
+ name: SetPipelineVariables
diff --git a/azure-pipelines/microbuild.after.yml b/azure-pipelines/microbuild.after.yml
index badd0bbc..e44ad21b 100644
--- a/azure-pipelines/microbuild.after.yml
+++ b/azure-pipelines/microbuild.after.yml
@@ -1,4 +1,10 @@
steps:
+- task: ms-vseng.MicroBuildShipTasks.7c429315-71ba-4cb3-94bb-f829c95f7915.MicroBuildCodesignVerify@2
+ displayName: Verify Signed Files
+ inputs:
+ TargetFolders: |
+ $(Build.SourcesDirectory)/bin/Packages/$(BuildConfiguration)/NuGet
+
- task: MicroBuildCleanup@1
condition: succeededOrFailed()
displayName: MicroBuild Cleanup
@@ -36,5 +42,5 @@ steps:
/repoName:$(Build.Repository.Name)
/additionalCodexArguments:-bld
/additionalCodexArguments:$(Build.ArtifactStagingDirectory)/build_logs
- condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
+ condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'), ne(variables['Build.Reason'], 'PullRequest'))
continueOnError: true
diff --git a/azure-pipelines/microbuild.before.yml b/azure-pipelines/microbuild.before.yml
index 8e30f75c..19e937a5 100644
--- a/azure-pipelines/microbuild.before.yml
+++ b/azure-pipelines/microbuild.before.yml
@@ -1,5 +1,4 @@
parameters:
-- name: SignType
- name: ShouldSkipOptimize
steps:
@@ -13,6 +12,6 @@ steps:
- task: MicroBuildSigningPlugin@2
inputs:
- signType: ${{ parameters.SignType }}
+ signType: $(SignType)
zipSources: false
displayName: Install MicroBuild Signing Plugin
diff --git a/azure-pipelines/official.yml b/azure-pipelines/official.yml
index c8640163..949addaf 100644
--- a/azure-pipelines/official.yml
+++ b/azure-pipelines/official.yml
@@ -5,10 +5,21 @@ trigger:
- 'v16.*'
- 'validate/*'
paths:
- exclude: [".github", "doc", "*.md", ".appveyor.yml", ".travis.yml"]
+ exclude:
+ - .github/
+ - doc/
+ - '*.md'
+ - .vscode/
+schedules:
+- cron: "0 3 * * *" # Daily @ 8 PM PST
+ displayName: Daily vs-insertion
+ branches:
+ include:
+ - master
+ - 'v16.*'
parameters:
-- name: SignType
+- name: SignTypeSelection
displayName: Sign type
type: string
default: Test
@@ -18,18 +29,75 @@ parameters:
type: boolean
default: false
-variables:
- TreatWarningsAsErrors: true
- UpdateXlfOnBuild: false # force build breaks if xlf files aren't updated on dev box with resx changes
- DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
- BuildConfiguration: Release
- BuildPlatform: Any CPU
- NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages
- SignType: ${{ parameters.SignType }}
+stages:
-jobs:
-- template: build.yml
- parameters:
- windowsPool: VSEng-MicroBuildVS2019
- SignType: ${{ parameters.SignType }}
- ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }}
+- stage: Build
+ variables:
+ TreatWarningsAsErrors: true
+ UpdateXlfOnBuild: false # force build breaks if xlf files aren't updated on dev box with resx changes
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+ BuildConfiguration: Release
+ BuildPlatform: Any CPU
+ NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages
+ SignTypeSelection: ${{ parameters.SignTypeSelection }}
+ jobs:
+ - template: build.yml
+ parameters:
+ windowsPool: VSEng-MicroBuildVS2019
+ ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }}
+
+- stage: symbol_archive
+ displayName: Symbol archival
+ condition: and(succeeded(), eq(dependencies.Build.outputs['Windows.SetPipelineVariables.SignType'], 'Real'))
+ jobs:
+ - job: archive
+ pool: VSEng-ReleasePool
+ steps:
+ - download: current
+ artifact: Variables-Windows
+ displayName: Download Variables-Windows artifact
+ - task: PowerShell@2
+ displayName: Set VSTS variables based on artifacts
+ inputs:
+ targetType: filePath
+ filePath: $(Pipeline.Workspace)/Variables-Windows/_pipelines.ps1
+ - download: current
+ artifact: symbols-Windows
+ displayName: Download symbols-Windows artifact
+ - task: MicroBuildArchiveSymbols@1
+ displayName: Archive $(SymbolsFeatureName) on Symweb
+ inputs:
+ SymbolsFeatureName: $(SymbolsFeatureName)
+ SymbolsSymwebProject: VS
+ SymbolsUncPath: \\cpvsbuild\drops\$(TeamName)\$(Build.DefinitionName)\$(Build.SourceBranchName)\$(Build.BuildNumber)\Symbols.Archival
+ SymbolsEmailContacts: vsidemicrobuild
+ SymbolsAgentPath: $(Pipeline.Workspace)/symbols-Windows
+ - task: MicroBuildCleanup@1
+ displayName: Send Telemetry
+
+- stage: azure_public_vssdk_feed
+ displayName: azure-public/vssdk feed
+ condition: and(succeeded(), eq(dependencies.Build.outputs['Windows.SetPipelineVariables.SignType'], 'Real'))
+ jobs:
+ - deployment: push
+ pool:
+ vmImage: ubuntu-latest
+ environment: No-Approval
+ strategy:
+ runOnce:
+ deploy:
+ steps:
+ - download: current
+ artifact: deployables-Windows
+ displayName: Download deployables-Windows artifact
+ - task: NuGetToolInstaller@1
+ displayName: Use NuGet 5.x
+ inputs:
+ versionSpec: 5.x
+ - task: NuGetCommand@2
+ displayName: NuGet push
+ inputs:
+ command: push
+ packagesToPush: $(Pipeline.Workspace)/deployables-Windows/NuGet/*.nupkg
+ nuGetFeedType: external
+ publishFeedCredentials: azure-public/vssdk
diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml
index 481762d4..9cb41fc6 100644
--- a/azure-pipelines/publish-deployables.yml
+++ b/azure-pipelines/publish-deployables.yml
@@ -3,6 +3,11 @@ steps:
displayName: Download deployables
artifact: deployables-Windows
+- task: NuGetToolInstaller@1
+ displayName: Use NuGet 5.x
+ inputs:
+ versionSpec: 5.x
+
- task: NuGetCommand@2
displayName: Push packages to CI feed
inputs:
diff --git a/azure-pipelines/release-deployment-prep.yml b/azure-pipelines/release-deployment-prep.yml
new file mode 100644
index 00000000..6dee28e5
--- /dev/null
+++ b/azure-pipelines/release-deployment-prep.yml
@@ -0,0 +1,9 @@
+steps:
+- download: CI
+ artifact: Variables-Windows
+ displayName: Download Variables-Windows artifact
+- task: PowerShell@2
+ displayName: Set VSTS variables based on artifacts
+ inputs:
+ targetType: filePath
+ filePath: $(Pipeline.Workspace)/CI/Variables-Windows/_pipelines.ps1
diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml
new file mode 100644
index 00000000..3058512c
--- /dev/null
+++ b/azure-pipelines/release.yml
@@ -0,0 +1,72 @@
+trigger: none # We only want to trigger manually or based on resources
+pr: none
+
+resources:
+ pipelines:
+ - pipeline: CI
+ source: Library # TODO: This should match the name of your CI pipeline
+ trigger:
+ tags:
+ - auto-release
+
+stages:
+- stage: GitHubRelease
+ displayName: GitHub Release
+ jobs:
+ - deployment: create
+ pool:
+ vmImage: ubuntu-latest
+ environment: No-Approval
+ strategy:
+ runOnce:
+ deploy:
+ steps:
+ - download: none
+ - powershell: |
+ Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)"
+ displayName: Set pipeline name
+ - task: GitHubRelease@1
+ displayName: GitHub release (create)
+ inputs:
+ gitHubConnection: AArnott
+ repositoryName: $(Build.Repository.Name)
+ target: $(resources.pipeline.CI.sourceCommit)
+ tagSource: userSpecifiedTag
+ tag: v$(resources.pipeline.CI.runName)
+ title: v$(resources.pipeline.CI.runName)
+ isDraft: true # After running this step, visit the new draft release, edit, and publish.
+ changeLogCompareToRelease: lastNonDraftRelease
+ changeLogType: issueBased
+ changeLogLabels: |
+ [
+ { "label" : "bug", "displayName" : "Fixes", "state" : "closed" },
+ { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" }
+ ]
+
+- stage: nuget_org
+ displayName: nuget.org
+ dependsOn: GitHubRelease
+ jobs:
+ - deployment: push
+ pool:
+ vmImage: ubuntu-latest
+ environment: No-Approval
+ strategy:
+ runOnce:
+ deploy:
+ steps:
+ - download: CI
+ artifact: deployables-Windows
+ displayName: Download deployables-Windows artifact
+ patterns: 'deployables-Windows/*'
+ - task: NuGetToolInstaller@1
+ displayName: Use NuGet 5.x
+ inputs:
+ versionSpec: 5.x
+ - task: NuGetCommand@2
+ displayName: NuGet push
+ inputs:
+ command: push
+ packagesToPush: $(Pipeline.Workspace)/CI/deployables-Windows/NuGet/*.nupkg
+ nuGetFeedType: external
+ publishFeedCredentials: VisualStudioExtensibility (nuget.org)
diff --git a/azure-pipelines/schedule-only-steps.yml b/azure-pipelines/schedule-only-steps.yml
new file mode 100644
index 00000000..ad07a341
--- /dev/null
+++ b/azure-pipelines/schedule-only-steps.yml
@@ -0,0 +1,3 @@
+steps:
+- powershell: echo "##vso[build.addbuildtag]auto-insertion"
+ displayName: Tag for auto-insertion
diff --git a/azure-pipelines/variables/InsertConfigValues.ps1 b/azure-pipelines/variables/InsertConfigValues.ps1
index c3e86989..72c8697f 100644
--- a/azure-pipelines/variables/InsertConfigValues.ps1
+++ b/azure-pipelines/variables/InsertConfigValues.ps1
@@ -1,4 +1,4 @@
-$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin\Packages\$env:BuildConfiguration")
+$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin\Packages\$env:BUILDCONFIGURATION")
$dirsToSearch = "$BinPath\NuGet\*.nupkg","$BinPath\CoreXT\*.nupkg" |? { Test-Path $_ }
$icv=@()
diff --git a/azure-pipelines/variables/InsertReviewers.ps1 b/azure-pipelines/variables/InsertReviewers.ps1
new file mode 100644
index 00000000..67ec2d89
--- /dev/null
+++ b/azure-pipelines/variables/InsertReviewers.ps1
@@ -0,0 +1 @@
+'Andrew Arnott'
diff --git a/azure-pipelines/variables/ShouldSkipOptimize.ps1 b/azure-pipelines/variables/ShouldSkipOptimize.ps1
new file mode 100644
index 00000000..65b670db
--- /dev/null
+++ b/azure-pipelines/variables/ShouldSkipOptimize.ps1
@@ -0,0 +1 @@
+'false'
diff --git a/azure-pipelines/variables/SignType.ps1 b/azure-pipelines/variables/SignType.ps1
new file mode 100644
index 00000000..663d8d49
--- /dev/null
+++ b/azure-pipelines/variables/SignType.ps1
@@ -0,0 +1,12 @@
+if ($env:SYSTEM_COLLECTIONID -eq '011b8bdf-6d56-4f87-be0d-0092136884d9') {
+ if ($env:BUILD_REASON -eq 'Schedule') {
+ 'real'
+ } else {
+ if ($env:SignTypeSelection) {
+ $env:SignTypeSelection
+ } else {
+ 'test'
+ }
+ }
+ }
+
\ No newline at end of file
diff --git a/azure-pipelines/variables/TeamEmail.ps1 b/azure-pipelines/variables/TeamEmail.ps1
new file mode 100644
index 00000000..7cf66982
--- /dev/null
+++ b/azure-pipelines/variables/TeamEmail.ps1
@@ -0,0 +1 @@
+'vsidemicrobuild@microsoft.com'
diff --git a/azure-pipelines/variables/_all.ps1 b/azure-pipelines/variables/_all.ps1
old mode 100644
new mode 100755
index ed099792..0407d307
--- a/azure-pipelines/variables/_all.ps1
+++ b/azure-pipelines/variables/_all.ps1
@@ -1,3 +1,5 @@
+#!/usr/bin/env pwsh
+
# This script returns a hashtable of build variables that should be set
# at the start of a build or release definition's execution.
diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1
index 9fa0c16b..55299550 100644
--- a/azure-pipelines/variables/_pipelines.ps1
+++ b/azure-pipelines/variables/_pipelines.ps1
@@ -5,11 +5,20 @@
# what the build would do. So only set them if they have not already been set.
(& "$PSScriptRoot\_all.ps1").GetEnumerator() |% {
- if (Test-Path -Path "env:$($_.Key.ToUpper())") {
- Write-Host "Skipping setting $($_.Key) because variable is already set." -ForegroundColor Cyan
+ # Always use ALL CAPS for env var names since Azure Pipelines converts variable names to all caps and on non-Windows OS, env vars are case sensitive.
+ $keyCaps = $_.Key.ToUpper()
+ if (Test-Path -Path "env:$keyCaps") {
+ Write-Host "Skipping setting $keyCaps because variable is already set to '$(Get-Content env:$keyCaps)'." -ForegroundColor Cyan
} else {
- Write-Host "$($_.Key)=$($_.Value)" -ForegroundColor Yellow
- Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)"
- Set-Item -Path "env:$($_.Key)" -Value $_.Value
+ Write-Host "$keyCaps=$($_.Value)" -ForegroundColor Yellow
+ if ($env:TF_BUILD) {
+ # Create two variables: the first that can be used by its simple name and accessible only within this job.
+ Write-Host "##vso[task.setvariable variable=$keyCaps]$($_.Value)"
+ # and the second that works across jobs and stages but must be fully qualified when referenced.
+ Write-Host "##vso[task.setvariable variable=$keyCaps;isOutput=true]$($_.Value)"
+ } elseif ($env:GITHUB_ACTIONS) {
+ Write-Host "::set-env name=$keyCaps::$($_.Value)"
+ }
+ Set-Item -Path "env:$keyCaps" -Value $_.Value
}
}
diff --git a/azure-pipelines/vs-insertion.yml b/azure-pipelines/vs-insertion.yml
new file mode 100644
index 00000000..9b23418d
--- /dev/null
+++ b/azure-pipelines/vs-insertion.yml
@@ -0,0 +1,50 @@
+trigger: none # We only want to trigger manually or based on resources
+pr: none
+
+resources:
+ pipelines:
+ - pipeline: CI
+ source: vs-threading
+ tags:
+ - Real signed
+ trigger:
+ tags:
+ - Real signed
+ - auto-insertion
+
+stages:
+- stage: VS
+ displayName: VS insertion
+ jobs:
+ - deployment: insertion
+ pool: VSEng-ReleasePool
+ environment: No-Approval
+ strategy:
+ runOnce:
+ deploy:
+ steps:
+ - powershell: |
+ Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)"
+ displayName: Set pipeline name
+ - template: release-deployment-prep.yml
+ - download: CI
+ artifact: VSInsertion-Windows
+ displayName: Download VSInsertion-Windows artifact
+ - task: NuGetCommand@2
+ displayName: Push CoreXT packages to VS feed
+ inputs:
+ command: push
+ packagesToPush: $(Pipeline.Workspace)/CI/VSInsertion-windows/*.nupkg
+ publishVstsFeed: 97a41293-2972-4f48-8c0e-05493ae82010
+ allowPackageConflicts: true
+ - task: MicroBuildInsertVsPayload@3
+ displayName: Insert VS Payload
+ inputs:
+ TeamName: $(TeamName)
+ TeamEmail: $(TeamEmail)
+ InsertionPayloadName: $(Build.Repository.Name) $(Build.BuildNumber)
+ InsertionBuildPolicy: Request Perf DDRITs
+ AutoCompletePR: true
+ AutoCompleteMergeStrategy: Squash
+ - task: MicroBuildCleanup@1
+ displayName: Send Telemetry
diff --git a/doc/library_with_jtf.md b/doc/library_with_jtf.md
index 40ae72c1..37605fc4 100644
--- a/doc/library_with_jtf.md
+++ b/doc/library_with_jtf.md
@@ -95,7 +95,7 @@ public static class LibrarySettings
{
get
{
- if (joinableTaskContext == null)
+ if (joinableTaskContext is null)
{
// This self-initializer is for when an app does not have a `JoinableTaskContext` to pass to the library.
// Our private instance will only work if this property getter first runs on the main thread of the application
@@ -108,7 +108,7 @@ public static class LibrarySettings
set
{
- Assumes.True(joinableTaskContext == null || joinableTaskContext == value, "This property has already been set to another value or is set after its value has been retrieved with a self-created value. Set this property once, before it is used elsewhere.");
+ Assumes.True(joinableTaskContext is null || joinableTaskContext == value, "This property has already been set to another value or is set after its value has been retrieved with a self-created value. Set this property once, before it is used elsewhere.");
joinableTaskContext = value;
}
}
@@ -117,7 +117,7 @@ public static class LibrarySettings
This pattern and self-initializer allows all the rest of your library code to assume JTF is always present (so you can use JTF.Run and JTF.RunAsync everywhere w/o feature that JTF will be null), and it mitigates all the deadlocks possible given the host constraints.
-Note that when you create your own default instance of JoinableTaskContext (i.e. when the host doesn't), it will consider the thread you're on to be the main thread. If SynchronizationContext.Current != null it will capture it and use it to switch to the main thread when you ask it to (very similar to how VS works today), otherwise any request to SwitchToMainThreadAsync will never switch the thread (since no `SynchronizationContext` was supplied to do so) but otherwise JTF continues to work.
+Note that when you create your own default instance of JoinableTaskContext (i.e. when the host doesn't), it will consider the thread you're on to be the main thread. If SynchronizationContext.Current is object it will capture it and use it to switch to the main thread when you ask it to (very similar to how VS works today), otherwise any request to SwitchToMainThreadAsync will never switch the thread (since no `SynchronizationContext` was supplied to do so) but otherwise JTF continues to work.
## Accept `JoinableTaskContext` as a constructor argument
diff --git a/global.json b/global.json
index 22ddecfc..2d3bd80b 100644
--- a/global.json
+++ b/global.json
@@ -1,7 +1,7 @@
{
"sdk": {
- "version": "3.1.100",
- "rollForward": "latestPatch",
+ "version": "3.1.302",
+ "rollForward": "patch",
"allowPrerelease": false
},
"msbuild-sdks": {
diff --git a/init.cmd b/init.cmd
index 5bef08da..667efabb 100644
--- a/init.cmd
+++ b/init.cmd
@@ -1,3 +1,20 @@
-@set PS1UnderCmd=1
-powershell.exe -ExecutionPolicy bypass -Command "& '%~dpn0.ps1'" %*
-@set PS1UnderCmd=
+@echo off
+SETLOCAL
+set PS1UnderCmd=1
+
+:: Get the datetime in a format that can go in a filename.
+set _my_datetime=%date%_%time%
+set _my_datetime=%_my_datetime: =_%
+set _my_datetime=%_my_datetime::=%
+set _my_datetime=%_my_datetime:/=_%
+set _my_datetime=%_my_datetime:.=_%
+set CmdEnvScriptPath=%temp%\envvarscript_%_my_datetime%.cmd
+
+powershell.exe -NoProfile -NoLogo -ExecutionPolicy bypass -Command "try { & '%~dpn0.ps1' %*; exit $LASTEXITCODE } catch { write-host $_; exit 1 }"
+
+:: Set environment variables in the parent cmd.exe process.
+IF EXIST "%CmdEnvScriptPath%" (
+ ENDLOCAL
+ CALL "%CmdEnvScriptPath%"
+ DEL "%CmdEnvScriptPath%"
+)
diff --git a/init.ps1 b/init.ps1
index 2baf7596..a99b95f4 100644
--- a/init.ps1
+++ b/init.ps1
@@ -1,27 +1,36 @@
+#!/usr/bin/env pwsh
+
<#
.SYNOPSIS
-Installs dependencies required to build and test the projects in this repository.
+ Installs dependencies required to build and test the projects in this repository.
.DESCRIPTION
-This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location,
-unless `-InstallLocality machine` is specified.
+ This MAY not require elevation, as the SDK and runtimes are installed to a per-user location,
+ unless the `-InstallLocality` switch is specified directing to a per-repo or per-machine location.
+ See detailed help on that switch for more information.
+
+ The CmdEnvScriptPath environment variable may be optionally set to a path to a cmd shell script to be created (or appended to if it already exists) that will set the environment variables in cmd.exe that are set within the PowerShell environment.
+ This is used by init.cmd in order to reapply any new environment variables to the parent cmd.exe process that were set in the powershell child process.
.PARAMETER InstallLocality
-A value indicating whether dependencies should be installed locally to the repo or at a per-user location.
-Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache.
-Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script.
-Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build.
-When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used.
-Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`.
-Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it.
+ A value indicating whether dependencies should be installed locally to the repo or at a per-user location.
+ Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache.
+ Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script.
+ Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build.
+ When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used.
+ Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`.
+ Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it.
.PARAMETER NoPrerequisites
-Skips the installation of prerequisite software (e.g. SDKs, tools).
+ Skips the installation of prerequisite software (e.g. SDKs, tools).
+.PARAMETER UpgradePrerequisites
+ Takes time to install prerequisites even if they are already present in case they need to be upgraded.
+ No effect if -NoPrerequisites is specified.
.PARAMETER NoRestore
-Skips the package restore step.
+ Skips the package restore step.
.PARAMETER Signing
-Install the MicroBuild signing plugin for building test-signed builds on desktop machines.
+ Install the MicroBuild signing plugin for building test-signed builds on desktop machines.
.PARAMETER OptProf
-Install the MicroBuild OptProf plugin for building optimized assemblies on desktop machines.
+ Install the MicroBuild OptProf plugin for building optimized assemblies on desktop machines.
.PARAMETER AccessToken
-An optional access token for authenticating to Azure Artifacts authenticated feeds.
+ An optional access token for authenticating to Azure Artifacts authenticated feeds.
#>
[CmdletBinding(SupportsShouldProcess=$true)]
Param (
@@ -30,6 +39,8 @@ Param (
[Parameter()]
[switch]$NoPrerequisites,
[Parameter()]
+ [switch]$UpgradePrerequisites,
+ [Parameter()]
[switch]$NoRestore,
[Parameter()]
[switch]$Signing,
@@ -39,9 +50,20 @@ Param (
[string]$AccessToken
)
+$EnvVars = @{}
+
if (!$NoPrerequisites) {
- & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken
+ & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken -Force:$UpgradePrerequisites
& "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality
+ if ($LASTEXITCODE -eq 3010) {
+ Exit 3010
+ }
+
+ # The procdump tool and env var is required for dotnet test to collect hang/crash dumps of tests.
+ # But it only works on Windows.
+ if ($env:OS -eq 'Windows_NT') {
+ $EnvVars['PROCDUMP_PATH'] = & "$PSScriptRoot\azure-pipelines\Get-ProcDump.ps1"
+ }
}
# Workaround nuget credential provider bug that causes very unreliable package restores on Azure Pipelines
@@ -52,15 +74,14 @@ Push-Location $PSScriptRoot
try {
$HeaderColor = 'Green'
- if (!$NoRestore) {
+ if (!$NoRestore -and $PSCmdlet.ShouldProcess("NuGet packages", "Restore")) {
Write-Host "Restoring NuGet packages" -ForegroundColor $HeaderColor
- dotnet restore src
+ dotnet restore
if ($lastexitcode -ne 0) {
throw "Failure while restoring packages."
}
}
- $EnvVars = @{}
$InstallNuGetPkgScriptPath = ".\azure-pipelines\Install-NuGetPackage.ps1"
$nugetVerbosity = 'quiet'
if ($Verbose) { $nugetVerbosity = 'normal' }
@@ -77,7 +98,7 @@ try {
$EnvVars['OptProfEnabled'] = '1'
}
- & "$PSScriptRoot\azure-pipelines\Set-EnvVars.ps1" -Variables $EnvVars | Out-Null
+ & "$PSScriptRoot/tools/Set-EnvVars.ps1" -Variables $EnvVars | Out-Null
}
catch {
Write-Error $error[0]
diff --git a/src/.editorconfig b/src/.editorconfig
new file mode 100644
index 00000000..36b70ad1
--- /dev/null
+++ b/src/.editorconfig
@@ -0,0 +1,13 @@
+[Microsoft.VisualStudio.Threading.Analyzers*/*.cs]
+
+# CS1591: Missing XML comment for publicly visible type or member
+dotnet_diagnostic.CS1591.severity = suggestion
+
+# CA1062: Validate arguments of public methods
+dotnet_diagnostic.CA1062.severity = none
+
+# CA2007: Consider calling ConfigureAwait on the awaited task
+dotnet_diagnostic.CA2007.severity = silent
+
+# RS2008: Enable analyzer release tracking
+dotnet_diagnostic.RS2008.severity = suggestion
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 82b2c946..c73680b5 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,50 +1,11 @@
+
+
- Debug
-
- $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\'))
- $(RepoRoot)bin\
- $(RepoRoot)obj\
- $(RepoObjPath)\$(MSBuildProjectName)\
- $(RepoBinPath)\$(MSBuildProjectName)\
- $(RepoBinPath)Packages\$(Configuration)\NuGet\
- true
-
- 8
- enable
-
- 2.0.58
- true
- true
- true
- snupkg
-
- Microsoft
- Microsoft, VisualStudioExtensibility
- © Microsoft Corporation. All rights reserved.
- https://github.com/Microsoft/vs-threading
- $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
-
PackageIcon.png
- MIT
-
-
-
-
-
-
-
+
-
-
-
-
-
-
- https://github.com/microsoft/vs-threading/releases/tag/v$(Version)
-
-
diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
index c3e1ac7f..e7edee55 100644
--- a/src/Directory.Build.targets
+++ b/src/Directory.Build.targets
@@ -1,8 +1,3 @@
-
- cobertura
- [xunit.*]*,[Microsoft.CodeAnalysis*]*
-
- $(OutputPath)/
-
+
diff --git a/src/IsolatedTestHost/IsolatedTestHost.csproj b/src/IsolatedTestHost/IsolatedTestHost.csproj
deleted file mode 100644
index 0ba028ab..00000000
--- a/src/IsolatedTestHost/IsolatedTestHost.csproj
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- Exe
- net472
- true
- $(NoWarn);CS1591
- ..\Microsoft.VisualStudio.Threading.Tests\Microsoft.VisualStudio.Threading.Tests.ruleset
- false
-
-
-
-
-
-
-
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/AssemblyInfo.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/AssemblyInfo.cs
index 17743930..18c0aa28 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/AssemblyInfo.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/AssemblyInfo.cs
@@ -1,8 +1,5 @@
-/********************************************************
-* *
-* © Copyright (C) Microsoft. All rights reserved. *
-* *
-*********************************************************/
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Resources;
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpCommonInterest.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpCommonInterest.cs
index ecb1fc9d..68aa2015 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpCommonInterest.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpCommonInterest.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
@@ -38,10 +39,10 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
///
internal static bool ShouldIgnoreContext(SyntaxNodeAnalysisContext context)
{
- var namespaceDeclaration = context.Node.FirstAncestorOrSelf();
- if (namespaceDeclaration != null)
+ NamespaceDeclarationSyntax? namespaceDeclaration = context.Node.FirstAncestorOrSelf();
+ if (namespaceDeclaration is object)
{
- foreach (var trivia in namespaceDeclaration.NamespaceKeyword.GetAllTrivia())
+ foreach (SyntaxTrivia trivia in namespaceDeclaration.NamespaceKeyword.GetAllTrivia())
{
const string autoGeneratedKeyword = @"";
if (trivia.FullSpan.Length > autoGeneratedKeyword.Length
@@ -62,12 +63,12 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
IEnumerable problematicMethods,
bool ignoreIfInsideAnonymousDelegate = false)
{
- if (descriptor == null)
+ if (descriptor is null)
{
throw new ArgumentNullException(nameof(descriptor));
}
- if (memberAccessSyntax == null)
+ if (memberAccessSyntax is null)
{
return;
}
@@ -77,7 +78,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
return;
}
- if (ignoreIfInsideAnonymousDelegate && context.Node.FirstAncestorOrSelf() != null)
+ if (ignoreIfInsideAnonymousDelegate && context.Node.FirstAncestorOrSelf() is object)
{
// We do not analyze JTF.Run inside anonymous functions because
// they are so often used as callbacks where the signature is constrained.
@@ -90,16 +91,16 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
return;
}
- var typeReceiver = context.SemanticModel.GetTypeInfo(memberAccessSyntax.Expression).Type;
- if (typeReceiver != null)
+ ITypeSymbol? typeReceiver = context.SemanticModel.GetTypeInfo(memberAccessSyntax.Expression).Type;
+ if (typeReceiver is object)
{
- foreach (var item in problematicMethods)
+ foreach (CommonInterest.SyncBlockingMethod item in problematicMethods)
{
if (memberAccessSyntax.Name.Identifier.Text == item.Method.Name &&
typeReceiver.Name == item.Method.ContainingType.Name &&
typeReceiver.BelongsToNamespace(item.Method.ContainingType.Namespace))
{
- var location = memberAccessSyntax.Name.GetLocation();
+ Location? location = memberAccessSyntax.Name.GetLocation();
context.ReportDiagnostic(Diagnostic.Create(descriptor, location));
}
}
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpUtils.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpUtils.cs
index 3e06b362..a08527f8 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpUtils.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpUtils.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
@@ -22,7 +23,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
internal static ExpressionSyntax IsolateMethodName(InvocationExpressionSyntax invocation)
{
- if (invocation == null)
+ if (invocation is null)
{
throw new ArgumentNullException(nameof(invocation));
}
@@ -39,7 +40,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
/// The containing function, and metadata for it.
internal static ContainingFunctionData GetContainingFunction(CSharpSyntaxNode syntaxNode)
{
- while (syntaxNode != null)
+ while (syntaxNode is object)
{
if (syntaxNode is SimpleLambdaExpressionSyntax simpleLambda)
{
@@ -75,7 +76,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
internal static bool IsOnLeftHandOfAssignment(SyntaxNode syntaxNode)
{
SyntaxNode? parent = null;
- while ((parent = syntaxNode.Parent) != null)
+ while ((parent = syntaxNode.Parent) is object)
{
if (parent is AssignmentExpressionSyntax assignment)
{
@@ -90,26 +91,26 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
internal static bool IsAssignedWithin(SyntaxNode container, SemanticModel semanticModel, ISymbol variable, CancellationToken cancellationToken)
{
- if (semanticModel == null)
+ if (semanticModel is null)
{
throw new ArgumentNullException(nameof(semanticModel));
}
- if (variable == null)
+ if (variable is null)
{
throw new ArgumentNullException(nameof(variable));
}
- if (container == null)
+ if (container is null)
{
return false;
}
- foreach (var node in container.DescendantNodesAndSelf(n => !(n is AnonymousFunctionExpressionSyntax)))
+ foreach (SyntaxNode? node in container.DescendantNodesAndSelf(n => !(n is AnonymousFunctionExpressionSyntax)))
{
if (node is AssignmentExpressionSyntax assignment)
{
- var assignedSymbol = semanticModel.GetSymbolInfo(assignment.Left, cancellationToken).Symbol;
+ ISymbol? assignedSymbol = semanticModel.GetSymbolInfo(assignment.Left, cancellationToken).Symbol;
if (variable.Equals(assignedSymbol))
{
return true;
@@ -122,12 +123,12 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
internal static MemberAccessExpressionSyntax MemberAccess(IReadOnlyList qualifiers, SimpleNameSyntax simpleName)
{
- if (qualifiers == null)
+ if (qualifiers is null)
{
throw new ArgumentNullException(nameof(qualifiers));
}
- if (simpleName == null)
+ if (simpleName is null)
{
throw new ArgumentNullException(nameof(simpleName));
}
@@ -140,7 +141,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
ExpressionSyntax result = SyntaxFactory.IdentifierName(qualifiers[0]);
for (int i = 1; i < qualifiers.Count; i++)
{
- var rightSide = SyntaxFactory.IdentifierName(qualifiers[i]);
+ IdentifierNameSyntax? rightSide = SyntaxFactory.IdentifierName(qualifiers[i]);
result = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, result, rightSide);
}
@@ -152,7 +153,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
///
internal static bool IsWithinNameOf([NotNullWhen(true)] SyntaxNode? syntaxNode)
{
- var invocation = syntaxNode?.FirstAncestorOrSelf();
+ InvocationExpressionSyntax? invocation = syntaxNode?.FirstAncestorOrSelf();
return invocation is object
&& (invocation.Expression as IdentifierNameSyntax)?.Identifier.Text == "nameof"
&& invocation.ArgumentList.Arguments.Count == 1;
@@ -160,14 +161,14 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
internal override Location? GetLocationOfBaseTypeName(INamedTypeSymbol symbol, INamedTypeSymbol baseType, Compilation compilation, CancellationToken cancellationToken)
{
- foreach (var syntaxReference in symbol.DeclaringSyntaxReferences)
+ foreach (SyntaxReference? syntaxReference in symbol.DeclaringSyntaxReferences)
{
- var syntaxNode = syntaxReference.GetSyntax(cancellationToken);
+ SyntaxNode? syntaxNode = syntaxReference.GetSyntax(cancellationToken);
if (syntaxNode is TypeDeclarationSyntax typeDeclarationSyntax)
{
if (compilation.GetSemanticModel(typeDeclarationSyntax.SyntaxTree) is { } semanticModel)
{
- foreach (var baseTypeSyntax in typeDeclarationSyntax.BaseList.Types)
+ foreach (BaseTypeSyntax? baseTypeSyntax in typeDeclarationSyntax.BaseList.Types)
{
SymbolInfo baseTypeSymbolInfo = semanticModel.GetSymbolInfo(baseTypeSyntax.Type, cancellationToken);
if (Equals(baseTypeSymbolInfo.Symbol, baseType))
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD001UseSwitchToMainThreadAsyncAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD001UseSwitchToMainThreadAsyncAnalyzer.cs
index c0425926..01848cb7 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD001UseSwitchToMainThreadAsyncAnalyzer.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD001UseSwitchToMainThreadAsyncAnalyzer.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD004AwaitSwitchToMainThreadAsyncAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD004AwaitSwitchToMainThreadAsyncAnalyzer.cs
index 8a211454..5580c313 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD004AwaitSwitchToMainThreadAsyncAnalyzer.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD004AwaitSwitchToMainThreadAsyncAnalyzer.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD011UseAsyncLazyAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD011UseAsyncLazyAnalyzer.cs
index 13a56721..33f4c8e3 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD011UseAsyncLazyAnalyzer.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD011UseAsyncLazyAnalyzer.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD012SpecifyJtfWhereAllowed.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD012SpecifyJtfWhereAllowed.cs
index 32cbaeaf..2143f395 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD012SpecifyJtfWhereAllowed.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD012SpecifyJtfWhereAllowed.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD105AvoidImplicitTaskSchedulerCurrentAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD105AvoidImplicitTaskSchedulerCurrentAnalyzer.cs
index f8406df3..94ee09e1 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD105AvoidImplicitTaskSchedulerCurrentAnalyzer.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD105AvoidImplicitTaskSchedulerCurrentAnalyzer.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD108AssertThreadRequirementUnconditionally.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD108AssertThreadRequirementUnconditionally.cs
index 1d8ac7c2..3a40bbe9 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD108AssertThreadRequirementUnconditionally.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD108AssertThreadRequirementUnconditionally.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD109AvoidAssertInAsyncMethodsAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD109AvoidAssertInAsyncMethodsAnalyzer.cs
index 20d0a859..6e620baa 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD109AvoidAssertInAsyncMethodsAnalyzer.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD109AvoidAssertInAsyncMethodsAnalyzer.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD112ImplementSystemIAsyncDisposableAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD112ImplementSystemIAsyncDisposableAnalyzer.cs
index 2a7ab0c8..dbaf87ba 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD112ImplementSystemIAsyncDisposableAnalyzer.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/CSharpVSTHRD112ImplementSystemIAsyncDisposableAnalyzer.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/Microsoft.VisualStudio.Threading.Analyzers.CSharp.csproj b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/Microsoft.VisualStudio.Threading.Analyzers.CSharp.csproj
index 6ddbd362..1aee7597 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/Microsoft.VisualStudio.Threading.Analyzers.CSharp.csproj
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/Microsoft.VisualStudio.Threading.Analyzers.CSharp.csproj
@@ -1,9 +1,6 @@
netstandard1.3
- true
- $(NoWarn);CS1591
- ..\Microsoft.VisualStudio.Threading.Analyzers\Microsoft.VisualStudio.Threading.Analyzers.ruleset
Microsoft.VisualStudio.Threading.Analyzers
false
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD002UseJtfRunAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD002UseJtfRunAnalyzer.cs
index a12a9188..cdf1fa7b 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD002UseJtfRunAnalyzer.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD002UseJtfRunAnalyzer.cs
@@ -1,8 +1,5 @@
-/********************************************************
-* *
-* © Copyright (C) Microsoft. All rights reserved. *
-* *
-*********************************************************/
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
@@ -63,18 +60,18 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
context.RegisterCompilationStartAction(compilationContext =>
{
- var taskSymbol = compilationContext.Compilation.GetTypeByMetadataName(Types.Task.FullName);
- if (taskSymbol != null)
+ INamedTypeSymbol? taskSymbol = compilationContext.Compilation.GetTypeByMetadataName(Types.Task.FullName);
+ if (taskSymbol is object)
{
compilationContext.RegisterCodeBlockStartAction(codeBlockContext =>
{
// We want to scan properties and methods that do not return Task or Task.
var methodSymbol = codeBlockContext.OwningSymbol as IMethodSymbol;
var propertySymbol = codeBlockContext.OwningSymbol as IPropertySymbol;
- if (propertySymbol != null || (methodSymbol != null && !methodSymbol.HasAsyncCompatibleReturnType()))
+ if (propertySymbol is object || (methodSymbol is object && !methodSymbol.HasAsyncCompatibleReturnType()))
{
- codeBlockContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => this.AnalyzeInvocation(c, taskSymbol)), SyntaxKind.InvocationExpression);
- codeBlockContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => this.AnalyzeMemberAccess(c, taskSymbol)), SyntaxKind.SimpleMemberAccessExpression);
+ codeBlockContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => AnalyzeInvocation(c, taskSymbol)), SyntaxKind.InvocationExpression);
+ codeBlockContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => AnalyzeMemberAccess(c, taskSymbol)), SyntaxKind.SimpleMemberAccessExpression);
}
});
}
@@ -96,43 +93,23 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
return null;
}
- private void AnalyzeInvocation(SyntaxNodeAnalysisContext context, INamedTypeSymbol taskSymbol)
- {
- var invocationExpressionSyntax = (InvocationExpressionSyntax)context.Node;
- this.InspectMemberAccess(
- context,
- invocationExpressionSyntax.Expression as MemberAccessExpressionSyntax,
- CommonInterest.ProblematicSyncBlockingMethods,
- taskSymbol);
- }
-
- private void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context, INamedTypeSymbol taskSymbol)
- {
- var memberAccessSyntax = (MemberAccessExpressionSyntax)context.Node;
- this.InspectMemberAccess(
- context,
- memberAccessSyntax,
- CommonInterest.SyncBlockingProperties,
- taskSymbol);
- }
-
- private void InspectMemberAccess(
+ private static void InspectMemberAccess(
SyntaxNodeAnalysisContext context,
MemberAccessExpressionSyntax? memberAccessSyntax,
IEnumerable problematicMethods,
INamedTypeSymbol taskSymbol)
{
- if (memberAccessSyntax == null)
+ if (memberAccessSyntax is null)
{
return;
}
// Are we in the context of an anonymous function that is passed directly in as an argument to another method?
- var anonymousFunctionSyntax = context.Node.FirstAncestorOrSelf();
+ AnonymousFunctionExpressionSyntax? anonymousFunctionSyntax = context.Node.FirstAncestorOrSelf();
var anonFuncAsArgument = anonymousFunctionSyntax?.Parent as ArgumentSyntax;
var invocationPassingExpression = anonFuncAsArgument?.Parent?.Parent as InvocationExpressionSyntax;
var invokedMemberAccess = invocationPassingExpression?.Expression as MemberAccessExpressionSyntax;
- if (invokedMemberAccess?.Name != null)
+ if (invokedMemberAccess?.Name is object)
{
// Does the anonymous function appear as the first argument to Task.ContinueWith?
var invokedMemberSymbol = context.SemanticModel.GetSymbolInfo(invokedMemberAccess.Name, context.CancellationToken).Symbol as IMethodSymbol;
@@ -141,8 +118,8 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
invocationPassingExpression?.ArgumentList?.Arguments.FirstOrDefault() == anonFuncAsArgument)
{
// Does the member access being analyzed belong to the Task that just completed?
- var firstParameter = GetFirstParameter(anonymousFunctionSyntax);
- if (firstParameter != null)
+ ParameterSyntax? firstParameter = GetFirstParameter(anonymousFunctionSyntax);
+ if (firstParameter is object)
{
// Are we accessing a member of the completed task?
ISymbol invokedObjectSymbol = context.SemanticModel.GetSymbolInfo(memberAccessSyntax.Expression, context.CancellationToken).Symbol;
@@ -158,5 +135,25 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
CSharpCommonInterest.InspectMemberAccess(context, memberAccessSyntax, Descriptor, problematicMethods);
}
+
+ private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context, INamedTypeSymbol taskSymbol)
+ {
+ var invocationExpressionSyntax = (InvocationExpressionSyntax)context.Node;
+ InspectMemberAccess(
+ context,
+ invocationExpressionSyntax.Expression as MemberAccessExpressionSyntax,
+ CommonInterest.ProblematicSyncBlockingMethods,
+ taskSymbol);
+ }
+
+ private static void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context, INamedTypeSymbol taskSymbol)
+ {
+ var memberAccessSyntax = (MemberAccessExpressionSyntax)context.Node;
+ InspectMemberAccess(
+ context,
+ memberAccessSyntax,
+ CommonInterest.SyncBlockingProperties,
+ taskSymbol);
+ }
}
}
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD003UseJtfRunAsyncAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD003UseJtfRunAsyncAnalyzer.cs
index 6282783b..223f648d 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD003UseJtfRunAsyncAnalyzer.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD003UseJtfRunAsyncAnalyzer.cs
@@ -1,8 +1,5 @@
-/********************************************************
-* *
-* © Copyright (C) Microsoft. All rights reserved. *
-* *
-*********************************************************/
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Threading.Analyzers
{
@@ -52,11 +49,6 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
- private static readonly IReadOnlyCollection DoNotPassTypesInSearchForAnonFuncInvocation = new[]
- {
- typeof(MethodDeclarationSyntax),
- };
-
///
public override ImmutableArray SupportedDiagnostics
{
@@ -84,7 +76,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
var arrowExpressionClause = (ArrowExpressionClauseSyntax)context.Node;
if (arrowExpressionClause.Parent is MethodDeclarationSyntax)
{
- var diagnostic = this.AnalyzeAwaitedOrReturnedExpression(arrowExpressionClause.Expression, context, context.CancellationToken);
+ Diagnostic? diagnostic = this.AnalyzeAwaitedOrReturnedExpression(arrowExpressionClause.Expression, context, context.CancellationToken);
if (diagnostic is object)
{
context.ReportDiagnostic(diagnostic);
@@ -97,8 +89,8 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
var lambdaExpression = (LambdaExpressionSyntax)context.Node;
if (lambdaExpression.Body is ExpressionSyntax expression)
{
- var diagnostic = this.AnalyzeAwaitedOrReturnedExpression(expression, context, context.CancellationToken);
- if (diagnostic != null)
+ Diagnostic? diagnostic = this.AnalyzeAwaitedOrReturnedExpression(expression, context, context.CancellationToken);
+ if (diagnostic is object)
{
context.ReportDiagnostic(diagnostic);
}
@@ -108,8 +100,8 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
private void AnalyzeReturnStatement(SyntaxNodeAnalysisContext context)
{
var returnStatement = (ReturnStatementSyntax)context.Node;
- var diagnostic = this.AnalyzeAwaitedOrReturnedExpression(returnStatement.Expression, context, context.CancellationToken);
- if (diagnostic != null)
+ Diagnostic? diagnostic = this.AnalyzeAwaitedOrReturnedExpression(returnStatement.Expression, context, context.CancellationToken);
+ if (diagnostic is object)
{
context.ReportDiagnostic(diagnostic);
}
@@ -118,8 +110,8 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
private void AnalyzeAwaitExpression(SyntaxNodeAnalysisContext context)
{
AwaitExpressionSyntax awaitExpressionSyntax = (AwaitExpressionSyntax)context.Node;
- var diagnostic = this.AnalyzeAwaitedOrReturnedExpression(awaitExpressionSyntax.Expression, context, context.CancellationToken);
- if (diagnostic != null)
+ Diagnostic? diagnostic = this.AnalyzeAwaitedOrReturnedExpression(awaitExpressionSyntax.Expression, context, context.CancellationToken);
+ if (diagnostic is object)
{
context.ReportDiagnostic(diagnostic);
}
@@ -127,14 +119,14 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
private Diagnostic? AnalyzeAwaitedOrReturnedExpression(ExpressionSyntax expressionSyntax, SyntaxNodeAnalysisContext context, CancellationToken cancellationToken)
{
- if (expressionSyntax == null)
+ if (expressionSyntax is null)
{
return null;
}
// Get the semantic model for the SyntaxTree for the given ExpressionSyntax, since it *may* not be in the same syntax tree
// as the original context.Node.
- if (!context.TryGetNewOrExistingSemanticModel(expressionSyntax.SyntaxTree, out var semanticModel))
+ if (!context.TryGetNewOrExistingSemanticModel(expressionSyntax.SyntaxTree, out SemanticModel? semanticModel))
{
return null;
}
@@ -174,12 +166,12 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
return null;
}
- foreach (var syntaxReference in fieldSymbol.DeclaringSyntaxReferences)
+ foreach (SyntaxReference? syntaxReference in fieldSymbol.DeclaringSyntaxReferences)
{
if (syntaxReference.GetSyntax(cancellationToken) is VariableDeclaratorSyntax declarationSyntax)
{
if (declarationSyntax.Initializer?.Value is InvocationExpressionSyntax invocationSyntax &&
- invocationSyntax.Expression != null)
+ invocationSyntax.Expression is object)
{
if (!context.Compilation.ContainsSyntaxTree(invocationSyntax.SyntaxTree))
{
@@ -188,7 +180,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
}
// Whitelist Task.From*() methods.
- if (!context.TryGetNewOrExistingSemanticModel(invocationSyntax.SyntaxTree, out var declarationSemanticModel))
+ if (!context.TryGetNewOrExistingSemanticModel(invocationSyntax.SyntaxTree, out SemanticModel? declarationSemanticModel))
{
return null;
}
@@ -203,12 +195,12 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
}
else if (declarationSyntax.Initializer?.Value is MemberAccessExpressionSyntax memberAccessSyntax && memberAccessSyntax.Expression is object)
{
- if (!context.TryGetNewOrExistingSemanticModel(memberAccessSyntax.SyntaxTree, out var declarationSemanticModel))
+ if (!context.TryGetNewOrExistingSemanticModel(memberAccessSyntax.SyntaxTree, out SemanticModel? declarationSemanticModel))
{
return null;
}
- var definition = declarationSemanticModel.GetSymbolInfo(memberAccessSyntax, cancellationToken).Symbol;
+ ISymbol? definition = declarationSemanticModel.GetSymbolInfo(memberAccessSyntax, cancellationToken).Symbol;
if (definition is IFieldSymbol field)
{
// Whitelist the TplExtensions.CompletedTask and related fields.
@@ -237,7 +229,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
if (Utils.IsTask(methodSymbol.ReturnType) && expressionSyntax is InvocationExpressionSyntax invocationExpressionSyntax)
{
// Consider all arguments
- var expressionsToConsider = invocationExpressionSyntax.ArgumentList.Arguments.Select(a => a.Expression);
+ IEnumerable? expressionsToConsider = invocationExpressionSyntax.ArgumentList.Arguments.Select(a => a.Expression);
// Consider the implicit first argument when this method is invoked as an extension method.
if (methodSymbol.IsExtensionMethod && invocationExpressionSyntax.Expression is MemberAccessExpressionSyntax invokedMember)
@@ -248,7 +240,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
}
}
- return expressionsToConsider.Select(e => this.AnalyzeAwaitedOrReturnedExpression(e, context, cancellationToken)).FirstOrDefault(r => r != null);
+ return expressionsToConsider.Select(e => this.AnalyzeAwaitedOrReturnedExpression(e, context, cancellationToken)).FirstOrDefault(r => r is object);
}
return null;
@@ -262,7 +254,7 @@ namespace Microsoft.VisualStudio.Threading.Analyzers
}
// Report warning if the task was not initialized within the current delegate or lambda expression
- var containingFunc = CSharpUtils.GetContainingFunction(expressionSyntax);
+ CSharpUtils.ContainingFunctionData containingFunc = CSharpUtils.GetContainingFunction(expressionSyntax);
if (containingFunc.BlockOrExpression is BlockSyntax delegateBlock)
{
if (dataflowAnalysisCompatibleVariable)
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD010MainThreadUsageAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD010MainThreadUsageAnalyzer.cs
index e684ee1c..a225d69f 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD010MainThreadUsageAnalyzer.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD010MainThreadUsageAnalyzer.cs
@@ -1,4 +1,7 @@
-namespace Microsoft.VisualStudio.Threading.Analyzers
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.VisualStudio.Threading.Analyzers
{
using System;
using System.Collections.Generic;
@@ -114,7 +117,7 @@
var mainThreadAssertingMethods = CommonInterest.ReadMethods(compilationStartContext.Options, CommonInterest.FileNamePatternForMethodsThatAssertMainThread, compilationStartContext.CancellationToken).ToImmutableArray();
var mainThreadSwitchingMethods = CommonInterest.ReadMethods(compilationStartContext.Options, CommonInterest.FileNamePatternForMethodsThatSwitchToMainThread, compilationStartContext.CancellationToken).ToImmutableArray();
var membersRequiringMainThread = CommonInterest.ReadTypesAndMembers(compilationStartContext.Options, CommonInterest.FileNamePatternForMembersRequiringMainThread, compilationStartContext.CancellationToken).ToImmutableArray();
- var diagnosticProperties = ImmutableDictionary.Empty
+ ImmutableDictionary? diagnosticProperties = ImmutableDictionary.Empty
.Add(CommonInterest.FileNamePatternForMethodsThatAssertMainThread.ToString(), string.Join("\n", mainThreadAssertingMethods))
.Add(CommonInterest.FileNamePatternForMethodsThatSwitchToMainThread.ToString(), string.Join("\n", mainThreadSwitchingMethods));
@@ -145,9 +148,9 @@
compilationStartContext.RegisterCompilationEndAction(compilationEndContext =>
{
- var calleeToCallerMap = CreateCalleeToCallerMap(callerToCalleeMap);
- var transitiveClosureOfMainThreadRequiringMethods = GetTransitiveClosureOfMainThreadRequiringMethods(methodsAssertingUIThreadRequirement, calleeToCallerMap);
- foreach (var implicitUserMethod in transitiveClosureOfMainThreadRequiringMethods.Except(methodsDeclaringUIThreadRequirement))
+ Dictionary>? calleeToCallerMap = CreateCalleeToCallerMap(callerToCalleeMap);
+ HashSet? transitiveClosureOfMainThreadRequiringMethods = GetTransitiveClosureOfMainThreadRequiringMethods(methodsAssertingUIThreadRequirement, calleeToCallerMap);
+ foreach (IMethodSymbol? implicitUserMethod in transitiveClosureOfMainThreadRequiringMethods.Except(methodsDeclaringUIThreadRequirement))
{
var reportSites = from info in callerToCalleeMap[implicitUserMethod]
where transitiveClosureOfMainThreadRequiringMethods.Contains(info.MethodSymbol)
@@ -156,7 +159,7 @@
foreach (var site in reportSites)
{
bool isAsync = Utils.IsAsyncReady(implicitUserMethod);
- var descriptor = isAsync ? DescriptorAsync : DescriptorSync;
+ DiagnosticDescriptor? descriptor = isAsync ? DescriptorAsync : DescriptorSync;
string calleeName = Utils.GetFullName(site.CalleeMethod);
var formattingArgs = isAsync ? new object[] { calleeName } : new object[] { calleeName, mainThreadAssertingMethods.FirstOrDefault() };
Diagnostic diagnostic = Diagnostic.Create(
@@ -177,12 +180,12 @@
void MarkMethod(IMethodSymbol method)
{
- if (result.Add(method) && calleeToCallerMap.TryGetValue(method, out var callers))
+ if (result.Add(method) && calleeToCallerMap.TryGetValue(method, out List? callers))
{
// If this is an async method, do *not* propagate its thread affinity to its callers.
if (!Utils.IsAsyncCompatibleReturnType(method.ReturnType))
{
- foreach (var caller in callers)
+ foreach (CallInfo caller in callers)
{
MarkMethod(caller.MethodSymbol);
}
@@ -190,7 +193,7 @@
}
}
- foreach (var method in methodsRequiringUIThread)
+ foreach (IMethodSymbol? method in methodsRequiringUIThread)
{
MarkMethod(method);
}
@@ -207,7 +210,7 @@
IMethodSymbol? GetPropertyAccessor(IPropertySymbol? propertySymbol)
{
- if (propertySymbol != null)
+ if (propertySymbol is object)
{
return CSharpUtils.IsOnLeftHandOfAssignment(context.Node)
? propertySymbol.SetMethod
@@ -251,12 +254,12 @@
{
var result = new Dictionary>();
- foreach (var item in callerToCalleeMap)
+ foreach (KeyValuePair> item in callerToCalleeMap)
{
- var caller = item.Key;
- foreach (var callee in item.Value)
+ IMethodSymbol? caller = item.Key;
+ foreach (CallInfo callee in item.Value)
{
- if (!result.TryGetValue(callee.MethodSymbol, out var callers))
+ if (!result.TryGetValue(callee.MethodSymbol, out List? callers))
{
result[callee.MethodSymbol] = callers = new List();
}
@@ -317,10 +320,10 @@
{
var invocationSyntax = (InvocationExpressionSyntax)context.Node;
var invokedMethod = context.SemanticModel.GetSymbolInfo(context.Node).Symbol as IMethodSymbol;
- if (invokedMethod != null)
+ if (invokedMethod is object)
{
- var methodDeclaration = context.Node.FirstAncestorOrSelf(n => CSharpCommonInterest.MethodSyntaxKinds.Contains(n.Kind()));
- if (methodDeclaration != null)
+ SyntaxNode? methodDeclaration = context.Node.FirstAncestorOrSelf(n => CSharpCommonInterest.MethodSyntaxKinds.Contains(n.Kind()));
+ if (methodDeclaration is object)
{
bool assertsMainThread = this.MainThreadAssertingMethods.Contains(invokedMethod);
bool switchesToMainThread = this.MainThreadSwitchingMethods.Contains(invokedMethod);
@@ -348,11 +351,11 @@
}
// The diagnostic (if any) should underline the method name only.
- var focusedNode = invocationSyntax.Expression;
+ ExpressionSyntax? focusedNode = invocationSyntax.Expression;
focusedNode = (focusedNode as MemberAccessExpressionSyntax)?.Name ?? focusedNode;
if (!this.AnalyzeMemberWithinContext(invokedMethod.ContainingType, invokedMethod, context, focusedNode.GetLocation()))
{
- foreach (var iface in invokedMethod.FindInterfacesImplemented())
+ foreach (ITypeSymbol? iface in invokedMethod.FindInterfacesImplemented())
{
if (this.AnalyzeMemberWithinContext(iface, invokedMethod, context, focusedNode.GetLocation()))
{
@@ -368,7 +371,7 @@
{
var memberAccessSyntax = (MemberAccessExpressionSyntax)context.Node;
var property = context.SemanticModel.GetSymbolInfo(context.Node).Symbol as IPropertySymbol;
- if (property != null)
+ if (property is object)
{
this.AnalyzeMemberWithinContext(property.ContainingType, property, context, memberAccessSyntax.Name.GetLocation());
}
@@ -378,7 +381,7 @@
{
var castSyntax = (CastExpressionSyntax)context.Node;
var type = context.SemanticModel.GetSymbolInfo(castSyntax.Type, context.CancellationToken).Symbol as ITypeSymbol;
- if (type != null && IsObjectLikelyToBeCOMObject(type))
+ if (type is object && IsObjectLikelyToBeCOMObject(type))
{
this.AnalyzeMemberWithinContext(type, null, context);
}
@@ -388,7 +391,7 @@
{
var asSyntax = (BinaryExpressionSyntax)context.Node;
var type = context.SemanticModel.GetSymbolInfo(asSyntax.Right, context.CancellationToken).Symbol as ITypeSymbol;
- if (type != null && IsObjectLikelyToBeCOMObject(type))
+ if (type is object && IsObjectLikelyToBeCOMObject(type))
{
Location asAndRightSide = Location.Create(context.Node.SyntaxTree, TextSpan.FromBounds(asSyntax.OperatorToken.Span.Start, asSyntax.Right.Span.End));
this.AnalyzeMemberWithinContext(type, null, context, asAndRightSide);
@@ -398,15 +401,16 @@
internal void AnalyzeIsPattern(SyntaxNodeAnalysisContext context)
{
var patternSyntax = (IsPatternExpressionSyntax)context.Node;
- if (patternSyntax.Pattern is DeclarationPatternSyntax declarationPatternSyntax && declarationPatternSyntax.Type != null)
+ if (patternSyntax.Pattern is DeclarationPatternSyntax declarationPatternSyntax && declarationPatternSyntax.Type is object)
{
var type = context.SemanticModel.GetSymbolInfo(declarationPatternSyntax.Type, context.CancellationToken).Symbol as ITypeSymbol;
- if (type != null && IsObjectLikelyToBeCOMObject(type))
+ if (type is object && IsObjectLikelyToBeCOMObject(type))
{
Location isAndTypeSide = Location.Create(
context.Node.SyntaxTree,
- TextSpan.FromBounds(patternSyntax.IsKeyword.SpanStart,
- declarationPatternSyntax.Type.Span.End));
+ TextSpan.FromBounds(
+ patternSyntax.IsKeyword.SpanStart,
+ declarationPatternSyntax.Type.Span.End));
this.AnalyzeMemberWithinContext(type, null, context, isAndTypeSide);
}
}
@@ -421,7 +425,7 @@
///
private static bool IsObjectLikelyToBeCOMObject(ITypeSymbol typeSymbol)
{
- if (typeSymbol == null)
+ if (typeSymbol is null)
{
throw new ArgumentNullException(nameof(typeSymbol));
}
@@ -435,7 +439,7 @@
private bool AnalyzeMemberWithinContext(ITypeSymbol type, ISymbol? symbol, SyntaxNodeAnalysisContext context, Location? focusDiagnosticOn = null)
{
- if (type == null)
+ if (type is null)
{
throw new ArgumentNullException(nameof(type));
}
@@ -445,18 +449,18 @@
if (requiresUIThread)
{
- var threadingContext = ThreadingContext.Unknown;
- var methodDeclaration = context.Node.FirstAncestorOrSelf(n => CSharpCommonInterest.MethodSyntaxKinds.Contains(n.Kind()));
- if (methodDeclaration != null)
+ ThreadingContext threadingContext = ThreadingContext.Unknown;
+ SyntaxNode? methodDeclaration = context.Node.FirstAncestorOrSelf(n => CSharpCommonInterest.MethodSyntaxKinds.Contains(n.Kind()));
+ if (methodDeclaration is object)
{
threadingContext = this.methodDeclarationNodes.GetValueOrDefault(methodDeclaration);
}
if (threadingContext != ThreadingContext.MainThread)
{
- var function = CSharpUtils.GetContainingFunction((CSharpSyntaxNode)context.Node);
+ CSharpUtils.ContainingFunctionData function = CSharpUtils.GetContainingFunction((CSharpSyntaxNode)context.Node);
Location location = focusDiagnosticOn ?? context.Node.GetLocation();
- var descriptor = function.IsAsync ? DescriptorAsync : DescriptorSync;
+ DiagnosticDescriptor? descriptor = function.IsAsync ? DescriptorAsync : DescriptorSync;
var formattingArgs = function.IsAsync ? new object[] { type.Name } : new object[] { type.Name, this.MainThreadAssertingMethods.FirstOrDefault() };
context.ReportDiagnostic(Diagnostic.Create(descriptor, location, this.DiagnosticProperties, formattingArgs));
return true;
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD102AvoidJtfRunInNonPublicMembersAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD102AvoidJtfRunInNonPublicMembersAnalyzer.cs
index 97830ef3..88a35955 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD102AvoidJtfRunInNonPublicMembersAnalyzer.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD102AvoidJtfRunInNonPublicMembersAnalyzer.cs
@@ -1,4 +1,7 @@
-namespace Microsoft.VisualStudio.Threading.Analyzers
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.VisualStudio.Threading.Analyzers
{
using System;
using System.Collections.Generic;
@@ -48,15 +51,14 @@
var methodSymbol = ctxt.OwningSymbol as IMethodSymbol;
if (!methodSymbol.HasAsyncCompatibleReturnType() && !Utils.IsPublic(methodSymbol) && !Utils.IsEntrypointMethod(methodSymbol, ctxt.SemanticModel, ctxt.CancellationToken) && !methodSymbol.FindInterfacesImplemented().Any(Utils.IsPublic))
{
- var methodAnalyzer = new MethodAnalyzer();
- ctxt.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeInvocation), SyntaxKind.InvocationExpression);
+ ctxt.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(MethodAnalyzer.AnalyzeInvocation), SyntaxKind.InvocationExpression);
}
});
}
- private class MethodAnalyzer
+ private static class MethodAnalyzer
{
- internal void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
+ internal static void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
{
var invocationExpressionSyntax = (InvocationExpressionSyntax)context.Node;
CSharpCommonInterest.InspectMemberAccess(
diff --git a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD103UseAsyncOptionAnalyzer.cs b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD103UseAsyncOptionAnalyzer.cs
index 5912483c..e64c5793 100644
--- a/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD103UseAsyncOptionAnalyzer.cs
+++ b/src/Microsoft.VisualStudio.Threading.Analyzers.CSharp/VSTHRD103UseAsyncOptionAnalyzer.cs
@@ -1,4 +1,7 @@
-namespace Microsoft.VisualStudio.Threading.Analyzers
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.VisualStudio.Threading.Analyzers
{
using System;
using System.Collections.Generic;
@@ -67,15 +70,14 @@
context.RegisterCodeBlockStartAction(ctxt =>
{
- var methodAnalyzer = new MethodAnalyzer();
- ctxt.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeInvocation), SyntaxKind.InvocationExpression);
- ctxt.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzePropertyGetter), SyntaxKind.SimpleMemberAccessExpression);
+ ctxt.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(MethodAnalyzer.AnalyzeInvocation), SyntaxKind.InvocationExpression);
+ ctxt.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(MethodAnalyzer.AnalyzePropertyGetter), SyntaxKind.SimpleMemberAccessExpression);
});
}
private class MethodAnalyzer
{
- internal void AnalyzePropertyGetter(SyntaxNodeAnalysisContext context)
+ internal static void AnalyzePropertyGetter(SyntaxNodeAnalysisContext context)
{
var memberAccessSyntax = (MemberAccessExpressionSyntax)context.Node;
if (IsInTaskReturningMethodOrDelegate(context))
@@ -84,7 +86,7 @@
}
}
- internal void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
+ internal static void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
{
if (IsInTaskReturningMethodOrDelegate(context))
{
@@ -100,19 +102,19 @@
// Also consider all method calls to check for Async-suffixed alternatives.
ExpressionSyntax invokedMethodName = CSharpUtils.IsolateMethodName(invocationExpressionSyntax);
- var symbolInfo = context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax, context.CancellationToken);
+ SymbolInfo symbolInfo = context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax, context.CancellationToken);
var methodSymbol = symbolInfo.Symbol as IMethodSymbol;
- if (methodSymbol != null && !methodSymbol.Name.EndsWith(VSTHRD200UseAsyncNamingConventionAnalyzer.MandatoryAsyncSuffix) &&
+ if (methodSymbol is object && !methodSymbol.Name.EndsWith(VSTHRD200UseAsyncNamingConventionAnalyzer.MandatoryAsyncSuffix, StringComparison.CurrentCulture) &&
!(methodSymbol.ReturnType?.Name == nameof(Task) && methodSymbol.ReturnType.BelongsToNamespace(Namespaces.SystemThreadingTasks)))
{
string asyncMethodName = methodSymbol.Name + VSTHRD200UseAsyncNamingConventionAnalyzer.MandatoryAsyncSuffix;
- var symbols = context.SemanticModel.LookupSymbols(
+ ImmutableArray symbols = context.SemanticModel.LookupSymbols(
invocationExpressionSyntax.Expression.GetLocation().SourceSpan.Start,
methodSymbol.ContainingType,
asyncMethodName,
includeReducedExtensionMethods: true);
- foreach (var s in symbols)
+ foreach (ISymbol? s in symbols)
{
if (s is IMethodSymbol m
&& !m.IsObsolete()
@@ -121,7 +123,7 @@
&& Utils.HasAsyncCompatibleReturnType(m))
{
// An async alternative exists.
- var properties = ImmutableDictionary.Empty
+ ImmutableDictionary? properties = ImmutableDictionary.Empty
.Add(AsyncMethodKeyName, asyncMethodName);
Diagnostic diagnostic = Diagnostic.Create(
@@ -157,47 +159,47 @@
// We want to scan invocations that occur inside Task and Task-returning delegates or methods.
// That is: methods that either are or could be made async.
IMethodSymbol? methodSymbol = null;
- var anonymousFunc = context.Node.FirstAncestorOrSelf();
- if (anonymousFunc != null)
+ AnonymousFunctionExpressionSyntax? anonymousFunc = context.Node.FirstAncestorOrSelf();
+ if (anonymousFunc is object)
{
- var symbolInfo = context.SemanticModel.GetSymbolInfo(anonymousFunc, context.CancellationToken);
+ SymbolInfo symbolInfo = context.SemanticModel.GetSymbolInfo(anonymousFunc, context.CancellationToken);
methodSymbol = symbolInfo.Symbol as IMethodSymbol;
}
else
{
- var methodDecl = context.Node.FirstAncestorOrSelf();
- if (methodDecl != null)
+ MethodDeclarationSyntax? methodDecl = context.Node.FirstAncestorOrSelf();
+ if (methodDecl is object)
{
methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodDecl, context.CancellationToken);
}
}
- var returnType = methodSymbol?.ReturnType;
+ ITypeSymbol? returnType = methodSymbol?.ReturnType;
return returnType?.Name == nameof(Task)
&& returnType.BelongsToNamespace(Namespaces.SystemThreadingTasks);
}
private static bool InspectMemberAccess(SyntaxNodeAnalysisContext context, [NotNullWhen(true)] MemberAccessExpressionSyntax? memberAccessSyntax, IEnumerable problematicMethods)
{
- if (memberAccessSyntax == null)
+ if (memberAccessSyntax is null)
{
return false;
}
- var memberSymbol = context.SemanticModel.GetSymbolInfo(memberAccessSyntax, context.CancellationToken).Symbol;
- if (memberSymbol != null)
+ ISymbol? memberSymbol = context.SemanticModel.GetSymbolInfo(memberAccessSyntax, context.CancellationToken).Symbol;
+ if (memberSymbol is object)
{
- foreach (var item in problematicMethods)
+ foreach (CommonInterest.SyncBlockingMethod item in problematicMethods)
{
if (item.Method.IsMatch(memberSymbol))
{
- var location = memberAccessSyntax.Name.GetLocation();
- var properties = ImmutableDictionary.Empty
- .Add(ExtensionMethodNamespaceKeyName, item.ExtensionMethodNamespace != null ? string.Join(".", item.ExtensionMethodNamespace) : string.Empty);
+ Location? location = memberAccessSyntax.Name.GetLocation();
+ ImmutableDictionary? properties = ImmutableDictionary.Empty
+ .Add(ExtensionMethodNamespaceKeyName, item.ExtensionMethodNamespace is object ? string.Join(".", item.ExtensionMethodNamespace) : string.Empty);
DiagnosticDescriptor descriptor;
var messageArgs = new List