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 arguments, CancellationToken cancellationToken) + { + return _rpc.InvokeWithCancellationAsync(targetName, arguments, cancellationToken); + } + + protected Task InvokeAsync( + string targetName, IReadOnlyList arguments, + Func funcWithDirectStream, CancellationToken cancellationToken) + { + return Extensions.InvokeAsync(_rpc, targetName, arguments, funcWithDirectStream, cancellationToken); + } + + protected Task InvokeAsync(string targetName, CancellationToken cancellationToken) + { + return InvokeAsync(targetName, SpecializedCollections.EmptyReadOnlyList(), cancellationToken); + } + + protected Task InvokeAsync( + string targetName, IReadOnlyList arguments, CancellationToken cancellationToken) + { + return _rpc.InvokeWithCancellationAsync(targetName, arguments, cancellationToken); + } + protected Task GetSolutionAsync(CancellationToken cancellationToken) { Contract.ThrowIfNull(_solutionInfo); @@ -123,7 +163,7 @@ public void Dispose() } _disposed = true; - Rpc.Dispose(); + _rpc.Dispose(); _shutdownCancellationSource.Dispose(); Dispose(disposing: true); diff --git a/src/Workspaces/VisualBasic/Portable/Rename/VisualBasicRenameRewriterLanguageService.vb b/src/Workspaces/VisualBasic/Portable/Rename/VisualBasicRenameRewriterLanguageService.vb index 27357f7fffeeb..c87350d524c43 100644 --- a/src/Workspaces/VisualBasic/Portable/Rename/VisualBasicRenameRewriterLanguageService.vb +++ b/src/Workspaces/VisualBasic/Portable/Rename/VisualBasicRenameRewriterLanguageService.vb @@ -731,6 +731,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Rename .Select(Function(loc) reverseMappedLocations(loc))) ElseIf renamedSymbol.Kind = SymbolKind.Property Then + conflicts.AddRange( + DeclarationConflictHelpers.GetMembersWithConflictingSignatures(DirectCast(renamedSymbol, IPropertySymbol), trimOptionalParameters:=True) _ + .Select(Function(loc) reverseMappedLocations(loc))) ConflictResolver.AddConflictingParametersOfProperties( referencedSymbols.Select(Function(s) s.Symbol).Concat(renameSymbol).Where(Function(sym) sym.Kind = SymbolKind.Property), renamedSymbol.Name,