未验证 提交 a2007922 编写于 作者: F Fredric Silberberg

Merge remote-tracking branch 'dotnet/master' into merge-master

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
<configuration>
<packageRestore>
<!-- NuGet Restore was observed to cause performance problems for in-IDE builds,
so it has been disabled.
THIS IS A PERFORMANCE-CRITICAL LINE. DO NOT REMOVE. ⚠ -->
<add key="enabled" value="false" />
</packageRestore>
<packageSources>
<clear />
<add key="dotnet-core" value="https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json" />
......
......@@ -17,7 +17,7 @@ You'll need to create a .resx file to hold your localizable resources. For the p
Using Localized Resources in Analyzers
--------------------------------------
Normally, .Net applications can simply access the resource through the type generated from the .resx file:
Normally, .NET applications can simply access the resource through the type generated from the .resx file:
``` C#
string message = AnalyzerResources.Message;
```
......
### VB Embedded Runtime inherits overflow checking from the compilation
See https://github.com/dotnet/roslyn/issues/6941. Some VB runtime methods are specified to throw an `OverflowException` when a converted value overflows the target type. When compiling a VB project with the runtime embedded (`/vbruntime*`), the compiler includes the necessary VB runtime helpers into the assembly that is produced. These runtime helpers inherit the overflow checking behavior of the VB.NET project that they are embedded into. As a result, if you both embed the runtime and have overflow checking disabled (`/removeintchecks+`), you will not get the specified exceptions from the runtime helpers. Although technically it is a bug, it has long been the behavior of VB.Net and we have found that customers would be broken by having it fixed, so we do not expect to change this behavior.
See https://github.com/dotnet/roslyn/issues/6941. Some VB runtime methods are specified to throw an `OverflowException` when a converted value overflows the target type. When compiling a VB project with the runtime embedded (`/vbruntime*`), the compiler includes the necessary VB runtime helpers into the assembly that is produced. These runtime helpers inherit the overflow checking behavior of the VB.NET project that they are embedded into. As a result, if you both embed the runtime and have overflow checking disabled (`/removeintchecks+`), you will not get the specified exceptions from the runtime helpers. Although technically it is a bug, it has long been the behavior of VB.NET and we have found that customers would be broken by having it fixed, so we do not expect to change this behavior.
``` vb
Sub Main()
......
......@@ -18,7 +18,8 @@ The minimal required version of .NET Framework is 4.7.2.
1. [Visual Studio 2019 RC](https://visualstudio.microsoft.com/downloads/#2019rc)
- Ensure C#, VB, MSBuild, .NET Core and Visual Studio Extensibility are included in the selected work loads
- Ensure Visual Studio is on Version "RC1" or greater
1. [.NET Core SDK 2.1.401](https://www.microsoft.com/net/download/core) (the installers are: [Windows x64 installer](https://dotnetcli.blob.core.windows.net/dotnet/Sdk/2.1.401/dotnet-sdk-2.1.401-win-x64.exe), [Windows x86 installer](https://dotnetcli.blob.core.windows.net/dotnet/Sdk/2.1.401/dotnet-sdk-2.1.401-win-x86.exe))
- Ensure "Use Previews" is checked in Tools -> Options -> Projects and Solutions -> .NET Core
1. [.NET Core SDK 3.0 Preview 3](https://dotnet.microsoft.com/download/dotnet-core/3.0) [Windows x64 installer](https://dotnet.microsoft.com/download/thank-you/dotnet-sdk-3.0.100-preview3-windows-x64-installer)
1. [PowerShell 5.0 or newer](https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell). If you are on Windows 10, you are fine; you'll only need to upgrade if you're on Windows 7. The download link is under the "upgrading existing Windows PowerShell" heading.
1. Run Restore.cmd
1. Open Roslyn.sln
......@@ -43,7 +44,7 @@ The Test.cmd script will run our unit test on already built binaries. It can be
2. Navigate to the directory of your Git clone.
3. Run `msbuild /v:m /m /nodereuse:false BuildAndTest.proj` in the command prompt.
You can more precisely control how the tests are run by running the eng/build.ps1 script directly with the relevant options. For example passing in the `-test` switch will run the tests on .Net Framework, whilst passing in the `-testCoreClr` switch will run the tests on .Net Core.
You can more precisely control how the tests are run by running the eng/build.ps1 script directly with the relevant options. For example passing in the `-test` switch will run the tests on .NET Framework, whilst passing in the `-testCoreClr` switch will run the tests on .NET Core.
The results of the tests can be viewed in the artifacts/TestResults directory.
......
......@@ -73,7 +73,7 @@ If the left-hand-side is nested the process will be repeated. For instance, in `
In the case where the expression on the right is a tuple expression, it is first given a type. So in `long x; string y; (x, y) = (1, null);` the literals on the right-hand-side are typed as `long` and `string` before the deconstruction even starts, which means that no conversions will be needed during the deconstruction steps.
We noted already that tuples (which are syntactic sugar for the `System.ValueTuple` underlying type) don't need to invoke `Deconstruct`.
The .Net framework also includes a set of `System.Tuple` types. Those are not recognized as C# tuples, and so will rely on the *Deconstruct* pattern. Those `Deconstruct` methods will be provided as extension methods for `System.Tuple` for up to 3 nestings deep (that is 21 elements).
The .NET framework also includes a set of `System.Tuple` types. Those are not recognized as C# tuples, and so will rely on the *Deconstruct* pattern. Those `Deconstruct` methods will be provided as extension methods for `System.Tuple` for up to 3 nestings deep (that is 21 elements).
A *deconstruction-assignment* returns a tuple value (with elements using default names) which is shaped and typed like the left-hand-side and holds the (converted) parts resulting from deconstruction.
......
......@@ -3,9 +3,9 @@
<ProductDependencies>
</ProductDependencies>
<ToolsetDependencies>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="1.0.0-beta.19162.7">
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="1.0.0-beta.19167.10">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>443dea11f8649fe12fedf60cfab0a4b2b20bd153</Sha>
<Sha>de7be3ba62b92e5c48c36876c851a14f154444af</Sha>
</Dependency>
</ToolsetDependencies>
</Dependencies>
......@@ -67,7 +67,7 @@
<MicrosoftInternalVisualStudioShellInterop140DesignTimeVersion>14.3.25407-alpha</MicrosoftInternalVisualStudioShellInterop140DesignTimeVersion>
<MicrosoftMetadataVisualizerVersion>1.0.0-beta1-63011-01</MicrosoftMetadataVisualizerVersion>
<MicrosoftMSXMLVersion>8.0.0.0-alpha</MicrosoftMSXMLVersion>
<MicrosoftNetCompilersToolsetVersion>3.1.0-beta1-19127-06</MicrosoftNetCompilersToolsetVersion>
<MicrosoftNetCompilersToolsetVersion>3.1.0-beta1-19164-01</MicrosoftNetCompilersToolsetVersion>
<MicrosoftNetCoreAnalyzersVersion>$(RoslynDiagnosticsNugetPackageVersion)</MicrosoftNetCoreAnalyzersVersion>
<MicrosoftNetCoreILAsmVersion>2.0.0</MicrosoftNetCoreILAsmVersion>
<MicrosoftNETCorePlatformsVersion>2.1.2</MicrosoftNETCorePlatformsVersion>
......
......@@ -34,6 +34,7 @@ param (
[switch]$bootstrap,
[string]$bootstrapConfiguration = "Release",
[switch][Alias('bl')]$binaryLog,
[switch]$buildServerLog,
[switch]$ci,
[switch]$procdump,
[switch]$skipAnalyzers,
......@@ -75,6 +76,7 @@ function Print-Usage() {
Write-Host " -verbosity <value> Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]"
Write-Host " -deployExtensions Deploy built vsixes (short: -d)"
Write-Host " -binaryLog Create MSBuild binary log (short: -bl)"
Write-Host " -buildServerLog Create Roslyn build server log"
Write-Host ""
Write-Host "Actions:"
Write-Host " -restore Restore packages (short: -r)"
......@@ -163,6 +165,9 @@ function Process-Arguments() {
if ($ci) {
$script:binaryLog = $true
if ($bootstrap) {
$script:buildServerLog = $true
}
}
if ($test32 -and $test64) {
......@@ -205,6 +210,11 @@ function BuildSolution() {
Write-Host "$($solution):"
$bl = if ($binaryLog) { "/bl:" + (Join-Path $LogDir "Build.binlog") } else { "" }
if ($buildServerLog) {
${env:ROSLYNCOMMANDLINELOGFILE} = Join-Path $LogDir "Build.Server.log"
}
$projects = Join-Path $RepoRoot $solution
$enableAnalyzers = !$skipAnalyzers
$toolsetBuildProj = InitializeToolset
......@@ -223,36 +233,41 @@ function BuildSolution() {
# Workaround for some machines in the AzDO pool not allowing long paths (%5c is msbuild escaped backslash)
$ibcDir = Join-Path $RepoRoot ".o%5c"
# Setting /p:TreatWarningsAsErrors=true is a workaround for https://github.com/Microsoft/msbuild/issues/3062.
# We don't pass /warnaserror to msbuild ($warnAsError is set to $false by default above), but set
# /p:TreatWarningsAsErrors=true so that compiler reported warnings, other than IDE0055 are treated as errors.
# Warnings reported from other msbuild tasks are not treated as errors for now.
MSBuild $toolsetBuildProj `
$bl `
/p:Configuration=$configuration `
/p:Projects=$projects `
/p:RepoRoot=$RepoRoot `
/p:Restore=$restore `
/p:Build=$build `
/p:Test=$testCoreClr `
/p:Rebuild=$rebuild `
/p:Pack=$pack `
/p:Sign=$sign `
/p:Publish=$publish `
/p:ContinuousIntegrationBuild=$ci `
/p:OfficialBuildId=$officialBuildId `
/p:UseRoslynAnalyzers=$enableAnalyzers `
/p:BootstrapBuildPath=$bootstrapDir `
/p:QuietRestore=$quietRestore `
/p:QuietRestoreBinaryLog=$binaryLog `
/p:TestTargetFrameworks=$testTargetFrameworks `
/p:TreatWarningsAsErrors=true `
/p:VisualStudioIbcSourceBranchName=$ibcSourceBranchName `
/p:VisualStudioIbcDropId=$ibcDropId `
/p:EnablePartialNgenOptimization=$applyOptimizationData `
/p:IbcOptimizationDataDir=$ibcDir `
$suppressExtensionDeployment `
@properties
try {
# Setting /p:TreatWarningsAsErrors=true is a workaround for https://github.com/Microsoft/msbuild/issues/3062.
# We don't pass /warnaserror to msbuild ($warnAsError is set to $false by default above), but set
# /p:TreatWarningsAsErrors=true so that compiler reported warnings, other than IDE0055 are treated as errors.
# Warnings reported from other msbuild tasks are not treated as errors for now.
MSBuild $toolsetBuildProj `
$bl `
/p:Configuration=$configuration `
/p:Projects=$projects `
/p:RepoRoot=$RepoRoot `
/p:Restore=$restore `
/p:Build=$build `
/p:Test=$testCoreClr `
/p:Rebuild=$rebuild `
/p:Pack=$pack `
/p:Sign=$sign `
/p:Publish=$publish `
/p:ContinuousIntegrationBuild=$ci `
/p:OfficialBuildId=$officialBuildId `
/p:UseRoslynAnalyzers=$enableAnalyzers `
/p:BootstrapBuildPath=$bootstrapDir `
/p:QuietRestore=$quietRestore `
/p:QuietRestoreBinaryLog=$binaryLog `
/p:TestTargetFrameworks=$testTargetFrameworks `
/p:TreatWarningsAsErrors=true `
/p:VisualStudioIbcSourceBranchName=$ibcSourceBranchName `
/p:VisualStudioIbcDropId=$ibcDropId `
/p:EnablePartialNgenOptimization=$applyOptimizationData `
/p:IbcOptimizationDataDir=$ibcDir `
$suppressExtensionDeployment `
@properties
}
finally {
${env:ROSLYNCOMMANDLINELOGFILE} = $null
}
}
......@@ -566,6 +581,15 @@ try {
}
}
if ($ci) {
$global:_DotNetInstallDir = Join-Path $RepoRoot ".dotnet"
InstallDotNetSdk $global:_DotNetInstallDir $GlobalJson.tools.dotnet
# Make sure a 2.1 runtime is installed so we can run our tests. Most of them still
# target netcoreapp2.1.
InstallDotNetSdk $global:_DotNetInstallDir "2.1.503"
}
if ($bootstrap) {
$bootstrapDir = Make-BootstrapBuild
}
......
......@@ -282,6 +282,9 @@ function BuildSolution {
InitializeDotNetCli $restore
# Make sure we have a 2.1 runtime available for running our tests
InstallDotNetSdk $_InitializeDotNetCli 2.1.503
bootstrap_dir=""
if [[ "$bootstrap" == true ]]; then
MakeBootstrapBuild
......
......@@ -11,11 +11,17 @@
</PropertyGroup>
<Import Project="$(MSBuildThisFileDirectory)DefaultVersions.props" Condition="Exists('$(MSBuildThisFileDirectory)DefaultVersions.props')" />
<!--
This won't be necessary once we solve this issue:
https://github.com/dotnet/arcade/issues/2266
-->
<Import Project="$(MSBuildThisFileDirectory)ArtifactsCategory.props" Condition="Exists('$(MSBuildThisFileDirectory)ArtifactsCategory.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.dotnet.build.tasks.feed\$(MicrosoftDotNetBuildTasksFeedVersion)\build\Microsoft.DotNet.Build.Tasks.Feed.targets" />
<Target Name="PublishToFeed">
<Error Condition="'$(TargetStaticFeed)' == ''" Text="TargetStaticFeed: Target feed for publishing assets wasn't provided." />
<Error Condition="'$(ArtifactsCategory)' == ''" Text="ArtifactsCategory: The artifacts' category produced by the build wasn't provided." />
<Error Condition="'$(AccountKeyToStaticFeed)' == ''" Text="AccountKeyToStaticFeed: Account key for target feed wasn't provided." />
<Error Condition="'$(ManifestsBasePath)' == ''" Text="Full path to asset manifests directory wasn't provided." />
<Error Condition="'$(BlobBasePath)' == '' AND '$(PackageBasePath)' == ''" Text="A valid full path to BlobBasePath of PackageBasePath is required." />
......@@ -26,7 +32,21 @@
</ItemGroup>
<Error Condition="'@(ManifestFiles)' == ''" Text="No manifest file was found in the provided path: $(ManifestsBasePath)" />
<!--
For now the type of packages being published will be informed for the whole build.
Eventually this will be specified on a per package basis:
TODO: https://github.com/dotnet/arcade/issues/2266
-->
<PropertyGroup>
<TargetStaticFeed Condition="'$(ArtifactsCategory.ToUpper())' == '.NETCORE'">https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json</TargetStaticFeed>
<TargetStaticFeed Condition="'$(ArtifactsCategory.ToUpper())' == '.NETCOREVALIDATION'">https://dotnetfeed.blob.core.windows.net/arcade-validation/index.json</TargetStaticFeed>
</PropertyGroup>
<Error
Condition="'$(TargetStaticFeed)' == ''"
Text="'$(ArtifactsCategory)' wasn't recognized as a valid artifact category. Valid categories are: '.NetCore' and '.NetCoreValidation'" />
<!-- Iterate publishing assets from each manifest file. -->
<PushArtifactsInManifestToFeed
ExpectedFeedUrl="$(TargetStaticFeed)"
......
......@@ -98,10 +98,20 @@ try {
Write-Verbose "Executing '$LocalInstallerCommand'"
Invoke-Expression "$LocalInstallerCommand"
if ($LASTEXITCODE -Ne "0") {
Write-Error "Execution failed"
exit 1
$errMsg = "$ToolName installation failed"
if ((Get-Variable 'DoNotAbortNativeToolsInstallationOnFailure' -ErrorAction 'SilentlyContinue') -and $DoNotAbortNativeToolsInstallationOnFailure) {
Write-Warning $errMsg
$toolInstallationFailure = $true
} else {
Write-Error $errMsg
exit 1
}
}
}
if ((Get-Variable 'toolInstallationFailure' -ErrorAction 'SilentlyContinue') -and $toolInstallationFailure) {
exit 1
}
}
else {
Write-Host "No native tools defined in global.json"
......
......@@ -52,6 +52,7 @@ jobs:
/p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests'
/p:BuildAssetRegistryToken=$(MaestroAccessToken)
/p:MaestroApiEndpoint=https://maestro-prod.westus2.cloudapp.azure.com
/p:PublishUsingPipelines=$(_PublishUsingPipelines)
/p:Configuration=$(_BuildConfig)
condition: ${{ parameters.condition }}
continueOnError: ${{ parameters.continueOnError }}
......
......@@ -2,7 +2,7 @@ parameters:
HelixSource: 'pr/default' # required -- sources must start with pr/, official/, prodcon/, or agent/
HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/'
HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number
HelixTargetQueues: '' # required -- semicolon delimited list of Helix queues to test on; see https://helix.dot.net/api/2018-03-14/info/queues for a list of queues
HelixTargetQueues: '' # required -- semicolon delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues
HelixAccessToken: '' # required -- access token to make Helix API requests; should be provided by the appropriate variable group
HelixPreCommands: '' # optional -- commands to run before Helix work item execution
HelixPostCommands: '' # optional -- commands to run after Helix work item execution
......
......@@ -14,7 +14,8 @@
DependsOnTargets="ResolveAssemblyReferences"
Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
<ItemGroup>
<SuggestedBindingRedirects Include="@(ReferencePath->'%(FusionName)')" MaxVersion="%(ReferencePath.Version)" KeepMetadata="-none-" Condition="'%(ReferencePath.FrameworkFile)' != 'true'" />
<!-- Note: ReferencePath.Version can be missing for design time builds prior to the first full build. -->
<SuggestedBindingRedirects Include="@(ReferencePath->'%(FusionName)')" MaxVersion="%(ReferencePath.Version)" KeepMetadata="-none-" Condition="'%(ReferencePath.FrameworkFile)' != 'true' and '%(ReferencePath.Version)' != ''" />
</ItemGroup>
</Target>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(CopyrightMicrosoft)' != ''">
<PropertyGroup>
<Copyright>$(CopyrightMicrosoft)</Copyright>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup>
<RepositoryUrl>https://github.com/dotnet/roslyn</RepositoryUrl>
<RepositoryRawUrl>https://raw.githubusercontent.com/dotnet/roslyn</RepositoryRawUrl>
<!-- Package Settings -->
<PackageLicenseUrl Condition="'$(PackageLicenseExpression)' == ''">$(RepositoryUrl)/blob/master/License.txt</PackageLicenseUrl>
<!-- The SPDX name for the source license. See https://spdx.org/licenses/. -->
<PackageLicenseType Condition="'$(PackageLicenseExpression)' == ''">Apache-2.0</PackageLicenseType>
<PackageIconUrl>https://go.microsoft.com/fwlink/?LinkID=288859</PackageIconUrl>
<PackageProjectUrl>https://github.com/dotnet/roslyn</PackageProjectUrl>
<PackageTags>Roslyn CodeAnalysis Compiler CSharp VB VisualBasic Parser Scanner Lexer Emit CodeGeneration Metadata IL Compilation Scripting Syntax Semantics</PackageTags>
<!--
Suppress a warning about upcoming deprecation of PackageLicenseUrl. When embedding licenses are supported,
replace PackageLicenseUrl with PackageLicenseExpression. See https://github.com/dotnet/roslyn/issues/31589 for details
-->
<NoWarn>$(NoWarn);NU5125</NoWarn>
<ThirdPartyNoticesFilePath>$(MSBuildThisFileDirectory)..\..\src\NuGet\ThirdPartyNotices.rtf</ThirdPartyNoticesFilePath>
<VSSDKTargetPlatformRegRootSuffix>RoslynDev</VSSDKTargetPlatformRegRootSuffix>
<!-- Disable the implicit nuget fallback folder as it makes it hard to locate and copy ref assemblies to the test output folder -->
......@@ -44,7 +29,6 @@
<!-- Set to non-existent file to prevent common targets from importing Microsoft.CodeAnalysis.targets -->
<CodeAnalysisTargets>*none*</CodeAnalysisTargets>
<ThirdPartyNoticesFilePath>$(MSBuildThisFileDirectory)..\..\src\NuGet\ThirdPartyNotices.rtf</ThirdPartyNoticesFilePath>
<DevDivPackagesDir>$(VisualStudioSetupOutputPath)DevDivPackages\</DevDivPackagesDir>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
......
......@@ -51,7 +51,8 @@
<_RelativePath>$([MSBuild]::MakeRelative($(RepoRoot), $(MSBuildProjectDirectory)))</_RelativePath>
<!-- TODO: Proper URL escaping -->
<_RawUrl>$(RepositoryRawUrl)/$(SourceRevisionId)/$(_RelativePath.Replace('\', '/'))/*</_RawUrl>
<_RepositoryRawUrl>https://raw.githubusercontent.com/dotnet/roslyn</_RepositoryRawUrl>
<_RawUrl>$(_RepositoryRawUrl)/$(SourceRevisionId)/$(_RelativePath.Replace('\', '/'))/*</_RawUrl>
<_Content>
<![CDATA[<?xml version="1.0" encoding="utf-8"?>
......
{
"tools": {
"dotnet": "2.1.401",
"dotnet": "3.0.100-preview3-010431",
"vs": {
"version": "16.0"
},
"xcopy-msbuild": "16.0.0-rc1-alpha"
},
"msbuild-sdks": {
"Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19162.7"
"Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19167.10"
}
}
......@@ -434,7 +434,7 @@ private BoundExpression CreateTupleLiteralConversion(SyntaxNode syntax, BoundTup
sourceTuple.Syntax,
sourceTuple.Type,
convertedArguments.ToImmutableAndFree(),
targetType);
targetType).WithSuppression(sourceTuple.IsSuppressed);
if (!TypeSymbol.Equals(sourceTuple.Type, destination, TypeCompareKind.ConsiderEverything2))
{
......
......@@ -286,7 +286,7 @@ private void InitializerCountRecursive(ImmutableArray<BoundExpression> inits, re
else
{
// NOTE: default values do not need to be initialized.
// .Net arrays are always zero-inited.
// .NET arrays are always zero-inited.
if (!init.IsDefaultValue())
{
initCount += 1;
......
......@@ -3236,7 +3236,7 @@ internal void SymbolDeclaredEvent(Symbol symbol)
/// <remarks>
/// In NetFx 4.0, block array initializers do not work on all combinations of {32/64 X Debug/Retail} when array elements are enums.
/// This is fixed in 4.5 thus enabling block array initialization for a very common case.
/// We look for the presence of <see cref="System.Runtime.GCLatencyMode.SustainedLowLatency"/> which was introduced in .Net 4.5
/// We look for the presence of <see cref="System.Runtime.GCLatencyMode.SustainedLowLatency"/> which was introduced in .NET Framework 4.5
/// </remarks>
internal bool EnableEnumArrayBlockInitialization
{
......
......@@ -1795,6 +1795,7 @@ private void VisitObjectCreationInitializer(Symbol containingSymbol, int contain
switch (node.Kind)
{
case BoundKind.ObjectInitializerExpression:
checkImplicitReceiver();
foreach (var initializer in ((BoundObjectInitializerExpression)node).Initializers)
{
switch (initializer.Kind)
......@@ -1809,6 +1810,7 @@ private void VisitObjectCreationInitializer(Symbol containingSymbol, int contain
}
break;
case BoundKind.CollectionInitializerExpression:
checkImplicitReceiver();
foreach (var initializer in ((BoundCollectionInitializerExpression)node).Initializers)
{
switch (initializer.Kind)
......@@ -1833,6 +1835,14 @@ private void VisitObjectCreationInitializer(Symbol containingSymbol, int contain
}
break;
}
void checkImplicitReceiver()
{
if (containingSlot >= 0)
{
_ = ReportPossibleNullReceiverIfNeeded(node.Type, this.State[containingSlot], checkNullableValueType: false, node.Syntax);
}
}
}
private void VisitObjectElementInitializer(int containingSlot, BoundAssignmentOperator node)
......@@ -5975,21 +5985,32 @@ private void CheckPossibleNullReceiver(BoundExpression receiverOpt, bool checkNu
#if DEBUG
Debug.Assert(receiverOpt.Type is null || AreCloseEnough(receiverOpt.Type, resultTypeSymbol));
#endif
if (ResultType.MayBeNull)
if (!ReportPossibleNullReceiverIfNeeded(resultTypeSymbol, ResultType.State, checkNullableValueType, receiverOpt.Syntax))
{
bool isValueType = resultTypeSymbol.IsValueType;
if (isValueType && (!checkNullableValueType || !resultTypeSymbol.IsNullableTypeOrTypeParameter() || resultTypeSymbol.GetNullableUnderlyingType().IsErrorType()))
{
return;
}
ReportSafetyDiagnostic(isValueType ? ErrorCode.WRN_NullableValueTypeMayBeNull : ErrorCode.WRN_NullReferenceReceiver, receiverOpt.Syntax);
return;
}
LearnFromNonNullTest(receiverOpt, ref this.State);
}
}
// Returns false if the type wasn't interesting
private bool ReportPossibleNullReceiverIfNeeded(TypeSymbol type, NullableFlowState state, bool checkNullableValueType, SyntaxNode syntax)
{
if (state.MayBeNull())
{
bool isValueType = type.IsValueType;
if (isValueType && (!checkNullableValueType || !type.IsNullableTypeOrTypeParameter() || type.GetNullableUnderlyingType().IsErrorType()))
{
return false;
}
ReportSafetyDiagnostic(isValueType ? ErrorCode.WRN_NullableValueTypeMayBeNull : ErrorCode.WRN_NullReferenceReceiver, syntax);
}
return true;
}
private static bool IsNullabilityMismatch(TypeWithAnnotations type1, TypeWithAnnotations type2)
{
// Note, when we are paying attention to nullability, we ignore insignificant differences and oblivious mismatch.
......
......@@ -2031,7 +2031,7 @@ public void AppConfig1()
[Fact]
public void AppConfig2()
{
// Create a dll with a reference to .net system
// Create a dll with a reference to .NET system
string libSource = @"
using System.Runtime.Versioning;
public class C { public static FrameworkName Goo() { return null; }}";
......
......@@ -1608,7 +1608,7 @@ interface ITest4<T, U>
);
}
[ClrOnlyFact(ClrOnlyReason.Ilasm), WorkItem(4163, "https://github.com/dotnet/roslyn/issues/4163")]
[Fact]
public void TypeUnification_03()
{
var ilSource = @"
......@@ -1756,7 +1756,7 @@ interface ITest4<T, U>
compilation.VerifyDiagnostics();
}
[ConditionalFact(typeof(ClrOnly), typeof(DesktopOnly))]
[ConditionalFact(typeof(DesktopOnly))]
[WorkItem(4163, "https://github.com/dotnet/roslyn/issues/4163")]
[WorkItem(18411, "https://github.com/dotnet/roslyn/issues/18411")]
public void DynamicEncodingDecoding_01()
......@@ -2038,7 +2038,7 @@ public override void Test(int [,] c)
Overridden");
}
[ConditionalFact(typeof(ClrOnly), typeof(DesktopOnly))]
[ConditionalFact(typeof(DesktopOnly))]
[WorkItem(5725, "https://github.com/dotnet/roslyn/issues/5725")]
[WorkItem(18411, "https://github.com/dotnet/roslyn/issues/18411")]
public void ModifiersWithConstructedType_01()
......@@ -2335,7 +2335,7 @@ System.ValueType I1.Test<U>(System.ValueType c)
CL3.Test");
}
[ConditionalFact(typeof(DesktopOnly), typeof(ClrOnly))]
[ConditionalFact(typeof(DesktopOnly))]
[WorkItem(5993, "https://github.com/dotnet/roslyn/issues/5993")]
[WorkItem(18411, "https://github.com/dotnet/roslyn/issues/18411")]
public void ConcatModifiersAndByRef_05()
......@@ -2392,7 +2392,7 @@ private static void Main()
});
}
[ConditionalFact(typeof(DesktopOnly), typeof(ClrOnly))]
[ConditionalFact(typeof(DesktopOnly))]
[WorkItem(18411, "https://github.com/dotnet/roslyn/issues/18411")]
public void ConcatModifiersAndByRef_06()
{
......
......@@ -313,7 +313,7 @@ class Test
Diagnostic(ErrorCode.ERR_BindToBogus, "M").WithArguments("RefTest.M(in int)").WithLocation(4, 38));
}
[ConditionalFact(typeof(ClrOnly))] // https://github.com/mono/mono/issues/6936
[Fact]
public void MissingInAttributeModreq_Method_Parameters_Override()
{
var reference = CompileIL(@"
......@@ -466,7 +466,7 @@ public static void Main()
CompileAndVerify(code, references: new[] { reference }, expectedOutput: "Child");
}
[ConditionalFact(typeof(ClrOnly))] // https://github.com/mono/mono/issues/6936
[Fact]
public void MissingInAttributeModreq_Method_Parameters_Override_ModOpt()
{
var reference = CompileIL(@"
......@@ -1259,7 +1259,7 @@ public void M(RefTest obj)
Diagnostic(ErrorCode.ERR_BindToBogus, "obj[0]").WithArguments("RefTest.this[in int]").WithLocation(6, 9));
}
[ConditionalFact(typeof(ClrOnly))] // https://github.com/mono/mono/issues/6936
[Fact]
public void MissingInAttributeModreq_Indexers_Parameters_Override()
{
var reference = CompileIL(@"
......@@ -1546,7 +1546,7 @@ Child Get
Child Set");
}
[ConditionalFact(typeof(ClrOnly))] // https://github.com/mono/mono/issues/6936
[Fact]
public void MissingInAttributeModreq_Indexers_Parameters_Override_Get()
{
var reference = CompileIL(@"
......@@ -1768,7 +1768,7 @@ public static void Main()
CompileAndVerify(code, references: new[] { reference }, expectedOutput: "Child Get");
}
[ConditionalFact(typeof(ClrOnly))] // https://github.com/mono/mono/issues/6936
[Fact]
public void MissingInAttributeModreq_Indexers_Parameters_Override_Set()
{
var reference = CompileIL(@"
......@@ -1970,7 +1970,7 @@ public static void Main()
CompileAndVerify(code, references: new[] { reference }, expectedOutput: "Child Set");
}
[ConditionalFact(typeof(ClrOnly))] // https://github.com/mono/mono/issues/6936
[Fact]
public void MissingInAttributeModreq_Indexers_Parameters_Override_ModOpt()
{
var reference = CompileIL(@"
......@@ -2257,7 +2257,7 @@ Child Get
Child Set");
}
[ConditionalFact(typeof(ClrOnly))] // https://github.com/mono/mono/issues/6936
[Fact]
public void MissingInAttributeModreq_Indexers_Parameters_Override_ModOpt_Get()
{
var reference = CompileIL(@"
......@@ -2479,7 +2479,7 @@ public static void Main()
CompileAndVerify(code, references: new[] { reference }, expectedOutput: "Child Get");
}
[ConditionalFact(typeof(ClrOnly))] // https://github.com/mono/mono/issues/6936
[Fact]
public void MissingInAttributeModreq_Indexers_Parameters_Override_ModOpt_Set()
{
var reference = CompileIL(@"
......
......@@ -1310,7 +1310,7 @@ static void Main()
}
[WorkItem(666162, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/666162")]
[ClrOnlyFact(ClrOnlyReason.Ilasm)]
[Fact]
public void Repro666162()
{
var il = @"
......
......@@ -1607,7 +1607,7 @@ public class Test { }
EntityHandle token = metadata.GetTypeRef(metadata.GetAssemblyRef("mscorlib"), "System.Runtime.CompilerServices", "AssemblyAttributesGoHereM");
Assert.True(token.IsNil); //could the type ref be located? If not then the attribute's not there.
// Exported types in .Net module cause PEVerify to fail.
// Exported types in .NET module cause PEVerify to fail.
CompileAndVerify(appCompilation, verify: Verification.Fails,
symbolValidator: m =>
{
......
......@@ -6981,7 +6981,7 @@ public class CF3<T>
forwardedTypes1Ref
}, TestOptions.ReleaseDll);
// Exported types in .Net modules cause PEVerify to fail on some platforms.
// Exported types in .NET modules cause PEVerify to fail on some platforms.
CompileAndVerify(compilation, verify: Verification.Skipped).VerifyDiagnostics();
compilation = CreateCompilation("[assembly: System.Runtime.CompilerServices.TypeForwardedToAttribute(typeof(CF3<byte>))]",
......
......@@ -515,8 +515,8 @@ public void ArrayTypes()
}
// Interfaces impl-ed by System.Array
// .Net 2/3.0 (7) IList&[T] -> ICollection&[T] ->IEnumerable&[T]; ICloneable;
// .Net 4.0 (9) IList&[T] -> ICollection&[T] ->IEnumerable&[T]; ICloneable; IStructuralComparable; IStructuralEquatable
// .NET 2/3.0 (7) IList&[T] -> ICollection&[T] ->IEnumerable&[T]; ICloneable;
// .NET 4.0 (9) IList&[T] -> ICollection&[T] ->IEnumerable&[T]; ICloneable; IStructuralComparable; IStructuralEquatable
// Array T[] impl IList[T] only
[Fact, WorkItem(537300, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537300"), WorkItem(527247, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/527247")]
public void ArrayTypeInterfaces()
......
......@@ -20,7 +20,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="$(MicrosoftDiaSymReaderNativeVersion)" Condition="'$(DotNetBuildFromSource)' != 'true'" />
<PackageReference Include="System.IO.Pipes.AccessControl" Version="$(SystemIOPipesAccessControlVersion)" Condition="'$(TargetFramework)' == 'netcoreapp2.1'" />
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="$(MicrosoftDiaSymReaderNativeVersion)"/>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Shared\RuntimeHostInfo.cs" />
......@@ -44,4 +43,4 @@
</None>
</ItemGroup>
<Import Project="..\..\Core\CommandLine\CommandLine.projitems" Label="Shared" />
</Project>
\ No newline at end of file
</Project>
......@@ -51,7 +51,7 @@ protected sealed override string GenerateCommandLineCommands()
/// <summary>
/// This generates the path to the executable that is directly ran.
/// This could be the managed assembly itself (on desktop .net on Windows),
/// This could be the managed assembly itself (on desktop .NET on Windows),
/// or a runtime such as dotnet.
/// </summary>
protected sealed override string GenerateFullPathToTool()
......
......@@ -71,7 +71,7 @@ public static bool LooksLikeTypeParameterName(this string name)
bool trimLeadingTypePrefix,
Func<char, char> convert)
{
// Special case the common .net pattern of "IGoo" as a type name. In this case we
// Special case the common .NET pattern of "IGoo" as a type name. In this case we
// want to generate "goo" as the parameter name.
if (!string.IsNullOrEmpty(shortName))
{
......
......@@ -21,7 +21,7 @@
<ItemGroup>
<Reference Include="System.Configuration" Condition="'$(TargetFramework)' != 'netcoreapp2.1'" />
<PackageReference Include="System.IO.Pipes.AccessControl" Version="$(SystemIOPipesAccessControlVersion)" Condition="'$(TargetFramework)' == 'netcoreapp2.1'" />
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="$(MicrosoftDiaSymReaderNativeVersion)"/>
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="$(MicrosoftDiaSymReaderNativeVersion)" Condition="'$(DotNetBuildFromSource)' != 'true'" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Shared\RuntimeHostInfo.cs" />
......@@ -43,4 +43,4 @@
<InternalsVisibleTo Include="VBCSCompiler.UnitTests" />
</ItemGroup>
<Import Project="..\..\Core\CommandLine\CommandLine.projitems" Label="Shared" />
</Project>
\ No newline at end of file
</Project>
......@@ -238,7 +238,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
InitializerCountRecursive(asArrayInit.Initializers, initCount, constInits)
Else
' NOTE Default values Do Not need To be initialized.
' .Net arrays are always zero-inited.
' .NET arrays are always zero-inited.
If Not init.IsDefaultValue() Then
initCount += 1
If init.ConstantValueOpt IsNot Nothing Then
......
......@@ -1278,7 +1278,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
''' <remarks>
''' In NetFx 4.0, block array initializers do not work on all combinations of {32/64 X Debug/Retail} when array elements are enums.
''' This is fixed in 4.5 thus enabling block array initialization for a very common case.
''' We look for the presence of <see cref="System.Runtime.GCLatencyMode.SustainedLowLatency"/> which was introduced in .Net 4.5
''' We look for the presence of <see cref="System.Runtime.GCLatencyMode.SustainedLowLatency"/> which was introduced in .NET Framework 4.5
''' </remarks>
Friend ReadOnly Property EnableEnumArrayBlockInitialization As Boolean
Get
......
......@@ -1042,7 +1042,7 @@ End class
token = metadata.GetTypeRef(metadata.GetAssemblyRef("mscorlib"), "System.Runtime.CompilerServices", "AssemblyAttributesGoHereM")
Assert.True(token.IsNil) 'could the type ref be located? If not then the attribute's not there.
' Exported types in .Net module cause PEVerify to fail.
' Exported types in .NET module cause PEVerify to fail.
CompileAndVerify(appCompilation, verify:=Verification.Fails,
symbolValidator:=Sub(m)
Dim metadataReader1 = DirectCast(m, PEModuleSymbol).Module.GetMetadataReader()
......@@ -1210,7 +1210,7 @@ End class
Dim appCompilation = CreateCompilationWithMscorlib40AndReferences(app, {modRef, New VisualBasicCompilationReference(forwardedTypesCompilation)}, TestOptions.ReleaseDll)
' Exported types in .Net module cause PEVerify to fail.
' Exported types in .NET module cause PEVerify to fail.
CompileAndVerify(appCompilation, verify:=Verification.Fails,
symbolValidator:=Sub(m)
Dim peReader1 = DirectCast(m, PEModuleSymbol).Module.GetMetadataReader()
......
......@@ -3195,7 +3195,7 @@ BC37218: Type 'ns.CF2' forwarded to assembly 'ForwardedTypes1, Version=0.0.0.0,
forwardedTypes1Ref
}, TestOptions.ReleaseDll)
' Exported types in .Net modules cause PEVerify to fail.
' Exported types in .NET modules cause PEVerify to fail.
CompileAndVerify(compilation, verify:=Verification.Fails).VerifyDiagnostics()
compilation = CreateCompilationWithMscorlib40AndReferences(emptySource,
......
......@@ -341,7 +341,7 @@ CaseLabel2:
End Set
End Property
'vb.net can't support abstract member variable
'VB.NET can't support abstract member variable
Public ReadOnly Property P2() As String
Get
End Get
......
......@@ -315,7 +315,7 @@ CaseLabel2:
End Set
End Property
'vb.net can't support abstract member variable
'VB.NET can't support abstract member variable
Public ReadOnly Property P2() As String
Get
End Get
......
......@@ -19,7 +19,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="$(MicrosoftDiaSymReaderNativeVersion)" Condition="'$(DotNetBuildFromSource)' != 'true'" />
<PackageReference Include="System.IO.Pipes.AccessControl" Version="$(SystemIOPipesAccessControlVersion)" Condition="'$(TargetFramework)' == 'netcoreapp2.1'" />
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="$(MicrosoftDiaSymReaderNativeVersion)"/>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Shared\RuntimeHostInfo.cs" />
......@@ -43,4 +42,4 @@
</None>
</ItemGroup>
<Import Project="..\..\Core\CommandLine\CommandLine.projitems" Label="Shared" />
</Project>
\ No newline at end of file
</Project>
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata minClientVersion="3.3">
<id>$PackageId$</id>
<description>$PackageDescription$</description>
<version>$Version$</version>
<authors>$Authors$</authors>
<requireLicenseAcceptance>$RequireLicenseAcceptance$</requireLicenseAcceptance>
<licenseUrl>$PackageLicenseUrl$</licenseUrl>
<projectUrl>$PackageProjectUrl$</projectUrl>
<copyright>$Copyright$</copyright>
<developmentDependency>$DevelopmentDependency$</developmentDependency>
<tags>$PackageTags$</tags>
<serviceable>$Serviceable$</serviceable>
<repository type="$RepositoryType$" url="$RepositoryUrl$" commit="$RepositoryCommit$" />
$CommonMetadataElements$
<dependencies>
<dependency id="Microsoft.CodeAnalysis.PooledObjects" version="$Version$" />
</dependencies>
......
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata minClientVersion="3.3">
<id>$PackageId$</id>
<description>$PackageDescription$</description>
<version>$Version$</version>
<authors>$Authors$</authors>
<requireLicenseAcceptance>$RequireLicenseAcceptance$</requireLicenseAcceptance>
<licenseUrl>$PackageLicenseUrl$</licenseUrl>
<projectUrl>$PackageProjectUrl$</projectUrl>
<copyright>$Copyright$</copyright>
<developmentDependency>$DevelopmentDependency$</developmentDependency>
<tags>$PackageTags$</tags>
<serviceable>$Serviceable$</serviceable>
<repository type="$RepositoryType$" url="$RepositoryUrl$" commit="$RepositoryCommit$" />
$CommonMetadataElements$
<contentFiles>
<files include="**/*.cs" buildAction="Compile" />
</contentFiles>
......
......@@ -6662,5 +6662,206 @@ void M(object p)
}
}", PreferUnusedLocal);
}
[WorkItem(33949, "https://github.com/dotnet/roslyn/issues/33949")]
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard))]
[InlineData(nameof(PreferUnusedLocal))]
public async Task UsedInArgumentAfterAnArgumentWithControlFlow(string optionName)
{
await TestMissingInRegularAndScriptAsync(
@"class A
{
public static void M(int? x)
{
A [|a|] = new A();
a = M2(x ?? 1, a);
}
private static A M2(int? x, A a)
{
return a;
}
}", optionName);
}
[WorkItem(33949, "https://github.com/dotnet/roslyn/issues/33949")]
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard))]
[InlineData(nameof(PreferUnusedLocal))]
public async Task ConpoundAssignmentWithControlFlowInValue(string optionName)
{
await TestMissingInRegularAndScriptAsync(
@"class A
{
public static void M(int? x)
{
int [|a|] = 1;
a += M2(x ?? 1);
}
private static int M2(int? x) => 0;
}", optionName);
}
[WorkItem(33843, "https://github.com/dotnet/roslyn/issues/33843")]
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard))]
[InlineData(nameof(PreferUnusedLocal))]
public async Task UsedValueWithUsingStatementAndLocalFunction(string optionName)
{
await TestMissingInRegularAndScriptAsync(
@"using System;
class C
{
private class Disposable : IDisposable { public void Dispose() { } }
public int M()
{
var result = 0;
void append() => [|result|] += 1; // IDE0059 for 'result'
using (var a = new Disposable())
append();
return result;
}
}", optionName);
}
[WorkItem(33843, "https://github.com/dotnet/roslyn/issues/33843")]
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard))]
[InlineData(nameof(PreferUnusedLocal))]
public async Task UsedValueWithUsingStatementAndLambda(string optionName)
{
await TestMissingInRegularAndScriptAsync(
@"using System;
class C
{
private class Disposable : IDisposable { public void Dispose() { } }
public int M()
{
var result = 0;
Action append = () => [|result|] += 1; // IDE0059 for 'result'
using (var a = new Disposable())
append();
return result;
}
}", optionName);
}
[WorkItem(33843, "https://github.com/dotnet/roslyn/issues/33843")]
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard))]
[InlineData(nameof(PreferUnusedLocal))]
public async Task UsedValueWithUsingStatementAndLambda_02(string optionName)
{
await TestMissingInRegularAndScriptAsync(
@"using System;
class C
{
private class Disposable : IDisposable { public void Dispose() { } }
public int M()
{
var result = 0;
Action appendLambda = () => [|result|] += 1;
void appendLocalFunction() => appendLambda();
Action appendDelegate = appendLocalFunction;
using (var a = new Disposable())
appendDelegate();
return result;
}
}", optionName);
}
[WorkItem(33843, "https://github.com/dotnet/roslyn/issues/33843")]
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard))]
[InlineData(nameof(PreferUnusedLocal))]
public async Task UsedValueWithUsingStatementAndLambda_03(string optionName)
{
await TestMissingInRegularAndScriptAsync(
@"using System;
class C
{
private class Disposable : IDisposable { public void Dispose() { } }
public int M()
{
var result = 0;
void appendLocalFunction() => [|result|] += 1;
Action appendLambda = () => appendLocalFunction();
Action appendDelegate = appendLambda;
using (var a = new Disposable())
appendDelegate();
return result;
}
}", optionName);
}
[WorkItem(33937, "https://github.com/dotnet/roslyn/issues/33937")]
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard))]
[InlineData(nameof(PreferUnusedLocal))]
public async Task AssignedInCatchUsedInFinally_ThrowInCatch(string optionName)
{
await TestMissingInRegularAndScriptAsync(
@"using System;
public static class Program
{
public static void Test()
{
var exceptionThrown = false;
try
{
throw new Exception();
}
catch
{
// The `exceptionThrown` token is incorrectly greyed out in the IDE
// IDE0059 Value assigned to 'exceptionThrown' is never used
[|exceptionThrown|] = true;
throw;
}
finally
{
// Breakpoint on this line is hit and 'true' is printed
Console.WriteLine(exceptionThrown);
}
}
}", optionName);
}
[WorkItem(33937, "https://github.com/dotnet/roslyn/issues/33937")]
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard))]
[InlineData(nameof(PreferUnusedLocal))]
public async Task AssignedInCatchUsedInFinally_NoThrowInCatch(string optionName)
{
await TestMissingInRegularAndScriptAsync(
@"using System;
public static class Program
{
public static void Test()
{
var exceptionThrown = false;
try
{
throw new Exception();
}
catch
{
[|exceptionThrown|] = true;
}
finally
{
Console.WriteLine(exceptionThrown);
}
}
}", optionName);
}
}
}
......@@ -2,10 +2,13 @@
using System;
using System.Composition;
using System.IO;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.VisualStudio.CodingConventions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Options
{
......@@ -13,21 +16,148 @@ namespace Microsoft.CodeAnalysis.Editor.Options
class EditorConfigDocumentOptionsProviderFactory : IDocumentOptionsProviderFactory
{
private readonly ICodingConventionsManager _codingConventionsManager;
private readonly IFileWatcher _fileWatcher;
private readonly IAsynchronousOperationListenerProvider _asynchronousOperationListenerProvider;
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public EditorConfigDocumentOptionsProviderFactory(
ICodingConventionsManager codingConventionsManager,
IFileWatcher fileWatcher,
IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider)
{
_codingConventionsManager = codingConventionsManager;
_fileWatcher = fileWatcher;
_asynchronousOperationListenerProvider = asynchronousOperationListenerProvider;
}
public IDocumentOptionsProvider Create(Workspace workspace)
{
return new EditorConfigDocumentOptionsProvider(workspace, _codingConventionsManager, _asynchronousOperationListenerProvider);
ICodingConventionsManager codingConventionsManager;
if (workspace.Kind == WorkspaceKind.RemoteWorkspace)
{
// If it's the remote workspace, it's our own implementation of the file watcher which is already doesn't have
// UI thread dependencies.
codingConventionsManager = _codingConventionsManager;
}
else
{
// The default file watcher implementation inside Visual Studio accientally depends on the UI thread
// (sometimes!) when trying to add a watch to a file. This can cause us to deadlock, since our assumption is
// consumption of a coding convention can be done freely without having to use a JTF-friendly wait.
// So we'll wrap the standard file watcher with one that defers the file watches until later.
var deferredFileWatcher = new DeferredFileWatcher(_fileWatcher, _asynchronousOperationListenerProvider);
codingConventionsManager = CodingConventionsManagerFactory.CreateCodingConventionsManager(deferredFileWatcher);
}
return new EditorConfigDocumentOptionsProvider(workspace, codingConventionsManager, _asynchronousOperationListenerProvider);
}
/// <summary>
/// An implementation of <see cref="IFileWatcher"/> that ensures we don't watch for a file synchronously to
/// avoid deadlocks.
/// </summary>
internal class DeferredFileWatcher : IFileWatcher
{
private readonly IFileWatcher _fileWatcher;
private readonly SimpleTaskQueue _taskQueue = new SimpleTaskQueue(TaskScheduler.Default);
private readonly IAsynchronousOperationListener _listener;
public DeferredFileWatcher(IFileWatcher fileWatcher, IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider)
{
_fileWatcher = fileWatcher;
_fileWatcher.ConventionFileChanged += OnConventionFileChanged;
_listener = asynchronousOperationListenerProvider.GetListener(FeatureAttribute.Workspace);
}
private Task OnConventionFileChanged(object sender, ConventionsFileChangeEventArgs arg)
{
return ConventionFileChanged?.Invoke(this, arg) ?? Task.CompletedTask;
}
public event ConventionsFileChangedAsyncEventHandler ConventionFileChanged;
public event ContextFileMovedAsyncEventHandler ContextFileMoved
{
add
{
_fileWatcher.ContextFileMoved += value;
}
remove
{
_fileWatcher.ContextFileMoved -= value;
}
}
public void Dispose()
{
_fileWatcher.ConventionFileChanged -= OnConventionFileChanged;
_fileWatcher.Dispose();
}
public void StartWatching(string fileName, string directoryPath)
{
var asyncToken = _listener.BeginAsyncOperation(nameof(DeferredFileWatcher) + "." + nameof(StartWatching));
// Read the file time stamp right now; we want to know if it changes between now
// and our ability to get the file watcher in place.
var originalFileTimeStamp = TryGetFileTimeStamp(fileName, directoryPath);
_taskQueue.ScheduleTask(() =>
{
_fileWatcher.StartWatching(fileName, directoryPath);
var newFileTimeStamp = TryGetFileTimeStamp(fileName, directoryPath);
if (originalFileTimeStamp != newFileTimeStamp)
{
ChangeType changeType;
if (!originalFileTimeStamp.HasValue && newFileTimeStamp.HasValue)
{
changeType = ChangeType.FileCreated;
}
else if (originalFileTimeStamp.HasValue && !newFileTimeStamp.HasValue)
{
changeType = ChangeType.FileDeleted;
}
else
{
changeType = ChangeType.FileModified;
}
ConventionFileChanged?.Invoke(this,
new ConventionsFileChangeEventArgs(fileName, directoryPath, changeType));
}
}).CompletesAsyncOperation(asyncToken);
}
private static DateTime? TryGetFileTimeStamp(string fileName, string directoryPath)
{
try
{
var fullFilePath = Path.Combine(directoryPath, fileName);
// Avoid a first-chance exception if the file definitely doesn't exist
if (!File.Exists(fullFilePath))
{
return null;
}
return FileUtilities.GetFileTimeStamp(fullFilePath);
}
catch (IOException)
{
return null;
}
}
public void StopWatching(string fileName, string directoryPath)
{
_taskQueue.ScheduleTask(() => _fileWatcher.StopWatching(fileName, directoryPath));
}
}
}
}
// 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 System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CommentSelection;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Editor.Implementation.CommentSelection
{
/// <summary>
/// Bridge between the new <see cref="ICommentSelectionService"/> and an existing
/// language which only supplies the old <see cref="ICommentUncommentService"/> service.
/// </summary>
internal class CommentSelectionServiceProxy : ICommentSelectionService
{
#pragma warning disable CS0618 // Type or member is obsolete
private readonly ICommentUncommentService _commentUncommentService;
public CommentSelectionServiceProxy(ICommentUncommentService commentUncommentService)
{
_commentUncommentService = commentUncommentService;
}
#pragma warning restore CS0618 // Type or member is obsolete
public Task<CommentSelectionInfo> GetInfoAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken)
=> Task.FromResult(new CommentSelectionInfo(
true, _commentUncommentService.SupportsBlockComment, _commentUncommentService.SingleLineCommentString,
_commentUncommentService.BlockCommentStartString, _commentUncommentService.BlockCommentEndString));
public Task<Document> FormatAsync(Document document, ImmutableArray<TextSpan> changes, CancellationToken cancellationToken)
=> Task.FromResult(_commentUncommentService.Format(document, changes, cancellationToken));
}
}
......@@ -146,15 +146,6 @@ private ICommentSelectionService GetService(Document document)
return service;
}
// If we couldn't find one, fallback to the legacy service.
#pragma warning disable CS0618 // Type or member is obsolete
var legacyService = document.GetLanguageService<ICommentUncommentService>();
#pragma warning restore CS0618 // Type or member is obsolete
if (legacyService != null)
{
return new CommentSelectionServiceProxy(legacyService);
}
return null;
}
......
// 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.Threading;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Editor.Implementation.CommentSelection
{
[Obsolete("Use Microsoft.CodeAnalysis.CommentSelection.ICommentSelectionService instead")]
internal interface ICommentUncommentService : ILanguageService
{
string SingleLineCommentString { get; }
bool SupportsBlockComment { get; }
string BlockCommentStartString { get; }
string BlockCommentEndString { get; }
Document Format(Document document, IEnumerable<TextSpan> changes, CancellationToken cancellationToken);
}
}
......@@ -363,7 +363,7 @@ private static IPropertySymbol GenerateProperty(Document document, IPropertySymb
// in the type. Instead, we just want to generate auto-props. So we effectively clone
// the property, just throwing aways anything we don't need for that purpose.
//
// We also want to follow general .net naming. So that means converting to pascal
// We also want to follow general .NET naming. So that means converting to pascal
// case from camel-case.
var getMethod = prop.GetMethod != null ? CreateAccessorSymbol(prop, MethodKind.PropertyGet) : null;
......
......@@ -373,7 +373,7 @@ private void ProvideEscapeCategoryCompletions(EmbeddedCompletionContext context)
context.AddIfMissing($@"\k< {Regex_name_or_number} >", Regex_named_backreference_short, Regex_named_backreference_long, parentOpt, @"\k<".Length, insertionText: @"\k<>");
// Note: we intentionally do not add `\<>` to the list. While supported by the
// .net regex engine, it is effectively deprecated and discouraged from use.
// .NET regex engine, it is effectively deprecated and discouraged from use.
// Instead, it is recommended that `\k<>` is used instead.
//
// context.AddIfMissing(@"\<>", "", "", parentOpt, @"\<".Length));
......
......@@ -110,7 +110,7 @@ private State(Compilation compilation)
if (char.IsLower(name[0]) && !semanticDocument.SemanticModel.Compilation.IsCaseSensitive)
{
// It's near universal in .Net that types start with a capital letter. As such,
// It's near universal in .NET that types start with a capital letter. As such,
// if this name starts with a lowercase letter, don't even bother to offer
// "generate type". The user most likely wants to run 'Add Import' (which will
// then fix up a case where they typed an existing type name in lowercase,
......
......@@ -121,7 +121,7 @@ internal abstract partial class AbstractNavigateToSearchService
}
// Would like to use CWT.AddOrUpdate. But that is not available on the
// version of .Net that we're using. So we need to take lock as we're
// version of .NET that we're using. So we need to take lock as we're
// making multiple mutations.
lock (s_lastProjectSearchCache)
{
......
......@@ -24,7 +24,7 @@ public static BitVector Run(ControlFlowGraph controlFlowGraph)
public override bool AnalyzeBlock(BasicBlock basicBlock, CancellationToken cancellationToken)
{
SetCurrentAnalysisData(basicBlock, isReachable: true);
SetCurrentAnalysisData(basicBlock, isReachable: true, cancellationToken);
return true;
}
......@@ -54,7 +54,7 @@ public override bool AnalyzeNonConditionalBranch(BasicBlock basicBlock, bool cur
return (currentIsReachable, currentIsReachable);
}
public override void SetCurrentAnalysisData(BasicBlock basicBlock, bool isReachable)
public override void SetCurrentAnalysisData(BasicBlock basicBlock, bool isReachable, CancellationToken cancellationToken)
{
_visited[basicBlock.Ordinal] = isReachable;
}
......
......@@ -1190,7 +1190,7 @@ CaseLabel2:
End Set
End Property
'vb.net can't support abstract member variable
'VB.NET can't support abstract member variable
Public ReadOnly Property P2() As String
Get
End Get
......@@ -2234,7 +2234,7 @@ CaseLabel2:
End Set
End Property
'vb.net can't support abstract member variable
'VB.NET can't support abstract member variable
Public ReadOnly Property P2() As String
Get
End Get
......
......@@ -103,10 +103,13 @@ private bool CheckDesktop(TextWriter textWriter, IEnumerable<string> assetRelati
string.Empty,
assetRelativeNames);
// Temporarily inserting Microsoft.DiaSymReader.Native.arm.dll while SDK team tracks down why
// it's being inserted into destkop builds.
// https://github.com/dotnet/cli/issues/10979
allGood &= VerifyVsix(
textWriter,
FindVsix("Roslyn.Compilers.Extension"),
assetRelativeNames.Concat(new[] { "Roslyn.Compilers.Extension.dll" }));
assetRelativeNames.Concat(new[] { "Roslyn.Compilers.Extension.dll", "Microsoft.DiaSymReader.Native.arm.dll" }));
return allGood;
}
......@@ -172,6 +175,7 @@ private bool GetPackageAssets(TextWriter textWriter, List<PackageAsset> packageA
// root as well. That copy is unnecessary.
coreClrAssets.RemoveAll(asset =>
PathComparer.Equals("Microsoft.DiaSymReader.Native.amd64.dll", asset.FileRelativeName) ||
PathComparer.Equals("Microsoft.DiaSymReader.Native.arm.dll", asset.FileRelativeName) ||
PathComparer.Equals("Microsoft.DiaSymReader.Native.x86.dll", asset.FileRelativeName));
// Move all of the assets into bincore as that is where the non-MSBuild task assets will go
......
......@@ -383,7 +383,7 @@ internal bool IsCPSProject(CodeAnalysis.Project project)
if (this.TryGetHierarchy(project.Id, out var hierarchy))
{
// Currently renaming files in CPS projects (i.e. .Net Core) doesn't work proprey.
// Currently renaming files in CPS projects (i.e. .NET Core) doesn't work proprey.
// This is because the remove/add of the documents in CPS is not synchronous
// (despite the DTE interfaces being synchronous). So Roslyn calls the methods
// expecting the changes to happen immediately. Because they are deferred in CPS
......
......@@ -5,6 +5,7 @@
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.VisualStudio.ComponentModelHost;
......@@ -18,19 +19,14 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Utilities
internal sealed class VisualStudioWaitIndicator : IWaitIndicator
{
private readonly SVsServiceProvider _serviceProvider;
private readonly bool _isUpdate1;
private static readonly Func<string, string, string> s_messageGetter = (t, m) => string.Format("{0} : {1}", t, m);
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public VisualStudioWaitIndicator(SVsServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
var shell = serviceProvider.GetService(typeof(SVsShell)) as IVsShell;
shell.GetProperty((int)__VSSPROPID5.VSSPROPID_ReleaseVersion, out var property);
_isUpdate1 = Equals(property, "14.0.24720.0 D14REL");
}
public WaitIndicatorResult Wait(
......@@ -59,13 +55,6 @@ public VisualStudioWaitIndicator(SVsServiceProvider serviceProvider)
private VisualStudioWaitContext StartWait(
string title, string message, bool allowCancel, bool showProgress)
{
// Update1 has a bug where trying to update hte progress bar will cause a hang.
// Check if we're on update1 and turn off 'showProgress' in that case.
if (_isUpdate1)
{
showProgress = false;
}
var componentModel = (IComponentModel)_serviceProvider.GetService(typeof(SComponentModel));
var workspace = componentModel.GetService<VisualStudioWorkspace>();
Contract.ThrowIfNull(workspace);
......
......@@ -21,7 +21,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Venus
internal sealed partial class ContainedDocument
{
// this is to support old venus/razor case before dev16.
// all new razor (asp.net core after dev16) should use thier own implementation not ours
// all new razor (asp.NET core after dev16) should use thier own implementation not ours
public class DocumentServiceProvider : IDocumentServiceProvider
{
private readonly SpanMapper _spanMapper;
......
......@@ -30,7 +30,7 @@ public override void ErrorLevelWarning()
base.ErrorLevelWarning();
}
[WpfFact, Trait(Traits.Feature, Traits.Features.ErrorList)]
[WpfFact(Skip = "https://github.com/dotnet/roslyn/issues/34211"), Trait(Traits.Feature, Traits.Features.ErrorList)]
[Trait(Traits.Feature, Traits.Features.NetCore)]
public override void ErrorsDuringMethodBodyEditing()
{
......
......@@ -26,7 +26,7 @@ public override void OpenCSharpThenVBSolution()
base.OpenCSharpThenVBSolution();
}
[WpfFact, Trait(Traits.Feature, Traits.Features.Workspace)]
[WpfFact(Skip = "https://github.com/dotnet/cli/issues/10989"), Trait(Traits.Feature, Traits.Features.Workspace)]
[Trait(Traits.Feature, Traits.Features.NetCore)]
public override void MetadataReference()
{
......
......@@ -69,7 +69,7 @@ public static bool LooksLikeStandaloneTypeName(this SimpleNameSyntax simpleName)
// "Standalone type name".
//
// 1. Users are not going to name types the same name as C# keywords (contextual or otherwise).
// 2. Types in .Net are virtually always start with a Uppercase. While keywords are lowercase)
// 2. Types in .NET are virtually always start with a Uppercase. While keywords are lowercase)
//
// Having a lowercase identifier which matches a c# keyword is enough of a signal
// to just not treat this as a standalone type name (even though for some identifiers
......
......@@ -146,25 +146,25 @@ private SyntaxToken GetStringToken(string text)
}
catch (IndexOutOfRangeException) when (allowIndexOutOfRange)
{
// bug with .net regex parser. Can happen with patterns like: (?<-0
// bug with .NET regex parser. Can happen with patterns like: (?<-0
Assert.NotEmpty(tree.Diagnostics);
return treeAndText;
}
catch (NullReferenceException) when (allowNullReference)
{
// bug with .net regex parser. can happen with patterns like: (?(?S))
// bug with .NET regex parser. can happen with patterns like: (?(?S))
return treeAndText;
}
catch (OutOfMemoryException) when (allowOutOfMemeory)
{
// bug with .net regex parser. can happen with patterns like: a{2147483647,}
// bug with .NET regex parser. can happen with patterns like: a{2147483647,}
return treeAndText;
}
catch (ArgumentException ex)
{
Assert.NotEmpty(tree.Diagnostics);
// Ensure the diagnostic we emit is the same as the .Net one. Note: we can only
// Ensure the diagnostic we emit is the same as the .NET one. Note: we can only
// do this in en-US as that's the only culture where we control the text exactly
// and can ensure it exactly matches Regex. We depend on localization to do a
// good enough job here for other languages.
......
......@@ -316,7 +316,7 @@ public void Visit(RegexTextNode node)
public void Visit(RegexPosixPropertyNode node)
{
// The .net parser just interprets the [ of the node, and skips the rest. So
// The .NET parser just interprets the [ of the node, and skips the rest. So
// classify the end part as a comment.
Result.Add(new ClassifiedSpan(node.TextToken.VirtualChars[0].Span, ClassificationTypeNames.RegexText));
Result.Add(new ClassifiedSpan(
......
......@@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions
/// <summary>
/// Minimal copy of https://github.com/dotnet/corefx/blob/master/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs
/// Used to accurately determine if something is a WordChar according to the .Net regex engine.
/// Used to accurately determine if something is a WordChar according to the .NET regex engine.
/// </summary>
internal static class RegexCharClass
{
......
......@@ -440,7 +440,7 @@ public RegexToken ScanOctalCharacters(RegexOptions options)
Position++;
// Ecmascript doesn't allow octal values above 32 (0x20 in hex). Note: we do
// *not* add a diagnostic. This is not an error situation. The .net lexer
// *not* add a diagnostic. This is not an error situation. The .NET lexer
// simply stops once it hits a value greater than a legal octal value.
if (HasOption(options, RegexOptions.ECMAScript) && currentVal >= 0x20)
{
......
......@@ -263,7 +263,7 @@ public override void Accept(IRegexNodeVisitor visitor)
}
/// <summary>
/// Represents a ```[:...:]``` node in a character class. Note: the .net regex parser
/// Represents a ```[:...:]``` node in a character class. Note: the .NET regex parser
/// simply treats this as the character ```[``` and ignores the rest of the ```:...:]```.
/// They latter part has no impact on the actual match engine that is produced.
/// </summary>
......
......@@ -23,18 +23,18 @@ namespace Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions
/// Produces a <see cref="RegexTree"/> from a sequence of <see cref="VirtualChar"/> characters.
///
/// Importantly, this parser attempts to replicate diagnostics with almost the exact same text
/// as the native .Net regex parser. This is important so that users get an understandable
/// as the native .NET regex parser. This is important so that users get an understandable
/// experience where it appears to them that this is all one cohesive system and that the IDE
/// will let them discover and fix the same issues they would encounter when previously trying
/// to just compile and execute these regexes.
/// </summary>
/// <remarks>
/// Invariants we try to maintain (and should consider a bug if we do not): l 1. If the .net
/// Invariants we try to maintain (and should consider a bug if we do not): l 1. If the .NET
/// regex parser does not report an error for a given pattern, we should not either. it would be
/// very bad if we told the user there was something wrong with there pattern when there really
/// wasn't.
///
/// 2. If the .net regex parser does report an error for a given pattern, we should either not
/// 2. If the .NET regex parser does report an error for a given pattern, we should either not
/// report an error (not recommended) or report the same error at an appropriate location in the
/// pattern. Not reporting the error can be confusing as the user will think their pattern is
/// ok, when it really is not. However, it can be acceptable to do this as it's not telling
......@@ -43,23 +43,23 @@ namespace Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions
/// documented in <see cref="ParsePossibleEcmascriptBackreferenceEscape"/>).
///
/// Note1: "report the same error" means that we will attempt to report the error using the same
/// text the .net regex parser uses for its error messages. This is so that the user is not
/// text the .NET regex parser uses for its error messages. This is so that the user is not
/// confused when they use the IDE vs running the regex by getting different messages for the
/// same issue.
///
/// Note2: the above invariants make life difficult at times. This happens due to the fact that
/// the .net parser is multi-pass. Meaning it does a first scan (which may report errors), then
/// the .NET parser is multi-pass. Meaning it does a first scan (which may report errors), then
/// does the full parse. This means that it might report an error in a later location during
/// the initial scan than it would during the parse. We replicate that behavior to follow the
/// second invariant.
///
/// Note3: It would be nice if we could check these invariants at runtime, so we could control
/// our behavior by the behavior of the real .net regex engine. For example, if the .net regex
/// our behavior by the behavior of the real .NET regex engine. For example, if the .NET regex
/// engine did not report any issues, we could suppress any diagnostics we generated and we
/// could log an NFW to record which pattern we deviated on so we could fix the issue for a
/// future release. However, we cannot do this as the .net regex engine has no guarantees about
/// future release. However, we cannot do this as the .NET regex engine has no guarantees about
/// its performance characteristics. For example, certain regex patterns might end up causing
/// that engine to consume unbounded amounts of CPU and memory. This is because the .net regex
/// that engine to consume unbounded amounts of CPU and memory. This is because the .NET regex
/// engine is not just a parser, but something that builds an actual recognizer using techniques
/// that are not necessarily bounded. As such, while we test ourselves around it during our
/// tests, we cannot do the same at runtime as part of the IDE.
......@@ -67,7 +67,7 @@ namespace Microsoft.CodeAnalysis.EmbeddedLanguages.RegularExpressions
/// This parser was based off the corefx RegexParser based at:
/// https://github.com/dotnet/corefx/blob/f759243d724f462da0bcef54e86588f8a55352c6/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs#L1
///
/// Note4: The .Net parser itself changes over time (for example to fix behavior that even it
/// Note4: The .NET parser itself changes over time (for example to fix behavior that even it
/// thinks is buggy). When this happens, we have to make a choice as to which behavior to
/// follow. In general, the overall principle is that we should follow the more lenient
/// behavior. If we end up taking the more strict interpretation we risk giving people an error
......@@ -104,7 +104,7 @@ internal partial struct RegexParser
/// produce the next token after that.
/// </summary>
/// <param name="allowTrivia">Whether or not trivia is allowed on the next token
/// produced. In the .net parser trivia is only allowed on a few constructs,
/// produced. In the .NET parser trivia is only allowed on a few constructs,
/// and our parser mimics that behavior. Note that even if trivia is allowed,
/// the type of trivia that can be scanned depends on the current RegexOptions.
/// For example, if <see cref="RegexOptions.IgnorePatternWhitespace"/> is currently
......@@ -135,7 +135,7 @@ public static RegexTree TryParse(VirtualCharSequence text, RegexOptions options)
// to then parse the tree again, as the captures will affect how we interpret
// certain things (i.e. escape references) and what errors will be reported.
//
// This is necessary as .net regexes allow references to *future* captures.
// This is necessary as .NET regexes allow references to *future* captures.
// As such, we don't know when we're seeing a reference if it's to something
// that exists or not.
var tree1 = new RegexParser(text, options,
......@@ -235,7 +235,7 @@ private RegexExpressionNode ParseAlternatingSequences(bool consumeCloseParen)
/// <summary>
/// Parses out code of the form: ...|...|...
/// This is the type of code you have at the top level of a regex, or inside any grouping
/// contruct. Note that sequences can be empty in .net regex. i.e. the following is legal:
/// contruct. Note that sequences can be empty in .NET regex. i.e. the following is legal:
///
/// ...||...
///
......@@ -853,7 +853,7 @@ private void MoveBackBeforePreviousScan()
private RegexConditionalGroupingNode ParseConditionalExpressionGrouping(
RegexToken openParenToken, RegexToken questionToken, RegexToken innerOpenParenToken)
{
// Reproduce very specific errors the .net regex parser looks for. Technically,
// Reproduce very specific errors the .NET regex parser looks for. Technically,
// we would error out in these cases no matter what. However, it means we can
// stringently enforce that our parser produces the same errors as the native one.
//
......@@ -1217,7 +1217,7 @@ private static RegexOptions OptionFromCode(VirtualChar ch)
private RegexBaseCharacterClassNode ParseCharacterClass()
{
// Note: ScanCharClass is one of the strangest function in the .net regex parser. Code
// Note: ScanCharClass is one of the strangest function in the .NET regex parser. Code
// for it is here:
// https://github.com/dotnet/corefx/blob/6ae0da1563e6e701bac61012c62ede8f8737f065/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs#L498
//
......@@ -1238,8 +1238,8 @@ private RegexBaseCharacterClassNode ParseCharacterClass()
// ignoring that character on the right side of a character range. So, if you had
// ```[#-\-b]```, then this *should* be treated as the character class containing
// the range of character from '#' to '-', unioned with the character 'b'. However,
// .net will interpret this as the character class containing the range of characters
// from '#' to 'b'. We follow .Net here to keep our errors in sync with them.
// .NET will interpret this as the character class containing the range of characters
// from '#' to 'b'. We follow .NET here to keep our errors in sync with them.
//
// See the comment about this in ParseRightSideOfCharacterClassRange
......@@ -1506,7 +1506,7 @@ private bool HasProblem(RegexNodeOrToken component)
private RegexExpressionNode ParseRightSideOfCharacterClassRange()
{
// Parsing the right hand side of a - is extremely strange (and most likely buggy) in
// the .net parser. Specifically, the .net parser will still consider itself on the
// the .NET parser. Specifically, the .NET parser will still consider itself on the
// right side no matter how many escaped dashes it sees. So, for example, the following
// is legal [a-\-] (even though \- is less than 'a'). Similarly, the following are
// *illegal* [b-\-a] and [b-\-\-a]. That's because the range that is checked is
......@@ -1601,7 +1601,7 @@ private RegexPrimaryExpressionNode ParseSingleCharacterClassComponent(bool isFir
ConsumeCurrentToken(allowTrivia: false));
}
// From the .net regex code:
// From the .NET regex code:
// This is code for Posix style properties - [:Ll:] or [:IsTibetan:].
// It currently doesn't do anything other than skip the whole thing!
if (!afterRangeMinus && _currentToken.Kind == RegexKind.OpenBracketToken && _lexer.IsAt(":"))
......@@ -1751,7 +1751,7 @@ private RegexEscapeNode ParsePossibleBackreferenceEscape(RegexToken backslashTok
RegexToken backslashToken, bool allowTriviaAfterEnd)
{
// Small deviation: Ecmascript allows references only to captures that precede
// this position (unlike .net which allows references in any direction). However,
// this position (unlike .NET which allows references in any direction). However,
// because we don't track position, we just consume the entire back-reference.
//
// This is addressable if we add position tracking when we locate all the captures.
......@@ -1849,7 +1849,7 @@ private RegexEscapeNode ParsePossibleKCaptureEscape(RegexToken backslashToken, b
if (capture.IsMissing || closeToken.IsMissing)
{
// Native parser falls back to normal escape scanning, if it doesn't see a capture,
// or close brace. For normal .net regexes, this will then fail later (as \k is not
// or close brace. For normal .NET regexes, this will then fail later (as \k is not
// a legal escape), but will succeed for ecmascript regexes.
_lexer.Position = afterBackslashPosition;
return ParseCharEscape(backslashToken, allowTriviaAfterEnd);
......@@ -1985,17 +1985,17 @@ private RegexControlEscapeNode ParseControlEscape(RegexToken backslashToken, boo
{
// From: https://github.com/dotnet/corefx/blob/80e220fc7009de0f0611ee6b52d4d5ffd25eb6c7/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs#L1450
// Note: Roslyn accepts a control escape that current .Net parser does not.
// Note: Roslyn accepts a control escape that current .NET parser does not.
// Specifically: \c[
//
// It is a bug that the .Net parser does not support this construct. The bug was
// It is a bug that the .NET parser does not support this construct. The bug was
// reported at: https://github.com/dotnet/corefx/issues/26501 and was fixed for
// CoreFx with https://github.com/dotnet/corefx/commit/80e220fc7009de0f0611ee6b52d4d5ffd25eb6c7
//
// Because it was a bug, we follow the correct behavior. That means we will not
// report a diagnostic for a Regex that someone might run on a previous version of
// .Net that ends up throwing at runtime. That's acceptable. Our goal is to match
// the latest .Net 'correct' behavior. Not intermediary points with bugs that have
// .NET that ends up throwing at runtime. That's acceptable. Our goal is to match
// the latest .NET 'correct' behavior. Not intermediary points with bugs that have
// since been fixed.
// \ca interpreted as \cA
......
......@@ -79,7 +79,7 @@ public static TBlockAnalysisData Run(ControlFlowGraph controlFlowGraph, DataFlow
var toVisit = new SortedSet<int>();
var firstBlock = blocks[firstBlockOrdinal];
analyzer.SetCurrentAnalysisData(firstBlock, initialAnalysisData);
analyzer.SetCurrentAnalysisData(firstBlock, initialAnalysisData, cancellationToken);
toVisit.Add(firstBlock.Ordinal);
var processedBlocks = PooledHashSet<BasicBlock>.GetInstance();
......@@ -122,7 +122,7 @@ public static TBlockAnalysisData Run(ControlFlowGraph controlFlowGraph, DataFlow
continue;
}
analyzer.SetCurrentAnalysisData(current, analyzer.GetEmptyAnalysisData());
analyzer.SetCurrentAnalysisData(current, analyzer.GetEmptyAnalysisData(), cancellationToken);
}
if (current.Ordinal < firstBlockOrdinal || current.Ordinal > lastBlockOrdinal)
......@@ -212,17 +212,21 @@ void FollowBranch(BasicBlock current, ControlFlowBranch branch, TBlockAnalysisDa
case ControlFlowBranchSemantics.None:
case ControlFlowBranchSemantics.ProgramTermination:
case ControlFlowBranchSemantics.StructuredExceptionHandling:
case ControlFlowBranchSemantics.Error:
Debug.Assert(branch.Destination == null);
return;
case ControlFlowBranchSemantics.Throw:
case ControlFlowBranchSemantics.Rethrow:
case ControlFlowBranchSemantics.Error:
Debug.Assert(branch.Destination == null);
StepThroughFinally(current.EnclosingRegion, destinationOrdinal: lastBlockOrdinal, ref currentAnalsisData);
return;
case ControlFlowBranchSemantics.Regular:
case ControlFlowBranchSemantics.Return:
Debug.Assert(branch.Destination != null);
if (StepThroughFinally(current.EnclosingRegion, branch.Destination, ref currentAnalsisData))
if (StepThroughFinally(current.EnclosingRegion, branch.Destination.Ordinal, ref currentAnalsisData))
{
var destination = branch.Destination;
var currentDestinationData = analyzer.GetCurrentAnalysisData(destination);
......@@ -234,7 +238,7 @@ void FollowBranch(BasicBlock current, ControlFlowBranch branch, TBlockAnalysisDa
if ((current.IsReachable || !destination.IsReachable) &&
(!analyzer.IsEqual(currentDestinationData, mergedAnalysisData) || !processedBlocks.Contains(destination)))
{
analyzer.SetCurrentAnalysisData(destination, mergedAnalysisData);
analyzer.SetCurrentAnalysisData(destination, mergedAnalysisData, cancellationToken);
toVisit.Add(branch.Destination.Ordinal);
}
}
......@@ -247,9 +251,8 @@ void FollowBranch(BasicBlock current, ControlFlowBranch branch, TBlockAnalysisDa
}
// Returns whether we should proceed to the destination after finallies were taken care of.
bool StepThroughFinally(ControlFlowRegion region, BasicBlock destination, ref TBlockAnalysisData currentAnalysisData)
bool StepThroughFinally(ControlFlowRegion region, int destinationOrdinal, ref TBlockAnalysisData currentAnalysisData)
{
int destinationOrdinal = destination.Ordinal;
while (!region.ContainsBlock(destinationOrdinal))
{
Debug.Assert(region.Kind != ControlFlowRegionKind.Root);
......
......@@ -24,7 +24,7 @@ internal abstract class DataFlowAnalyzer<TBlockAnalysisData> : IDisposable
/// <summary>
/// Updates the current analysis data for the given basic block.
/// </summary>
public abstract void SetCurrentAnalysisData(BasicBlock basicBlock, TBlockAnalysisData data);
public abstract void SetCurrentAnalysisData(BasicBlock basicBlock, TBlockAnalysisData data, CancellationToken cancellationToken);
/// <summary>
/// Analyze the given basic block and return the block analysis data at the end of the block for its successors.
......
......@@ -156,30 +156,24 @@ private sealed class FlowGraphAnalysisData : AnalysisData
public BasicBlockAnalysisData GetBlockAnalysisData(BasicBlock basicBlock)
=> _analysisDataByBasicBlockMap[basicBlock];
public BasicBlockAnalysisData GetOrCreateBlockAnalysisData(BasicBlock basicBlock)
public BasicBlockAnalysisData GetOrCreateBlockAnalysisData(BasicBlock basicBlock, CancellationToken cancellationToken)
{
if (_analysisDataByBasicBlockMap[basicBlock] == null)
{
_analysisDataByBasicBlockMap[basicBlock] = CreateBlockAnalysisData();
}
HandleCatchOrFilterOrFinallyInitialization(basicBlock);
HandleCatchOrFilterOrFinallyInitialization(basicBlock, cancellationToken);
return _analysisDataByBasicBlockMap[basicBlock];
}
private PooledHashSet<(ISymbol, IOperation)> GetOrCreateSymbolWritesInBlockRange(int firstBlockOrdinal, int lastBlockOrdinal)
private PooledHashSet<(ISymbol, IOperation)> GetOrCreateSymbolWritesInBlockRange(int firstBlockOrdinal, int lastBlockOrdinal, CancellationToken cancellationToken)
{
if (!_symbolWritesInsideBlockRangeMap.TryGetValue((firstBlockOrdinal, lastBlockOrdinal), out var writesInBlockRange))
{
// Compute all descendant operations in basic block range.
var operations = PooledHashSet<IOperation>.GetInstance();
for (int i = firstBlockOrdinal; i <= lastBlockOrdinal; i++)
{
foreach (var operation in ControlFlowGraph.Blocks[i].DescendantOperations())
{
operations.Add(operation);
}
}
AddDescendantOperationsInRange(ControlFlowGraph, firstBlockOrdinal, lastBlockOrdinal, operations, cancellationToken);
// Filter down the operations to writes within this block range.
writesInBlockRange = PooledHashSet<(ISymbol, IOperation)>.GetInstance();
......@@ -195,13 +189,110 @@ private PooledHashSet<(ISymbol, IOperation)> GetOrCreateSymbolWritesInBlockRange
return writesInBlockRange;
}
private void AddDescendantOperationsInRange(
ControlFlowGraph cfg,
int firstBlockOrdinal,
int lastBlockOrdinal,
PooledHashSet<IOperation> operationsBuilder,
CancellationToken cancellationToken)
{
// Compute all descendant operations in basic block range.
for (int i = firstBlockOrdinal; i <= lastBlockOrdinal; i++)
{
cancellationToken.ThrowIfCancellationRequested();
foreach (var operation in cfg.Blocks[i].DescendantOperations())
{
var added = operationsBuilder.Add(operation);
if (added && operation is IInvocationOperation invocation)
{
if (invocation.Instance != null &&
_reachingDelegateCreationTargets.TryGetValue(invocation.Instance, out var targets))
{
AddDescendantOperationsFromDelegateCreationTargets(targets);
}
else if (invocation.TargetMethod.IsLocalFunction())
{
var localFunctionGraph = cfg.GetLocalFunctionControlFlowGraphInScope(invocation.TargetMethod);
if (localFunctionGraph != null)
{
AddDescendantOperationsInLambdaOrLocalFunctionGraph(localFunctionGraph);
}
}
}
}
}
return;
// Local functions.
void AddDescendantOperationsFromDelegateCreationTargets(PooledHashSet<IOperation> targets)
{
foreach (var target in targets)
{
ControlFlowGraph lambdaOrLocalFunctionCfgOpt = null;
switch (target)
{
case IFlowAnonymousFunctionOperation flowAnonymousFunctionOperation:
lambdaOrLocalFunctionCfgOpt = TryGetAnonymousFunctionControlFlowGraphInScope(flowAnonymousFunctionOperation);
break;
case ILocalFunctionOperation localFunctionOperation:
lambdaOrLocalFunctionCfgOpt = TryGetLocalFunctionControlFlowGraphInScope(localFunctionOperation.Symbol);
break;
case IMethodReferenceOperation methodReferenceOperation when (methodReferenceOperation.Method.IsLocalFunction()):
lambdaOrLocalFunctionCfgOpt = TryGetLocalFunctionControlFlowGraphInScope(methodReferenceOperation.Method);
break;
}
if (lambdaOrLocalFunctionCfgOpt != null &&
operationsBuilder.Add(target))
{
AddDescendantOperationsInLambdaOrLocalFunctionGraph(lambdaOrLocalFunctionCfgOpt);
}
}
}
void AddDescendantOperationsInLambdaOrLocalFunctionGraph(ControlFlowGraph lambdaOrLocalFunctionCfg)
{
Debug.Assert(lambdaOrLocalFunctionCfg != null);
AddDescendantOperationsInRange(lambdaOrLocalFunctionCfg, firstBlockOrdinal: 0,
lastBlockOrdinal: lambdaOrLocalFunctionCfg.Blocks.Length - 1, operationsBuilder, cancellationToken);
}
ControlFlowGraph TryGetAnonymousFunctionControlFlowGraphInScope(IFlowAnonymousFunctionOperation flowAnonymousFunctionOperation)
{
if (_lambdaTargetsToAccessingCfgMap.TryGetValue(flowAnonymousFunctionOperation, out var lambdaAccessingCfg))
{
var anonymousFunctionCfg = lambdaAccessingCfg.GetAnonymousFunctionControlFlowGraphInScope(flowAnonymousFunctionOperation);
Debug.Assert(anonymousFunctionCfg != null);
return anonymousFunctionCfg;
}
return null;
}
ControlFlowGraph TryGetLocalFunctionControlFlowGraphInScope(IMethodSymbol localFunction)
{
Debug.Assert(localFunction.IsLocalFunction());
if (_localFunctionTargetsToAccessingCfgMap.TryGetValue(localFunction, out var localFunctionAccessingCfg))
{
var localFunctionCfg = localFunctionAccessingCfg.GetLocalFunctionControlFlowGraphInScope(localFunction);
Debug.Assert(localFunctionCfg != null);
return localFunctionCfg;
}
return null;
}
}
/// <summary>
/// Special handling to ensure that at start of catch/filter/finally region analysis,
/// we mark all symbol writes from the corresponding try region as reachable in the
/// catch/filter/finally region.
/// </summary>
/// <param name="basicBlock"></param>
private void HandleCatchOrFilterOrFinallyInitialization(BasicBlock basicBlock)
private void HandleCatchOrFilterOrFinallyInitialization(BasicBlock basicBlock, CancellationToken cancellationToken)
{
Debug.Assert(_analysisDataByBasicBlockMap[basicBlock] != null);
......@@ -259,7 +350,7 @@ private void HandleCatchOrFilterOrFinallyInitialization(BasicBlock basicBlock)
mergedAnalysisData.SetAnalysisDataFrom(GetBlockAnalysisData(firstBasicBlockInOutermostRegion));
// All symbol writes within the try region are considered reachable at start of catch/finally region.
foreach (var (symbol, write) in GetOrCreateSymbolWritesInBlockRange(containingTryCatchFinallyRegion.FirstBlockOrdinal, basicBlock.Ordinal - 1))
foreach (var (symbol, write) in GetOrCreateSymbolWritesInBlockRange(containingTryCatchFinallyRegion.FirstBlockOrdinal, basicBlock.Ordinal - 1, cancellationToken))
{
mergedAnalysisData.OnWriteReferenceFound(symbol, write, maybeWritten: true);
SymbolsWriteBuilder[(symbol, write)] = true;
......@@ -269,8 +360,8 @@ private void HandleCatchOrFilterOrFinallyInitialization(BasicBlock basicBlock)
SetBlockAnalysisData(basicBlock, mergedAnalysisData);
}
public void SetCurrentBlockAnalysisDataFrom(BasicBlock basicBlock)
=> SetCurrentBlockAnalysisDataFrom(GetOrCreateBlockAnalysisData(basicBlock));
public void SetCurrentBlockAnalysisDataFrom(BasicBlock basicBlock, CancellationToken cancellationToken)
=> SetCurrentBlockAnalysisDataFrom(GetOrCreateBlockAnalysisData(basicBlock, cancellationToken));
public void SetAnalysisDataOnEntryBlockStart()
{
......@@ -284,8 +375,8 @@ public void SetAnalysisDataOnEntryBlockStart()
public void SetBlockAnalysisData(BasicBlock basicBlock, BasicBlockAnalysisData data)
=> _analysisDataByBasicBlockMap[basicBlock] = data;
public void SetBlockAnalysisDataFrom(BasicBlock basicBlock, BasicBlockAnalysisData data)
=> GetOrCreateBlockAnalysisData(basicBlock).SetAnalysisDataFrom(data);
public void SetBlockAnalysisDataFrom(BasicBlock basicBlock, BasicBlockAnalysisData data, CancellationToken cancellationToken)
=> GetOrCreateBlockAnalysisData(basicBlock, cancellationToken).SetAnalysisDataFrom(data);
public void SetAnalysisDataOnExitBlockEnd()
{
......
......@@ -17,22 +17,18 @@ internal static partial class SymbolUsageAnalysis
private sealed partial class DataFlowAnalyzer : DataFlowAnalyzer<BasicBlockAnalysisData>
{
private readonly FlowGraphAnalysisData _analysisData;
private readonly CancellationToken _cancellationToken;
private DataFlowAnalyzer(ControlFlowGraph cfg, ISymbol owningSymbol, CancellationToken cancellationToken)
private DataFlowAnalyzer(ControlFlowGraph cfg, ISymbol owningSymbol)
{
_analysisData = FlowGraphAnalysisData.Create(cfg, owningSymbol, AnalyzeLocalFunctionOrLambdaInvocation);
_cancellationToken = cancellationToken;
}
private DataFlowAnalyzer(
ControlFlowGraph cfg,
IMethodSymbol lambdaOrLocalFunction,
FlowGraphAnalysisData parentAnalysisData,
CancellationToken cancellationToken)
FlowGraphAnalysisData parentAnalysisData)
{
_analysisData = FlowGraphAnalysisData.Create(cfg, lambdaOrLocalFunction, parentAnalysisData);
_cancellationToken = cancellationToken;
var entryBlockAnalysisData = GetEmptyAnalysisData();
entryBlockAnalysisData.SetAnalysisDataFrom(parentAnalysisData.CurrentBlockAnalysisData);
......@@ -42,7 +38,7 @@ private DataFlowAnalyzer(ControlFlowGraph cfg, ISymbol owningSymbol, Cancellatio
public static SymbolUsageResult RunAnalysis(ControlFlowGraph cfg, ISymbol owningSymbol, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
using (var analyzer = new DataFlowAnalyzer(cfg, owningSymbol, cancellationToken))
using (var analyzer = new DataFlowAnalyzer(cfg, owningSymbol))
{
_ = CustomDataFlowAnalysis<BasicBlockAnalysisData>.Run(cfg, analyzer, cancellationToken);
return analyzer._analysisData.ToResult();
......@@ -61,7 +57,7 @@ public override void Dispose()
Debug.Assert(localFunctionOrLambda.IsLocalFunction() || localFunctionOrLambda.IsAnonymousFunction());
cancellationToken.ThrowIfCancellationRequested();
using (var analyzer = new DataFlowAnalyzer(cfg, localFunctionOrLambda, (FlowGraphAnalysisData)parentAnalysisData, cancellationToken))
using (var analyzer = new DataFlowAnalyzer(cfg, localFunctionOrLambda, (FlowGraphAnalysisData)parentAnalysisData))
{
var resultBlockAnalysisData = CustomDataFlowAnalysis<BasicBlockAnalysisData>.Run(cfg, analyzer, cancellationToken);
if (resultBlockAnalysisData == null)
......@@ -101,7 +97,7 @@ public override BasicBlockAnalysisData AnalyzeBlock(BasicBlock basicBlock, Cance
void BeforeBlockAnalysis()
{
// Initialize current block analysis data.
_analysisData.SetCurrentBlockAnalysisDataFrom(basicBlock);
_analysisData.SetCurrentBlockAnalysisDataFrom(basicBlock, cancellationToken);
// At start of entry block, handle parameter definitions from method declaration.
if (basicBlock.Kind == BasicBlockKind.Entry)
......@@ -155,8 +151,8 @@ public override BasicBlockAnalysisData GetCurrentAnalysisData(BasicBlock basicBl
public override BasicBlockAnalysisData GetEmptyAnalysisData()
=> _analysisData.CreateBlockAnalysisData();
public override void SetCurrentAnalysisData(BasicBlock basicBlock, BasicBlockAnalysisData data)
=> _analysisData.SetBlockAnalysisDataFrom(basicBlock, data);
public override void SetCurrentAnalysisData(BasicBlock basicBlock, BasicBlockAnalysisData data, CancellationToken cancellationToken)
=> _analysisData.SetBlockAnalysisDataFrom(basicBlock, data, cancellationToken);
public override bool IsEqual(BasicBlockAnalysisData analysisData1, BasicBlockAnalysisData analysisData2)
=> analysisData1 == null ? analysisData2 == null : analysisData1.Equals(analysisData2);
......
......@@ -102,7 +102,7 @@ private void OnReferenceFound(ISymbol symbol, IOperation operation)
var isReadFrom = valueUsageInfo.IsReadFrom();
var isWrittenTo = valueUsageInfo.IsWrittenTo();
if (isWrittenTo && MakePendingWrite())
if (isWrittenTo && MakePendingWrite(operation, symbolOpt: symbol))
{
// Certain writes are processed at a later visit
// and are marked as a pending write for post processing.
......@@ -145,50 +145,62 @@ private void OnReferenceFound(ISymbol symbol, IOperation operation)
{
OnReadReferenceFound(symbol);
}
}
return;
private bool MakePendingWrite(IOperation operation, ISymbol symbolOpt)
{
Debug.Assert(symbolOpt != null || operation.Kind == OperationKind.FlowCaptureReference);
// Local functions
bool MakePendingWrite()
if (operation.Parent is IAssignmentOperation assignmentOperation &&
assignmentOperation.Target == operation)
{
Debug.Assert(isWrittenTo);
if (operation.Parent is IAssignmentOperation assignmentOperation &&
assignmentOperation.Target == operation)
{
var set = PooledHashSet<(ISymbol, IOperation)>.GetInstance();
set.Add((symbol, operation));
_pendingWritesMap.Add(assignmentOperation, set);
return true;
}
else if (operation.IsInLeftOfDeconstructionAssignment(out var deconstructionAssignment))
var set = PooledHashSet<(ISymbol, IOperation)>.GetInstance();
set.Add((symbolOpt, operation));
_pendingWritesMap.Add(assignmentOperation, set);
return true;
}
else if (operation.IsInLeftOfDeconstructionAssignment(out var deconstructionAssignment))
{
if (!_pendingWritesMap.TryGetValue(deconstructionAssignment, out var set))
{
if (!_pendingWritesMap.TryGetValue(deconstructionAssignment, out var set))
{
set = PooledHashSet<(ISymbol, IOperation)>.GetInstance();
_pendingWritesMap.Add(deconstructionAssignment, set);
}
set.Add((symbol, operation));
return true;
set = PooledHashSet<(ISymbol, IOperation)>.GetInstance();
_pendingWritesMap.Add(deconstructionAssignment, set);
}
return false;
set.Add((symbolOpt, operation));
return true;
}
return false;
}
private void ProcessPendingWritesForAssignmentTarget(IAssignmentOperation operation)
{
if (_pendingWritesMap.TryGetValue(operation, out var pendingWrites))
{
foreach (var (symbol, write) in pendingWrites)
var isUsedCompountAssignment = operation.IsAnyCompoundAssignment() &&
operation.Parent?.Kind != OperationKind.ExpressionStatement;
foreach (var (symbolOpt, write) in pendingWrites)
{
OnWriteReferenceFound(symbol, write, maybeWritten: false);
if (write.Kind != OperationKind.FlowCaptureReference)
{
Debug.Assert(symbolOpt != null);
OnWriteReferenceFound(symbolOpt, write, maybeWritten: false);
if (operation.IsAnyCompoundAssignment() &&
operation.Parent?.Kind != OperationKind.ExpressionStatement)
if (isUsedCompountAssignment)
{
OnReadReferenceFound(symbolOpt);
}
}
else
{
OnReadReferenceFound(symbol);
Debug.Assert(symbolOpt == null);
var captureReference = (IFlowCaptureReferenceOperation)write;
Debug.Assert(_currentAnalysisData.IsLValueFlowCapture(captureReference.Id));
OnLValueDereferenceFound(captureReference.Id);
}
}
......@@ -254,7 +266,8 @@ public override void VisitFlowCaptureReference(IFlowCaptureReferenceOperation op
{
base.VisitFlowCaptureReference(operation);
if (_currentAnalysisData.IsLValueFlowCapture(operation.Id))
if (_currentAnalysisData.IsLValueFlowCapture(operation.Id) &&
!MakePendingWrite(operation, symbolOpt: null))
{
OnLValueDereferenceFound(operation.Id);
}
......
......@@ -73,7 +73,7 @@ private static Option<T> CreateOption<T>(OptionGroup group, string name, T defau
/// Default value of 120 was picked based on the amount of code in a github.com diff at 1080p.
/// That resolution is the most common value as per the last DevDiv survey as well as the latest
/// Steam hardware survey. This also seems to a reasonable length default in that shorter
/// lengths can often feel too cramped for .Net languages, which are often starting with a
/// lengths can often feel too cramped for .NET languages, which are often starting with a
/// default indentation of at least 16 (for namespace, class, member, plus the final construct
/// indentation).
/// </summary>
......
......@@ -18,7 +18,7 @@ public static bool OverlapsHiddenPosition(this SyntaxTree tree, TextSpan span, C
return text.OverlapsHiddenPosition(span, (position, cancellationToken2) =>
{
// implements the ASP.Net IsHidden rule
// implements the ASP.NET IsHidden rule
var lineVisibility = tree.GetLineVisibility(position, cancellationToken2);
return lineVisibility == LineVisibility.Hidden || lineVisibility == LineVisibility.BeforeFirstLineDirective;
},
......
......@@ -99,7 +99,7 @@ private static int ComputeK(int expectedCount, double falsePositiveProbability)
/// This is needed over the normal 'string.GetHashCode()' because we need to be able to generate
/// 'k' different well distributed hashes for any given string s. Also, we want to be able to
/// generate these hashes without allocating any memory. My ideal solution would be to use an
/// MD5 hash. However, there appears to be no way to do MD5 in .Net where you can:
/// MD5 hash. However, there appears to be no way to do MD5 in .NET where you can:
///
/// a) feed it individual values instead of a byte[]
///
......
......@@ -89,7 +89,7 @@ public static T WaitAndGetResult_CanCallOnBackground<T>(this Task<T> task, Cance
return task.Result;
}
// NOTE(cyrusn): Once we switch over to .Net 4.5 we can make our SafeContinueWith overloads
// NOTE(cyrusn): Once we switch over to .NET Framework 4.5 we can make our SafeContinueWith overloads
// simply call into task.ContinueWith(..., TaskContinuationOptions.LazyCancellation, ...) as
// that will have the semantics that we want. From the TPL guys:
//
......
......@@ -3,10 +3,10 @@
namespace Microsoft.CodeAnalysis.Host
{
/// <summary>
/// Provides a way to map from an assembly name to the actual path of the .Net framework
/// Provides a way to map from an assembly name to the actual path of the .NET Framework
/// assemby with that name in the context of a specified project. For example, if the
/// assembly name is "System.Data" then a project targetting .Net 2.0 would resolve this
/// to a different path than a project targetting .Net 4.5.
/// assembly name is "System.Data" then a project targetting .NET 2.0 would resolve this
/// to a different path than a project targetting .NET 4.5.
/// </summary>
internal interface IFrameworkAssemblyPathResolver : IWorkspaceService
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册