diff --git a/src/Analyzers/CSharp/Tests/RemoveUnnecessaryParentheses/RemoveUnnecessaryExpressionParenthesesTests.cs b/src/Analyzers/CSharp/Tests/RemoveUnnecessaryParentheses/RemoveUnnecessaryExpressionParenthesesTests.cs index be8d5e3e93685..36c6d019fa0b7 100644 --- a/src/Analyzers/CSharp/Tests/RemoveUnnecessaryParentheses/RemoveUnnecessaryExpressionParenthesesTests.cs +++ b/src/Analyzers/CSharp/Tests/RemoveUnnecessaryParentheses/RemoveUnnecessaryExpressionParenthesesTests.cs @@ -2,12 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.RemoveUnnecessaryParentheses; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics; @@ -2753,5 +2752,59 @@ public void M() } ", offeredWhenRequireForClarityIsEnabled: true); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)] + [WorkItem(45100, "https://github.com/dotnet/roslyn/issues/45100")] + public async Task TestArithmeticOverflow1() + { + await TestMissingAsync( +@"class C +{ + void M(int a) + { + checked + { + return a + $$(int.MaxValue + -int.MaxValue); + } + } +}", parameters: new TestParameters(options: RemoveAllUnnecessaryParentheses)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)] + [WorkItem(45100, "https://github.com/dotnet/roslyn/issues/45100")] + public async Task TestArithmeticOverflow1_CompilationOption() + { + await TestMissingAsync( +@"class C +{ + void M(int a) + { + return a + $$(int.MaxValue + -int.MaxValue); + } +}", parameters: new TestParameters( + options: RemoveAllUnnecessaryParentheses, + compilationOptions: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, checkOverflow: true))); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryParentheses)] + [WorkItem(45100, "https://github.com/dotnet/roslyn/issues/45100")] + public async Task TestArithmeticOverflow2() + { + await TestInRegularAndScript1Async( +@"class C +{ + void M(int a) + { + return a + $$(int.MaxValue + -int.MaxValue); + } +}", +@"class C +{ + void M(int a) + { + return a + int.MaxValue + -int.MaxValue; + } +}", parameters: new TestParameters(options: RemoveAllUnnecessaryParentheses)); + } } } diff --git a/src/Analyzers/VisualBasic/Tests/RemoveUnnecessaryParentheses/RemoveUnnecessaryParenthesesTests.vb b/src/Analyzers/VisualBasic/Tests/RemoveUnnecessaryParentheses/RemoveUnnecessaryParenthesesTests.vb index aef3c3af53a18..35038621ed8a5 100644 --- a/src/Analyzers/VisualBasic/Tests/RemoveUnnecessaryParentheses/RemoveUnnecessaryParenthesesTests.vb +++ b/src/Analyzers/VisualBasic/Tests/RemoveUnnecessaryParentheses/RemoveUnnecessaryParenthesesTests.vb @@ -18,6 +18,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.RemoveUnnecessaryP Partial Public Class RemoveUnnecessaryParenthesesTests Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest + Private Shared ReadOnly CheckOverflow As CompilationOptions = New VisualBasicCompilationOptions(OutputKind.ConsoleApplication, checkOverflow:=True) + Private Shared ReadOnly DoNotCheckOverflow As CompilationOptions = New VisualBasicCompilationOptions(OutputKind.ConsoleApplication, checkOverflow:=False) + Friend Overrides Function CreateDiagnosticProviderAndFixer(Workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider) Return (New VisualBasicRemoveUnnecessaryParenthesesDiagnosticAnalyzer(), New VisualBasicRemoveUnnecessaryParenthesesCodeFixProvider()) End Function @@ -32,13 +35,18 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.RemoveUnnecessaryP Private Shadows Async Function TestAsync(initial As String, expected As String, offeredWhenRequireAllParenthesesForClarityIsEnabled As Boolean, - Optional ByVal index As Integer = 0) As Task - Await TestInRegularAndScriptAsync(initial, expected, options:=RemoveAllUnnecessaryParentheses, index:=index) + Optional index As Integer = 0, + Optional checkOverflow As Boolean = True) As Task + Dim compilationOptions = If(checkOverflow, + RemoveUnnecessaryParenthesesTests.CheckOverflow, + RemoveUnnecessaryParenthesesTests.DoNotCheckOverflow) + + Await TestInRegularAndScriptAsync(initial, expected, options:=RemoveAllUnnecessaryParentheses, index:=index, compilationOptions:=compilationOptions) If (offeredWhenRequireAllParenthesesForClarityIsEnabled) Then - Await TestInRegularAndScriptAsync(initial, expected, options:=MyBase.RequireAllParenthesesForClarity, index:=index) + Await TestInRegularAndScriptAsync(initial, expected, options:=RequireAllParenthesesForClarity, index:=index, compilationOptions:=compilationOptions) Else - Await TestMissingAsync(initial, parameters:=New TestParameters(options:=MyBase.RequireAllParenthesesForClarity)) + Await TestMissingAsync(initial, parameters:=New TestParameters(options:=RequireAllParenthesesForClarity, compilationOptions:=compilationOptions)) End If End Function @@ -114,7 +122,7 @@ end class", parameters:=New TestParameters(options:=RequireOtherBinaryParenthese End Function - Public Async Function TestArithmeticNotRequiredForClarityWhenPrecedenceStaysTheSame1() As Task + Public Async Function TestArithmeticNotRequiredForClarityWhenPrecedenceStaysTheSame1_DoNotCheckOverflow() As Task Await TestAsync( "class C sub M() @@ -125,7 +133,17 @@ end class", sub M() dim x = 1 + 2 + 3 end sub -end class", offeredWhenRequireAllParenthesesForClarityIsEnabled:=True) +end class", offeredWhenRequireAllParenthesesForClarityIsEnabled:=True, checkOverflow:=False) + End Function + + + Public Async Function TestArithmeticNotRequiredForClarityWhenPrecedenceStaysTheSame1_CheckOverflow() As Task + Await TestMissingAsync( +"class C + sub M() + dim x = 1 + $$(2 + 3) + end sub +end class", New TestParameters(options:=RequireArithmeticBinaryParenthesesForClarity)) End Function @@ -587,7 +605,7 @@ end class", New TestParameters(options:=RemoveAllUnnecessaryParentheses), firstL - Public Async Function TestUnnecessaryParenthesisDiagnosticInNestedExpression() As Task + Public Async Function TestUnnecessaryParenthesisDiagnosticInNestedExpression_DoNotCheckOverflow() As Task Dim outerParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(1 + (2 + 3) + 4)", 2, 16) Dim innerParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(2 + 3)", 2, 21) Dim expectedDiagnostics = New DiagnosticDescription() {outerParentheticalExpressionDiagnostic, innerParentheticalExpressionDiagnostic} @@ -596,12 +614,12 @@ end class", New TestParameters(options:=RemoveAllUnnecessaryParentheses), firstL sub M() dim x = [|(1 + (2 + 3) + 4)|] end sub -end class", New TestParameters(options:=RemoveAllUnnecessaryParentheses), expectedDiagnostics) +end class", New TestParameters(options:=RemoveAllUnnecessaryParentheses, compilationOptions:=DoNotCheckOverflow), expectedDiagnostics) End Function - Public Async Function TestUnnecessaryParenthesisDiagnosticInNestedMultiLineExpression() As Task + Public Async Function TestUnnecessaryParenthesisDiagnosticInNestedMultiLineExpression_DoNotCheckOverflow() As Task Dim outerFirstLineParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(1 + 2 +", 2, 16) Dim innerParentheticalExpressionDiagnostic = GetRemoveUnnecessaryParenthesesDiagnostic("(3 + 4)", 3, 12) Dim expectedDiagnostics = New DiagnosticDescription() {outerFirstLineParentheticalExpressionDiagnostic, innerParentheticalExpressionDiagnostic} @@ -612,7 +630,7 @@ end class", New TestParameters(options:=RemoveAllUnnecessaryParentheses), expect (3 + 4) + 5 + 6)|] end sub -end class", New TestParameters(options:=RemoveAllUnnecessaryParentheses), expectedDiagnostics) +end class", New TestParameters(options:=RemoveAllUnnecessaryParentheses, compilationOptions:=DoNotCheckOverflow), expectedDiagnostics) End Function diff --git a/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs index 3d4cfb7b8e9fc..45ff92a6ef52f 100644 --- a/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/AbstractCodeGenerationTests.cs @@ -2,19 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; using System.Linq; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.VisualBasic.Syntax; -using Microsoft.VisualStudio.Composition; -using Microsoft.VisualStudio.LanguageServices; using Roslyn.Test.Utilities; using Xunit; @@ -31,18 +28,19 @@ private static SyntaxNode Simplify( var projectId = ProjectId.CreateNewId(); var project = workspace.CurrentSolution - .AddProject(projectId, languageName, $"{languageName}.dll", languageName).GetProject(projectId); + .AddProject(projectId, languageName, $"{languageName}.dll", languageName).GetRequiredProject(projectId); var normalizedSyntax = syntaxNode.NormalizeWhitespace().ToFullString(); var document = project.AddMetadataReference(TestMetadata.Net451.mscorlib) .AddDocument("Fake Document", SourceText.From(normalizedSyntax)); + var root = document.GetRequiredSyntaxRootAsync(default).AsTask().Result; var annotatedDocument = document.WithSyntaxRoot( - document.GetSyntaxRootAsync().Result.WithAdditionalAnnotations(Simplification.Simplifier.Annotation)); + root.WithAdditionalAnnotations(Simplifier.Annotation)); - var simplifiedDocument = Simplification.Simplifier.ReduceAsync(annotatedDocument).Result; + var simplifiedDocument = Simplifier.ReduceAsync(annotatedDocument).Result; - var rootNode = simplifiedDocument.GetSyntaxRootAsync().Result; + var rootNode = simplifiedDocument.GetRequiredSyntaxRootAsync(default).AsTask().Result; return rootNode; } @@ -78,7 +76,7 @@ internal static void Test( if (cs != null || csSimple != null) { - var codeDefFactory = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetService(); + var codeDefFactory = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(); var node = nodeCreator(codeDefFactory); node = node.NormalizeWhitespace(); @@ -99,7 +97,7 @@ internal static void Test( if (vb != null || vbSimple != null) { - var codeDefFactory = workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetService(); + var codeDefFactory = workspace.Services.GetLanguageServices(LanguageNames.VisualBasic).GetRequiredService(); var node = nodeCreator(codeDefFactory); node = node.NormalizeWhitespace(); diff --git a/src/EditorFeatures/Test/CodeGeneration/ExpressionGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/ExpressionGenerationTests.cs index 6bdc4a7d09052..e66fa8db8dc54 100644 --- a/src/EditorFeatures/Test/CodeGeneration/ExpressionGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/ExpressionGenerationTests.cs @@ -181,7 +181,7 @@ public void TestAddExpression2() cs: "(1) + ((2) + (3))", csSimple: "1 + 2 + 3", vb: "(1) + ((2) + (3))", - vbSimple: "1 + 2 + 3"); + vbSimple: "1 + (2 + 3)"); } [Fact] @@ -224,7 +224,7 @@ public void TestMultiplyExpression2() cs: "(1) * ((2) * (3))", csSimple: "1 * 2 * 3", vb: "(1) * ((2) * (3))", - vbSimple: "1 * 2 * 3"); + vbSimple: "1 * (2 * 3)"); } [Fact] diff --git a/src/Workspaces/Core/Portable/LanguageServices/SemanticsFactsService/SemanticFacts/AbstractSemanticFactsService.cs b/src/Workspaces/Core/Portable/LanguageServices/SemanticsFactsService/SemanticFacts/AbstractSemanticFactsService.cs index 84e3deba94334..b0714fea6e221 100644 --- a/src/Workspaces/Core/Portable/LanguageServices/SemanticsFactsService/SemanticFacts/AbstractSemanticFactsService.cs +++ b/src/Workspaces/Core/Portable/LanguageServices/SemanticsFactsService/SemanticFacts/AbstractSemanticFactsService.cs @@ -2,8 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - +using System; using System.Threading; namespace Microsoft.CodeAnalysis.LanguageServices diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs index 48a0ec4e07548..a9c212b8901e4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ParenthesizedExpressionSyntaxExtensions.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Extensions; +using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; @@ -414,12 +414,11 @@ private static bool RemovalChangesAssociation( // 3) for logical operators the result will always be the same (there are // additional conditions that are checked for non-logical operators). if (IsAssociative(parentBinaryExpression.Kind()) && - node.Expression.Kind() == parentBinaryExpression.Kind() && - parentBinaryExpression.Right == node) + parentBinaryExpression.Right == node && + node.Expression.IsKind(parentBinaryExpression.Kind(), out BinaryExpressionSyntax? nodeBinary)) { - return !node.IsSafeToChangeAssociativity( - node.Expression, parentBinaryExpression.Left, - parentBinaryExpression.Right, semanticModel); + return !CSharpSemanticFacts.Instance.IsSafeToChangeAssociativity( + nodeBinary, parentBinaryExpression, semanticModel); } // Null-coalescing is right associative; removing parens from the LHS changes the association. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs index 7c30407135668..01ff486109918 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs @@ -30,6 +30,8 @@ private CSharpSemanticFacts() { } + public ISyntaxFacts SyntaxFacts => CSharpSyntaxFacts.Instance; + public bool SupportsImplicitInterfaceImplementation => true; public bool ExposesAnonymousFunctionParameterNames => false; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index 880b5a12e6adc..6fb74a6ed131d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -253,7 +253,6 @@ - @@ -377,6 +376,7 @@ + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ISemanticFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ISemanticFacts.cs index 6da22448b8798..08ddd7f64044e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ISemanticFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ISemanticFacts.cs @@ -13,6 +13,8 @@ namespace Microsoft.CodeAnalysis.LanguageServices { internal partial interface ISemanticFacts { + ISyntaxFacts SyntaxFacts { get; } + /// /// True if this language supports implementing an interface by signature only. If false, /// implementations must specific explicitly which symbol they're implementing. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ParenthesizedExpressionSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ISemanticFactsExtensions.cs similarity index 66% rename from src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ParenthesizedExpressionSyntaxExtensions.cs rename to src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ISemanticFactsExtensions.cs index 5017a6949d13d..d996546ccd1dd 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ParenthesizedExpressionSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Services/SemanticFacts/ISemanticFactsExtensions.cs @@ -3,14 +3,18 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.Operations; -namespace Microsoft.CodeAnalysis.Extensions +namespace Microsoft.CodeAnalysis.LanguageServices { - internal static class CommonParenthesizedExpressionSyntaxExtensions + internal static class ISemanticFactsExtensions { - public static bool IsSafeToChangeAssociativity( - this SyntaxNode parenthesizedExpression, SyntaxNode innerExpression, - SyntaxNode parentBinaryLeft, SyntaxNode parentBinaryRight, SemanticModel semanticModel) + public static bool IsSafeToChangeAssociativity( + this ISemanticFacts semanticFacts, + TBinaryExpressionSyntax innerBinary, + TBinaryExpressionSyntax parentBinary, + SemanticModel semanticModel) + where TBinaryExpressionSyntax : SyntaxNode { // Now we'll perform a few semantic checks to determine whether removal // of the parentheses might break semantics. Note that we'll try and be @@ -21,28 +25,24 @@ public static bool IsSafeToChangeAssociativity( // First, does the binary expression result in an operator overload being // called? - var symbolInfo = semanticModel.GetSymbolInfo(innerExpression); + var symbolInfo = semanticModel.GetSymbolInfo(innerBinary); if (AnySymbolIsUserDefinedOperator(symbolInfo)) - { return false; - } // Second, check the type and converted type of the binary expression. // Are they the same? - var innerTypeInfo = semanticModel.GetTypeInfo(innerExpression); + var innerTypeInfo = semanticModel.GetTypeInfo(innerBinary); if (innerTypeInfo.Type != null && innerTypeInfo.ConvertedType != null) { if (!innerTypeInfo.Type.Equals(innerTypeInfo.ConvertedType)) - { return false; - } } // It's not safe to change associativity for dynamic variables as the actual type isn't known. See https://github.com/dotnet/roslyn/issues/47365 if (innerTypeInfo.Type is IDynamicTypeSymbol) - { return false; - } + + semanticFacts.SyntaxFacts.GetPartsOfBinaryExpression(parentBinary, out var parentBinaryLeft, out var parentBinaryRight); // Only allow us to change associativity if all the types are the same. // for example, if we have: int + (int + long) then we don't want to @@ -59,23 +59,34 @@ public static bool IsSafeToChangeAssociativity( return false; } - // Floating point is not safe to change associativity of. For example, - // if the user has "large * (large * small)" then this will become - // "(large * large) * small. And that could easily overflow to Inf (and - // other badness). - var parentBinary = parenthesizedExpression.Parent; - if (parentBinary is null) - { - return false; - } - + // Floating point is not safe to change associativity of. For example, if the user has "large * (large * + // small)" then this will become "(large * large) * small. And that could easily overflow to Inf (and other + // badness). var outerTypeInfo = semanticModel.GetTypeInfo(parentBinary); if (IsFloatingPoint(innerTypeInfo) || IsFloatingPoint(outerTypeInfo)) - { return false; + + if (semanticModel.GetOperation(parentBinary) is IBinaryOperation parentBinaryOp && + semanticModel.GetOperation(innerBinary) is IBinaryOperation innerBinaryOp) + { + if ((parentBinaryOp.IsChecked || innerBinaryOp.IsChecked) && + (IsArithmetic(parentBinaryOp) || IsArithmetic(innerBinaryOp))) + { + // For checked operations, we can't change which type of operator we're performing in a row as that + // could lead to overflow if we end up doing something like an addition prior to a subtraction. + return false; + } } return true; + + static bool IsArithmetic(IBinaryOperation op) + { + return op.OperatorKind is BinaryOperatorKind.Add or + BinaryOperatorKind.Subtract or + BinaryOperatorKind.Multiply or + BinaryOperatorKind.Divide; + } } private static bool AnySymbolIsUserDefinedOperator(SymbolInfo symbolInfo) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/ParenthesizedExpressionSyntaxExtensions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/ParenthesizedExpressionSyntaxExtensions.vb index 062eb6c0b5da6..cf067ef59aba4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/ParenthesizedExpressionSyntaxExtensions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Extensions/ParenthesizedExpressionSyntaxExtensions.vb @@ -4,7 +4,7 @@ Imports System.Runtime.CompilerServices Imports System.Threading -Imports Microsoft.CodeAnalysis.Extensions +Imports Microsoft.CodeAnalysis.LanguageServices Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions @@ -397,9 +397,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions If IsAssociative(parentBinaryExpression.Kind) AndAlso expression.Kind = parentExpression.Kind Then - Return node.IsSafeToChangeAssociativity( - node.Expression, parentBinaryExpression.Left, - parentBinaryExpression.Right, semanticModel) + Return VisualBasicSemanticFacts.Instance.IsSafeToChangeAssociativity( + binaryExpression, parentBinaryExpression, semanticModel) End If End If diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb index ded95e302ab56..dd0df2b375c6f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb @@ -19,6 +19,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Private Sub New() End Sub + Public ReadOnly Property SyntaxFacts As ISyntaxFacts Implements ISemanticFacts.SyntaxFacts + Get + Return VisualBasicSyntaxFacts.Instance + End Get + End Property + Public ReadOnly Property SupportsImplicitInterfaceImplementation As Boolean Implements ISemanticFacts.SupportsImplicitInterfaceImplementation Get Return False diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsService.cs index 9e0299091bcf9..8522643d5e697 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/LanguageServices/CSharpSemanticFactsService.cs @@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.LanguageServices; -using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Operations; @@ -24,7 +23,7 @@ internal sealed partial class CSharpSemanticFactsService : AbstractSemanticFacts { internal static readonly CSharpSemanticFactsService Instance = new(); - protected override ISyntaxFacts SyntaxFacts => CSharpSyntaxFacts.Instance; + public override ISyntaxFacts SyntaxFacts => CSharpSyntaxFacts.Instance; protected override ISemanticFacts SemanticFacts => CSharpSemanticFacts.Instance; private CSharpSemanticFactsService() diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SemanticsFactsService/AbstractSemanticFactsService.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SemanticsFactsService/AbstractSemanticFactsService.cs index 7f02fc0730b34..9269cc53c7ac0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SemanticsFactsService/AbstractSemanticFactsService.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/LanguageServices/SemanticsFactsService/AbstractSemanticFactsService.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.LanguageServices { internal abstract partial class AbstractSemanticFactsService : ISemanticFacts { - protected abstract ISyntaxFacts SyntaxFacts { get; } + public abstract ISyntaxFacts SyntaxFacts { get; } protected abstract ISemanticFacts SemanticFacts { get; } protected abstract SyntaxToken ToIdentifierToken(string identifier); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSemanticFactsService.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSemanticFactsService.vb index 5bee2fee605dc..9a94724fdd35f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSemanticFactsService.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/LanguageServices/VisualBasicSemanticFactsService.vb @@ -33,7 +33,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Shared ReadOnly Instance As New VisualBasicSemanticFactsService() - Protected Overrides ReadOnly Property SyntaxFacts As ISyntaxFacts = VisualBasicSyntaxFacts.Instance + Public Overrides ReadOnly Property SyntaxFacts As ISyntaxFacts = VisualBasicSyntaxFacts.Instance Protected Overrides ReadOnly Property SemanticFacts As ISemanticFacts = VisualBasicSemanticFacts.Instance Private Sub New()