diff --git a/BuildAndTest.proj b/BuildAndTest.proj
index 64b484d150ce9..b85c5aa0f5b76 100644
--- a/BuildAndTest.proj
+++ b/BuildAndTest.proj
@@ -99,18 +99,29 @@
/rootSuffix:RoslynDev /vsInstallDir:"$([System.IO.Path]::GetFullPath('$(MSBuildBinPath)\..\..\..'))"
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/Compilers.sln b/Compilers.sln
index 603ac6079f602..d22ba9ca90b41 100644
--- a/Compilers.sln
+++ b/Compilers.sln
@@ -26,8 +26,14 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpCompilerSemanticTest", "src\Compilers\CSharp\Test\Semantic\CSharpCompilerSemanticTest.csproj", "{B2C33A93-DB30-4099-903E-77D75C4C3F45}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpCompilerSymbolTest", "src\Compilers\CSharp\Test\Symbol\CSharpCompilerSymbolTest.csproj", "{28026D16-EB0C-40B0-BDA7-11CAA2B97CCC}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpCompilerSyntaxTest", "src\Compilers\CSharp\Test\Syntax\CSharpCompilerSyntaxTest.csproj", "{50D26304-0961-4A51-ABF6-6CAD1A56D202}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VisualBasic", "VisualBasic", "{C65C6143-BED3-46E6-869E-9F0BE6E84C37}"
EndProject
@@ -108,10 +114,19 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSBuildTask", "src\Compilers\Core\MSBuildTask\MSBuildTask.csproj", "{7AD4FE65-9A30-41A6-8004-AA8F89BCB7F3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptingTest", "src\Scripting\CoreTest\ScriptingTest.csproj", "{2DAE4406-7A89-4B5F-95C3-BC5472CE47CE}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpScriptingTest", "src\Scripting\CSharpTest\CSharpScriptingTest.csproj", "{2DAE4406-7A89-4B5F-95C3-BC5422CE47CE}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BasicScriptingTest", "src\Scripting\VisualBasicTest\BasicScriptingTest.vbproj", "{ABC7262E-1053-49F3-B846-E3091BB92E8C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripting", "Scripting", "{3FF38FD4-DF16-44B0-924F-0D5AE155495B}"
EndProject
@@ -144,18 +159,27 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeStyleFixes", "src\CodeStyle\Core\CodeFixes\CodeStyleFixes.csproj", "{5FF1E493-69CC-4D0B-83F2-039F469A04E1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeStyleTests", "src\CodeStyle\Core\Tests\CodeStyleTests.csproj", "{9FF1205F-1D7C-4EE4-B038-3456FE6EBEAF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpCodeStyle", "src\CodeStyle\CSharp\Analyzers\CSharpCodeStyle.csproj", "{AA87BFED-089A-4096-B8D5-690BDC7D5B24}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpCodeStyleFixes", "src\CodeStyle\CSharp\CodeFixes\CSharpCodeStyleFixes.csproj", "{A07ABCF5-BC43-4EE9-8FD8-B2D77FD54D73}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpCodeStyleTests", "src\CodeStyle\CSharp\Tests\CSharpCodeStyleTests.csproj", "{5018D049-5870-465A-889B-C742CE1E31CB}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BasicCodeStyle", "src\CodeStyle\VisualBasic\Analyzers\BasicCodeStyle.vbproj", "{2531A8C4-97DD-47BC-A79C-B7846051E137}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BasicCodeStyleFixes", "src\CodeStyle\VisualBasic\CodeFixes\BasicCodeStyleFixes.vbproj", "{0141285D-8F6C-42C7-BAF3-3C0CCD61C716}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BasicCodeStyleTests", "src\CodeStyle\VisualBasic\Tests\BasicCodeStyleTests.vbproj", "{E512C6C1-F085-4AD7-B0D9-E8F1A0A2A510}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
diff --git a/README.md b/README.md
index 4770c0bfadf0a..09374138191bd 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,7 @@
|**dev15.0.x**|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_debug_unit32/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_debug_unit32/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_debug_unit64/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_debug_unit64/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_release_unit32/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_release_unit32/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_release_unit64/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_release_unit64/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_determinism/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_determinism/)|[![Build Status](https://ci.dot.net/buildStatus/icon?job=dotnet_roslyn/dev15.0.x/windows_debug_vs-integration)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_debug_vs-integration/)|[![Build Status](https://ci.dot.net/buildStatus/icon?job=dotnet_roslyn/dev15.0.x/windows_release_vs-integration)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/windows_release_vs-integration/)|
|**dev15.1.x**|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_debug_unit32/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_debug_unit32/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_debug_unit64/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_debug_unit64/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_release_unit32/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_release_unit32/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_release_unit64/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_release_unit64/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_determinism/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_determinism/)|[![Build Status](https://ci.dot.net/buildStatus/icon?job=dotnet_roslyn/dev15.1.x/windows_debug_vs-integration)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_debug_vs-integration/)|[![Build Status](https://ci.dot.net/buildStatus/icon?job=dotnet_roslyn/dev15.1.x/windows_release_vs-integration)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/windows_release_vs-integration/)|
|**dev15.2.x**|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_debug_unit32/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_debug_unit32/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_debug_unit64/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_debug_unit64/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_release_unit32/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_release_unit32/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_release_unit64/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_release_unit64/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_determinism/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_determinism/)|[![Build Status](https://ci.dot.net/buildStatus/icon?job=dotnet_roslyn/dev15.2.x/windows_debug_vs-integration)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_debug_vs-integration/)|[![Build Status](https://ci.dot.net/buildStatus/icon?job=dotnet_roslyn/dev15.2.x/windows_release_vs-integration)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/windows_release_vs-integration/)|
+|**dev15.3-preview1**|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_debug_unit32/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_debug_unit32/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_debug_unit64/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_debug_unit64/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_release_unit32/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_release_unit32/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_release_unit64/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_release_unit64/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_determinism/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_determinism/)|[![Build Status](https://ci.dot.net/buildStatus/icon?job=dotnet_roslyn/dev15.3-preview1/windows_debug_vs-integration)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_debug_vs-integration/)|[![Build Status](https://ci.dot.net/buildStatus/icon?job=dotnet_roslyn/dev15.3-preview1/windows_release_vs-integration)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/windows_release_vs-integration/)|
|**dev16**|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_debug_unit32/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_debug_unit32/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_debug_unit64/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_debug_unit64/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_release_unit32/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_release_unit32/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_release_unit64/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_release_unit64/)|[![Build Status](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_determinism/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_determinism/)|[![Build Status](https://ci.dot.net/buildStatus/icon?job=dotnet_roslyn/dev16/windows_debug_vs-integration)](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_debug_vs-integration/)|[![Build Status](https://ci.dot.net/buildStatus/icon?job=dotnet_roslyn/dev16/windows_release_vs-integration)](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/windows_release_vs-integration/)|
### Linux/Mac - Unit Tests
@@ -18,6 +19,7 @@
|**dev15.0.x**|[![BuildStatus](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/linux_debug/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/linux_debug/)||[![BuildStatus](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/mac_debug/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.0.x/job/mac_debug/)|
|**dev15.1.x**|[![BuildStatus](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/linux_debug/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/linux_debug/)||[![BuildStatus](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/mac_debug/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.1.x/job/mac_debug/)|
|**dev15.2.x**|[![BuildStatus](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/linux_debug/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/linux_debug/)||[![BuildStatus](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/mac_debug/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.2.x/job/mac_debug/)|
+|**dev15.3-preview1**|[![BuildStatus](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/linux_debug/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/linux_debug/)||[![BuildStatus](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/mac_debug/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev15.3-preview1/job/mac_debug/)|
|**dev16**|[![BuildStatus](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/ubuntu_14_debug/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/ubuntu_14_debug/)|[![BuildStatus](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/ubuntu_16_debug/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/ubuntu_16_debug/)|[![BuildStatus](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/mac_debug/badge/icon)](https://ci.dot.net/job/dotnet_roslyn/job/dev16/job/mac_debug/)|
[//]: # (End current test results)
diff --git a/Roslyn.sln b/Roslyn.sln
index ec802e0e67bcf..41f0b21ebc336 100644
--- a/Roslyn.sln
+++ b/Roslyn.sln
@@ -28,8 +28,14 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpCompilerSemanticTest", "src\Compilers\CSharp\Test\Semantic\CSharpCompilerSemanticTest.csproj", "{B2C33A93-DB30-4099-903E-77D75C4C3F45}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpCompilerSymbolTest", "src\Compilers\CSharp\Test\Symbol\CSharpCompilerSymbolTest.csproj", "{28026D16-EB0C-40B0-BDA7-11CAA2B97CCC}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpCompilerSyntaxTest", "src\Compilers\CSharp\Test\Syntax\CSharpCompilerSyntaxTest.csproj", "{50D26304-0961-4A51-ABF6-6CAD1A56D202}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VisualBasic", "VisualBasic", "{C65C6143-BED3-46E6-869E-9F0BE6E84C37}"
EndProject
@@ -106,10 +112,16 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scripting", "src\Scripting\Core\Scripting.csproj", "{12A68549-4E8C-42D6-8703-A09335F97997}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptingTest", "src\Scripting\CoreTest\ScriptingTest.csproj", "{2DAE4406-7A89-4B5F-95C3-BC5472CE47CE}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpScripting", "src\Scripting\CSharp\CSharpScripting.csproj", "{066F0DBD-C46C-4C20-AFEC-99829A172625}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpScriptingTest", "src\Scripting\CSharpTest\CSharpScriptingTest.csproj", "{2DAE4406-7A89-4B5F-95C3-BC5422CE47CE}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InteractiveFeatures", "src\Interactive\Features\InteractiveFeatures.csproj", "{8E2A252E-A140-45A6-A81A-2652996EA589}"
EndProject
@@ -250,6 +262,9 @@ EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BasicScriptingTest.Desktop", "src\Scripting\VisualBasicTest.Desktop\BasicScriptingTest.Desktop.vbproj", "{24973B4C-FD09-4EE1-97F4-EA03E6B12040}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BasicScriptingTest", "src\Scripting\VisualBasicTest\BasicScriptingTest.vbproj", "{ABC7262E-1053-49F3-B846-E3091BB92E8C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Diagnostics", "src\Test\Diagnostics\Diagnostics.csproj", "{E2E889A5-2489-4546-9194-47C63E49EAEB}"
EndProject
@@ -371,10 +386,19 @@ EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BasicCodeStyleFixes", "src\CodeStyle\VisualBasic\CodeFixes\BasicCodeStyleFixes.vbproj", "{0141285D-8F6C-42C7-BAF3-3C0CCD61C716}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeStyleTests", "src\CodeStyle\Core\Tests\CodeStyleTests.csproj", "{9FF1205F-1D7C-4EE4-B038-3456FE6EBEAF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpCodeStyleTests", "src\CodeStyle\CSharp\Tests\CSharpCodeStyleTests.csproj", "{5018D049-5870-465A-889B-C742CE1E31CB}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "BasicCodeStyleTests", "src\CodeStyle\VisualBasic\Tests\BasicCodeStyleTests.vbproj", "{E512C6C1-F085-4AD7-B0D9-E8F1A0A2A510}"
+ ProjectSection(ProjectDependencies) = postProject
+ {76C6F005-C89D-4348-BB4A-391898DBEB52} = {76C6F005-C89D-4348-BB4A-391898DBEB52}
+ EndProjectSection
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
diff --git a/build/Rulesets/Roslyn_BuildRules.ruleset b/build/Rulesets/Roslyn_BuildRules.ruleset
index c2da92b629f26..80a582eb370aa 100644
--- a/build/Rulesets/Roslyn_BuildRules.ruleset
+++ b/build/Rulesets/Roslyn_BuildRules.ruleset
@@ -20,6 +20,7 @@
+
@@ -35,9 +36,19 @@
+
+
+
+
+
+
+
+
+
+
@@ -45,6 +56,8 @@
+
+
@@ -110,4 +123,4 @@
-
\ No newline at end of file
+
diff --git a/build/Targets/Dependencies.props b/build/Targets/Dependencies.props
index d25f03b1feea3..f9a8a6fadf63d 100644
--- a/build/Targets/Dependencies.props
+++ b/build/Targets/Dependencies.props
@@ -2,6 +2,7 @@
+ 0.9.2
3.0.0-unstable0085
1.9.4
0.2.0
@@ -21,7 +22,7 @@
0.8.31-beta
1.0.35
1.1.0
- 1.0.0-beta1-61518-02
+ 1.0.0-beta1-61618-01
1.5.0
1.2.0
1.0.0-beta1-61531-03
diff --git a/build/Targets/Imports.targets b/build/Targets/Imports.targets
index 4ca1c5aa511d5..a41f3d1d7df7e 100644
--- a/build/Targets/Imports.targets
+++ b/build/Targets/Imports.targets
@@ -11,14 +11,14 @@
<_CopyReferences>false
<_CopyProjectReferences>false
false
- $(OutDir)Exes\$(MSBuildProjectName)\
+ $(OutputPath)Exes\$(MSBuildProjectName)\
<_IsAnyUnitTest>true
true
- $(OutDir)UnitTests\$(MSBuildProjectName)\
+ $(OutputPath)UnitTests\$(MSBuildProjectName)\
@@ -39,21 +39,21 @@
<_IsAnyUnitTest>true
<_IsAnyPortableUnitTest>true
false
- $(OutDir)Dlls\$(MSBuildProjectName)\
+ $(OutputPath)Dlls\$(MSBuildProjectName)\
<_CopyReferences>false
false
- $(OutDir)Exes\
+ $(OutputPath)Exes\
<_CopyReferences>false
true
- $(OutDir)Vsix\$(MSBuildProjectName)\
+ $(OutputPath)Vsix\$(MSBuildProjectName)\
@@ -62,8 +62,8 @@
$(AllowedReferenceRelatedFileExtensions);.pdb
true
- $(OutDir)CoreClrTest
- $(OutDir)UnitTests\Portable\
+ $(OutputPath)CoreClrTest
+ $(OutputPath)UnitTests\Portable\
@@ -74,19 +74,19 @@
<_CopyReferences>false
<_CopyProjectReferences>false
false
- $(OutDir)Dlls\$(MSBuildProjectName)\
+ $(OutputPath)Dlls\$(MSBuildProjectName)\
true
- $(OutDir)Exes\$(MSBuildProjectName)\
+ $(OutputPath)Exes\$(MSBuildProjectName)\
true
- $(OutDir)Exes\$(MSBuildProjectName)\
+ $(OutputPath)Exes\$(MSBuildProjectName)\
@@ -114,7 +114,6 @@
- $(OutDir)
0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9
002400000480000094000000060200000024000052534131000400000100010055e0217eb635f69281051f9a823e0c7edd90f28063eb6c7a742a19b4f6139778ee0af438f47aed3b6e9f99838aa8dba689c7a71ddb860c96d923830b57bbd5cd6119406ddb9b002cf1c723bf272d6acbb7129e9d6dd5a5309c94e0ff4b2c884d45a55f475cd7dba59198086f61f5a8c8b5e601c0edbf269733f6f578fc8579c2
@@ -367,6 +366,7 @@
DeployPortableOnDeveloperBuild;$(PrepareResourcesDependsOn)
+ RemoveDuplicateXUnitContent;$(PrepareForBuildDependsOn)
$(IntermediateOutputPath)$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)
$(IntermediateOutputPath)$(TargetFileName).pcbm
$(NuGetPackageRoot)\RoslynDependencies.OptimizationData\2.0.0-rc-61101-16\content\OptimizationData
@@ -464,10 +464,29 @@
Targets="GetTargetPath"
BuildInParallel="true">
-
+
+
+
+
+
+
+
+
diff --git a/build/Targets/Roslyn.Toolsets.Xunit.targets b/build/Targets/Roslyn.Toolsets.Xunit.targets
index 4b837cd3fca06..39950a76c6cf7 100644
--- a/build/Targets/Roslyn.Toolsets.Xunit.targets
+++ b/build/Targets/Roslyn.Toolsets.Xunit.targets
@@ -32,7 +32,5 @@
app.config
-
-
-
\ No newline at end of file
+
diff --git a/build/Targets/Settings.props b/build/Targets/Settings.props
index a702d4dd7508d..fce63778e6a8b 100644
--- a/build/Targets/Settings.props
+++ b/build/Targets/Settings.props
@@ -18,7 +18,7 @@
2.0.1
RoslynTools.Microsoft.VSIXExpInstaller
0.2.1-beta
- 1.2.0-beta2
+ 2.0.0-beta1-61628-06
$(NuGetPackageRoot)\Microsoft.Net.RoslynDiagnostics\$(RoslynDiagnosticsNugetPackageVersion)\build\Microsoft.Net.RoslynDiagnostics.props
$(NuGetPackageRoot)\Roslyn.Build.Util\0.9.4-portable\lib\dotnet\Roslyn.MSBuild.Util.dll
$(AdditionalFileItemNames);PublicAPI
@@ -27,7 +27,7 @@
true
true
$(RepoRoot)Binaries\
- $(BaseOutputPath)$(Configuration)\
+ $(BaseOutputPath)$(Configuration)\
$(RepoRoot)Binaries\Obj\
$(BaseIntermediateOutputPath)$(Configuration)\$(MSBuildProjectName)\
@@ -47,7 +47,7 @@
$(VisualStudioVersion)
false
diff --git a/build/ToolsetPackages/project.json b/build/ToolsetPackages/project.json
index 394e26814b195..cf83655a35253 100644
--- a/build/ToolsetPackages/project.json
+++ b/build/ToolsetPackages/project.json
@@ -7,7 +7,7 @@
"Microsoft.NETCore.Platforms": "1.1.0",
"Microsoft.DiaSymReader.Native": "1.5.0",
"Microsoft.Net.Compilers": "2.0.1",
- "Microsoft.Net.RoslynDiagnostics": "1.2.0-beta2",
+ "Microsoft.Net.RoslynDiagnostics": "2.0.0-beta1-61628-06",
"FakeSign": "0.9.2",
"xunit": "2.2.0-beta4-build3444",
"xunit.runner.console": "2.2.0-beta4-build3444",
diff --git a/build/config/RepoUtilData.json b/build/config/RepoUtilData.json
index ebd46ab5a2463..85ecd228dc5f7 100644
--- a/build/config/RepoUtilData.json
+++ b/build/config/RepoUtilData.json
@@ -50,7 +50,8 @@
"GitLink",
"Microsoft.NETCore.Runtime.CoreCLR",
"Microsoft.VSSDK.BuildTools",
- "NETStandard.Library"
+ "NETStandard.Library",
+ "FakeSign"
]
}
},
diff --git a/build/config/SignToolData.json b/build/config/SignToolData.json
index ce3c84e033ff4..e3e9589e83567 100644
--- a/build/config/SignToolData.json
+++ b/build/config/SignToolData.json
@@ -1,7 +1,7 @@
{
"sign": [
{
- "certificate": "Microsoft402",
+ "certificate": "MicrosoftSHA2",
"strongName": "MsSharedLib72",
"values": [
"Dlls\\BasicCodeAnalysis\\Microsoft.CodeAnalysis.VisualBasic.dll",
diff --git a/build/scripts/build-utils.ps1 b/build/scripts/build-utils.ps1
index c8c66eb70a275..2f24e9b2055a3 100644
--- a/build/scripts/build-utils.ps1
+++ b/build/scripts/build-utils.ps1
@@ -9,43 +9,89 @@ $ErrorActionPreference="Stop"
# Handy function for executing a command in powershell and throwing if it
# fails.
+#
+# Use this when the full command is known at script authoring time and
+# doesn't require any dynamic argument build up. Example:
+#
+# Exec-Block { & $msbuild Test.proj }
#
# Original sample came from: http://jameskovacs.com/2010/02/25/the-exec-problem/
-function Exec([scriptblock]$cmd, [switch]$echo = $false) {
- if ($echo) {
- & $cmd
- }
- else {
- $output = & $cmd
- }
+function Exec-Block([scriptblock]$cmd) {
+ & $cmd
# Need to check both of these cases for errors as they represent different items
# - $?: did the powershell script block throw an error
# - $lastexitcode: did a windows command executed by the script block end in error
if ((-not $?) -or ($lastexitcode -ne 0)) {
- if (-not $echo) {
- Write-Host $output
- }
throw "Command failed to execute: $cmd"
}
}
-function Exec-Echo([scriptblock]$cmd) {
- Exec $cmd -echo:$true
+# Handy function for executing a windows command which needs to go through
+# windows command line parsing.
+#
+# Use this when the command arguments are stored in a variable. Particularly
+# when the variable needs reparsing by the windows command line. Example:
+#
+# $args = "/p:ManualBuild=true Test.proj"
+# Exec-Command $msbuild $args
+#
+function Exec-Command([string]$command, [string]$commandArgs) {
+ $startInfo = New-Object System.Diagnostics.ProcessStartInfo
+ $startInfo.FileName = $command
+ $startInfo.Arguments = $commandArgs
+
+ $startInfo.RedirectStandardOutput = $true
+ $startInfo.UseShellExecute = $false
+ $startInfo.CreateNoWindow = $true
+
+ $process = New-Object System.Diagnostics.Process
+ $process.StartInfo = $startInfo
+ $process.StartInfo.RedirectStandardOutput = $true;
+ $process.Start() | Out-Null
+
+ $finished = $false
+ try {
+ # The OutputDataReceived event doesn't fire as events are sent by the
+ # process in powershell. Possibly due to subtlties of how Powershell
+ # manages the thread pool that I'm not aware of. Using blocking
+ # reading here as an alternative which is fine since this blocks
+ # on completion already.
+ $out = $process.StandardOutput
+ while (-not $out.EndOfStream) {
+ $line = $out.ReadLine()
+ Write-Output $line
+ }
+
+ while (-not $process.WaitForExit(100)) {
+ # Non-blocking loop done to allow ctr-c interrupts
+ }
+
+ $finished = $true
+ if ($process.ExitCode -ne 0) {
+ throw "Command failed to execute: $command $commandArgs"
+ }
+ }
+ finally {
+ # If we didn't finish then an error occured or the user hit ctrl-c. Either
+ # way kill the process
+ if (-not $finished) {
+ $process.Kill()
+ }
+ }
}
-# Handy function for executing Invoke-Expression and reliably throwing an
-# error if the expression, or the command it invoked, fails
-#
-# Original sample came from: http://jameskovacs.com/2010/02/25/the-exec-problem/
-function Exec-Expression([string]$expr) {
- Exec { Invoke-Expression $expr } -echo:$true
+# Handy function for executing a powershell script in a clean environment with
+# arguments. Prefer this over & sourcing a script as it will both use a clean
+# environment and do proper error checking
+function Exec-Script([string]$script, [string]$scriptArgs = "") {
+ Exec-Command "powershell" "-noprofile -executionPolicy RemoteSigned -file `"$script`" $scriptArgs"
}
# Ensure that NuGet is installed and return the path to the
# executable to use.
function Ensure-NuGet() {
- Exec { & (Join-Path $PSScriptRoot "download-nuget.ps1") }
+ Exec-Block { & (Join-Path $PSScriptRoot "download-nuget.ps1") } | Out-Host
$nuget = Join-Path $repoDir "NuGet.exe"
return $nuget
}
@@ -56,7 +102,7 @@ function Ensure-BasicTool([string]$name, [string]$version) {
$p = Join-Path (Get-PackagesDir) "$($name).$($version)"
if (-not (Test-Path $p)) {
$nuget = Ensure-NuGet
- Exec { & $nuget install $name -OutputDirectory (Get-PackagesDir) -Version $version }
+ Exec-Block { & $nuget install $name -OutputDirectory (Get-PackagesDir) -Version $version } | Out-Null
}
return $p
@@ -206,14 +252,14 @@ function Get-VisualStudioDir() {
# Clear out the NuGet package cache
function Clear-PackageCache() {
$nuget = Ensure-NuGet
- Exec { & $nuget locals all -clear }
+ Exec-Block { & $nuget locals all -clear } | Out-Host
}
# Restore a single project
function Restore-Project([string]$fileName, [string]$nuget, [string]$msbuildDir) {
$nugetConfig = Join-Path $repoDir "nuget.config"
$filePath = Join-Path $repoDir $fileName
- Exec { & $nuget restore -verbosity quiet -configfile $nugetConfig -MSBuildPath $msbuildDir -Project2ProjectTimeOut 1200 $filePath }
+ Exec-Block { & $nuget restore -verbosity quiet -configfile $nugetConfig -MSBuildPath $msbuildDir -Project2ProjectTimeOut 1200 $filePath } | Out-Null
}
# Restore all of the projects that the repo consumes
diff --git a/build/scripts/build.ps1 b/build/scripts/build.ps1
index b59fbd8b0b40b..0c53de2ab25be 100644
--- a/build/scripts/build.ps1
+++ b/build/scripts/build.ps1
@@ -4,6 +4,7 @@ param (
[switch]$build = $false,
[switch]$restore = $false,
[switch]$test = $false,
+ [switch]$test64 = $false,
[switch]$clean = $false,
[switch]$clearPackageCache = $false,
[string]$project = "",
@@ -17,7 +18,8 @@ function Print-Usage() {
Write-Host "Build.ps1"
Write-Host "`t-build Run a build operation (default false)"
Write-Host "`t-restore Run a restore operation (default false)"
- Write-Host "`t-test Run tests (default false)"
+ Write-Host "`t-test Run unit tests (default false)"
+ Write-Host "`t-test64 Run unit tests in 64 bit mode"
Write-Host "`t-clean Do a clean build / restore (default false)"
Write-Host "`t-clearPackageCache Clear package cache before restoring"
Write-Host "`t-project Project the build or restore should target"
@@ -33,12 +35,16 @@ function Run-Build() {
$target = if ($project -ne "") { $project } else { Join-Path $repoDir "Roslyn.sln" }
$buildArgs = "$buildArgs $target"
- Exec-Expression "& `"$msbuild`" $buildArgs"
+ Exec-Command $msbuild $buildArgs | Out-Host
}
function Run-Test() {
$proj = Join-Path $repoDir "BuildAndTest.proj"
- Exec-Expression "& `"$msbuild`" /v:m /p:SkipCoreClr=true /t:Test $proj"
+ $args = "/v:m /p:SkipCoreClr=true /p:ManualTest=true /t:Test $proj"
+ if ($test64) {
+ $args += " /p:Test64=true"
+ }
+ Exec-Command $msbuild $args | Out-Host
}
try {
@@ -68,7 +74,7 @@ try {
Run-Build
}
- if ($test) {
+ if ($test -or $test64) {
Run-Test
}
}
diff --git a/build/scripts/check-toolset-insertion.ps1 b/build/scripts/check-toolset-insertion.ps1
index 8d1493aa66545..a5e4e15f790f3 100644
--- a/build/scripts/check-toolset-insertion.ps1
+++ b/build/scripts/check-toolset-insertion.ps1
@@ -21,6 +21,11 @@ try
"Microsoft.Build.Utilities.Core.dll",
"Microsoft.DiaSymReader.Native.arm.dll"
)
+
+ $exludedFromVsix = @(
+ "Microsoft.DiaSymReader.Native.x86.dll", # installed by msbuild setup component
+ "Microsoft.DiaSymReader.Native.amd64.dll" # installed by msbuild setup component
+ )
$deploymentPath = join-path $binariesPath "Exes\Toolset"
$deployedFiles =
@@ -92,7 +97,7 @@ try
foreach ($file in $deployedFiles)
{
write-host "`t$file"
- if ($msbuildroslynfiles.Contains($file))
+ if ($msbuildroslynfiles.Contains($file) -or $exludedFromVsix.Contains($file))
{
continue;
}
diff --git a/build/scripts/cibuild.ps1 b/build/scripts/cibuild.ps1
index a7916ead7132c..75fe3f9fc00c4 100644
--- a/build/scripts/cibuild.ps1
+++ b/build/scripts/cibuild.ps1
@@ -11,6 +11,8 @@ param (
[switch]$skipRestore = $false,
[switch]$skipCommitPrinting = $false,
[switch]$release = $false,
+ [switch]$skipCoreClrTests = $false,
+ [switch]$skipDesktopTests = $false,
[parameter(ValueFromRemainingArguments=$true)] $badArgs)
Set-StrictMode -version 2.0
@@ -24,6 +26,8 @@ function Print-Usage() {
Write-Host " -test64 Run units tests in the 64-bit runner."
Write-Host " -$testVsi Run all integration tests."
Write-Host " -$testVsiNetCore Run just dotnet core integration tests."
+ Write-Host " -skipCoreClrTests Skip running unit tests on CoreCLR"
+ Write-Host " -skipDesktopTests Skip running unit tests on Desktop"
}
function Run-MSBuild() {
@@ -31,10 +35,12 @@ function Run-MSBuild() {
# that we do not reuse MSBuild nodes from other jobs/builds on the machine. Otherwise,
# we'll run into issues such as https://github.com/dotnet/roslyn/issues/6211.
# MSBuildAdditionalCommandLineArgs=
- & $msbuild /warnaserror /nologo /m /nodeReuse:false /consoleloggerparameters:Verbosity=minimal /filelogger /fileloggerparameters:Verbosity=normal @args
- if (-not $?) {
- throw "Build failed"
+ $buildArgs = "/warnaserror /nologo /m /nodeReuse:false /consoleloggerparameters:Verbosity=minimal /filelogger /fileloggerparameters:Verbosity=normal"
+ foreach ($arg in $args) {
+ $buildArgs += " $arg"
}
+
+ Exec-Command $msbuild $buildArgs
}
# Kill any instances VBCSCompiler.exe to release locked files, ignoring stderr if process is not open
@@ -87,14 +93,14 @@ try {
Redirect-Temp
if ($testBuildCorrectness) {
- Exec-Echo { & ".\build\scripts\test-build-correctness.ps1" -config $buildConfiguration }
+ Exec-Block { & ".\build\scripts\test-build-correctness.ps1" -config $buildConfiguration } | Out-Host
exit 0
}
# Output the commit that we're building, for reference in Jenkins logs
if (-not $skipCommitPrinting) {
Write-Host "Building this commit:"
- Exec { & git show --no-patch --pretty=raw HEAD }
+ Exec-Block { & git show --no-patch --pretty=raw HEAD } | Out-Host
}
# Build with the real assembly version, since that's what's contained in the bootstrap compiler redirects
@@ -108,14 +114,14 @@ try {
Terminate-BuildProcesses
if ($testDeterminism) {
- Exec { & ".\build\scripts\test-determinism.ps1" -buildDir $bootstrapDir }
+ Exec-Block { & ".\build\scripts\test-determinism.ps1" -buildDir $bootstrapDir } | Out-Host
Terminate-BuildProcesses
exit 0
}
if ($testPerfCorrectness) {
Run-MSBuild Roslyn.sln /p:Configuration=$buildConfiguration /p:DeployExtension=false
- Exec { & ".\Binaries\$buildConfiguration\Exes\Perf.Runner\Roslyn.Test.Performance.Runner.exe" --ci-test }
+ Exec-Block { & ".\Binaries\$buildConfiguration\Exes\Perf.Runner\Roslyn.Test.Performance.Runner.exe" --ci-test } | Out-Host
exit 0
}
@@ -140,7 +146,7 @@ try {
Create-Directory ".\Binaries\$buildConfiguration\tools\"
# Get the benchview tools - Place alongside Roslyn.Test.Performance.Runner.exe
- Exec { & ".\build\scripts\install_benchview_tools.cmd" ".\Binaries\$buildConfiguration\tools\" }
+ Exec-Block { & ".\build\scripts\install_benchview_tools.cmd" ".\Binaries\$buildConfiguration\tools\" } | Out-Host
}
Terminate-BuildProcesses
@@ -154,13 +160,15 @@ try {
$target = if ($skipTest) { "Build" } else { "BuildAndTest" }
$test64Arg = if ($test64) { "true" } else { "false" }
$testVsiArg = if ($testVsi) { "true" } else { "false" }
+ $skipCoreClrTestsArg = if ($skipCoreClrTests) { "true" } else { "false" }
+ $skipDesktopTestsArg = if ($skipDesktopTests) { "true" } else { "false" }
$buildLog = Join-Path $binariesdir "Build.log"
if ($testVsiNetCore) {
- Run-MSBuild /p:BootstrapBuildPath="$bootstrapDir" BuildAndTest.proj /t:$target /p:Configuration=$buildConfiguration /p:Test64=$test64Arg /p:TestVsi=true /p:Trait="Feature=NetCore" /p:PathMap="$($repoDir)=q:\roslyn" /p:Feature=pdb-path-determinism /fileloggerparameters:LogFile="$buildLog"`;verbosity=diagnostic /p:DeployExtension=false
+ Run-MSBuild /p:BootstrapBuildPath="$bootstrapDir" BuildAndTest.proj /t:$target /p:Configuration=$buildConfiguration /p:Test64=$test64Arg /p:TestVsi=true /p:SkipCoreClrTest=$skipCoreClrTestsArg /p:SkipDesktopTest=$skipDesktopTestsArg /p:Trait="Feature=NetCore" /p:PathMap="$($repoDir)=q:\roslyn" /p:Feature=pdb-path-determinism /fileloggerparameters:LogFile="$buildLog"`;verbosity=diagnostic /p:DeployExtension=false
}
else {
- Run-MSBuild /p:BootstrapBuildPath="$bootstrapDir" BuildAndTest.proj /t:$target /p:Configuration=$buildConfiguration /p:Test64=$test64Arg /p:TestVsi=$testVsiArg /p:PathMap="$($repoDir)=q:\roslyn" /p:Feature=pdb-path-determinism /fileloggerparameters:LogFile="$buildLog"`;verbosity=diagnostic /p:DeployExtension=false
+ Run-MSBuild /p:BootstrapBuildPath="$bootstrapDir" BuildAndTest.proj /t:$target /p:Configuration=$buildConfiguration /p:Test64=$test64Arg /p:TestVsi=$testVsiArg /p:SkipCoreClrTest=$skipCoreClrTestsArg /p:SkipDesktopTest=$skipDesktopTestsArg /p:PathMap="$($repoDir)=q:\roslyn" /p:Feature=pdb-path-determinism /fileloggerparameters:LogFile="$buildLog"`;verbosity=diagnostic /p:DeployExtension=false
}
exit 0
diff --git a/build/scripts/generate-compiler-code.ps1 b/build/scripts/generate-compiler-code.ps1
index 4ac3612f9f037..d9acdedfd0de1 100644
--- a/build/scripts/generate-compiler-code.ps1
+++ b/build/scripts/generate-compiler-code.ps1
@@ -14,10 +14,7 @@ function Run-Tool($tool, $toolArgs) {
throw "$tool does not exist"
}
- Exec-Expression "& `"$coreRun`" `"$tool`" $toolArgs"
- if ((-not $?) -or ($lastexitcode -ne 0)) {
- throw "Failed"
- }
+ Exec-Command "$coreRun" "`"$tool`" $toolArgs" | Out-Host
}
function Run-LanguageCore($language, $languageSuffix, $languageDir, $syntaxTool, $errorFactsTool, $generatedDir, $generatedTestDir) {
diff --git a/build/scripts/test-build-correctness.ps1 b/build/scripts/test-build-correctness.ps1
index 85b00ec69ce99..dd2055da0f9ce 100644
--- a/build/scripts/test-build-correctness.ps1
+++ b/build/scripts/test-build-correctness.ps1
@@ -34,24 +34,24 @@ try {
}
Write-Host "Building Roslyn.sln with logging support"
- Exec-Echo { & $msbuild /v:m /m /logger:StructuredLogger`,$structuredLoggerPath`;$logPath /nodeReuse:false /p:DeployExtension=false Roslyn.sln }
+ Exec-Command $msbuild "/v:m /m /logger:StructuredLogger,$structuredLoggerPath;$logPath /nodeReuse:false /p:DeployExtension=false Roslyn.sln"
Write-Host ""
# Verify the state of our various build artifacts
Write-Host "Running BuildBoss"
$buildBossPath = Join-Path $configDir "Exes\BuildBoss\BuildBoss.exe"
- Exec-Echo { & $buildBossPath Roslyn.sln Compilers.sln src\Samples\Samples.sln CrossPlatform.sln "build\Targets" $logPath }
+ Exec-Command $buildBossPath "Roslyn.sln Compilers.sln src\Samples\Samples.sln CrossPlatform.sln build\Targets $logPath"
Write-Host ""
# Verify the state of our project.jsons
Write-Host "Running RepoUtil"
$repoUtilPath = Join-Path $configDir "Exes\RepoUtil\RepoUtil.exe"
- Exec-Echo { & $repoUtilPath verify }
+ Exec-Command $repoUtilPath verify
Write-Host ""
# Verify the state of our generated syntax files
Write-Host "Checking generated compiler files"
- Exec-Echo { & (Join-Path $PSScriptRoot "generate-compiler-code.ps1") -test }
+ Exec-Block { & (Join-Path $PSScriptRoot "generate-compiler-code.ps1") -test }
exit 0
}
diff --git a/build/scripts/test-determinism.ps1 b/build/scripts/test-determinism.ps1
index 93d178d868a37..de59d2b6f71c2 100644
--- a/build/scripts/test-determinism.ps1
+++ b/build/scripts/test-determinism.ps1
@@ -37,12 +37,10 @@ function Run-Build() {
# Clean out the previous run
Write-Host "Cleaning the Binaries"
- Remove-Item -re -fo $debugDir
- Remove-Item -re -fo $objDir
- Exec {& $msbuild /nologo /v:m /nodeReuse:false /t:clean $sln }
+ Exec-Command $msbuild "/nologo /v:m /nodeReuse:false /t:clean $sln"
Write-Host "Building the Solution"
- Exec { & $msbuild /nologo /v:m /nodeReuse:false /m /p:DebugDeterminism=true /p:BootstrapBuildPath=$script:buildDir '/p:Features="debug-determinism;pdb-path-determinism"' /p:UseRoslynAnalyzers=false $pathMapBuildOption $sln }
+ Exec-Command $msbuild "/nologo /v:m /nodeReuse:false /m /p:DebugDeterminism=true /p:BootstrapBuildPath=$script:buildDir /p:Features=`"debug-determinism;pdb-path-determinism`" /p:UseRoslynAnalyzers=false $pathMapBuildOption $sln"
}
finally {
Pop-Location
diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md
index fdc296f49a43e..ab18ef653b598 100644
--- a/docs/Language Feature Status.md
+++ b/docs/Language Feature Status.md
@@ -1,7 +1,7 @@
Language Feature Status
=====
-This document reflects the status, and planned work, for the compiler team. It is a live document
+This document reflects the status, and planned work in progress, for the compiler team. It is a live document
and will be updated as work progresses, features are added / removed, and as work on feature progresses.
This is not an exhaustive list of our features but rather the ones which have active development
efforts behind them.
@@ -13,7 +13,8 @@ efforts behind them.
| [Async Main](https://github.com/dotnet/csharplang/blob/master/proposals/async-main.md) | [async-main](https://github.com/dotnet/roslyn/tree/features/async-main) | Prototype | [tyoverby](https://github.com/tyoverby) | [vsadov](https://github.com/vsadov) | [stephentoub](https://github.com/stephentoub) |
| [Default Expressions](https://github.com/dotnet/csharplang/blob/master/proposals/target-typed-default.md) | master | Merged | [jcouv](https://github.com/jcouv) | [cston](https://github.com/cston) | [jcouv](https://github.com/jcouv) |
| [Ref Assemblies](https://github.com/dotnet/roslyn/blob/features/refout/docs/features/refout.md) | [refout](https://github.com/dotnet/roslyn/tree/features/refout) | Integration & validation | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | N/A |
-| [Infer tuple names](https://github.com/dotnet/csharplang/blob/master/proposals/target-typed-default.md) | [tuple-names](https://github.com/dotnet/roslyn/tree/features/tuple-names) | Implementation | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) |
+| [Infer tuple names](https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.1/infer-tuple-names.md) | master | Merged | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) |
+| [Pattern-matching with generics](https://github.com/dotnet/csharplang/blob/master/proposals/generics-pattern-match.md) | https://github.com/dotnet/roslyn/pull/18784 | Implementation | [gafter](https://github.com/gafter) | [agocke](https://github.com/agocke) | [gafter](https://github.com/gafter) |
# C# 7.2
@@ -27,8 +28,8 @@ efforts behind them.
| Feature | Branch | State | Developers | Reviewer | LDM Champ |
| ------- | ------ | ----- | ---------- | -------- | --------- |
-| [Default Interface Methods](https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md) | [defaultInterfaceImplementation](https://github.com/dotnet/roslyn/tree/features/DefaultInterfaceImplementation) | Proposal | [AlekseyTs](https://github.com/AlekseyTs) | [gafter](https://github.com/gafter) | [gafter](https://github.com/gafter) |
-| [Nullable reference type](https://github.com/dotnet/roslyn/blob/features/NullableReferenceTypes/docs/features/NullableReferenceTypes/Nullable%20reference%20types.md) | none | Prototype | [cston](https://github.com/cston), [AlekseyTs](https://github.com/AlekseyTs) | | [gafter](https://github.com/gafter) |
+| [Default Interface Methods](https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md) | [defaultInterfaceImplementation](https://github.com/dotnet/roslyn/tree/features/DefaultInterfaceImplementation) | Prototype | [AlekseyTs](https://github.com/AlekseyTs) | [gafter](https://github.com/gafter) | [gafter](https://github.com/gafter) |
+| [Nullable reference type](https://github.com/dotnet/roslyn/blob/features/NullableReferenceTypes/docs/features/NullableReferenceTypes/Nullable%20reference%20types.md) | [NullableReferenceTypes](https://github.com/dotnet/roslyn/tree/features/NullableReferenceTypes) | Prototype | [cston](https://github.com/cston), [AlekseyTs](https://github.com/AlekseyTs) | | [mattwar](https://github.com/mattwar) |
# FAQ
diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - post VS2017.md b/docs/compilers/CSharp/Compiler Breaking Changes - post VS2017.md
index f324e453a2591..f35cbb494ee15 100644
--- a/docs/compilers/CSharp/Compiler Breaking Changes - post VS2017.md
+++ b/docs/compilers/CSharp/Compiler Breaking Changes - post VS2017.md
@@ -7,3 +7,10 @@ In C# 7, the compiler accepted a pattern of the form `dynamic identifier`, e.g.
- https://github.com/dotnet/roslyn/issues/17674 In C# 7, the compiler accepted an assignment statement of the form `_ = M();` where M is a `void` method. The compiler now rejects that.
- https://github.com/dotnet/roslyn/issues/17173 Before C# 7.1, `csc` would accept leading zeroes in the `/langversion` option. Now it should reject it. Example: `csc.exe source.cs /langversion:07`.
+
+- https://github.com/dotnet/csharplang/issues/415
+In C# 7.0, elements in tuple literals can be named explicitly, but in C# 7.1, elements that aren't named explicitly will get an inferred named. This uses the same rules as members in anonymous types which aren't named explicitly.
+For instance, `var t = (a, b.c, this.d);` will produce a tuple with element names "a", "c" and "d". As a result, an invocation on a tuple member may result in a different result than it did in C# 7.0.
+Consider the case where the type of `a` is `System.Func` and you write `var local = t.a();`. This will now find the first element of the tuple and invoke it, whereas previously it could only mean "invoke an extension method named 'a'".
+
+- https://github.com/dotnet/roslyn/issues/16870 In C# 7.0 and before C# 7.1, the compiler accepted self-assignments in deconstruction-assignment. The compiler now produces a warning for that. For instance, in `(x, y) = (x, 2);`.
diff --git a/docs/compilers/Design/Closure Conversion.md b/docs/compilers/Design/Closure Conversion.md
new file mode 100644
index 0000000000000..9f7574764ed6c
--- /dev/null
+++ b/docs/compilers/Design/Closure Conversion.md
@@ -0,0 +1,175 @@
+Closure Conversion in C#
+========================
+
+This document describes the how the C# compiler turns closures (anonymous and local functions) into top-level functions (methods).
+
+If you aren't familiar with closure conversion, the introduction contains a walkthrough describing the transformations. Otherwise, you can skip to the Internals section to see how the actual transformations are done in Roslyn.
+
+# Introduction
+
+In the simplest case, this is trivial -- all closures are simply given new, unmentionable names and are lifted to the top level as static methods. The complexity comes when a closure captures a variable from its surrounding scope. At that point, we must not only move the closure to a method, we also have to create an "environment" to hold its captured variables and somehow deliver that environment into the context of the rewritten method.
+
+There are two possible strategies that are both employed in different situations in the compiler. The first strategy is to pass the environment as an extra parameter to all method calls to the closure. For example,
+
+```csharp
+void M()
+{
+ int x = 0;
+ int Local() => x + 1;
+}
+```
+
+becomes
+
+```csharp
+void M()
+{
+ var env = new Environment();
+ env.x = 0;
+ <>__Local(env);
+}
+
+static int <>__Local(Environment env)
+{
+ return env.x + 1;
+}
+
+struct Environment
+{
+ int x;
+}
+```
+
+Instead of referring to local variables, the rewritten closure now references fields on the environment. A `struct` environment is used to prevent extra allocations, since `struct`s are normally allocated on the stack. However, the astute reader may notice a problem with this conversion -- `struct`s are always copied when passed as arguments to a function call! This means that writes to the environment field will not always propogate back to the local variable in the method `M`. To work around this flaw, all Environment variables are passed as `ref` arguments to the rewritten closures.
+
+The second strategy for rewriting closures is necessary when the closure interacts with external code. Consider the following program:
+
+```csharp
+void M(IEnumerable e)
+{
+ int x = 0;
+ var positive = e.Where(n => n > 0);
+ ...
+}
+```
+
+In this case we're passing a closure to the `IEnumerable.Where` function, which is expecting a delegate of type `Func`. Note that that delegate type is immutable -- it is defined in external code and cannot be changed. Therefore, rewriting external callsites to take an extra `Environment` argument is impossible. We have to choose a different strategy for acquiring the environment.
+
+What we do is use a `class` Environment for cases like this. With a `class` Environment, the previous environment can be rewritten as follows:
+
+```csharp
+void M(IEnumerable e)
+{
+ var env = new Environment();
+ env.x = 0;
+ var positive = e.Where(env.<>__Local);
+}
+
+class Environment
+{
+ int x;
+
+ bool <>__Local(int n) => n > 0;
+}
+```
+
+Since the local variables are now fields in a class instance we can keep the same delegate signature and rely on field access to read and write the free variables.
+
+This covers the transformations C# performs at a high level. The following section covers how these transformations are performed in detail.
+
+# Internals
+
+There are two phases at the top level of closure conversion. The first phase, Analysis, is responsible for building an AnalysisResult data structure which contains all information necessary to rewrite all closures. The second phase, Rewriting, actually performs the aforementioned rewriting by replacing and adding BoundNodes to the Bound Tree. The most important contract between these two phases is that the Analysis phase performs no modifications to the Bound Tree and the Rewriting phase performs no computation and contains no logic aside from a simple mechanical modification of the Bound Tree based on the AnalysisResult.
+
+## Analysis
+
+In this phase we build an AnalysisResult, which is a tree structure that exactly represents the state mapping from the original program to the closure-converted form.
+
+For example, the following program
+
+```csharp
+void M()
+{
+ int x = 0;
+ int Local() => x + 1;
+ {
+ int y = 0;
+ int z = 0;
+ int Local2() => Local() + y;
+ z++;
+ Local2();
+ }
+ Local();
+}
+```
+
+Would produce a tree similar to
+
+```
+ +-------------------------------------+
+ |Captured: Closures: |
+ |int x int Local() |
+ |int Local() |
+ | |
+ | +--------------------------------+ |
+ | | Captured: Closures: | |
+ | | int y int Local2() | |
+ | | | |
+ | +--------------------------------+ |
+ +-------------------------------------+
+
+```
+
+To create this AnalysisResult there are multiple passes. The first pass gathers information by constructing a naive tree of scopes, closures, and captured variables. The result is a tree of nested scopes, where each scope lists the captured variables declared in the scope and the closures in that scope. The first pass must first gather information since most rewriting decisions, like what Environment type to use for the closures or what the rewritten closure signature will be, are dependent on context from the entire method.
+
+Information about captured variables are stored on instances of the `CapturedVariable` class, which holds information about the Symbol that was captured and rewriting information like the `SynthesizedLocal` that will replace the variable post-rewriting. Similarly, closures will be stored in instances of the `Closure` class, which contain both the original Symbol and the synthesized type or method created for the closure. All of these classes are mutable since it's expected that later passes will fill in more rewriting information using the structure gathered from the earlier passes.
+
+For instance, in the previous example we need to walk the tree to generate an Environment for the closures `Closure`, resulting in something like the following:
+
+```
+Closure
+-------
+Name: Local
+Generated Sig: int <>_Local(ref <>_Env1)
+Environment:
+ - Captures: 'int x'
+ - Name: <>_Env1
+ - Type: Struct
+
+Name: Local2
+Generated Sig: int <>_Local(ref <>_Env2, ref <>_Env1)
+Environment:
+ - Captures: 'int y', 'ref <>_Env1'
+ - Name: <>_Env2
+ - Type: Struct
+```
+
+This result would be generated by each piece filling in required info: first filling in all the capture lists, then deciding the Environment type based on the capture list, then generating the end signature based on the environment type and final capture list.
+
+Some further details of analysis calculations can be found below:
+
+**TODO** _Add details for each analysis phase as implementation is fleshed out_
+
+
+* Deciding what environment type is necessary for each closure. An environment can be a struct unless one of the following things is true:
+
+ 1. The closure is converted to delegate.
+ 2. The closure captures a variable which is captured by a closure that cannot have a `struct` Environment.
+ 3. A reference to the closure is captured by a closure that cannot have a `struct` Environment.
+
+* Creating `SynthesizedLocal`s for hoisted captured variables and captured Environment references
+* Assigning rewritten names, signatures, and type parameters to each closure
+
+## Optimization
+
+The final passes are optimization passes. They attempt to simplify the tree by removing intermediate scopes with no captured variables and otherwise correcting the tree to create the most efficient rewritten form. Optimization opportunities could include running escape analysis to determine if capture hoisting could be done via copy or done in a narrower scope.
+
+## Rewriting
+
+The rewriting phase simply walks the bound tree and, at each new scope, checks to see if the AnalysisResult contains a scope with rewriting information to process. If so, locals and closures are replaced with the substitutions provided by the tree. Practically, this means that the tree contains:
+
+1. A list of synthesized locals to add to each scope.
+
+2. A set of proxies to replace existing symbols.
+
+3. A list of synthesized methods and types to add to the enclosing type.
\ No newline at end of file
diff --git a/docs/compilers/Visual Basic/CommandLine.md b/docs/compilers/Visual Basic/CommandLine.md
index 7a05a9ef440e8..0a7afcefd67da 100644
--- a/docs/compilers/Visual Basic/CommandLine.md
+++ b/docs/compilers/Visual Basic/CommandLine.md
@@ -45,7 +45,7 @@
| **LANGUAGE**
| `/define:`*symbol_list* | Declare global conditional compilation symbol(s). *symbol_list* is *name*`=`*value*`,`... (Short form: `/d`)
| `/imports:`*import_list* | Declare global Imports for namespaces in referenced metadata files. *import_list* is *namespace*`,`...
-| `/langversion:`*number* | Specify language version: `9`|`9.0`|`10`|`10.0`|`11`|`11.0`|`12`|`12.0`|`13`|`13.0`|`14`|`14.0`. The default is `14`.
+| `/langversion:`*number* | Specify language version: `9`|`9.0`|`10`|`10.0`|`11`|`11.0`|`12`|`12.0`|`13`|`13.0`|`14`|`14.0`|`15`|`15.0`|`15.3`. The default is `15` and the latest is `15.3`.
| `/optionexplicit`{`+`|`-`} | Require explicit declaration of variables.
| `/optioninfer`{`+`|`-`} | Allow type inference of variables.
| `/rootnamespace`:*string* | Specifies the root Namespace for all top-level type declarations.
diff --git a/docs/compilers/Visual Basic/Compiler Breaking Changes - post VS2017.md b/docs/compilers/Visual Basic/Compiler Breaking Changes - post VS2017.md
new file mode 100755
index 0000000000000..3346c7eb13ffb
--- /dev/null
+++ b/docs/compilers/Visual Basic/Compiler Breaking Changes - post VS2017.md
@@ -0,0 +1,7 @@
+Changes since VS2017 (VB 15)
+===========================
+
+- https://github.com/dotnet/csharplang/issues/415
+In VB 15, elements in tuple literals can be named explicitly, but in VB 15.3, elements that aren't named explicitly will get an inferred named. This uses the same rules as members in anonymous types which aren't named explicitly.
+For instance, `Dim t = (a, b.c, Me.d)` will produce a tuple with element names "a", "c" and "d". As a result, an invocation on a tuple member may result in a different result than it did in VB 15.
+Consider the case where the type of `a` is `System.Func(Of Boolean)` and you write `Dim local = t.a()`. This will now find the first element of the tuple and invoke it, whereas previously it could only mean "invoke an extension method named 'a'".
diff --git a/docs/contributing/Powershell Guidelines.md b/docs/contributing/Powershell Guidelines.md
index 39e69363f6d93..bbdb1a1343c3e 100644
--- a/docs/contributing/Powershell Guidelines.md
+++ b/docs/contributing/Powershell Guidelines.md
@@ -88,26 +88,28 @@ to the invocation and removes the need for error prone if checking after every c
# DO NOT
& msbuild /v:m /m Roslyn.sln
# DO
-Exec { & msbuild /v:m /m Roslyn.sln }
+Exec-Block { & msbuild /v:m /m Roslyn.sln }
```
Note this will not work for the rare Windows commands which use 0 as an exit code on failure. For
example robocopy and corflags.
In some cases windows commands need to have their argument list built up dynamically. When that
-happens do not use Invoke-Expression to execute the command, instead use Exec-Expression. The former
-does not fail when the windows command fails and can lead to silent errors. The Exec-Expression
-will throw if the underlying expression or windows command fails.
+happens do not use Invoke-Expression to execute the command, instead use Exec-Command. The former
+does not fail when the windows command fails, can invoke powershell argument parsing and doesn't
+have a mechanism for echoing output to console. The Exec-Command uses Process directly and can support
+the major functionality needed.
``` powershell
-$command = "& msbuild /v:m Roslyn.sln"
+$command = "C:\Program Files (x86)\Microsoft Visual Studio\Preview\Dogfood\MSBuild\15.0\Bin\MSBuild.exe"
+$args = "/v:m Roslyn.sln"
if (...) {
- $command += " /fl /flp:v=diag"
+ $args += " /fl /flp:v=diag"
}
# DO NOT
-Invoke-Expression $command
+Invoke-Expression "& $command $args"
# DO
-Exec-Expression $command
+Exec-Command $command $args
```
diff --git a/docs/features/ExperimentalAttribute.md b/docs/features/ExperimentalAttribute.md
new file mode 100644
index 0000000000000..bf050ff2b88aa
--- /dev/null
+++ b/docs/features/ExperimentalAttribute.md
@@ -0,0 +1,142 @@
+ExperimentalAttribute
+=====================
+Report warnings for references to types and members marked with `Windows.Foundation.Metadata.ExperimentalAttribute`.
+```
+namespace Windows.Foundation.Metadata
+{
+ [AttributeUsage(
+ AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum |
+ AttributeTargets.Interface | AttributeTargets.Delegate,
+ AllowMultiple = false)]
+ public sealed class ExperimentalAttribute : Attribute
+ {
+ }
+}
+```
+
+## Warnings
+The warning message is a specific message, where `'{0}'` is the fully-qualified type or member name.
+```
+'{0}' is for evaluation purposes only and is subject to change or removal in future updates.
+```
+
+The warning is reported for any reference to a type or member marked with the attribute.
+(The `AttributeUsage` is for types only so the attribute cannot be applied to non-type members from C# or VB,
+but the attribute could be applied to non-type members outside of C# or VB.)
+```
+[Experimental]
+class A
+{
+ internal object F;
+ internal static object G;
+ internal class B { }
+}
+class C
+{
+ static void Main()
+ {
+ F(default(A)); // warning CS08305: 'A' is for evaluation purposes only ...
+ F(typeof(A)); // warning CS08305: 'A' is for evaluation purposes only ...
+ F(nameof(A)); // warning CS08305: 'A' is for evaluation purposes only ...
+ var a = new A(); // warning CS08305: 'A' is for evaluation purposes only ...
+ F(a.F);
+ F(A.G); // warning CS08305: 'A' is for evaluation purposes only ...
+ F(null); // warning CS08305: 'A' is for evaluation purposes only ...
+ }
+ static void F(T t)
+ {
+ }
+}
+```
+
+The attribute is not inherited from base types or overridden members.
+```
+[Experimental]
+class A
+{
+ [Experimental]
+ internal virtual void F()
+ {
+ }
+}
+class B : A // warning CS08305: 'A' is for evaluation purposes only ...
+{
+ internal override void F()
+ {
+ base.F(); // warning CS08305: 'A.F' is for evaluation purposes only ...
+ }
+}
+class C
+{
+ static void F(A a, B b) // warning CS08305: 'A' is for evaluation purposes only ...
+ {
+ a.F(); // warning CS08305: 'A.F' is for evaluation purposes only ...
+ b.F();
+ }
+}
+```
+
+There is no automatic suppression of warnings: warnings are generated for all references, even within `[Experimental]` members.
+Suppressing the warning requires an explicit compiler option or `#pragma`.
+```
+[Experimental] enum E { }
+[Experimental]
+class C
+{
+ private C(E e) // warning CS08305: 'E' is for evaluation purposes only ...
+ {
+ }
+ internal static C Create() // warning CS08305: 'C' is for evaluation purposes only ...
+ {
+ return Create(0);
+ }
+#pragma warning disable 8305
+ internal static C Create(E e)
+ {
+ return new C(e);
+ }
+}
+```
+
+## ObsoleteAttribute and DeprecatedAttribute
+`ExperimentalAttribute` is independent of `System.ObsoleteAttribute` or `Windows.Framework.Metadata.DeprecatedAttribute`.
+
+Warnings for `[Experimental]` are reported within `[Obsolete]` or `[Deprecated]` members.
+Warnings and errors for `[Obsolete]` and `[Deprecated]` are reported inside `[Experimental]` members.
+```
+[Obsolete]
+class A
+{
+ static object F() => new C(); // warning CS08305: 'C' is for evaluation purposes only ...
+}
+[Deprecated(null, DeprecationType.Deprecate, 0)]
+class B
+{
+ static object F() => new C(); // warning CS08305: 'C' is for evaluation purposes only ...
+}
+[Experimental]
+class C
+{
+ static object F() => new B(); // warning CS0612: 'B' is obsolete
+}
+```
+
+Warnings and errors for `[Obsolete]` and `[Deprecated]` are reported instead of `[Experimental]` if there are multiple attributes.
+```
+[Obsolete]
+[Experimental]
+class A
+{
+}
+[Experimental]
+[Deprecated(null, DeprecationType.Deprecate, 0)]
+class B
+{
+}
+class C
+{
+ static A F() => null; // warning CS0612: 'A' is obsolete
+ static B G() => null; // warning CS0612: 'B' is obsolete
+}
+
+```
\ No newline at end of file
diff --git a/netci.groovy b/netci.groovy
index d53132101c48a..2d7e1e3048ccd 100644
--- a/netci.groovy
+++ b/netci.groovy
@@ -54,7 +54,7 @@ if (branchName.startsWith("features/")) {
commitPullList = [true]
}
-// Windows
+// Windows Desktop CLR
commitPullList.each { isPr ->
['debug', 'release'].each { configuration ->
['unit32', 'unit64'].each { buildTarget ->
@@ -62,7 +62,7 @@ commitPullList.each { isPr ->
def myJob = job(jobName) {
description("Windows ${configuration} tests on ${buildTarget}")
steps {
- batchFile(""".\\build\\scripts\\cibuild.cmd ${(configuration == 'debug') ? '/debug' : '/release'} ${(buildTarget == 'unit32') ? '/test32' : '/test64'}""")
+ batchFile(""".\\build\\scripts\\cibuild.cmd ${(configuration == 'debug') ? '/debug' : '/release'} ${(buildTarget == 'unit32') ? '/test32' : '/test64'} /skipCoreClrTests""")
}
}
@@ -75,6 +75,25 @@ commitPullList.each { isPr ->
}
}
+// Windows CoreCLR
+commitPullList.each { isPr ->
+ ['debug', 'release'].each { configuration ->
+ def jobName = Utilities.getFullJobName(projectName, "windows_coreclr_test", isPr)
+ def myJob = job(jobName) {
+ description("Windows CoreCLR unit tests")
+ steps {
+ batchFile(""".\\build\\scripts\\cibuild.cmd ${(configuration == 'debug') ? '/debug' : '/release'} /skipDesktopTests""")
+ }
+ }
+
+ def triggerPhraseOnly = false
+ def triggerPhraseExtra = ""
+ Utilities.setMachineAffinity(myJob, 'Windows_NT', 'win2016-base')
+ Utilities.addXUnitDotNETResults(myJob, '**/xUnitResults/*.xml')
+ addRoslynJob(myJob, jobName, branchName, isPr, triggerPhraseExtra, triggerPhraseOnly)
+ }
+}
+
// Ubuntu 14.04
commitPullList.each { isPr ->
def jobName = Utilities.getFullJobName(projectName, "ubuntu_14_debug", isPr)
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.cs
index 155b3e2192ba1..e40be9c0c6507 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder.cs
@@ -530,7 +530,7 @@ internal static void ReportDiagnosticsIfObsolete(
leastOverriddenSymbol.GetAttributes();
}
- ThreeState reportedOnOverridden = ReportDiagnosticsIfObsoleteInternal(diagnostics, leastOverriddenSymbol, node, containingMember, location);
+ var diagnosticKind = ReportDiagnosticsIfObsoleteInternal(diagnostics, leastOverriddenSymbol, node, containingMember, location);
// CONSIDER: In place of hasBaseReceiver, dev11 also accepts cases where symbol.ContainingType is a "simple type" (e.g. int)
// or a special by-ref type (e.g. ArgumentHandle). These cases are probably more important for other checks performed by
@@ -540,74 +540,43 @@ internal static void ReportDiagnosticsIfObsolete(
// If the overridden member was not definitely obsolete and this is a (non-virtual) base member
// access, then check the overriding symbol as well.
- if (reportedOnOverridden != ThreeState.True && checkOverridingSymbol)
+ switch (diagnosticKind)
{
- Debug.Assert(reportedOnOverridden != ThreeState.Unknown, "We forced attribute binding above.");
-
- ReportDiagnosticsIfObsoleteInternal(diagnostics, symbol, node, containingMember, location);
+ case ObsoleteDiagnosticKind.NotObsolete:
+ case ObsoleteDiagnosticKind.Lazy:
+ if (checkOverridingSymbol)
+ {
+ Debug.Assert(diagnosticKind != ObsoleteDiagnosticKind.Lazy, "We forced attribute binding above.");
+ ReportDiagnosticsIfObsoleteInternal(diagnostics, symbol, node, containingMember, location);
+ }
+ break;
}
}
- ///
- /// True if the symbol is definitely obsolete.
- /// False if the symbol is definitely not obsolete.
- /// Unknown if the symbol may be obsolete.
- ///
- /// NOTE: The return value reflects obsolete-ness, not whether or not the diagnostic was reported.
- ///
- internal static ThreeState ReportDiagnosticsIfObsoleteInternal(DiagnosticBag diagnostics, Symbol symbol, SyntaxNodeOrToken node, Symbol containingMember, BinderFlags location)
+ internal static ObsoleteDiagnosticKind ReportDiagnosticsIfObsoleteInternal(DiagnosticBag diagnostics, Symbol symbol, SyntaxNodeOrToken node, Symbol containingMember, BinderFlags location)
{
Debug.Assert(diagnostics != null);
- if (symbol.ObsoleteState == ThreeState.False)
- {
- return ThreeState.False;
- }
-
- var data = symbol.ObsoleteAttributeData;
- if (data == null)
- {
- // Obsolete attribute has errors.
- return ThreeState.False;
- }
-
- // If we haven't cracked attributes on the symbol at all or we haven't
- // cracked attribute arguments enough to be able to report diagnostics for
- // ObsoleteAttribute, store the symbol so that we can report diagnostics at a
- // later stage.
- if (symbol.ObsoleteState == ThreeState.Unknown)
- {
- diagnostics.Add(new LazyObsoleteDiagnosticInfo(symbol, containingMember, location), node.GetLocation());
- return ThreeState.Unknown;
- }
-
- // After this point, always return True.
-
- var inObsoleteContext = ObsoleteAttributeHelpers.GetObsoleteContextState(containingMember);
+ var kind = ObsoleteAttributeHelpers.GetObsoleteDiagnosticKind(symbol, containingMember);
- // If we are in a context that is already obsolete, there is no point reporting
- // more obsolete diagnostics.
- if (inObsoleteContext == ThreeState.True)
+ DiagnosticInfo info = null;
+ switch (kind)
{
- return ThreeState.True;
- }
- // If the context is unknown, then store the symbol so that we can do this check at a
- // later stage
- else if (inObsoleteContext == ThreeState.Unknown)
- {
- diagnostics.Add(new LazyObsoleteDiagnosticInfo(symbol, containingMember, location), node.GetLocation());
- return ThreeState.True;
+ case ObsoleteDiagnosticKind.Diagnostic:
+ info = ObsoleteAttributeHelpers.CreateObsoleteDiagnostic(symbol, location);
+ break;
+ case ObsoleteDiagnosticKind.Lazy:
+ case ObsoleteDiagnosticKind.LazyPotentiallySuppressed:
+ info = new LazyObsoleteDiagnosticInfo(symbol, containingMember, location);
+ break;
}
- // We have all the information we need to report diagnostics right now. So do it.
- var diagInfo = ObsoleteAttributeHelpers.CreateObsoleteDiagnostic(symbol, location);
- if (diagInfo != null)
+ if (info != null)
{
- diagnostics.Add(diagInfo, node.GetLocation());
- return ThreeState.True;
+ diagnostics.Add(info, node.GetLocation());
}
- return ThreeState.True;
+ return kind;
}
internal static bool IsSymbolAccessibleConditional(
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs
index dba04f102ec84..654983fb1c5a5 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs
@@ -47,10 +47,16 @@ private BoundExpression BindAnonymousObjectCreation(AnonymousObjectCreationExpre
}
else
{
+ if (!IsAnonymousTypeMemberExpression(expression))
+ {
+ hasError = true;
+ diagnostics.Add(ErrorCode.ERR_InvalidAnonymousTypeMemberDeclarator, expression.GetLocation());
+ }
+
nameToken = expression.ExtractAnonymousTypeMemberName();
}
- hasError = hasError || expression.HasErrors;
+ hasError |= expression.HasErrors;
boundExpressions[i] = this.BindValue(expression, diagnostics, BindValueKind.RValue);
// check the name to be unique
@@ -131,6 +137,32 @@ private BoundExpression BindAnonymousObjectCreation(AnonymousObjectCreationExpre
hasError);
}
+ private static bool IsAnonymousTypeMemberExpression(ExpressionSyntax expr)
+ {
+ while (true)
+ {
+ switch (expr.Kind())
+ {
+ case SyntaxKind.QualifiedName:
+ expr = ((QualifiedNameSyntax)expr).Right;
+ continue;
+ case SyntaxKind.ConditionalAccessExpression:
+ expr = ((ConditionalAccessExpressionSyntax)expr).WhenNotNull;
+ if (expr.Kind() == SyntaxKind.MemberBindingExpression)
+ {
+ return true;
+ }
+
+ continue;
+ case SyntaxKind.IdentifierName:
+ case SyntaxKind.SimpleMemberAccessExpression:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+
///
/// Actually, defines if an error ERR_AnonymousTypeNotAvailable is to be generated;
///
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
index 26670db57bafe..064045ec7866f 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
@@ -13,8 +14,8 @@ namespace Microsoft.CodeAnalysis.CSharp
{
///
/// This portion of the binder converts deconstruction-assignment syntax (AssignmentExpressionSyntax nodes with the left
- /// being a tuple expression or declaration expression) into a BoundAssignmentOperator (or bad node).
- /// The BoundAssignmentOperator will have:
+ /// being a tuple expression or declaration expression) into a BoundDeconstructionAssignmentOperator (or bad node).
+ /// The BoundDeconstructionAssignmentOperator will have:
/// - a BoundTupleLiteral as its Left,
/// - a BoundConversion as its Right, holding:
/// - a tree of Conversion objects with Kind=Deconstruction, information about a Deconstruct method (optional) and
@@ -461,7 +462,8 @@ private static TypeSymbol MakeMergedTupleType(ArrayBuilder),
compilation: compilation,
diagnostics: diagnostics,
- shouldCheckConstraints: false);
+ shouldCheckConstraints: false,
+ errorPositions: default(ImmutableArray));
}
private BoundTupleLiteral DeconstructionVariablesAsTuple(CSharpSyntaxNode syntax, ArrayBuilder variables, DiagnosticBag diagnostics, bool hasErrors)
@@ -470,6 +472,7 @@ private BoundTupleLiteral DeconstructionVariablesAsTuple(CSharpSyntaxNode syntax
var valuesBuilder = ArrayBuilder.GetInstance(count);
var typesBuilder = ArrayBuilder.GetInstance(count);
var locationsBuilder = ArrayBuilder.GetInstance(count);
+ var namesBuilder = ArrayBuilder.GetInstance(count);
foreach (var variable in variables)
{
if (variable.HasNestedVariables)
@@ -477,23 +480,47 @@ private BoundTupleLiteral DeconstructionVariablesAsTuple(CSharpSyntaxNode syntax
var nestedTuple = DeconstructionVariablesAsTuple(variable.Syntax, variable.NestedVariables, diagnostics, hasErrors);
valuesBuilder.Add(nestedTuple);
typesBuilder.Add(nestedTuple.Type);
+ namesBuilder.Add(null);
}
else
{
var single = variable.Single;
valuesBuilder.Add(single);
typesBuilder.Add(single.Type);
+ namesBuilder.Add(ExtractDeconstructResultElementName(single));
}
locationsBuilder.Add(variable.Syntax.Location);
}
+ var uniqueFieldNames = PooledHashSet.GetInstance();
+ RemoveDuplicateInferredTupleNames(namesBuilder, uniqueFieldNames);
+ uniqueFieldNames.Free();
+ ImmutableArray tupleNames = namesBuilder.ToImmutableAndFree();
+
+ bool disallowInferredNames = this.Compilation.LanguageVersion.DisallowInferredTupleElementNames();
+ var inferredPositions = tupleNames.SelectAsArray(n => n != null);
+
var type = TupleTypeSymbol.Create(syntax.Location,
typesBuilder.ToImmutableAndFree(), locationsBuilder.ToImmutableAndFree(),
- elementNames: default(ImmutableArray), compilation: this.Compilation,
- shouldCheckConstraints: !hasErrors, syntax: syntax, diagnostics: hasErrors ? null : diagnostics);
+ tupleNames, this.Compilation,
+ shouldCheckConstraints: !hasErrors,
+ errorPositions: disallowInferredNames ? inferredPositions : default(ImmutableArray),
+ syntax: syntax, diagnostics: hasErrors ? null : diagnostics);
+
+ // Always track the inferred positions in the bound node, so that conversions don't produce a warning
+ // for "dropped names" on tuple literal when the name was inferred.
+ return new BoundTupleLiteral(syntax, tupleNames, inferredPositions, arguments: valuesBuilder.ToImmutableAndFree(), type: type);
+ }
+
+ /// Extract inferred name from a single deconstruction variable.
+ private static string ExtractDeconstructResultElementName(BoundExpression expression)
+ {
+ if (expression.Kind == BoundKind.DiscardExpression)
+ {
+ return null;
+ }
- return new BoundTupleLiteral(syntax: syntax, argumentNamesOpt: default(ImmutableArray),
- arguments: valuesBuilder.ToImmutableAndFree(), type: type);
+ return InferTupleElementName(expression.Syntax);
}
///
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
index a7591f24219fb..7b3587c586de9 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
@@ -742,23 +742,37 @@ private BoundExpression BindDeclarationVariables(TypeSymbol declType, VariableDe
case SyntaxKind.ParenthesizedVariableDesignation:
{
var tuple = (ParenthesizedVariableDesignationSyntax)node;
- var builder = ArrayBuilder.GetInstance(tuple.Variables.Count);
+ int count = tuple.Variables.Count;
+ var builder = ArrayBuilder.GetInstance(count);
+ var namesBuilder = ArrayBuilder.GetInstance(count);
+
foreach (var n in tuple.Variables)
{
builder.Add(BindDeclarationVariables(declType, n, n, diagnostics));
+ namesBuilder.Add(InferTupleElementName(n));
}
var subExpressions = builder.ToImmutableAndFree();
+ var uniqueFieldNames = PooledHashSet.GetInstance();
+ RemoveDuplicateInferredTupleNames(namesBuilder, uniqueFieldNames);
+ uniqueFieldNames.Free();
+
+ var tupleNames = namesBuilder.ToImmutableAndFree();
+ var inferredPositions = tupleNames.SelectAsArray(n => n != null);
+ bool disallowInferredNames = this.Compilation.LanguageVersion.DisallowInferredTupleElementNames();
+
// We will not check constraints at this point as this code path
// is failure-only and the caller is expected to produce a diagnostic.
var tupleType = TupleTypeSymbol.Create(
null,
subExpressions.SelectAsArray(e => e.Type),
default(ImmutableArray),
- default(ImmutableArray),
+ tupleNames,
Compilation,
- shouldCheckConstraints: false);
- return new BoundTupleLiteral(syntax, default(ImmutableArray), subExpressions, tupleType);
+ shouldCheckConstraints: false,
+ errorPositions: disallowInferredNames ? inferredPositions : default(ImmutableArray));
+
+ return new BoundTupleLiteral(syntax, default(ImmutableArray), inferredPositions, subExpressions, tupleType);
}
default:
throw ExceptionUtilities.UnexpectedValue(node.Kind());
@@ -780,41 +794,30 @@ private BoundExpression BindTupleExpression(TupleExpressionSyntax node, Diagnost
return BadExpression(node, args);
}
- bool hasErrors = false;
bool hasNaturalType = true;
- // set of names already used
- var uniqueFieldNames = PooledHashSet.GetInstance();
-
var boundArguments = ArrayBuilder.GetInstance(arguments.Count);
var elementTypes = ArrayBuilder.GetInstance(arguments.Count);
var elementLocations = ArrayBuilder.GetInstance(arguments.Count);
- ArrayBuilder elementNames = null;
- // prepare and check element names and types
+ // prepare names
+ var (elementNames, inferredPositions, hasErrors) = ExtractTupleElementNames(arguments, diagnostics);
+
+ // prepare types and locations
for (int i = 0; i < numElements; i++)
{
ArgumentSyntax argumentSyntax = arguments[i];
- string name = null;
IdentifierNameSyntax nameSyntax = argumentSyntax.NameColon?.Name;
if (nameSyntax != null)
{
- name = nameSyntax.Identifier.ValueText;
elementLocations.Add(nameSyntax.Location);
-
- if (!CheckTupleMemberName(name, i, argumentSyntax.NameColon.Name, diagnostics, uniqueFieldNames))
- {
- hasErrors = true;
- }
}
else
{
elementLocations.Add(argumentSyntax.Location);
}
- CollectTupleFieldMemberNames(name, i + 1, numElements, ref elementNames);
-
BoundExpression boundArgument = BindValue(argumentSyntax.Expression, diagnostics, BindValueKind.RValue);
if (boundArgument.Type?.SpecialType == SpecialType.System_Void)
{
@@ -835,26 +838,151 @@ private BoundExpression BindTupleExpression(TupleExpressionSyntax node, Diagnost
}
}
- uniqueFieldNames.Free();
-
- var elementNamesArray = elementNames == null ?
- default(ImmutableArray) :
- elementNames.ToImmutableAndFree();
-
NamedTypeSymbol tupleTypeOpt = null;
var elements = elementTypes.ToImmutableAndFree();
var locations = elementLocations.ToImmutableAndFree();
if (hasNaturalType)
{
- tupleTypeOpt = TupleTypeSymbol.Create(node.Location, elements, locations, elementNamesArray, this.Compilation, syntax: node, diagnostics: diagnostics, shouldCheckConstraints: true);
+ bool disallowInferredNames = this.Compilation.LanguageVersion.DisallowInferredTupleElementNames();
+
+ tupleTypeOpt = TupleTypeSymbol.Create(node.Location, elements, locations, elementNames,
+ this.Compilation, syntax: node, diagnostics: diagnostics, shouldCheckConstraints: true,
+ errorPositions: disallowInferredNames ? inferredPositions : default(ImmutableArray));
}
else
{
TupleTypeSymbol.VerifyTupleTypePresent(elements.Length, node, this.Compilation, diagnostics);
}
- return new BoundTupleLiteral(node, elementNamesArray, boundArguments.ToImmutableAndFree(), tupleTypeOpt, hasErrors);
+ // Always track the inferred positions in the bound node, so that conversions don't produce a warning
+ // for "dropped names" on tuple literal when the name was inferred.
+ return new BoundTupleLiteral(node, elementNames, inferredPositions, boundArguments.ToImmutableAndFree(), tupleTypeOpt, hasErrors);
+ }
+
+ private static (ImmutableArray elementNamesArray, ImmutableArray inferredArray, bool hasErrors) ExtractTupleElementNames(
+ SeparatedSyntaxList arguments, DiagnosticBag diagnostics)
+ {
+ bool hasErrors = false;
+ int numElements = arguments.Count;
+ var uniqueFieldNames = PooledHashSet.GetInstance();
+ ArrayBuilder elementNames = null;
+ ArrayBuilder inferredElementNames = null;
+
+ for (int i = 0; i < numElements; i++)
+ {
+ ArgumentSyntax argumentSyntax = arguments[i];
+ IdentifierNameSyntax nameSyntax = argumentSyntax.NameColon?.Name;
+
+ string name = null;
+ string inferredName = null;
+
+ if (nameSyntax != null)
+ {
+ name = nameSyntax.Identifier.ValueText;
+
+ if (diagnostics != null && !CheckTupleMemberName(name, i, argumentSyntax.NameColon.Name, diagnostics, uniqueFieldNames))
+ {
+ hasErrors = true;
+ }
+ }
+ else
+ {
+ inferredName = InferTupleElementName(argumentSyntax.Expression);
+ }
+
+ CollectTupleFieldMemberName(name, i, numElements, ref elementNames);
+ CollectTupleFieldMemberName(inferredName, i, numElements, ref inferredElementNames);
+ }
+
+ RemoveDuplicateInferredTupleNames(inferredElementNames, uniqueFieldNames);
+ uniqueFieldNames.Free();
+
+ var result = MergeTupleElementNames(elementNames, inferredElementNames);
+ elementNames?.Free();
+ inferredElementNames?.Free();
+ return (result.names, result.inferred, hasErrors);
+ }
+
+ private static (ImmutableArray names, ImmutableArray inferred) MergeTupleElementNames(
+ ArrayBuilder elementNames, ArrayBuilder inferredElementNames)
+ {
+ if (elementNames == null)
+ {
+ if (inferredElementNames == null)
+ {
+ return (default(ImmutableArray), default(ImmutableArray));
+ }
+ else
+ {
+ var finalNames = inferredElementNames.ToImmutable();
+ return (finalNames, finalNames.SelectAsArray(n => n != null));
+ }
+ }
+
+ if (inferredElementNames == null)
+ {
+ return (elementNames.ToImmutable(), default(ImmutableArray));
+ }
+
+ Debug.Assert(elementNames.Count == inferredElementNames.Count);
+ var builder = ArrayBuilder.GetInstance(elementNames.Count);
+ for (int i = 0; i < elementNames.Count; i++)
+ {
+ string inferredName = inferredElementNames[i];
+ if (elementNames[i] == null && inferredName != null)
+ {
+ elementNames[i] = inferredName;
+ builder.Add(true);
+ }
+ else
+ {
+ builder.Add(false);
+ }
+ }
+
+ return (elementNames.ToImmutable(), builder.ToImmutableAndFree());
+ }
+
+ private static void RemoveDuplicateInferredTupleNames(ArrayBuilder inferredElementNames, HashSet uniqueFieldNames)
+ {
+ if (inferredElementNames == null)
+ {
+ return;
+ }
+
+ // Inferred names that duplicate an explicit name or a previous inferred name are tagged for removal
+ var toRemove = PooledHashSet.GetInstance();
+ foreach (var name in inferredElementNames)
+ {
+ if (name != null && !uniqueFieldNames.Add(name))
+ {
+ toRemove.Add(name);
+ }
+ }
+
+ for (int i = 0; i < inferredElementNames.Count; i++)
+ {
+ var inferredName = inferredElementNames[i];
+ if (inferredName != null && toRemove.Contains(inferredName))
+ {
+ inferredElementNames[i] = null;
+ }
+ }
+ toRemove.Free();
+ }
+
+ private static string InferTupleElementName(SyntaxNode syntax)
+ {
+ string name = syntax.TryGetInferredMemberName();
+
+ // Reserved names are never candidates to be inferred names, at any position
+ if (name == null || TupleTypeSymbol.IsElementNameReserved(name) != -1)
+ {
+ return null;
+ }
+
+ return name;
}
private BoundExpression BindRefValue(RefValueExpressionSyntax node, DiagnosticBag diagnostics)
@@ -3565,7 +3693,7 @@ private BoundExpression BindClassCreationExpression(ObjectCreationExpressionSynt
}
else if (node.Type.Kind() == SyntaxKind.TupleType)
{
- Debug.Assert(node.HasErrors, "new should be a syntax error");
+ diagnostics.Add(ErrorCode.ERR_NewWithTupleTypeSyntax, node.Type.GetLocation());
return MakeBadExpressionForObjectCreation(node, type, boundInitializerOpt, analyzedArguments);
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
index 15bd156c13e0f..d02e32d22e28e 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
@@ -442,7 +442,7 @@ private TypeSymbol BindTupleType(TupleTypeSyntax syntax, DiagnosticBag diagnosti
locations.Add(argumentSyntax.Location);
}
- CollectTupleFieldMemberNames(name, i + 1, numElements, ref elementNames);
+ CollectTupleFieldMemberName(name, i, numElements, ref elementNames);
}
uniqueFieldNames.Free();
@@ -480,11 +480,12 @@ private TypeSymbol BindTupleType(TupleTypeSyntax syntax, DiagnosticBag diagnosti
elementNames.ToImmutableAndFree(),
this.Compilation,
this.ShouldCheckConstraints,
- syntax,
- diagnostics);
+ errorPositions: default(ImmutableArray),
+ syntax: syntax,
+ diagnostics: diagnostics);
}
- private static void CollectTupleFieldMemberNames(string name, int position, int tupleSize, ref ArrayBuilder elementNames)
+ private static void CollectTupleFieldMemberName(string name, int elementIndex, int tupleSize, ref ArrayBuilder elementNames)
{
// add the name to the list
// names would typically all be there or none at all
@@ -498,7 +499,7 @@ private static void CollectTupleFieldMemberNames(string name, int position, int
if (name != null)
{
elementNames = ArrayBuilder.GetInstance(tupleSize);
- for (int j = 1; j < position; j++)
+ for (int j = 0; j < elementIndex; j++)
{
elementNames.Add(null);
}
diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
index e983843d28939..65f01d851c992 100644
--- a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
@@ -649,7 +649,7 @@ private bool GetEnumeratorInfo(ref ForEachEnumeratorInfo.Builder builder, BoundE
if (!string.IsNullOrEmpty(collectionExprType.Name) || !collectionExpr.HasErrors)
{
- diagnostics.Add(ErrorCode.ERR_ForEachMissingMember, _syntax.Expression.Location, collectionExprType.ToDisplayString(), GetEnumeratorMethodName);
+ diagnostics.Add(ErrorCode.ERR_ForEachMissingMember, _syntax.Expression.Location, collectionExprType, GetEnumeratorMethodName);
}
return false;
}
diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
index 3f6fe70b8906d..e4962d7696bee 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
+++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
@@ -3,6 +3,8 @@
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
\ No newline at end of file
+
diff --git a/src/Setup/DevDivInsertionFiles/BuildDevDivInsertionFiles.vb b/src/Setup/DevDivInsertionFiles/BuildDevDivInsertionFiles.vb
index 3b07f411d10e4..07dc69a17c728 100644
--- a/src/Setup/DevDivInsertionFiles/BuildDevDivInsertionFiles.vb
+++ b/src/Setup/DevDivInsertionFiles/BuildDevDivInsertionFiles.vb
@@ -98,14 +98,15 @@ Public Class BuildDevDivInsertionFiles
' the src/NuGet/Microsoft.Net.Compilers.nuspec file, the
' src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.swr file,
' and src/Compilers/Extension/CompilerExtension.csproj file.
+ '
+ ' Note: Microsoft.DiaSymReader.Native.amd64.dll and Microsoft.DiaSymReader.Native.x86.dll
+ ' are installed by msbuild setup, not Roslyn.
Private ReadOnly CompilerFiles As String() = {
"Microsoft.CodeAnalysis.dll",
"Microsoft.CodeAnalysis.CSharp.dll",
"Microsoft.CodeAnalysis.Scripting.dll",
"Microsoft.CodeAnalysis.CSharp.Scripting.dll",
"Microsoft.CodeAnalysis.VisualBasic.dll",
- "Microsoft.DiaSymReader.Native.amd64.dll",
- "Microsoft.DiaSymReader.Native.x86.dll",
"System.AppContext.dll",
"System.Console.dll",
"System.Diagnostics.FileVersionInfo.dll",
diff --git a/src/Setup/DevDivPackages/Roslyn.proj b/src/Setup/DevDivPackages/Roslyn.proj
index 7fd9635c5c66e..f7349818e07da 100644
--- a/src/Setup/DevDivPackages/Roslyn.proj
+++ b/src/Setup/DevDivPackages/Roslyn.proj
@@ -3,16 +3,16 @@
- $(OutDir)DevDivInsertionFiles
+ $(OutputPath)\DevDivInsertionFiles
$(InsertionFilesDir)\VS.Tools.Roslyn
- $(OutDir)DevDivPackages\Roslyn
+ $(OutputPath)\DevDivPackages\Roslyn
$(NuGetPerBuildPreReleaseVersion)
$(NuGetReleaseVersion)-cibuild
- $(OutDir)
+ $(OutputPath)
$(NuGetPerBuildPreReleaseVersion)
@@ -30,4 +30,4 @@
-
\ No newline at end of file
+
diff --git a/src/Setup/DevDivPackages/Roslyn/project.json b/src/Setup/DevDivPackages/Roslyn/project.json
index af8c16a0b197f..142bc9394495f 100644
--- a/src/Setup/DevDivPackages/Roslyn/project.json
+++ b/src/Setup/DevDivPackages/Roslyn/project.json
@@ -1,7 +1,6 @@
{
"dependencies": {
"Microsoft.DiaSymReader": "1.1.0",
- "Microsoft.DiaSymReader.Native": "1.5.0",
"Microsoft.CodeAnalysis.Elfie": "0.10.6-rc2",
"System.Collections.Immutable": "1.3.1",
"System.Reflection.Metadata": "1.4.2",
diff --git a/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.swixproj b/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.swixproj
index 03f9fc4b50c60..1be98515de706 100644
--- a/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.swixproj
+++ b/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.swixproj
@@ -6,7 +6,8 @@
neutral
false
- $(OutDir)Insertion
+ $(OutputPath)
+ $(OutputPath)\Insertion
true
vsix
@@ -14,7 +15,7 @@
- $(PackagePreprocessorDefinitions);Version=$(VsixVersion);OutputPath=$(OutDir)
+ $(PackagePreprocessorDefinitions);Version=$(VsixVersion);OutputPath=$(RoslynOutputPath)
$(BaseIntermediateOutputPath)$(Configuration)\
@@ -23,4 +24,4 @@
-
\ No newline at end of file
+
diff --git a/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.swr b/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.swr
index 890e3bf4aa6f0..7900402e91a30 100644
--- a/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.swr
+++ b/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.swr
@@ -34,9 +34,6 @@ folder InstallDir:\MSBuild\15.0\Bin\Roslyn
file source=$(OutputPath)\Vsix\CompilerExtension\System.Reflection.Metadata.dll vs.file.ngenArchitecture=all
file source=$(OutputPath)\Exes\csi\System.ValueTuple.dll vs.file.ngenArchitecture=all
- file source=$(OutputPath)\Vsix\CompilerExtension\Microsoft.DiaSymReader.Native.amd64.dll
- file source=$(OutputPath)\Vsix\CompilerExtension\Microsoft.DiaSymReader.Native.x86.dll
-
file source=$(OutputPath)\Vsix\CompilerExtension\System.AppContext.dll vs.file.ngenArchitecture=all
file source=$(OutputPath)\Vsix\CompilerExtension\System.Console.dll vs.file.ngenArchitecture=all
file source=$(OutputPath)\Vsix\CompilerExtension\System.Diagnostics.FileVersionInfo.dll vs.file.ngenArchitecture=all
diff --git a/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.vsmanproj b/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.vsmanproj
index d17ac1dd62634..2436b6d3b4ba0 100644
--- a/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.vsmanproj
+++ b/src/Setup/DevDivVsix/CompilersPackage/Microsoft.CodeAnalysis.Compilers.vsmanproj
@@ -6,7 +6,7 @@
true
true
- $(OutDir)Insertion\
+ $(OutputPath)Insertion\
true
false
false
@@ -29,4 +29,4 @@
-
\ No newline at end of file
+
diff --git a/src/Setup/DevDivVsix/MicrosoftCodeAnalysisLanguageServices/Microsoft.CodeAnalysis.LanguageServices.vsmanproj b/src/Setup/DevDivVsix/MicrosoftCodeAnalysisLanguageServices/Microsoft.CodeAnalysis.LanguageServices.vsmanproj
index f1e02c2793255..bd502c3f9e81c 100644
--- a/src/Setup/DevDivVsix/MicrosoftCodeAnalysisLanguageServices/Microsoft.CodeAnalysis.LanguageServices.vsmanproj
+++ b/src/Setup/DevDivVsix/MicrosoftCodeAnalysisLanguageServices/Microsoft.CodeAnalysis.LanguageServices.vsmanproj
@@ -6,7 +6,7 @@
true
true
- $(OutDir)Insertion
+ $(OutputPath)\Insertion
true
false
false
@@ -38,4 +38,4 @@
-
\ No newline at end of file
+
diff --git a/src/Setup/DevDivVsix/PortableFacades/PortableFacades.swixproj b/src/Setup/DevDivVsix/PortableFacades/PortableFacades.swixproj
index f931f13551c3f..9163ec5a36dbc 100644
--- a/src/Setup/DevDivVsix/PortableFacades/PortableFacades.swixproj
+++ b/src/Setup/DevDivVsix/PortableFacades/PortableFacades.swixproj
@@ -6,7 +6,7 @@
neutral
false
- $(OutDir)Insertion
+ $(OutputPath)\Insertion
true
vsix
@@ -23,4 +23,4 @@
-
\ No newline at end of file
+
diff --git a/src/Setup/DevDivVsix/PortableFacades/PortableFacades.vsmanproj b/src/Setup/DevDivVsix/PortableFacades/PortableFacades.vsmanproj
index a6fecdc827d36..89dc8b22de47e 100644
--- a/src/Setup/DevDivVsix/PortableFacades/PortableFacades.vsmanproj
+++ b/src/Setup/DevDivVsix/PortableFacades/PortableFacades.vsmanproj
@@ -6,7 +6,7 @@
true
true
- $(OutDir)Insertion\
+ $(OutputPath)\Insertion\
true
false
false
@@ -24,4 +24,4 @@
-
\ No newline at end of file
+
diff --git a/src/Setup/SetupStep1.proj b/src/Setup/SetupStep1.proj
index 04f418a8306cf..2a5d8d0393e03 100644
--- a/src/Setup/SetupStep1.proj
+++ b/src/Setup/SetupStep1.proj
@@ -25,7 +25,7 @@
where building multiple projects that produce VSIXes larger than 10MB will race against each other -->
-
+
@@ -40,4 +40,4 @@
-
\ No newline at end of file
+
diff --git a/src/Setup/SetupStep2.proj b/src/Setup/SetupStep2.proj
index 4f6b35d31de34..aa04243ae80dd 100644
--- a/src/Setup/SetupStep2.proj
+++ b/src/Setup/SetupStep2.proj
@@ -8,7 +8,7 @@
-
+
@@ -23,4 +23,4 @@
-
\ No newline at end of file
+
diff --git a/src/Setup/Vsix/Vsix.proj b/src/Setup/Vsix/Vsix.proj
index 1b53f56703549..21b7f52dfded6 100644
--- a/src/Setup/Vsix/Vsix.proj
+++ b/src/Setup/Vsix/Vsix.proj
@@ -6,7 +6,7 @@
-
+
-
\ No newline at end of file
+
diff --git a/src/Test/Utilities/Portable/Compilation/CompilationDifference.cs b/src/Test/Utilities/Portable/Compilation/CompilationDifference.cs
index b4d272c2a632a..40bfaa8f37286 100644
--- a/src/Test/Utilities/Portable/Compilation/CompilationDifference.cs
+++ b/src/Test/Utilities/Portable/Compilation/CompilationDifference.cs
@@ -118,7 +118,7 @@ public void VerifyPdb(
[CallerLineNumber]int expectedValueSourceLine = 0,
[CallerFilePath]string expectedValueSourcePath = null)
{
- VerifyPdb(methodTokens, XElement.Parse(expectedPdb), format, expectedValueSourceLine, expectedValueSourcePath, expectedIsXmlLiteral: false);
+ VerifyPdb(methodTokens, expectedPdb, format, expectedValueSourceLine, expectedValueSourcePath, expectedIsXmlLiteral: false);
}
public void VerifyPdb(
@@ -128,12 +128,12 @@ public void VerifyPdb(
[CallerLineNumber]int expectedValueSourceLine = 0,
[CallerFilePath]string expectedValueSourcePath = null)
{
- VerifyPdb(methodTokens, expectedPdb, format, expectedValueSourceLine, expectedValueSourcePath, expectedIsXmlLiteral: true);
+ VerifyPdb(methodTokens, expectedPdb.ToString(), format, expectedValueSourceLine, expectedValueSourcePath, expectedIsXmlLiteral: true);
}
private void VerifyPdb(
IEnumerable methodTokens,
- XElement expectedPdb,
+ string expectedPdb,
DebugInformationFormat format,
int expectedValueSourceLine,
string expectedValueSourcePath,
@@ -142,15 +142,10 @@ private void VerifyPdb(
Assert.NotEqual(default(DebugInformationFormat), format);
Assert.NotEqual(DebugInformationFormat.Embedded, format);
- var actualXml = XElement.Parse(PdbToXmlConverter.DeltaPdbToXml(new ImmutableMemoryStream(PdbDelta), methodTokens));
-
- PdbValidation.AdjustToPdbFormat(
- actualPdb: actualXml,
- actualIsPortable: NextGeneration.InitialBaseline.HasPortablePdb,
- expectedPdb: expectedPdb,
- expectedIsPortable: format != DebugInformationFormat.Pdb);
+ string actualPdb = PdbToXmlConverter.DeltaPdbToXml(new ImmutableMemoryStream(PdbDelta), methodTokens);
+ var (actualXml, expectedXml) = PdbValidation.AdjustToPdbFormat(actualPdb, expectedPdb, actualIsPortable: NextGeneration.InitialBaseline.HasPortablePdb);
- AssertXml.Equal(expectedPdb, actualXml, $"Format: {format}{Environment.NewLine}", expectedValueSourcePath, expectedValueSourceLine, expectedIsXmlLiteral);
+ AssertXml.Equal(expectedXml, actualXml, $"Format: {format}{Environment.NewLine}", expectedValueSourcePath, expectedValueSourceLine, expectedIsXmlLiteral);
}
internal string GetMethodIL(string qualifiedMethodName)
@@ -196,5 +191,12 @@ public void VerifySynthesizedFields(string typeName, params string[] expectedSyn
var actual = EmitResult.Baseline.SynthesizedMembers.Single(e => e.Key.ToString() == typeName).Value.OfType().Select(f => f.Name + ": " + f.Type);
AssertEx.SetEqual(expectedSynthesizedTypesAndMemberCounts, actual, itemSeparator: "\r\n");
}
+
+ public void VerifyUpdatedMethods(params string[] expectedMethodTokens)
+ {
+ AssertEx.Equal(
+ expectedMethodTokens,
+ UpdatedMethods.Select(methodHandle => $"0x{MetadataTokens.GetToken(methodHandle):X8}"));
+ }
}
}
diff --git a/src/Test/Utilities/Portable/Pdb/PdbValidation.cs b/src/Test/Utilities/Portable/Pdb/PdbValidation.cs
index 23ab401a868e1..ef8158465840a 100644
--- a/src/Test/Utilities/Portable/Pdb/PdbValidation.cs
+++ b/src/Test/Utilities/Portable/Pdb/PdbValidation.cs
@@ -49,13 +49,11 @@ internal static void VerifyPdb(
[CallerLineNumber]int expectedValueSourceLine = 0,
[CallerFilePath]string expectedValueSourcePath = null)
{
- var expectedPdbXml = XElement.Parse(string.IsNullOrWhiteSpace(expectedPdb) ? " " : expectedPdb);
-
VerifyPdbImpl(
compilation,
debugEntryPoint,
qualifiedMethodName,
- expectedPdbXml,
+ string.IsNullOrWhiteSpace(expectedPdb) ? " " : expectedPdb,
format,
options,
expectedValueSourceLine,
@@ -89,7 +87,7 @@ internal static void VerifyPdb(
compilation,
debugEntryPoint,
qualifiedMethodName,
- expectedPdb,
+ expectedPdb.ToString(),
format,
options,
expectedValueSourceLine,
@@ -101,7 +99,7 @@ private static void VerifyPdbImpl(
this Compilation compilation,
IMethodSymbol debugEntryPoint,
string qualifiedMethodName,
- XElement expectedPdb,
+ string expectedPdb,
DebugInformationFormat format,
PdbToXmlOptions options,
int expectedValueSourceLine,
@@ -112,134 +110,125 @@ private static void VerifyPdbImpl(
if (format == 0 || format == DebugInformationFormat.Pdb)
{
- var actualNativePdb = XElement.Parse(GetPdbXml(compilation, debugEntryPoint, options, qualifiedMethodName, portable: false));
- AssertXml.Equal(expectedPdb, actualNativePdb, $"PDB format: Windows{Environment.NewLine}", expectedValueSourcePath, expectedValueSourceLine, expectedIsXmlLiteral);
+ var actualPdb = GetPdbXml(compilation, debugEntryPoint, options, qualifiedMethodName, portable: false);
+ var (actualXml, expectedXml) = AdjustToPdbFormat(actualPdb, expectedPdb, actualIsPortable: false);
+
+ AssertXml.Equal(expectedXml, actualXml, $"PDB format: Windows{Environment.NewLine}", expectedValueSourcePath, expectedValueSourceLine, expectedIsXmlLiteral);
}
if (format == 0 || format == DebugInformationFormat.PortablePdb)
{
- var actualPortablePdb = XElement.Parse(GetPdbXml(compilation, debugEntryPoint, options, qualifiedMethodName, portable: true));
-
- // If format is not specified, we share expected output between portable and non-portable.
- // The output is then non-portable since it contains more information (such as cdi).
- AdjustToPdbFormat(
- actualPdb: actualPortablePdb,
- actualIsPortable: true,
- expectedPdb: expectedPdb,
- expectedIsPortable: format == DebugInformationFormat.PortablePdb);
+ string actualPdb = GetPdbXml(compilation, debugEntryPoint, options, qualifiedMethodName, portable: true);
+ var (actualXml, expectedXml) = AdjustToPdbFormat(actualPdb, expectedPdb, actualIsPortable: true);
- AssertXml.Equal(expectedPdb, actualPortablePdb, $"PDB format: Portable{Environment.NewLine}", expectedValueSourcePath, expectedValueSourceLine, expectedIsXmlLiteral);
+ AssertXml.Equal(expectedXml, actualXml, $"PDB format: Portable{Environment.NewLine}", expectedValueSourcePath, expectedValueSourceLine, expectedIsXmlLiteral);
}
}
- internal static void AdjustToPdbFormat(
- XElement actualPdb,
- bool actualIsPortable,
- XElement expectedPdb,
- bool expectedIsPortable)
+ internal static (XElement Actual, XElement Expected) AdjustToPdbFormat(string actualPdb, string expectedPdb, bool actualIsPortable)
{
- if (actualIsPortable == expectedIsPortable)
+ var actualXml = XElement.Parse(actualPdb);
+ var expectedXml = XElement.Parse(expectedPdb);
+
+ if (actualIsPortable)
+ {
+ // Windows SymWriter doesn't serialize empty scopes.
+ // In Portable PDB each method with a body (even with no locals) has a scope that points to the imports. Such scope appears as empty
+ // in the current XML representation.
+ RemoveEmptyScopes(actualXml);
+
+ RemoveWindowsSpecificElements(expectedXml);
+ }
+ else
{
- return;
+ RemovePortableSpecificElements(expectedXml);
}
- // The test doesn't specify portable as expected PDB unless it's testing portable only in which case actual is also portable.
- Assert.False(expectedIsPortable);
- Assert.True(actualIsPortable);
+ RemoveEmptySequencePoints(expectedXml);
+ RemoveEmptyScopes(expectedXml);
+ RemoveEmptyCustomDebugInfo(expectedXml);
+ RemoveEmptyMethods(expectedXml);
+ RemoveFormatAttributes(expectedXml);
- // SymWriter doesn't create empty scopes. When the C# compiler uses forwarding CDI instead of a NamespaceScope
- // the scope is actually not empty - it logically contains the imports. Portable PDB does not use forwarding and thus
- // creates the scope. When generating PDB XML for testing the Portable DiaSymReader returns empty namespaces.
- RemoveEmptyScopes(actualPdb);
+ return (actualXml, expectedXml);
+ }
- // if the actual format is portable and the expected is not, remove native-only artifacts:
- RemoveNonPortablePdb(expectedPdb);
+ private static bool RemoveElements(IEnumerable elements)
+ {
+ var array = elements.ToArray();
- RemoveEmptySequencePoints(expectedPdb);
+ foreach (var e in array)
+ {
+ e.Remove();
+ }
- // remove scopes that only contained non-portable elements (namespace scopes)
- RemoveEmptyScopes(expectedPdb);
- RemoveMethodsWithNoSequencePoints(expectedPdb);
- RemoveEmptyMethods(expectedPdb);
+ return array.Length > 0;
}
- private static void RemoveMethodsWithNoSequencePoints(XElement pdb)
+ private static void RemoveEmptyCustomDebugInfo(XElement pdb)
{
- var methods = (from e in pdb.DescendantsAndSelf()
- where e.Name == "method"
- select e).ToArray();
- foreach (var method in methods)
- {
- bool hasNoSequencePoints = method.DescendantsAndSelf().Where(node => node.Name == "entry").IsEmpty();
- if (hasNoSequencePoints)
- {
- method.Remove();
- }
- }
+ RemoveElements(from e in pdb.DescendantsAndSelf()
+ where e.Name == "customDebugInfo" && !e.HasElements
+ select e);
}
private static void RemoveEmptyScopes(XElement pdb)
{
- XElement[] emptyScopes;
-
- do
- {
- emptyScopes = (from e in pdb.DescendantsAndSelf()
- where e.Name == "scope" && !e.HasElements
- select e).ToArray();
-
- foreach (var e in emptyScopes)
- {
- e.Remove();
- }
- }
- while (emptyScopes.Any());
+ while (RemoveElements(from e in pdb.DescendantsAndSelf()
+ where e.Name == "scope" && !e.HasElements
+ select e));
}
private static void RemoveEmptySequencePoints(XElement pdb)
{
- var emptyScopes = from e in pdb.DescendantsAndSelf()
- where e.Name == "sequencePoints" && !e.HasElements
- select e;
-
- foreach (var e in emptyScopes.ToArray())
- {
- e.Remove();
- }
+ RemoveElements(from e in pdb.DescendantsAndSelf()
+ where e.Name == "sequencePoints" && !e.HasElements
+ select e);
}
private static void RemoveEmptyMethods(XElement pdb)
{
- var emptyScopes = from e in pdb.DescendantsAndSelf()
- where e.Name == "method" && !e.HasElements
- select e;
+ RemoveElements(from e in pdb.DescendantsAndSelf()
+ where e.Name == "method" && !e.HasElements
+ select e);
+ }
- foreach (var e in emptyScopes.ToArray())
- {
- e.Remove();
- }
+ private static void RemoveWindowsSpecificElements(XElement expectedNativePdb)
+ {
+ RemoveElements(from e in expectedNativePdb.DescendantsAndSelf()
+ where e.Name == "forwardIterator" ||
+ e.Name == "forwardToModule" ||
+ e.Name == "forward" ||
+ e.Name == "tupleElementNames" ||
+ e.Name == "dynamicLocals" ||
+ e.Name == "using" ||
+ e.Name == "currentnamespace" ||
+ e.Name == "defaultnamespace" ||
+ e.Name == "importsforward" ||
+ e.Name == "xmlnamespace" ||
+ e.Name == "alias" ||
+ e.Name == "namespace" ||
+ e.Name == "type" ||
+ e.Name == "defunct" ||
+ e.Name == "extern" ||
+ e.Name == "externinfo" ||
+ e.Name == "local" && e.Attributes().Any(a => a.Name.LocalName == "name" && a.Value.StartsWith("$VB$ResumableLocal_")) ||
+ e.Attributes().Any(a => a.Name.LocalName == "format" && a.Value == "windows")
+ select e);
}
- private static void RemoveNonPortablePdb(XElement expectedNativePdb)
+ private static void RemovePortableSpecificElements(XElement expectedNativePdb)
{
- var nonPortableElements = from e in expectedNativePdb.DescendantsAndSelf()
- where e.Name == "customDebugInfo" ||
- e.Name == "currentnamespace" ||
- e.Name == "defaultnamespace" ||
- e.Name == "importsforward" ||
- e.Name == "xmlnamespace" ||
- e.Name == "alias" ||
- e.Name == "namespace" ||
- e.Name == "type" ||
- e.Name == "defunct" ||
- e.Name == "extern" ||
- e.Name == "externinfo" ||
- e.Name == "local" && e.Attributes().Any(a => a.Name.LocalName == "name" && a.Value.StartsWith("$VB$ResumableLocal_"))
- select e;
-
- foreach (var e in nonPortableElements.ToArray())
+ RemoveElements(from e in expectedNativePdb.DescendantsAndSelf()
+ where e.Attributes().Any(a => a.Name.LocalName == "format" && a.Value == "portable")
+ select e);
+ }
+
+ private static void RemoveFormatAttributes(XElement pdb)
+ {
+ foreach (var element in pdb.DescendantsAndSelf())
{
- e.Remove();
+ element.Attributes().FirstOrDefault(a => a.Name.LocalName == "format")?.Remove();
}
}
diff --git a/src/Test/Utilities/Portable/TestBase.cs b/src/Test/Utilities/Portable/TestBase.cs
index 9bdbe2b6bf663..e5ca5549f60cf 100644
--- a/src/Test/Utilities/Portable/TestBase.cs
+++ b/src/Test/Utilities/Portable/TestBase.cs
@@ -4,6 +4,7 @@
using System.Diagnostics;
using System.IO;
using System.Reflection;
+using System.Threading;
using System.Xml.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -147,7 +148,12 @@ public static MetadataReference SystemCoreRef
{
if (s_systemCoreRef == null)
{
- s_systemCoreRef = AssemblyMetadata.CreateFromImage(TestResources.NetFX.v4_0_30319.System_Core).GetReference(display: "System.Core.v4_0_30319.dll");
+ // We rely on reference equality in CreateSharedCompilation, so
+ // we must use a CompareExchange here.
+ Interlocked.CompareExchange(
+ ref s_systemCoreRef,
+ AssemblyMetadata.CreateFromImage(TestResources.NetFX.v4_0_30319.System_Core).GetReference(display: "System.Core.v4_0_30319.dll"),
+ null);
}
return s_systemCoreRef;
@@ -414,7 +420,12 @@ public static MetadataReference SystemRef
{
if (s_systemRef == null)
{
- s_systemRef = AssemblyMetadata.CreateFromImage(TestResources.NetFX.v4_0_30319.System).GetReference(display: "System.v4_0_30319.dll");
+ // We rely on reference equality in CreateSharedCompilation, so
+ // we must use a CompareExchange here.
+ Interlocked.CompareExchange(
+ ref s_systemRef,
+ AssemblyMetadata.CreateFromImage(TestResources.NetFX.v4_0_30319.System).GetReference(display: "System.v4_0_30319.dll"),
+ null);
}
return s_systemRef;
diff --git a/src/Test/Utilities/Portable/project.json b/src/Test/Utilities/Portable/project.json
index 2514bbdcbe11d..4d3cbef72331b 100644
--- a/src/Test/Utilities/Portable/project.json
+++ b/src/Test/Utilities/Portable/project.json
@@ -2,7 +2,7 @@
"dependencies": {
"Microsoft.CodeAnalysis.Test.Resources.Proprietary": "2.0.0-pre-20160714",
"Microsoft.CSharp": "4.3.0",
- "Microsoft.DiaSymReader.Converter.Xml": "1.0.0-beta1-61518-02",
+ "Microsoft.DiaSymReader.Converter.Xml": "1.0.0-beta1-61618-01",
"Microsoft.Metadata.Visualizer": "1.0.0-beta1-61531-03",
"Microsoft.NETCore.Platforms": "1.1.0",
"Microsoft.NETCore.Portable.Compatibility": "1.0.1",
diff --git a/src/Tools/BuildBoss/StructuredLoggerCheckerUtil.cs b/src/Tools/BuildBoss/StructuredLoggerCheckerUtil.cs
index c5d389d5b1a73..02ebd27531040 100644
--- a/src/Tools/BuildBoss/StructuredLoggerCheckerUtil.cs
+++ b/src/Tools/BuildBoss/StructuredLoggerCheckerUtil.cs
@@ -50,12 +50,6 @@ public bool Check(TextWriter textWriter)
var allGood = true;
foreach (var pair in _copyMap.OrderBy(x => x.Key))
{
- // Issue https://github.com/dotnet/roslyn/issues/18753
- if (Path.GetFileName(pair.Key) == "xunit.abstractions.dll")
- {
- continue;
- }
-
var list = pair.Value;
if (list.Count > 1)
{
diff --git a/src/Tools/GenerateSdkPackages/README.md b/src/Tools/GenerateSdkPackages/README.md
index 5d49c3b201f91..506b7420c27f6 100644
--- a/src/Tools/GenerateSdkPackages/README.md
+++ b/src/Tools/GenerateSdkPackages/README.md
@@ -1,8 +1,48 @@
# Generate SDK Packages
-This is a collection of tools for generating a set of NuGet packages for the VS SDK and updating our repo to consume them. This is a temporary solution until we work with the VS SDK team to help address a couple of issues with how their packages are produced.
+This is a collection of tools for generating a set of NuGet packages for the VS SDK and updating our repo to consume
+them. This is a temporary solution until we work with the VS SDK team to help address a couple of issues with how their
+packages are produced.
- make-all.ps1: Generates all of the NuGet packages we need for the VS SDK
- change-all.ps1: Changes all our project.json files to reference a new VS SDK version
+## Example workflow
+
+Here is an example of building, testing and uploading the packages for the 26418.00 build of d15prerel. First step is
+to make the packages for the build.
+
+``` powershell
+> .\make-all.ps1 -version "26418.00" -branch "d15prerel" -outpath c:\users\jaredpar\temp\nuget
+```
+
+This will create all of the packages with the version string 15.0.26418-alpha. Next the build needs to be updated
+to reflect this change in version for the packages we are consuming.
+
+``` powershell
+> .\change-all.ps1 -version "26418.00"
+```
+
+Before uploading the packages to myget please do a local build to validate the changes. In order to do this the
+following line needs to be added to NuGet.config. Do not merge this change, it is for testing only.
+
+``` xml
+
+```
+
+Given this entry we can quickly run the following developer flow to validate the changes:
+
+``` cmd
+> cd
+> Restore.cmd
+> Build.cmd
+> Test.cmd
+```
+
+Assuming this all passes then revert the change to NuGet.config, upload the packages to the roslyn-tools feed of
+myget and submit the result of `change-all.ps1` as a PR.
+
+
+
+
diff --git a/src/Tools/GenerateSdkPackages/change-all.ps1 b/src/Tools/GenerateSdkPackages/change-all.ps1
index d1553c885180f..54c9491163200 100644
--- a/src/Tools/GenerateSdkPackages/change-all.ps1
+++ b/src/Tools/GenerateSdkPackages/change-all.ps1
@@ -1,45 +1,44 @@
-Param(
- [string]$version = ""
-)
+[CmdletBinding(PositionalBinding=$false)]
+Param([string]$version = "")
-set-strictmode -version 2.0
-$ErrorActionPreference="Stop"
+Set-StrictMode -version 2.0
+$ErrorActionPreference = "Stop"
try {
if ($version -eq "") {
- write-host "Need a -version"
+ Write-Host "Need a -version"
exit 1
}
- $rootPath = resolve-path (join-path $PSScriptRoot "..\..\..\")
- $repoUtil = join-path $rootPath "Binaries\Debug\Exes\RepoUtil\RepoUtil.exe"
- if (-not (test-path $repoUtil)) {
- write-host "RepoUtil not found $repoUtil"
+ $rootPath = Resolve-Path (Join-Path $PSScriptRoot "..\..\..\")
+ $repoUtil = Join-Path $rootPath "Binaries\Debug\Exes\RepoUtil\RepoUtil.exe"
+ if (-not (Test-Path $repoUtil)) {
+ Write-Host "RepoUtil not found $repoUtil"
exit 1
}
- $fileList = gc (join-path $PSScriptRoot "files.txt")
+ $fileList = Get-Content (Join-Path $PSScriptRoot "files.txt")
$shortVersion = $version.Substring(0, $version.IndexOf('.'))
$packageVersion = "15.0.$shortVersion-alpha"
$changeList = @()
- write-host "Moving version to $packageVersion"
+ Write-Host "Moving version to $packageVersion"
foreach ($item in $fileList) {
- $name = split-path -leaf $item
+ $name = Split-Path -leaf $item
$simpleName = [IO.Path]::GetFileNameWithoutExtension($name)
$changeList += "$simpleName $packageVersion"
}
$changeFilePath = [IO.Path]::GetTempFileName()
- $changeList -join [Environment]::NewLine | out-file $changeFilePath
- write-host (gc -raw $changeFilePath)
+ $changeList -join [Environment]::NewLine | Out-File $changeFilePath
+ Write-Host (gc -raw $changeFilePath)
- $fullSln = join-path $rootPath "..\Roslyn.sln"
- if (test-path $fullSln) {
+ $fullSln = Join-Path $rootPath "..\Roslyn.sln"
+ if (Test-Path $fullSln) {
# Running as a part of the full enlisment. Need to add some extra paramteers
- $sourcesPath = resolve-path (join-path $rootPath "..")
+ $sourcesPath = Resolve-Path (Join-Path $rootPath "..")
$generatePath = $rootPath
- $configPath = join-path $rootPath "build\config\RepoUtilData.json"
+ $configPath = Join-Path $rootPath "build\config\RepoUtilData.json"
& $repoUtil -sourcesPath $sourcesPath -generatePath $generatePath -config $configPath change -version $changeFilePath
}
else {
@@ -48,7 +47,8 @@ try {
}
}
-catch [exception] {
- write-host $_.Exception
- exit -1
+catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ exit 1
}
diff --git a/src/Tools/GenerateSdkPackages/engine.nuspec b/src/Tools/GenerateSdkPackages/engine.nuspec
index 5925d34d4657a..ff23ae8a9ac23 100644
--- a/src/Tools/GenerateSdkPackages/engine.nuspec
+++ b/src/Tools/GenerateSdkPackages/engine.nuspec
@@ -17,8 +17,8 @@
VSSDK
-
-
+
+
diff --git a/src/Tools/GenerateSdkPackages/make-all.ps1 b/src/Tools/GenerateSdkPackages/make-all.ps1
index 5724959b6b96e..f25f8ad000fed 100644
--- a/src/Tools/GenerateSdkPackages/make-all.ps1
+++ b/src/Tools/GenerateSdkPackages/make-all.ps1
@@ -1,113 +1,95 @@
-Param(
+[CmdletBinding(PositionalBinding=$false)]
+param(
[string]$version = "26014.00",
[string]$branch = "d15rel",
- [string]$outPath = $null,
- [string]$fakeSign = $null
+ [string]$outPath = $null
)
-set-strictmode -version 2.0
-$ErrorActionPreference="Stop"
+Set-StrictMode -version 2.0
+$ErrorActionPreference = "Stop"
# Package a normal DLL into a nuget. Default used for packages that have a simple 1-1
# relationship between DLL and NuGet for only Net46.
-function package-normal() {
- $baseNuspecPath = join-path $PSScriptRoot "base.nuspec"
- $sourceFilePath = join-path $dropPath $item
- $filePath = join-path $dllPath $name
- if (-not (test-path $sourceFilePath)) {
- write-host "Could not locate $sourceFilePath"
+function Package-Normal() {
+ $baseNuspecPath = Join-Path $PSScriptRoot "base.nuspec"
+ $sourceFilePath = Join-Path $dropPath $item
+ $filePath = Join-Path $dllPath $name
+ if (-not (Test-Path $sourceFilePath)) {
+ Write-Host "Could not locate $sourceFilePath"
continue;
}
- cp $sourceFilePath $filePath
+ Copy-Item $sourceFilePath $filePath
& $fakeSign -f $filePath
& $nuget pack $baseNuspecPath -OutputDirectory $packagePath -Properties name=$simpleName`;version=$packageVersion`;filePath=$filePath
}
# The debugger DLLs have a more complex structure and it's easier to special case
# copying them over.
-function copy-debugger() {
- $refRootPath = [IO.Path]::GetFullPath((join-path $dropPath "..\..\Debugger\ReferenceDLL"))
- $debuggerDllPath = join-path $dllPath "debugger"
- $net20Path = join-path $debuggerDllPath "net20"
- $net45Path = join-path $debuggerDllPath "net45"
- $portablePath = join-path $debuggerDllPath "portable"
-
- mkdir $debuggerDllPath -ErrorAction SilentlyContinue | out-null
- mkdir $net20Path -ErrorAction SilentlyContinue | out-null
- mkdir $net45Path -ErrorAction SilentlyContinue | out-null
- mkdir $portablePath -ErrorAction SilentlyContinue | out-null
-
- pushd $debuggerDllPath
- try {
- $d = join-path $dropPath "..\..\Debugger"
- cp (join-path $d "RemoteDebugger\Microsoft.VisualStudio.Debugger.Engine.dll") $net20Path
- cp (join-path $d "IDE\Microsoft.VisualStudio.Debugger.Engine.dll") $net45Path
- cp (join-path $d "x-plat\coreclr.windows\mcg\Microsoft.VisualStudio.Debugger.Engine.dll") $portablePath
- cp (join-path $dropPath "Microsoft.VisualStudio.Debugger.Metadata.dll") $net20Path
- cp (join-path $dropPath "Microsoft.VisualStudio.Debugger.Metadata.dll") $portablePath
- gci -re -in *.dll | %{ & $fakeSign -f $_ }
- }
- finally {
- popd
- }
+function Copy-Debugger() {
+ $refRootPath = [IO.Path]::GetFullPath((Join-Path $dropPath "..\..\Debugger\ReferenceDLL"))
+ $debuggerDllPath = Join-Path $dllPath "debugger"
+ Create-Directory $debuggerDllPath
+ Copy-Item -re -fo "$refRootPath\*" $debuggerDllPath
}
# Used to package debugger nugets
-function package-debugger() {
+function Package-Debugger() {
param( [string]$kind )
- $debuggerPath = join-path $dllPath "debugger"
- $nuspecPath = join-path $PSScriptRoot "$kind.nuspec"
+ $debuggerPath = Join-Path $dllPath "debugger"
+ $nuspecPath = Join-Path $PSScriptRoot "$kind.nuspec"
& $nuget pack $nuspecPath -OutputDirectory $packagePath -Properties version=$packageVersion`;debuggerPath=$debuggerPath
}
try {
if ($outPath -eq "") {
- write-host "Need an -outPath value"
+ Write-Host "Need an -outPath value"
exit 1
}
- if ($fakeSign -eq "") {
- write-host "Need a -fakeSign value"
- exit 1
- }
+ . (Join-Path $PSScriptRoot "..\..\..\build\scripts\build-utils.ps1")
- $list = gc (join-path $PSScriptRoot "files.txt")
+ $list = Get-Content (Join-Path $PSScriptRoot "files.txt")
$dropPath = "\\cpvsbuild\drops\VS\$branch\raw\$version\binaries.x86ret\bin\i386"
- $nuget = join-path $PSScriptRoot "..\..\..\nuget.exe"
+ $nuget = Join-Path $PSScriptRoot "..\..\..\nuget.exe"
+ $fakeSign = Join-Path (Get-PackageDir "FakeSign") "Tools\FakeSign.exe"
$shortVersion = $version.Substring(0, $version.IndexOf('.'))
$packageVersion = "15.0.$shortVersion-alpha"
- $dllPath = join-path $outPath "Dlls"
- $packagePath = join-path $outPath "Packages"
+ $dllPath = Join-Path $outPath "Dlls"
+ $packagePath = Join-Path $outPath "Packages"
- write-host "Drop path is $dropPath"
- write-host "Package version $packageVersion"
- write-host "Out path is $outPath"
+ Write-Host "Drop path is $dropPath"
+ Write-Host "Package version $packageVersion"
+ Write-Host "Out path is $outPath"
- mkdir $outPath -ErrorAction SilentlyContinue | out-null
- mkdir $dllPath -ErrorAction SilentlyContinue | out-null
- mkdir $packagePath -ErrorAction SilentlyContinue | out-null
- pushd $outPath
+ Create-Directory $outPath
+ Create-Directory $dllPath
+ Create-Directory $packagePath
+ Push-Location $outPath
try {
- copy-debugger
+ Copy-Debugger
foreach ($item in $list) {
- $name = split-path -leaf $item
+ $name = Split-Path -leaf $item
$simpleName = [IO.Path]::GetFileNameWithoutExtension($name)
- write-host "Packing $simpleName"
+ Write-Host "Packing $simpleName"
switch ($simpleName) {
- "Microsoft.VisualStudio.Debugger.Engine" { package-debugger "engine" }
- "Microsoft.VisualStudio.Debugger.Metadata" { package-debugger "metadata" }
- default { package-normal }
+ "Microsoft.VisualStudio.Debugger.Engine" { Package-Debugger "engine" }
+ "Microsoft.VisualStudio.Debugger.Metadata" { Package-Debugger "metadata" }
+ default { Package-Normal }
}
}
}
finally {
- popd
+ Pop-Location
}
}
-catch [exception] {
- write-host $_.Exception
- exit -1
+catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ Get-PSCallstack
+ throw
+
+ exit 1
}
diff --git a/src/Tools/GenerateSdkPackages/metadata.nuspec b/src/Tools/GenerateSdkPackages/metadata.nuspec
index 3f4d9fd992201..adee79778f849 100644
--- a/src/Tools/GenerateSdkPackages/metadata.nuspec
+++ b/src/Tools/GenerateSdkPackages/metadata.nuspec
@@ -17,7 +17,7 @@
VSSDK
-
+
diff --git a/src/Tools/Github/GithubMergeTool/run.csx b/src/Tools/Github/GithubMergeTool/run.csx
index ef7890cfaf247..bbc90c880298b 100644
--- a/src/Tools/Github/GithubMergeTool/run.csx
+++ b/src/Tools/Github/GithubMergeTool/run.csx
@@ -57,6 +57,7 @@ private static async Task RunAsync()
await MakeRoslynPr("dev15.0.x", "dev15.1.x");
await MakeRoslynPr("dev15.1.x", "master");
await MakeRoslynPr("master", "dev16");
+ await MakeRoslynPr("master", "features/ioperation");
// Roslyn-internal branches
await MakeRoslynInternalPr("dev15.0.x", "dev15.1.x");
diff --git a/src/Tools/MicroBuild/cibuild.ps1 b/src/Tools/MicroBuild/cibuild.ps1
index 44d5c97b9eb6b..8a7fddf98638c 100644
--- a/src/Tools/MicroBuild/cibuild.ps1
+++ b/src/Tools/MicroBuild/cibuild.ps1
@@ -15,19 +15,17 @@ function Terminate-BuildProcesses() {
}
try {
+ Write-Host "${env:Userprofile}"
. (Join-Path $PSScriptRoot "..\..\..\build\scripts\build-utils.ps1")
Push-Location $PSScriptRoot
$nuget = Ensure-NuGet
- Exec { & $nuget locals all -clear }
+ Exec-Block { & $nuget locals all -clear } | Out-Host
$msbuild = Ensure-MSBuild
# The /nowarn exception can be removed once we fix https://github.com/dotnet/roslyn/issues/17325
- & $msbuild /nodereuse:false /p:Configuration=Release /p:SkipTest=true Build.proj /warnaserror /nowarn:MSB3277
- if (-not $?) {
- throw "Build failed"
- }
+ Exec-Block { & $msbuild /nodereuse:false /p:Configuration=Release /p:SkipTest=true Build.proj /warnaserror /nowarn:MSB3277 } | Out-Host
exit 0
}
diff --git a/src/Tools/MicroBuild/publish-assets.ps1 b/src/Tools/MicroBuild/publish-assets.ps1
index 3c0b56518c785..61db51110d528 100644
--- a/src/Tools/MicroBuild/publish-assets.ps1
+++ b/src/Tools/MicroBuild/publish-assets.ps1
@@ -40,6 +40,7 @@ try
"dev15.0.x" { }
"dev15.1.x" { }
"dev15.2.x" { }
+ "dev15.3-preview1" { }
"master" { }
"post-dev15" { }
"features/refout" { }
diff --git a/src/VisualStudio/CSharp/Impl/CSharpVisualStudio.csproj b/src/VisualStudio/CSharp/Impl/CSharpVisualStudio.csproj
index e45c1edd4defb..a91cb4f8e26b4 100644
--- a/src/VisualStudio/CSharp/Impl/CSharpVisualStudio.csproj
+++ b/src/VisualStudio/CSharp/Impl/CSharpVisualStudio.csproj
@@ -130,6 +130,7 @@
+
diff --git a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs
index 246f96ac0f4bc..f59aa21411022 100644
--- a/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs
+++ b/src/VisualStudio/CSharp/Impl/CodeModel/CSharpCodeModelService.NodeLocator.cs
@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
+using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
@@ -18,22 +19,16 @@ internal partial class CSharpCodeModelService
{
protected override AbstractNodeLocator CreateNodeLocator()
{
- return new NodeLocator(this);
+ return new NodeLocator();
}
private class NodeLocator : AbstractNodeLocator
{
- public NodeLocator(CSharpCodeModelService codeModelService)
- : base(codeModelService)
- {
- }
+ protected override string LanguageName => LanguageNames.CSharp;
- protected override EnvDTE.vsCMPart DefaultPart
- {
- get { return EnvDTE.vsCMPart.vsCMPartWholeWithAttributes; }
- }
+ protected override EnvDTE.vsCMPart DefaultPart => EnvDTE.vsCMPart.vsCMPartWholeWithAttributes;
- protected override VirtualTreePoint? GetStartPoint(SourceText text, SyntaxNode node, EnvDTE.vsCMPart part)
+ protected override VirtualTreePoint? GetStartPoint(SourceText text, OptionSet options, SyntaxNode node, EnvDTE.vsCMPart part)
{
switch (node.Kind())
{
@@ -53,16 +48,16 @@ protected override EnvDTE.vsCMPart DefaultPart
case SyntaxKind.DestructorDeclaration:
case SyntaxKind.OperatorDeclaration:
case SyntaxKind.ConversionOperatorDeclaration:
- return GetStartPoint(text, (BaseMethodDeclarationSyntax)node, part);
+ return GetStartPoint(text, options, (BaseMethodDeclarationSyntax)node, part);
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.IndexerDeclaration:
case SyntaxKind.EventDeclaration:
- return GetStartPoint(text, (BasePropertyDeclarationSyntax)node, part);
+ return GetStartPoint(text, options, (BasePropertyDeclarationSyntax)node, part);
case SyntaxKind.GetAccessorDeclaration:
case SyntaxKind.SetAccessorDeclaration:
case SyntaxKind.AddAccessorDeclaration:
case SyntaxKind.RemoveAccessorDeclaration:
- return GetStartPoint(text, (AccessorDeclarationSyntax)node, part);
+ return GetStartPoint(text, options, (AccessorDeclarationSyntax)node, part);
case SyntaxKind.DelegateDeclaration:
return GetStartPoint(text, (DelegateDeclarationSyntax)node, part);
case SyntaxKind.NamespaceDeclaration:
@@ -81,7 +76,7 @@ protected override EnvDTE.vsCMPart DefaultPart
}
}
- protected override VirtualTreePoint? GetEndPoint(SourceText text, SyntaxNode node, EnvDTE.vsCMPart part)
+ protected override VirtualTreePoint? GetEndPoint(SourceText text, OptionSet options, SyntaxNode node, EnvDTE.vsCMPart part)
{
switch (node.Kind())
{
@@ -141,7 +136,7 @@ private VirtualTreePoint GetBodyStartPoint(SourceText text, SyntaxToken openBrac
: new VirtualTreePoint(openBrace.SyntaxTree, text, openBrace.Span.End);
}
- private VirtualTreePoint GetBodyStartPoint(SourceText text, SyntaxToken openBrace, SyntaxToken closeBrace, int memberStartColumn)
+ private VirtualTreePoint GetBodyStartPoint(SourceText text, OptionSet options, SyntaxToken openBrace, SyntaxToken closeBrace, int memberStartColumn)
{
Debug.Assert(!openBrace.IsMissing);
Debug.Assert(!closeBrace.IsMissing);
@@ -181,7 +176,7 @@ private VirtualTreePoint GetBodyStartPoint(SourceText text, SyntaxToken openBrac
// If the line is all whitespace then place the caret at the first indent after the start
// of the member.
- var indentSize = GetTabSize(text);
+ var indentSize = GetTabSize(options);
var lineText = lineAfterOpenBrace.ToString();
var lineEndColumn = lineText.GetColumnFromLineOffset(lineText.Length, indentSize);
@@ -347,7 +342,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, BaseTypeDeclarationSynta
return new VirtualTreePoint(node.SyntaxTree, text, startPosition);
}
- private VirtualTreePoint GetStartPoint(SourceText text, BaseMethodDeclarationSyntax node, EnvDTE.vsCMPart part)
+ private VirtualTreePoint GetStartPoint(SourceText text, OptionSet options, BaseMethodDeclarationSyntax node, EnvDTE.vsCMPart part)
{
int startPosition;
@@ -380,9 +375,9 @@ private VirtualTreePoint GetStartPoint(SourceText text, BaseMethodDeclarationSyn
if (node.Body != null && !node.Body.OpenBraceToken.IsMissing)
{
var line = text.Lines.GetLineFromPosition(node.SpanStart);
- var indentation = line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(GetTabSize(text));
+ var indentation = line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(GetTabSize(options));
- return GetBodyStartPoint(text, node.Body.OpenBraceToken, node.Body.CloseBraceToken, indentation);
+ return GetBodyStartPoint(text, options, node.Body.OpenBraceToken, node.Body.CloseBraceToken, indentation);
}
else
{
@@ -436,7 +431,7 @@ private AccessorDeclarationSyntax FindFirstAccessorNode(BasePropertyDeclarationS
return node.AccessorList.Accessors.FirstOrDefault();
}
- private VirtualTreePoint GetStartPoint(SourceText text, BasePropertyDeclarationSyntax node, EnvDTE.vsCMPart part)
+ private VirtualTreePoint GetStartPoint(SourceText text, OptionSet options, BasePropertyDeclarationSyntax node, EnvDTE.vsCMPart part)
{
int startPosition;
@@ -467,17 +462,17 @@ private VirtualTreePoint GetStartPoint(SourceText text, BasePropertyDeclarationS
if (firstAccessorNode != null)
{
var line = text.Lines.GetLineFromPosition(firstAccessorNode.SpanStart);
- var indentation = line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(GetTabSize(text));
+ var indentation = line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(GetTabSize(options));
if (firstAccessorNode.Body != null)
{
- return GetBodyStartPoint(text, firstAccessorNode.Body.OpenBraceToken, firstAccessorNode.Body.CloseBraceToken, indentation);
+ return GetBodyStartPoint(text, options, firstAccessorNode.Body.OpenBraceToken, firstAccessorNode.Body.CloseBraceToken, indentation);
}
else if (!firstAccessorNode.SemicolonToken.IsMissing)
{
// This is total weirdness from the old C# code model with auto props.
// If there isn't a body, the semi-colon is used
- return GetBodyStartPoint(text, firstAccessorNode.SemicolonToken, firstAccessorNode.SemicolonToken, indentation);
+ return GetBodyStartPoint(text, options, firstAccessorNode.SemicolonToken, firstAccessorNode.SemicolonToken, indentation);
}
}
@@ -487,9 +482,9 @@ private VirtualTreePoint GetStartPoint(SourceText text, BasePropertyDeclarationS
if (node.AccessorList != null && !node.AccessorList.OpenBraceToken.IsMissing)
{
var line = text.Lines.GetLineFromPosition(node.SpanStart);
- var indentation = line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(GetTabSize(text));
+ var indentation = line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(GetTabSize(options));
- return GetBodyStartPoint(text, node.AccessorList.OpenBraceToken, node.AccessorList.CloseBraceToken, indentation);
+ return GetBodyStartPoint(text, options, node.AccessorList.OpenBraceToken, node.AccessorList.CloseBraceToken, indentation);
}
throw Exceptions.ThrowEFail();
@@ -501,7 +496,7 @@ private VirtualTreePoint GetStartPoint(SourceText text, BasePropertyDeclarationS
return new VirtualTreePoint(node.SyntaxTree, text, startPosition);
}
- private VirtualTreePoint GetStartPoint(SourceText text, AccessorDeclarationSyntax node, EnvDTE.vsCMPart part)
+ private VirtualTreePoint GetStartPoint(SourceText text, OptionSet options, AccessorDeclarationSyntax node, EnvDTE.vsCMPart part)
{
int startPosition;
@@ -526,9 +521,9 @@ private VirtualTreePoint GetStartPoint(SourceText text, AccessorDeclarationSynta
if (node.Body != null && !node.Body.OpenBraceToken.IsMissing)
{
var line = text.Lines.GetLineFromPosition(node.SpanStart);
- var indentation = line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(GetTabSize(text));
+ var indentation = line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(GetTabSize(options));
- return GetBodyStartPoint(text, node.Body.OpenBraceToken, node.Body.CloseBraceToken, indentation);
+ return GetBodyStartPoint(text, options, node.Body.OpenBraceToken, node.Body.CloseBraceToken, indentation);
}
throw Exceptions.ThrowEFail();
diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml
index bb02d9d38ec13..a365fc75093ac 100644
--- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml
+++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml
@@ -100,6 +100,16 @@
x:Name="at_the_end"
Content="{x:Static local:AdvancedOptionPageStrings.Option_at_the_end}"/>
+
+
+
+
+
+
diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs
index 77b0d7d0f70d3..54cb686744fd1 100644
--- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs
+++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs
@@ -48,6 +48,9 @@ public AdvancedOptionPageControl(IServiceProvider serviceProvider) : base(servic
BindToOption(with_other_members_of_the_same_kind, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind, LanguageNames.CSharp);
BindToOption(at_the_end, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.AtTheEnd, LanguageNames.CSharp);
+
+ BindToOption(prefer_throwing_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferThrowingProperties, LanguageNames.CSharp);
+ BindToOption(prefer_auto_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties, LanguageNames.CSharp);
}
}
}
\ No newline at end of file
diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs
index f6b1e507ddf29..f80af24135173 100644
--- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs
+++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs
@@ -62,6 +62,15 @@ public static string Option_with_other_members_of_the_same_kind
public static string Option_at_the_end
=> ServicesVSResources.at_the_end;
+ public static string Option_When_generating_properties
+ => ServicesVSResources.When_generating_properties;
+
+ public static string Option_prefer_auto_properties
+ => ServicesVSResources.prefer_auto_properties;
+
+ public static string Option_prefer_throwing_properties
+ => ServicesVSResources.prefer_throwing_properties;
+
public static string Option_GenerateXmlDocCommentsForTripleSlash
{
get { return CSharpVSResources.Generate_XML_documentation_comments_for; }
diff --git a/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpEntryPointFinderService.cs b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpEntryPointFinderService.cs
new file mode 100644
index 0000000000000..615cae4bda048
--- /dev/null
+++ b/src/VisualStudio/CSharp/Impl/ProjectSystemShim/CSharpEntryPointFinderService.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Composition;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
+
+namespace Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim
+{
+ [ExportLanguageService(typeof(IEntryPointFinderService), LanguageNames.CSharp), Shared]
+ internal class CSharpEntryPointFinderService : IEntryPointFinderService
+ {
+ public IEnumerable FindEntryPoints(INamespaceSymbol symbol, bool findFormsOnly)
+ {
+ return EntryPointFinder.FindEntryPoints(symbol);
+ }
+ }
+}
diff --git a/src/VisualStudio/Core/Def/Implementation/FindReferences/VisualStudioDefinitionsAndReferencesFactory.cs b/src/VisualStudio/Core/Def/Implementation/FindReferences/VisualStudioDefinitionsAndReferencesFactory.cs
index 927844d6c6a08..3a3cdad79d8ff 100644
--- a/src/VisualStudio/Core/Def/Implementation/FindReferences/VisualStudioDefinitionsAndReferencesFactory.cs
+++ b/src/VisualStudio/Core/Def/Implementation/FindReferences/VisualStudioDefinitionsAndReferencesFactory.cs
@@ -7,6 +7,7 @@
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Completion;
+using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Navigation;
@@ -31,11 +32,11 @@ public VisualStudioDefinitionsAndReferencesFactory(SVsServiceProvider servicePro
}
public override DefinitionItem GetThirdPartyDefinitionItem(
- Solution solution, ISymbol definition, CancellationToken cancellationToken)
+ Solution solution, DefinitionItem definitionItem, CancellationToken cancellationToken)
{
var symbolNavigationService = solution.Workspace.Services.GetService();
if (!symbolNavigationService.WouldNavigateToSymbol(
- definition, solution, cancellationToken,
+ definitionItem, solution, cancellationToken,
out var filePath, out var lineNumber, out var charOffset))
{
return null;
@@ -43,7 +44,7 @@ public override DefinitionItem GetThirdPartyDefinitionItem(
var displayParts = GetDisplayParts(filePath, lineNumber, charOffset);
return new ExternalDefinitionItem(
- GlyphTags.GetTags(definition.GetGlyph()), displayParts,
+ definitionItem.Tags, displayParts,
_serviceProvider, filePath, lineNumber, charOffset);
}
@@ -93,7 +94,11 @@ public ExternalDefinitionItem(
string filePath,
int lineNumber,
int charOffset)
- : base(tags, displayParts, ImmutableArray.Empty)
+ : base(tags, displayParts, ImmutableArray.Empty,
+ originationParts: default(ImmutableArray),
+ sourceSpans: default(ImmutableArray),
+ properties: null,
+ displayIfNoReferences: true)
{
_serviceProvider = serviceProvider;
_filePath = filePath;
@@ -101,9 +106,9 @@ public ExternalDefinitionItem(
_charOffset = charOffset;
}
- public override bool CanNavigateTo() => true;
+ public override bool CanNavigateTo(Workspace workspace) => true;
- public override bool TryNavigateTo()
+ public override bool TryNavigateTo(Workspace workspace, bool isPreview)
{
return TryOpenFile() && TryNavigateToPosition();
}
diff --git a/src/VisualStudio/Core/Def/Implementation/ICodeModelNavigationPointService.cs b/src/VisualStudio/Core/Def/Implementation/ICodeModelNavigationPointService.cs
index 7b4de14cc6976..aca474e631c51 100644
--- a/src/VisualStudio/Core/Def/Implementation/ICodeModelNavigationPointService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ICodeModelNavigationPointService.cs
@@ -3,6 +3,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host;
+using Microsoft.CodeAnalysis.Options;
namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
@@ -11,11 +12,11 @@ internal interface ICodeModelNavigationPointService : ILanguageService
///
/// Retrieves the start point of a given node for the specified EnvDTE.vsCMPart.
///
- VirtualTreePoint? GetStartPoint(SyntaxNode node, EnvDTE.vsCMPart? part = null);
+ VirtualTreePoint? GetStartPoint(SyntaxNode node, OptionSet options, EnvDTE.vsCMPart? part = null);
///
/// Retrieves the end point of a given node for the specified EnvDTE.vsCMPart.
///
- VirtualTreePoint? GetEndPoint(SyntaxNode node, EnvDTE.vsCMPart? part = null);
+ VirtualTreePoint? GetEndPoint(SyntaxNode node, OptionSet options, EnvDTE.vsCMPart? part = null);
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/Library/FindResults/LibraryManager.cs b/src/VisualStudio/Core/Def/Implementation/Library/FindResults/LibraryManager.cs
index b60d5848cff56..4970207077068 100644
--- a/src/VisualStudio/Core/Def/Implementation/Library/FindResults/LibraryManager.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Library/FindResults/LibraryManager.cs
@@ -12,9 +12,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindRes
[Guid(Guids.RoslynLibraryIdString)]
internal partial class LibraryManager : AbstractLibraryManager
{
- public LibraryManager(IServiceProvider serviceProvider)
+ private readonly Workspace _workspace;
+
+ public LibraryManager(Workspace workspace, IServiceProvider serviceProvider)
: base(Guids.RoslynLibraryId, serviceProvider)
{
+ _workspace = workspace;
}
public override uint GetLibraryFlags()
diff --git a/src/VisualStudio/Core/Def/Implementation/Library/FindResults/LibraryManager_FindReferences.cs b/src/VisualStudio/Core/Def/Implementation/Library/FindResults/LibraryManager_FindReferences.cs
index 2215cea7f0023..5e3decd24a47a 100644
--- a/src/VisualStudio/Core/Def/Implementation/Library/FindResults/LibraryManager_FindReferences.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Library/FindResults/LibraryManager_FindReferences.cs
@@ -40,7 +40,7 @@ internal IList CreateFindReferencesItems(
var query =
from d in definitionsAndReferences.Definitions
let referenceItems = CreateReferenceItems(d, definitionsAndReferences, commonPathElements)
- select new DefinitionTreeItem(d, referenceItems);
+ select new DefinitionTreeItem(_workspace, d, referenceItems);
return query.ToList();
}
diff --git a/src/VisualStudio/Core/Def/Implementation/Library/FindResults/TreeItems/DefinitionTreeItem.cs b/src/VisualStudio/Core/Def/Implementation/Library/FindResults/TreeItems/DefinitionTreeItem.cs
index ad63ca8c6b79c..e7667e84e0e30 100644
--- a/src/VisualStudio/Core/Def/Implementation/Library/FindResults/TreeItems/DefinitionTreeItem.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Library/FindResults/TreeItems/DefinitionTreeItem.cs
@@ -12,13 +12,16 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindRes
{
internal class DefinitionTreeItem : AbstractTreeItem
{
+ private readonly Workspace _workspace;
private readonly DefinitionItem _definitionItem;
public DefinitionTreeItem(
+ Workspace workspace,
DefinitionItem definitionItem,
ImmutableArray referenceItems)
: base(definitionItem.Tags.GetGlyph().GetGlyphIndex())
{
+ _workspace = workspace;
_definitionItem = definitionItem;
this.Children.AddRange(referenceItems);
@@ -49,14 +52,14 @@ private string CreateDisplayText()
public override int GoToSource()
{
- return _definitionItem.TryNavigateTo()
+ return _definitionItem.TryNavigateTo(_workspace, isPreview: true)
? VSConstants.S_OK
: VSConstants.E_FAIL;
}
public override bool CanGoToDefinition()
{
- return _definitionItem.CanNavigateTo();
+ return _definitionItem.CanNavigateTo(_workspace);
}
}
}
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs
index a5a42da3000ce..31b4702d3546c 100644
--- a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs
@@ -1,10 +1,15 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Collections.Generic;
using System.Diagnostics;
+using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Editor;
+using Microsoft.CodeAnalysis.Editor.FindUsages;
+using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists;
@@ -33,7 +38,13 @@ internal abstract partial class AbstractObjectBrowserLibraryManager : AbstractLi
private AbstractListItemFactory _listItemFactory;
private object _classMemberGate = new object();
- protected AbstractObjectBrowserLibraryManager(string languageName, Guid libraryGuid, __SymbolToolLanguage preferredLanguage, IServiceProvider serviceProvider)
+ private readonly IEnumerable> _streamingPresenters;
+
+ protected AbstractObjectBrowserLibraryManager(
+ string languageName,
+ Guid libraryGuid,
+ __SymbolToolLanguage preferredLanguage,
+ IServiceProvider serviceProvider)
: base(libraryGuid, serviceProvider)
{
_languageName = languageName;
@@ -43,6 +54,8 @@ protected AbstractObjectBrowserLibraryManager(string languageName, Guid libraryG
this.Workspace = componentModel.GetService();
this.LibraryService = this.Workspace.Services.GetLanguageServices(languageName).GetService();
this.Workspace.WorkspaceChanged += OnWorkspaceChanged;
+
+ this._streamingPresenters = componentModel.DefaultExportProvider.GetExports();
}
internal abstract AbstractDescriptionBuilder CreateDescriptionBuilder(
@@ -481,24 +494,21 @@ protected override bool TryExec(Guid commandGroup, uint commandId)
switch (commandId)
{
case (uint)VSConstants.VSStd97CmdID.FindReferences:
+ var streamingPresenter = _streamingPresenters.FirstOrDefault()?.Value;
var symbolListItem = _activeListItem as SymbolListItem;
- if (symbolListItem != null)
+
+ if (streamingPresenter != null && symbolListItem?.ProjectId != null)
{
- var projectId = symbolListItem.ProjectId;
- if (projectId != null)
+ var project = this.Workspace.CurrentSolution.GetProject(symbolListItem.ProjectId);
+ if (project != null)
{
- var project = this.Workspace.CurrentSolution.GetProject(projectId);
- if (project != null)
- {
- var compilation = project
- .GetCompilationAsync(CancellationToken.None)
- .WaitAndGetResult(CancellationToken.None);
-
- var symbol = symbolListItem.ResolveSymbol(compilation);
-
- this.Workspace.TryFindAllReferences(symbol, project, CancellationToken.None);
- return true;
- }
+ // Note: we kick of FindReferencesAsync in a 'fire and forget' manner.
+ // We don't want to block the UI thread while we compute the references,
+ // and the references will be asynchronously added to the FindReferences
+ // window as they are computed. The user also knows something is happening
+ // as the window, with the progress-banner will pop up immediately.
+ var task = FindReferencesAsync(streamingPresenter, symbolListItem, project);
+ return true;
}
}
@@ -508,5 +518,51 @@ protected override bool TryExec(Guid commandGroup, uint commandId)
return false;
}
+
+ private async Task FindReferencesAsync(
+ IStreamingFindUsagesPresenter presenter, SymbolListItem symbolListItem, Project project)
+ {
+ try
+ {
+ // Let the presented know we're starting a search. It will give us back
+ // the context object that the FAR service will push results into.
+ var context = presenter.StartSearch(
+ EditorFeaturesResources.Find_References, supportsReferences: true);
+
+ var cancellationToken = context.CancellationToken;
+
+ // Kick off the work to do the actual finding on a BG thread. That way we don'
+ // t block the calling (UI) thread too long if we happen to do our work on this
+ // thread.
+ await Task.Run(async () =>
+ {
+ await FindReferencesAsync(symbolListItem, project, context, cancellationToken).ConfigureAwait(false);
+ }, cancellationToken).ConfigureAwait(false);
+
+ // Note: we don't need to put this in a finally. The only time we might not hit
+ // this is if cancellation or another error gets thrown. In the former case,
+ // that means that a new search has started. We don't care about telling the
+ // context it has completed. In the latter case something wrong has happened
+ // and we don't want to run any more code in this particular context.
+ await context.OnCompletedAsync().ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
+ {
+ }
+ catch (Exception e) when (FatalError.ReportWithoutCrash(e))
+ {
+ }
+ }
+
+ private static async Task FindReferencesAsync(SymbolListItem symbolListItem, Project project, CodeAnalysis.FindUsages.FindUsagesContext context, CancellationToken cancellationToken)
+ {
+ var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
+ var symbol = symbolListItem.ResolveSymbol(compilation);
+ if (symbol != null)
+ {
+ await AbstractFindUsagesService.FindSymbolReferencesAsync(
+ context, symbol, project, cancellationToken).ConfigureAwait(false);
+ }
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Extensions/IVsHierarchyExtensions.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Extensions/IVsHierarchyExtensions.cs
index 4fa5e51d74922..68f7f9217b6de 100644
--- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Extensions/IVsHierarchyExtensions.cs
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/Extensions/IVsHierarchyExtensions.cs
@@ -76,5 +76,10 @@ public static bool TryGetTypeGuid(this IVsHierarchy hierarchy, out Guid typeGuid
{
return hierarchy.TryGetGuidProperty(__VSHPROPID.VSHPROPID_TypeGuid, out typeGuid);
}
+
+ public static bool TryGetTargetFrameworkMoniker(this IVsHierarchy hierarchy, uint itemId, out string targetFrameworkMoniker)
+ {
+ return hierarchy.TryGetItemProperty(itemId, (int)__VSHPROPID4.VSHPROPID_TargetFrameworkMoniker, out targetFrameworkMoniker);
+ }
}
}
diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IEntryPointFinderService.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IEntryPointFinderService.cs
new file mode 100644
index 0000000000000..a6052247ed275
--- /dev/null
+++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/IEntryPointFinderService.cs
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Host;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
+{
+ internal interface IEntryPointFinderService : ILanguageService
+ {
+ ///
+ /// Finds the types that contain entry points like the Main method in a give namespace.
+ ///
+ /// The namespace to search.
+ /// Restrict the search to only Windows Forms classes. Note that this is only implemented for VisualBasic
+ IEnumerable FindEntryPoints(INamespaceSymbol symbol, bool findFormsOnly);
+ }
+}
diff --git a/src/VisualStudio/Core/Def/Implementation/RQName/RQName.cs b/src/VisualStudio/Core/Def/Implementation/RQName/RQName.cs
index d29bd5cb77434..bff78830583bd 100644
--- a/src/VisualStudio/Core/Def/Implementation/RQName/RQName.cs
+++ b/src/VisualStudio/Core/Def/Implementation/RQName/RQName.cs
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis;
-using Microsoft.VisualStudio.LanguageServices.Implementation.RQName;
+using Microsoft.CodeAnalysis.Features.RQName;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.LanguageServices
@@ -19,9 +19,6 @@ public static class RQName
/// A string suitable to pass as the pszRQName argument to methods in
/// and .
public static string From(ISymbol symbol)
- {
- var node = RQNodeBuilder.Build(symbol);
- return (node != null) ? ParenthesesTreeWriter.ToParenthesesFormat(node.ToSimpleTree()) : null;
- }
+ => RQNameInternal.From(symbol);
}
-}
+}
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs
index d058ddd411a99..152361e46de76 100644
--- a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs
@@ -124,20 +124,19 @@ private HostType GetHostType()
var projectionBuffer = _containedLanguage.DataBuffer as IProjectionBuffer;
if (projectionBuffer != null)
{
- // For TypeScript hosted in HTML the source buffers will have type names
- // HTMLX and TypeScript. RazorCSharp has an HTMLX base type but should
- // not be associated with the HTML host type. Use ContentType.TypeName
- // instead of ContentType.IsOfType for HTMLX to ensure the Razor host
- // type is identified correctly.
- if (projectionBuffer.SourceBuffers.Any(b => b.ContentType.IsOfType(HTML) ||
- string.Compare(HTMLX, b.ContentType.TypeName, StringComparison.OrdinalIgnoreCase) == 0))
+ // RazorCSharp has an HTMLX base type but should not be associated with
+ // the HTML host type, so we check for it first.
+ if (projectionBuffer.SourceBuffers.Any(b => b.ContentType.IsOfType(Razor)))
{
- return HostType.HTML;
+ return HostType.Razor;
}
- if (projectionBuffer.SourceBuffers.Any(b => b.ContentType.IsOfType(Razor)))
+ // For TypeScript hosted in HTML the source buffers will have type names
+ // HTMLX and TypeScript.
+ if (projectionBuffer.SourceBuffers.Any(b => b.ContentType.IsOfType(HTML) ||
+ b.ContentType.IsOfType(HTMLX)))
{
- return HostType.Razor;
+ return HostType.HTML;
}
}
else
diff --git a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs
index 96d4da2029566..586496fdb8dd9 100644
--- a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs
@@ -61,7 +61,8 @@ public static string CreateUniqueEventName(
var tree = document.GetSyntaxTreeSynchronously(cancellationToken);
var typeNode = type.DeclaringSyntaxReferences.Where(r => r.SyntaxTree == tree).Select(r => r.GetSyntax(cancellationToken)).First();
var codeModel = document.Project.LanguageServices.GetService();
- var point = codeModel.GetStartPoint(typeNode, EnvDTE.vsCMPart.vsCMPartBody);
+ var options = document.GetOptionsAsync(cancellationToken).WaitAndGetResult_Venus(cancellationToken);
+ var point = codeModel.GetStartPoint(typeNode, options, EnvDTE.vsCMPart.vsCMPartBody);
var reservedNames = semanticModel.LookupSymbols(point.Value.Position, type).Select(m => m.Name);
return NameGenerator.EnsureUniqueness(name, reservedNames, document.Project.LanguageServices.GetService().IsCaseSensitive);
@@ -202,7 +203,8 @@ public static Tuple EnsureEventHandler(
var position = type.Locations.First(loc => loc.SourceTree == targetSyntaxTree).SourceSpan.Start;
var destinationType = syntaxFacts.GetContainingTypeDeclaration(targetSyntaxTree.GetRoot(cancellationToken), position);
- var insertionPoint = codeModel.GetEndPoint(destinationType, EnvDTE.vsCMPart.vsCMPartBody);
+ var options = targetDocument.GetOptionsAsync(cancellationToken).WaitAndGetResult_Venus(cancellationToken);
+ var insertionPoint = codeModel.GetEndPoint(destinationType, options, EnvDTE.vsCMPart.vsCMPartBody);
if (insertionPoint == null)
{
@@ -261,10 +263,12 @@ public static bool TryGetMemberNavigationPoint(
var memberNode = member.DeclaringSyntaxReferences.Select(r => r.GetSyntax(cancellationToken)).FirstOrDefault();
if (memberNode != null)
{
- var navigationPoint = codeModel.GetStartPoint(memberNode, EnvDTE.vsCMPart.vsCMPartNavigate);
+ var memberNodeDocument = thisDocument.Project.Solution.GetDocument(memberNode.SyntaxTree);
+ var options = memberNodeDocument.GetOptionsAsync(cancellationToken).WaitAndGetResult_Venus(cancellationToken);
+ var navigationPoint = codeModel.GetStartPoint(memberNode, options, EnvDTE.vsCMPart.vsCMPartNavigate);
if (navigationPoint != null)
{
- targetDocument = thisDocument.Project.Solution.GetDocument(memberNode.SyntaxTree);
+ targetDocument = memberNodeDocument;
textSpan = navigationPoint.Value.ToVsTextSpan();
return true;
}
diff --git a/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs b/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs
index e731aea949d87..783615afa1b88 100644
--- a/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs
@@ -7,11 +7,8 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
-using Microsoft.VisualStudio;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
-using Microsoft.VisualStudio.LanguageServices.Implementation.RQName;
using Microsoft.VisualStudio.Shell.Interop;
-using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
@@ -195,4 +192,4 @@ private Dictionary> GetHierarchiesAndItemIDsFromDocumen
return hierarchyToItemIDsMap;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioDocumentNavigationService.cs b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioDocumentNavigationService.cs
index 87c91a7443ef8..f6fea9c666fab 100644
--- a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioDocumentNavigationService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioDocumentNavigationService.cs
@@ -275,7 +275,11 @@ private static Document OpenDocument(Workspace workspace, DocumentId documentId,
{
if (options.GetOption(NavigationOptions.PreferProvisionalTab))
{
- using (NewDocumentStateScope ndss = new NewDocumentStateScope(__VSNEWDOCUMENTSTATE.NDS_Provisional, VSConstants.NewDocumentStateReason.Navigation))
+ // If we're just opening the provisional tab, then do not "activate" the document
+ // (i.e. don't give it focus). This way if a user is just arrowing through a set
+ // of FindAllReferences results, they don't have their cursor placed into the document.
+ var state = __VSNEWDOCUMENTSTATE.NDS_Provisional | __VSNEWDOCUMENTSTATE.NDS_NoActivate;
+ using (var scope = new NewDocumentStateScope(state, VSConstants.NewDocumentStateReason.Navigation))
{
workspace.OpenDocument(documentId);
}
diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs
index 371f6517daee9..a090d970c7aeb 100644
--- a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs
@@ -6,8 +6,10 @@
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
+using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Implementation.Structure;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
+using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
@@ -156,9 +158,13 @@ private bool TryNotifyForSpecificSymbol(
ISymbol symbol, Solution solution, CancellationToken cancellationToken)
{
AssertIsForeground();
+
+ var definitionItem = symbol.ToNonClassifiedDefinitionItem(solution, includeHiddenLocations: true);
+ definitionItem.Properties.TryGetValue(DefinitionItem.RQNameKey1, out var rqName);
+
if (!TryGetNavigationAPIRequiredArguments(
- symbol, solution, cancellationToken,
- out var hierarchy, out var itemID, out var navigationNotify, out var rqname))
+ definitionItem, rqName, solution, cancellationToken,
+ out var hierarchy, out var itemID, out var navigationNotify))
{
return false;
}
@@ -166,30 +172,21 @@ private bool TryNotifyForSpecificSymbol(
int returnCode = navigationNotify.OnBeforeNavigateToSymbol(
hierarchy,
itemID,
- rqname,
+ rqName,
out var navigationHandled);
- if (returnCode == VSConstants.S_OK && navigationHandled == 1)
- {
- return true;
- }
-
- return false;
+ return returnCode == VSConstants.S_OK && navigationHandled == 1;
}
public bool WouldNavigateToSymbol(
- ISymbol symbol, Solution solution, CancellationToken cancellationToken,
+ DefinitionItem definitionItem, Solution solution, CancellationToken cancellationToken,
out string filePath, out int lineNumber, out int charOffset)
{
- if (WouldNotifyToSpecificSymbol(symbol, solution, cancellationToken, out filePath, out lineNumber, out charOffset))
- {
- return true;
- }
+ definitionItem.Properties.TryGetValue(DefinitionItem.RQNameKey1, out var rqName1);
+ definitionItem.Properties.TryGetValue(DefinitionItem.RQNameKey2, out var rqName2);
- // If the symbol being considered is a constructor and no third parties choose to
- // navigate to the constructor, then try the constructor's containing type.
- if (symbol.IsConstructor() && WouldNotifyToSpecificSymbol(
- symbol.ContainingType, solution, cancellationToken, out filePath, out lineNumber, out charOffset))
+ if (WouldNotifyToSpecificSymbol(definitionItem, rqName1, solution, cancellationToken, out filePath, out lineNumber, out charOffset) ||
+ WouldNotifyToSpecificSymbol(definitionItem, rqName2, solution, cancellationToken, out filePath, out lineNumber, out charOffset))
{
return true;
}
@@ -201,7 +198,7 @@ public bool WouldNavigateToSymbol(
}
public bool WouldNotifyToSpecificSymbol(
- ISymbol symbol, Solution solution, CancellationToken cancellationToken,
+ DefinitionItem definitionItem, string rqName, Solution solution, CancellationToken cancellationToken,
out string filePath, out int lineNumber, out int charOffset)
{
AssertIsForeground();
@@ -209,9 +206,15 @@ public bool WouldNotifyToSpecificSymbol(
filePath = null;
lineNumber = 0;
charOffset = 0;
+
+ if (rqName == null)
+ {
+ return false;
+ }
+
if (!TryGetNavigationAPIRequiredArguments(
- symbol, solution, cancellationToken,
- out var hierarchy, out var itemID, out var navigationNotify, out var rqname))
+ definitionItem, rqName, solution, cancellationToken,
+ out var hierarchy, out var itemID, out var navigationNotify))
{
return false;
}
@@ -221,7 +224,7 @@ public bool WouldNotifyToSpecificSymbol(
int queryNavigateStatusCode = navigationNotify.QueryNavigateToSymbol(
hierarchy,
itemID,
- rqname,
+ rqName,
out var navigateToHierarchy,
out var navigateToItem,
navigateToTextSpan,
@@ -239,43 +242,38 @@ public bool WouldNotifyToSpecificSymbol(
}
private bool TryGetNavigationAPIRequiredArguments(
- ISymbol symbol,
+ DefinitionItem definitionItem,
+ string rqName,
Solution solution,
CancellationToken cancellationToken,
out IVsHierarchy hierarchy,
out uint itemID,
- out IVsSymbolicNavigationNotify navigationNotify,
- out string rqname)
+ out IVsSymbolicNavigationNotify navigationNotify)
{
AssertIsForeground();
hierarchy = null;
navigationNotify = null;
- rqname = null;
itemID = (uint)VSConstants.VSITEMID.Nil;
- if (!symbol.Locations.Any())
+ if (rqName == null)
{
return false;
}
- var sourceLocations = symbol.Locations.Where(loc => loc.IsInSource);
+ var sourceLocations = definitionItem.SourceSpans;
if (!sourceLocations.Any())
{
return false;
}
- var documents = sourceLocations.Select(loc => solution.GetDocument(loc.SourceTree)).WhereNotNull();
- if (!documents.Any())
- {
- return false;
- }
+ var documents = sourceLocations.SelectAsArray(loc => loc.Document);
// We can only pass one itemid to IVsSymbolicNavigationNotify, so prefer itemids from
// documents we consider to be "generated" to give external language services the best
// chance of participating.
- var generatedDocuments = documents.Where(d => d.IsGeneratedCode(cancellationToken));
+ var generatedDocuments = documents.WhereAsArray(d => d.IsGeneratedCode(cancellationToken));
var documentToUse = generatedDocuments.FirstOrDefault() ?? documents.First();
if (!TryGetVsHierarchyAndItemId(documentToUse, out hierarchy, out itemID))
@@ -289,8 +287,7 @@ private bool TryGetNavigationAPIRequiredArguments(
return false;
}
- rqname = LanguageServices.RQName.From(symbol);
- return rqname != null;
+ return true;
}
private bool TryGetVsHierarchyAndItemId(Document document, out IVsHierarchy hierarchy, out uint itemID)
diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs
index 4489c6295122a..a18ba876fcd2a 100644
--- a/src/VisualStudio/Core/Def/RoslynPackage.cs
+++ b/src/VisualStudio/Core/Def/RoslynPackage.cs
@@ -62,11 +62,11 @@ protected override void Initialize()
var method = compilerFailFast.GetMethod(nameof(FailFast.OnFatalException), BindingFlags.Static | BindingFlags.NonPublic);
property.SetValue(null, Delegate.CreateDelegate(property.PropertyType, method));
- RegisterFindResultsLibraryManager();
-
var componentModel = (IComponentModel)this.GetService(typeof(SComponentModel));
_workspace = componentModel.GetService();
+ RegisterFindResultsLibraryManager();
+
// Ensure the options persisters are loaded since we have to fetch options from the shell
componentModel.GetExtensions();
@@ -186,7 +186,7 @@ private void RegisterFindResultsLibraryManager()
var objectManager = this.GetService(typeof(SVsObjectManager)) as IVsObjectManager2;
if (objectManager != null)
{
- _libraryManager = new LibraryManager(this);
+ _libraryManager = new LibraryManager(_workspace, this);
if (ErrorHandler.Failed(objectManager.RegisterSimpleLibrary(_libraryManager, out _libraryManagerCookie)))
{
diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.Designer.cs b/src/VisualStudio/Core/Def/ServicesVSResources.Designer.cs
index ed96967717564..f151708ab124c 100644
--- a/src/VisualStudio/Core/Def/ServicesVSResources.Designer.cs
+++ b/src/VisualStudio/Core/Def/ServicesVSResources.Designer.cs
@@ -1457,6 +1457,15 @@ internal static string Pick_members {
}
}
+ ///
+ /// Looks up a localized string similar to prefer auto properties.
+ ///
+ internal static string prefer_auto_properties {
+ get {
+ return ResourceManager.GetString("prefer_auto_properties", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Prefer braces.
///
@@ -1547,6 +1556,15 @@ internal static string Prefer_predefined_type {
}
}
+ ///
+ /// Looks up a localized string similar to prefer throwing properties.
+ ///
+ internal static string prefer_throwing_properties {
+ get {
+ return ResourceManager.GetString("prefer_throwing_properties", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Preference.
///
@@ -2164,7 +2182,7 @@ internal static string Type_Parameters_colon {
internal static string Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio {
get {
return ResourceManager.GetString("Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_er" +
- "ror_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual Studio", resourceCulture);
+ "ror_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio", resourceCulture);
}
}
@@ -2332,6 +2350,15 @@ internal static string VisualStudioWorkspace_TryApplyChanges_cannot_be_called_fr
}
}
+ ///
+ /// Looks up a localized string similar to When generating properties:.
+ ///
+ internal static string When_generating_properties {
+ get {
+ return ResourceManager.GetString("When_generating_properties", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to When inserting properties, events and methods, place them:.
///
diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx
index 03a31223fb3d9..e23b643793526 100644
--- a/src/VisualStudio/Core/Def/ServicesVSResources.resx
+++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx
@@ -873,7 +873,7 @@ Additional information: {1}
Pick members
-
+
Unfortunately, a process used by Visual Studio has encountered an unrecoverable error. We recommend saving your work, and then closing and restarting Visual Studio.
@@ -900,6 +900,15 @@ Additional information: {1}
VisualStudioWorkspace.TryApplyChanges cannot be called from a background thread.
+
+ prefer auto properties
+
+
+ prefer throwing properties
+
+
+ When generating properties:
+
Options
diff --git a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
index 19480510cffe1..e688d411d9220 100644
--- a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
+++ b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
@@ -96,6 +96,7 @@
+
@@ -126,6 +127,7 @@
+
@@ -551,48 +553,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.AbstractNodeLocator.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.AbstractNodeLocator.cs
index 2603a962906e1..45dd5162c023e 100644
--- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.AbstractNodeLocator.cs
+++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.AbstractNodeLocator.cs
@@ -2,6 +2,8 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
+using Microsoft.CodeAnalysis.Formatting;
+using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel
@@ -12,33 +14,28 @@ internal partial class AbstractCodeModelService : ICodeModelService
protected abstract class AbstractNodeLocator
{
- private readonly AbstractCodeModelService _codeModelService;
-
- protected AbstractNodeLocator(AbstractCodeModelService codeModelService)
- {
- _codeModelService = codeModelService;
- }
+ protected abstract string LanguageName { get; }
protected abstract EnvDTE.vsCMPart DefaultPart { get; }
- protected abstract VirtualTreePoint? GetStartPoint(SourceText text, SyntaxNode node, EnvDTE.vsCMPart part);
- protected abstract VirtualTreePoint? GetEndPoint(SourceText text, SyntaxNode node, EnvDTE.vsCMPart part);
+ protected abstract VirtualTreePoint? GetStartPoint(SourceText text, OptionSet options, SyntaxNode node, EnvDTE.vsCMPart part);
+ protected abstract VirtualTreePoint? GetEndPoint(SourceText text, OptionSet options, SyntaxNode node, EnvDTE.vsCMPart part);
- protected int GetTabSize(SourceText text)
+ protected int GetTabSize(OptionSet options)
{
- return _codeModelService.GetTabSize(text);
+ return options.GetOption(FormattingOptions.TabSize, LanguageName);
}
- public VirtualTreePoint? GetStartPoint(SyntaxNode node, EnvDTE.vsCMPart? part)
+ public VirtualTreePoint? GetStartPoint(SyntaxNode node, OptionSet options, EnvDTE.vsCMPart? part)
{
var text = node.SyntaxTree.GetText();
- return GetStartPoint(text, node, part ?? DefaultPart);
+ return GetStartPoint(text, options, node, part ?? DefaultPart);
}
- public VirtualTreePoint? GetEndPoint(SyntaxNode node, EnvDTE.vsCMPart? part)
+ public VirtualTreePoint? GetEndPoint(SyntaxNode node, OptionSet options, EnvDTE.vsCMPart? part)
{
var text = node.SyntaxTree.GetText();
- return GetEndPoint(text, node, part ?? DefaultPart);
+ return GetEndPoint(text, options, node, part ?? DefaultPart);
}
}
}
diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs
index c261f07e3248e..d665f4082edea 100644
--- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs
+++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs
@@ -77,23 +77,6 @@ protected string GetNewLineCharacter(SourceText text)
return _editorOptionsFactoryService.GetEditorOptions(text).GetNewLineCharacter();
}
- protected int GetTabSize(SourceText text)
- {
- var snapshot = text.FindCorrespondingEditorTextSnapshot();
- return GetTabSize(snapshot);
- }
-
- protected int GetTabSize(ITextSnapshot snapshot)
- {
- if (snapshot == null)
- {
- throw new ArgumentNullException(nameof(snapshot));
- }
-
- var textBuffer = snapshot.TextBuffer;
- return _editorOptionsFactoryService.GetOptions(textBuffer).GetTabSize();
- }
-
protected SyntaxToken GetTokenWithoutAnnotation(SyntaxToken current, Func nextTokenGetter)
{
while (current.ContainsAnnotations)
@@ -552,14 +535,14 @@ public void Rename(ISymbol symbol, string newName, Solution solution)
public abstract string GetExternalSymbolName(ISymbol symbol);
public abstract string GetExternalSymbolFullName(ISymbol symbol);
- public VirtualTreePoint? GetStartPoint(SyntaxNode node, EnvDTE.vsCMPart? part)
+ public VirtualTreePoint? GetStartPoint(SyntaxNode node, OptionSet options, EnvDTE.vsCMPart? part)
{
- return _nodeLocator.GetStartPoint(node, part);
+ return _nodeLocator.GetStartPoint(node, options, part);
}
- public VirtualTreePoint? GetEndPoint(SyntaxNode node, EnvDTE.vsCMPart? part)
+ public VirtualTreePoint? GetEndPoint(SyntaxNode node, OptionSet options, EnvDTE.vsCMPart? part)
{
- return _nodeLocator.GetEndPoint(node, part);
+ return _nodeLocator.GetEndPoint(node, options, part);
}
public abstract EnvDTE.vsCMAccess GetAccess(ISymbol symbol);
diff --git a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs
index c426af31f8e25..ca8114c42399e 100644
--- a/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs
+++ b/src/VisualStudio/Core/Impl/CodeModel/InternalElements/AbstractCodeElement.cs
@@ -3,6 +3,7 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.LanguageServices.Implementation.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
@@ -152,7 +153,8 @@ public EnvDTE.TextPoint StartPoint
{
get
{
- var point = CodeModelService.GetStartPoint(LookupNode());
+ var options = GetDocument().GetOptionsAsync(CancellationToken.None).WaitAndGetResult_CodeModel(CancellationToken.None);
+ var point = CodeModelService.GetStartPoint(LookupNode(), options);
if (point == null)
{
return null;
@@ -166,7 +168,8 @@ public EnvDTE.TextPoint EndPoint
{
get
{
- var point = CodeModelService.GetEndPoint(LookupNode());
+ var options = GetDocument().GetOptionsAsync(CancellationToken.None).WaitAndGetResult_CodeModel(CancellationToken.None);
+ var point = CodeModelService.GetEndPoint(LookupNode(), options);
if (point == null)
{
return null;
@@ -178,7 +181,8 @@ public EnvDTE.TextPoint EndPoint
public virtual EnvDTE.TextPoint GetStartPoint(EnvDTE.vsCMPart part)
{
- var point = CodeModelService.GetStartPoint(LookupNode(), part);
+ var options = GetDocument().GetOptionsAsync(CancellationToken.None).WaitAndGetResult_CodeModel(CancellationToken.None);
+ var point = CodeModelService.GetStartPoint(LookupNode(), options, part);
if (point == null)
{
return null;
@@ -189,7 +193,8 @@ public virtual EnvDTE.TextPoint GetStartPoint(EnvDTE.vsCMPart part)
public virtual EnvDTE.TextPoint GetEndPoint(EnvDTE.vsCMPart part)
{
- var point = CodeModelService.GetEndPoint(LookupNode(), part);
+ var options = GetDocument().GetOptionsAsync(CancellationToken.None).WaitAndGetResult_CodeModel(CancellationToken.None);
+ var point = CodeModelService.GetEndPoint(LookupNode(), options, part);
if (point == null)
{
return null;
diff --git a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs
index e5d99a2a37c0f..5c73518a1bd9a 100644
--- a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs
+++ b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProject_IWorkspaceProjectContext.cs
@@ -120,6 +120,9 @@ public void SetOptions(string commandLineForOptions)
ExecuteForegroundAction(() =>
{
var commandLineArguments = SetArgumentsAndUpdateOptions(commandLineForOptions);
+
+ SetRuleSetFile(commandLineArguments.RuleSetPath);
+
PostSetOptions(commandLineArguments);
});
}
diff --git a/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs b/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs
index 1626d02b64914..671b0ff846c71 100644
--- a/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs
+++ b/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs
@@ -10,18 +10,13 @@
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Undo;
using Microsoft.CodeAnalysis.FindSymbols;
-using Microsoft.CodeAnalysis.FindUsages;
-using Microsoft.CodeAnalysis.GeneratedCodeRecognition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
-using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Composition;
-using Microsoft.VisualStudio.LanguageServices.Implementation;
using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel;
using Microsoft.VisualStudio.LanguageServices.Implementation.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
-using Microsoft.VisualStudio.Shell;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices
@@ -31,18 +26,15 @@ namespace Microsoft.VisualStudio.LanguageServices
internal class RoslynVisualStudioWorkspace : VisualStudioWorkspaceImpl
{
private readonly IEnumerable> _streamingPresenters;
- private readonly IEnumerable> _referencedSymbolsPresenters;
[ImportingConstructor]
private RoslynVisualStudioWorkspace(
ExportProvider exportProvider,
[ImportMany] IEnumerable> streamingPresenters,
- [ImportMany] IEnumerable> referencedSymbolsPresenters,
[ImportMany] IEnumerable documentOptionsProviderFactories)
: base(exportProvider.AsExportProvider())
{
_streamingPresenters = streamingPresenters;
- _referencedSymbolsPresenters = referencedSymbolsPresenters;
foreach (var providerFactory in documentOptionsProviderFactories)
{
@@ -202,44 +194,15 @@ public override bool TryGoToDefinition(
public override bool TryFindAllReferences(ISymbol symbol, Project project, CancellationToken cancellationToken)
{
- if (!_referencedSymbolsPresenters.Any())
- {
- return false;
- }
-
- if (!TryResolveSymbol(symbol, project, cancellationToken, out var searchSymbol, out var searchProject))
- {
- return false;
- }
-
- var searchSolution = searchProject.Solution;
-
- var result = SymbolFinder
- .FindReferencesAsync(searchSymbol, searchSolution, cancellationToken)
- .WaitAndGetResult(cancellationToken).ToList();
-
- if (result != null)
- {
- DisplayReferencedSymbols(searchSolution, result);
- return true;
- }
-
+ // Legacy API. Previously used by ObjectBrowser to support 'FindRefs' off of an
+ // object browser item. Now ObjectBrowser goes through the streaming-FindRefs system.
return false;
}
- public override void DisplayReferencedSymbols(
- Solution solution, IEnumerable referencedSymbols)
+ public override void DisplayReferencedSymbols(Solution solution, IEnumerable referencedSymbols)
{
- var service = this.Services.GetService();
- var definitionsAndReferences = service.CreateDefinitionsAndReferences(
- solution, referencedSymbols,
- includeHiddenLocations: false, cancellationToken: CancellationToken.None);
-
- foreach (var presenter in _referencedSymbolsPresenters)
- {
- presenter.Value.DisplayResult(definitionsAndReferences);
- return;
- }
+ // Legacy API. Previously used by ObjectBrowser to support 'FindRefs' off of an
+ // object browser item. Now ObjectBrowser goes through the streaming-FindRefs system.
}
internal override object GetBrowseObject(SymbolListItem symbolListItem)
diff --git a/src/VisualStudio/Core/Next/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs b/src/VisualStudio/Core/Next/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs
index efc411f7e6c11..e593f2f5ab596 100644
--- a/src/VisualStudio/Core/Next/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs
+++ b/src/VisualStudio/Core/Next/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs
@@ -4,15 +4,12 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Editor;
+using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.FindUsages;
-using Microsoft.CodeAnalysis.Formatting;
-using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell.FindAllReferences;
@@ -221,8 +218,12 @@ public IDisposable Subscribe(ITableDataSink sink)
#region FindUsagesContext overrides.
- public sealed override void SetSearchTitle(string title)
- => _findReferencesWindow.Title = title;
+ public sealed override Task SetSearchTitleAsync(string title)
+ {
+ // Note: IFindAllReferenceWindow.Title is safe to set from any thread.
+ _findReferencesWindow.Title = title;
+ return SpecializedTasks.EmptyTask;
+ }
public sealed override async Task OnCompletedAsync()
{
@@ -271,22 +272,12 @@ protected async Task CreateDocumentSpanEntryAsync(
var document = documentSpan.Document;
var (guid, projectName, sourceText) = await GetGuidAndProjectNameAndSourceTextAsync(document).ConfigureAwait(false);
- var narrowSpan = documentSpan.SourceSpan;
- var lineSpan = GetLineSpanForReference(sourceText, narrowSpan);
-
- var taggedLineParts = await GetTaggedTextForDocumentRegionAsync(document, narrowSpan, lineSpan).ConfigureAwait(false);
+ var classifiedSpansAndHighlightSpan =
+ await ClassifiedSpansAndHighlightSpan.ClassifyAsync(documentSpan, CancellationToken).ConfigureAwait(false);
return new DocumentSpanEntry(
this, definitionBucket, documentSpan, spanKind,
- projectName, guid, sourceText, taggedLineParts);
- }
-
- private TextSpan GetLineSpanForReference(SourceText sourceText, TextSpan referenceSpan)
- {
- var sourceLine = sourceText.Lines.GetLineFromPosition(referenceSpan.Start);
- var firstNonWhitespacePosition = sourceLine.GetFirstNonWhitespacePosition().Value;
-
- return TextSpan.FromBounds(firstNonWhitespacePosition, sourceLine.End);
+ projectName, guid, sourceText, classifiedSpansAndHighlightSpan);
}
private TextSpan GetRegionSpanForReference(SourceText sourceText, TextSpan referenceSpan)
@@ -302,202 +293,6 @@ private TextSpan GetRegionSpanForReference(SourceText sourceText, TextSpan refer
sourceText.Lines[lastLineNumber].End);
}
- private async Task GetTaggedTextForDocumentRegionAsync(
- Document document, TextSpan narrowSpan, TextSpan widenedSpan)
- {
- var highlightSpan = new TextSpan(
- start: narrowSpan.Start - widenedSpan.Start,
- length: narrowSpan.Length);
-
- var classifiedSpans = await GetClassifiedSpansAsync(document, narrowSpan, widenedSpan).ConfigureAwait(false);
- return new ClassifiedSpansAndHighlightSpan(classifiedSpans, highlightSpan);
- }
-
- private async Task> GetClassifiedSpansAsync(
- Document document, TextSpan narrowSpan, TextSpan widenedSpan)
- {
- var classificationService = document.GetLanguageService();
- if (classificationService == null)
- {
- // For languages that don't expose a classification service, we show the entire
- // item as plain text. Break the text into three spans so that we can properly
- // highlight the 'narrow-span' later on when we display the item.
- return ImmutableArray.Create(
- new ClassifiedSpan(ClassificationTypeNames.Text, TextSpan.FromBounds(widenedSpan.Start, narrowSpan.Start)),
- new ClassifiedSpan(ClassificationTypeNames.Text, narrowSpan),
- new ClassifiedSpan(ClassificationTypeNames.Text, TextSpan.FromBounds(narrowSpan.End, widenedSpan.End)));
- }
-
- // Call out to the individual language to classify the chunk of text around the
- // reference. We'll get both the syntactic and semantic spans for this region.
- // Because the semantic tags may override the semantic ones (for example,
- // "DateTime" might be syntactically an identifier, but semantically a struct
- // name), we'll do a later merging step to get the final correct list of
- // classifications. For tagging, normally the editor handles this. But as
- // we're producing the list of Inlines ourselves, we have to handles this here.
- var syntaxSpans = ListPool.Allocate();
- var semanticSpans = ListPool.Allocate();
- try
- {
- var sourceText = await document.GetTextAsync(CancellationToken).ConfigureAwait(false);
-
- await classificationService.AddSyntacticClassificationsAsync(
- document, widenedSpan, syntaxSpans, CancellationToken).ConfigureAwait(false);
- await classificationService.AddSemanticClassificationsAsync(
- document, widenedSpan, semanticSpans, CancellationToken).ConfigureAwait(false);
-
- var classifiedSpans = MergeClassifiedSpans(
- syntaxSpans, semanticSpans, widenedSpan, sourceText);
- return classifiedSpans;
- }
- finally
- {
- ListPool.Free(syntaxSpans);
- ListPool.Free(semanticSpans);
- }
- }
-
- private ImmutableArray MergeClassifiedSpans(
- List syntaxSpans, List semanticSpans,
- TextSpan widenedSpan, SourceText sourceText)
- {
- // The spans produced by the language services may not be ordered
- // (indeed, this happens with semantic classification as different
- // providers produce different results in an arbitrary order). Order
- // them first before proceeding.
- Order(syntaxSpans);
- Order(semanticSpans);
-
- // It's possible for us to get classified spans that occur *before*
- // or after the span we want to present. This happens because the calls to
- // AddSyntacticClassificationsAsync and AddSemanticClassificationsAsync
- // may return more spans than the range asked for. While bad form,
- // it's never been a requirement that implementation not do that.
- // For example, the span may be the non-full-span of a node, but the
- // classifiers may still return classifications for leading/trailing
- // trivia even if it's out of the bounds of that span.
- //
- // To deal with that, we adjust all spans so that they don't go outside
- // of the range we care about.
- AdjustSpans(syntaxSpans, widenedSpan);
- AdjustSpans(semanticSpans, widenedSpan);
-
- // The classification service will only produce classifications for
- // things it knows about. i.e. there will be gaps in what it produces.
- // Fill in those gaps so we have *all* parts of the span
- // classified properly.
- var filledInSyntaxSpans = ArrayBuilder.GetInstance();
- var filledInSemanticSpans = ArrayBuilder.GetInstance();
-
- try
- {
- FillInClassifiedSpanGaps(sourceText, widenedSpan.Start, syntaxSpans, filledInSyntaxSpans);
- FillInClassifiedSpanGaps(sourceText, widenedSpan.Start, semanticSpans, filledInSemanticSpans);
-
- // Now merge the lists together, taking all the results from syntaxParts
- // unless they were overridden by results in semanticParts.
- return MergeParts(filledInSyntaxSpans, filledInSemanticSpans);
- }
- finally
- {
- filledInSyntaxSpans.Free();
- filledInSemanticSpans.Free();
- }
- }
-
- private void AdjustSpans(List spans, TextSpan widenedSpan)
- {
- for (var i = 0; i < spans.Count; i++)
- {
- var span = spans[i];
-
- // Make sure the span actually intersects 'widenedSpan'. If it
- // does not, just put in an empty length span. It will get ignored later
- // when we walk through this list.
- var intersection = span.TextSpan.Intersection(widenedSpan);
-
- var newSpan = new ClassifiedSpan(span.ClassificationType,
- intersection ?? new TextSpan());
- spans[i] = newSpan;
- }
- }
-
- private static void FillInClassifiedSpanGaps(
- SourceText sourceText, int startPosition,
- List classifiedSpans, ArrayBuilder result)
- {
- foreach (var span in classifiedSpans)
- {
- // Ignore empty spans. We can get those when the classification service
- // returns spans outside of the range of the span we asked to classify.
- if (span.TextSpan.Length == 0)
- {
- continue;
- }
-
- // If there is space between this span and the last one, then add a space.
- if (startPosition != span.TextSpan.Start)
- {
- result.Add(new ClassifiedSpan(ClassificationTypeNames.Text,
- TextSpan.FromBounds(
- startPosition, span.TextSpan.Start)));
- }
-
- result.Add(span);
- startPosition = span.TextSpan.End;
- }
- }
-
- private void Order(List syntaxSpans)
- {
- syntaxSpans.Sort((s1, s2) => s1.TextSpan.Start - s2.TextSpan.Start);
- }
-
- private ImmutableArray MergeParts(
- ArrayBuilder syntaxParts,
- ArrayBuilder semanticParts)
- {
- // Take all the syntax parts. However, if any have been overridden by a
- // semantic part, then choose that one.
-
- var finalParts = ArrayBuilder.GetInstance();
- var lastReplacementIndex = 0;
- for (int i = 0, n = syntaxParts.Count; i < n; i++)
- {
- var syntaxPartAndSpan = syntaxParts[i];
-
- // See if we can find a semantic part to replace this syntax part.
- var replacementIndex = semanticParts.FindIndex(
- lastReplacementIndex, t => t.TextSpan == syntaxPartAndSpan.TextSpan);
-
- // Take the semantic part if it's just 'text'. We want to keep it if
- // the semantic classifier actually produced an interesting result
- // (as opposed to it just being a 'gap' classification).
- var part = replacementIndex >= 0 && !IsClassifiedAsText(semanticParts[replacementIndex])
- ? semanticParts[replacementIndex]
- : syntaxPartAndSpan;
- finalParts.Add(part);
-
- if (replacementIndex >= 0)
- {
- // If we found a semantic replacement, update the lastIndex.
- // That way we can start searching from that point instead
- // of checking all the elements each time.
- lastReplacementIndex = replacementIndex + 1;
- }
- }
-
- return finalParts.ToImmutableAndFree();
- }
-
- private bool IsClassifiedAsText(ClassifiedSpan partAndSpan)
- {
- // Don't take 'text' from the semantic parts. We'll get those for the
- // spaces between the actual interesting semantic spans, and we don't
- // want them to override actual good syntax spans.
- return partAndSpan.ClassificationType == ClassificationTypeNames.Text;
- }
-
public sealed override Task OnReferenceFoundAsync(SourceReferenceItem reference)
=> OnReferenceFoundWorkerAsync(reference);
diff --git a/src/VisualStudio/Core/Next/FindReferences/Entries/DocumentSpanEntry.cs b/src/VisualStudio/Core/Next/FindReferences/Entries/DocumentSpanEntry.cs
index 1293153a2734e..68c45919b30eb 100644
--- a/src/VisualStudio/Core/Next/FindReferences/Entries/DocumentSpanEntry.cs
+++ b/src/VisualStudio/Core/Next/FindReferences/Entries/DocumentSpanEntry.cs
@@ -8,10 +8,12 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Editor;
+using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo;
using Microsoft.CodeAnalysis.Editor.Implementation.ReferenceHighlighting;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Preview;
+using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.LanguageServices.Implementation.Extensions;
diff --git a/src/VisualStudio/Core/Next/FindReferences/FindReferencesTableControlEventProcessorProvider.cs b/src/VisualStudio/Core/Next/FindReferences/FindReferencesTableControlEventProcessorProvider.cs
index fadb3cff5e17f..0ef92fde3e93f 100644
--- a/src/VisualStudio/Core/Next/FindReferences/FindReferencesTableControlEventProcessorProvider.cs
+++ b/src/VisualStudio/Core/Next/FindReferences/FindReferencesTableControlEventProcessorProvider.cs
@@ -33,7 +33,7 @@ public override void PreprocessNavigate(ITableEntryHandle entry, TableEntryNavig
var supportsNavigation = entry.Identity as ISupportsNavigation;
if (supportsNavigation != null)
{
- if (supportsNavigation.TryNavigateTo())
+ if (supportsNavigation.TryNavigateTo(e.IsPreview))
{
e.Handled = true;
return;
diff --git a/src/VisualStudio/Core/Next/FindReferences/ISupportsNavigation.cs b/src/VisualStudio/Core/Next/FindReferences/ISupportsNavigation.cs
index bbd27fe9259b4..db0a6a2e4fefd 100644
--- a/src/VisualStudio/Core/Next/FindReferences/ISupportsNavigation.cs
+++ b/src/VisualStudio/Core/Next/FindReferences/ISupportsNavigation.cs
@@ -4,6 +4,6 @@ namespace Microsoft.VisualStudio.LanguageServices.FindUsages
{
internal interface ISupportsNavigation
{
- bool TryNavigateTo();
+ bool TryNavigateTo(bool isPreview);
}
}
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Next/FindReferences/RoslynDefinitionBucket.cs b/src/VisualStudio/Core/Next/FindReferences/RoslynDefinitionBucket.cs
index fbeedb1f129de..35341c0d82a0c 100644
--- a/src/VisualStudio/Core/Next/FindReferences/RoslynDefinitionBucket.cs
+++ b/src/VisualStudio/Core/Next/FindReferences/RoslynDefinitionBucket.cs
@@ -34,10 +34,8 @@ public RoslynDefinitionBucket(
DefinitionItem = definitionItem;
}
- public bool TryNavigateTo()
- {
- return DefinitionItem.TryNavigateTo();
- }
+ public bool TryNavigateTo(bool isPreview)
+ => DefinitionItem.TryNavigateTo(_presenter._workspace, isPreview);
public override bool TryGetValue(string key, out object content)
{
diff --git a/src/VisualStudio/Core/Next/FindReferences/TaggedTextAndHighlightSpan.cs b/src/VisualStudio/Core/Next/FindReferences/TaggedTextAndHighlightSpan.cs
deleted file mode 100644
index cf1b6855c7a26..0000000000000
--- a/src/VisualStudio/Core/Next/FindReferences/TaggedTextAndHighlightSpan.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Collections.Immutable;
-using Microsoft.CodeAnalysis.Classification;
-using Microsoft.CodeAnalysis.Text;
-
-namespace Microsoft.VisualStudio.LanguageServices.FindUsages
-{
- internal partial class StreamingFindUsagesPresenter
- {
- private struct ClassifiedSpansAndHighlightSpan
- {
- public readonly ImmutableArray ClassifiedSpans;
- public readonly TextSpan HighlightSpan;
-
- public ClassifiedSpansAndHighlightSpan(
- ImmutableArray classifiedSpans,
- TextSpan highlightSpan)
- {
- ClassifiedSpans = classifiedSpans;
- HighlightSpan = highlightSpan;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Next/Remote/JsonRpcClient.cs b/src/VisualStudio/Core/Next/Remote/JsonRpcClient.cs
index 5f30d5205d917..42e1d7d427efd 100644
--- a/src/VisualStudio/Core/Next/Remote/JsonRpcClient.cs
+++ b/src/VisualStudio/Core/Next/Remote/JsonRpcClient.cs
@@ -7,6 +7,7 @@
using System.Threading.Tasks;
using StreamJsonRpc;
using Microsoft.CodeAnalysis.Remote;
+using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Remote
{
@@ -22,10 +23,12 @@ internal class JsonRpcClient : IDisposable
public JsonRpcClient(
Stream stream, object callbackTarget, bool useThisAsCallback, CancellationToken cancellationToken)
{
+ Contract.Requires(stream != null);
+
var target = useThisAsCallback ? this : callbackTarget;
_cancellationToken = cancellationToken;
- _rpc = new JsonRpc(stream, stream, target);
+ _rpc = new JsonRpc(new JsonRpcMessageHandler(stream, stream), target);
_rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance);
_rpc.Disconnected += OnDisconnected;
diff --git a/src/VisualStudio/Core/Next/Remote/JsonRpcMessageHandler.cs b/src/VisualStudio/Core/Next/Remote/JsonRpcMessageHandler.cs
new file mode 100644
index 0000000000000..81eb5c574a3f6
--- /dev/null
+++ b/src/VisualStudio/Core/Next/Remote/JsonRpcMessageHandler.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO;
+using StreamJsonRpc;
+
+namespace Microsoft.VisualStudio.LanguageServices.Remote
+{
+ // This is a workaround for a limitation in vs-threading.
+ // https://github.com/dotnet/roslyn/issues/19042
+ internal class JsonRpcMessageHandler : HeaderDelimitedMessageHandler
+ {
+ public JsonRpcMessageHandler(Stream sendingStream, Stream receivingStream)
+ : base(sendingStream, receivingStream)
+ {
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ // Do not call base.Dispose. We do not want the AsyncSemaphore instances to be disposed due to a race
+ // condition.
+
+ if (disposing)
+ {
+ ReceivingStream?.Dispose();
+ SendingStream?.Dispose();
+ }
+ }
+ }
+}
diff --git a/src/VisualStudio/Core/Next/Remote/JsonRpcSession.cs b/src/VisualStudio/Core/Next/Remote/JsonRpcSession.cs
index 8ac9cb1727c13..95318f119232e 100644
--- a/src/VisualStudio/Core/Next/Remote/JsonRpcSession.cs
+++ b/src/VisualStudio/Core/Next/Remote/JsonRpcSession.cs
@@ -31,15 +31,35 @@ internal class JsonRpcSession : RemoteHostClient.Session
private readonly CancellationTokenRegistration _cancellationRegistration;
public static async Task CreateAsync(
- PinnedRemotableDataScope snapshot,
+ Optional>> getSnapshotAsync,
object callbackTarget,
Stream serviceStream,
Stream snapshotStreamOpt,
CancellationToken cancellationToken)
{
- var session = new JsonRpcSession(snapshot, callbackTarget, serviceStream, snapshotStreamOpt, cancellationToken);
+ var snapshot = getSnapshotAsync.Value == null ? null : await getSnapshotAsync.Value(cancellationToken).ConfigureAwait(false);
- await session.InitializeAsync().ConfigureAwait(false);
+ JsonRpcSession session;
+ try
+ {
+ session = new JsonRpcSession(snapshot, callbackTarget, serviceStream, snapshotStreamOpt, cancellationToken);
+ }
+ catch
+ {
+ snapshot?.Dispose();
+ throw;
+ }
+
+ try
+ {
+ await session.InitializeAsync().ConfigureAwait(false);
+ }
+ catch when (!cancellationToken.IsCancellationRequested)
+ {
+ // The session disposes of itself when cancellation is requested.
+ session.Dispose();
+ throw;
+ }
return session;
}
@@ -52,6 +72,8 @@ private JsonRpcSession(
CancellationToken cancellationToken) :
base(snapshot, cancellationToken)
{
+ Contract.Requires((snapshot == null) == (snapshotStreamOpt == null));
+
// get session id
_currentSessionId = Interlocked.Increment(ref s_sessionId);
diff --git a/src/VisualStudio/Core/Next/Remote/ServiceHubRemoteHostClient.cs b/src/VisualStudio/Core/Next/Remote/ServiceHubRemoteHostClient.cs
index ff1a0ffe7a8ff..a4b9e2a3d9624 100644
--- a/src/VisualStudio/Core/Next/Remote/ServiceHubRemoteHostClient.cs
+++ b/src/VisualStudio/Core/Next/Remote/ServiceHubRemoteHostClient.cs
@@ -5,6 +5,7 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Execution;
@@ -105,7 +106,7 @@ private ServiceHubRemoteHostClient(
_hostGroup = hostGroup;
_timeout = TimeSpan.FromMilliseconds(workspace.Options.GetOption(RemoteHostOptions.RequestServiceTimeoutInMS));
- _rpc = new JsonRpc(stream, stream, target: this);
+ _rpc = new JsonRpc(new JsonRpcMessageHandler(stream, stream), target: this);
_rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance);
// handle disconnected situation
@@ -114,17 +115,17 @@ private ServiceHubRemoteHostClient(
_rpc.StartListening();
}
- protected override async Task TryCreateServiceSessionAsync(string serviceName, PinnedRemotableDataScope snapshot, object callbackTarget, CancellationToken cancellationToken)
+ protected override async Task TryCreateServiceSessionAsync(string serviceName, Optional>> getSnapshotAsync, object callbackTarget, CancellationToken cancellationToken)
{
// get stream from service hub to communicate snapshot/asset related information
// this is the back channel the system uses to move data between VS and remote host for solution related information
- var snapshotStream = snapshot == null ? null : await RequestServiceAsync(_hubClient, WellKnownServiceHubServices.SnapshotService, _hostGroup, _timeout, cancellationToken).ConfigureAwait(false);
+ var snapshotStream = getSnapshotAsync.Value == null ? null : await RequestServiceAsync(_hubClient, WellKnownServiceHubServices.SnapshotService, _hostGroup, _timeout, cancellationToken).ConfigureAwait(false);
// get stream from service hub to communicate service specific information
// this is what consumer actually use to communicate information
var serviceStream = await RequestServiceAsync(_hubClient, serviceName, _hostGroup, _timeout, cancellationToken).ConfigureAwait(false);
- return await JsonRpcSession.CreateAsync(snapshot, callbackTarget, serviceStream, snapshotStream, cancellationToken).ConfigureAwait(false);
+ return await JsonRpcSession.CreateAsync(getSnapshotAsync, callbackTarget, serviceStream, snapshotStream, cancellationToken).ConfigureAwait(false);
}
protected override void OnConnected()
diff --git a/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj b/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj
index 100288ef84c47..d9ae8c0a7b6ba 100644
--- a/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj
+++ b/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj
@@ -102,10 +102,10 @@
-
+
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/AnalyzerItemTracker.cs b/src/VisualStudio/Core/SolutionExplorerShim/AnalyzerItemTracker.cs
index b966baf954c38..bf03a04fbc0ff 100644
--- a/src/VisualStudio/Core/SolutionExplorerShim/AnalyzerItemTracker.cs
+++ b/src/VisualStudio/Core/SolutionExplorerShim/AnalyzerItemTracker.cs
@@ -54,7 +54,7 @@ public void Unregister()
public uint SelectedItemId { get; private set; } = VSConstants.VSITEMID_NIL;
public AnalyzersFolderItem SelectedFolder { get; private set; }
public ImmutableArray SelectedAnalyzerItems { get; private set; } = ImmutableArray.Empty;
- public ImmutableArray SelectedDiagnosticItems { get; private set; } = ImmutableArray.Empty;
+ public ImmutableArray SelectedDiagnosticItems { get; private set; } = ImmutableArray.Empty;
int IVsSelectionEvents.OnCmdUIContextChanged(uint dwCmdUICookie, int fActive)
{
@@ -95,7 +95,7 @@ int IVsSelectionEvents.OnSelectionChanged(
.FirstOrDefault();
this.SelectedDiagnosticItems = selectedObjects
- .OfType()
+ .OfType()
.Select(b => b.DiagnosticItem)
.ToImmutableArray();
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersCommandHandler.cs b/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersCommandHandler.cs
index e971c479c7d7d..2f6108312be86 100644
--- a/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersCommandHandler.cs
+++ b/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersCommandHandler.cs
@@ -187,7 +187,7 @@ public IContextMenuController DiagnosticContextMenuController
private bool ShouldShowDiagnosticContextMenu(IEnumerable items)
{
- return items.All(item => item is DiagnosticItem);
+ return items.All(item => item is BaseDiagnosticItem);
}
private void UpdateDiagnosticContextMenu()
@@ -253,7 +253,7 @@ private void UpdateSeverityMenuItemsChecked()
HashSet selectedItemSeverities = new HashSet();
- var groups = _tracker.SelectedDiagnosticItems.GroupBy(item => item.AnalyzerItem.AnalyzersFolder.ProjectId);
+ var groups = _tracker.SelectedDiagnosticItems.GroupBy(item => item.ProjectId);
foreach (var group in groups)
{
@@ -412,7 +412,7 @@ private void SetSeverityHandler(object sender, EventArgs args)
foreach (var selectedDiagnostic in _tracker.SelectedDiagnosticItems)
{
- var projectId = selectedDiagnostic.AnalyzerItem.AnalyzersFolder.ProjectId;
+ var projectId = selectedDiagnostic.ProjectId;
var project = (AbstractProject)workspace.GetHostProject(projectId);
if (project == null)
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersFolderItem/AnalyzersFolderItemProvider.cs b/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersFolderItem/AnalyzersFolderItemProvider.cs
index dfea7bb1beb73..39cf05d549025 100644
--- a/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersFolderItem/AnalyzersFolderItemProvider.cs
+++ b/src/VisualStudio/Core/SolutionExplorerShim/AnalyzersFolderItem/AnalyzersFolderItemProvider.cs
@@ -68,7 +68,7 @@ private IAttachedCollectionSource CreateCollectionSourceCore(IVsHierarchyItem pa
{
var hierarchyMapper = TryGetProjectMap();
if (hierarchyMapper != null &&
- hierarchyMapper.TryGetProjectId(parentItem, out var projectId))
+ hierarchyMapper.TryGetProjectId(parentItem, targetFrameworkMoniker: null, projectId: out var projectId))
{
var workspace = TryGetWorkspace();
return new AnalyzersFolderItemSource(workspace, projectId, item, _commandHandler);
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItem.BrowseObject.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItem.BrowseObject.cs
similarity index 95%
rename from src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItem.BrowseObject.cs
rename to src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItem.BrowseObject.cs
index 4d93470a8c9c9..e7da0994e2d6f 100644
--- a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItem.BrowseObject.cs
+++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItem.BrowseObject.cs
@@ -9,13 +9,13 @@
namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
{
- internal sealed partial class DiagnosticItem : BaseItem
+ internal abstract partial class BaseDiagnosticItem
{
internal class BrowseObject : LocalizableProperties
{
- private DiagnosticItem _diagnosticItem;
+ private BaseDiagnosticItem _diagnosticItem;
- public BrowseObject(DiagnosticItem diagnosticItem)
+ public BrowseObject(BaseDiagnosticItem diagnosticItem)
{
_diagnosticItem = diagnosticItem;
}
@@ -121,7 +121,7 @@ public override string GetComponentName()
}
[Browsable(false)]
- public DiagnosticItem DiagnosticItem
+ public BaseDiagnosticItem DiagnosticItem
{
get { return _diagnosticItem; }
}
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItem.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItem.cs
similarity index 71%
rename from src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItem.cs
rename to src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItem.cs
index 50c41e8cfba4e..287357d7be3f3 100644
--- a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItem.cs
+++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItem.cs
@@ -1,36 +1,30 @@
-// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel;
-using System.Linq;
using System.Xml.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
-using Microsoft.Internal.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.Imaging;
using Microsoft.VisualStudio.Imaging.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
-using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
{
- internal sealed partial class DiagnosticItem : BaseItem
+ internal abstract partial class BaseDiagnosticItem : BaseItem
{
- private readonly DiagnosticDescriptor _descriptor;
- private ReportDiagnostic _effectiveSeverity;
- private readonly AnalyzerItem _analyzerItem;
- private readonly IContextMenuController _contextMenuController;
+ protected readonly DiagnosticDescriptor _descriptor;
+ protected ReportDiagnostic _effectiveSeverity;
public override event PropertyChangedEventHandler PropertyChanged;
- public DiagnosticItem(AnalyzerItem analyzerItem, DiagnosticDescriptor descriptor, ReportDiagnostic effectiveSeverity, IContextMenuController contextMenuController)
+
+ public BaseDiagnosticItem(DiagnosticDescriptor descriptor, ReportDiagnostic effectiveSeverity)
: base(string.Format("{0}: {1}", descriptor.Id, descriptor.Title))
{
- _analyzerItem = analyzerItem;
_descriptor = descriptor;
_effectiveSeverity = effectiveSeverity;
- _contextMenuController = contextMenuController;
}
public override ImageMoniker IconMoniker
@@ -41,13 +35,9 @@ public override ImageMoniker IconMoniker
}
}
- public AnalyzerItem AnalyzerItem
- {
- get
- {
- return _analyzerItem;
- }
- }
+ protected abstract Workspace Workspace { get; }
+ public abstract ProjectId ProjectId { get; }
+ protected abstract AnalyzerReference AnalyzerReference { get; }
public DiagnosticDescriptor Descriptor
{
@@ -70,14 +60,6 @@ public override object GetBrowseObject()
return new BrowseObject(this);
}
- public override IContextMenuController ContextMenuController
- {
- get
- {
- return _contextMenuController;
- }
- }
-
public Uri GetHelpLink()
{
if (BrowserHelper.TryGetUri(Descriptor.HelpLinkUri, out var link))
@@ -87,7 +69,7 @@ public Uri GetHelpLink()
if (!string.IsNullOrWhiteSpace(Descriptor.Id))
{
- _analyzerItem.AnalyzersFolder.Workspace.GetLanguageAndProjectType(_analyzerItem.AnalyzersFolder.ProjectId, out var language, out var projectType);
+ Workspace.GetLanguageAndProjectType(ProjectId, out var language, out var projectType);
// we use message format here since we don't have actual instance of diagnostic here.
// (which means we do not have a message)
@@ -141,7 +123,7 @@ private void UpdateRuleSetFile(string pathToRuleSet, ReportDiagnostic value)
{
var ruleSetDocument = XDocument.Load(pathToRuleSet);
- ruleSetDocument.SetSeverity(_analyzerItem.AnalyzerReference.Display, _descriptor.Id, value);
+ ruleSetDocument.SetSeverity(AnalyzerReference.Display, _descriptor.Id, value);
ruleSetDocument.Save(pathToRuleSet);
}
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItemSource.DiagnosticDescriptorComparer.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItemSource.DiagnosticDescriptorComparer.cs
similarity index 95%
rename from src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItemSource.DiagnosticDescriptorComparer.cs
rename to src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItemSource.DiagnosticDescriptorComparer.cs
index 0be9bed6af8fa..ec72be60d8e6b 100644
--- a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItemSource.DiagnosticDescriptorComparer.cs
+++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItemSource.DiagnosticDescriptorComparer.cs
@@ -7,7 +7,7 @@
namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
{
- internal partial class DiagnosticItemSource
+ internal abstract partial class BaseDiagnosticItemSource
{
internal sealed class DiagnosticDescriptorComparer : IComparer
{
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItemSource.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItemSource.cs
similarity index 64%
rename from src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItemSource.cs
rename to src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItemSource.cs
index 0a08c0df3fdae..ed0a6b4adf002 100644
--- a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItemSource.cs
+++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/BaseDiagnosticItemSource.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections;
@@ -10,47 +10,52 @@
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Shell;
-using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
{
- internal partial class DiagnosticItemSource : IAttachedCollectionSource
+ internal abstract partial class BaseDiagnosticItemSource : IAttachedCollectionSource
{
- private static readonly DiagnosticDescriptorComparer s_comparer = new DiagnosticDescriptorComparer();
-
- private readonly AnalyzerItem _item;
- private readonly IAnalyzersCommandHandler _commandHandler;
- private readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService;
- private BulkObservableCollection _diagnosticItems;
- private Workspace _workspace;
- private ProjectId _projectId;
- private ReportDiagnostic _generalDiagnosticOption;
- private ImmutableDictionary _specificDiagnosticOptions;
-
- public DiagnosticItemSource(AnalyzerItem item, IAnalyzersCommandHandler commandHandler, IDiagnosticAnalyzerService diagnosticAnalyzerService)
+ protected static readonly DiagnosticDescriptorComparer s_comparer = new DiagnosticDescriptorComparer();
+
+ protected readonly Workspace _workspace;
+ protected readonly ProjectId _projectId;
+ protected readonly IAnalyzersCommandHandler _commandHandler;
+ protected readonly IDiagnosticAnalyzerService _diagnosticAnalyzerService;
+
+ protected BulkObservableCollection _diagnosticItems;
+
+ protected ReportDiagnostic _generalDiagnosticOption;
+ protected ImmutableDictionary _specificDiagnosticOptions;
+
+ public BaseDiagnosticItemSource(Workspace workspace, ProjectId projectId, IAnalyzersCommandHandler commandHandler, IDiagnosticAnalyzerService diagnosticAnalyzerService)
{
- _item = item;
+ _workspace = workspace;
+ _projectId = projectId;
_commandHandler = commandHandler;
_diagnosticAnalyzerService = diagnosticAnalyzerService;
}
- public object SourceItem
- {
- get
- {
- return _item;
- }
- }
+ public abstract AnalyzerReference AnalyzerReference { get; }
+ protected abstract BaseDiagnosticItem CreateItem(DiagnosticDescriptor diagnostic, ReportDiagnostic effectiveSeverity);
+
+ public abstract object SourceItem { get; }
public bool HasItems
{
get
{
- _workspace = _item.AnalyzersFolder.Workspace;
- _projectId = _item.AnalyzersFolder.ProjectId;
+ if (_diagnosticItems != null)
+ {
+ return _diagnosticItems.Count > 0;
+ }
+
+ if (AnalyzerReference == null)
+ {
+ return false;
+ }
var project = _workspace.CurrentSolution.GetProject(_projectId);
- return _item.AnalyzerReference.GetAnalyzers(project.Language).Length > 0;
+ return AnalyzerReference.GetAnalyzers(project.Language).Length > 0;
}
}
@@ -60,17 +65,14 @@ public IEnumerable Items
{
if (_diagnosticItems == null)
{
- _workspace = _item.AnalyzersFolder.Workspace;
- _projectId = _item.AnalyzersFolder.ProjectId;
-
var project = _workspace.CurrentSolution.GetProject(_projectId);
_generalDiagnosticOption = project.CompilationOptions.GeneralDiagnosticOption;
_specificDiagnosticOptions = project.CompilationOptions.SpecificDiagnosticOptions;
- _diagnosticItems = new BulkObservableCollection();
+ _diagnosticItems = new BulkObservableCollection();
_diagnosticItems.AddRange(GetDiagnosticItems(project.Language, project.CompilationOptions));
- _workspace.WorkspaceChanged += Workspace_WorkspaceChanged;
+ _workspace.WorkspaceChanged += OnWorkspaceChangedLookForOptionsChanges;
}
Logger.Log(
@@ -81,7 +83,7 @@ public IEnumerable Items
}
}
- private IEnumerable GetDiagnosticItems(string language, CompilationOptions options)
+ private IEnumerable GetDiagnosticItems(string language, CompilationOptions options)
{
// Within an analyzer assembly, an individual analyzer may report multiple different diagnostics
// with the same ID. Or, multiple analyzers may report diagnostics with the same ID. Or a
@@ -92,7 +94,7 @@ private IEnumerable GetDiagnosticItems(string language, Compilat
// VS to another. So we group the diagnostics by ID, sort them within a group, and take the first
// one.
- return _item.AnalyzerReference.GetAnalyzers(language)
+ return AnalyzerReference.GetAnalyzers(language)
.SelectMany(a => _diagnosticAnalyzerService.GetDiagnosticDescriptors(a))
.GroupBy(d => d.Id)
.OrderBy(g => g.Key, StringComparer.CurrentCulture)
@@ -100,23 +102,23 @@ private IEnumerable GetDiagnosticItems(string language, Compilat
{
var selectedDiagnostic = g.OrderBy(d => d, s_comparer).First();
var effectiveSeverity = selectedDiagnostic.GetEffectiveSeverity(options);
- return new DiagnosticItem(_item, selectedDiagnostic, effectiveSeverity, _commandHandler.DiagnosticContextMenuController);
+ return CreateItem(selectedDiagnostic, effectiveSeverity);
});
}
- private void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs e)
+ private void OnWorkspaceChangedLookForOptionsChanges(object sender, WorkspaceChangeEventArgs e)
{
if (e.Kind == WorkspaceChangeKind.SolutionCleared ||
e.Kind == WorkspaceChangeKind.SolutionReloaded ||
e.Kind == WorkspaceChangeKind.SolutionRemoved)
{
- _workspace.WorkspaceChanged -= Workspace_WorkspaceChanged;
+ _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForOptionsChanges;
}
else if (e.ProjectId == _projectId)
{
if (e.Kind == WorkspaceChangeKind.ProjectRemoved)
{
- _workspace.WorkspaceChanged -= Workspace_WorkspaceChanged;
+ _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForOptionsChanges;
}
else if (e.Kind == WorkspaceChangeKind.ProjectChanged)
{
@@ -139,5 +141,6 @@ private void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs
}
}
}
+
}
}
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItem.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItem.cs
new file mode 100644
index 0000000000000..8c6c8341ae544
--- /dev/null
+++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItem.cs
@@ -0,0 +1,42 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.Internal.VisualStudio.PlatformUI;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
+{
+ internal sealed partial class CpsDiagnosticItem : BaseDiagnosticItem
+ {
+ private readonly CpsDiagnosticItemSource _source;
+
+ public CpsDiagnosticItem(CpsDiagnosticItemSource source, DiagnosticDescriptor descriptor, ReportDiagnostic effectiveSeverity)
+ : base(descriptor, effectiveSeverity)
+ {
+ _source = source;
+ }
+
+ protected override Workspace Workspace
+ {
+ get { return _source.Workspace; }
+ }
+
+ public override ProjectId ProjectId
+ {
+ get { return _source.ProjectId; }
+ }
+
+ protected override AnalyzerReference AnalyzerReference
+ {
+ get { return _source.AnalyzerReference; }
+ }
+
+ public override IContextMenuController ContextMenuController
+ {
+ get
+ {
+ return _source.DiagnosticItemContextMenuController;
+ }
+ }
+ }
+}
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItemProvider.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItemProvider.cs
new file mode 100644
index 0000000000000..c645392f6df45
--- /dev/null
+++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItemProvider.cs
@@ -0,0 +1,193 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel.Composition;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.Internal.VisualStudio.PlatformUI;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Utilities;
+using Microsoft.VisualStudio.ComponentModelHost;
+using System.Runtime.CompilerServices;
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
+{
+ [Export(typeof(IAttachedCollectionSourceProvider))]
+ [Name(nameof(CpsDiagnosticItemProvider))]
+ [Order]
+ internal sealed class CpsDiagnosticItemProvider : AttachedCollectionSourceProvider
+ {
+ private readonly IAnalyzersCommandHandler _commandHandler;
+ private readonly IComponentModel _componentModel;
+
+ private IDiagnosticAnalyzerService _diagnosticAnalyzerService;
+ private IHierarchyItemToProjectIdMap _projectMap;
+ private Workspace _workspace;
+
+ [ImportingConstructor]
+ public CpsDiagnosticItemProvider(
+ [Import(typeof(AnalyzersCommandHandler))]IAnalyzersCommandHandler commandHandler,
+ [Import(typeof(SVsServiceProvider))]IServiceProvider serviceProvider)
+ {
+ _commandHandler = commandHandler;
+ _componentModel = (IComponentModel)serviceProvider.GetService(typeof(SComponentModel));
+ }
+
+ protected override IAttachedCollectionSource CreateCollectionSource(IVsHierarchyItem item, string relationshipName)
+ {
+ if (item != null &&
+ item.HierarchyIdentity != null &&
+ item.HierarchyIdentity.NestedHierarchy != null &&
+ relationshipName == KnownRelationships.Contains)
+ {
+ if (NestedHierarchyHasProjectTreeCapability(item, "AnalyzerDependency"))
+ {
+ var projectRootItem = FindProjectRootItem(item, out string targetFrameworkMoniker);
+ if (projectRootItem != null)
+ {
+ return CreateCollectionSourceCore(projectRootItem, item, targetFrameworkMoniker);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Starting at the given item, walks up the tree to find the item representing the project root.
+ /// If the item is located under a target-framwork specific node, the corresponding
+ /// TargetFrameworkMoniker will be found as well.
+ ///
+ private static IVsHierarchyItem FindProjectRootItem(IVsHierarchyItem item, out string targetFrameworkMoniker)
+ {
+ targetFrameworkMoniker = null;
+
+ for (var parent = item; parent != null; parent = parent.Parent)
+ {
+ if (targetFrameworkMoniker == null)
+ {
+ targetFrameworkMoniker = GetTargetFrameworkMoniker(parent, targetFrameworkMoniker);
+ }
+
+ if (NestedHierarchyHasProjectTreeCapability(parent, "ProjectRoot"))
+ {
+ return parent;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Given an item determines if it represents a particular target frmework.
+ /// If so, it returns the corresponding TargetFrameworkMoniker.
+ ///
+ private static string GetTargetFrameworkMoniker(IVsHierarchyItem item, string targetFrameworkMoniker)
+ {
+ var hierarchy = item.HierarchyIdentity.NestedHierarchy;
+ var itemId = item.HierarchyIdentity.NestedItemID;
+
+ var projectTreeCapabilities = GetProjectTreeCapabilities(hierarchy, itemId);
+
+ bool isTargetNode = false;
+ string potentialTFM = null;
+ foreach (var capability in projectTreeCapabilities)
+ {
+ if (capability.Equals("TargetNode"))
+ {
+ isTargetNode = true;
+ }
+ else if (capability.StartsWith("$TFM:"))
+ {
+ potentialTFM = capability.Substring("$TFM:".Length);
+ }
+ }
+
+ return isTargetNode ? potentialTFM : null;
+ }
+
+ // This method is separate from CreateCollectionSource and marked with
+ // MethodImplOptions.NoInlining because we don't want calls to CreateCollectionSource
+ // to cause Roslyn assemblies to load where they aren't needed.
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private IAttachedCollectionSource CreateCollectionSourceCore(IVsHierarchyItem projectRootItem, IVsHierarchyItem item, string targetFrameworkMoniker)
+ {
+ var hierarchyMapper = TryGetProjectMap();
+ if (hierarchyMapper != null &&
+ hierarchyMapper.TryGetProjectId(projectRootItem, targetFrameworkMoniker, out var projectId))
+ {
+ var workspace = TryGetWorkspace();
+ var analyzerService = GetAnalyzerService();
+ return new CpsDiagnosticItemSource(workspace, projectId, item, _commandHandler, analyzerService);
+ }
+
+ return null;
+ }
+
+ private static bool NestedHierarchyHasProjectTreeCapability(IVsHierarchyItem item, string capability)
+ {
+ var hierarchy = item.HierarchyIdentity.NestedHierarchy;
+ var itemId = item.HierarchyIdentity.NestedItemID;
+
+ var projectTreeCapabilities = GetProjectTreeCapabilities(hierarchy, itemId);
+ return projectTreeCapabilities.Any(c => c.Equals(capability));
+ }
+
+ private static ImmutableArray GetProjectTreeCapabilities(IVsHierarchy hierarchy, uint itemId)
+ {
+ if (hierarchy.GetProperty(itemId, (int)__VSHPROPID7.VSHPROPID_ProjectTreeCapabilities, out var capabilitiesObj) == VSConstants.S_OK)
+ {
+ var capabilitiesString = (string)capabilitiesObj;
+ return ImmutableArray.Create(capabilitiesString.Split(' '));
+ }
+ else
+ {
+ return ImmutableArray.Empty;
+ }
+ }
+
+ private Workspace TryGetWorkspace()
+ {
+ if (_workspace == null)
+ {
+ var provider = _componentModel.DefaultExportProvider.GetExportedValueOrDefault();
+ if (provider != null)
+ {
+ _workspace = provider.GetWorkspace();
+ }
+ }
+
+ return _workspace;
+ }
+
+ private IHierarchyItemToProjectIdMap TryGetProjectMap()
+ {
+ var workspace = TryGetWorkspace();
+ if (workspace == null)
+ {
+ return null;
+ }
+
+ if (_projectMap == null)
+ {
+ _projectMap = workspace.Services.GetService();
+ }
+
+ return _projectMap;
+ }
+
+ private IDiagnosticAnalyzerService GetAnalyzerService()
+ {
+ if (_diagnosticAnalyzerService == null)
+ {
+ _diagnosticAnalyzerService = _componentModel.GetService();
+ }
+
+ return _diagnosticAnalyzerService;
+ }
+
+ }
+}
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItemSource.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItemSource.cs
new file mode 100644
index 0000000000000..81713c046cdb1
--- /dev/null
+++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/CpsDiagnosticItemSource.cs
@@ -0,0 +1,102 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.ComponentModel;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.Internal.VisualStudio.PlatformUI;
+using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
+using Microsoft.VisualStudio.Shell;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
+{
+ internal partial class CpsDiagnosticItemSource : BaseDiagnosticItemSource, INotifyPropertyChanged
+ {
+ private readonly IVsHierarchyItem _item;
+
+ private AnalyzerReference _analyzerReference;
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ public CpsDiagnosticItemSource(Workspace workspace, ProjectId projectId, IVsHierarchyItem item, IAnalyzersCommandHandler commandHandler, IDiagnosticAnalyzerService analyzerService)
+ : base(workspace, projectId, commandHandler, analyzerService)
+ {
+ _item = item;
+
+ _analyzerReference = TryGetAnalyzerReference(_workspace.CurrentSolution);
+ if (_analyzerReference == null)
+ {
+ // The workspace doesn't know about the project and/or the analyzer yet.
+ // Hook up an event handler so we can update when it does.
+ _workspace.WorkspaceChanged += OnWorkspaceChangedLookForAnalyzer;
+ }
+ }
+
+ public IContextMenuController DiagnosticItemContextMenuController => _commandHandler.DiagnosticContextMenuController;
+ public Workspace Workspace => _workspace;
+ public ProjectId ProjectId => _projectId;
+
+ public override object SourceItem => _item;
+
+ public override AnalyzerReference AnalyzerReference => _analyzerReference;
+ protected override BaseDiagnosticItem CreateItem(DiagnosticDescriptor diagnostic, ReportDiagnostic effectiveSeverity)
+ {
+ return new CpsDiagnosticItem(this, diagnostic, effectiveSeverity);
+ }
+
+ private void OnWorkspaceChangedLookForAnalyzer(object sender, WorkspaceChangeEventArgs e)
+ {
+ if (e.Kind == WorkspaceChangeKind.SolutionCleared ||
+ e.Kind == WorkspaceChangeKind.SolutionReloaded ||
+ e.Kind == WorkspaceChangeKind.SolutionRemoved)
+ {
+ _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer;
+ }
+ else if (e.Kind == WorkspaceChangeKind.SolutionAdded)
+ {
+ _analyzerReference = TryGetAnalyzerReference(e.NewSolution);
+ if (_analyzerReference != null)
+ {
+ _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer;
+
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasItems)));
+ }
+ }
+ else if (e.ProjectId == _projectId)
+ {
+ if (e.Kind == WorkspaceChangeKind.ProjectRemoved)
+ {
+ _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer;
+ }
+ else if (e.Kind == WorkspaceChangeKind.ProjectAdded
+ || e.Kind == WorkspaceChangeKind.ProjectChanged)
+ {
+ _analyzerReference = TryGetAnalyzerReference(e.NewSolution);
+ if (_analyzerReference != null)
+ {
+ _workspace.WorkspaceChanged -= OnWorkspaceChangedLookForAnalyzer;
+
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(HasItems)));
+ }
+ }
+ }
+ }
+
+ private AnalyzerReference TryGetAnalyzerReference(Solution solution)
+ {
+ var project = solution.GetProject(_projectId);
+
+ if (project == null)
+ {
+ return null;
+ }
+
+ if (!_item.HierarchyIdentity.NestedHierarchy.TryGetItemName(_item.HierarchyIdentity.NestedItemID, out string name))
+ {
+ return null;
+ }
+
+ return project.AnalyzerReferences.FirstOrDefault(r => r.Display.Equals(name));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItem.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItem.cs
new file mode 100644
index 0000000000000..902c9f1c27f15
--- /dev/null
+++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItem.cs
@@ -0,0 +1,54 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.ComponentModel;
+using System.Linq;
+using System.Xml.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
+using Microsoft.Internal.VisualStudio.PlatformUI;
+using Microsoft.VisualStudio.Imaging;
+using Microsoft.VisualStudio.Imaging.Interop;
+using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
+using Roslyn.Utilities;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
+{
+ internal sealed partial class LegacyDiagnosticItem : BaseDiagnosticItem
+ {
+ private readonly AnalyzerItem _analyzerItem;
+ private readonly IContextMenuController _contextMenuController;
+
+ public LegacyDiagnosticItem(AnalyzerItem analyzerItem, DiagnosticDescriptor descriptor, ReportDiagnostic effectiveSeverity, IContextMenuController contextMenuController)
+ : base(descriptor, effectiveSeverity)
+ {
+ _analyzerItem = analyzerItem;
+
+ _contextMenuController = contextMenuController;
+ }
+
+ protected override Workspace Workspace
+ {
+ get { return _analyzerItem.AnalyzersFolder.Workspace; }
+ }
+
+ public override ProjectId ProjectId
+ {
+ get { return _analyzerItem.AnalyzersFolder.ProjectId; }
+ }
+
+ protected override AnalyzerReference AnalyzerReference
+ {
+ get { return _analyzerItem.AnalyzerReference; }
+ }
+
+ public override IContextMenuController ContextMenuController
+ {
+ get
+ {
+ return _contextMenuController;
+ }
+ }
+ }
+}
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItemProvider.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItemProvider.cs
similarity index 86%
rename from src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItemProvider.cs
rename to src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItemProvider.cs
index 96d9baa0d45a0..954063f25da9f 100644
--- a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/DiagnosticItemProvider.cs
+++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItemProvider.cs
@@ -11,9 +11,9 @@
namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
{
[Export(typeof(IAttachedCollectionSourceProvider))]
- [Name("DiagnosticsItemProvider")]
+ [Name(nameof(LegacyDiagnosticItemProvider))]
[Order]
- internal sealed class DiagnosticItemProvider : AttachedCollectionSourceProvider
+ internal sealed class LegacyDiagnosticItemProvider : AttachedCollectionSourceProvider
{
private readonly IAnalyzersCommandHandler _commandHandler;
private readonly IServiceProvider _serviceProvider;
@@ -21,7 +21,7 @@ internal sealed class DiagnosticItemProvider : AttachedCollectionSourceProvider<
private IDiagnosticAnalyzerService _diagnosticAnalyzerService;
[ImportingConstructor]
- public DiagnosticItemProvider(
+ public LegacyDiagnosticItemProvider(
[Import(typeof(AnalyzersCommandHandler))]IAnalyzersCommandHandler commandHandler,
[Import(typeof(SVsServiceProvider))]IServiceProvider serviceProvider)
{
@@ -34,7 +34,7 @@ protected override IAttachedCollectionSource CreateCollectionSource(AnalyzerItem
if (relationshipName == KnownRelationships.Contains)
{
IDiagnosticAnalyzerService analyzerService = GetAnalyzerService();
- return new DiagnosticItemSource(item, _commandHandler, analyzerService);
+ return new LegacyDiagnosticItemSource(item, _commandHandler, analyzerService);
}
return null;
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItemSource.cs b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItemSource.cs
new file mode 100644
index 0000000000000..2108e6228549e
--- /dev/null
+++ b/src/VisualStudio/Core/SolutionExplorerShim/DiagnosticItem/LegacyDiagnosticItemSource.cs
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
+{
+ internal partial class LegacyDiagnosticItemSource : BaseDiagnosticItemSource
+ {
+ private readonly AnalyzerItem _item;
+
+ public LegacyDiagnosticItemSource(AnalyzerItem item, IAnalyzersCommandHandler commandHandler, IDiagnosticAnalyzerService diagnosticAnalyzerService)
+ : base(item.AnalyzersFolder.Workspace, item.AnalyzersFolder.ProjectId, commandHandler, diagnosticAnalyzerService)
+ {
+ _item = item;
+ }
+
+ public override object SourceItem
+ {
+ get
+ {
+ return _item;
+ }
+ }
+
+ public override AnalyzerReference AnalyzerReference
+ {
+ get { return _item.AnalyzerReference; }
+ }
+
+ protected override BaseDiagnosticItem CreateItem(DiagnosticDescriptor diagnostic, ReportDiagnostic effectiveSeverity)
+ {
+ return new LegacyDiagnosticItem(_item, diagnostic, effectiveSeverity, _commandHandler.DiagnosticContextMenuController);
+ }
+ }
+}
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/HierarchyItemToProjectIdMap.cs b/src/VisualStudio/Core/SolutionExplorerShim/HierarchyItemToProjectIdMap.cs
index 539aac18fa723..fb1cc5e0dd9b8 100644
--- a/src/VisualStudio/Core/SolutionExplorerShim/HierarchyItemToProjectIdMap.cs
+++ b/src/VisualStudio/Core/SolutionExplorerShim/HierarchyItemToProjectIdMap.cs
@@ -6,6 +6,7 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
{
@@ -20,7 +21,7 @@ public HierarchyItemToProjectIdMap(VisualStudioWorkspaceImpl workspace)
_workspace = workspace;
}
- public bool TryGetProjectId(IVsHierarchyItem hierarchyItem, out ProjectId projectId)
+ public bool TryGetProjectId(IVsHierarchyItem hierarchyItem, string targetFrameworkMoniker, out ProjectId projectId)
{
if (_workspace.DeferredState == null)
{
@@ -28,9 +29,32 @@ public bool TryGetProjectId(IVsHierarchyItem hierarchyItem, out ProjectId projec
return false;
}
+ var nestedHierarchy = hierarchyItem.HierarchyIdentity.NestedHierarchy;
+ var nestedHierarchyId = hierarchyItem.HierarchyIdentity.NestedItemID;
+
+ if (!nestedHierarchy.TryGetCanonicalName(nestedHierarchyId, out string nestedCanonicalName))
+ {
+ projectId = default(ProjectId);
+ return false;
+ }
+
var project = _workspace.DeferredState.ProjectTracker.ImmutableProjects
- .Where(p => p.Hierarchy == hierarchyItem.HierarchyIdentity.NestedHierarchy)
- .Where(p => p.ProjectSystemName == hierarchyItem.CanonicalName)
+ .Where(p =>
+ {
+ if (p.Hierarchy.TryGetCanonicalName((uint)VSConstants.VSITEMID.Root, out string projectCanonicalName)
+ && projectCanonicalName.Equals(nestedCanonicalName, System.StringComparison.OrdinalIgnoreCase))
+ {
+ if (targetFrameworkMoniker == null)
+ {
+ return true;
+ }
+
+ return p.Hierarchy.TryGetTargetFrameworkMoniker((uint)VSConstants.VSITEMID.Root, out string projectTargetFrameworkMoniker)
+ && projectTargetFrameworkMoniker.Equals(targetFrameworkMoniker);
+ }
+
+ return false;
+ })
.SingleOrDefault();
if (project == null)
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/IHierarchyItemToProjectIdMap.cs b/src/VisualStudio/Core/SolutionExplorerShim/IHierarchyItemToProjectIdMap.cs
index 53b51826c3050..a5e86235c6fc1 100644
--- a/src/VisualStudio/Core/SolutionExplorerShim/IHierarchyItemToProjectIdMap.cs
+++ b/src/VisualStudio/Core/SolutionExplorerShim/IHierarchyItemToProjectIdMap.cs
@@ -6,8 +6,21 @@
namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
{
+ ///
+ /// Maps from hierarchy items to project IDs.
+ ///
internal interface IHierarchyItemToProjectIdMap : IWorkspaceService
{
- bool TryGetProjectId(IVsHierarchyItem hierarchyItem, out ProjectId projectId);
+ ///
+ /// Given an representing a project and an optional target framework moniker,
+ /// returns the of the equivalent Roslyn .
+ ///
+ /// An for the project root.
+ /// An optional string representing a TargetFrameworkMoniker.
+ /// This is only useful in multi-targeting scenarios where there may be multiple Roslyn projects
+ /// (one per target framework) for a single project on disk.
+ /// The of the found project, if any.
+ /// True if the desired project was found; false otherwise.
+ bool TryGetProjectId(IVsHierarchyItem hierarchyItem, string targetFrameworkMoniker, out ProjectId projectId);
}
}
diff --git a/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.csproj b/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.csproj
index fb6b1d2f0fd5f..124e8e3acc66c 100644
--- a/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.csproj
+++ b/src/VisualStudio/Core/SolutionExplorerShim/SolutionExplorerShim.csproj
@@ -72,19 +72,24 @@
-
-
+
+
+
+
+
+
+
-
+
-
-
+
+
True
@@ -113,4 +118,4 @@
-
+
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Test/CodeModel/AbstractCodeElementTests`1.vb b/src/VisualStudio/Core/Test/CodeModel/AbstractCodeElementTests`1.vb
index 807638eaf1aa2..aa68e7e956b7b 100644
--- a/src/VisualStudio/Core/Test/CodeModel/AbstractCodeElementTests`1.vb
+++ b/src/VisualStudio/Core/Test/CodeModel/AbstractCodeElementTests`1.vb
@@ -29,6 +29,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.CodeModel
Assert.NotNull(codeElement)
expected(codeElement)
+
+ ' Now close the file and ensure the behavior is still the same
+ state.VisualStudioWorkspace.CloseDocument(state.Workspace.Documents.Single().Id)
+
+ codeElement = GetCodeElement(state)
+ Assert.NotNull(codeElement)
+
+ expected(codeElement)
End Using
End Sub
diff --git a/src/VisualStudio/Core/Test/FindResults/FindResultsTests.vb b/src/VisualStudio/Core/Test/FindResults/FindResultsTests.vb
deleted file mode 100644
index ced49b7352683..0000000000000
--- a/src/VisualStudio/Core/Test/FindResults/FindResultsTests.vb
+++ /dev/null
@@ -1,261 +0,0 @@
-' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-Imports System.Text
-Imports System.Threading
-Imports Microsoft.CodeAnalysis
-Imports Microsoft.CodeAnalysis.Editor.UnitTests
-Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities
-Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
-Imports Microsoft.CodeAnalysis.FindUsages
-Imports Microsoft.CodeAnalysis.FindSymbols
-Imports Microsoft.VisualStudio.Composition
-Imports Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults
-Imports Microsoft.VisualStudio.LanguageServices.UnitTests.ObjectBrowser.Mocks
-Imports Roslyn.Test.Utilities
-Imports Roslyn.Utilities
-
-Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.FindResults
- Public Class FindResultsTests
-
-
- Public Async Function ConstructorReferencesShouldNotAppearUnderClassNodeInCSharp() As System.Threading.Tasks.Task
- Dim markup =
-
- Dim expectedResults = New List(Of AbstractTreeItem) From
- {
- TestFindResult.CreateDefinition($"[CSharpAssembly1] C.C() ({ServicesVSResources._1_reference})",
- TestFindResult.CreateReference("Test1.cs - (11, 21) : var a = new C();")),
- TestFindResult.CreateDefinition($"[CSharpAssembly1] C.C(int) ({ServicesVSResources._1_reference})",
- TestFindResult.CreateReference("Test1.cs - (12, 21) : var b = new C(5);")),
- TestFindResult.CreateDefinition($"[CSharpAssembly1] class C ({ServicesVSResources._1_reference})",
- TestFindResult.CreateReference("Test1.cs - (13, 17) : var c = C.z;"))
- }
-
- Await VerifyAsync(markup, LanguageNames.CSharp, expectedResults)
- End Function
-
-
-
- Public Async Function ConstructorReferencesShouldNotAppearUnderClassNodeInVisualBasic() As System.Threading.Tasks.Task
- Dim markup =
-
- Dim expectedResults = New List(Of AbstractTreeItem) From
- {
- TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Class C ({ServicesVSResources._1_reference})",
- TestFindResult.CreateReference("Test1.vb - (14, 17) : Dim d = C.z")),
- TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Sub C.New() ({ServicesVSResources._1_reference})",
- TestFindResult.CreateReference("Test1.vb - (12, 21) : Dim a = New C()")),
- TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Sub C.New(Integer) ({ServicesVSResources._1_reference})",
- TestFindResult.CreateReference("Test1.vb - (13, 21) : Dim b = New C(5)"))
- }
-
- Await VerifyAsync(markup, LanguageNames.VisualBasic, expectedResults)
- End Function
-
-
- Public Async Function TestSourceNamespace() As System.Threading.Tasks.Task
- Dim markup =
-
- Dim expectedResults = New List(Of AbstractTreeItem) From
- {
- TestFindResult.CreateUnnavigable($"namespace NS ({String.Format(ServicesVSResources._0_references, 2)})",
- TestFindResult.CreateReference("Test1.cs - (2, 11) : namespace NS"),
- TestFindResult.CreateReference("Test1.cs - (6, 11) : namespace NS"))
- }
-
- Await VerifyAsync(markup, LanguageNames.CSharp, expectedResults)
- End Function
-
-
- Public Async Function TestMetadataNamespace() As System.Threading.Tasks.Task
- Dim markup =
-
- Dim expectedResults = New List(Of AbstractTreeItem) From
- {
- TestFindResult.CreateUnnavigable($"namespace System ({String.Format(ServicesVSResources._0_references, 2)})",
- TestFindResult.CreateReference("Test1.cs - (2, 7) : using System;"),
- TestFindResult.CreateReference("Test1.cs - (3, 7) : using System.Threading;"))
- }
-
- Await VerifyAsync(markup, LanguageNames.CSharp, expectedResults)
- End Function
-
- Private Shared ReadOnly s_exportProvider As ExportProvider = MinimalTestExportProvider.CreateExportProvider(
- TestExportProvider.MinimumCatalogWithCSharpAndVisualBasic.WithParts(
- GetType(MockDocumentNavigationServiceProvider),
- GetType(MockSymbolNavigationServiceProvider),
- GetType(DefaultDefinitionsAndReferencesFactory)))
-
- Private Async Function VerifyAsync(markup As XElement, languageName As String, expectedResults As IList(Of AbstractTreeItem)) As System.Threading.Tasks.Task
- Dim workspaceXml =
-
- CommonReferences="true">
- <%= markup %>
-
-
-
- Using workspace = TestWorkspace.Create(workspaceXml, exportProvider:=s_exportProvider)
- Dim doc = workspace.Documents.Single()
- Dim workspaceDoc = workspace.CurrentSolution.GetDocument(doc.Id)
- If Not doc.CursorPosition.HasValue Then
- Assert.True(False, "Missing caret location in document.")
- End If
-
- Dim symbol = Await SymbolFinder.FindSymbolAtPositionAsync(workspaceDoc, doc.CursorPosition.Value, CancellationToken.None)
- Assert.NotNull(symbol)
-
- Dim result = Await SymbolFinder.FindReferencesAsync(symbol, workspace.CurrentSolution, CancellationToken.None)
-
- WpfTestCase.RequireWpfFact($"The {NameOf(Implementation.Library.FindResults.LibraryManager)} assumes it's on the VS UI thread and thus uses WaitAndGetResult")
- Dim libraryManager = New LibraryManager(New MockServiceProvider(New MockComponentModel(workspace.ExportProvider)))
-
- Dim factory = workspace.Services.GetService(Of IDefinitionsAndReferencesFactory)
- Dim definitionsAndReferences = factory.CreateDefinitionsAndReferences(
- workspace.CurrentSolution, result,
- includeHiddenLocations:=False, cancellationToken:=CancellationToken.None)
- Dim findReferencesTree = libraryManager.CreateFindReferencesItems(definitionsAndReferences)
-
- ' We cannot control the ordering of top-level nodes in the Find Symbol References window, so do not consider ordering of these items here.
- expectedResults = expectedResults.OrderBy(Function(n) n.DisplayText).ToList()
- findReferencesTree = findReferencesTree.OrderBy(Function(n) n.DisplayText).ToList()
-
- VerifyResultsTree(expectedResults, findReferencesTree)
- End Using
- End Function
-
- Private Sub VerifyResultsTree(expectedResults As IList(Of AbstractTreeItem), findReferencesTree As IList(Of AbstractTreeItem))
- Assert.True(expectedResults.Count = findReferencesTree.Count, $"Unexpected number of results. Expected: {expectedResults.Count} Actual: {findReferencesTree.Count}
-Expected Items:
-{GetResultText(expectedResults)}
-Actual Items:
-{GetResultText(findReferencesTree)}
-")
-
- For index = 0 To expectedResults.Count - 1
- Dim expectedItem = expectedResults(index)
- Dim actualItem = findReferencesTree(index)
-
- Assert.Equal(expectedItem.DisplayText, actualItem.DisplayText)
- Assert.Equal(expectedItem.CanGoToDefinition, actualItem.CanGoToDefinition)
- Assert.Equal(expectedItem.CanGoToReference, actualItem.CanGoToReference)
-
- Dim expectedHasChildren = expectedItem.Children IsNot Nothing AndAlso expectedItem.Children.Count > 0
- Dim actualHasChildren = actualItem.Children IsNot Nothing AndAlso actualItem.Children.Count > 0
-
- Assert.Equal(expectedHasChildren, actualHasChildren)
-
- If expectedHasChildren Then
- VerifyResultsTree(expectedItem.Children, actualItem.Children)
- End If
- Next
- End Sub
-
- Private Function GetResultText(items As IList(Of AbstractTreeItem)) As String
- Dim indentString = String.Empty
- Dim stringBuilder = New StringBuilder()
-
- GetResultTextWorker(items, stringBuilder, indentString)
-
- Return stringBuilder.ToString()
- End Function
-
- Private Sub GetResultTextWorker(items As IList(Of AbstractTreeItem), stringBuilder As StringBuilder, indentString As String)
- For Each item In items
- stringBuilder.Append(indentString)
- stringBuilder.Append(item.DisplayText)
- stringBuilder.Append(" [Kind: " &
- If(item.CanGoToDefinition, "Def", String.Empty) &
- If(item.CanGoToReference, "Ref", String.Empty) &
- If(item.CanGoToDefinition OrElse item.CanGoToDefinition, "None", String.Empty) &
- "]")
-
- If item.Children IsNot Nothing AndAlso item.Children.Any() Then
- GetResultTextWorker(item.Children, stringBuilder, indentString + " ")
- End If
- Next
- End Sub
-
- Private Class TestFindResult
- Inherits AbstractTreeItem
-
- Public ReadOnly expectedCanGoToDefinition As Boolean?
- Public ReadOnly expectedCanGoToReference As Boolean?
-
- Public Overrides Function CanGoToDefinition() As Boolean
- Return If(expectedCanGoToDefinition, True)
- End Function
-
- Public Overrides Function CanGoToReference() As Boolean
- Return If(expectedCanGoToReference, True)
- End Function
-
- Public Shared Function CreateDefinition(displayText As String, ParamArray children As TestFindResult()) As TestFindResult
- Return New TestFindResult(displayText, children, expectedCanGoToDefinition:=True, expectedCanGoToReference:=False)
- End Function
-
- Public Shared Function CreateReference(displayText As String, ParamArray children As TestFindResult()) As TestFindResult
- Return New TestFindResult(displayText, children, expectedCanGoToDefinition:=False, expectedCanGoToReference:=True)
- End Function
-
- Public Shared Function CreateUnnavigable(displayText As String, ParamArray children As TestFindResult()) As TestFindResult
- Return New TestFindResult(displayText, children, expectedCanGoToDefinition:=False, expectedCanGoToReference:=False)
- End Function
-
- Private Sub New(displayText As String,
- children As TestFindResult(),
- expectedCanGoToDefinition As Boolean,
- expectedCanGoToReference As Boolean)
-
- MyBase.New(0)
- Me.DisplayText = displayText
- Me.expectedCanGoToDefinition = expectedCanGoToDefinition
- Me.expectedCanGoToReference = expectedCanGoToReference
- Me.Children = If(children IsNot Nothing AndAlso children.Length > 0, children, Nothing)
- End Sub
-
- Public Overrides Function GoToSource() As Integer
- Throw New NotImplementedException()
- End Function
- End Class
- End Class
-End Namespace
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Test/RQName/RQNameTests.vb b/src/VisualStudio/Core/Test/RQName/RQNameTests.vb
index 6dded08bdb778..207203e3817ce 100644
--- a/src/VisualStudio/Core/Test/RQName/RQNameTests.vb
+++ b/src/VisualStudio/Core/Test/RQName/RQNameTests.vb
@@ -8,7 +8,6 @@ Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.FindSymbols
Imports Microsoft.CodeAnalysis.LanguageServices
Imports Microsoft.CodeAnalysis.Shared.Extensions
-Imports Microsoft.VisualStudio.LanguageServices.Implementation.RQName
Imports Roslyn.Test.Utilities
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.RQNameTests
diff --git a/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj b/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj
index 424180bc1afea..c633ca10a6952 100644
--- a/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj
+++ b/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj
@@ -330,11 +330,11 @@
-
+
@@ -390,7 +390,7 @@
-
+
@@ -411,4 +411,4 @@
-
+
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Test/SolutionExplorer/CpsDiagnosticItemTests.vb b/src/VisualStudio/Core/Test/SolutionExplorer/CpsDiagnosticItemTests.vb
new file mode 100644
index 0000000000000..7079d83425157
--- /dev/null
+++ b/src/VisualStudio/Core/Test/SolutionExplorer/CpsDiagnosticItemTests.vb
@@ -0,0 +1,47 @@
+' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
+Imports Microsoft.VisualStudio.LanguageServices.SolutionExplorer
+Imports Roslyn.Test.Utilities
+
+Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer
+ Public Class CpsDiagnosticItemTests
+
+ Public Sub Name()
+ Dim descriptor = CreateDescriptor()
+
+ Dim diagnostic = New CpsDiagnosticItem(Nothing, descriptor, ReportDiagnostic.Error)
+
+ Assert.Equal(expected:="TST0001: A test diagnostic", actual:=diagnostic.Text)
+ End Sub
+
+
+ Public Sub BrowseObject()
+ Dim descriptor = CreateDescriptor()
+
+ Dim diagnostic = New CpsDiagnosticItem(Nothing, descriptor, ReportDiagnostic.Info)
+ Dim browseObject = DirectCast(diagnostic.GetBrowseObject(), LegacyDiagnosticItem.BrowseObject)
+
+ Assert.Equal(expected:=SolutionExplorerShim.Diagnostic_Properties, actual:=browseObject.GetClassName())
+ Assert.Equal(expected:="TST0001", actual:=browseObject.GetComponentName())
+ Assert.Equal(expected:="TST0001", actual:=browseObject.Id)
+ Assert.Equal(expected:="A test diagnostic", actual:=browseObject.Title)
+ Assert.Equal(expected:="Test", actual:=browseObject.Category)
+ Assert.Equal(expected:=SolutionExplorerShim.Error_, actual:=browseObject.DefaultSeverity)
+ Assert.Equal(expected:=SolutionExplorerShim.Info, actual:=browseObject.EffectiveSeverity)
+ Assert.Equal(expected:=True, actual:=browseObject.EnabledByDefault)
+
+ End Sub
+
+ Private Shared Function CreateDescriptor() As DiagnosticDescriptor
+ Return New DiagnosticDescriptor(
+ id:="TST0001",
+ title:="A test diagnostic",
+ messageFormat:="A test message",
+ category:="Test",
+ defaultSeverity:=DiagnosticSeverity.Error,
+ isEnabledByDefault:=True)
+ End Function
+ End Class
+End Namespace
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Test/SolutionExplorer/DiagnosticDescriptorComparerTests.vb b/src/VisualStudio/Core/Test/SolutionExplorer/DiagnosticDescriptorComparerTests.vb
index 0e476226a3113..1f3d71cba5b28 100644
--- a/src/VisualStudio/Core/Test/SolutionExplorer/DiagnosticDescriptorComparerTests.vb
+++ b/src/VisualStudio/Core/Test/SolutionExplorer/DiagnosticDescriptorComparerTests.vb
@@ -28,7 +28,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer
DiagnosticSeverity.Warning,
True)
- Dim comparer = New DiagnosticItemSource.DiagnosticDescriptorComparer()
+ Dim comparer = New LegacyDiagnosticItemSource.DiagnosticDescriptorComparer()
Dim result = comparer.Compare(x, y)
@@ -57,7 +57,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer
DiagnosticSeverity.Warning,
True)
- Dim comparer = New DiagnosticItemSource.DiagnosticDescriptorComparer()
+ Dim comparer = New LegacyDiagnosticItemSource.DiagnosticDescriptorComparer()
Dim result = comparer.Compare(x, y)
@@ -86,7 +86,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer
DiagnosticSeverity.Warning,
True)
- Dim comparer = New DiagnosticItemSource.DiagnosticDescriptorComparer()
+ Dim comparer = New LegacyDiagnosticItemSource.DiagnosticDescriptorComparer()
Dim result = comparer.Compare(x, y)
diff --git a/src/VisualStudio/Core/Test/SolutionExplorer/DiagnosticItemTests.vb b/src/VisualStudio/Core/Test/SolutionExplorer/LegacyDiagnosticItemTests.vb
similarity index 87%
rename from src/VisualStudio/Core/Test/SolutionExplorer/DiagnosticItemTests.vb
rename to src/VisualStudio/Core/Test/SolutionExplorer/LegacyDiagnosticItemTests.vb
index a4f3f4f895734..cb2feacdcd232 100644
--- a/src/VisualStudio/Core/Test/SolutionExplorer/DiagnosticItemTests.vb
+++ b/src/VisualStudio/Core/Test/SolutionExplorer/LegacyDiagnosticItemTests.vb
@@ -6,12 +6,12 @@ Imports Microsoft.VisualStudio.LanguageServices.SolutionExplorer
Imports Roslyn.Test.Utilities
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer
- Public Class DiagnosticItemTests
+ Public Class LegacyDiagnosticItemTests
Public Sub Name()
Dim descriptor = CreateDescriptor()
- Dim diagnostic = New DiagnosticItem(Nothing, descriptor, ReportDiagnostic.Error, Nothing)
+ Dim diagnostic = New LegacyDiagnosticItem(Nothing, descriptor, ReportDiagnostic.Error, Nothing)
Assert.Equal(expected:="TST0001: A test diagnostic", actual:=diagnostic.Text)
End Sub
@@ -20,8 +20,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer
Public Sub BrowseObject()
Dim descriptor = CreateDescriptor()
- Dim diagnostic = New DiagnosticItem(Nothing, descriptor, ReportDiagnostic.Info, Nothing)
- Dim browseObject = DirectCast(diagnostic.GetBrowseObject(), DiagnosticItem.BrowseObject)
+ Dim diagnostic = New LegacyDiagnosticItem(Nothing, descriptor, ReportDiagnostic.Info, Nothing)
+ Dim browseObject = DirectCast(diagnostic.GetBrowseObject(), LegacyDiagnosticItem.BrowseObject)
Assert.Equal(expected:=SolutionExplorerShim.Diagnostic_Properties, actual:=browseObject.GetClassName())
Assert.Equal(expected:="TST0001", actual:=browseObject.GetComponentName())
diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpErrorListDesktop.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpErrorListDesktop.cs
index 5bd39a22d0bfb..878bc37e995dd 100644
--- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpErrorListDesktop.cs
+++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpErrorListDesktop.cs
@@ -14,13 +14,13 @@ public CSharpErrorListDesktop(VisualStudioInstanceFactory instanceFactory)
{
}
- [Fact, Trait(Traits.Feature, Traits.Features.ErrorList)]
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/18996"), Trait(Traits.Feature, Traits.Features.ErrorList)]
public override void ErrorList()
{
base.ErrorList();
}
- [Fact, Trait(Traits.Feature, Traits.Features.ErrorList)]
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/18996"), Trait(Traits.Feature, Traits.Features.ErrorList)]
public override void ErrorLevelWarning()
{
base.ErrorLevelWarning();
diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpErrorListNetCore.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpErrorListNetCore.cs
index 1371a46315f66..8ffd84a7d2920 100644
--- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpErrorListNetCore.cs
+++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpErrorListNetCore.cs
@@ -14,21 +14,21 @@ public CSharpErrorListNetCore(VisualStudioInstanceFactory instanceFactory)
{
}
- [Fact, Trait(Traits.Feature, Traits.Features.ErrorList)]
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/18996"), Trait(Traits.Feature, Traits.Features.ErrorList)]
[Trait(Traits.Feature, Traits.Features.NetCore)]
public override void ErrorList()
{
base.ErrorList();
}
- [Fact, Trait(Traits.Feature, Traits.Features.ErrorList)]
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/18996"), Trait(Traits.Feature, Traits.Features.ErrorList)]
[Trait(Traits.Feature, Traits.Features.NetCore)]
public override void ErrorLevelWarning()
{
base.ErrorLevelWarning();
}
- [Fact, Trait(Traits.Feature, Traits.Features.ErrorList)]
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/19090"), Trait(Traits.Feature, Traits.Features.ErrorList)]
[Trait(Traits.Feature, Traits.Features.NetCore)]
public override void ErrorsDuringMethodBodyEditing()
{
diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpReferenceHighlighting.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpReferenceHighlighting.cs
index e216ac66345ab..627ac96efc079 100644
--- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpReferenceHighlighting.cs
+++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpReferenceHighlighting.cs
@@ -42,7 +42,7 @@ void M({|reference:C|} c) where T : {|reference:C|}
VerifyNone("void");
}
- [Fact, Trait(Traits.Feature, Traits.Features.Classification)]
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/19059"), Trait(Traits.Feature, Traits.Features.Classification)]
public void WrittenReference()
{
var markup = @"
diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSquigglesDesktop.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSquigglesDesktop.cs
index 17d9a55f72187..7fcf1ebdf63cc 100644
--- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSquigglesDesktop.cs
+++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSquigglesDesktop.cs
@@ -14,13 +14,13 @@ public CSharpSquigglesDesktop(VisualStudioInstanceFactory instanceFactory)
{
}
- [Fact, Trait(Traits.Feature, Traits.Features.ErrorSquiggles)]
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/19091"), Trait(Traits.Feature, Traits.Features.ErrorSquiggles)]
public override void VerifySyntaxErrorSquiggles()
{
base.VerifySyntaxErrorSquiggles();
}
- [Fact, Trait(Traits.Feature, Traits.Features.ErrorSquiggles)]
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/19091"), Trait(Traits.Feature, Traits.Features.ErrorSquiggles)]
public override void VerifySemanticErrorSquiggles()
{
base.VerifySemanticErrorSquiggles();
diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSquigglesNetCore.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSquigglesNetCore.cs
index cd16ac8f71e41..c6433cf144455 100644
--- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSquigglesNetCore.cs
+++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpSquigglesNetCore.cs
@@ -14,14 +14,14 @@ public CSharpSquigglesNetCore(VisualStudioInstanceFactory instanceFactory)
{
}
- [Fact, Trait(Traits.Feature, Traits.Features.ErrorSquiggles)]
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/19091"), Trait(Traits.Feature, Traits.Features.ErrorSquiggles)]
[Trait(Traits.Feature, Traits.Features.NetCore)]
public override void VerifySyntaxErrorSquiggles()
{
base.VerifySyntaxErrorSquiggles();
}
- [Fact, Trait(Traits.Feature, Traits.Features.ErrorSquiggles)]
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/19091"), Trait(Traits.Feature, Traits.Features.ErrorSquiggles)]
[Trait(Traits.Feature, Traits.Features.NetCore)]
public override void VerifySemanticErrorSquiggles()
{
diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicReferenceHighlighting.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicReferenceHighlighting.cs
index 4520ab6b597c7..873349a13f999 100644
--- a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicReferenceHighlighting.cs
+++ b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicReferenceHighlighting.cs
@@ -23,7 +23,7 @@ public BasicReferenceHighlighting(VisualStudioInstanceFactory instanceFactory)
{
}
- [Fact, Trait(Traits.Feature, Traits.Features.Classification)]
+ [Fact(Skip = "https://github.com/dotnet/roslyn/issues/19059"), Trait(Traits.Feature, Traits.Features.Classification)]
public void Highlighting()
{
var markup = @"
diff --git a/src/VisualStudio/Setup/VisualStudioSetup.csproj b/src/VisualStudio/Setup/VisualStudioSetup.csproj
index 5a8925bd3a291..2b25b62b8c861 100644
--- a/src/VisualStudio/Setup/VisualStudioSetup.csproj
+++ b/src/VisualStudio/Setup/VisualStudioSetup.csproj
@@ -229,10 +229,6 @@
true
-
-
-
-
diff --git a/src/VisualStudio/Setup/source.extension.vsixmanifest b/src/VisualStudio/Setup/source.extension.vsixmanifest
index 98e129d348282..ddc6459c06620 100644
--- a/src/VisualStudio/Setup/source.extension.vsixmanifest
+++ b/src/VisualStudio/Setup/source.extension.vsixmanifest
@@ -48,5 +48,6 @@
+
diff --git a/src/VisualStudio/TestUtilities2/CodeModel/CodeModelTestHelpers.vb b/src/VisualStudio/TestUtilities2/CodeModel/CodeModelTestHelpers.vb
index c4f6e3dab0789..4d28c153ae193 100644
--- a/src/VisualStudio/TestUtilities2/CodeModel/CodeModelTestHelpers.vb
+++ b/src/VisualStudio/TestUtilities2/CodeModel/CodeModelTestHelpers.vb
@@ -54,8 +54,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.CodeModel
project.LanguageServices,
mockVisualStudioWorkspace)
- Dim editorOptionsFactoryService = workspace.GetService(Of IEditorOptionsFactoryService)()
- Dim mockTextManagerAdapter = New MockTextManagerAdapter(editorOptionsFactoryService)
+ Dim mockTextManagerAdapter = New MockTextManagerAdapter()
For Each documentId In project.DocumentIds
' Note that a parent is not specified below. In Visual Studio, this would normally be an EnvDTE.Project instance.
diff --git a/src/VisualStudio/TestUtilities2/CodeModel/Mocks/MockTextManagerAdapter.vb b/src/VisualStudio/TestUtilities2/CodeModel/Mocks/MockTextManagerAdapter.vb
index bf620aaaa75f3..c2eb2e15cc620 100644
--- a/src/VisualStudio/TestUtilities2/CodeModel/Mocks/MockTextManagerAdapter.vb
+++ b/src/VisualStudio/TestUtilities2/CodeModel/Mocks/MockTextManagerAdapter.vb
@@ -1,7 +1,9 @@
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+Imports System.Threading
Imports Microsoft.CodeAnalysis.Editor
Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities
+Imports Microsoft.CodeAnalysis.Formatting
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel
Imports Microsoft.VisualStudio.Text.Editor
@@ -11,16 +13,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.CodeModel.Mocks
Friend NotInheritable Class MockTextManagerAdapter
Implements ITextManagerAdapter
- Private ReadOnly _editorOptionsFactoryService As IEditorOptionsFactoryService
-
- Public Sub New(editorOptionsFactoryService As IEditorOptionsFactoryService)
- _editorOptionsFactoryService = editorOptionsFactoryService
- End Sub
-
Public Function CreateTextPoint(fileCodeModel As FileCodeModel, point As VirtualTreePoint) As EnvDTE.TextPoint Implements ITextManagerAdapter.CreateTextPoint
- Dim textBuffer = point.Text.Container.TryGetTextBuffer()
- Dim tabSize = _editorOptionsFactoryService.GetOptions(textBuffer).GetTabSize()
- Return New MockTextPoint(point, tabSize)
+ Dim options = fileCodeModel.GetDocument().GetOptionsAsync().WaitAndGetResult_CodeModel(CancellationToken.None)
+ Return New MockTextPoint(point, options.GetOption(FormattingOptions.TabSize))
End Function
End Class
End Namespace
diff --git a/src/VisualStudio/TestUtilities2/MockVisualStudioWorkspace.vb b/src/VisualStudio/TestUtilities2/MockVisualStudioWorkspace.vb
index 59132086d23bb..a8b179fdc8556 100644
--- a/src/VisualStudio/TestUtilities2/MockVisualStudioWorkspace.vb
+++ b/src/VisualStudio/TestUtilities2/MockVisualStudioWorkspace.vb
@@ -96,10 +96,16 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests
Private ReadOnly _documentId As DocumentId
Private ReadOnly _workspace As TestWorkspace
+ Private ReadOnly _needsClose As Boolean = False
Public Sub New(documentId As DocumentId, workspace As TestWorkspace)
Me._documentId = documentId
Me._workspace = workspace
+
+ If Not workspace.IsDocumentOpen(documentId) Then
+ _workspace.OpenDocument(documentId)
+ _needsClose = True
+ End If
End Sub
Public ReadOnly Property TextBuffer As Global.Microsoft.VisualStudio.Text.ITextBuffer Implements IInvisibleEditor.TextBuffer
@@ -109,6 +115,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests
End Property
Public Sub Dispose() Implements IDisposable.Dispose
+ If _needsClose Then
+ _workspace.CloseDocument(_documentId)
+ End If
End Sub
End Class
diff --git a/src/VisualStudio/TestUtilities2/ProjectSystemShim/Framework/HierarchyItemMapper.vb b/src/VisualStudio/TestUtilities2/ProjectSystemShim/Framework/HierarchyItemMapper.vb
index 9692c4eb56bf5..87b608b1d7b51 100644
--- a/src/VisualStudio/TestUtilities2/ProjectSystemShim/Framework/HierarchyItemMapper.vb
+++ b/src/VisualStudio/TestUtilities2/ProjectSystemShim/Framework/HierarchyItemMapper.vb
@@ -15,7 +15,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Fr
_tracker = projectTracker
End Sub
- Public Function TryGetProjectId(hierarchyItem As IVsHierarchyItem, ByRef projectId As ProjectId) As Boolean Implements IHierarchyItemToProjectIdMap.TryGetProjectId
+ Public Function TryGetProjectId(hierarchyItem As IVsHierarchyItem, targetFrameworkMoniker As String, ByRef projectId As ProjectId) As Boolean Implements IHierarchyItemToProjectIdMap.TryGetProjectId
Dim project = _tracker.ImmutableProjects.
Where(Function(p) p.Hierarchy Is hierarchyItem.HierarchyIdentity.NestedHierarchy).
diff --git a/src/VisualStudio/VisualBasic/Impl/BasicVisualStudio.vbproj b/src/VisualStudio/VisualBasic/Impl/BasicVisualStudio.vbproj
index 9ae4c31d69633..af5790efab505 100644
--- a/src/VisualStudio/VisualBasic/Impl/BasicVisualStudio.vbproj
+++ b/src/VisualStudio/VisualBasic/Impl/BasicVisualStudio.vbproj
@@ -134,6 +134,7 @@
+
diff --git a/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.NodeLocator.vb b/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.NodeLocator.vb
index 135462120e65b..8d4c88a085a10 100644
--- a/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.NodeLocator.vb
+++ b/src/VisualStudio/VisualBasic/Impl/CodeModel/VisualBasicCodeModelService.NodeLocator.vb
@@ -3,6 +3,7 @@
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities
+Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Extensions
@@ -13,15 +14,17 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
Partial Friend Class VisualBasicCodeModelService
Protected Overrides Function CreateNodeLocator() As AbstractNodeLocator
- Return New NodeLocator(Me)
+ Return New NodeLocator()
End Function
Private Class NodeLocator
Inherits AbstractNodeLocator
- Public Sub New(codeModelService As VisualBasicCodeModelService)
- MyBase.New(codeModelService)
- End Sub
+ Protected Overrides ReadOnly Property LanguageName As String
+ Get
+ Return LanguageNames.VisualBasic
+ End Get
+ End Property
Protected Overrides ReadOnly Property DefaultPart As EnvDTE.vsCMPart
Get
@@ -29,22 +32,22 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
End Get
End Property
- Protected Overrides Function GetStartPoint(text As SourceText, node As SyntaxNode, part As EnvDTE.vsCMPart) As VirtualTreePoint?
+ Protected Overrides Function GetStartPoint(text As SourceText, options As OptionSet, node As SyntaxNode, part As EnvDTE.vsCMPart) As VirtualTreePoint?
Select Case node.Kind
Case SyntaxKind.ClassBlock,
SyntaxKind.InterfaceBlock,
SyntaxKind.ModuleBlock,
SyntaxKind.StructureBlock
- Return GetTypeBlockStartPoint(text, DirectCast(node, TypeBlockSyntax), part)
+ Return GetTypeBlockStartPoint(text, options, DirectCast(node, TypeBlockSyntax), part)
Case SyntaxKind.EnumBlock
- Return GetEnumBlockStartPoint(text, DirectCast(node, EnumBlockSyntax), part)
+ Return GetEnumBlockStartPoint(text, options, DirectCast(node, EnumBlockSyntax), part)
Case SyntaxKind.ClassStatement,
SyntaxKind.InterfaceStatement,
SyntaxKind.ModuleStatement,
SyntaxKind.StructureStatement
- Return GetTypeBlockStartPoint(text, DirectCast(node.Parent, TypeBlockSyntax), part)
+ Return GetTypeBlockStartPoint(text, options, DirectCast(node.Parent, TypeBlockSyntax), part)
Case SyntaxKind.EnumStatement
- Return GetEnumBlockStartPoint(text, DirectCast(node.Parent, EnumBlockSyntax), part)
+ Return GetEnumBlockStartPoint(text, options, DirectCast(node.Parent, EnumBlockSyntax), part)
Case SyntaxKind.ConstructorBlock,
SyntaxKind.FunctionBlock,
SyntaxKind.OperatorBlock,
@@ -54,7 +57,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
SyntaxKind.AddHandlerAccessorBlock,
SyntaxKind.RemoveHandlerAccessorBlock,
SyntaxKind.RaiseEventAccessorBlock
- Return GetMethodBlockStartPoint(text, DirectCast(node, MethodBlockBaseSyntax), part)
+ Return GetMethodBlockStartPoint(text, options, DirectCast(node, MethodBlockBaseSyntax), part)
Case SyntaxKind.SubNewStatement,
SyntaxKind.OperatorStatement,
SyntaxKind.GetAccessorStatement,
@@ -62,11 +65,11 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
SyntaxKind.AddHandlerStatement,
SyntaxKind.RemoveHandlerStatement,
SyntaxKind.RaiseEventStatement
- Return GetMethodBlockStartPoint(text, DirectCast(node.Parent, MethodBlockBaseSyntax), part)
+ Return GetMethodBlockStartPoint(text, options, DirectCast(node.Parent, MethodBlockBaseSyntax), part)
Case SyntaxKind.FunctionStatement,
SyntaxKind.SubStatement
If TypeOf node.Parent Is MethodBlockBaseSyntax Then
- Return GetMethodBlockStartPoint(text, DirectCast(node.Parent, MethodBlockBaseSyntax), part)
+ Return GetMethodBlockStartPoint(text, options, DirectCast(node.Parent, MethodBlockBaseSyntax), part)
Else
Return GetMethodStatementStartPoint(text, DirectCast(node, MethodStatementSyntax), part)
End If
@@ -80,7 +83,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
Return GetPropertyStatementStartPoint(text, DirectCast(node, PropertyStatementSyntax), part)
Case SyntaxKind.EventBlock
- Return GetEventBlockStartPoint(text, DirectCast(node, EventBlockSyntax), part)
+ Return GetEventBlockStartPoint(text, options, DirectCast(node, EventBlockSyntax), part)
Case SyntaxKind.EventStatement
Return GetEventStatementStartPoint(text, DirectCast(node, EventStatementSyntax), part)
@@ -89,9 +92,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
Return GetDelegateStatementStartPoint(text, DirectCast(node, DelegateStatementSyntax), part)
Case SyntaxKind.NamespaceBlock
- Return GetNamespaceBlockStartPoint(text, DirectCast(node, NamespaceBlockSyntax), part)
+ Return GetNamespaceBlockStartPoint(text, options, DirectCast(node, NamespaceBlockSyntax), part)
Case SyntaxKind.NamespaceStatement
- Return GetNamespaceBlockStartPoint(text, DirectCast(node.Parent, NamespaceBlockSyntax), part)
+ Return GetNamespaceBlockStartPoint(text, options, DirectCast(node.Parent, NamespaceBlockSyntax), part)
Case SyntaxKind.ModifiedIdentifier
Return GetVariableStartPoint(text, DirectCast(node, ModifiedIdentifierSyntax), part)
Case SyntaxKind.EnumMemberDeclaration
@@ -119,7 +122,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
End Select
End Function
- Protected Overrides Function GetEndPoint(text As SourceText, node As SyntaxNode, part As EnvDTE.vsCMPart) As VirtualTreePoint?
+ Protected Overrides Function GetEndPoint(text As SourceText, options As OptionSet, node As SyntaxNode, part As EnvDTE.vsCMPart) As VirtualTreePoint?
Select Case node.Kind
Case SyntaxKind.ClassBlock,
SyntaxKind.InterfaceBlock,
@@ -291,7 +294,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
End If
End Function
- Private Function GetTypeBlockStartPoint(text As SourceText, typeBlock As TypeBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
+ Private Function GetTypeBlockStartPoint(text As SourceText, options As OptionSet, typeBlock As TypeBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
Dim startPosition As Integer
Select Case part
@@ -341,7 +344,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
End If
If part = EnvDTE.vsCMPart.vsCMPartNavigate Then
- Return NavigationPointHelpers.GetNavigationPoint(text, GetTabSize(text), typeBlock.BlockStatement, typeBlock.EndBlockStatement, statementLine.LineNumber + 1)
+ Return NavigationPointHelpers.GetNavigationPoint(text, GetTabSize(options), typeBlock.BlockStatement, typeBlock.EndBlockStatement, statementLine.LineNumber + 1)
End If
Case Else
@@ -377,7 +380,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
Return New VirtualTreePoint(typeBlock.SyntaxTree, text, startPosition)
End Function
- Private Function GetEnumBlockStartPoint(text As SourceText, enumBlock As EnumBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
+ Private Function GetEnumBlockStartPoint(text As SourceText, options As OptionSet, enumBlock As EnumBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
Dim startPosition As Integer
Select Case part
@@ -412,7 +415,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
End If
If part = EnvDTE.vsCMPart.vsCMPartNavigate Then
- Return NavigationPointHelpers.GetNavigationPoint(text, GetTabSize(text), enumBlock.EnumStatement, enumBlock.EndEnumStatement, statementLine.LineNumber + 1)
+ Return NavigationPointHelpers.GetNavigationPoint(text, GetTabSize(options), enumBlock.EnumStatement, enumBlock.EndEnumStatement, statementLine.LineNumber + 1)
End If
Case Else
@@ -448,7 +451,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
Return New VirtualTreePoint(enumBlock.SyntaxTree, text, startPosition)
End Function
- Private Function GetMethodBlockStartPoint(text As SourceText, methodBlock As MethodBlockBaseSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
+ Private Function GetMethodBlockStartPoint(text As SourceText, options As OptionSet, methodBlock As MethodBlockBaseSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
Dim startPosition As Integer
Select Case part
@@ -479,7 +482,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
Throw Exceptions.ThrowEFail()
End If
- Return GetEventBlockStartPoint(text, eventBlock, part)
+ Return GetEventBlockStartPoint(text, options, eventBlock, part)
Case Else
Throw Exceptions.ThrowEFail()
End Select
@@ -493,7 +496,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
EnvDTE.vsCMPart.vsCMPartWhole
startPosition = NavigationPointHelpers.GetHeaderStartPosition(methodBlock)
Case EnvDTE.vsCMPart.vsCMPartNavigate
- Return NavigationPointHelpers.GetNavigationPoint(text, GetTabSize(text), methodBlock)
+ Return NavigationPointHelpers.GetNavigationPoint(text, GetTabSize(options), methodBlock)
Case EnvDTE.vsCMPart.vsCMPartBody,
EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
@@ -777,7 +780,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
Return New VirtualTreePoint(propertyStatement.SyntaxTree, text, startPosition)
End Function
- Private Function GetEventBlockStartPoint(text As SourceText, eventBlock As EventBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
+ Private Function GetEventBlockStartPoint(text As SourceText, options As OptionSet, eventBlock As EventBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
Dim startPosition As Integer
Select Case part
@@ -802,7 +805,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
Case EnvDTE.vsCMPart.vsCMPartNavigate
- Return NavigationPointHelpers.GetNavigationPoint(text, GetTabSize(text), eventBlock)
+ Return NavigationPointHelpers.GetNavigationPoint(text, GetTabSize(options), eventBlock)
Case EnvDTE.vsCMPart.vsCMPartBody,
EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
@@ -974,7 +977,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
.FirstOrNullable(Function(t) t.Kind = SyntaxKind.ColonTrivia)
End Function
- Private Function GetNamespaceBlockStartPoint(text As SourceText, namespaceBlock As NamespaceBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
+ Private Function GetNamespaceBlockStartPoint(text As SourceText, options As OptionSet, namespaceBlock As NamespaceBlockSyntax, part As EnvDTE.vsCMPart) As VirtualTreePoint?
Dim startPosition As Integer
Select Case part
@@ -1003,7 +1006,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.CodeModel
lineNumber = text.Lines.IndexOf(colonTrivia.Value.SpanStart)
End If
- Return NavigationPointHelpers.GetNavigationPoint(text, GetTabSize(text), namespaceBlock.NamespaceStatement, namespaceBlock.EndNamespaceStatement, lineNumber)
+ Return NavigationPointHelpers.GetNavigationPoint(text, GetTabSize(options), namespaceBlock.NamespaceStatement, namespaceBlock.EndNamespaceStatement, lineNumber)
Case EnvDTE.vsCMPart.vsCMPartBody,
EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter
diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml
index e983f378c28f9..0a2d5fe43a8df 100644
--- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml
+++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml
@@ -110,6 +110,16 @@
x:Name="at_the_end"
Content="{x:Static local:AdvancedOptionPageStrings.Option_at_the_end}"/>
+
+
+
+
+
+
diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb
index 6e069fc4a3647..5f210c872d6c3 100644
--- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb
+++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb
@@ -45,6 +45,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
BindToOption(with_other_members_of_the_same_kind, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind, LanguageNames.VisualBasic)
BindToOption(at_the_end, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.AtTheEnd, LanguageNames.VisualBasic)
+
+ BindToOption(prefer_throwing_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferThrowingProperties, LanguageNames.VisualBasic)
+ BindToOption(prefer_auto_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties, LanguageNames.VisualBasic)
End Sub
End Class
End Namespace
\ No newline at end of file
diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb
index 21e2639bdd9ba..6443bafbed7cd 100644
--- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb
+++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb
@@ -84,6 +84,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
Public ReadOnly Property Option_with_other_members_of_the_same_kind As String =
ServicesVSResources.with_other_members_of_the_same_kind
+ Public ReadOnly Property Option_When_generating_properties As String =
+ ServicesVSResources.When_generating_properties
+
+ Public ReadOnly Property Option_prefer_auto_properties As String =
+ ServicesVSResources.prefer_auto_properties
+
+ Public ReadOnly Property Option_prefer_throwing_properties As String =
+ ServicesVSResources.prefer_throwing_properties
+
Public ReadOnly Property Option_at_the_end As String =
ServicesVSResources.at_the_end
diff --git a/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicEntryPointFinderService.vb b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicEntryPointFinderService.vb
new file mode 100644
index 0000000000000..61475edf37540
--- /dev/null
+++ b/src/VisualStudio/VisualBasic/Impl/ProjectSystemShim/VisualBasicEntryPointFinderService.vb
@@ -0,0 +1,17 @@
+' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+Imports System.Composition
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Host.Mef
+Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
+
+Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ProjectSystemShim
+
+ Friend Class VisualBasicEntryPointFinderService
+ Implements IEntryPointFinderService
+
+ Public Function FindEntryPoints(symbol As INamespaceSymbol, findFormsOnly As Boolean) As IEnumerable(Of INamedTypeSymbol) Implements IEntryPointFinderService.FindEntryPoints
+ Return EntryPointFinder.FindEntryPoints(symbol, findFormsOnly)
+ End Function
+ End Class
+End Namespace
diff --git a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb
index 075e38b9c523d..5ca1427f13152 100644
--- a/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb
+++ b/src/VisualStudio/VisualBasic/Impl/Snippets/SnippetCompletionProvider.vb
@@ -52,10 +52,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets
Dim syntaxFacts = document.GetLanguageService(Of ISyntaxFactsService)()
Dim isPossibleTupleContext = syntaxFacts.IsPossibleTupleContext(syntaxTree, position, cancellationToken)
- context.IsExclusive = True
+ context.IsExclusive = ShouldBeExclusive(context.Options)
context.AddItems(CreateCompletionItems(snippets, isPossibleTupleContext))
End Function
+ Private Function ShouldBeExclusive(options As OptionSet) As Boolean
+ Return options.GetOption(CompletionOptions.SnippetsBehavior, LanguageNames.VisualBasic) = SnippetsRule.IncludeAfterTypingIdentifierQuestionTab
+ End Function
+
Private Shared ReadOnly s_commitChars As Char() = {" "c, ";"c, "("c, ")"c, "["c, "]"c, "{"c, "}"c, "."c, ","c, ":"c, "+"c, "-"c, "*"c, "/"c, "\"c, "^"c, "<"c, ">"c, "'"c, "="c}
Private Shared ReadOnly s_rules As CompletionItemRules = CompletionItemRules.Create(
commitCharacterRules:=ImmutableArray.Create(CharacterSetModificationRule.Create(CharacterSetModificationKind.Replace, s_commitChars)))
diff --git a/src/Workspaces/CSharp/Portable/CSharpWorkspace.csproj b/src/Workspaces/CSharp/Portable/CSharpWorkspace.csproj
index cab0a9ad932a2..2f65b502395b8 100644
--- a/src/Workspaces/CSharp/Portable/CSharpWorkspace.csproj
+++ b/src/Workspaces/CSharp/Portable/CSharpWorkspace.csproj
@@ -212,6 +212,8 @@
+
+
diff --git a/src/Workspaces/CSharp/Portable/Classification/Classifiers/NameSyntaxClassifier.cs b/src/Workspaces/CSharp/Portable/Classification/Classifiers/NameSyntaxClassifier.cs
index b1acceab1d169..7c9f466ebf499 100644
--- a/src/Workspaces/CSharp/Portable/Classification/Classifiers/NameSyntaxClassifier.cs
+++ b/src/Workspaces/CSharp/Portable/Classification/Classifiers/NameSyntaxClassifier.cs
@@ -180,8 +180,9 @@ private bool IsInVarContext(NameSyntax name)
{
return
name.CheckParent(v => v.Type == name) ||
- name.CheckParent(v => v.Type == name) ||
name.CheckParent(f => f.Type == name) ||
+ name.CheckParent(v => v.Type == name) ||
+ name.CheckParent(v => v.Type == name) ||
name.CheckParent(f => f.Type == name);
}
@@ -308,4 +309,4 @@ private bool IsSymbolCalledVar(ISymbol symbol)
return symbol != null && symbol.Name == "var";
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/CSharpSyntaxContext.cs b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/CSharpSyntaxContext.cs
index d8b921b8a0f38..9a76d032db288 100644
--- a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/CSharpSyntaxContext.cs
+++ b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/CSharpSyntaxContext.cs
@@ -98,13 +98,15 @@ private CSharpSyntaxContext(
bool isCatchFilterContext,
bool isDestructorTypeContext,
bool isPossibleTupleContext,
+ bool isPatternContext,
CancellationToken cancellationToken)
: base(workspace, semanticModel, position, leftToken, targetToken,
isTypeContext, isNamespaceContext, isNamespaceDeclarationNameContext,
isPreProcessorDirectiveContext,
isRightOfDotOrArrowOrColonColon, isStatementContext, isAnyExpressionContext,
isAttributeNameContext, isEnumTypeMemberAccessContext, isNameOfContext,
- isInQuery, isInImportsDirective, IsWithinAsyncMethod(), isPossibleTupleContext, cancellationToken)
+ isInQuery, isInImportsDirective, IsWithinAsyncMethod(), isPossibleTupleContext,
+ isPatternContext, cancellationToken)
{
this.ContainingTypeDeclaration = containingTypeDeclaration;
this.ContainingTypeOrEnumDeclaration = containingTypeOrEnumDeclaration;
@@ -242,6 +244,7 @@ private static CSharpSyntaxContext CreateContextWorker(Workspace workspace, Sema
syntaxTree.IsCatchFilterContext(position, leftToken),
isDestructorTypeContext,
syntaxTree.IsPossibleTupleContext(leftToken, position),
+ syntaxTree.IsPatternContext(leftToken, position),
cancellationToken);
}
diff --git a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs
index 14830f106f979..51cab85594def 100644
--- a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs
+++ b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs
@@ -1260,6 +1260,20 @@ public static bool IsPossibleTupleContext(this SyntaxTree syntaxTree, SyntaxToke
return false;
}
+ public static bool IsPatternContext(this SyntaxTree syntaxTree, SyntaxToken leftToken, int position)
+ {
+ leftToken = leftToken.GetPreviousTokenIfTouchingWord(position);
+
+ // case $$
+ // is $$
+ if (leftToken.IsKind(SyntaxKind.CaseKeyword, SyntaxKind.IsKeyword))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
private static SyntaxToken FindTokenOnLeftOfNode(SyntaxNode node)
{
return node.FindTokenOnLeftOfPosition(node.SpanStart);
diff --git a/src/Workspaces/CSharp/Portable/Extensions/ParenthesizedExpressionSyntaxExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ParenthesizedExpressionSyntaxExtensions.cs
index 5ba94870b5ec7..14966876a0292 100644
--- a/src/Workspaces/CSharp/Portable/Extensions/ParenthesizedExpressionSyntaxExtensions.cs
+++ b/src/Workspaces/CSharp/Portable/Extensions/ParenthesizedExpressionSyntaxExtensions.cs
@@ -115,6 +115,21 @@ public static bool CanRemoveParentheses(this ParenthesizedExpressionSyntax node,
return true;
}
+ // Cases:
+ // new {(x)} -> {x}
+ // new { a = (x)} -> { a = x }
+ // new { a = (x = c)} -> { a = x = c }
+ if (node.Parent is AnonymousObjectMemberDeclaratorSyntax anonymousDeclarator)
+ {
+ // Assignment expressions are not allowed unless member is named
+ if (anonymousDeclarator.NameEquals == null && expression.IsAnyAssignExpression())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
// Cases:
// where (x + 1 > 14) -> where x + 1 > 14
if (node.Parent is QueryClauseSyntax)
diff --git a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
index 0940df6dd281a..4c9b26d2b7c66 100644
--- a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
+++ b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs
@@ -776,99 +776,129 @@ public bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo dec
{
case SyntaxKind.ClassDeclaration:
var classDecl = (ClassDeclarationSyntax)node;
- declaredSymbolInfo = new DeclaredSymbolInfo(classDecl.Identifier.ValueText,
+ declaredSymbolInfo = new DeclaredSymbolInfo(
+ classDecl.Identifier.ValueText,
+ GetTypeParameterSuffix(classDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Class, classDecl.Identifier.Span,
+ DeclaredSymbolInfoKind.Class,
+ GetAccessibility(classDecl, classDecl.Modifiers),
+ classDecl.Identifier.Span,
GetInheritanceNames(classDecl.BaseList));
return true;
case SyntaxKind.ConstructorDeclaration:
var ctorDecl = (ConstructorDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
ctorDecl.Identifier.ValueText,
+ GetConstructorSuffix(ctorDecl),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Constructor,
+ GetAccessibility(ctorDecl, ctorDecl.Modifiers),
ctorDecl.Identifier.Span,
inheritanceNames: ImmutableArray.Empty,
- parameterCount: (ushort)(ctorDecl.ParameterList?.Parameters.Count ?? 0));
+ parameterCount: ctorDecl.ParameterList?.Parameters.Count ?? 0);
return true;
case SyntaxKind.DelegateDeclaration:
var delegateDecl = (DelegateDeclarationSyntax)node;
- declaredSymbolInfo = new DeclaredSymbolInfo(delegateDecl.Identifier.ValueText,
+ declaredSymbolInfo = new DeclaredSymbolInfo(
+ delegateDecl.Identifier.ValueText,
+ GetTypeParameterSuffix(delegateDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Delegate, delegateDecl.Identifier.Span,
+ DeclaredSymbolInfoKind.Delegate,
+ GetAccessibility(delegateDecl, delegateDecl.Modifiers),
+ delegateDecl.Identifier.Span,
inheritanceNames: ImmutableArray.Empty);
return true;
case SyntaxKind.EnumDeclaration:
var enumDecl = (EnumDeclarationSyntax)node;
- declaredSymbolInfo = new DeclaredSymbolInfo(enumDecl.Identifier.ValueText,
+ declaredSymbolInfo = new DeclaredSymbolInfo(
+ enumDecl.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Enum, enumDecl.Identifier.Span,
+ DeclaredSymbolInfoKind.Enum,
+ GetAccessibility(enumDecl, enumDecl.Modifiers),
+ enumDecl.Identifier.Span,
inheritanceNames: ImmutableArray.Empty);
return true;
case SyntaxKind.EnumMemberDeclaration:
var enumMember = (EnumMemberDeclarationSyntax)node;
- declaredSymbolInfo = new DeclaredSymbolInfo(enumMember.Identifier.ValueText,
+ declaredSymbolInfo = new DeclaredSymbolInfo(
+ enumMember.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.EnumMember, enumMember.Identifier.Span,
+ DeclaredSymbolInfoKind.EnumMember,
+ Accessibility.Public,
+ enumMember.Identifier.Span,
inheritanceNames: ImmutableArray.Empty);
return true;
case SyntaxKind.EventDeclaration:
var eventDecl = (EventDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
- ExpandExplicitInterfaceName(eventDecl.Identifier.ValueText, eventDecl.ExplicitInterfaceSpecifier),
+ eventDecl.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Event, eventDecl.Identifier.Span,
+ DeclaredSymbolInfoKind.Event,
+ GetAccessibility(eventDecl, eventDecl.Modifiers),
+ eventDecl.Identifier.Span,
inheritanceNames: ImmutableArray.Empty);
return true;
case SyntaxKind.IndexerDeclaration:
var indexerDecl = (IndexerDeclarationSyntax)node;
- declaredSymbolInfo = new DeclaredSymbolInfo(WellKnownMemberNames.Indexer,
+ declaredSymbolInfo = new DeclaredSymbolInfo(
+ "this", GetIndexerSuffix(indexerDecl),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Indexer, indexerDecl.ThisKeyword.Span,
+ DeclaredSymbolInfoKind.Indexer,
+ GetAccessibility(indexerDecl, indexerDecl.Modifiers),
+ indexerDecl.ThisKeyword.Span,
inheritanceNames: ImmutableArray.Empty);
return true;
case SyntaxKind.InterfaceDeclaration:
var interfaceDecl = (InterfaceDeclarationSyntax)node;
- declaredSymbolInfo = new DeclaredSymbolInfo(interfaceDecl.Identifier.ValueText,
+ declaredSymbolInfo = new DeclaredSymbolInfo(
+ interfaceDecl.Identifier.ValueText, GetTypeParameterSuffix(interfaceDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Interface, interfaceDecl.Identifier.Span,
+ DeclaredSymbolInfoKind.Interface,
+ GetAccessibility(interfaceDecl, interfaceDecl.Modifiers),
+ interfaceDecl.Identifier.Span,
GetInheritanceNames(interfaceDecl.BaseList));
return true;
case SyntaxKind.MethodDeclaration:
var method = (MethodDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
- ExpandExplicitInterfaceName(method.Identifier.ValueText, method.ExplicitInterfaceSpecifier),
+ method.Identifier.ValueText, GetMethodSuffix(method),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Method,
+ IsExtensionMethod(method) ? DeclaredSymbolInfoKind.ExtensionMethod : DeclaredSymbolInfoKind.Method,
+ GetAccessibility(method, method.Modifiers),
method.Identifier.Span,
inheritanceNames: ImmutableArray.Empty,
- parameterCount: (ushort)(method.ParameterList?.Parameters.Count ?? 0),
- typeParameterCount: (ushort)(method.TypeParameterList?.Parameters.Count ?? 0));
+ parameterCount: method.ParameterList?.Parameters.Count ?? 0,
+ typeParameterCount: method.TypeParameterList?.Parameters.Count ?? 0);
return true;
case SyntaxKind.PropertyDeclaration:
var property = (PropertyDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
- ExpandExplicitInterfaceName(property.Identifier.ValueText, property.ExplicitInterfaceSpecifier),
+ property.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Property, property.Identifier.Span,
+ DeclaredSymbolInfoKind.Property,
+ GetAccessibility(property, property.Modifiers),
+ property.Identifier.Span,
inheritanceNames: ImmutableArray.Empty);
return true;
case SyntaxKind.StructDeclaration:
var structDecl = (StructDeclarationSyntax)node;
- declaredSymbolInfo = new DeclaredSymbolInfo(structDecl.Identifier.ValueText,
+ declaredSymbolInfo = new DeclaredSymbolInfo(
+ structDecl.Identifier.ValueText, GetTypeParameterSuffix(structDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Struct, structDecl.Identifier.Span,
+ DeclaredSymbolInfoKind.Struct,
+ GetAccessibility(structDecl, structDecl.Modifiers),
+ structDecl.Identifier.Span,
GetInheritanceNames(structDecl.BaseList));
return true;
case SyntaxKind.VariableDeclarator:
@@ -885,10 +915,12 @@ public bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo dec
: DeclaredSymbolInfoKind.Field;
declaredSymbolInfo = new DeclaredSymbolInfo(
- variableDeclarator.Identifier.ValueText,
+ variableDeclarator.Identifier.ValueText, null,
GetContainerDisplayName(fieldDeclaration.Parent),
GetFullyQualifiedContainerName(fieldDeclaration.Parent),
- kind, variableDeclarator.Identifier.Span,
+ kind,
+ GetAccessibility(fieldDeclaration, fieldDeclaration.Modifiers),
+ variableDeclarator.Identifier.Span,
inheritanceNames: ImmutableArray.Empty);
return true;
}
@@ -900,6 +932,151 @@ public bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo dec
return false;
}
+ private string GetConstructorSuffix(ConstructorDeclarationSyntax constructor)
+ => constructor.Modifiers.Any(SyntaxKind.StaticKeyword)
+ ? ".static " + constructor.Identifier + "()"
+ : GetSuffix('(', ')', constructor.ParameterList.Parameters);
+
+ private string GetMethodSuffix(MethodDeclarationSyntax method)
+ => GetTypeParameterSuffix(method.TypeParameterList) +
+ GetSuffix('(', ')', method.ParameterList.Parameters);
+
+ private string GetIndexerSuffix(IndexerDeclarationSyntax indexer)
+ => GetSuffix('[', ']', indexer.ParameterList.Parameters);
+
+ private string GetTypeParameterSuffix(TypeParameterListSyntax typeParameterList)
+ {
+ if (typeParameterList == null)
+ {
+ return null;
+ }
+
+ var pooledBuilder = PooledStringBuilder.GetInstance();
+
+ var builder = pooledBuilder.Builder;
+ builder.Append('<');
+
+ var first = true;
+ foreach (var parameter in typeParameterList.Parameters)
+ {
+ if (!first)
+ {
+ builder.Append(", ");
+ }
+
+ builder.Append(parameter.Identifier.Text);
+ }
+
+ builder.Append('>');
+
+ return pooledBuilder.ToStringAndFree();
+ }
+
+ ///
+ /// Builds up the suffix to show for something with parameters in navigate-to.
+ /// While it would be nice to just use the compiler SymbolDisplay API for this,
+ /// it would be too expensive as it requires going back to Symbols (which requires
+ /// creating compilations, etc.) in a perf sensitive area.
+ ///
+ /// So, instead, we just build a reasonable suffix using the pure syntax that a
+ /// user provided. That means that if they wrote "Method(System.Int32 i)" we'll
+ /// show that as "Method(System.Int32)" not "Method(int)". Given that this is
+ /// actually what the user wrote, and it saves us from ever having to go back to
+ /// symbols/compilations, this is well worth it, even if it does mean we have to
+ /// create our own 'symbol display' logic here.
+ ///
+ private string GetSuffix(
+ char openBrace, char closeBrace, SeparatedSyntaxList parameters)
+ {
+ var pooledBuilder = PooledStringBuilder.GetInstance();
+
+ var builder = pooledBuilder.Builder;
+ builder.Append(openBrace);
+ AppendParameters(parameters, builder);
+ builder.Append(closeBrace);
+
+ return pooledBuilder.ToStringAndFree();
+ }
+
+ private void AppendParameters(SeparatedSyntaxList parameters, StringBuilder builder)
+ {
+ var first = true;
+ foreach (var parameter in parameters)
+ {
+ if (!first)
+ {
+ builder.Append(", ");
+ }
+
+ foreach (var modifier in parameter.Modifiers)
+ {
+ builder.Append(modifier.Text);
+ builder.Append(' ');
+ }
+
+ if (parameter.Type != null)
+ {
+ AppendTokens(parameter.Type, builder);
+ }
+ else
+ {
+ builder.Append(parameter.Identifier.Text);
+ }
+
+ first = false;
+ }
+ }
+
+ private bool IsExtensionMethod(MethodDeclarationSyntax method)
+ => method.ParameterList.Parameters.Count > 0 &&
+ method.ParameterList.Parameters[0].Modifiers.Any(SyntaxKind.ThisKeyword);
+
+ private Accessibility GetAccessibility(SyntaxNode node, SyntaxTokenList modifiers)
+ {
+ var sawInternal = false;
+ foreach (var modifier in modifiers)
+ {
+ switch (modifier.Kind())
+ {
+ case SyntaxKind.PublicKeyword: return Accessibility.Public;
+ case SyntaxKind.PrivateKeyword: return Accessibility.Private;
+ case SyntaxKind.ProtectedKeyword: return Accessibility.Protected;
+ case SyntaxKind.InternalKeyword:
+ sawInternal = true;
+ continue;
+ }
+ }
+
+ if (sawInternal)
+ {
+ return Accessibility.Internal;
+ }
+
+ // No accessibility modifiers:
+ switch (node.Parent.Kind())
+ {
+ case SyntaxKind.ClassDeclaration:
+ case SyntaxKind.StructDeclaration:
+ // Anything without modifiers is private if it's in a class/struct declaration.
+ return Accessibility.Private;
+ case SyntaxKind.InterfaceDeclaration:
+ // Anything without modifiers is public if it's in an interface declaration.
+ return Accessibility.Public;
+ case SyntaxKind.CompilationUnit:
+ // Things are private by default in script
+ if (((CSharpParseOptions)node.SyntaxTree.Options).Kind == SourceCodeKind.Script)
+ {
+ return Accessibility.Private;
+ }
+
+ return Accessibility.Internal;
+
+ default:
+ // Otherwise it's internal
+ return Accessibility.Internal;
+ }
+ }
+
private ImmutableArray GetInheritanceNames(BaseListSyntax baseList)
{
if (baseList == null)
@@ -1035,13 +1212,6 @@ private string GetTypeName(TypeSyntax type)
private static string GetSimpleTypeName(SimpleNameSyntax name)
=> name.Identifier.ValueText;
- private static string ExpandExplicitInterfaceName(string identifier, ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifier)
- {
- return explicitInterfaceSpecifier == null
- ? identifier
- : $"{explicitInterfaceSpecifier.Name.GetNameToken().ValueText}.{identifier}";
- }
-
private string GetContainerDisplayName(SyntaxNode node)
{
return GetDisplayName(node, DisplayNameOptions.IncludeTypeParameters);
diff --git a/src/Workspaces/CSharp/Portable/Rename/LocalConflictVisitor.cs b/src/Workspaces/CSharp/Portable/Rename/LocalConflictVisitor.cs
index 16d215a197a52..ef39a69502b61 100644
--- a/src/Workspaces/CSharp/Portable/Rename/LocalConflictVisitor.cs
+++ b/src/Workspaces/CSharp/Portable/Rename/LocalConflictVisitor.cs
@@ -37,12 +37,17 @@ public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
}
public override void VisitBlock(BlockSyntax node)
+ {
+ VisitBlockStatements(node, node.Statements);
+ }
+
+ private void VisitBlockStatements(SyntaxNode node, IEnumerable statements)
{
var tokens = new List();
// We want to collect any variable declarations that are in the block
// before visiting nested statements
- foreach (var statement in node.Statements)
+ foreach (var statement in statements)
{
if (statement.Kind() == SyntaxKind.LocalDeclarationStatement)
{
@@ -183,6 +188,13 @@ public override void VisitQueryContinuation(QueryContinuationSyntax node)
_tracker.RemoveIdentifier(node.Identifier);
}
+ public override void VisitSwitchStatement(SwitchStatementSyntax node)
+ {
+ var statements = node.ChildNodes().Where(x => x.IsKind(SyntaxKind.SwitchSection)).SelectMany(x => x.ChildNodes());
+
+ VisitBlockStatements(node, statements);
+ }
+
public IEnumerable ConflictingTokens
{
get
diff --git a/src/Workspaces/CSharp/Portable/Simplification/CSharpInferredMemberNameReducer.Rewriter.cs b/src/Workspaces/CSharp/Portable/Simplification/CSharpInferredMemberNameReducer.Rewriter.cs
new file mode 100755
index 0000000000000..f6a9aae9a8ca7
--- /dev/null
+++ b/src/Workspaces/CSharp/Portable/Simplification/CSharpInferredMemberNameReducer.Rewriter.cs
@@ -0,0 +1,45 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Options;
+
+namespace Microsoft.CodeAnalysis.CSharp.Simplification
+{
+ internal partial class CSharpInferredMemberNameReducer
+ {
+ private class Rewriter : AbstractExpressionRewriter
+ {
+ public Rewriter(OptionSet optionSet, CancellationToken cancellationToken)
+ : base(optionSet, cancellationToken)
+ {
+ }
+
+ public override SyntaxNode VisitArgument(ArgumentSyntax node)
+ {
+ var newNode = base.VisitArgument(node);
+
+ if (node.Parent.IsKind(SyntaxKind.TupleExpression))
+ {
+ return SimplifyNode(
+ node,
+ parentNode: node.Parent,
+ newNode: newNode,
+ simplifier: SimplifyTupleName);
+ }
+
+ return newNode;
+ }
+
+ public override SyntaxNode VisitAnonymousObjectMemberDeclarator(AnonymousObjectMemberDeclaratorSyntax node)
+ {
+ return SimplifyNode(
+ node,
+ parentNode: node.Parent,
+ newNode: base.VisitAnonymousObjectMemberDeclarator(node),
+ simplifier: SimplifyAnonymousTypeMemberName);
+ }
+ }
+ }
+}
diff --git a/src/Workspaces/CSharp/Portable/Simplification/CSharpInferredMemberNameReducer.cs b/src/Workspaces/CSharp/Portable/Simplification/CSharpInferredMemberNameReducer.cs
new file mode 100755
index 0000000000000..21dc2d5051648
--- /dev/null
+++ b/src/Workspaces/CSharp/Portable/Simplification/CSharpInferredMemberNameReducer.cs
@@ -0,0 +1,58 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading;
+using Microsoft.CodeAnalysis.CSharp.Extensions;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Options;
+
+namespace Microsoft.CodeAnalysis.CSharp.Simplification
+{
+ ///
+ /// Complexify makes inferred names explicit for tuple elements and anonymous type members. This
+ /// class considers which ones of those can be simplified (after the refactoring was done).
+ /// If the inferred name of the member matches, the explicit name (from Complexify) can be removed.
+ ///
+ internal partial class CSharpInferredMemberNameReducer : AbstractCSharpReducer
+ {
+ public override IExpressionRewriter CreateExpressionRewriter(OptionSet optionSet, CancellationToken cancellationToken)
+ {
+ return new Rewriter(optionSet, cancellationToken);
+ }
+
+ private static ArgumentSyntax SimplifyTupleName(ArgumentSyntax node, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken)
+ {
+ // Tuple elements are arguments in a tuple expression
+ if (node.NameColon == null || !node.IsParentKind(SyntaxKind.TupleExpression))
+ {
+ return node;
+ }
+
+ var inferredName = node.Expression.TryGetInferredMemberName();
+
+ if (inferredName == null || inferredName != node.NameColon.Name.Identifier.ValueText)
+ {
+ return node;
+ }
+
+ return node.WithNameColon(null).WithTriviaFrom(node);
+ }
+
+
+ private static SyntaxNode SimplifyAnonymousTypeMemberName(AnonymousObjectMemberDeclaratorSyntax node, SemanticModel semanticModel, OptionSet optionSet, CancellationToken canellationToken)
+ {
+ if (node.NameEquals == null)
+ {
+ return node;
+ }
+
+ var inferredName = node.Expression.TryGetInferredMemberName();
+
+ if (inferredName == null || inferredName != node.NameEquals.Name.Identifier.ValueText)
+ {
+ return node;
+ }
+
+ return node.WithNameEquals(null).WithTriviaFrom(node);
+ }
+ }
+}
diff --git a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.Expander.cs b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.Expander.cs
index 1e046122698da..4763a06f015fb 100644
--- a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.Expander.cs
+++ b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.Expander.cs
@@ -257,6 +257,24 @@ public override SyntaxNode VisitArgument(ArgumentSyntax node)
var newArgument = (ArgumentSyntax)base.VisitArgument(node);
+ if (node.NameColon == null
+ && node.Parent is TupleExpressionSyntax tuple
+ && !IsTupleInDeconstruction(tuple)) // The language currently does not allow explicit element names in deconstruction
+ {
+ var inferredName = node.Expression.TryGetInferredMemberName();
+ if (CanMakeNameExplicitInTuple(tuple, inferredName))
+ {
+ var identifier = SyntaxFactory.Identifier(inferredName);
+ identifier = TryEscapeIdentifierToken(identifier, node, _semanticModel);
+
+ newArgument = newArgument
+ .WithoutLeadingTrivia()
+ .WithNameColon(SyntaxFactory.NameColon(SyntaxFactory.IdentifierName(identifier)))
+ .WithAdditionalAnnotations(Simplifier.Annotation)
+ .WithLeadingTrivia(node.GetLeadingTrivia());
+ }
+ }
+
var argumentType = _semanticModel.GetTypeInfo(node.Expression).ConvertedType;
if (argumentType != null &&
!IsPassedToDelegateCreationExpression(node, argumentType) &&
@@ -271,6 +289,62 @@ public override SyntaxNode VisitArgument(ArgumentSyntax node)
return newArgument;
}
+ private static bool CanMakeNameExplicitInTuple(TupleExpressionSyntax tuple, string name)
+ {
+ if (name == null || SyntaxFacts.IsReservedTupleElementName(name))
+ {
+ return false;
+ }
+
+ bool found = false;
+ foreach (var argument in tuple.Arguments)
+ {
+ string elementName = null;
+ if (argument.NameColon != null)
+ {
+ elementName = argument.NameColon.Name.Identifier.ValueText;
+ }
+ else
+ {
+ elementName = argument.Expression?.TryGetInferredMemberName();
+ }
+
+ if (elementName?.Equals(name, StringComparison.Ordinal) == true)
+ {
+ if (found)
+ {
+ // No duplicate names allowed
+ return false;
+ }
+ found = true;
+ }
+ }
+
+ return true;
+ }
+
+ public override SyntaxNode VisitAnonymousObjectMemberDeclarator(AnonymousObjectMemberDeclaratorSyntax node)
+ {
+ var newDeclarator = (AnonymousObjectMemberDeclaratorSyntax)base.VisitAnonymousObjectMemberDeclarator(node);
+ if (node.NameEquals == null)
+ {
+ var inferredName = node.Expression.TryGetInferredMemberName();
+ if (inferredName != null)
+ {
+ var identifier = SyntaxFactory.Identifier(inferredName);
+ identifier = TryEscapeIdentifierToken(identifier, node, _semanticModel);
+
+ newDeclarator = newDeclarator
+ .WithoutLeadingTrivia()
+ .WithNameEquals(SyntaxFactory.NameEquals(SyntaxFactory.IdentifierName(identifier))
+ .WithLeadingTrivia(node.GetLeadingTrivia()))
+ .WithAdditionalAnnotations(Simplifier.Annotation);
+ }
+ }
+
+ return newDeclarator;
+ }
+
public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node)
{
_cancellationToken.ThrowIfCancellationRequested();
diff --git a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs
index fee06023aa41d..89c78c6fe5510 100644
--- a/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs
+++ b/src/Workspaces/CSharp/Portable/Simplification/CSharpSimplificationService.cs
@@ -30,7 +30,8 @@ internal partial class CSharpSimplificationService : AbstractSimplificationServi
new CSharpExtensionMethodReducer(),
new CSharpParenthesesReducer(),
new CSharpEscapingReducer(),
- new CSharpMiscellaneousReducer());
+ new CSharpMiscellaneousReducer(),
+ new CSharpInferredMemberNameReducer());
public CSharpSimplificationService() : base(s_reducers)
{
@@ -90,6 +91,11 @@ public static SyntaxToken TryEscapeIdentifierToken(SyntaxToken syntaxToken, Synt
return syntaxToken;
}
+ if (SyntaxFacts.GetContextualKeywordKind(syntaxToken.ValueText) == SyntaxKind.UnderscoreToken)
+ {
+ return syntaxToken;
+ }
+
var parent = parentOfToken.Parent;
if (parentOfToken is SimpleNameSyntax && parent.Kind() == SyntaxKind.XmlNameAttribute)
{
@@ -184,5 +190,34 @@ protected override void GetUnusedNamespaceImports(SemanticModel model, HashSet
{
private const double ExactMatchDistance = 0.0;
private const double EpsilonDistance = 0.00001;
- private const double MatchingDistance1 = 0.5;
- private const double MatchingDistance2 = 1.0;
- private const double MatchingDistance3 = 1.5;
- private const double MaxDistance = 2.0;
+ private const double MatchingDistance1 = 0.25;
+ private const double MatchingDistance2 = 0.5;
+ private const double MaxDistance = 1.0;
private readonly TreeComparer _comparer;
private readonly TNode _root1;
@@ -154,7 +153,6 @@ private void ComputeMatchForLabel(int label, List s1, List s2)
ComputeMatchForLabel(s1, s2, tiedToAncestor, EpsilonDistance); // almost exact match
ComputeMatchForLabel(s1, s2, tiedToAncestor, MatchingDistance1); // ok match
ComputeMatchForLabel(s1, s2, tiedToAncestor, MatchingDistance2); // ok match
- ComputeMatchForLabel(s1, s2, tiedToAncestor, MatchingDistance3); // ok match
ComputeMatchForLabel(s1, s2, tiedToAncestor, MaxDistance); // any match
}
@@ -168,6 +166,7 @@ private void ComputeMatchForLabel(List s1, List s2, int tiedToAnce
// So in the case of totally matching sequences, we process them in O(n) -
// both node1 and firstNonMatch2 will be advanced simultaneously.
+ Debug.Assert(maxAcceptableDistance >= ExactMatchDistance && maxAcceptableDistance <= MaxDistance);
int count1 = s1.Count;
int count2 = s2.Count;
int firstNonMatch2 = 0;
@@ -184,7 +183,7 @@ private void ComputeMatchForLabel(List s1, List s2, int tiedToAnce
// Find node2 that matches node1 the best, i.e. has minimal distance.
- double bestDistance = MaxDistance;
+ double bestDistance = MaxDistance * 2;
TNode bestMatch = default(TNode);
bool matched = false;
int i2;
@@ -258,6 +257,11 @@ private void ComputeMatchForLabel(List s1, List s2, int tiedToAnce
{
firstNonMatch2 = i2 + 1;
}
+
+ if (firstNonMatch2 == count2)
+ {
+ return;
+ }
}
}
}
diff --git a/src/Workspaces/Core/Portable/Execution/PinnedRemotableDataScope.cs b/src/Workspaces/Core/Portable/Execution/PinnedRemotableDataScope.cs
index 1fe0fad6f8b10..be115ef2f7ffb 100644
--- a/src/Workspaces/Core/Portable/Execution/PinnedRemotableDataScope.cs
+++ b/src/Workspaces/Core/Portable/Execution/PinnedRemotableDataScope.cs
@@ -12,10 +12,11 @@ namespace Microsoft.CodeAnalysis.Execution
///
/// checksum scope that one can use to pin assets in memory while working on remote host
///
- internal class PinnedRemotableDataScope : IDisposable
+ internal sealed class PinnedRemotableDataScope : IDisposable
{
private readonly AssetStorages _storages;
private readonly AssetStorages.Storage _storage;
+ private bool _disposed;
public readonly Checksum SolutionChecksum;
@@ -63,7 +64,12 @@ public IReadOnlyDictionary GetRemotableData(IEnumerable
public void Dispose()
{
- _storages.UnregisterSnapshot(this);
+ if (!_disposed)
+ {
+ _disposed = true;
+ _storages.UnregisterSnapshot(this);
+ }
+
GC.SuppressFinalize(this);
}
diff --git a/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs b/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs
index 5729db84a0048..515fe0757fd8d 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_AllDeclarations.cs
@@ -93,18 +93,20 @@ await AddMetadataDeclarationsWithNormalQueryAsync(
private static async Task<(bool, ImmutableArray)> TryFindAllDeclarationsWithNormalQueryInRemoteProcessAsync(
Project project, SearchQuery query, SymbolFilter criteria, CancellationToken cancellationToken)
{
- var session = await SymbolFinder.TryGetRemoteSessionAsync(
- project.Solution, cancellationToken).ConfigureAwait(false);
- if (session != null)
+ using (var session = await SymbolFinder.TryGetRemoteSessionAsync(
+ project.Solution, cancellationToken).ConfigureAwait(false))
{
- var result = await session.InvokeAsync(
- nameof(IRemoteSymbolFinder.FindAllDeclarationsWithNormalQueryAsync),
- project.Id, query.Name, query.Kind, criteria).ConfigureAwait(false);
+ if (session != null)
+ {
+ var result = await session.InvokeAsync(
+ nameof(IRemoteSymbolFinder.FindAllDeclarationsWithNormalQueryAsync),
+ project.Id, query.Name, query.Kind, criteria).ConfigureAwait(false);
- var rehydrated = await RehydrateAsync(
- project.Solution, result, cancellationToken).ConfigureAwait(false);
+ var rehydrated = await RehydrateAsync(
+ project.Solution, result, cancellationToken).ConfigureAwait(false);
- return (true, rehydrated);
+ return (true, rehydrated);
+ }
}
return (false, ImmutableArray.Empty);
diff --git a/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_SourceDeclarations.cs b/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_SourceDeclarations.cs
index 6874c667c720a..0b3b97066249d 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_SourceDeclarations.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/Declarations/DeclarationFinder_SourceDeclarations.cs
@@ -1,16 +1,12 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Collections.Generic;
using System.Collections.Immutable;
-using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.PatternMatching;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Shared.Extensions;
-using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols
{
@@ -118,17 +114,19 @@ public static async Task> FindSourceDeclarati
private static async Task<(bool, ImmutableArray)> TryFindSourceDeclarationsWithNormalQueryInRemoteProcessAsync(
Solution solution, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken)
{
- var session = await SymbolFinder.TryGetRemoteSessionAsync(solution, cancellationToken).ConfigureAwait(false);
- if (session != null)
+ using (var session = await SymbolFinder.TryGetRemoteSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
- var result = await session.InvokeAsync(
- nameof(IRemoteSymbolFinder.FindSolutionSourceDeclarationsWithNormalQueryAsync),
- name, ignoreCase, criteria).ConfigureAwait(false);
+ if (session != null)
+ {
+ var result = await session.InvokeAsync(
+ nameof(IRemoteSymbolFinder.FindSolutionSourceDeclarationsWithNormalQueryAsync),
+ name, ignoreCase, criteria).ConfigureAwait(false);
- var rehydrated = await RehydrateAsync(
- solution, result, cancellationToken).ConfigureAwait(false);
+ var rehydrated = await RehydrateAsync(
+ solution, result, cancellationToken).ConfigureAwait(false);
- return (true, rehydrated);
+ return (true, rehydrated);
+ }
}
return (false, ImmutableArray.Empty);
@@ -137,17 +135,19 @@ public static async Task> FindSourceDeclarati
private static async Task<(bool, ImmutableArray)> TryFindSourceDeclarationsWithNormalQueryInRemoteProcessAsync(
Project project, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken)
{
- var session = await SymbolFinder.TryGetRemoteSessionAsync(project.Solution, cancellationToken).ConfigureAwait(false);
- if (session != null)
+ using (var session = await SymbolFinder.TryGetRemoteSessionAsync(project.Solution, cancellationToken).ConfigureAwait(false))
{
- var result = await session.InvokeAsync(
- nameof(IRemoteSymbolFinder.FindProjectSourceDeclarationsWithNormalQueryAsync),
- project.Id, name, ignoreCase, criteria).ConfigureAwait(false);
+ if (session != null)
+ {
+ var result = await session.InvokeAsync(
+ nameof(IRemoteSymbolFinder.FindProjectSourceDeclarationsWithNormalQueryAsync),
+ project.Id, name, ignoreCase, criteria).ConfigureAwait(false);
- var rehydrated = await RehydrateAsync(
- project.Solution, result, cancellationToken).ConfigureAwait(false);
+ var rehydrated = await RehydrateAsync(
+ project.Solution, result, cancellationToken).ConfigureAwait(false);
- return (true, rehydrated);
+ return (true, rehydrated);
+ }
}
return (false, ImmutableArray.Empty);
@@ -156,17 +156,19 @@ public static async Task> FindSourceDeclarati
private static async Task<(bool, ImmutableArray)> TryFindSourceDeclarationsWithPatternInRemoteProcessAsync(
Project project, string pattern, SymbolFilter criteria, CancellationToken cancellationToken)
{
- var session = await SymbolFinder.TryGetRemoteSessionAsync(project.Solution, cancellationToken).ConfigureAwait(false);
- if (session != null)
+ using (var session = await SymbolFinder.TryGetRemoteSessionAsync(project.Solution, cancellationToken).ConfigureAwait(false))
{
- var result = await session.InvokeAsync(
- nameof(IRemoteSymbolFinder.FindProjectSourceDeclarationsWithPatternAsync),
- project.Id, pattern, criteria).ConfigureAwait(false);
+ if (session != null)
+ {
+ var result = await session.InvokeAsync(
+ nameof(IRemoteSymbolFinder.FindProjectSourceDeclarationsWithPatternAsync),
+ project.Id, pattern, criteria).ConfigureAwait(false);
- var rehydrated = await RehydrateAsync(
- project.Solution, result, cancellationToken).ConfigureAwait(false);
+ var rehydrated = await RehydrateAsync(
+ project.Solution, result, cancellationToken).ConfigureAwait(false);
- return (true, rehydrated);
+ return (true, rehydrated);
+ }
}
return (false, ImmutableArray.Empty);
@@ -183,26 +185,31 @@ public static async Task> FindSourceDeclarati
internal static async Task> FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync(
Solution solution, string name, bool ignoreCase, SymbolFilter criteria, CancellationToken cancellationToken)
{
- var query = SearchQuery.Create(name, ignoreCase);
- var result = ArrayBuilder.GetInstance();
- foreach (var projectId in solution.ProjectIds)
+ using (var query = SearchQuery.Create(name, ignoreCase))
{
- var project = solution.GetProject(projectId);
- await AddCompilationDeclarationsWithNormalQueryAsync(
- project, query, criteria, result, cancellationToken).ConfigureAwait(false);
- }
+ var result = ArrayBuilder.GetInstance();
+ foreach (var projectId in solution.ProjectIds)
+ {
+ var project = solution.GetProject(projectId);
+ await AddCompilationDeclarationsWithNormalQueryAsync(
+ project, query, criteria, result, cancellationToken).ConfigureAwait(false);
+ }
- return result.ToImmutableAndFree();
+ return result.ToImmutableAndFree();
+ }
}
internal static async Task> FindSourceDeclarationsWithNormalQueryInCurrentProcessAsync(
Project project, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken)
{
var list = ArrayBuilder.GetInstance();
- await AddCompilationDeclarationsWithNormalQueryAsync(
- project, SearchQuery.Create(name, ignoreCase),
- filter, list, cancellationToken).ConfigureAwait(false);
- return list.ToImmutableAndFree();
+
+ using (var query = SearchQuery.Create(name, ignoreCase))
+ {
+ await AddCompilationDeclarationsWithNormalQueryAsync(
+ project, query, filter, list, cancellationToken).ConfigureAwait(false);
+ return list.ToImmutableAndFree();
+ }
}
internal static async Task> FindSourceDeclarationsWithPatternInCurrentProcessAsync(
@@ -214,51 +221,36 @@ internal static async Task> FindSourceDeclara
// we don't want to check the whole pattern against it (as it will clearly fail), instead
// we only want to check the 'WL' portion. Then, after we get all the candidate symbols
// we'll check if the full name matches the full pattern.
- var patternMatcher = new PatternMatcher(pattern);
- var query = SearchQuery.CreateCustom(
- k => !patternMatcher.GetMatchesForLastSegmentOfPattern(k).IsDefaultOrEmpty);
-
- var symbolAndProjectIds = await SymbolFinder.FindSourceDeclarationsWithCustomQueryAsync(
- project, query, criteria, cancellationToken).ConfigureAwait(false);
+ var (namePart, containerPart) = PatternMatcher.GetNameAndContainer(pattern);
- var result = ArrayBuilder.GetInstance();
+ var dotIndex = pattern.LastIndexOf('.');
+ var isDottedPattern = dotIndex >= 0;
- // Now see if the symbols the compiler returned actually match the full pattern.
- foreach (var symbolAndProjectId in symbolAndProjectIds)
+ // If we don't have a dot in the pattern, just make a pattern matcher for the entire
+ // pattern they passed in. Otherwise, make a pattern matcher just for the part after
+ // the dot.
+ using (var nameMatcher = PatternMatcher.CreatePatternMatcher(namePart, includeMatchedSpans: false))
+ using (var query = SearchQuery.CreateCustom(nameMatcher.Matches))
{
- var symbol = symbolAndProjectId.Symbol;
+ var symbolAndProjectIds = await SymbolFinder.FindSourceDeclarationsWithCustomQueryAsync(
+ project, query, criteria, cancellationToken).ConfigureAwait(false);
- // As an optimization, don't bother getting the container for this symbol if this
- // isn't a dotted pattern. Getting the container could cause lots of string
- // allocations that we don't if we're never going to check it.
- var matches = !patternMatcher.IsDottedPattern
- ? new PatternMatches(patternMatcher.GetMatches(GetSearchName(symbol)))
- : patternMatcher.GetMatches(GetSearchName(symbol), GetContainer(symbol));
-
- if (matches.IsEmpty)
+ if (symbolAndProjectIds.Length == 0 ||
+ !isDottedPattern)
{
- // Didn't actually match the full pattern, ignore it.
- continue;
+ // If it wasn't a dotted pattern, or we didn't get anything back, then we're done.
+ // We can just return whatever set of results we got so far.
+ return symbolAndProjectIds;
}
- result.Add(symbolAndProjectId);
- }
-
- return result.ToImmutableAndFree();
- }
-
- private static string GetSearchName(ISymbol symbol)
- {
- if (symbol.IsConstructor() || symbol.IsStaticConstructor())
- {
- return symbol.ContainingType.Name;
- }
- else if (symbol.IsIndexer() && symbol.Name == WellKnownMemberNames.Indexer)
- {
- return "this";
+ // Ok, we had a dotted pattern. Have to see if the symbol's container matches the
+ // pattern as well.
+ using (var containerPatternMatcher = PatternMatcher.CreateDotSeparatedContainerMatcher(containerPart))
+ {
+ return symbolAndProjectIds.WhereAsArray(t =>
+ containerPatternMatcher.Matches(GetContainer(t.Symbol)));
+ }
}
-
- return symbol.Name;
}
private static string GetContainer(ISymbol symbol)
diff --git a/src/Workspaces/Core/Portable/FindSymbols/DeclaredSymbolInfo.cs b/src/Workspaces/Core/Portable/FindSymbols/DeclaredSymbolInfo.cs
index 2c74a048bca4f..0afb72e6fc75f 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/DeclaredSymbolInfo.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/DeclaredSymbolInfo.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Immutable;
+using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ErrorReporting;
@@ -19,60 +20,115 @@ internal enum DeclaredSymbolInfoKind : byte
Enum,
EnumMember,
Event,
+ ExtensionMethod,
Field,
Indexer,
Interface,
Method,
Module,
Property,
- Struct
+ Struct,
}
internal struct DeclaredSymbolInfo
{
+ ///
+ /// The name to pattern match against, and to show in a final presentation layer.
+ ///
public string Name { get; }
+
+ ///
+ /// An optional suffix to be shown in a presentation layer appended to .
+ /// Can be null.
+ ///
+ public string NameSuffix { get; }
+
+ ///
+ /// Container of the symbol that can be shown in a final presentation layer.
+ /// For example, the container of a type "KeyValuePair" might be
+ /// "System.Collections.Generic.Dictionary<TKey, TValue>". This can
+ /// then be shown with something like "type System.Collections.Generic.Dictionary<TKey, TValue>"
+ /// to indicate where the symbol is located.
+ ///
public string ContainerDisplayName { get; }
+
+ ///
+ /// Dotted container name of the symbol, used for pattern matching. For example
+ /// The fully qualified container of a type "KeyValuePair" would be
+ /// "System.Collections.Generic.Dictionary" (note the lack of type parameters).
+ /// This way someone can search for "D.KVP" and have the "D" part of the pattern
+ /// match against this. This should not be shown in a presentation layer.
+ ///
public string FullyQualifiedContainerName { get; }
- public DeclaredSymbolInfoKind Kind { get; }
+
public TextSpan Span { get; }
- public ushort ParameterCount { get; }
- public ushort TypeParameterCount { get; }
+
+ // Store the kind, accessibility, parameter-count, and type-parameter-count
+ // in a single int. Each gets 4 bits which is ample and gives us more space
+ // for flags in the future.
+ private readonly uint _flags;
+
+ private const uint Lower4BitMask = 0b1111;
+
+ public DeclaredSymbolInfoKind Kind => GetKind(_flags);
+ public Accessibility Accessibility => GetAccessibility(_flags);
+ public byte ParameterCount => GetParameterCount(_flags);
+ public byte TypeParameterCount => GetTypeParameterCount(_flags);
///
/// The names directly referenced in source that this type inherits from.
///
- public ImmutableArray InheritanceNames { get; }
+ public ImmutableArray InheritanceNames { get; }
public DeclaredSymbolInfo(
string name,
+ string nameSuffix,
string containerDisplayName,
string fullyQualifiedContainerName,
DeclaredSymbolInfoKind kind,
+ Accessibility accessibility,
TextSpan span,
ImmutableArray inheritanceNames,
- ushort parameterCount = 0, ushort typeParameterCount = 0)
+ int parameterCount = 0, int typeParameterCount = 0)
: this()
{
Name = name;
+ NameSuffix = nameSuffix;
ContainerDisplayName = containerDisplayName;
FullyQualifiedContainerName = fullyQualifiedContainerName;
- Kind = kind;
Span = span;
- ParameterCount = parameterCount;
- TypeParameterCount = typeParameterCount;
InheritanceNames = inheritanceNames;
+
+ const uint MaxFlagValue = 0b1111;
+ Contract.ThrowIfTrue((uint)accessibility > MaxFlagValue);
+ Contract.ThrowIfTrue((uint)kind > MaxFlagValue);
+ parameterCount = Math.Min(parameterCount, (byte)MaxFlagValue);
+ typeParameterCount = Math.Min(typeParameterCount, (byte)MaxFlagValue);
+
+ _flags = (uint)kind | ((uint)accessibility << 4) | ((uint)parameterCount << 8) | ((uint)typeParameterCount << 12);
}
+ private static DeclaredSymbolInfoKind GetKind(uint flags)
+ => (DeclaredSymbolInfoKind)(flags & Lower4BitMask);
+
+ private static Accessibility GetAccessibility(uint flags)
+ => (Accessibility)((flags >> 4) & Lower4BitMask);
+
+ private static byte GetParameterCount(uint flags)
+ => (byte)((flags >> 8) & Lower4BitMask);
+
+ private static byte GetTypeParameterCount(uint flags)
+ => (byte)((flags >> 12) & Lower4BitMask);
+
internal void WriteTo(ObjectWriter writer)
{
writer.WriteString(Name);
+ writer.WriteString(NameSuffix);
writer.WriteString(ContainerDisplayName);
writer.WriteString(FullyQualifiedContainerName);
- writer.WriteByte((byte)Kind);
+ writer.WriteUInt32(_flags);
writer.WriteInt32(Span.Start);
writer.WriteInt32(Span.Length);
- writer.WriteUInt16(ParameterCount);
- writer.WriteUInt16(TypeParameterCount);
writer.WriteInt32(InheritanceNames.Length);
foreach (var name in InheritanceNames)
@@ -84,24 +140,32 @@ internal void WriteTo(ObjectWriter writer)
internal static DeclaredSymbolInfo ReadFrom_ThrowsOnFailure(ObjectReader reader)
{
var name = reader.ReadString();
- var immediateContainer = reader.ReadString();
- var entireContainer = reader.ReadString();
- var kind = (DeclaredSymbolInfoKind)reader.ReadByte();
+ var nameSuffix = reader.ReadString();
+ var containerDisplayName = reader.ReadString();
+ var fullyQualifiedContainerName = reader.ReadString();
+ var flags = reader.ReadUInt32();
var spanStart = reader.ReadInt32();
var spanLength = reader.ReadInt32();
- var parameterCount = reader.ReadUInt16();
- var typeParameterCount = reader.ReadUInt16();
var inheritanceNamesLength = reader.ReadInt32();
- var builder = ImmutableArray.CreateBuilder(inheritanceNamesLength);
+ var builder = ArrayBuilder.GetInstance(inheritanceNamesLength);
for (var i = 0; i < inheritanceNamesLength; i++)
{
builder.Add(reader.ReadString());
}
+ var span = new TextSpan(spanStart, spanLength);
return new DeclaredSymbolInfo(
- name, immediateContainer, entireContainer, kind, new TextSpan(spanStart, spanLength),
- builder.MoveToImmutable(), parameterCount, typeParameterCount);
+ name: name,
+ nameSuffix: nameSuffix,
+ containerDisplayName: containerDisplayName,
+ fullyQualifiedContainerName: fullyQualifiedContainerName,
+ kind: GetKind(flags),
+ accessibility: GetAccessibility(flags),
+ span: span,
+ inheritanceNames: builder.ToImmutableAndFree(),
+ parameterCount: GetParameterCount(flags),
+ typeParameterCount: GetTypeParameterCount(flags));
}
public async Task TryResolveAsync(Document document, CancellationToken cancellationToken)
diff --git a/src/Workspaces/Core/Portable/FindSymbols/SearchQuery.cs b/src/Workspaces/Core/Portable/FindSymbols/SearchQuery.cs
index 661b1ea0f1fdd..a8c7a4442da96 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/SearchQuery.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/SearchQuery.cs
@@ -5,7 +5,7 @@
namespace Microsoft.CodeAnalysis.FindSymbols
{
- internal class SearchQuery
+ internal class SearchQuery : IDisposable
{
/// The name being searched for. Is null in the case of custom predicate searching.. But
/// can be used for faster index based searching when it is available.
@@ -18,6 +18,8 @@ internal class SearchQuery
///The predicate to fall back on if faster index searching is not possible.
private readonly Func _predicate;
+ private readonly WordSimilarityChecker _wordSimilarityChecker;
+
private SearchQuery(string name, SearchKind kind)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
@@ -36,8 +38,8 @@ private SearchQuery(string name, SearchKind kind)
// its 'AreSimilar' method. That way we only create the WordSimilarityChecker
// once and it can cache all the information it needs while it does the AreSimilar
// check against all the possible candidates.
- var editDistance = new WordSimilarityChecker(name, substringsAreSimilar: false);
- _predicate = editDistance.AreSimilar;
+ _wordSimilarityChecker = WordSimilarityChecker.Allocate(name, substringsAreSimilar: false);
+ _predicate = _wordSimilarityChecker.AreSimilar;
break;
default:
throw ExceptionUtilities.UnexpectedValue(kind);
@@ -50,6 +52,11 @@ private SearchQuery(Func predicate)
_predicate = predicate ?? throw new ArgumentNullException(nameof(predicate));
}
+ public void Dispose()
+ {
+ _wordSimilarityChecker?.Free();
+ }
+
public static SearchQuery Create(string name, SearchKind kind)
=> new SearchQuery(name, kind);
diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations_AllDeclarations.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations_AllDeclarations.cs
index 9f016feb82cf3..6e7ee15dc9d76 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations_AllDeclarations.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations_AllDeclarations.cs
@@ -14,9 +14,12 @@ public static partial class SymbolFinder
public static async Task> FindDeclarationsAsync(
Project project, string name, bool ignoreCase, CancellationToken cancellationToken = default(CancellationToken))
{
- var declarations = await DeclarationFinder.FindAllDeclarationsWithNormalQueryAsync(
- project, SearchQuery.Create(name, ignoreCase), SymbolFilter.All, cancellationToken).ConfigureAwait(false);
- return declarations.SelectAsArray(t => t.Symbol);
+ using (var query = SearchQuery.Create(name, ignoreCase))
+ {
+ var declarations = await DeclarationFinder.FindAllDeclarationsWithNormalQueryAsync(
+ project, query, SymbolFilter.All, cancellationToken).ConfigureAwait(false);
+ return declarations.SelectAsArray(t => t.Symbol);
+ }
}
///
@@ -25,9 +28,12 @@ public static async Task> FindDeclarationsAsync(
public static async Task> FindDeclarationsAsync(
Project project, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
{
- var declarations = await DeclarationFinder.FindAllDeclarationsWithNormalQueryAsync(
- project, SearchQuery.Create(name, ignoreCase), filter, cancellationToken).ConfigureAwait(false);
- return declarations.SelectAsArray(t => t.Symbol);
+ using (var query = SearchQuery.Create(name, ignoreCase))
+ {
+ var declarations = await DeclarationFinder.FindAllDeclarationsWithNormalQueryAsync(
+ project, query, filter, cancellationToken).ConfigureAwait(false);
+ return declarations.SelectAsArray(t => t.Symbol);
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations_CustomQueries.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations_CustomQueries.cs
index 0b21f95bbab5e..024cef2beed75 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations_CustomQueries.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations_CustomQueries.cs
@@ -30,10 +30,13 @@ public static partial class SymbolFinder
///
public static async Task> FindSourceDeclarationsAsync(Solution solution, Func predicate, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
{
- var declarations = await FindSourceDeclarationsWithCustomQueryAsync(
- solution, SearchQuery.CreateCustom(predicate), filter, cancellationToken).ConfigureAwait(false);
+ using (var query = SearchQuery.CreateCustom(predicate))
+ {
+ var declarations = await FindSourceDeclarationsWithCustomQueryAsync(
+ solution, query, filter, cancellationToken).ConfigureAwait(false);
- return declarations.SelectAsArray(d => d.Symbol);
+ return declarations.SelectAsArray(d => d.Symbol);
+ }
}
private static async Task> FindSourceDeclarationsWithCustomQueryAsync(
@@ -74,10 +77,13 @@ private static async Task> FindSourceDeclarat
///
public static async Task> FindSourceDeclarationsAsync(Project project, Func predicate, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
{
- var declarations = await FindSourceDeclarationsWithCustomQueryAsync(
- project, SearchQuery.CreateCustom(predicate), filter, cancellationToken).ConfigureAwait(false);
+ using (var query = SearchQuery.CreateCustom(predicate))
+ {
+ var declarations = await FindSourceDeclarationsWithCustomQueryAsync(
+ project, query, filter, cancellationToken).ConfigureAwait(false);
- return declarations.SelectAsArray(d => d.Symbol);
+ return declarations.SelectAsArray(d => d.Symbol);
+ }
}
internal static async Task> FindSourceDeclarationsWithCustomQueryAsync(
diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs
index 8840256ce3941..4a11652d7ee15 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs
@@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.FindSymbols
internal sealed partial class SyntaxTreeIndex : IObjectWritable
{
private const string PersistenceName = "";
- private const string SerializationFormat = "3";
+ private const string SerializationFormat = "6";
///
/// in memory cache will hold onto any info related to opened documents in primary branch or all documents in forked branch
diff --git a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractSyntaxFactsService.cs b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractSyntaxFactsService.cs
index f0ffe4d76218e..4f1ec0a5c5edc 100644
--- a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractSyntaxFactsService.cs
+++ b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractSyntaxFactsService.cs
@@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
+using System.Text;
namespace Microsoft.CodeAnalysis.LanguageServices
{
@@ -391,5 +392,20 @@ public string GetBannerText(SyntaxNode documentationCommentTriviaSyntax, Cancell
=> DocumentationCommentService.GetBannerText(documentationCommentTriviaSyntax, cancellationToken);
protected abstract IDocumentationCommentService DocumentationCommentService { get; }
+
+ protected static void AppendTokens(SyntaxNode node, StringBuilder builder)
+ {
+ foreach (var child in node.ChildNodesAndTokens())
+ {
+ if (child.IsToken)
+ {
+ builder.Append(child.AsToken().Text);
+ }
+ else
+ {
+ AppendTokens(child.AsNode(), builder);
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Workspaces/Core/Portable/NamingStyles/Serialization/NamingStylePreferences.cs b/src/Workspaces/Core/Portable/NamingStyles/Serialization/NamingStylePreferences.cs
index 8164ad60d1e77..4d3cbd63d6df1 100644
--- a/src/Workspaces/Core/Portable/NamingStyles/Serialization/NamingStylePreferences.cs
+++ b/src/Workspaces/Core/Portable/NamingStyles/Serialization/NamingStylePreferences.cs
@@ -82,12 +82,24 @@ public override bool Equals(object obj)
public bool Equals(NamingStylePreferences other)
{
- return !ReferenceEquals(other, null) &&
- CreateXElement().ToString() == other.CreateXElement().ToString();
+ return other == null
+ ? false
+ : CreateXElement().ToString() == other.CreateXElement().ToString();
}
public static bool operator ==(NamingStylePreferences left, NamingStylePreferences right)
- => left?.Equals(right) == true;
+ {
+ if (ReferenceEquals(left, null) && ReferenceEquals(right, null))
+ {
+ return true;
+ }
+ else if (ReferenceEquals(left, null) || ReferenceEquals(right, null))
+ {
+ return false;
+ }
+
+ return left.Equals(right);
+ }
public static bool operator !=(NamingStylePreferences left, NamingStylePreferences right)
=> !(left == right);
diff --git a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.AllLowerCamelCaseMatcher.cs b/src/Workspaces/Core/Portable/PatternMatching/AllLowerCamelCaseMatcher.cs
similarity index 51%
rename from src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.AllLowerCamelCaseMatcher.cs
rename to src/Workspaces/Core/Portable/PatternMatching/AllLowerCamelCaseMatcher.cs
index 737318c8b2741..e72270bdee4c9 100644
--- a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.AllLowerCamelCaseMatcher.cs
+++ b/src/Workspaces/Core/Portable/PatternMatching/AllLowerCamelCaseMatcher.cs
@@ -1,32 +1,33 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Diagnostics;
+using Microsoft.CodeAnalysis.Shared;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.PatternMatching
{
- internal sealed partial class PatternMatcher : IDisposable
+ internal partial class PatternMatcher
{
///
- /// Encapsulated matches responsible for mathcing an all lowercase pattern against
+ /// Encapsulated matches responsible for matching an all lowercase pattern against
/// a candidate using CamelCase matching. i.e. this code is responsible for finding the
/// match between "cofipro" and "CodeFixProvider".
///
private struct AllLowerCamelCaseMatcher
{
- private readonly string _candidate;
private readonly bool _includeMatchedSpans;
+ private readonly string _candidate;
private readonly StringBreaks _candidateHumps;
private readonly TextChunk _patternChunk;
private readonly string _patternText;
- public AllLowerCamelCaseMatcher(string candidate, bool includeMatchedSpans, StringBreaks candidateHumps, TextChunk patternChunk)
+ public AllLowerCamelCaseMatcher(bool includeMatchedSpans, string candidate, StringBreaks candidateHumps, TextChunk patternChunk)
{
- _candidate = candidate;
_includeMatchedSpans = includeMatchedSpans;
+ _candidate = candidate;
_candidateHumps = candidateHumps;
_patternChunk = patternChunk;
_patternText = _patternChunk.Text;
@@ -34,10 +35,10 @@ public AllLowerCamelCaseMatcher(string candidate, bool includeMatchedSpans, Stri
///
/// Returns null if no match was found, 1 if a contiguous match was found, 2 if a
- /// match as found that starts at the beginning of the candidate, and 3 if a continguous
+ /// match as found that starts at the beginning of the candidate, and 3 if a contiguous
/// match was found that starts at the beginning of the candidate.
///
- public int? TryMatch(out List matchedSpans)
+ public PatternMatchKind? TryMatch(out ImmutableArray matchedSpans)
{
// We have something like cofipro and we want to match CodeFixProvider.
//
@@ -47,32 +48,46 @@ public AllLowerCamelCaseMatcher(string candidate, bool includeMatchedSpans, Stri
// basically have to branch out and try all options at every character
// in the pattern chunk.
- var patternIndex = 0;
- var candidateHumpIndex = 0;
+ var result = TryMatch(
+ patternIndex: 0, candidateHumpIndex: 0, contiguous: null);
+
+ if (result == null)
+ {
+ matchedSpans = ImmutableArray.Empty;
+ return null;
+ }
- var (bestWeight, localMatchedSpans) = TryMatch(
- patternIndex, candidateHumpIndex, contiguous: null);
+ matchedSpans = _includeMatchedSpans && result.Value.MatchedSpansInReverse != null
+ ? new NormalizedTextSpanCollection(result.Value.MatchedSpansInReverse).ToImmutableArray()
+ : ImmutableArray.Empty;
- matchedSpans = localMatchedSpans;
- return bestWeight;
+ result?.Free();
+ return GetKind(result.Value);
}
- private (int? bestWeight, List matchedSpans) TryMatch(
+ private PatternMatchKind GetKind(CamelCaseResult result)
+ => PatternMatcher.GetCamelCaseKind(result, _candidateHumps);
+
+ private CamelCaseResult? TryMatch(
int patternIndex, int candidateHumpIndex, bool? contiguous)
{
if (patternIndex == _patternText.Length)
{
// We hit the end. So we were able to match against this candidate.
- return (bestWeight: contiguous == false ? 0 : CamelCaseContiguousBonus,
- matchedSpans: _includeMatchedSpans ? new List() : null);
+ // We are contiguous if our contiguous tracker was not set to false.
+ var matchedSpansInReverse = _includeMatchedSpans ? ArrayBuilder.GetInstance() : null;
+ return new CamelCaseResult(
+ fromStart: false,
+ contiguous: contiguous != false,
+ matchCount: 0,
+ matchedSpansInReverse: matchedSpansInReverse);
}
- var bestWeight = default(int?);
- var bestMatchedSpans = default(List);
+ var bestResult = default(CamelCaseResult?);
// Look for a hump in the candidate that matches the current letter we're on.
var patternCharacter = _patternText[patternIndex];
- for (var humpIndex = candidateHumpIndex; humpIndex < _candidateHumps.Count; humpIndex++)
+ for (int humpIndex = candidateHumpIndex, n = _candidateHumps.GetCount(); humpIndex < n; humpIndex++)
{
// If we've been contiguous, but we jumped past a hump, then we're no longer contiguous.
if (contiguous.HasValue && contiguous.Value)
@@ -94,113 +109,131 @@ public AllLowerCamelCaseMatcher(string candidate, bool includeMatchedSpans, Stri
// is cofipro, and we've matched the 'f' against the 'F', then the max of
// the pattern we'll want to consume is "fip" against "Fix". We don't want
// consume parts of the pattern once we reach the next hump.
-
+
// We matched something. If this was our first match, consider ourselves
// contiguous.
- if (contiguous == null)
- {
- contiguous = true;
- }
+ var localContiguous = contiguous == null ? true : contiguous.Value;
- var (weight, matchedSpans) = TryConsumePatternOrMatchNextHump(
- patternIndex, humpIndex, contiguous.Value);
- if (weight == null)
- {
- // Even though we matched this current candidate hump we failed to match
- // the remainder of the pattern. Continue to the next candidate hump
- // to see if our pattern character will match it and potentially succed.
- continue;
- }
+ var result = TryConsumePatternOrMatchNextHump(
+ patternIndex, humpIndex, localContiguous);
- Debug.Assert(weight >= 0);
- if (weight == CamelCaseMaxWeight)
+ if (result == null)
{
- // We found a path that allowed us to match everything contiguously
- // from the beginning. This is the best match possible. So we can
- // just stop now and return this result.
- return (weight, matchedSpans);
+ continue;
}
- // This is a decent match. But something else could beat it, store
- // it if it's the best match we have so far, but keep searching.
- if (bestWeight == null || weight > bestWeight)
+ if (UpdateBestResultIfBetter(result.Value, ref bestResult, matchSpanToAdd: null))
{
- bestWeight = weight;
- bestMatchedSpans = matchedSpans;
+ // We found the best result so far. We can stop immediately.
+ break;
}
}
}
- return (bestWeight, bestMatchedSpans);
+ return bestResult;
}
- private (int? bestWeight, List matchedSpans) TryConsumePatternOrMatchNextHump(
+ private CamelCaseResult? TryConsumePatternOrMatchNextHump(
int patternIndex, int humpIndex, bool contiguous)
{
- var bestWeight = default(int?);
- var bestMatchedSpans = default(List);
+ var bestResult = default(CamelCaseResult?);
var candidateHump = _candidateHumps[humpIndex];
var maxPatternHumpLength = _patternText.Length - patternIndex;
var maxCandidateHumpLength = candidateHump.Length;
+
var maxHumpMatchLength = Math.Min(maxPatternHumpLength, maxCandidateHumpLength);
for (var possibleHumpMatchLength = 1; possibleHumpMatchLength <= maxHumpMatchLength; possibleHumpMatchLength++)
{
if (!LowercaseSubstringsMatch(
- _candidate, candidateHump.Start,
- _patternText, patternIndex, possibleHumpMatchLength))
+ _candidate, candidateHump.Start,
+ _patternText, patternIndex, possibleHumpMatchLength))
{
// Stop trying to consume once the pattern contents no longer matches
// against the current candidate hump.
break;
}
- // This is the span of the hump of the candidate we matched.
- var candidateMatchSpan = new TextSpan(candidateHump.Start, possibleHumpMatchLength);
-
// The pattern substring 'f' has matched against 'F', or 'fi' has matched
// against 'Fi'. recurse and let the rest of the pattern match the remainder
// of the candidate.
- var (weight, matchedSpans) = TryMatch(
+ var resultOpt = TryMatch(
patternIndex + possibleHumpMatchLength, humpIndex + 1, contiguous);
- if (weight == null)
+ if (resultOpt == null)
{
- // Didn't match when we recursed. Try to consume more and see if that gets us
- // somewhere.
+ // Didn't match. Try the next longer pattern chunk.
continue;
}
- Debug.Assert(weight <= CamelCaseContiguousBonus);
-
+ var result = resultOpt.Value;
+ // If this is our first hump add a 'from start' bonus.
if (humpIndex == 0)
{
- weight += CamelCaseMatchesFromStartBonus;
+ result = result.WithFromStart(true);
}
- if (weight == CamelCaseMaxWeight)
+ // This is the span of the hump of the candidate we matched.
+ var matchSpanToAdd = new TextSpan(candidateHump.Start, possibleHumpMatchLength);
+ if (UpdateBestResultIfBetter(result, ref bestResult, matchSpanToAdd))
{
- // We found a path that allowed us to match everything contiguously
- // from the beginning. This is the best match possible. So we can
- // just stop now and return thie result.
- matchedSpans?.Insert(0, candidateMatchSpan);
- return (weight, matchedSpans);
+ // We found the best result so far. We can stop immediately.
+ break;
}
+ }
- // This is a decent match. But something else could beat it, store
- // it if it's the best match we have so far, but keep searching.
- if (bestWeight == null || weight > bestWeight)
- {
- matchedSpans?.Insert(0, candidateMatchSpan);
+ return bestResult;
+ }
- bestWeight = weight;
- bestMatchedSpans = matchedSpans;
- }
+ ///
+ /// Updates the currently stored 'best result' if the current result is better.
+ /// Returns 'true' if no further work is required and we can break early, or
+ /// 'false' if we need to keep on going.
+ ///
+ /// If 'weight' is better than 'bestWeight' and matchSpanToAdd is not null, then
+ /// matchSpanToAdd will be added to matchedSpansInReverse.
+ ///
+ private bool UpdateBestResultIfBetter(
+ CamelCaseResult result, ref CamelCaseResult? bestResult, TextSpan? matchSpanToAdd)
+ {
+ if (matchSpanToAdd != null)
+ {
+ result = result.WithAddedMatchedSpan(matchSpanToAdd.Value);
+ }
+
+ if (!IsBetter(result, bestResult))
+ {
+ // Even though we matched this current candidate hump we failed to match
+ // the remainder of the pattern. Continue to the next candidate hump
+ // to see if our pattern character will match it and potentially succeed.
+ result.Free();
+
+ // We need to keep going.
+ return false;
+ }
+
+ // This was result was better than whatever previous best result we had was.
+ // Free and overwrite the existing best results, and keep going.
+ bestResult?.Free();
+ bestResult = result;
+
+ // We found a path that allowed us to match everything contiguously
+ // from the beginning. This is the best match possible. So we can
+ // just break out now and return this result.
+ return GetKind(result) == PatternMatchKind.CamelCaseExact;
+ }
+
+ private bool IsBetter(CamelCaseResult result, CamelCaseResult? currentBestResult)
+ {
+ if (currentBestResult == null)
+ {
+ // We have no current best. So this result is the best.
+ return true;
}
- return (bestWeight, bestMatchedSpans);
+ return GetKind(result) < GetKind(currentBestResult.Value);
}
private bool LowercaseSubstringsMatch(
diff --git a/src/Workspaces/Core/Portable/PatternMatching/CamelCaseResult.cs b/src/Workspaces/Core/Portable/PatternMatching/CamelCaseResult.cs
new file mode 100644
index 0000000000000..6fcdfdee61fca
--- /dev/null
+++ b/src/Workspaces/Core/Portable/PatternMatching/CamelCaseResult.cs
@@ -0,0 +1,72 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Diagnostics;
+using Microsoft.CodeAnalysis.Shared.Utilities;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Microsoft.CodeAnalysis.PatternMatching
+{
+ internal partial class PatternMatcher
+ {
+ private struct CamelCaseResult
+ {
+ public readonly bool FromStart;
+ public readonly bool Contiguous;
+ public readonly int MatchCount;
+ public readonly ArrayBuilder MatchedSpansInReverse;
+
+ public CamelCaseResult(bool fromStart, bool contiguous, int matchCount, ArrayBuilder matchedSpansInReverse)
+ {
+ FromStart = fromStart;
+ Contiguous = contiguous;
+ MatchCount = matchCount;
+ MatchedSpansInReverse = matchedSpansInReverse;
+
+ Debug.Assert(matchedSpansInReverse == null || matchedSpansInReverse.Count == matchCount);
+ }
+
+ public void Free()
+ {
+ MatchedSpansInReverse?.Free();
+ }
+
+ public CamelCaseResult WithFromStart(bool fromStart)
+ => new CamelCaseResult(fromStart, Contiguous, MatchCount, MatchedSpansInReverse);
+
+ public CamelCaseResult WithAddedMatchedSpan(TextSpan value)
+ {
+ MatchedSpansInReverse?.Add(value);
+ return new CamelCaseResult(FromStart, Contiguous, MatchCount + 1, MatchedSpansInReverse);
+ }
+ }
+
+ private static PatternMatchKind GetCamelCaseKind(CamelCaseResult result, StringBreaks candidateHumps)
+ {
+ var toEnd = result.MatchCount == candidateHumps.GetCount();
+ if (result.FromStart)
+ {
+ if (result.Contiguous)
+ {
+ // We contiguously matched humps from the start of this candidate. If we
+ // matched all the humps, then this was an exact match, otherwise it was a
+ // contiguous prefix match
+ return toEnd
+ ? PatternMatchKind.CamelCaseExact
+ : PatternMatchKind.CamelCasePrefix;
+ }
+ else
+ {
+ return PatternMatchKind.CamelCaseNonContiguousPrefix;
+ }
+ }
+ else
+ {
+ // We didn't match from the start. Distinguish between a match whose humps are all
+ // contiguous, and one that isn't.
+ return result.Contiguous
+ ? PatternMatchKind.CamelCaseSubstring
+ : PatternMatchKind.CamelCaseNonContiguousSubstring;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Workspaces/Core/Portable/PatternMatching/ContainerPatternMatcher.cs b/src/Workspaces/Core/Portable/PatternMatching/ContainerPatternMatcher.cs
new file mode 100644
index 0000000000000..d925dc15619f0
--- /dev/null
+++ b/src/Workspaces/Core/Portable/PatternMatching/ContainerPatternMatcher.cs
@@ -0,0 +1,101 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Globalization;
+using System.Linq;
+
+namespace Microsoft.CodeAnalysis.PatternMatching
+{
+ internal partial class PatternMatcher
+ {
+ private sealed partial class ContainerPatternMatcher : PatternMatcher
+ {
+ private readonly PatternSegment[] _patternSegments;
+ private readonly char[] _containerSplitCharacters;
+
+ public ContainerPatternMatcher(
+ string[] patternParts, char[] containerSplitCharacters,
+ CultureInfo culture,
+ bool allowFuzzyMatching = false)
+ : base(false, culture, allowFuzzyMatching)
+ {
+ _containerSplitCharacters = containerSplitCharacters;
+
+ _patternSegments = patternParts
+ .Select(text => new PatternSegment(text.Trim(), allowFuzzyMatching: allowFuzzyMatching))
+ .ToArray();
+
+ _invalidPattern = _patternSegments.Length == 0 || _patternSegments.Any(s => s.IsInvalid);
+ }
+
+ public override void Dispose()
+ {
+ base.Dispose();
+
+ foreach (var segment in _patternSegments)
+ {
+ segment.Dispose();
+ }
+ }
+
+ public override bool AddMatches(string container, ArrayBuilder matches)
+ {
+ if (SkipMatch(container))
+ {
+ return false;
+ }
+
+ return AddMatches(container, matches, fuzzyMatch: false) ||
+ AddMatches(container, matches, fuzzyMatch: true);
+ }
+
+ private bool AddMatches(string container, ArrayBuilder matches, bool fuzzyMatch)
+ {
+ if (fuzzyMatch && !_allowFuzzyMatching)
+ {
+ return false;
+ }
+
+ var tempContainerMatches = ArrayBuilder.GetInstance();
+
+ try
+ {
+ var containerParts = container.Split(_containerSplitCharacters, StringSplitOptions.RemoveEmptyEntries);
+
+ var relevantDotSeparatedSegmentLength = _patternSegments.Length;
+ if (_patternSegments.Length > containerParts.Length)
+ {
+ // There weren't enough container parts to match against the pattern parts.
+ // So this definitely doesn't match.
+ return false;
+ }
+
+ // So far so good. Now break up the container for the candidate and check if all
+ // the dotted parts match up correctly.
+
+ for (int i = _patternSegments.Length - 1, j = containerParts.Length - 1;
+ i >= 0;
+ i--, j--)
+ {
+ var segment = _patternSegments[i];
+ var containerName = containerParts[j];
+ if (!MatchPatternSegment(containerName, segment, tempContainerMatches, fuzzyMatch))
+ {
+ // This container didn't match the pattern piece. So there's no match at all.
+ return false;
+ }
+ }
+
+ // Success, this symbol's full name matched against the dotted name the user was asking
+ // about.
+ matches.AddRange(tempContainerMatches);
+ return true;
+ }
+ finally
+ {
+ tempContainerMatches.Free();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Workspaces/Core/Portable/PatternMatching/PatternMatch.cs b/src/Workspaces/Core/Portable/PatternMatching/PatternMatch.cs
index 23d920f5f3306..5dc1dd6cbafcb 100644
--- a/src/Workspaces/Core/Portable/PatternMatching/PatternMatch.cs
+++ b/src/Workspaces/Core/Portable/PatternMatching/PatternMatch.cs
@@ -9,11 +9,6 @@ namespace Microsoft.CodeAnalysis.PatternMatching
{
internal struct PatternMatch : IComparable
{
- ///
- /// The weight of a CamelCase match. A higher number indicates a more accurate match.
- ///
- public int? CamelCaseWeight { get; }
-
///
/// True if this was a case sensitive match.
///
@@ -36,11 +31,9 @@ internal PatternMatch(
PatternMatchKind resultType,
bool punctuationStripped,
bool isCaseSensitive,
- TextSpan? matchedSpan,
- int? camelCaseWeight = null)
+ TextSpan? matchedSpan)
: this(resultType, punctuationStripped, isCaseSensitive,
- matchedSpan == null ? ImmutableArray.Empty : ImmutableArray.Create(matchedSpan.Value),
- camelCaseWeight)
+ matchedSpan == null ? ImmutableArray.Empty : ImmutableArray.Create(matchedSpan.Value))
{
}
@@ -48,24 +41,17 @@ internal PatternMatch(
PatternMatchKind resultType,
bool punctuationStripped,
bool isCaseSensitive,
- ImmutableArray matchedSpans,
- int? camelCaseWeight = null)
+ ImmutableArray matchedSpans)
: this()
{
this.Kind = resultType;
this.IsCaseSensitive = isCaseSensitive;
- this.CamelCaseWeight = camelCaseWeight;
this.MatchedSpans = matchedSpans;
_punctuationStripped = punctuationStripped;
-
- if ((resultType == PatternMatchKind.CamelCase) != camelCaseWeight.HasValue)
- {
- throw new ArgumentException("A CamelCase weight must be specified if and only if the resultType is CamelCase.");
- }
}
public PatternMatch WithMatchedSpans(ImmutableArray matchedSpans)
- => new PatternMatch(Kind, _punctuationStripped, IsCaseSensitive, matchedSpans, CamelCaseWeight);
+ => new PatternMatch(Kind, _punctuationStripped, IsCaseSensitive, matchedSpans);
public int CompareTo(PatternMatch other)
=> CompareTo(other, ignoreCase: false);
@@ -74,7 +60,6 @@ public int CompareTo(PatternMatch other, bool ignoreCase)
{
int diff;
if ((diff = CompareType(this, other)) != 0 ||
- (diff = CompareCamelCase(this, other)) != 0 ||
(diff = CompareCase(this, other, ignoreCase)) != 0 ||
(diff = ComparePunctuation(this, other)) != 0)
{
@@ -111,17 +96,5 @@ private static int CompareCase(PatternMatch result1, PatternMatch result2, bool
private static int CompareType(PatternMatch result1, PatternMatch result2)
=> result1.Kind - result2.Kind;
-
- private static int CompareCamelCase(PatternMatch result1, PatternMatch result2)
- {
- if (result1.Kind == PatternMatchKind.CamelCase && result2.Kind == PatternMatchKind.CamelCase)
- {
- // Swap the values here. If result1 has a higher weight, then we want it to come
- // first.
- return result2.CamelCaseWeight.Value - result1.CamelCaseWeight.Value;
- }
-
- return 0;
- }
}
}
\ No newline at end of file
diff --git a/src/Workspaces/Core/Portable/PatternMatching/PatternMatchKind.cs b/src/Workspaces/Core/Portable/PatternMatching/PatternMatchKind.cs
index 977b761cf8dfe..17cd71ace4b49 100644
--- a/src/Workspaces/Core/Portable/PatternMatching/PatternMatchKind.cs
+++ b/src/Workspaces/Core/Portable/PatternMatching/PatternMatchKind.cs
@@ -24,10 +24,61 @@ internal enum PatternMatchKind
///
Substring,
+ // Note: CamelCased matches are ordered from best to worst.
+
+ ///
+ /// All camel-humps in the pattern matched a camel-hump in the candidate. All camel-humps
+ /// in the candidate were matched by a camel-hump in the pattern.
+ ///
+ /// Example: "CFPS" matching "CodeFixProviderService"
+ /// Example: "cfps" matching "CodeFixProviderService"
+ /// Example: "CoFiPrSe" matching "CodeFixProviderService"
+ ///
+ CamelCaseExact,
+
+ ///
+ /// All camel-humps in the pattern matched a camel-hump in the candidate. The first camel-hump
+ /// in the pattern matched the first camel-hump in the candidate. There was no gap in the camel-
+ /// humps in the candidate that were matched.
+ ///
+ /// Example: "CFP" matching "CodeFixProviderService"
+ /// Example: "cfp" matching "CodeFixProviderService"
+ /// Example: "CoFiPRo" matching "CodeFixProviderService"
+ ///
+ CamelCasePrefix,
+
+ ///
+ /// All camel-humps in the pattern matched a camel-hump in the candidate. The first camel-hump
+ /// in the pattern matched the first camel-hump in the candidate. There was at least one gap in
+ /// the camel-humps in the candidate that were matched.
+ ///
+ /// Example: "CP" matching "CodeFixProviderService"
+ /// Example: "cp" matching "CodeFixProviderService"
+ /// Example: "CoProv" matching "CodeFixProviderService"
+ ///
+ CamelCaseNonContiguousPrefix,
+
+ ///
+ /// All camel-humps in the pattern matched a camel-hump in the candidate. The first camel-hump
+ /// in the pattern did not match the first camel-hump in the pattern. There was no gap in the camel-
+ /// humps in the candidate that were matched.
+ ///
+ /// Example: "FP" matching "CodeFixProviderService"
+ /// Example: "fp" matching "CodeFixProviderService"
+ /// Example: "FixPro" matching "CodeFixProviderService"
+ ///
+ CamelCaseSubstring,
+
///
- /// The pattern matched the CamelCased candidate string.
+ /// All camel-humps in the pattern matched a camel-hump in the candidate. The first camel-hump
+ /// in the pattern did not match the first camel-hump in the pattern. There was at least one gap in
+ /// the camel-humps in the candidate that were matched.
+ ///
+ /// Example: "FS" matching "CodeFixProviderService"
+ /// Example: "fs" matching "CodeFixProviderService"
+ /// Example: "FixSer" matching "CodeFixProviderService"
///
- CamelCase,
+ CamelCaseNonContiguousSubstring,
///
/// The pattern matches the candidate in a fuzzy manner. Fuzzy matching allows for
diff --git a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.TextChunk.cs b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.TextChunk.cs
index a5f4ae3d685ff..d7cb5aeb70c37 100644
--- a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.TextChunk.cs
+++ b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.TextChunk.cs
@@ -32,13 +32,14 @@ public TextChunk(string text, bool allowFuzzingMatching)
this.Text = text;
this.CharacterSpans = StringBreaker.BreakIntoCharacterParts(text);
this.SimilarityChecker = allowFuzzingMatching
- ? new WordSimilarityChecker(text, substringsAreSimilar: false)
+ ? WordSimilarityChecker.Allocate(text, substringsAreSimilar: false)
: null;
}
public void Dispose()
{
- this.SimilarityChecker?.Dispose();
+ this.CharacterSpans.Dispose();
+ this.SimilarityChecker?.Free();
}
}
}
diff --git a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.cs b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.cs
index f936a15052453..93dbb053e84c9 100644
--- a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.cs
+++ b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
-using System.Linq;
using Microsoft.CodeAnalysis.Shared;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
@@ -19,21 +18,19 @@ namespace Microsoft.CodeAnalysis.PatternMatching
/// Also, while the pattern matcher is culture aware, it uses the culture specified in the
/// constructor.
///
- internal sealed partial class PatternMatcher : IDisposable
+ internal abstract partial class PatternMatcher : IDisposable
{
+ private static readonly char[] s_dotCharacterArray = { '.' };
+
public const int NoBonus = 0;
public const int CamelCaseContiguousBonus = 1;
public const int CamelCaseMatchesFromStartBonus = 2;
public const int CamelCaseMaxWeight = CamelCaseContiguousBonus + CamelCaseMatchesFromStartBonus;
- private static readonly char[] s_dotCharacterArray = { '.' };
-
private readonly object _gate = new object();
+ private readonly bool _includeMatchedSpans;
private readonly bool _allowFuzzyMatching;
- private readonly bool _invalidPattern;
- private readonly PatternSegment _fullPatternSegment;
- private readonly PatternSegment[] _dotSeparatedPatternSegments;
private readonly Dictionary _stringToWordSpans = new Dictionary();
private static readonly Func _breakIntoWordSpans = StringBreaker.BreakIntoWordParts;
@@ -41,217 +38,80 @@ internal sealed partial class PatternMatcher : IDisposable
// PERF: Cache the culture's compareInfo to avoid the overhead of asking for them repeatedly in inner loops
private readonly CompareInfo _compareInfo;
+ private bool _invalidPattern;
///
/// Construct a new PatternMatcher using the specified culture.
///
- /// The pattern to make the pattern matcher for.
/// The culture to use for string searching and comparison.
+ /// Whether or not the matching parts of the candidate should be supplied in results.
/// Whether or not close matches should count as matches.
- public PatternMatcher(
- string pattern,
- CultureInfo culture = null,
+ protected PatternMatcher(
+ bool includeMatchedSpans,
+ CultureInfo culture,
bool allowFuzzyMatching = false)
{
culture = culture ?? CultureInfo.CurrentCulture;
- pattern = pattern.Trim();
_compareInfo = culture.CompareInfo;
+ _includeMatchedSpans = includeMatchedSpans;
_allowFuzzyMatching = allowFuzzyMatching;
-
- _fullPatternSegment = new PatternSegment(pattern, allowFuzzyMatching);
-
- if (pattern.IndexOf('.') < 0)
- {
- // PERF: Avoid string.Split allocations when the pattern doesn't contain a dot.
- _dotSeparatedPatternSegments = pattern.Length > 0
- ? new PatternSegment[1] { _fullPatternSegment }
- : Array.Empty();
- }
- else
- {
- _dotSeparatedPatternSegments = pattern.Split(s_dotCharacterArray, StringSplitOptions.RemoveEmptyEntries)
- .Select(text => new PatternSegment(text.Trim(), allowFuzzyMatching))
- .ToArray();
- }
-
- _invalidPattern = _dotSeparatedPatternSegments.Length == 0 || _dotSeparatedPatternSegments.Any(s => s.IsInvalid);
}
- public void Dispose()
+ public virtual void Dispose()
{
- _fullPatternSegment.Dispose();
- foreach (var segment in _dotSeparatedPatternSegments)
+ foreach (var kvp in _stringToWordSpans)
{
- segment.Dispose();
+ kvp.Value.Dispose();
}
- }
- public bool IsDottedPattern => _dotSeparatedPatternSegments.Length > 1;
-
- private bool SkipMatch(string candidate)
- {
- return _invalidPattern || string.IsNullOrWhiteSpace(candidate);
+ _stringToWordSpans.Clear();
}
- public ImmutableArray GetMatches(string candidate)
- => GetMatches(candidate, includeMatchSpans: false);
+ //public bool IsDottedPattern => _dotSeparatedPatternSegments.Length > 1;
- ///
- /// Determines if a given candidate string matches under a multiple word query text, as you
- /// would find in features like Navigate To.
- ///
- /// The word being tested.
- /// Whether or not the matched spans should be included with results
- /// If this was a match, a set of match types that occurred while matching the
- /// patterns. If it was not a match, it returns null.
- public ImmutableArray GetMatches(string candidate, bool includeMatchSpans)
+ //private bool SkipMatch(string candidate)
+
+ public static PatternMatcher CreatePatternMatcher(
+ string pattern,
+ CultureInfo culture = null,
+ bool includeMatchedSpans = false,
+ bool allowFuzzyMatching = false)
{
- if (SkipMatch(candidate))
- {
- return ImmutableArray.Empty;
- }
-
- var result = MatchPatternSegment(candidate, includeMatchSpans, _fullPatternSegment, fuzzyMatch: true);
- if (!result.IsEmpty)
- {
- return result;
- }
-
- return MatchPatternSegment(candidate, includeMatchSpans, _fullPatternSegment, fuzzyMatch: false);
+ return new SimplePatternMatcher(pattern, culture, includeMatchedSpans, allowFuzzyMatching);
}
- public ImmutableArray GetMatchesForLastSegmentOfPattern(string candidate)
+ public static PatternMatcher CreateContainerPatternMatcher(
+ string[] patternParts,
+ char[] containerSplitCharacters,
+ CultureInfo culture = null,
+ bool allowFuzzyMatching = false)
{
- if (SkipMatch(candidate))
- {
- return ImmutableArray.Empty;
- }
-
- var result = MatchPatternSegment(candidate, includeMatchSpans: false, patternSegment: _dotSeparatedPatternSegments.Last(), fuzzyMatch: false);
- if (!result.IsEmpty)
- {
- return result;
- }
-
- return MatchPatternSegment(candidate, includeMatchSpans: false, patternSegment: _dotSeparatedPatternSegments.Last(), fuzzyMatch: true);
+ return new ContainerPatternMatcher(
+ patternParts, containerSplitCharacters, culture, allowFuzzyMatching);
}
- public PatternMatches GetMatches(string candidate, string dottedContainer)
- => GetMatches(candidate, dottedContainer, includeMatchSpans: false);
-
- ///
- /// Matches a pattern against a candidate, and an optional dotted container for the
- /// candidate. If the container is provided, and the pattern itself contains dots, then
- /// the pattern will be tested against the candidate and container. Specifically,
- /// the part of the pattern after the last dot will be tested against the candidate. If
- /// a match occurs there, then the remaining dot-separated portions of the pattern will
- /// be tested against every successive portion of the container from right to left.
- ///
- /// i.e. if you have a pattern of "Con.WL" and the candidate is "WriteLine" with a
- /// dotted container of "System.Console", then "WL" will be tested against "WriteLine".
- /// With a match found there, "Con" will then be tested against "Console".
- ///
- public PatternMatches GetMatches(
- string candidate, string dottedContainer, bool includeMatchSpans)
+ public static PatternMatcher CreateDotSeparatedContainerMatcher(
+ string pattern,
+ CultureInfo culture = null,
+ bool allowFuzzyMatching = false)
{
- var result = GetMatches(candidate, dottedContainer, includeMatchSpans, fuzzyMatch: false);
- if (!result.IsEmpty)
- {
- return result;
- }
-
- return GetMatches(candidate, dottedContainer, includeMatchSpans, fuzzyMatch: true);
+ return CreateContainerPatternMatcher(
+ pattern.Split(s_dotCharacterArray, StringSplitOptions.RemoveEmptyEntries),
+ s_dotCharacterArray, culture, allowFuzzyMatching);
}
- private PatternMatches GetMatches(
- string candidate, string dottedContainer, bool includeMatchSpans, bool fuzzyMatch)
+ internal static (string name, string containerOpt) GetNameAndContainer(string pattern)
{
- if (fuzzyMatch && !_allowFuzzyMatching)
- {
- return PatternMatches.Empty;
- }
-
- if (SkipMatch(candidate))
- {
- return PatternMatches.Empty;
- }
-
- // First, check that the last part of the dot separated pattern matches the name of the
- // candidate. If not, then there's no point in proceeding and doing the more
- // expensive work.
- var candidateMatch = MatchPatternSegment(candidate, includeMatchSpans, _dotSeparatedPatternSegments.Last(), fuzzyMatch);
- if (candidateMatch.IsDefaultOrEmpty)
- {
- return PatternMatches.Empty;
- }
-
- dottedContainer = dottedContainer ?? string.Empty;
- var containerParts = dottedContainer.Split(s_dotCharacterArray, StringSplitOptions.RemoveEmptyEntries);
-
- // -1 because the last part was checked against the name, and only the rest
- // of the parts are checked against the container.
- var relevantDotSeparatedSegmentLength = _dotSeparatedPatternSegments.Length - 1;
- if (relevantDotSeparatedSegmentLength > containerParts.Length)
- {
- // There weren't enough container parts to match against the pattern parts.
- // So this definitely doesn't match.
- return PatternMatches.Empty;
- }
-
- // So far so good. Now break up the container for the candidate and check if all
- // the dotted parts match up correctly.
- var containerMatches = ArrayBuilder.GetInstance();
-
- try
- {
- // Don't need to check the last segment. We did that as the very first bail out step.
- for (int i = 0, j = containerParts.Length - relevantDotSeparatedSegmentLength;
- i < relevantDotSeparatedSegmentLength;
- i++, j++)
- {
- var segment = _dotSeparatedPatternSegments[i];
- var containerName = containerParts[j];
- var containerMatch = MatchPatternSegment(containerName, includeMatchSpans, segment, fuzzyMatch);
- if (containerMatch.IsDefaultOrEmpty)
- {
- // This container didn't match the pattern piece. So there's no match at all.
- return PatternMatches.Empty;
- }
-
- containerMatches.AddRange(containerMatch);
- }
-
- // Success, this symbol's full name matched against the dotted name the user was asking
- // about.
- return new PatternMatches(candidateMatch, containerMatches.ToImmutable());
- }
- finally
- {
- containerMatches.Free();
- }
+ var dotIndex = pattern.LastIndexOf('.');
+ var containsDots = dotIndex >= 0;
+ return containsDots
+ ? (name: pattern.Substring(dotIndex + 1), containerOpt: pattern.Substring(0, dotIndex))
+ : (name: pattern, containerOpt: null);
}
- ///
- /// Determines if a given candidate string matches under a multiple word query text, as you
- /// would find in features like Navigate To.
- ///
- ///
- /// PERF: This is slightly faster and uses less memory than
- /// so, unless you need to know the full set of matches, use this version.
- ///
- /// The word being tested.
- /// Whether or not the matched spans should be included with results
- /// If this was a match, the first element of the set of match types that occurred while matching the
- /// patterns. If it was not a match, it returns null.
- public PatternMatch? GetFirstMatch(string candidate, bool inludeMatchSpans = false)
- {
- if (SkipMatch(candidate))
- {
- return null;
- }
+ public abstract bool AddMatches(string candidate, ArrayBuilder matches);
- return MatchPatternSegment(candidate, inludeMatchSpans, _fullPatternSegment, wantAllMatches: false, allMatches: out _, fuzzyMatch: false) ??
- MatchPatternSegment(candidate, inludeMatchSpans, _fullPatternSegment, wantAllMatches: false, allMatches: out _, fuzzyMatch: true);
- }
+ private bool SkipMatch(string candidate)
+ => _invalidPattern || string.IsNullOrWhiteSpace(candidate);
private StringBreaks GetWordSpans(string word)
{
@@ -261,13 +121,6 @@ private StringBreaks GetWordSpans(string word)
}
}
- internal PatternMatch? MatchSingleWordPattern_ForTestingOnly(string candidate)
- {
- return MatchPatternChunk(candidate, includeMatchSpans: true,
- patternChunk: _fullPatternSegment.TotalTextChunk, punctuationStripped: false,
- fuzzyMatch: false);
- }
-
private static bool ContainsUpperCaseLetter(string pattern)
{
// Expansion of "foreach(char ch in pattern)" to avoid a CharEnumerator allocation
@@ -284,10 +137,33 @@ private static bool ContainsUpperCaseLetter(string pattern)
private PatternMatch? MatchPatternChunk(
string candidate,
- bool includeMatchSpans,
TextChunk patternChunk,
bool punctuationStripped,
bool fuzzyMatch)
+ {
+ return fuzzyMatch
+ ? FuzzyMatchPatternChunk(candidate, patternChunk, punctuationStripped)
+ : NonFuzzyMatchPatternChunk(candidate, patternChunk, punctuationStripped);
+ }
+
+ private PatternMatch? FuzzyMatchPatternChunk(
+ string candidate,
+ TextChunk patternChunk,
+ bool punctuationStripped)
+ {
+ if (patternChunk.SimilarityChecker.AreSimilar(candidate))
+ {
+ return new PatternMatch(
+ PatternMatchKind.Fuzzy, punctuationStripped, isCaseSensitive: false, matchedSpan: null);
+ }
+
+ return null;
+ }
+
+ private PatternMatch? NonFuzzyMatchPatternChunk(
+ string candidate,
+ TextChunk patternChunk,
+ bool punctuationStripped)
{
int caseInsensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.IgnoreCase);
if (caseInsensitiveIndex == 0)
@@ -298,7 +174,7 @@ private static bool ContainsUpperCaseLetter(string pattern)
// sensitive manner. If it does, return that there was an exact match.
return new PatternMatch(
PatternMatchKind.Exact, punctuationStripped, isCaseSensitive: candidate == patternChunk.Text,
- matchedSpan: GetMatchedSpan(includeMatchSpans, 0, candidate.Length));
+ matchedSpan: GetMatchedSpan(0, candidate.Length));
}
else
{
@@ -306,7 +182,7 @@ private static bool ContainsUpperCaseLetter(string pattern)
// manner. If it does, return that there was a prefix match.
return new PatternMatch(
PatternMatchKind.Prefix, punctuationStripped, isCaseSensitive: _compareInfo.IsPrefix(candidate, patternChunk.Text),
- matchedSpan: GetMatchedSpan(includeMatchSpans, 0, patternChunk.Text.Length));
+ matchedSpan: GetMatchedSpan(0, patternChunk.Text.Length));
}
}
@@ -335,18 +211,18 @@ private static bool ContainsUpperCaseLetter(string pattern)
isCaseSensitive: PartStartsWith(
candidate, new TextSpan(caseInsensitiveIndex, patternChunk.Text.Length),
patternChunk.Text, CompareOptions.None),
- matchedSpan: GetMatchedSpan(includeMatchSpans, caseInsensitiveIndex, patternChunk.Text.Length));
+ matchedSpan: GetMatchedSpan(caseInsensitiveIndex, patternChunk.Text.Length));
}
var wordSpans = GetWordSpans(candidate);
- for (int i = 0; i < wordSpans.Count; i++)
+ for (int i = 0, n = wordSpans.GetCount(); i < n; i++)
{
var span = wordSpans[i];
if (PartStartsWith(candidate, span, patternChunk.Text, CompareOptions.IgnoreCase))
{
return new PatternMatch(PatternMatchKind.Substring, punctuationStripped,
isCaseSensitive: PartStartsWith(candidate, span, patternChunk.Text, CompareOptions.None),
- matchedSpan: GetMatchedSpan(includeMatchSpans, span.Start, patternChunk.Text.Length));
+ matchedSpan: GetMatchedSpan(span.Start, patternChunk.Text.Length));
}
}
}
@@ -361,13 +237,12 @@ private static bool ContainsUpperCaseLetter(string pattern)
{
return new PatternMatch(
PatternMatchKind.Substring, punctuationStripped, isCaseSensitive: true,
- matchedSpan: GetMatchedSpan(includeMatchSpans, caseSensitiveIndex, patternChunk.Text.Length));
+ matchedSpan: GetMatchedSpan(caseSensitiveIndex, patternChunk.Text.Length));
}
}
var match = TryCamelCaseMatch(
- candidate, includeMatchSpans, patternChunk,
- punctuationStripped, isLowercase);
+ candidate, patternChunk, punctuationStripped, isLowercase);
if (match.HasValue)
{
return match.Value;
@@ -390,34 +265,16 @@ private static bool ContainsUpperCaseLetter(string pattern)
{
return new PatternMatch(
PatternMatchKind.Substring, punctuationStripped, isCaseSensitive: false,
- matchedSpan: GetMatchedSpan(includeMatchSpans, caseInsensitiveIndex, patternChunk.Text.Length));
+ matchedSpan: GetMatchedSpan(caseInsensitiveIndex, patternChunk.Text.Length));
}
}
}
- if (fuzzyMatch)
- {
- if (patternChunk.SimilarityChecker.AreSimilar(candidate))
- {
- return new PatternMatch(
- PatternMatchKind.Fuzzy, punctuationStripped, isCaseSensitive: false, matchedSpan: null);
- }
- }
-
return null;
}
- private ImmutableArray GetMatchedSpans(bool includeMatchSpans, List matchedSpans)
- {
- return includeMatchSpans
- ? new NormalizedTextSpanCollection(matchedSpans).ToImmutableArray()
- : ImmutableArray.Empty;
- }
-
- private static TextSpan? GetMatchedSpan(bool includeMatchSpans, int start, int length)
- {
- return includeMatchSpans ? new TextSpan(start, length) : (TextSpan?)null;
- }
+ private TextSpan? GetMatchedSpan(int start, int length)
+ => _includeMatchedSpans ? new TextSpan(start, length) : (TextSpan?)null;
private static bool ContainsSpaceOrAsterisk(string text)
{
@@ -433,24 +290,6 @@ private static bool ContainsSpaceOrAsterisk(string text)
return false;
}
- private ImmutableArray MatchPatternSegment(
- string candidate, bool includeMatchSpans, PatternSegment patternSegment, bool fuzzyMatch)
- {
- if (fuzzyMatch && !_allowFuzzyMatching)
- {
- return ImmutableArray.Empty;
- }
-
- var singleMatch = MatchPatternSegment(candidate, includeMatchSpans, patternSegment,
- wantAllMatches: true, fuzzyMatch: fuzzyMatch, allMatches: out var matches);
- if (singleMatch.HasValue)
- {
- return ImmutableArray.Create(singleMatch.Value);
- }
-
- return matches;
- }
-
///
/// Internal helper for MatchPatternInternal
///
@@ -462,24 +301,18 @@ private ImmutableArray MatchPatternSegment(
///
/// The word being tested.
/// The segment of the pattern to check against the candidate.
- /// Does the caller want all matches or just the first?
+ /// The result array to place the matches in.
/// If a fuzzy match should be performed
- /// If is true, and there's more than one match, then the list of all matches.
- /// Whether or not the matched spans should be included with results
/// If there's only one match, then the return value is that match. Otherwise it is null.
- private PatternMatch? MatchPatternSegment(
+ private bool MatchPatternSegment(
string candidate,
- bool includeMatchSpans,
PatternSegment segment,
- bool wantAllMatches,
- bool fuzzyMatch,
- out ImmutableArray allMatches)
+ ArrayBuilder matches,
+ bool fuzzyMatch)
{
- allMatches = ImmutableArray.Empty;
-
if (fuzzyMatch && !_allowFuzzyMatching)
{
- return null;
+ return false;
}
// First check if the segment matches as is. This is also useful if the segment contains
@@ -491,11 +324,12 @@ private ImmutableArray MatchPatternSegment(
// multi-word segment.
if (!ContainsSpaceOrAsterisk(segment.TotalTextChunk.Text))
{
- var match = MatchPatternChunk(candidate, includeMatchSpans,
- segment.TotalTextChunk, punctuationStripped: false, fuzzyMatch: fuzzyMatch);
+ var match = MatchPatternChunk(
+ candidate, segment.TotalTextChunk, punctuationStripped: false, fuzzyMatch: fuzzyMatch);
if (match != null)
{
- return match;
+ matches.Add(match.Value);
+ return true;
}
}
@@ -539,7 +373,7 @@ private ImmutableArray MatchPatternSegment(
//
// Only if all words have some sort of match is the pattern considered matched.
- var matches = ArrayBuilder.GetInstance();
+ var tempMatches = ArrayBuilder.GetInstance();
try
{
@@ -547,28 +381,22 @@ private ImmutableArray MatchPatternSegment(
foreach (var subWordTextChunk in subWordTextChunks)
{
// Try to match the candidate with this word
- var result = MatchPatternChunk(candidate, includeMatchSpans,
- subWordTextChunk, punctuationStripped: true, fuzzyMatch: fuzzyMatch);
+ var result = MatchPatternChunk(
+ candidate, subWordTextChunk, punctuationStripped: true, fuzzyMatch: fuzzyMatch);
if (result == null)
{
- return null;
+ return false;
}
- if (!wantAllMatches || subWordTextChunks.Length == 1)
- {
- // Stop at the first word
- return result;
- }
-
- matches.Add(result.Value);
+ tempMatches.Add(result.Value);
}
- allMatches = matches.ToImmutable();
- return null;
+ matches.AddRange(tempMatches);
+ return tempMatches.Count > 0;
}
finally
{
- matches.Free();
+ tempMatches.Free();
}
}
@@ -608,7 +436,7 @@ private bool PartStartsWith(string candidate, TextSpan candidatePart, string pat
=> PartStartsWith(candidate, candidatePart, pattern, new TextSpan(0, pattern.Length), compareOptions);
private PatternMatch? TryCamelCaseMatch(
- string candidate, bool includeMatchSpans, TextChunk patternChunk,
+ string candidate, TextChunk patternChunk,
bool punctuationStripped, bool isLowercase)
{
if (isLowercase)
@@ -616,36 +444,36 @@ private bool PartStartsWith(string candidate, TextSpan candidatePart, string pat
// e) If the word was entirely lowercase, then attempt a special lower cased camel cased
// match. i.e. cofipro would match CodeFixProvider.
var candidateParts = GetWordSpans(candidate);
- var camelCaseWeight = TryAllLowerCamelCaseMatch(
- candidate, includeMatchSpans, candidateParts, patternChunk, out var matchedSpans);
- if (camelCaseWeight.HasValue)
+ var camelCaseKind = TryAllLowerCamelCaseMatch(
+ candidate, candidateParts, patternChunk, out var matchedSpans);
+ if (camelCaseKind.HasValue)
{
return new PatternMatch(
- PatternMatchKind.CamelCase, punctuationStripped, isCaseSensitive: false, camelCaseWeight: camelCaseWeight,
- matchedSpans: GetMatchedSpans(includeMatchSpans, matchedSpans));
+ camelCaseKind.Value, punctuationStripped, isCaseSensitive: false,
+ matchedSpans: matchedSpans);
}
}
else
{
// f) If the word was not entirely lowercase, then attempt a normal camel cased match.
// i.e. CoFiPro would match CodeFixProvider, but CofiPro would not.
- if (patternChunk.CharacterSpans.Count > 0)
+ if (patternChunk.CharacterSpans.GetCount() > 0)
{
- var candidateParts = GetWordSpans(candidate);
- var camelCaseWeight = TryUpperCaseCamelCaseMatch(candidate, includeMatchSpans, candidateParts, patternChunk, CompareOptions.None, out var matchedSpans);
- if (camelCaseWeight.HasValue)
+ var candidateHumps = GetWordSpans(candidate);
+ var camelCaseKind = TryUpperCaseCamelCaseMatch(candidate, candidateHumps, patternChunk, CompareOptions.None, out var matchedSpans);
+ if (camelCaseKind.HasValue)
{
return new PatternMatch(
- PatternMatchKind.CamelCase, punctuationStripped, isCaseSensitive: true, camelCaseWeight: camelCaseWeight,
- matchedSpans: GetMatchedSpans(includeMatchSpans, matchedSpans));
+ camelCaseKind.Value, punctuationStripped, isCaseSensitive: true,
+ matchedSpans: matchedSpans);
}
- camelCaseWeight = TryUpperCaseCamelCaseMatch(candidate, includeMatchSpans, candidateParts, patternChunk, CompareOptions.IgnoreCase, out matchedSpans);
- if (camelCaseWeight.HasValue)
+ camelCaseKind = TryUpperCaseCamelCaseMatch(candidate, candidateHumps, patternChunk, CompareOptions.IgnoreCase, out matchedSpans);
+ if (camelCaseKind.HasValue)
{
return new PatternMatch(
- PatternMatchKind.CamelCase, punctuationStripped, isCaseSensitive: false, camelCaseWeight: camelCaseWeight,
- matchedSpans: GetMatchedSpans(includeMatchSpans, matchedSpans));
+ camelCaseKind.Value, punctuationStripped, isCaseSensitive: false,
+ matchedSpans: matchedSpans);
}
}
}
@@ -653,114 +481,103 @@ private bool PartStartsWith(string candidate, TextSpan candidatePart, string pat
return null;
}
- private int? TryAllLowerCamelCaseMatch(
+ private PatternMatchKind? TryAllLowerCamelCaseMatch(
string candidate,
- bool includeMatchedSpans,
StringBreaks candidateParts,
TextChunk patternChunk,
- out List matchedSpans)
+ out ImmutableArray matchedSpans)
{
- var matcher = new AllLowerCamelCaseMatcher(candidate, includeMatchedSpans, candidateParts, patternChunk);
+ var matcher = new AllLowerCamelCaseMatcher(_includeMatchedSpans, candidate, candidateParts, patternChunk);
return matcher.TryMatch(out matchedSpans);
}
- private int? TryUpperCaseCamelCaseMatch(
+ private PatternMatchKind? TryUpperCaseCamelCaseMatch(
string candidate,
- bool includeMatchedSpans,
- StringBreaks candidateParts,
+ StringBreaks candidateHumps,
TextChunk patternChunk,
CompareOptions compareOption,
- out List matchedSpans)
+ out ImmutableArray matchedSpans)
{
- matchedSpans = null;
- var patternChunkCharacterSpans = patternChunk.CharacterSpans;
+ var patternHumps = patternChunk.CharacterSpans;
// Note: we may have more pattern parts than candidate parts. This is because multiple
// pattern parts may match a candidate part. For example "SiUI" against "SimpleUI".
// We'll have 3 pattern parts Si/U/I against two candidate parts Simple/UI. However, U
// and I will both match in UI.
- int currentCandidate = 0;
- int currentChunkSpan = 0;
+ int currentCandidateHump = 0;
+ int currentPatternHump = 0;
int? firstMatch = null;
bool? contiguous = null;
+ var patternHumpCount = patternHumps.GetCount();
+ var candidateHumpCount = candidateHumps.GetCount();
+
+ var matchSpans = ArrayBuilder.GetInstance();
while (true)
{
// Let's consider our termination cases
- if (currentChunkSpan == patternChunkCharacterSpans.Count)
+ if (currentPatternHump == patternHumpCount)
{
Contract.Requires(firstMatch.HasValue);
Contract.Requires(contiguous.HasValue);
- // We did match! We shall assign a weight to this
- var weight = 0;
+ var matchCount = matchSpans.Count;
+ matchedSpans = _includeMatchedSpans
+ ? new NormalizedTextSpanCollection(matchSpans).ToImmutableArray()
+ : ImmutableArray.Empty;
+ matchSpans.Free();
- // Was this contiguous?
- if (contiguous.Value)
- {
- weight += CamelCaseContiguousBonus;
- }
-
- // Did we start at the beginning of the candidate?
- if (firstMatch.Value == 0)
- {
- weight += CamelCaseMatchesFromStartBonus;
- }
-
- return weight;
+ var camelCaseResult = new CamelCaseResult(firstMatch == 0, contiguous.Value, matchCount, null);
+ return GetCamelCaseKind(camelCaseResult, candidateHumps);
}
- else if (currentCandidate == candidateParts.Count)
+ else if (currentCandidateHump == candidateHumpCount)
{
// No match, since we still have more of the pattern to hit
- matchedSpans = null;
+ matchedSpans = ImmutableArray.Empty;
+ matchSpans.Free();
return null;
}
- var candidatePart = candidateParts[currentCandidate];
+ var candidateHump = candidateHumps[currentCandidateHump];
bool gotOneMatchThisCandidate = false;
// Consider the case of matching SiUI against SimpleUIElement. The candidate parts
// will be Simple/UI/Element, and the pattern parts will be Si/U/I. We'll match 'Si'
// against 'Simple' first. Then we'll match 'U' against 'UI'. However, we want to
// still keep matching pattern parts against that candidate part.
- for (; currentChunkSpan < patternChunkCharacterSpans.Count; currentChunkSpan++)
+ for (; currentPatternHump < patternHumpCount; currentPatternHump++)
{
- var patternChunkCharacterSpan = patternChunkCharacterSpans[currentChunkSpan];
+ var patternChunkCharacterSpan = patternHumps[currentPatternHump];
if (gotOneMatchThisCandidate)
{
// We've already gotten one pattern part match in this candidate. We will
// only continue trying to consume pattern parts if the last part and this
// part are both upper case.
- if (!char.IsUpper(patternChunk.Text[patternChunkCharacterSpans[currentChunkSpan - 1].Start]) ||
- !char.IsUpper(patternChunk.Text[patternChunkCharacterSpans[currentChunkSpan].Start]))
+ if (!char.IsUpper(patternChunk.Text[patternHumps[currentPatternHump - 1].Start]) ||
+ !char.IsUpper(patternChunk.Text[patternHumps[currentPatternHump].Start]))
{
break;
}
}
- if (!PartStartsWith(candidate, candidatePart, patternChunk.Text, patternChunkCharacterSpan, compareOption))
+ if (!PartStartsWith(candidate, candidateHump, patternChunk.Text, patternChunkCharacterSpan, compareOption))
{
break;
}
- if (includeMatchedSpans)
- {
- matchedSpans = matchedSpans ?? new List();
- matchedSpans.Add(new TextSpan(candidatePart.Start, patternChunkCharacterSpan.Length));
- }
-
+ matchSpans.Add(new TextSpan(candidateHump.Start, patternChunkCharacterSpan.Length));
gotOneMatchThisCandidate = true;
- firstMatch = firstMatch ?? currentCandidate;
+ firstMatch = firstMatch ?? currentCandidateHump;
// If we were contiguous, then keep that value. If we weren't, then keep that
// value. If we don't know, then set the value to 'true' as an initial match is
// obviously contiguous.
contiguous = contiguous ?? true;
- candidatePart = new TextSpan(candidatePart.Start + patternChunkCharacterSpan.Length, candidatePart.Length - patternChunkCharacterSpan.Length);
+ candidateHump = new TextSpan(candidateHump.Start + patternChunkCharacterSpan.Length, candidateHump.Length - patternChunkCharacterSpan.Length);
}
// Check if we matched anything at all. If we didn't, then we need to unset the
@@ -773,7 +590,7 @@ private bool PartStartsWith(string candidate, TextSpan candidatePart, string pat
}
// Move onto the next candidate.
- currentCandidate++;
+ currentCandidateHump++;
}
}
}
diff --git a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcherExtensions.cs b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcherExtensions.cs
new file mode 100644
index 0000000000000..4d3b782817fec
--- /dev/null
+++ b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcherExtensions.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.PatternMatching
+{
+ internal static class PatternMatcherExtensions
+ {
+ public static PatternMatch? GetFirstMatch(this PatternMatcher matcher, string candidate)
+ {
+ var matches = ArrayBuilder.GetInstance();
+ matcher.AddMatches(candidate, matches);
+
+ var result = matches.FirstOrNullable();
+ matches.Free();
+
+ return result;
+ }
+
+ public static bool Matches(this PatternMatcher matcher, string candidate)
+ => matcher.GetFirstMatch(candidate) != null;
+ }
+}
\ No newline at end of file
diff --git a/src/Workspaces/Core/Portable/PatternMatching/PatternMatches.cs b/src/Workspaces/Core/Portable/PatternMatching/PatternMatches.cs
deleted file mode 100644
index 1455a57e88b28..0000000000000
--- a/src/Workspaces/Core/Portable/PatternMatching/PatternMatches.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Immutable;
-using System.Linq;
-
-namespace Microsoft.CodeAnalysis.PatternMatching
-{
- ///
- /// Pattern matching results returned when calling
- /// Specifically, this type individually provides the matches produced when matching against the
- /// 'candidate' text and the 'container' text.
- ///
- internal struct PatternMatches
- {
- public static readonly PatternMatches Empty = new PatternMatches(
- ImmutableArray.Empty, ImmutableArray.Empty);
-
- public readonly ImmutableArray CandidateMatches;
- public readonly ImmutableArray ContainerMatches;
-
- public PatternMatches(ImmutableArray candidateMatches,
- ImmutableArray containerMatches = default(ImmutableArray))
- {
- CandidateMatches = candidateMatches.NullToEmpty();
- ContainerMatches = containerMatches.NullToEmpty();
- }
-
- public bool IsEmpty => CandidateMatches.IsEmpty && ContainerMatches.IsEmpty;
-
- internal bool All(Func predicate)
- {
- return CandidateMatches.All(predicate) && ContainerMatches.All(predicate);
- }
-
- internal bool Any(Func predicate)
- {
- return CandidateMatches.Any(predicate) || ContainerMatches.Any(predicate);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Workspaces/Core/Portable/PatternMatching/SimplePatternMatcher.cs b/src/Workspaces/Core/Portable/PatternMatching/SimplePatternMatcher.cs
new file mode 100644
index 0000000000000..455ca2aeed90a
--- /dev/null
+++ b/src/Workspaces/Core/Portable/PatternMatching/SimplePatternMatcher.cs
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Globalization;
+
+namespace Microsoft.CodeAnalysis.PatternMatching
+{
+ internal partial class PatternMatcher
+ {
+ private sealed partial class SimplePatternMatcher : PatternMatcher
+ {
+ private readonly PatternSegment _fullPatternSegment;
+
+ public SimplePatternMatcher(
+ string pattern,
+ CultureInfo culture,
+ bool includeMatchedSpans,
+ bool allowFuzzyMatching)
+ : base(includeMatchedSpans, culture, allowFuzzyMatching)
+ {
+ pattern = pattern.Trim();
+
+ _fullPatternSegment = new PatternSegment(pattern, allowFuzzyMatching);
+ _invalidPattern = _fullPatternSegment.IsInvalid;
+ }
+
+ public override void Dispose()
+ {
+ base.Dispose();
+ _fullPatternSegment.Dispose();
+ }
+
+ ///
+ /// Determines if a given candidate string matches under a multiple word query text, as you
+ /// would find in features like Navigate To.
+ ///
+ /// If this was a match, a set of match types that occurred while matching the
+ /// patterns. If it was not a match, it returns null.
+ public override bool AddMatches(string candidate, ArrayBuilder matches)
+ {
+ if (SkipMatch(candidate))
+ {
+ return false;
+ }
+
+ return MatchPatternSegment(candidate, _fullPatternSegment, matches, fuzzyMatch: false) ||
+ MatchPatternSegment(candidate, _fullPatternSegment, matches, fuzzyMatch: true);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs b/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs
index e0b0e11d88169..cd5b36d1378aa 100644
--- a/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs
+++ b/src/Workspaces/Core/Portable/Remote/RemoteHostClient.cs
@@ -24,30 +24,6 @@ protected RemoteHostClient(Workspace workspace)
public event EventHandler ConnectionChanged;
- [Obsolete("use TryCreateServiceSessionAsync instead")]
- public Task CreateServiceSessionAsync(string serviceName, CancellationToken cancellationToken)
- {
- return CreateServiceSessionAsync(serviceName, callbackTarget: null, cancellationToken: cancellationToken);
- }
-
- [Obsolete("use TryCreateServiceSessionAsync instead")]
- public Task CreateServiceSessionAsync(string serviceName, object callbackTarget, CancellationToken cancellationToken)
- {
- return TryCreateServiceSessionAsync(serviceName, snapshot: null, callbackTarget: callbackTarget, cancellationToken: cancellationToken);
- }
-
- [Obsolete("use TryCreateServiceSessionAsync instead")]
- public Task CreateServiceSessionAsync(string serviceName, Solution solution, CancellationToken cancellationToken)
- {
- return CreateServiceSessionAsync(serviceName, solution, callbackTarget: null, cancellationToken: cancellationToken);
- }
-
- [Obsolete("use TryCreateServiceSessionAsync instead")]
- public Task CreateServiceSessionAsync(string serviceName, Solution solution, object callbackTarget, CancellationToken cancellationToken)
- {
- return TryCreateServiceSessionAsync(serviceName, solution, callbackTarget, cancellationToken);
- }
-
///
/// Create for the if possible.
/// otherwise, return null.
@@ -69,7 +45,7 @@ public Task TryCreateServiceSessionAsync(string serviceName, Cancellati
///
public Task TryCreateServiceSessionAsync(string serviceName, object callbackTarget, CancellationToken cancellationToken)
{
- return TryCreateServiceSessionAsync(serviceName, snapshot: null, callbackTarget: callbackTarget, cancellationToken: cancellationToken);
+ return TryCreateServiceSessionAsync(serviceName, getSnapshotAsync: null, callbackTarget: callbackTarget, cancellationToken: cancellationToken);
}
///
@@ -93,26 +69,15 @@ public Task TryCreateServiceSessionAsync(string serviceName, Solution s
///
public async Task TryCreateServiceSessionAsync(string serviceName, Solution solution, object callbackTarget, CancellationToken cancellationToken)
{
- var snapshot = await GetPinnedScopeAsync(solution, cancellationToken).ConfigureAwait(false);
- return await TryCreateServiceSessionAsync(serviceName, snapshot, callbackTarget, cancellationToken).ConfigureAwait(false);
+ Func> getSnapshotAsync = ct => GetPinnedScopeAsync(solution, ct);
+ return await TryCreateServiceSessionAsync(serviceName, getSnapshotAsync, callbackTarget, cancellationToken).ConfigureAwait(false);
}
protected abstract void OnConnected();
protected abstract void OnDisconnected();
- [Obsolete]
- protected virtual Task CreateServiceSessionAsync(string serviceName, PinnedRemotableDataScope snapshot, object callbackTarget, CancellationToken cancellationToken)
- {
- return SpecializedTasks.Default();
- }
-
- protected virtual Task TryCreateServiceSessionAsync(string serviceName, PinnedRemotableDataScope snapshot, object callbackTarget, CancellationToken cancellationToken)
- {
-#pragma warning disable CS0612 // leave it for now to not break backward compatibility
- return CreateServiceSessionAsync(serviceName, snapshot, callbackTarget, cancellationToken);
-#pragma warning restore CS0612 // Type or member is obsolete
- }
+ protected abstract Task TryCreateServiceSessionAsync(string serviceName, Optional>> getSnapshotAsync, object callbackTarget, CancellationToken cancellationToken);
internal void Shutdown()
{
@@ -210,7 +175,7 @@ public NoOpClient(Workspace workspace) :
}
protected override Task TryCreateServiceSessionAsync(
- string serviceName, PinnedRemotableDataScope snapshot, object callbackTarget, CancellationToken cancellationToken)
+ string serviceName, Optional>> getSnapshotAsync, object callbackTarget, CancellationToken cancellationToken)
{
return SpecializedTasks.Default();
}
diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ContextQuery/SyntaxContext.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ContextQuery/SyntaxContext.cs
index 0c86d555aed69..dd0b939662389 100644
--- a/src/Workspaces/Core/Portable/Shared/Extensions/ContextQuery/SyntaxContext.cs
+++ b/src/Workspaces/Core/Portable/Shared/Extensions/ContextQuery/SyntaxContext.cs
@@ -32,6 +32,7 @@ protected SyntaxContext(
bool isInImportsDirective,
bool isWithinAsyncMethod,
bool isPossibleTupleContext,
+ bool isPatternContext,
CancellationToken cancellationToken)
{
this.Workspace = workspace;
@@ -54,6 +55,7 @@ protected SyntaxContext(
this.IsInImportsDirective = isInImportsDirective;
this.IsWithinAsyncMethod = isWithinAsyncMethod;
this.IsPossibleTupleContext = isPossibleTupleContext;
+ this.IsPatternContext = isPatternContext;
this.InferredTypes = ComputeInferredTypes(workspace, semanticModel, position, cancellationToken);
}
@@ -83,6 +85,7 @@ protected SyntaxContext(
public bool IsInImportsDirective { get; }
public bool IsWithinAsyncMethod { get; }
public bool IsPossibleTupleContext { get; }
+ public bool IsPatternContext { get; }
public IEnumerable InferredTypes { get; }
diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ICodeDefinitionFactoryExtensions_CreateEqualsMethod.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ICodeDefinitionFactoryExtensions_CreateEqualsMethod.cs
index 9d2d48e7bfaff..b639847c1e605 100644
--- a/src/Workspaces/Core/Portable/Shared/Extensions/ICodeDefinitionFactoryExtensions_CreateEqualsMethod.cs
+++ b/src/Workspaces/Core/Portable/Shared/Extensions/ICodeDefinitionFactoryExtensions_CreateEqualsMethod.cs
@@ -286,7 +286,7 @@ private static ImmutableArray CreateIEquatableEqualsMethodStatements
public static string GetLocalName(this INamedTypeSymbol containingType)
{
var parts = StringBreaker.BreakIntoWordParts(containingType.Name);
- for (var i = parts.Count - 1; i >= 0; i--)
+ for (var i = parts.GetCount() - 1; i >= 0; i--)
{
var p = parts[i];
if (char.IsLetter(containingType.Name[p.Start]))
diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/StringBreaker.cs b/src/Workspaces/Core/Portable/Shared/Utilities/StringBreaker.cs
index 0785e57af16af..1afb76e83a925 100644
--- a/src/Workspaces/Core/Portable/Shared/Utilities/StringBreaker.cs
+++ b/src/Workspaces/Core/Portable/Shared/Utilities/StringBreaker.cs
@@ -14,9 +14,9 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities
/// bitfields are stored in a 32-bit bitmap.
/// Falls back to a if the encoding won't work.
///
- internal struct StringBreaks
+ internal partial struct StringBreaks : IDisposable
{
- private readonly List _spans;
+ private readonly ArrayBuilder _spans;
private readonly EncodedSpans _encodedSpans;
// These two values may be adjusted. The remaining constants are
@@ -32,27 +32,6 @@ internal struct StringBreaks
private const int MaxGap = (1 << BitsForGap) - 1;
private const int MaxLength = (1 << BitsForLength) - 1;
- private struct EncodedSpans
- {
- private const uint Mask = (1u << BitsPerEncodedSpan) - 1u;
- private uint _value;
-
- public byte this[int index]
- {
- get
- {
- Debug.Assert(index >= 0 && index < MaxShortSpans);
- return (byte)((_value >> (index * BitsPerEncodedSpan)) & Mask);
- }
- set
- {
- Debug.Assert(index >= 0 && index < MaxShortSpans);
- int shift = index * BitsPerEncodedSpan;
- _value = (_value & ~(Mask << shift)) | ((uint)value << shift);
- }
- }
- }
-
public static StringBreaks Create(string text, Func spanGenerator)
{
Debug.Assert(text != null);
@@ -92,9 +71,9 @@ private static bool TryEncodeSpans(string text, Func span
return true;
}
- private static List CreateFallbackList(string text, Func spanGenerator)
+ private static ArrayBuilder CreateFallbackList(string text, Func spanGenerator)
{
- List list = new List();
+ var list = ArrayBuilder.GetInstance();
for (int start = 0; start < text.Length;)
{
var span = spanGenerator(text, start);
@@ -119,29 +98,34 @@ private StringBreaks(EncodedSpans encodedSpans)
_spans = null;
}
- private StringBreaks(List spans)
+ private StringBreaks(ArrayBuilder spans)
{
_encodedSpans = default(EncodedSpans);
_spans = spans;
}
- public int Count
+ public void Dispose()
{
- get
+ _spans?.Free();
+ }
+
+ public int GetCount()
+ {
+ if (_spans != null)
{
- if (_spans != null)
- {
- return _spans.Count;
- }
+ return _spans.Count;
+ }
- int i;
- for (i = 0; i < MaxShortSpans; i++)
+ int i;
+ for (i = 0; i < MaxShortSpans; i++)
+ {
+ if (_encodedSpans[i] == 0)
{
- if (_encodedSpans[i] == 0) break;
+ break;
}
-
- return i;
}
+
+ return i;
}
public TextSpan this[int index]
diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/StringBreaks.EncodedSpans.cs b/src/Workspaces/Core/Portable/Shared/Utilities/StringBreaks.EncodedSpans.cs
new file mode 100644
index 0000000000000..c7f08a9929cf0
--- /dev/null
+++ b/src/Workspaces/Core/Portable/Shared/Utilities/StringBreaks.EncodedSpans.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Diagnostics;
+
+namespace Microsoft.CodeAnalysis.Shared.Utilities
+{
+ internal partial struct StringBreaks
+ {
+ private struct EncodedSpans
+ {
+ private const uint Mask = (1u << BitsPerEncodedSpan) - 1u;
+ private uint _value;
+
+ public byte this[int index]
+ {
+ get
+ {
+ Debug.Assert(index >= 0 && index < MaxShortSpans);
+ return (byte)((_value >> (index * BitsPerEncodedSpan)) & Mask);
+ }
+ set
+ {
+ Debug.Assert(index >= 0 && index < MaxShortSpans);
+ int shift = index * BitsPerEncodedSpan;
+ _value = (_value & ~(Mask << shift)) | ((uint)value << shift);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs b/src/Workspaces/Core/Portable/Shared/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs
index 691f86c0258b7..05c4f969fc963 100644
--- a/src/Workspaces/Core/Portable/Shared/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs
+++ b/src/Workspaces/Core/Portable/Shared/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs
@@ -211,8 +211,11 @@ private bool MethodsAreEquivalent(IMethodSymbol x, IMethodSymbol y, Dictionary
public static partial class Simplifier
{
diff --git a/src/Workspaces/Core/Portable/Tags/WellKnownTags.cs b/src/Workspaces/Core/Portable/Tags/WellKnownTags.cs
index 7157c9423fa04..8433c505faaa8 100644
--- a/src/Workspaces/Core/Portable/Tags/WellKnownTags.cs
+++ b/src/Workspaces/Core/Portable/Tags/WellKnownTags.cs
@@ -70,10 +70,13 @@ internal static class WellKnownTagArrays
internal static readonly ImmutableArray DelegatePrivate = ImmutableArray.Create(WellKnownTags.Delegate, WellKnownTags.Private);
internal static readonly ImmutableArray DelegateInternal = ImmutableArray.Create(WellKnownTags.Delegate, WellKnownTags.Internal);
internal static readonly ImmutableArray EnumPublic = ImmutableArray.Create(WellKnownTags.Enum, WellKnownTags.Public);
- internal static readonly ImmutableArray EnumProtected = ImmutableArray.Create(WellKnownTags.Enum, WellKnownTags.Public);
+ internal static readonly ImmutableArray EnumProtected = ImmutableArray.Create(WellKnownTags.Enum, WellKnownTags.Protected);
internal static readonly ImmutableArray EnumPrivate = ImmutableArray.Create(WellKnownTags.Enum, WellKnownTags.Private);
internal static readonly ImmutableArray EnumInternal = ImmutableArray.Create(WellKnownTags.Enum, WellKnownTags.Internal);
- internal static readonly ImmutableArray EnumMember = ImmutableArray.Create(WellKnownTags.EnumMember);
+ internal static readonly ImmutableArray EnumMemberPublic = ImmutableArray.Create(WellKnownTags.EnumMember, WellKnownTags.Public);
+ internal static readonly ImmutableArray EnumMemberProtected = ImmutableArray.Create(WellKnownTags.EnumMember, WellKnownTags.Protected);
+ internal static readonly ImmutableArray EnumMemberPrivate = ImmutableArray.Create(WellKnownTags.EnumMember, WellKnownTags.Private);
+ internal static readonly ImmutableArray EnumMemberInternal = ImmutableArray.Create(WellKnownTags.EnumMember, WellKnownTags.Internal);
internal static readonly ImmutableArray EventPublic = ImmutableArray.Create(WellKnownTags.Event, WellKnownTags.Public);
internal static readonly ImmutableArray EventProtected = ImmutableArray.Create(WellKnownTags.Event, WellKnownTags.Protected);
internal static readonly ImmutableArray EventPrivate = ImmutableArray.Create(WellKnownTags.Event, WellKnownTags.Private);
diff --git a/src/Workspaces/Core/Portable/Utilities/SpellChecker.cs b/src/Workspaces/Core/Portable/Utilities/SpellChecker.cs
index b10ee303aa4de..f4438e12f0eb3 100644
--- a/src/Workspaces/Core/Portable/Utilities/SpellChecker.cs
+++ b/src/Workspaces/Core/Portable/Utilities/SpellChecker.cs
@@ -23,24 +23,23 @@ public SpellChecker(VersionStamp version, BKTree bKTree)
_bkTree = bKTree;
}
- public SpellChecker(VersionStamp version, IEnumerable corpus)
+ public SpellChecker(VersionStamp version, IEnumerable corpus)
: this(version, BKTree.Create(corpus))
{
}
public IList FindSimilarWords(string value)
- {
- return FindSimilarWords(value, substringsAreSimilar: false);
- }
+ => FindSimilarWords(value, substringsAreSimilar: false);
public IList FindSimilarWords(string value, bool substringsAreSimilar)
{
var result = _bkTree.Find(value, threshold: null);
- using (var spellChecker = new WordSimilarityChecker(value, substringsAreSimilar))
- {
- return result.Where(spellChecker.AreSimilar).ToArray();
- }
+ var checker = WordSimilarityChecker.Allocate(value, substringsAreSimilar);
+ var array = result.Where(checker.AreSimilar).ToArray();
+ checker.Free();
+
+ return array;
}
internal void WriteTo(ObjectWriter writer)
@@ -74,7 +73,7 @@ internal static SpellChecker ReadFrom(ObjectReader reader)
}
}
- internal class WordSimilarityChecker : IDisposable
+ internal class WordSimilarityChecker
{
private struct CacheResult
{
@@ -97,16 +96,37 @@ public CacheResult(string candidate, bool areSimilar, double similarityWeight)
private string _source;
private EditDistance _editDistance;
- private readonly int _threshold;
+ private int _threshold;
///
/// Whether or words should be considered similar if one is contained within the other
/// (regardless of edit distance). For example if is true then IService would be considered
/// similar to IServiceFactory despite the edit distance being quite high at 7.
///
- private readonly bool _substringsAreSimilar;
+ private bool _substringsAreSimilar;
+
+ private static readonly object s_poolGate = new object();
+ private static readonly Stack s_pool = new Stack();
+
+ public static WordSimilarityChecker Allocate(string text, bool substringsAreSimilar)
+ {
+ WordSimilarityChecker checker;
+ lock (s_poolGate)
+ {
+ checker = s_pool.Count > 0
+ ? s_pool.Pop()
+ : new WordSimilarityChecker();
+ }
+
+ checker.Initialize(text, substringsAreSimilar);
+ return checker;
+ }
+
+ private WordSimilarityChecker()
+ {
+ }
- public WordSimilarityChecker(string text, bool substringsAreSimilar)
+ private void Initialize(string text, bool substringsAreSimilar)
{
_source = text ?? throw new ArgumentNullException(nameof(text));
_threshold = GetThreshold(_source);
@@ -114,29 +134,31 @@ public WordSimilarityChecker(string text, bool substringsAreSimilar)
_substringsAreSimilar = substringsAreSimilar;
}
- public void Dispose()
+ public void Free()
{
_editDistance?.Dispose();
+ _source = null;
_editDistance = null;
+ _lastAreSimilarResult = default(CacheResult);
+ lock (s_poolGate)
+ {
+ s_pool.Push(this);
+ }
}
public static bool AreSimilar(string originalText, string candidateText)
- {
- return AreSimilar(originalText, candidateText, substringsAreSimilar: false);
- }
+ => AreSimilar(originalText, candidateText, substringsAreSimilar: false);
public static bool AreSimilar(string originalText, string candidateText, bool substringsAreSimilar)
- {
- return AreSimilar(originalText, candidateText, substringsAreSimilar, out var unused);
- }
+ => AreSimilar(originalText, candidateText, substringsAreSimilar, out var unused);
public static bool AreSimilar(string originalText, string candidateText, out double similarityWeight)
{
return AreSimilar(
- originalText, candidateText,
+ originalText, candidateText,
substringsAreSimilar: false, similarityWeight: out similarityWeight);
}
-
+
///
/// Returns true if 'originalText' and 'candidateText' are likely a misspelling of each other.
/// Returns false otherwise. If it is a likely misspelling a similarityWeight is provided
@@ -144,21 +166,18 @@ public static bool AreSimilar(string originalText, string candidateText, out dou
///
public static bool AreSimilar(string originalText, string candidateText, bool substringsAreSimilar, out double similarityWeight)
{
- using (var checker = new WordSimilarityChecker(originalText, substringsAreSimilar))
- {
- return checker.AreSimilar(candidateText, out similarityWeight);
- }
+ var checker = Allocate(originalText, substringsAreSimilar);
+ var result = checker.AreSimilar(candidateText, out similarityWeight);
+ checker.Free();
+
+ return result;
}
internal static int GetThreshold(string value)
- {
- return value.Length <= 4 ? 1 : 2;
- }
+ => value.Length <= 4 ? 1 : 2;
public bool AreSimilar(string candidateText)
- {
- return AreSimilar(candidateText, out var similarityWeight);
- }
+ => AreSimilar(candidateText, out var similarityWeight);
public bool AreSimilar(string candidateText, out double similarityWeight)
{
@@ -242,4 +261,4 @@ private static double Penalty(string candidateText, string originalText)
return 0;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Workspaces/Core/Portable/Workspaces.csproj b/src/Workspaces/Core/Portable/Workspaces.csproj
index 511d5bd5b18d6..8387fcc21e295 100644
--- a/src/Workspaces/Core/Portable/Workspaces.csproj
+++ b/src/Workspaces/Core/Portable/Workspaces.csproj
@@ -407,13 +407,16 @@
+
+
-
+
-
+
+
@@ -424,6 +427,7 @@
+
diff --git a/src/Workspaces/Remote/Razor/RazorServiceHub.csproj b/src/Workspaces/Remote/Razor/RazorServiceHub.csproj
index 6e29caea382bd..4351aeb3493ec 100644
--- a/src/Workspaces/Remote/Razor/RazorServiceHub.csproj
+++ b/src/Workspaces/Remote/Razor/RazorServiceHub.csproj
@@ -44,6 +44,9 @@
+
+ Shared\JsonRpcMessageHandler.cs
+
Shared\RoslynJsonConverter.cs
diff --git a/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj b/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj
index 26d66f271df3b..1ab54a50d292b 100644
--- a/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj
+++ b/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj
@@ -60,6 +60,9 @@
Telemetry\VSTelemetryLogger.cs
+
+ Shared\JsonRpcMessageHandler.cs
+
diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_SymbolFinder.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_SymbolFinder.cs
index 0d94ec32c14c0..77e7982ce9263 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_SymbolFinder.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_SymbolFinder.cs
@@ -50,10 +50,13 @@ public async Task FindAllDeclarationsWithNorma
var solution = await GetSolutionAsync().ConfigureAwait(false);
var project = solution.GetProject(projectId);
- var result = await DeclarationFinder.FindAllDeclarationsWithNormalQueryInCurrentProcessAsync(
- project, SearchQuery.Create(name, searchKind), criteria, this.CancellationToken).ConfigureAwait(false);
+ using (var query = SearchQuery.Create(name, searchKind))
+ {
+ var result = await DeclarationFinder.FindAllDeclarationsWithNormalQueryInCurrentProcessAsync(
+ project, query, criteria, this.CancellationToken).ConfigureAwait(false);
- return result.Select(SerializableSymbolAndProjectId.Dehydrate).ToArray();
+ return result.Select(SerializableSymbolAndProjectId.Dehydrate).ToArray();
+ }
}
public async Task FindSolutionSourceDeclarationsWithNormalQueryAsync(
diff --git a/src/Workspaces/Remote/ServiceHub/Services/RemoteHostService.cs b/src/Workspaces/Remote/ServiceHub/Services/RemoteHostService.cs
index 78e22214e8a91..35449361371ce 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/RemoteHostService.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/RemoteHostService.cs
@@ -2,8 +2,11 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Diagnostics;
using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ErrorReporting;
@@ -14,6 +17,7 @@
using Microsoft.CodeAnalysis.Storage;
using Microsoft.VisualStudio.LanguageServices.Telemetry;
using Microsoft.VisualStudio.Telemetry;
+using Roslyn.Utilities;
using RoslynLogger = Microsoft.CodeAnalysis.Internal.Log.Logger;
namespace Microsoft.CodeAnalysis.Remote
@@ -41,6 +45,8 @@ static RemoteHostService()
// this should let us to freely try to use all resources possible without worrying about affecting
// host's work such as responsiveness or build.
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal;
+
+ SetNativeDllSearchDirectories();
}
public RemoteHostService(Stream stream, IServiceProvider serviceProvider) :
@@ -219,5 +225,29 @@ private static AbstractPersistentStorageService GetPersistentStorageService()
var persistentStorageService = workspace.Services.GetService() as AbstractPersistentStorageService;
return persistentStorageService;
}
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+ private static extern IntPtr AddDllDirectory(string directory);
+
+ private static void SetNativeDllSearchDirectories()
+ {
+ if (PlatformInformation.IsWindows)
+ {
+ // Set LoadLibrary search directory to %VSINSTALLDIR%\Common7\IDE so that the compiler
+ // can P/Invoke to Microsoft.DiaSymReader.Native when emitting Windows PDBs.
+ //
+ // The AppDomain base directory is specified in VisualStudio\Setup.Next\codeAnalysisService.servicehub.service.json
+ // to be the directory where devenv.exe is -- which is exactly the directory we need to add to the search paths:
+ //
+ // "appBasePath": "%VSAPPIDDIR%"
+ //
+
+ var cookie = AddDllDirectory(AppDomain.CurrentDomain.BaseDirectory);
+ if (cookie == IntPtr.Zero)
+ {
+ throw new Win32Exception();
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs b/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs
index 44f7c95c5f080..36336263409c7 100644
--- a/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs
+++ b/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs
@@ -6,6 +6,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Options;
+using Microsoft.VisualStudio.LanguageServices.Remote;
using Roslyn.Utilities;
using StreamJsonRpc;
@@ -66,7 +67,7 @@ protected ServiceHubServiceBase(IServiceProvider serviceProvider, Stream stream)
// due to this issue - https://github.com/dotnet/roslyn/issues/16900#issuecomment-277378950
// all sub type must explicitly start JsonRpc once everything is
// setup
- Rpc = new JsonRpc(stream, stream, this);
+ Rpc = new JsonRpc(new JsonRpcMessageHandler(stream, stream), this);
Rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance);
Rpc.Disconnected += OnRpcDisconnected;
}
diff --git a/src/Workspaces/VisualBasic/Portable/BasicWorkspace.vbproj b/src/Workspaces/VisualBasic/Portable/BasicWorkspace.vbproj
index 9648cf604cf8f..1ebbafe3f0dc4 100644
--- a/src/Workspaces/VisualBasic/Portable/BasicWorkspace.vbproj
+++ b/src/Workspaces/VisualBasic/Portable/BasicWorkspace.vbproj
@@ -190,6 +190,8 @@
+
+
diff --git a/src/Workspaces/VisualBasic/Portable/Classification/Classifiers/NameSyntaxClassifier.vb b/src/Workspaces/VisualBasic/Portable/Classification/Classifiers/NameSyntaxClassifier.vb
index a02ea0731f145..519db827cf5f4 100644
--- a/src/Workspaces/VisualBasic/Portable/Classification/Classifiers/NameSyntaxClassifier.vb
+++ b/src/Workspaces/VisualBasic/Portable/Classification/Classifiers/NameSyntaxClassifier.vb
@@ -80,9 +80,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Classification.Classifiers
Dim token = GetNameToken(node)
Return SpecializedCollections.SingletonEnumerable(
New ClassifiedSpan(token.Span, ClassificationTypeNames.Keyword))
+ Else
+ ' We bound to a constructor, but we weren't something like the 'New' in 'X.New'.
+ ' This can happen when we're actually just binding the full node 'X.New'. In this
+ ' case, don't return anything for this full node. We'll end up hitting the
+ ' 'New' node as the worker walks down, and we'll classify it then.
+ Return Nothing
End If
-
- symbol = method.ContainingType
End If
End If
diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/VisualBasicSyntaxContext.vb b/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/VisualBasicSyntaxContext.vb
index b7ad3dd55bbd4..7f53116f5284e 100644
--- a/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/VisualBasicSyntaxContext.vb
+++ b/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/VisualBasicSyntaxContext.vb
@@ -97,6 +97,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery
isInImportsDirective:=isInImportsDirective,
isWithinAsyncMethod:=IsWithinAsyncMethod(targetToken, cancellationToken),
isPossibleTupleContext:=isPossibleTupleContext,
+ isPatternContext:=False,
cancellationToken:=cancellationToken)
Dim syntaxTree = semanticModel.SyntaxTree
diff --git a/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb b/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
index c437b5293ddfa..b8facb022e39a 100644
--- a/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
+++ b/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb
@@ -845,9 +845,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim classDecl = CType(node, ClassBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
classDecl.ClassStatement.Identifier.ValueText,
+ GetTypeParameterSuffix(classDecl.ClassStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Class, classDecl.ClassStatement.Identifier.Span,
+ DeclaredSymbolInfoKind.Class,
+ GetAccessibility(classDecl, classDecl.ClassStatement.Modifiers),
+ classDecl.ClassStatement.Identifier.Span,
GetInheritanceNames(classDecl))
Return True
Case SyntaxKind.ConstructorBlock
@@ -856,12 +859,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
If typeBlock IsNot Nothing Then
declaredSymbolInfo = New DeclaredSymbolInfo(
typeBlock.BlockStatement.Identifier.ValueText,
+ GetConstructorSuffix(constructor),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Constructor,
+ GetAccessibility(constructor, constructor.SubNewStatement.Modifiers),
constructor.SubNewStatement.NewKeyword.Span,
ImmutableArray(Of String).Empty,
- parameterCount:=CType(If(constructor.SubNewStatement.ParameterList?.Parameters.Count, 0), UShort))
+ parameterCount:=If(constructor.SubNewStatement.ParameterList?.Parameters.Count, 0))
Return True
End If
@@ -869,58 +874,73 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim delegateDecl = CType(node, DelegateStatementSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
delegateDecl.Identifier.ValueText,
+ GetTypeParameterSuffix(delegateDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Delegate, delegateDecl.Identifier.Span,
+ DeclaredSymbolInfoKind.Delegate,
+ GetAccessibility(delegateDecl, delegateDecl.Modifiers),
+ delegateDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.EnumBlock
Dim enumDecl = CType(node, EnumBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
- enumDecl.EnumStatement.Identifier.ValueText,
+ enumDecl.EnumStatement.Identifier.ValueText, Nothing,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Enum, enumDecl.EnumStatement.Identifier.Span,
+ DeclaredSymbolInfoKind.Enum,
+ GetAccessibility(enumDecl, enumDecl.EnumStatement.Modifiers),
+ enumDecl.EnumStatement.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.EnumMemberDeclaration
Dim enumMember = CType(node, EnumMemberDeclarationSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
- enumMember.Identifier.ValueText,
+ enumMember.Identifier.ValueText, Nothing,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.EnumMember, enumMember.Identifier.Span,
+ DeclaredSymbolInfoKind.EnumMember,
+ Accessibility.Public,
+ enumMember.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.EventStatement
Dim eventDecl = CType(node, EventStatementSyntax)
- Dim eventParent = If(TypeOf node.Parent Is EventBlockSyntax, node.Parent.Parent, node.Parent)
+ Dim statementOrBlock = If(TypeOf node.Parent Is EventBlockSyntax, node.Parent, node)
+ Dim eventParent = statementOrBlock.Parent
declaredSymbolInfo = New DeclaredSymbolInfo(
- eventDecl.Identifier.ValueText,
+ eventDecl.Identifier.ValueText, Nothing,
GetContainerDisplayName(eventParent),
GetFullyQualifiedContainerName(eventParent),
- DeclaredSymbolInfoKind.Event, eventDecl.Identifier.Span,
+ DeclaredSymbolInfoKind.Event,
+ GetAccessibility(statementOrBlock, eventDecl.Modifiers),
+ eventDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.FunctionBlock, SyntaxKind.SubBlock
Dim funcDecl = CType(node, MethodBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
funcDecl.SubOrFunctionStatement.Identifier.ValueText,
+ GetMethodSuffix(funcDecl),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Method,
+ GetAccessibility(node, funcDecl.SubOrFunctionStatement.Modifiers),
funcDecl.SubOrFunctionStatement.Identifier.Span,
ImmutableArray(Of String).Empty,
- parameterCount:=CType(If(funcDecl.SubOrFunctionStatement.ParameterList?.Parameters.Count, 0), UShort),
- typeParameterCount:=CType(If(funcDecl.SubOrFunctionStatement.TypeParameterList?.Parameters.Count, 0), UShort))
+ parameterCount:=If(funcDecl.SubOrFunctionStatement.ParameterList?.Parameters.Count, 0),
+ typeParameterCount:=If(funcDecl.SubOrFunctionStatement.TypeParameterList?.Parameters.Count, 0))
Return True
Case SyntaxKind.InterfaceBlock
Dim interfaceDecl = CType(node, InterfaceBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
interfaceDecl.InterfaceStatement.Identifier.ValueText,
+ GetTypeParameterSuffix(interfaceDecl.InterfaceStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Interface, interfaceDecl.InterfaceStatement.Identifier.Span,
+ DeclaredSymbolInfoKind.Interface,
+ GetAccessibility(interfaceDecl, interfaceDecl.InterfaceStatement.Modifiers),
+ interfaceDecl.InterfaceStatement.Identifier.Span,
GetInheritanceNames(interfaceDecl))
Return True
Case SyntaxKind.ModifiedIdentifier
@@ -932,10 +952,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
DeclaredSymbolInfoKind.Constant,
DeclaredSymbolInfoKind.Field)
declaredSymbolInfo = New DeclaredSymbolInfo(
- modifiedIdentifier.Identifier.ValueText,
+ modifiedIdentifier.Identifier.ValueText, Nothing,
GetContainerDisplayName(fieldDecl.Parent),
GetFullyQualifiedContainerName(fieldDecl.Parent),
- kind, modifiedIdentifier.Identifier.Span,
+ kind, GetAccessibility(fieldDecl, fieldDecl.Modifiers),
+ modifiedIdentifier.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
End If
@@ -943,28 +964,37 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim moduleDecl = CType(node, ModuleBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
moduleDecl.ModuleStatement.Identifier.ValueText,
+ GetTypeParameterSuffix(moduleDecl.ModuleStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Module, moduleDecl.ModuleStatement.Identifier.Span,
+ DeclaredSymbolInfoKind.Module,
+ GetAccessibility(moduleDecl, moduleDecl.ModuleStatement.Modifiers),
+ moduleDecl.ModuleStatement.Identifier.Span,
GetInheritanceNames(moduleDecl))
Return True
Case SyntaxKind.PropertyStatement
Dim propertyDecl = CType(node, PropertyStatementSyntax)
- Dim propertyParent = If(TypeOf node.Parent Is PropertyBlockSyntax, node.Parent.Parent, node.Parent)
+ Dim statementOrBlock = If(TypeOf node.Parent Is PropertyBlockSyntax, node.Parent, node)
+ Dim propertyParent = statementOrBlock.Parent
declaredSymbolInfo = New DeclaredSymbolInfo(
- propertyDecl.Identifier.ValueText,
+ propertyDecl.Identifier.ValueText, GetPropertySuffix(propertyDecl),
GetContainerDisplayName(propertyParent),
GetFullyQualifiedContainerName(propertyParent),
- DeclaredSymbolInfoKind.Property, propertyDecl.Identifier.Span,
+ DeclaredSymbolInfoKind.Property,
+ GetAccessibility(statementOrBlock, propertyDecl.Modifiers),
+ propertyDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.StructureBlock
Dim structDecl = CType(node, StructureBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
structDecl.StructureStatement.Identifier.ValueText,
+ GetTypeParameterSuffix(structDecl.StructureStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
- DeclaredSymbolInfoKind.Struct, structDecl.StructureStatement.Identifier.Span,
+ DeclaredSymbolInfoKind.Struct,
+ GetAccessibility(structDecl, structDecl.StructureStatement.Modifiers),
+ structDecl.StructureStatement.Identifier.Span,
GetInheritanceNames(structDecl))
Return True
End Select
@@ -973,6 +1003,145 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return False
End Function
+ Private Function GetMethodSuffix(method As MethodBlockSyntax) As String
+ Return GetTypeParameterSuffix(method.SubOrFunctionStatement.TypeParameterList) &
+ GetSuffix(method.SubOrFunctionStatement.ParameterList)
+ End Function
+
+ Private Function GetConstructorSuffix(method As ConstructorBlockSyntax) As String
+ Return ".New" & GetSuffix(method.SubNewStatement.ParameterList)
+ End Function
+
+ Private Function GetPropertySuffix([property] As PropertyStatementSyntax) As String
+ If [property].ParameterList Is Nothing Then
+ Return Nothing
+ End If
+
+ Return GetSuffix([property].ParameterList)
+ End Function
+
+ Private Function GetTypeParameterSuffix(typeParameterList As TypeParameterListSyntax) As String
+ If typeParameterList Is Nothing Then
+ Return Nothing
+ End If
+
+ Dim pooledBuilder = PooledStringBuilder.GetInstance()
+
+ Dim builder = pooledBuilder.Builder
+ builder.Append("(Of ")
+
+ Dim First = True
+ For Each parameter In typeParameterList.Parameters
+ If Not First Then
+ builder.Append(", ")
+ End If
+
+ builder.Append(parameter.Identifier.Text)
+ First = False
+ Next
+
+ builder.Append(")"c)
+
+ Return pooledBuilder.ToStringAndFree()
+ End Function
+
+
+
+ '''
+ ''' Builds up the suffix to show for something with parameters in navigate-to.
+ ''' While it would be nice to just use the compiler SymbolDisplay API for this,
+ ''' it would be too expensive as it requires going back to Symbols (which requires
+ ''' creating compilations, etc.) in a perf sensitive area.
+ '''
+ ''' So, instead, we just build a reasonable suffix using the pure syntax that a
+ ''' user provided. That means that if they wrote "Method(System.Int32 i)" we'll
+ ''' show that as "Method(System.Int32)" Not "Method(Integer)". Given that this Is
+ ''' actually what the user wrote, And it saves us from ever having to go back to
+ ''' symbols/compilations, this Is well worth it, even if it does mean we have to
+ ''' create our own 'symbol display' logic here.
+ '''
+ Private Function GetSuffix(parameterList As ParameterListSyntax) As String
+ If parameterList Is Nothing OrElse parameterList.Parameters.Count = 0 Then
+ Return "()"
+ End If
+
+ Dim pooledBuilder = PooledStringBuilder.GetInstance()
+
+ Dim builder = pooledBuilder.Builder
+ builder.Append("("c)
+ If parameterList IsNot Nothing Then
+ AppendParameters(parameterList.Parameters, builder)
+ End If
+ builder.Append(")"c)
+
+ Return pooledBuilder.ToStringAndFree()
+ End Function
+
+ Private Sub AppendParameters(parameters As SeparatedSyntaxList(Of ParameterSyntax), builder As StringBuilder)
+ Dim First = True
+ For Each parameter In parameters
+ If Not First Then
+ builder.Append(", ")
+ End If
+
+ For Each modifier In parameter.Modifiers
+ If modifier.Kind() <> SyntaxKind.ByValKeyword Then
+ builder.Append(modifier.Text)
+ builder.Append(" "c)
+ End If
+ Next
+
+ If parameter.AsClause?.Type IsNot Nothing Then
+ AppendTokens(parameter.AsClause.Type, builder)
+ End If
+
+ First = False
+ Next
+ End Sub
+
+ Private Function GetAccessibility(node As SyntaxNode, modifiers As SyntaxTokenList) As Accessibility
+ Dim sawFriend = False
+
+ For Each modifier In modifiers
+ Select Case modifier.Kind()
+ Case SyntaxKind.PublicKeyword : Return Accessibility.Public
+ Case SyntaxKind.PrivateKeyword : Return Accessibility.Private
+ Case SyntaxKind.ProtectedKeyword : Return Accessibility.Protected
+ Case SyntaxKind.FriendKeyword
+ sawFriend = True
+ Continue For
+ End Select
+ Next
+
+ If sawFriend Then
+ Return Accessibility.Internal
+ End If
+
+ ' No accessibility modifiers
+ Select Case node.Parent.Kind()
+ Case SyntaxKind.ClassBlock
+ ' In a class, fields and shared-constructors are private by default,
+ ' everything Else Is Public
+ If node.Kind() = SyntaxKind.FieldDeclaration Then
+ Return Accessibility.Private
+ End If
+
+ If node.Kind() = SyntaxKind.ConstructorBlock AndAlso
+ DirectCast(node, ConstructorBlockSyntax).SubNewStatement.Modifiers.Any(SyntaxKind.SharedKeyword) Then
+ Return Accessibility.Private
+ End If
+
+ Return Accessibility.Public
+
+ Case SyntaxKind.StructureBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ModuleBlock
+ ' Everything in a struct/interface/module is public
+ Return Accessibility.Public
+ End Select
+
+ ' Otherwise, it's internal
+ Return Accessibility.Internal
+ End Function
+
Private Function GetInheritanceNames(typeBlock As TypeBlockSyntax) As ImmutableArray(Of String)
Dim builder = ArrayBuilder(Of String).GetInstance()
diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicInferredMemberNameReducer.Rewriter.vb b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicInferredMemberNameReducer.Rewriter.vb
new file mode 100644
index 0000000000000..47d16bdfbb964
--- /dev/null
+++ b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicInferredMemberNameReducer.Rewriter.vb
@@ -0,0 +1,44 @@
+' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+Imports System.Threading
+Imports Microsoft.CodeAnalysis.Options
+Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
+
+Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification
+ Partial Friend Class VisualBasicInferredMemberNameReducer
+
+ Private Class Rewriter
+ Inherits AbstractExpressionRewriter
+
+ Public Sub New(optionSet As OptionSet, cancellationToken As CancellationToken)
+ MyBase.New(optionSet, cancellationToken)
+ End Sub
+
+ Public Overrides Function VisitSimpleArgument(node As SimpleArgumentSyntax) As SyntaxNode
+ CancellationToken.ThrowIfCancellationRequested()
+
+ Dim newNode = MyBase.VisitSimpleArgument(node)
+
+ If node.IsParentKind(SyntaxKind.TupleExpression) Then
+ Return SimplifyNode(
+ node,
+ parentNode:=node.Parent,
+ newNode:=newNode,
+ simplifyFunc:=AddressOf SimplifyTupleName)
+ End If
+
+ Return newNode
+ End Function
+
+ Public Overrides Function VisitNamedFieldInitializer(node As NamedFieldInitializerSyntax) As SyntaxNode
+ Dim newNode = MyBase.VisitNamedFieldInitializer(node)
+
+ Return SimplifyNode(
+ node,
+ parentNode:=node.Parent,
+ newNode:=newNode,
+ simplifyFunc:=AddressOf SimplifyNamedFieldInitializer)
+ End Function
+ End Class
+ End Class
+End Namespace
diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicInferredMemberNameReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicInferredMemberNameReducer.vb
new file mode 100644
index 0000000000000..b3e14d8dd7613
--- /dev/null
+++ b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicInferredMemberNameReducer.vb
@@ -0,0 +1,55 @@
+' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+Imports System.Threading
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Options
+Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
+
+Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification
+ '''
+ ''' Complexify makes inferred names explicit for tuple elements and anonymous type members. This
+ ''' class considers which ones of those can be simplified (after the refactoring was done).
+ ''' If the inferred name of the member matches, the explicit name (from Complexifiy) can be removed.
+ '''
+ Partial Friend Class VisualBasicInferredMemberNameReducer
+ Inherits AbstractVisualBasicReducer
+
+ Public Overrides Function CreateExpressionRewriter(optionSet As OptionSet, cancellationToken As CancellationToken) As IExpressionRewriter
+ Return New VisualBasicInferredMemberNameReducer.Rewriter(optionSet, cancellationToken)
+ End Function
+
+ Private Shared Function SimplifyTupleName(
+ node As SimpleArgumentSyntax,
+ semanticModel As SemanticModel,
+ optionSet As OptionSet,
+ cancellationToken As CancellationToken
+ ) As SimpleArgumentSyntax
+
+ ' Tuple elements are arguments in a tuple expression
+ If node.NameColonEquals Is Nothing OrElse Not node.IsParentKind(SyntaxKind.TupleExpression) Then
+ Return node
+ End If
+
+ Dim inferredName = node.Expression.TryGetInferredMemberName()
+
+ If inferredName Is Nothing OrElse
+ Not CaseInsensitiveComparison.Equals(inferredName, node.NameColonEquals.Name.Identifier.ValueText) Then
+
+ Return node
+ End If
+
+ Return node.WithNameColonEquals(Nothing).WithTriviaFrom(node)
+ End Function
+
+ Private Shared Function SimplifyNamedFieldInitializer(node As NamedFieldInitializerSyntax, arg2 As SemanticModel, arg3 As OptionSet, arg4 As CancellationToken) As SyntaxNode
+ Dim inferredName = node.Expression.TryGetInferredMemberName()
+
+ If inferredName Is Nothing OrElse
+ Not CaseInsensitiveComparison.Equals(inferredName, node.Name.Identifier.ValueText) Then
+ Return node
+ End If
+
+ Return SyntaxFactory.InferredFieldInitializer(node.Expression).WithTriviaFrom(node)
+ End Function
+ End Class
+End Namespace
diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.Expander.vb b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.Expander.vb
index 8891e71256d58..d9506a604b9fa 100644
--- a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.Expander.vb
+++ b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.Expander.vb
@@ -295,6 +295,23 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification
Dim newSimpleArgument = DirectCast(MyBase.VisitSimpleArgument(node), SimpleArgumentSyntax)
+ If node.NameColonEquals Is Nothing Then
+ Dim tuple = TryCast(node.Parent, TupleExpressionSyntax)
+ If tuple IsNot Nothing Then
+ Dim inferredName = node.Expression.TryGetInferredMemberName()
+ If CanMakeNameExplicitInTuple(tuple, inferredName) Then
+ Dim identifier = SyntaxFactory.Identifier(inferredName)
+ identifier = TryEscapeIdentifierToken(identifier, _semanticModel)
+
+ newSimpleArgument = newSimpleArgument.
+ WithLeadingTrivia().
+ WithNameColonEquals(SyntaxFactory.NameColonEquals(SyntaxFactory.IdentifierName(identifier))).
+ WithAdditionalAnnotations(Simplifier.Annotation).
+ WithLeadingTrivia(node.GetLeadingTrivia())
+ End If
+ End If
+ End If
+
' We need to be careful here. if this is a local, field or property passed to a ByRef argument, we shouldn't
' parenthesize to avoid breaking copy-back semantics.
Dim symbol = _semanticModel.GetSymbolInfo(node.Expression, _cancellationToken).Symbol
@@ -326,6 +343,50 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification
Return newSimpleArgument
End Function
+ Private Function CanMakeNameExplicitInTuple(tuple As TupleExpressionSyntax, name As String) As Boolean
+ If name Is Nothing OrElse SyntaxFacts.IsReservedTupleElementName(name) Then
+ Return False
+ End If
+
+ Dim found = False
+
+ For Each argument In tuple.Arguments
+ Dim elementName = Nothing
+ If argument.NameColonEquals IsNot Nothing Then
+ elementName = argument.NameColonEquals.Name.Identifier.ValueText
+ Else
+ elementName = argument.Expression?.TryGetInferredMemberName()
+ End If
+
+ If CaseInsensitiveComparison.Equals(elementName, name) Then
+ If found Then
+ ' No duplicate names allowed
+ Return False
+ End If
+ found = True
+ End If
+ Next
+
+ Return True
+ End Function
+
+ Public Overrides Function VisitInferredFieldInitializer(node As InferredFieldInitializerSyntax) As SyntaxNode
+ Dim newInitializer = TryCast(MyBase.VisitInferredFieldInitializer(node), InferredFieldInitializerSyntax)
+ If newInitializer IsNot Nothing Then
+ Dim inferredName = node.Expression.TryGetInferredMemberName()
+ If inferredName IsNot Nothing Then
+ Dim identifier = SyntaxFactory.Identifier(inferredName)
+ identifier = TryEscapeIdentifierToken(identifier, _semanticModel)
+
+ Return SyntaxFactory.NamedFieldInitializer(SyntaxFactory.IdentifierName(identifier), newInitializer.Expression.WithoutLeadingTrivia()).
+ WithLeadingTrivia(node.GetLeadingTrivia()).
+ WithAdditionalAnnotations(Simplifier.Annotation)
+ End If
+ End If
+
+ Return newInitializer
+ End Function
+
Public Overrides Function VisitGenericName(node As GenericNameSyntax) As SyntaxNode
_cancellationToken.ThrowIfCancellationRequested()
diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb
index 9312e562c696f..d8c1469412ccf 100644
--- a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb
+++ b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb
@@ -25,7 +25,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification
New VisualBasicEscapingReducer(), ' order before VisualBasicMiscellaneousReducer, see RenameNewOverload test
New VisualBasicMiscellaneousReducer(),
New VisualBasicCastReducer(),
- New VisualBasicVariableDeclaratorReducer())
+ New VisualBasicVariableDeclaratorReducer(),
+ New VisualBasicInferredMemberNameReducer())
Public Sub New()
MyBase.New(s_reducers)