diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 8df80fc769933..87b8ad3debccc 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -2,9 +2,9 @@
-
+
https://github.com/dotnet/arcade
- a0d951e12a53401c3da812b581e39feb4a5bb4ab
+ 2ca74c76adc84f0459b4a0352034db463d0b910f
diff --git a/eng/build.ps1 b/eng/build.ps1
index 4b0d37e584eec..26305fbc93408 100644
--- a/eng/build.ps1
+++ b/eng/build.ps1
@@ -208,7 +208,11 @@ function BuildSolution() {
$projects = Join-Path $RepoRoot $solution
$enableAnalyzers = !$skipAnalyzers
$toolsetBuildProj = InitializeToolset
- $quietRestore = !$ci
+
+ # Have to disable quiet restore during bootstrap builds to work around
+ # an arcade bug
+ # https://github.com/dotnet/arcade/issues/2220
+ $quietRestore = !($ci -or ($bootstrapDir -ne ""))
$testTargetFrameworks = if ($testCoreClr) { "netcoreapp2.1" } else { "" }
$ibcSourceBranchName = GetIbcSourceBranchName
$ibcDropId = if ($officialIbcDropId -ne "default") { $officialIbcDropId } else { "" }
diff --git a/eng/common/PublishToPackageFeed.proj b/eng/common/PublishToPackageFeed.proj
index 8149e3fb6a134..b26d28a90b81f 100644
--- a/eng/common/PublishToPackageFeed.proj
+++ b/eng/common/PublishToPackageFeed.proj
@@ -11,7 +11,6 @@
-
diff --git a/eng/common/generate-graph-files.ps1 b/eng/common/generate-graph-files.ps1
index c04c80e4f61da..e09c64e9f6f47 100644
--- a/eng/common/generate-graph-files.ps1
+++ b/eng/common/generate-graph-files.ps1
@@ -42,7 +42,7 @@ try {
}
Write-Host "Generating dependency graph..."
- $darc = Invoke-Expression "& `"$darcExe`" $options"
+ Invoke-Expression "& `"$darcExe`" $options"
CheckExitCode "Generating dependency graph"
$graph = Get-Content $graphVizFilePath
diff --git a/eng/common/templates/job/generate-graph-files.yml b/eng/common/templates/job/generate-graph-files.yml
new file mode 100644
index 0000000000000..e54ce956f9088
--- /dev/null
+++ b/eng/common/templates/job/generate-graph-files.yml
@@ -0,0 +1,48 @@
+parameters:
+ # Optional: dependencies of the job
+ dependsOn: ''
+
+ # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool
+ pool: {}
+
+ # Optional: Include toolset dependencies in the generated graph files
+ includeToolset: false
+
+jobs:
+- job: Generate_Graph_Files
+
+ dependsOn: ${{ parameters.dependsOn }}
+
+ displayName: Generate Graph Files
+
+ pool: ${{ parameters.pool }}
+
+ variables:
+ # Publish-Build-Assets provides: MaestroAccessToken, BotAccount-dotnet-maestro-bot-PAT
+ # DotNet-AllOrgs-Darc-Pats provides: dn-bot-devdiv-dnceng-rw-code-pat
+ - group: Publish-Build-Assets
+ - group: DotNet-AllOrgs-Darc-Pats
+ - name: _GraphArguments
+ value: -gitHubPat $(BotAccount-dotnet-maestro-bot-PAT)
+ -azdoPat $(dn-bot-devdiv-dnceng-rw-code-pat)
+ -barToken $(MaestroAccessToken)
+ -outputFolder '$(Build.StagingDirectory)/GraphFiles/'
+ - ${{ if ne(parameters.includeToolset, 'false') }}:
+ - name: _GraphArguments
+ value: ${{ variables._GraphArguments }} -includeToolset
+
+ steps:
+ - task: PowerShell@2
+ displayName: Generate Graph Files
+ inputs:
+ filePath: eng\common\generate-graph-files.ps1
+ arguments: $(_GraphArguments)
+ continueOnError: true
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Graph to Artifacts
+ inputs:
+ PathtoPublish: '$(Build.StagingDirectory)/GraphFiles'
+ PublishLocation: Container
+ ArtifactName: GraphFiles
+ continueOnError: true
+ condition: always()
diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml
index c1a5b4849acea..06ed58de41f38 100644
--- a/eng/common/templates/jobs/jobs.yml
+++ b/eng/common/templates/jobs/jobs.yml
@@ -13,7 +13,13 @@ parameters:
# Optional: Enable publishing to the build asset registry
enablePublishBuildAssets: false
-
+
+ graphFileGeneration:
+ # Optional: Enable generating the graph files at the end of the build
+ enabled: false
+ # Optional: Include toolset dependencies in the generated graph files
+ includeToolset: false
+
# Optional: Include PublishTestResults task
enablePublishTestResults: false
@@ -68,4 +74,13 @@ jobs:
vmImage: vs2017-win2016
runAsPublic: ${{ parameters.runAsPublic }}
enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }}
-
+
+- ${{ if and(eq(parameters.graphFileGeneration.enabled, true), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - template: ../job/generate-graph-files.yml
+ parameters:
+ continueOnError: ${{ parameters.continueOnError }}
+ includeToolset: ${{ parameters.graphFileGeneration.includeToolset }}
+ dependsOn:
+ - Asset_Registry_Publish
+ pool:
+ vmImage: vs2017-win2016
diff --git a/global.json b/global.json
index ba36c3954819f..11ca7fe248580 100644
--- a/global.json
+++ b/global.json
@@ -7,6 +7,6 @@
"xcopy-msbuild": "15.9.0-alpha"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19157.23"
+ "Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19161.14"
}
}
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs
index 0bae27436c72d..6cef15b885418 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass_Switch.cs
@@ -30,7 +30,8 @@ private void VisitSwitchBlock(BoundSwitchStatement node)
{
foreach (var label in section.SwitchLabels)
{
- if (reachableLabels.Contains(label.Label) || label.HasErrors)
+ if (reachableLabels.Contains(label.Label) || label.HasErrors ||
+ label == node.DefaultLabel && node.Expression.ConstantValue == null && IsTraditionalSwitch(node))
{
SetState(initialState.Clone());
}
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
index 8655f054f9185..062b0ca75ed13 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
@@ -53,16 +53,20 @@ internal sealed class VariableState
/// Contains a result type which tells us whether the expression may be null,
/// and an l-value type which tells us whether we can assign null to the expression.
///
+ [DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
private readonly struct VisitResult
{
public readonly TypeWithState RValueType;
public readonly TypeSymbolWithAnnotations LValueType;
- public VisitResult(TypeWithState resultType, TypeSymbolWithAnnotations lValueType)
+ public VisitResult(TypeWithState rValueType, TypeSymbolWithAnnotations lValueType)
{
- RValueType = resultType;
+ RValueType = rValueType;
LValueType = lValueType;
}
+
+ private string GetDebuggerDisplay() =>
+ $"RValueType={RValueType.GetDebuggerDisplay()}, LValueType={LValueType.GetDebuggerDisplay()}";
}
///
@@ -135,7 +139,7 @@ private TypeWithState ResultType
get => _visitResult.RValueType;
set
{
- SetResult(resultType: value, lvalueType: value.ToTypeSymbolWithAnnotations());
+ SetResult(rvalueType: value, lvalueType: value.ToTypeSymbolWithAnnotations());
}
}
@@ -152,7 +156,7 @@ private TypeSymbolWithAnnotations LvalueResultType
get => _visitResult.LValueType;
set
{
- SetResult(resultType: value.ToTypeWithState(), lvalueType: value);
+ SetResult(rvalueType: value.ToTypeWithState(), lvalueType: value);
}
}
@@ -164,9 +168,9 @@ private void UseLvalueOnly()
LvalueResultType = LvalueResultType;
}
- private void SetResult(TypeWithState resultType, TypeSymbolWithAnnotations lvalueType)
+ private void SetResult(TypeWithState rvalueType, TypeSymbolWithAnnotations lvalueType)
{
- _visitResult = new VisitResult(resultType, lvalueType);
+ _visitResult = new VisitResult(rvalueType, lvalueType);
}
///
@@ -534,8 +538,12 @@ protected override int MakeSlot(BoundExpression node)
}
break;
case ConversionKind.Identity:
+ case ConversionKind.ImplicitReference:
+ case ConversionKind.ExplicitReference:
case ConversionKind.ImplicitTupleLiteral:
+ case ConversionKind.ExplicitTupleLiteral:
case ConversionKind.ImplicitTuple:
+ case ConversionKind.ExplicitTuple:
if (isSupportedConversion(conv.Conversion, conv.Operand))
{
return MakeSlot(conv.Operand);
@@ -548,6 +556,7 @@ protected override int MakeSlot(BoundExpression node)
case BoundKind.ObjectCreationExpression:
case BoundKind.DynamicObjectCreationExpression:
case BoundKind.AnonymousObjectCreationExpression:
+ case BoundKind.NewT:
case BoundKind.TupleLiteral:
case BoundKind.ConvertedTupleLiteral:
return getPlaceholderSlot(node);
@@ -573,7 +582,7 @@ int getPlaceholderSlot(BoundExpression expr)
return -1;
}
- MethodSymbol getTopLevelMethod(MethodSymbol method)
+ static MethodSymbol getTopLevelMethod(MethodSymbol method)
{
while ((object)method != null)
{
@@ -589,7 +598,7 @@ MethodSymbol getTopLevelMethod(MethodSymbol method)
// Returns true if the nullable state from the operand of the conversion
// can be used as is, and we can create a slot from the conversion.
- bool isSupportedConversion(Conversion conversion, BoundExpression operandOpt)
+ static bool isSupportedConversion(Conversion conversion, BoundExpression operandOpt)
{
// https://github.com/dotnet/roslyn/issues/32599: Allow implicit and explicit
// conversions where the nullable state of the operand remains valid.
@@ -598,23 +607,37 @@ bool isSupportedConversion(Conversion conversion, BoundExpression operandOpt)
case ConversionKind.Identity:
case ConversionKind.DefaultOrNullLiteral:
case ConversionKind.ImplicitReference:
+ case ConversionKind.ExplicitReference:
return true;
case ConversionKind.ImplicitTupleLiteral:
+ case ConversionKind.ExplicitTupleLiteral:
+ switch (operandOpt?.Kind)
{
- var arguments = ((BoundConvertedTupleLiteral)operandOpt).Arguments;
- var conversions = conversion.UnderlyingConversions;
- for (int i = 0; i < arguments.Length; i++)
- {
- // https://github.com/dotnet/roslyn/issues/32600: Copy nullable
- // state of tuple elements independently.
- if (!isSupportedConversion(conversions[i], (arguments[i] as BoundConversion)?.Operand))
+ case BoundKind.Conversion:
{
- return false;
+ var operandConversion = (BoundConversion)operandOpt;
+ return isSupportedConversion(operandConversion.Conversion, operandConversion.Operand);
}
- }
- return true;
+ case BoundKind.ConvertedTupleLiteral:
+ {
+ var arguments = ((BoundConvertedTupleLiteral)operandOpt).Arguments;
+ var conversions = conversion.UnderlyingConversions;
+ for (int i = 0; i < arguments.Length; i++)
+ {
+ // https://github.com/dotnet/roslyn/issues/32600: Copy nullable
+ // state of tuple elements independently.
+ if (!isSupportedConversion(conversions[i], (arguments[i] as BoundConversion)?.Operand))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ default:
+ return false;
}
case ConversionKind.ImplicitTuple:
+ case ConversionKind.ExplicitTuple:
// https://github.com/dotnet/roslyn/issues/32600: Copy nullable
// state of tuple elements independently.
return conversion.UnderlyingConversions.All(c => isSupportedConversion(c, null));
@@ -852,12 +875,12 @@ private void ReportNullabilityMismatchInAssignment(SyntaxNode syntaxNode, object
// https://github.com/dotnet/roslyn/issues/33428: Can the areEquivalentTypes check be removed
// if InheritNullableStateOfMember asserts the member is valid for target and value?
- if (areEquivalentTypes(targetType, valueType)) // https://github.com/dotnet/roslyn/issues/29968 Allow assignment to base type.
+ if (areEquivalentTypes(targetType, valueType))
{
// https://github.com/dotnet/roslyn/issues/31395: We should copy all tracked state from `value` regardless of
// BoundNode type but we'll need to handle cycles (see NullableReferenceTypesTests.Members_FieldCycle_07).
// For now, we copy a limited set of BoundNode types that shouldn't contain cycles.
- if ((targetType.IsReferenceType && (value.Kind == BoundKind.ObjectCreationExpression || value.Kind == BoundKind.AnonymousObjectCreationExpression || value.Kind == BoundKind.DynamicObjectCreationExpression || targetType.TypeSymbol.IsAnonymousType)) ||
+ if ((targetType.IsReferenceType && (isSupportedReferenceTypeValue(value) || targetType.TypeSymbol.IsAnonymousType)) ||
targetType.IsNullableType())
{
// Nullable is handled here rather than in InheritNullableStateOfTrackableStruct since that
@@ -875,8 +898,24 @@ private void ReportNullabilityMismatchInAssignment(SyntaxNode syntaxNode, object
}
}
- bool areEquivalentTypes(TypeSymbolWithAnnotations target, TypeWithState assignedValue) =>
+ static bool areEquivalentTypes(TypeSymbolWithAnnotations target, TypeWithState assignedValue) =>
target.TypeSymbol.Equals(assignedValue.Type, TypeCompareKind.AllIgnoreOptions);
+
+ // https://github.com/dotnet/roslyn/issues/31395: See comment above.
+ static bool isSupportedReferenceTypeValue(BoundExpression value)
+ {
+ switch (value.Kind)
+ {
+ case BoundKind.Conversion:
+ return isSupportedReferenceTypeValue(((BoundConversion)value).Operand);
+ case BoundKind.ObjectCreationExpression:
+ case BoundKind.AnonymousObjectCreationExpression:
+ case BoundKind.DynamicObjectCreationExpression:
+ return true;
+ default:
+ return false;
+ }
+ }
}
private void ReportNonSafetyDiagnostic(SyntaxNode syntax)
@@ -1291,7 +1330,6 @@ public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node)
return null;
}
- bool inferredType = node.DeclaredType.InferredType;
TypeSymbolWithAnnotations type = local.Type;
TypeWithState valueType;
if (local.IsRef)
@@ -1300,8 +1338,8 @@ public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node)
}
else
{
+ bool inferredType = node.DeclaredType.InferredType;
valueType = VisitOptionalImplicitConversion(initializer, targetTypeOpt: inferredType ? default : type, useLegacyWarnings: true, AssignmentKind.Assignment);
-
if (inferredType)
{
if (valueType.HasNullType)
@@ -1395,7 +1433,9 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre
ImmutableArray argumentResults,
BoundExpression initializerOpt)
{
- Debug.Assert(node.Kind == BoundKind.ObjectCreationExpression || node.Kind == BoundKind.DynamicObjectCreationExpression);
+ Debug.Assert(node.Kind == BoundKind.ObjectCreationExpression ||
+ node.Kind == BoundKind.DynamicObjectCreationExpression ||
+ node.Kind == BoundKind.NewT);
var argumentTypes = argumentResults.SelectAsArray(ar => ar.RValueType);
int slot = -1;
@@ -1403,14 +1443,13 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre
NullableFlowState resultState = NullableFlowState.NotNull;
if ((object)type != null)
{
- bool isTrackableStructType = EmptyStructTypeCache.IsTrackableStructType(type);
- var constructor = (node as BoundObjectCreationExpression)?.Constructor;
- bool isDefaultValueTypeConstructor = constructor?.IsDefaultValueTypeConstructor() == true;
-
- if (!type.IsValueType || isTrackableStructType)
+ slot = GetOrCreateObjectCreationPlaceholderSlot(node);
+ if (slot > 0)
{
- slot = GetOrCreateObjectCreationPlaceholderSlot(node);
- if (slot > 0 && isTrackableStructType)
+ var constructor = (node as BoundObjectCreationExpression)?.Constructor;
+ bool isDefaultValueTypeConstructor = constructor?.IsDefaultValueTypeConstructor() == true;
+
+ if (EmptyStructTypeCache.IsTrackableStructType(type))
{
this.State[slot] = NullableFlowState.NotNull;
var tupleType = constructor?.ContainingType as TupleTypeSymbol;
@@ -1428,21 +1467,21 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre
isDefaultValue: isDefaultValueTypeConstructor);
}
}
- }
- else if (type.IsNullableType())
- {
- if (isDefaultValueTypeConstructor)
- {
- // a nullable value type created with its default constructor is by definition null
- resultState = NullableFlowState.MaybeNull;
- }
- else if (constructor.ParameterCount == 1)
+ else if (type.IsNullableType())
{
- // if we deal with one-parameter ctor that takes underlying, then Value state is inferred from the argument.
- var parameterType = constructor.ParameterTypes[0];
- if (AreNullableAndUnderlyingTypes(type, parameterType.TypeSymbol, out TypeSymbolWithAnnotations underlyingType))
+ if (isDefaultValueTypeConstructor)
{
- TrackNullableStateOfNullableValue(node, arguments[0], type, underlyingType);
+ // a nullable value type created with its default constructor is by definition null
+ resultState = NullableFlowState.MaybeNull;
+ }
+ else if (constructor.ParameterCount == 1)
+ {
+ // if we deal with one-parameter ctor that takes underlying, then Value state is inferred from the argument.
+ var parameterType = constructor.ParameterTypes[0];
+ if (AreNullableAndUnderlyingTypes(type, parameterType.TypeSymbol, out TypeSymbolWithAnnotations underlyingType))
+ {
+ TrackNullableStateOfNullableValue(node, arguments[0], type, underlyingType);
+ }
}
}
}
@@ -1706,13 +1745,11 @@ private ArrayTypeSymbol VisitArrayInitializer(BoundArrayCreation node)
node, returnTypesOpt: null, initialState: null, callbackOpt: null);
int n = returns.Count;
- var expressions = ArrayBuilder.GetInstance();
var resultTypes = ArrayBuilder.GetInstance(n);
var placeholdersBuilder = ArrayBuilder.GetInstance(n);
for (int i = 0; i < n; i++)
{
var (returnExpr, resultType) = returns[i];
- expressions.Add(returnExpr);
resultTypes.Add(resultType);
placeholdersBuilder.Add(CreatePlaceholderIfNecessary(returnExpr, resultType));
}
@@ -1745,7 +1782,6 @@ private ArrayTypeSymbol VisitArrayInitializer(BoundArrayCreation node)
}
resultTypes.Free();
- expressions.Free();
walker.Free();
return inferredType;
@@ -2325,6 +2361,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
{
(consequence, consequenceConversion, consequenceResult) = visitConditionalOperand(consequenceState, node.Consequence);
Unsplit();
+ consequenceState = this.State;
(alternative, alternativeConversion, alternativeResult) = visitConditionalOperand(alternativeState, node.Alternative);
Unsplit();
Join(ref this.State, ref consequenceState);
@@ -2361,32 +2398,22 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
if (!isConstantFalse)
{
- convertedConsequenceResult = ApplyConversion(
+ convertedConsequenceResult = convertResult(
node.Consequence,
consequence,
consequenceConversion,
resultTypeWithAnnotations,
- consequenceResult.ToTypeWithState(),
- checkConversion: true,
- fromExplicitCast: false,
- useLegacyWarnings: false,
- AssignmentKind.Assignment,
- reportTopLevelWarnings: false).ToTypeSymbolWithAnnotations();
+ consequenceResult);
}
if (!isConstantTrue)
{
- convertedAlternativeResult = ApplyConversion(
+ convertedAlternativeResult = convertResult(
node.Alternative,
alternative,
alternativeConversion,
resultTypeWithAnnotations,
- alternativeResult.ToTypeWithState(),
- checkConversion: true,
- fromExplicitCast: false,
- useLegacyWarnings: false,
- AssignmentKind.Assignment,
- reportTopLevelWarnings: false).ToTypeSymbolWithAnnotations();
+ alternativeResult);
}
if (!convertedAlternativeResult.HasType)
@@ -2465,6 +2492,26 @@ NullableAnnotation getNullableAnnotation(BoundExpression expr, TypeSymbolWithAnn
return (operand, conversion, resultWithAnnotation);
}
+
+ TypeSymbolWithAnnotations convertResult(
+ BoundExpression node,
+ BoundExpression operand,
+ Conversion conversion,
+ TypeSymbolWithAnnotations targetType,
+ TypeSymbolWithAnnotations operandType)
+ {
+ return ApplyConversion(
+ node,
+ operand,
+ conversion,
+ targetType,
+ operandType.ToTypeWithState(),
+ checkConversion: true,
+ fromExplicitCast: false,
+ useLegacyWarnings: false,
+ AssignmentKind.Assignment,
+ reportTopLevelWarnings: false).ToTypeSymbolWithAnnotations();
+ }
}
///
@@ -4667,7 +4714,6 @@ public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmen
TypeSymbolWithAnnotations leftLValueType = LvalueResultType;
TypeWithState leftResultType = ResultType;
- TypeWithState resultType;
Debug.Assert(!IsConditionalState);
TypeWithState leftOnRightType = GetAdjustedResult(leftResultType, MakeSlot(node.Left));
@@ -4694,6 +4740,7 @@ public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmen
leftOnRightType = default;
}
+ TypeWithState resultType;
TypeWithState rightType = VisitRvalueWithState(node.Right);
if ((object)node.Operator.ReturnType != null)
{
@@ -5459,9 +5506,7 @@ public override BoundNode VisitImplicitReceiver(BoundImplicitReceiver node)
public override BoundNode VisitAnonymousPropertyDeclaration(BoundAnonymousPropertyDeclaration node)
{
- var result = base.VisitAnonymousPropertyDeclaration(node);
- SetNotNullResult(node);
- return result;
+ throw ExceptionUtilities.Unreachable;
}
public override BoundNode VisitNoPiaObjectCreationExpression(BoundNoPiaObjectCreationExpression node)
@@ -5473,9 +5518,8 @@ public override BoundNode VisitNoPiaObjectCreationExpression(BoundNoPiaObjectCre
public override BoundNode VisitNewT(BoundNewT node)
{
- var result = base.VisitNewT(node);
- ResultType = new TypeWithState(node.Type, NullableFlowState.NotNull);
- return result;
+ VisitObjectOrDynamicObjectCreation(node, ImmutableArray.Empty, ImmutableArray.Empty, node.InitializerExpressionOpt);
+ return null;
}
public override BoundNode VisitArrayInitialization(BoundArrayInitialization node)
diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeWithState.cs b/src/Compilers/CSharp/Portable/Symbols/TypeWithState.cs
index 0251f93c4d9ad..91b2765f68d15 100644
--- a/src/Compilers/CSharp/Portable/Symbols/TypeWithState.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/TypeWithState.cs
@@ -10,8 +10,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
internal readonly struct TypeWithState
{
- public TypeSymbol Type { get; }
- public NullableFlowState State { get; }
+ public readonly TypeSymbol Type;
+ public readonly NullableFlowState State;
public bool HasNullType => Type is null;
public bool MayBeNull => State == NullableFlowState.MaybeNull;
public bool IsNotNull => State == NullableFlowState.NotNull;
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs
index 261bfd3f18f29..fd34dfd251d8a 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs
@@ -19,7 +19,6 @@ public class NullableReferenceTypesTests : CSharpTestBase
{
private const string Tuple2NonNullable =
@"
-
namespace System
{
#nullable enable
@@ -42,9 +41,7 @@ public override string ToString()
return """";
}
}
-}
-
- ";
+}";
private const string TupleRestNonNullable =
@"
@@ -21318,6 +21315,75 @@ static void F(bool b)
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(6, 9));
}
+ [Fact]
+ public void ConditionalOperator_16()
+ {
+ var source =
+@"class Program
+{
+ static bool F(object? x)
+ {
+ return true;
+ }
+ static void F1(bool b, bool c, object x1, object? y1)
+ {
+ if (b ? c && F(x1 = y1) : true) // 1
+ {
+ x1.ToString(); // 2
+ }
+ }
+ static void F2(bool b, bool c, object x2, object? y2)
+ {
+ if (b ? true : c && F(x2 = y2)) // 3
+ {
+ x2.ToString(); // 4
+ }
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics(
+ // (9,29): warning CS8600: Converting null literal or possible null value to non-nullable type.
+ // if (b ? c && F(x1 = y1) : true) // 1
+ Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "y1").WithLocation(9, 29),
+ // (11,13): warning CS8602: Possible dereference of a null reference.
+ // x1.ToString(); // 2
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(11, 13),
+ // (16,36): warning CS8600: Converting null literal or possible null value to non-nullable type.
+ // if (b ? true : c && F(x2 = y2)) // 3
+ Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "y2").WithLocation(16, 36),
+ // (18,13): warning CS8602: Possible dereference of a null reference.
+ // x2.ToString(); // 4
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x2").WithLocation(18, 13));
+ }
+
+ [Fact]
+ public void ConditionalOperator_17()
+ {
+ var source =
+@"class Program
+{
+ static void F(bool x, bool y, bool z, bool? w)
+ {
+ object o;
+ o = x ? y && z : w; // 1
+ o = true ? y && z : w;
+ o = false ? w : y && z;
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ // Should there be a warning for // 1 only?
+ comp.VerifyDiagnostics(
+ // (6,13): warning CS8600: Converting null literal or possible null value to non-nullable type.
+ // o = x ? y && z : w; // 1
+ Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x ? y && z : w").WithLocation(6, 13),
+ // (7,13): warning CS8600: Converting null literal or possible null value to non-nullable type.
+ // o = true ? y && z : w;
+ Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "true ? y && z : w").WithLocation(7, 13),
+ // (8,13): warning CS8600: Converting null literal or possible null value to non-nullable type.
+ // o = false ? w : y && z;
+ Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "false ? w : y && z").WithLocation(8, 13));
+ }
+
[Fact]
public void ConditionalOperator_TopLevelNullability()
{
@@ -34490,6 +34556,27 @@ class Awaiter : System.Runtime.CompilerServices.INotifyCompletion
);
}
+ [Fact]
+ public void Await_03()
+ {
+ var source =
+@"using System.Threading.Tasks;
+class Program
+{
+ async void M(Task? x, Task? y)
+ {
+ if (y == null) return;
+ await x; // 1
+ await y;
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics(
+ // (7,15): warning CS8602: Possible dereference of a null reference.
+ // await x; // 1
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(7, 15));
+ }
+
[Fact]
public void Await_ProduceResultTypeFromTask()
{
@@ -39174,6 +39261,55 @@ static void Main()
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "RefReturn()").WithLocation(15, 32));
}
+ [Fact]
+ [WorkItem(27317, "https://github.com/dotnet/roslyn/pull/27317")]
+ public void RefOutSuppressionInference()
+ {
+ var src = @"
+class C
+{
+ void M(ref T t) { }
+ void M2(out T t) => throw null!;
+ void M3(in T t) { }
+ T M4(in T t) => t;
+
+ void M3()
+ {
+ string? s1 = null;
+ M(ref s1!);
+ s1.ToString();
+
+ string? s2 = null;
+ M2(out s2!);
+ s2.ToString();
+
+ string? s3 = null;
+ M3(s3!);
+ s3.ToString(); // warn
+
+ string? s4 = null;
+ M3(in s4!);
+ s4.ToString(); // warn
+
+ string? s5 = null;
+ s5 = M4(s5!);
+ s5.ToString();
+
+ string? s6 = null;
+ s6 = M4(in s6!);
+ s6.ToString();
+ }
+}";
+ var comp = CreateCompilation(src, options: WithNonNullTypesTrue(TestOptions.DebugDll));
+ comp.VerifyDiagnostics(
+ // (21,9): warning CS8602: Possible dereference of a null reference.
+ // s3.ToString(); // warn
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s3").WithLocation(21, 9),
+ // (25,9): warning CS8602: Possible dereference of a null reference.
+ // s4.ToString(); // warn
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s4").WithLocation(25, 9));
+ }
+
[Fact]
[WorkItem(27522, "https://github.com/dotnet/roslyn/issues/27522")]
[WorkItem(29903, "https://github.com/dotnet/roslyn/issues/29903")]
@@ -43531,8 +43667,6 @@ static void F2()
}
}";
var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
- // https://github.com/dotnet/roslyn/issues/29968 Allow conversion to base
- // type to avoid the warning for `u2.y.F.ToString();`.
comp.VerifyDiagnostics(
// (12,22): warning CS8619: Nullability of reference types in value of type '(A?, A)' doesn't match target type '(A, A?)'.
// (A, A?) t1 = (null, new A() { F = 1 }); // 1
@@ -43545,10 +43679,7 @@ static void F2()
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "(null, new B() { F = 2 })").WithArguments("(A?, A)", "(A, A?)").WithLocation(20, 22),
// (22,9): warning CS8602: Possible dereference of a null reference.
// u2.x.ToString(); // 4
- Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "u2.x").WithLocation(22, 9),
- // (24,9): warning CS8602: Possible dereference of a null reference.
- // u2.y.F.ToString();
- Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "u2.y.F").WithLocation(24, 9));
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "u2.x").WithLocation(22, 9));
comp.VerifyTypes();
}
@@ -43642,25 +43773,27 @@ static void F(string x, string? y)
t.Item2.ToString(); // 2
u.Item1.ToString();
u.Item2.ToString(); // 3
- v.Item1.ToString(); // 4
- v.Item2.ToString(); // 5
+ v.Item1.ToString();
+ v.Item2.ToString(); // 4
}
}";
var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
- // https://github.com/dotnet/roslyn/issues/32599: Support explicit conversions (see // 5).
comp.VerifyDiagnostics(
// (5,30): warning CS8619: Nullability of reference types in value of type '(object x, string? y)' doesn't match target type '(object, string)'.
// (object, string) t = ((object, string))(x, y)/*T:(object! x, string? y)*/; // 1
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "((object, string))(x, y)").WithArguments("(object x, string? y)", "(object, string)").WithLocation(5, 30),
// (5,52): warning CS8600: Converting null literal or possible null value to non-nullable type.
- // (object, string) t = ((object, string))(x, y)/*T:(string? x, string? y)*/; // 1
+ // (object, string) t = ((object, string))(x, y)/*T:(object! x, string? y)*/; // 1
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "y").WithLocation(5, 52),
+ // (9,9): warning CS8602: Possible dereference of a null reference.
+ // t.Item2.ToString(); // 2
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t.Item2").WithLocation(9, 9),
// (11,9): warning CS8602: Possible dereference of a null reference.
// u.Item2.ToString(); // 3
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "u.Item2").WithLocation(11, 9),
- // (12,9): warning CS8602: Possible dereference of a null reference.
- // v.Item1.ToString(); // 4
- Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "v.Item1").WithLocation(12, 9));
+ // (13,9): warning CS8602: Possible dereference of a null reference.
+ // v.Item2.ToString(); // 4
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "v.Item2").WithLocation(13, 9));
comp.VerifyTypes();
}
@@ -50914,8 +51047,7 @@ static void F()
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "c.E").WithLocation(9, 9));
}
- // https://github.com/dotnet/roslyn/issues/29977: Support assignment of derived type instances.
- [Fact(Skip = "https://github.com/dotnet/roslyn/issues/29977")]
+ [Fact]
[WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
public void Members_ObjectInitializer_DerivedType()
{
@@ -50935,31 +51067,27 @@ static void Main()
{
A a;
a = new B() { F = new A(), G = new object() };
- a.F.ToString(); // 1
+ a.F.ToString();
a = new A();
- a.F.ToString(); // 2
+ a.F.ToString(); // 1
a = new B() { F = new B() { F = new A() } };
- a.F.ToString(); // 3
- a.F.F.ToString(); // 3
+ a.F.ToString();
+ a.F.F.ToString();
a = new B() { G = new object() };
- a.F.ToString(); // 4
+ a.F.ToString(); // 2
}
}";
var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue());
comp.VerifyDiagnostics(
// (18,9): warning CS8602: Possible dereference of a null reference.
- // a.F.ToString(); // 2
+ // a.F.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "a.F").WithLocation(18, 9),
- // (20,9): warning CS8602: Possible dereference of a null reference.
- // a.F.ToString(); // 3
- Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "a.F").WithLocation(20, 9),
// (23,9): warning CS8602: Possible dereference of a null reference.
- // a.F.ToString(); // 4
+ // a.F.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "a.F").WithLocation(23, 9));
}
- // https://github.com/dotnet/roslyn/issues/29977: Support assignment of derived type instances.
- [Fact(Skip = "https://github.com/dotnet/roslyn/issues/29977")]
+ [Fact]
[WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
public void Members_Assignment()
{
@@ -50998,11 +51126,417 @@ static void Main()
// (17,9): warning CS8602: Possible dereference of a null reference.
// a.F.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "a.F").WithLocation(17, 9),
+ // (20,9): warning CS8602: Possible dereference of a null reference.
+ // a.F.ToString(); // 2
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "a.F").WithLocation(20, 9),
+ // (23,9): warning CS8602: Possible dereference of a null reference.
+ // a.F.ToString(); // 3
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "a.F").WithLocation(23, 9),
+ // (24,9): warning CS8602: Possible dereference of a null reference.
+ // a.F.F.ToString(); // 3
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "a.F.F").WithLocation(24, 9),
// (27,9): warning CS8602: Possible dereference of a null reference.
// a.F.ToString(); // 4
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "a.F").WithLocation(27, 9));
}
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_ReferenceConversions_01()
+ {
+ var source =
+@"class A
+{
+ internal object? FA;
+}
+class B : A
+{
+ internal object FB = new object();
+}
+class Program
+{
+ static void F()
+ {
+ A a = new B() { FA = 1 };
+ a.FA.ToString();
+ a = new B() { FA = 2, FB = null }; // 1
+ ((B)a).FA.ToString();
+ ((B)a).FB.ToString(); // 2
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics(
+ // (15,36): warning CS8625: Cannot convert null literal to non-nullable reference type.
+ // a = new B() { FA = 2, FB = null }; // 1
+ Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(15, 36),
+ // (17,9): warning CS8602: Possible dereference of a null reference.
+ // ((B)a).FB.ToString(); // 2
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "((B)a).FB").WithLocation(17, 9));
+ }
+
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_ReferenceConversions_02()
+ {
+ var source =
+@"class A
+{
+ internal object? FA;
+}
+class B : A
+{
+ internal object FB = new object();
+}
+class Program
+{
+ static void F()
+ {
+ B b = new B() { FA = 1 };
+ A a = b;
+ a.FA.ToString();
+ a = new B() { FB = null }; // 1
+ b = (B)a;
+ b.FB.ToString(); // 2
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ // https://github.com/dotnet/roslyn/issues/31395: Nullability of class members should be copied on assignment.
+ comp.VerifyDiagnostics(
+ // (15,9): warning CS8602: Possible dereference of a null reference.
+ // a.FA.ToString();
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "a.FA").WithLocation(15, 9),
+ // (16,28): warning CS8625: Cannot convert null literal to non-nullable reference type.
+ // a = new B() { FB = null }; // 1
+ Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(16, 28));
+ }
+
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_ReferenceConversions_03()
+ {
+ var source =
+@"interface IA
+{
+ object? PA { get; set; }
+}
+interface IB : IA
+{
+ object PB { get; set; }
+}
+class Program
+{
+ static void F(IB b)
+ {
+ b.PA = 1;
+ b.PB = null; // 1
+ ((IA)b).PA.ToString();
+ ((IB)(object)b).PB.ToString(); // 2
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics(
+ // (14,16): warning CS8625: Cannot convert null literal to non-nullable reference type.
+ // b.PB = null; // 1
+ Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(14, 16),
+ // (16,9): warning CS8602: Possible dereference of a null reference.
+ // ((IB)(object)b).PB.ToString(); // 2
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "((IB)(object)b).PB").WithLocation(16, 9));
+ }
+
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_ReferenceConversions_04()
+ {
+ var source =
+@"interface IA
+{
+ object? PA { get; set; }
+}
+interface IB : IA
+{
+ object PB { get; set; }
+}
+class Program
+{
+ static void F(IB b)
+ {
+ b.PA = 1;
+ b.PB = null; // 1
+ object o = b;
+ b = o; // 2
+ b.PA.ToString();
+ b = (IB)o;
+ b.PB.ToString(); // 3
+ ((IB)o).PA.ToString();
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ // https://github.com/dotnet/roslyn/issues/31395: Nullability of class members should be copied on assignment.
+ comp.VerifyDiagnostics(
+ // (14,16): warning CS8625: Cannot convert null literal to non-nullable reference type.
+ // b.PB = null; // 1
+ Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(14, 16),
+ // (16,13): error CS0266: Cannot implicitly convert type 'object' to 'IB'. An explicit conversion exists (are you missing a cast?)
+ // b = o; // 2
+ Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "o").WithArguments("object", "IB").WithLocation(16, 13),
+ // (17,9): warning CS8602: Possible dereference of a null reference.
+ // b.PA.ToString();
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "b.PA").WithLocation(17, 9),
+ // (20,9): warning CS8602: Possible dereference of a null reference.
+ // ((IB)o).PA.ToString();
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "((IB)o).PA").WithLocation(20, 9));
+ }
+
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_ReferenceConversions_05()
+ {
+ var source =
+@"#pragma warning disable 0649
+class C
+{
+ internal object? F;
+}
+class Program
+{
+ static void F(object x, object? y)
+ {
+ if (((C)x).F != null)
+ ((C)x).F.ToString();
+ if (((C?)y)?.F != null)
+ ((C)y).F.ToString();
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics();
+ }
+
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_ReferenceConversions_06()
+ {
+ var source =
+@"class C
+{
+ internal object F() => null!;
+}
+class Program
+{
+ static void F(object? x)
+ {
+ if (((C?)x)?.F() != null)
+ ((C)x).F().ToString();
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics();
+ }
+
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_ReferenceConversions_07()
+ {
+ var source =
+@"interface I
+{
+ object? P { get; }
+}
+class Program
+{
+ static void F(object x, object? y)
+ {
+ if (((I)x).P != null)
+ ((I)x).P.ToString();
+ if (((I?)y)?.P != null)
+ ((I)y).P.ToString();
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics();
+ }
+
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_ReferenceConversions_08()
+ {
+ var source =
+@"interface I
+{
+ object F();
+}
+class Program
+{
+ static void F(object? x)
+ {
+ if (((I?)x)?.F() != null)
+ ((I)x).F().ToString();
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics();
+ }
+
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_ReferenceConversions_09()
+ {
+ var source =
+@"class A
+{
+ internal bool? F;
+}
+class B : A
+{
+}
+class Program
+{
+ static void M(bool b1, bool b2)
+ {
+ A a;
+ if (b1 ? b2 && (a = new B() { F = true }).F.Value : false)
+ {
+ }
+ if (true ? b2 && (a = new B() { F = false }).F.Value : false)
+ {
+ }
+ if (false ? false : b2 && (a = new B() { F = b1 }).F.Value)
+ {
+ }
+ if (false ? b2 && (a = new B() { F = null }).F.Value : true)
+ {
+ }
+ _ = (a = new B() { F = null }).F.Value; // 1
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics(
+ // (25,13): warning CS8629: Nullable value type may be null.
+ // _ = (a = new B() { F = null }).F.Value; // 1
+ Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "(a = new B() { F = null }).F").WithLocation(25, 13));
+ }
+
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_TupleConversions_01()
+ {
+ var source =
+@"class A
+{
+ internal object? FA;
+}
+class B : A
+{
+ internal object FB = new object();
+}
+class Program
+{
+ static void F()
+ {
+ (B, object) t = (new B() { FA = 1 }, new B() { FB = null }); // 1
+ t.Item1.FA.ToString();
+ ((A)t.Item1).FA.ToString();
+ ((B)t.Item2).FB.ToString(); // 2
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics(
+ // (13,61): warning CS8625: Cannot convert null literal to non-nullable reference type.
+ // (B, object) t = (new B() { FA = 1 }, new B() { FB = null }); // 1
+ Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(13, 61),
+ // (16,9): warning CS8602: Possible dereference of a null reference.
+ // ((B)t.Item2).FB.ToString(); // 2
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "((B)t.Item2).FB").WithLocation(16, 9));
+ }
+
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_TupleConversions_02()
+ {
+ var source =
+@"class A
+{
+ internal object? FA;
+}
+class B : A
+{
+ internal object FB = new object();
+}
+class Program
+{
+ static void F()
+ {
+ (B, object) t = (new B() { FA = 1 }, new B() { FB = null }); // 1
+ (((A, A))t).Item1.FA.ToString();
+ (((B, B))t).Item2.FB.ToString(); // 2
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics(
+ // (13,61): warning CS8625: Cannot convert null literal to non-nullable reference type.
+ // (B, object) t = (new B() { FA = 1 }, new B() { FB = null }); // 1
+ Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(13, 61),
+ // (15,9): warning CS8602: Possible dereference of a null reference.
+ // (((B, B))t).Item2.FB.ToString(); // 2
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(((B, B))t).Item2.FB").WithLocation(15, 9));
+ }
+
+ [Fact]
+ [WorkItem(29977, "https://github.com/dotnet/roslyn/issues/29977")]
+ public void Conversions_TupleConversions_03()
+ {
+ var source =
+@"class A
+{
+ internal object? FA;
+}
+class B : A
+{
+ internal object FB = new object();
+}
+class Program
+{
+ static void F()
+ {
+ B b = new B() { FA = 1, FB = null }; // 1
+ (B, (A, A)) t;
+ t = (b, (b, b));
+ t.Item1.FB.ToString(); // 2
+ t.Item2.Item1.FA.ToString();
+ t = ((B, (A, A)))(b, (b, b));
+ t.Item1.FB.ToString(); // 3
+ t.Item2.Item1.FA.ToString();
+ (A, (B, B)) u;
+ u = t; // 4
+ u.Item1.FA.ToString();
+ u.Item2.Item2.FB.ToString(); // 5
+ u = ((A, (B, B)))t;
+ u.Item1.FA.ToString();
+ u.Item2.Item2.FB.ToString(); // 6
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ // https://github.com/dotnet/roslyn/issues/31395: Nullability of class members should be copied on assignment.
+ comp.VerifyDiagnostics(
+ // (13,38): warning CS8625: Cannot convert null literal to non-nullable reference type.
+ // B b = new B() { FA = 1, FB = null }; // 1
+ Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(13, 38),
+ // (17,9): warning CS8602: Possible dereference of a null reference.
+ // t.Item2.Item1.FA.ToString();
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t.Item2.Item1.FA").WithLocation(17, 9),
+ // (20,9): warning CS8602: Possible dereference of a null reference.
+ // t.Item2.Item1.FA.ToString();
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "t.Item2.Item1.FA").WithLocation(20, 9),
+ // (22,13): error CS0266: Cannot implicitly convert type '(B, (A, A))' to '(A, (B, B))'. An explicit conversion exists (are you missing a cast?)
+ // u = t; // 4
+ Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "t").WithArguments("(B, (A, A))", "(A, (B, B))").WithLocation(22, 13),
+ // (23,9): warning CS8602: Possible dereference of a null reference.
+ // u.Item1.FA.ToString();
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "u.Item1.FA").WithLocation(23, 9),
+ // (26,9): warning CS8602: Possible dereference of a null reference.
+ // u.Item1.FA.ToString();
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "u.Item1.FA").WithLocation(26, 9));
+ }
+
[Fact]
public void Members_FieldCycle_01()
{
@@ -51266,6 +51800,39 @@ static void M(S s)
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s.P.F").WithLocation(19, 9));
}
+ [Fact]
+ public void Members_StaticField_Struct()
+ {
+ var source =
+@"struct S where T : class
+{
+ internal T F;
+ internal T? G;
+ internal static S Instance = new S();
+}
+class Program
+{
+ static void F() where T : class, new()
+ {
+ S.Instance.F = null; // 1
+ S.Instance.G = new T();
+ S.Instance.F.ToString(); // 2
+ S.Instance.G.ToString();
+ }
+}";
+ var comp = CreateCompilation(source, options: WithNonNullTypesTrue());
+ comp.VerifyDiagnostics(
+ // (5,26): error CS0523: Struct member 'S.Instance' of type 'S' causes a cycle in the struct layout
+ // internal static S Instance = new S();
+ Diagnostic(ErrorCode.ERR_StructLayoutCycle, "Instance").WithArguments("S.Instance", "S").WithLocation(5, 26),
+ // (11,27): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
+ // S.Instance.F = null; // 1
+ Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(11, 27),
+ // (13,9): warning CS8602: Possible dereference of a null reference.
+ // S.Instance.F.ToString(); // 2
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "S.Instance.F").WithLocation(13, 9));
+ }
+
[Fact]
public void Members_DefaultConstructor_Class()
{
@@ -55708,9 +56275,9 @@ class C {
// (4,2): error CS8652: The feature 'nullable reference types' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// #nullable enable
Diagnostic(ErrorCode.ERR_FeatureInPreview, "nullable").WithArguments("nullable reference types").WithLocation(4, 2),
- // (5,2): error CS8652: The feature 'nullable reference types' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // (4,2): error CS8652: The feature 'nullable reference types' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// #nullable enable
- Diagnostic(ErrorCode.ERR_FeatureInPreview, "nullable").WithArguments("nullable reference types").WithLocation(5, 2),
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "nullable").WithArguments("nullable reference types").WithLocation(4, 2),
// (6,20): error CS8652: The feature 'object generic type constraint' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// where T1 : object
Diagnostic(ErrorCode.ERR_FeatureInPreview, "object").WithArguments("object generic type constraint").WithLocation(6, 20),
@@ -55718,13 +56285,16 @@ class C {
// (string?, string) t1;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "?").WithArguments("nullable reference types").WithLocation(7, 16),
// (7,20): error CS8652: The feature 'object generic type constraint' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // where T1 : object
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "object").WithArguments("object generic type constraint").WithLocation(7, 20),
+ // (7,20): error CS8652: The feature 'object generic type constraint' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// where T2 : object
Diagnostic(ErrorCode.ERR_FeatureInPreview, "object").WithArguments("object generic type constraint").WithLocation(7, 20),
// (8,20): error CS8652: The feature 'object generic type constraint' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
- // where T3 : object
+ // where T2 : object
Diagnostic(ErrorCode.ERR_FeatureInPreview, "object").WithArguments("object generic type constraint").WithLocation(8, 20),
// (8,20): error CS8652: The feature 'object generic type constraint' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
- // where T1 : object
+ // where T3 : object
Diagnostic(ErrorCode.ERR_FeatureInPreview, "object").WithArguments("object generic type constraint").WithLocation(8, 20),
// (8,33): error CS8652: The feature 'nullable reference types' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// Type t2 = typeof((string?, string));
@@ -55732,9 +56302,6 @@ class C {
// (9,20): error CS8652: The feature 'object generic type constraint' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// where T4 : object
Diagnostic(ErrorCode.ERR_FeatureInPreview, "object").WithArguments("object generic type constraint").WithLocation(9, 20),
- // (9,20): error CS8652: The feature 'object generic type constraint' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
- // where T2 : object
- Diagnostic(ErrorCode.ERR_FeatureInPreview, "object").WithArguments("object generic type constraint").WithLocation(9, 20),
// (10,20): error CS8652: The feature 'object generic type constraint' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// where T5 : object
Diagnostic(ErrorCode.ERR_FeatureInPreview, "object").WithArguments("object generic type constraint").WithLocation(10, 20),
@@ -82714,7 +83281,7 @@ static IB CreateB(T t)
static void F1(T x1)
{
if (x1 == null) return;
- var y1 = CreateB(x1);
+ var y1 = CreateB(x1);
y1.A.ToString(); // 1
y1.B.ToString(); // 2
}
@@ -82729,21 +83296,21 @@ static void F1(T x1)
static void F3() where T : class, new()
{
T? x3 = new T();
- var y3 = CreateB(x3);
+ var y3 = CreateB(x3);
y3.A.ToString();
y3.B.ToString();
}
static void F4() where T : struct
{
T? x4 = null;
- var y4 = CreateB(x4);
+ var y4 = CreateB(x4);
_ = y4.A.Value; // 6
_ = y4.B.Value; // 7
}
static void F5() where T : struct
{
T? x5 = new T();
- var y5 = CreateB(x5);
+ var y5 = CreateB(x5);
_ = y5.A.Value; // 8
_ = y5.B.Value; // 9
}
@@ -82852,7 +83419,7 @@ static void F1(T x1)
if (x1 == null) return;
T y1 = default; // 1
var ix1 = CreateB(x1);
- var iy1 = CreateB(y1);
+ var iy1 = CreateB(y1);
ix1.A(y1);
ix1.B(y1);
iy1.A(x1);
@@ -82863,7 +83430,7 @@ static void F2() where T : class, new()
T x2 = null; // 2
T? y2 = new T();
var ix2 = CreateB(x2);
- var iy2 = CreateB(y2);
+ var iy2 = CreateB(y2);
ix2.A(y2);
ix2.B(y2);
iy2.A(x2); // 3
@@ -82874,7 +83441,7 @@ static void F2() where T : class, new()
T? x3 = null;
T? y3 = new T();
var ix3 = CreateB(x3);
- var iy3 = CreateB(y3);
+ var iy3 = CreateB(y3);
ix3.A(y3);
ix3.B(y3);
iy3.A(x3);
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs
index c7dc08aca6cc2..aace3845fccea 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SwitchTests.cs
@@ -2918,6 +2918,35 @@ public static void Main()
);
}
+ [Fact]
+ [WorkItem(33783, "https://github.com/dotnet/roslyn/issues/33783")]
+ public void UnreachableDefaultInBoolSwitch()
+ {
+ var text = @"
+public class TestClass
+{
+ public static void Main()
+ {
+ bool b = false;
+ switch (b)
+ {
+ case true:
+ break;
+ case false:
+ break;
+ default:
+ break; //1
+ }
+ }
+}";
+ CreateCompilation(text, parseOptions: TestOptions.Regular6).VerifyDiagnostics();
+ CreateCompilation(text, parseOptions: TestOptions.Regular7_3).VerifyDiagnostics();
+ CreateCompilation(text).VerifyDiagnostics(
+ // (14,17): warning CS0162: Unreachable code detected
+ // break; //1
+ Diagnostic(ErrorCode.WRN_UnreachableCode, "break").WithLocation(14, 17));
+ }
+
#endregion
}
}
diff --git a/src/EditorFeatures/Test2/Rename/RenameEngineTests.VisualBasicConflicts.vb b/src/EditorFeatures/Test2/Rename/RenameEngineTests.VisualBasicConflicts.vb
index b8a21ff643bef..78175f7fad7f9 100644
--- a/src/EditorFeatures/Test2/Rename/RenameEngineTests.VisualBasicConflicts.vb
+++ b/src/EditorFeatures/Test2/Rename/RenameEngineTests.VisualBasicConflicts.vb
@@ -3112,6 +3112,64 @@ End Class
End Using
End Sub
+
+
+
+ Public Sub RenameParameterizedPropertyResolvedConflict()
+ Using result = RenameEngineResult.Create(_outputHelper,
+
+
+
+
+
+ , renameTo:="P")
+
+ result.AssertLabeledSpansAre("Conflict0", replacement:="Return P(CObj(""""))", type:=RelatedLocationType.ResolvedNonReferenceConflict)
+ End Using
+ End Sub
+
+
+
+
+ Public Sub RenameParameterizedPropertyUnresolvedConflict()
+ Using result = RenameEngineResult.Create(_outputHelper,
+
+
+
+
+
+ , renameTo:="P")
+
+ result.AssertLabeledSpansAre("Conflict", type:=RelatedLocationType.UnresolvedConflict)
+ End Using
+ End Sub
+
diff --git a/src/VisualStudio/Core/Def/Experimentation/VisualStudioExperimentationService.cs b/src/VisualStudio/Core/Def/Experimentation/VisualStudioExperimentationService.cs
index 370ef27d4e7d0..e5ef4b0c079e1 100644
--- a/src/VisualStudio/Core/Def/Experimentation/VisualStudioExperimentationService.cs
+++ b/src/VisualStudio/Core/Def/Experimentation/VisualStudioExperimentationService.cs
@@ -57,10 +57,16 @@ public bool IsExperimentEnabled(string experimentName)
{
try
{
- var enabled = _featureFlags.IsFeatureEnabled(experimentName, defaultValue: false);
- if (enabled)
+ // check whether "." exist in the experimentName since it is requirement for featureflag service.
+ // we do this since RPS complains about resource file being loaded for invalid name exception
+ // we are not testing all rules but just simple "." check
+ if (experimentName.IndexOf(".") > 0)
{
- return enabled;
+ var enabled = _featureFlags.IsFeatureEnabled(experimentName, defaultValue: false);
+ if (enabled)
+ {
+ return enabled;
+ }
}
}
catch
diff --git a/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs b/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs
index 5fac5518074be..2e11134a0a659 100644
--- a/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs
+++ b/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs
@@ -259,7 +259,7 @@ private class TestService : ServiceHubServiceBase
{
Event = new ManualResetEvent(false);
- Rpc.StartListening();
+ StartService();
}
public readonly ManualResetEvent Event;
diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs
index 8e823d7a83b57..a89c28ceb7e57 100644
--- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs
+++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs
@@ -40,7 +40,7 @@ internal static partial class ConflictResolver
/// The original name of the identifier.
/// The new name of the identifier
/// The option for rename
- /// Called after renaming references. Can be used by callers to
+ /// Called after renaming references. Can be used by callers to
/// indicate if the new symbols that the reference binds to should be considered to be ok or
/// are in conflict. 'true' means they are conflicts. 'false' means they are not conflicts.
/// 'null' means that the default conflict check should be used.
@@ -181,14 +181,31 @@ private static bool IsRenameValid(ConflictResolution conflictResolution, ISymbol
{
try
{
+ var project = conflictResolution.NewSolution.GetProject(renamedSymbol.ContainingAssembly, cancellationToken);
+
if (renamedSymbol.ContainingSymbol.IsKind(SymbolKind.NamedType))
{
var otherThingsNamedTheSame = renamedSymbol.ContainingType.GetMembers(renamedSymbol.Name)
.Where(s => !s.Equals(renamedSymbol) &&
- string.Equals(s.MetadataName, renamedSymbol.MetadataName, StringComparison.Ordinal) &&
- (s.Kind != SymbolKind.Method || renamedSymbol.Kind != SymbolKind.Method));
+ string.Equals(s.MetadataName, renamedSymbol.MetadataName, StringComparison.Ordinal));
- AddConflictingSymbolLocations(otherThingsNamedTheSame, conflictResolution, reverseMappedLocations);
+ IEnumerable otherThingsNamedTheSameExcludeMethodAndParameterizedProperty;
+
+ // Possibly overloaded symbols are excluded here and handled elsewhere
+ var semanticFactsService = project.LanguageServices.GetService();
+ if (semanticFactsService.SupportsParameterizedProperties)
+ {
+ otherThingsNamedTheSameExcludeMethodAndParameterizedProperty = otherThingsNamedTheSame
+ .Where(s=> !s.MatchesKind(SymbolKind.Method, SymbolKind.Property) ||
+ !renamedSymbol.MatchesKind(SymbolKind.Method, SymbolKind.Property));
+ }
+ else
+ {
+ otherThingsNamedTheSameExcludeMethodAndParameterizedProperty = otherThingsNamedTheSame
+ .Where(s => s.Kind != SymbolKind.Method || renamedSymbol.Kind != SymbolKind.Method);
+ }
+
+ AddConflictingSymbolLocations(otherThingsNamedTheSameExcludeMethodAndParameterizedProperty, conflictResolution, reverseMappedLocations);
}
@@ -220,8 +237,6 @@ private static bool IsRenameValid(ConflictResolution conflictResolution, ISymbol
// Some types of symbols (namespaces, cref stuff, etc) might not have ContainingAssemblies
if (renamedSymbol.ContainingAssembly != null)
{
- var project = conflictResolution.NewSolution.GetProject(renamedSymbol.ContainingAssembly, cancellationToken);
-
// There also might be language specific rules we need to include
var languageRenameService = project.LanguageServices.GetService();
var languageConflicts = await languageRenameService.ComputeDeclarationConflictsAsync(
diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/DeclarationConflictHelpers.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/DeclarationConflictHelpers.cs
index 128e8a8834480..23f4cb6c07238 100644
--- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/DeclarationConflictHelpers.cs
+++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/DeclarationConflictHelpers.cs
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@@ -17,24 +18,53 @@ public static ImmutableArray GetMembersWithConflictingSignatures(IMeth
.OfType()
.Where(m => !m.Equals(renamedMethod) && m.Arity == renamedMethod.Arity);
- var signatureToConflictingMember = new Dictionary, IMethodSymbol>(ConflictingSignatureComparer.Instance);
+ return GetConflictLocations(renamedMethod, potentiallyConfictingMethods, isMethod:true,
+ (method) => GetAllSignatures((method as IMethodSymbol).Parameters, trimOptionalParameters));
+ }
+
+ public static ImmutableArray GetMembersWithConflictingSignatures(IPropertySymbol renamedProperty, bool trimOptionalParameters)
+ {
+ var potentiallyConfictingProperties =
+ renamedProperty.ContainingType.GetMembers(renamedProperty.Name)
+ .OfType()
+ .Where(m => !m.Equals(renamedProperty) && m.Parameters.Count() == renamedProperty.Parameters.Count());
+
+ return GetConflictLocations(renamedProperty, potentiallyConfictingProperties, isMethod: false,
+ (property)=>GetAllSignatures((property as IPropertySymbol).Parameters, trimOptionalParameters));
+ }
+
+ private static ImmutableArray GetConflictLocations(ISymbol renamedMember,
+ IEnumerable potentiallyConfictingMembers,
+ bool isMethod,
+ Func>> getAllSignatures)
+ {
+ var signatureToConflictingMember = new Dictionary, ISymbol>(ConflictingSignatureComparer.Instance);
- foreach (var method in potentiallyConfictingMethods)
+ foreach (var member in potentiallyConfictingMembers)
{
- foreach (var signature in GetAllSignatures(method, trimOptionalParameters))
+ foreach (var signature in getAllSignatures(member))
{
- signatureToConflictingMember[signature] = method;
+ signatureToConflictingMember[signature] = member;
}
}
var builder = ArrayBuilder.GetInstance();
- foreach (var signature in GetAllSignatures(renamedMethod, trimOptionalParameters))
+ foreach (var signature in getAllSignatures(renamedMember))
{
if (signatureToConflictingMember.TryGetValue(signature, out var conflictingSymbol))
{
- if (!(conflictingSymbol.PartialDefinitionPart != null && conflictingSymbol.PartialDefinitionPart == renamedMethod) &&
- !(conflictingSymbol.PartialImplementationPart != null && conflictingSymbol.PartialImplementationPart == renamedMethod))
+ if (isMethod)
+ {
+ var conflictingMethod = conflictingSymbol as IMethodSymbol;
+ var renamedMethod = renamedMember as IMethodSymbol;
+ if (!(conflictingMethod.PartialDefinitionPart != null && conflictingMethod.PartialDefinitionPart == renamedMethod) &&
+ !(conflictingMethod.PartialImplementationPart != null && conflictingMethod.PartialImplementationPart == renamedMethod))
+ {
+ builder.AddRange(conflictingSymbol.Locations);
+ }
+ }
+ else
{
builder.AddRange(conflictingSymbol.Locations);
}
@@ -57,25 +87,20 @@ public bool Equals(ImmutableArray x, ImmutableArray y)
public int GetHashCode(ImmutableArray obj)
{
- // This is a very simple GetHashCode implementation. Doing something "fancier" here
- // isn't really worth it, since to compute a proper hash we'd end up walking all the
- // ITypeSymbols anyways.
+ // This is a very simple GetHashCode implementation. Doing something "fancier" here
+ // isn't really worth it, since to compute a proper hash we'd end up walking all the
+ // ITypeSymbols anyways.
return obj.Length;
}
}
- private static ImmutableArray> GetAllSignatures(IMethodSymbol method, bool trimOptionalParameters)
+ private static ImmutableArray> GetAllSignatures(ImmutableArray parameters, bool trimOptionalParameters)
{
var resultBuilder = ArrayBuilder>.GetInstance();
var signatureBuilder = ArrayBuilder.GetInstance();
- if (method.MethodKind == MethodKind.Conversion)
- {
- signatureBuilder.Add(method.ReturnType);
- }
-
- foreach (var parameter in method.Parameters)
+ foreach (var parameter in parameters)
{
// In VB, a method effectively creates multiple signatures which are produced by
// chopping off each of the optional parameters on the end, last to first, per 4.1.1 of
diff --git a/src/Workspaces/Remote/Razor/Microsoft.CodeAnalysis.Remote.Razor.ServiceHub.csproj b/src/Workspaces/Remote/Razor/Microsoft.CodeAnalysis.Remote.Razor.ServiceHub.csproj
index 9daeb52f562d8..51a3769c60f39 100644
--- a/src/Workspaces/Remote/Razor/Microsoft.CodeAnalysis.Remote.Razor.ServiceHub.csproj
+++ b/src/Workspaces/Remote/Razor/Microsoft.CodeAnalysis.Remote.Razor.ServiceHub.csproj
@@ -42,5 +42,14 @@
Shared\ServiceHubServiceBase.cs
+
+ Shared\Extensions.cs
+
+
+ Shared\ClientDirectStream.cs
+
+
+ Shared\ServerDirectStream.cs
+
\ No newline at end of file
diff --git a/src/Workspaces/Remote/Razor/Shared/WatsonReporter.cs b/src/Workspaces/Remote/Razor/Shared/WatsonReporter.cs
new file mode 100644
index 0000000000000..7ebdb922edf53
--- /dev/null
+++ b/src/Workspaces/Remote/Razor/Shared/WatsonReporter.cs
@@ -0,0 +1,32 @@
+// 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 Microsoft.VisualStudio.Telemetry;
+
+namespace Microsoft.VisualStudio.Telemetry
+{
+ internal interface IFaultUtility
+ {
+ void AddProcessDump(int pid);
+ void AddFile(string fullpathname);
+ }
+}
+
+namespace Microsoft.CodeAnalysis.ErrorReporting
+{
+ ///
+ /// dummy types just to make linked file work
+ ///
+ internal class WatsonReporter
+ {
+ public static void Report(string description, Exception exception)
+ {
+ // do nothing
+ }
+
+ public static void Report(string description, Exception exception, Func callback)
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService.cs
index 4801a9cdd0341..f538d60eddae2 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService.cs
@@ -11,7 +11,7 @@ internal partial class CodeAnalysisService : ServiceHubServiceBase
public CodeAnalysisService(Stream stream, IServiceProvider serviceProvider) :
base(serviceProvider, stream)
{
- Rpc.StartListening();
+ StartService();
}
}
}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_AddImport.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_AddImport.cs
index 8cdcc72d89d63..4e15508fac813 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_AddImport.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_AddImport.cs
@@ -61,8 +61,8 @@ public SymbolSearchService(CodeAnalysisService codeAnalysisService)
public async Task> FindPackagesWithTypeAsync(
string source, string name, int arity, CancellationToken cancellationToken)
{
- var result = await codeAnalysisService.Rpc.InvokeAsync>(
- nameof(FindPackagesWithTypeAsync), source, name, arity).ConfigureAwait(false);
+ var result = await codeAnalysisService.InvokeAsync>(
+ nameof(FindPackagesWithTypeAsync), new object[] { source, name, arity }, cancellationToken).ConfigureAwait(false);
return result;
}
@@ -70,8 +70,8 @@ public SymbolSearchService(CodeAnalysisService codeAnalysisService)
public async Task> FindPackagesWithAssemblyAsync(
string source, string assemblyName, CancellationToken cancellationToken)
{
- var result = await codeAnalysisService.Rpc.InvokeAsync>(
- nameof(FindPackagesWithAssemblyAsync), source, assemblyName).ConfigureAwait(false);
+ var result = await codeAnalysisService.InvokeAsync>(
+ nameof(FindPackagesWithAssemblyAsync), new object[] { source, assemblyName }, cancellationToken).ConfigureAwait(false);
return result;
}
@@ -79,8 +79,8 @@ public SymbolSearchService(CodeAnalysisService codeAnalysisService)
public async Task> FindReferenceAssembliesWithTypeAsync(
string name, int arity, CancellationToken cancellationToken)
{
- var result = await codeAnalysisService.Rpc.InvokeAsync>(
- nameof(FindReferenceAssembliesWithTypeAsync), name, arity).ConfigureAwait(false);
+ var result = await codeAnalysisService.InvokeAsync>(
+ nameof(FindReferenceAssembliesWithTypeAsync), new object[] { name, arity }, cancellationToken).ConfigureAwait(false);
return result;
}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_SymbolFinder.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_SymbolFinder.cs
index c054891cd0564..7e72c4d5a08e2 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_SymbolFinder.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_SymbolFinder.cs
@@ -168,10 +168,10 @@ public FindLiteralReferencesProgressCallback(CodeAnalysisService service)
}
public Task ReportProgressAsync(int current, int maximum)
- => _service.Rpc.InvokeAsync(nameof(ReportProgressAsync), current, maximum);
+ => _service.InvokeAsync(nameof(ReportProgressAsync), new object[] { current, maximum }, CancellationToken.None);
public Task OnReferenceFoundAsync(Document document, TextSpan span)
- => _service.Rpc.InvokeAsync(nameof(OnReferenceFoundAsync), document.Id, span);
+ => _service.InvokeAsync(nameof(OnReferenceFoundAsync), new object[] { document.Id, span }, CancellationToken.None);
}
private class FindReferencesProgressCallback : IStreamingFindReferencesProgress
@@ -184,30 +184,29 @@ public FindReferencesProgressCallback(CodeAnalysisService service)
}
public Task OnStartedAsync()
- => _service.Rpc.InvokeAsync(nameof(OnStartedAsync));
+ => _service.InvokeAsync(nameof(OnStartedAsync), CancellationToken.None);
public Task OnCompletedAsync()
- => _service.Rpc.InvokeAsync(nameof(OnCompletedAsync));
+ => _service.InvokeAsync(nameof(OnCompletedAsync), CancellationToken.None);
public Task ReportProgressAsync(int current, int maximum)
- => _service.Rpc.InvokeAsync(nameof(ReportProgressAsync), current, maximum);
+ => _service.InvokeAsync(nameof(ReportProgressAsync), new object[] { current, maximum }, CancellationToken.None);
public Task OnFindInDocumentStartedAsync(Document document)
- => _service.Rpc.InvokeAsync(nameof(OnFindInDocumentStartedAsync), document.Id);
+ => _service.InvokeAsync(nameof(OnFindInDocumentStartedAsync), new object[] { document.Id }, CancellationToken.None);
public Task OnFindInDocumentCompletedAsync(Document document)
- => _service.Rpc.InvokeAsync(nameof(OnFindInDocumentCompletedAsync), document.Id);
+ => _service.InvokeAsync(nameof(OnFindInDocumentCompletedAsync), new object[] { document.Id }, CancellationToken.None);
public Task OnDefinitionFoundAsync(SymbolAndProjectId definition)
- => _service.Rpc.InvokeAsync(nameof(OnDefinitionFoundAsync),
- SerializableSymbolAndProjectId.Dehydrate(definition));
+ => _service.InvokeAsync(nameof(OnDefinitionFoundAsync), new object[] { SerializableSymbolAndProjectId.Dehydrate(definition) }, CancellationToken.None);
public Task OnReferenceFoundAsync(
SymbolAndProjectId definition, ReferenceLocation reference)
{
- return _service.Rpc.InvokeAsync(nameof(OnReferenceFoundAsync),
- SerializableSymbolAndProjectId.Dehydrate(definition),
- SerializableReferenceLocation.Dehydrate(reference));
+ return _service.InvokeAsync(nameof(OnReferenceFoundAsync),
+ new object[] { SerializableSymbolAndProjectId.Dehydrate(definition), SerializableReferenceLocation.Dehydrate(reference) },
+ CancellationToken.None);
}
}
}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/RemoteHostService.cs b/src/Workspaces/Remote/ServiceHub/Services/RemoteHostService.cs
index cfd55bb4ce7bf..2be0887cd5c01 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/RemoteHostService.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/RemoteHostService.cs
@@ -57,7 +57,7 @@ static RemoteHostService()
base(serviceProvider, stream)
{
// this service provide a way for client to make sure remote host is alive
- Rpc.StartListening();
+ StartService();
}
public string Connect(string host, int uiCultureLCID, int cultureLCID, string serializedSession, CancellationToken cancellationToken)
diff --git a/src/Workspaces/Remote/ServiceHub/Services/RemoteSymbolSearchUpdateEngine.cs b/src/Workspaces/Remote/ServiceHub/Services/RemoteSymbolSearchUpdateEngine.cs
index 826e41da9fbcc..5bfb7639fe1fd 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/RemoteSymbolSearchUpdateEngine.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/RemoteSymbolSearchUpdateEngine.cs
@@ -21,7 +21,7 @@ public RemoteSymbolSearchUpdateEngine(Stream stream, IServiceProvider servicePro
_updateEngine = new SymbolSearchUpdateEngine(
logService: this, progressService: this);
- Rpc.StartListening();
+ StartService();
}
public Task UpdateContinuouslyAsync(string sourceName, string localSettingsDirectory)
@@ -68,22 +68,22 @@ public Task> FindReferenceAssembliesWithT
#region Messages to forward from here to VS
public Task LogExceptionAsync(string exception, string text)
- => this.Rpc.InvokeAsync(nameof(LogExceptionAsync), exception, text);
+ => this.InvokeAsync(nameof(LogExceptionAsync), new object[] { exception, text }, CancellationToken.None);
public Task LogInfoAsync(string text)
- => this.Rpc.InvokeAsync(nameof(LogInfoAsync), text);
+ => this.InvokeAsync(nameof(LogInfoAsync), new object[] { text }, CancellationToken.None);
public Task OnDownloadFullDatabaseStartedAsync(string title)
- => this.Rpc.InvokeAsync(nameof(OnDownloadFullDatabaseStartedAsync), title);
+ => this.InvokeAsync(nameof(OnDownloadFullDatabaseStartedAsync), new object[] { title }, CancellationToken.None);
public Task OnDownloadFullDatabaseSucceededAsync()
- => this.Rpc.InvokeAsync(nameof(OnDownloadFullDatabaseSucceededAsync));
+ => this.InvokeAsync(nameof(OnDownloadFullDatabaseSucceededAsync), CancellationToken.None);
public Task OnDownloadFullDatabaseCanceledAsync()
- => this.Rpc.InvokeAsync(nameof(OnDownloadFullDatabaseCanceledAsync));
+ => this.InvokeAsync(nameof(OnDownloadFullDatabaseCanceledAsync), CancellationToken.None);
public Task OnDownloadFullDatabaseFailedAsync(string message)
- => this.Rpc.InvokeAsync(nameof(OnDownloadFullDatabaseFailedAsync), message);
+ => this.InvokeAsync(nameof(OnDownloadFullDatabaseFailedAsync), new object[] { message }, CancellationToken.None);
#endregion
}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/SnapshotService.JsonRpcAssetSource.cs b/src/Workspaces/Remote/ServiceHub/Services/SnapshotService.JsonRpcAssetSource.cs
index 3d75f5852546a..96e2cfdd2492b 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/SnapshotService.JsonRpcAssetSource.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/SnapshotService.JsonRpcAssetSource.cs
@@ -38,7 +38,7 @@ public override async Task> RequestAssetsAsync(int sco
{
return await _owner.RunServiceAsync(cancellationToken =>
{
- return _owner.Rpc.InvokeAsync(WellKnownServiceHubServices.AssetService_RequestAssetAsync,
+ return _owner.InvokeAsync(WellKnownServiceHubServices.AssetService_RequestAssetAsync,
new object[] { scopeId, checksums.ToArray() },
(s, c) => ReadAssets(s, scopeId, checksums, serializerService, c), cancellationToken);
}, callerCancellation).ConfigureAwait(false);
@@ -52,8 +52,7 @@ public override async Task> RequestAssetsAsync(int sco
private bool ReportUnlessCanceled(Exception ex, CancellationToken cancellationToken)
{
- if (!cancellationToken.IsCancellationRequested &&
- ((IDisposableObservable)_owner.Rpc).IsDisposed)
+ if (!cancellationToken.IsCancellationRequested && _owner.IsDisposed)
{
// kill OOP if snapshot service got disconnected due to this exception.
FailFast.OnFatalException(ex);
diff --git a/src/Workspaces/Remote/ServiceHub/Services/SnapshotService.cs b/src/Workspaces/Remote/ServiceHub/Services/SnapshotService.cs
index 91a2743ffbef0..e87dba01ef6d1 100644
--- a/src/Workspaces/Remote/ServiceHub/Services/SnapshotService.cs
+++ b/src/Workspaces/Remote/ServiceHub/Services/SnapshotService.cs
@@ -19,7 +19,7 @@ internal partial class SnapshotService : ServiceHubServiceBase
{
_source = new JsonRpcAssetSource(this);
- Rpc.StartListening();
+ StartService();
}
}
}
diff --git a/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs b/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs
index 81f54cd5833f0..6b99cf5c825f5 100644
--- a/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs
+++ b/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
@@ -20,14 +21,17 @@ internal abstract class ServiceHubServiceBase : IDisposable
private static int s_instanceId;
private readonly CancellationTokenSource _shutdownCancellationSource;
+ private readonly JsonRpc _rpc;
protected readonly int InstanceId;
- protected readonly JsonRpc Rpc;
protected readonly TraceSource Logger;
protected readonly AssetStorage AssetStorage;
protected readonly CancellationToken ShutdownCancellationToken;
+ [Obsolete("don't use RPC directly but use it through StartService and InvokeAsync", error: true)]
+ protected readonly JsonRpc Rpc;
+
///
/// PinnedSolutionInfo.ScopeId. scope id of the solution. caller and callee share this id which one
/// can use to find matching caller and callee while exchanging data
@@ -62,9 +66,14 @@ protected ServiceHubServiceBase(IServiceProvider serviceProvider, Stream stream)
// due to this issue - https://github.com/dotnet/roslyn/issues/16900#issuecomment-277378950
// all sub type must explicitly start JsonRpc once everything is
// setup
- Rpc = new JsonRpc(new JsonRpcMessageHandler(stream, stream), this);
- Rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance);
- Rpc.Disconnected += OnRpcDisconnected;
+ _rpc = new JsonRpc(new JsonRpcMessageHandler(stream, stream), this);
+ _rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance);
+ _rpc.Disconnected += OnRpcDisconnected;
+
+ // we do this since we want to mark Rpc as obsolete but want to set its value for
+ // partner teams until they move. we can't use Rpc directly since we will get
+ // obsolete error and we can't suppress it since it is an error
+ this.GetType().GetField("Rpc", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, _rpc);
}
protected string DebugInstanceString => $"{GetType()} ({InstanceId})";
@@ -82,6 +91,37 @@ protected RoslynServices RoslynServices
}
}
+ protected bool IsDisposed => ((IDisposableObservable)_rpc).IsDisposed;
+
+ protected void StartService()
+ {
+ _rpc.StartListening();
+ }
+
+ protected Task InvokeAsync(
+ string targetName, IReadOnlyList