diff --git a/.editorconfig b/.editorconfig index 3a08978605e93..9dbed4dade131 100644 --- a/.editorconfig +++ b/.editorconfig @@ -163,6 +163,9 @@ dotnet_diagnostic.IDE0043.severity = warning # IDE0044: Make field readonly dotnet_diagnostic.IDE0044.severity = warning +# IDE0170: Prefer extended property pattern +dotnet_diagnostic.IDE0170.severity = warning + # RS0016: Only enable if API files are present dotnet_public_api_analyzer.require_api_files = true @@ -211,6 +214,7 @@ csharp_style_pattern_matching_over_as_with_null_check = true:suggestion csharp_style_inlined_variable_declaration = true:suggestion csharp_style_throw_expression = true:suggestion csharp_style_conditional_delegate_call = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion # Space preferences csharp_space_after_cast = false diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md index fb013cd155c2b..2ce5dee119dbf 100644 --- a/docs/Language Feature Status.md +++ b/docs/Language Feature Status.md @@ -19,7 +19,8 @@ efforts behind them. | [Parameter null-checking](https://github.com/dotnet/csharplang/issues/2145) | [param-nullchecking](https://github.com/dotnet/roslyn/tree/features/param-nullchecking) | [Merged in 17.1p3](https://github.com/dotnet/roslyn/issues/36024) | [RikkiGibson](https://github.com/RikkiGibson), [fayrose](https://github.com/fayrose) | [cston](https://github.com/cston), [chsienki](https://github.com/chsienki) | [jaredpar](https://github.com/jaredpar) | | [Raw string literals](https://github.com/dotnet/csharplang/issues/4304) | [RawStringLiterals](https://github.com/dotnet/roslyn/tree/features/RawStringLiterals) | [Merged into 17.2](https://github.com/dotnet/roslyn/issues/55306) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | | [Cache delegates for static method group](https://github.com/dotnet/roslyn/issues/5835) | main | [Merged into 17.2](https://github.com/dotnet/roslyn/pull/58288) | [pawchen](https://github.com/pawchen) | [AlekseyTs](https://github.com/AlekseyTs), [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs) | -| [nameof(parameter)](https://github.com/dotnet/csharplang/issues/373) | main | [In Progress](https://github.com/dotnet/roslyn/issues/40524) | [jcouv](https://github.com/jcouv) | TBD | [jcouv](https://github.com/jcouv) | +| [nameof(parameter)](https://github.com/dotnet/csharplang/issues/373) | main | [Merged into 17.3p2](https://github.com/dotnet/roslyn/issues/40524) | [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs), [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv) | +| [Relaxing Shift Operator](https://github.com/dotnet/csharplang/issues/4666) | main | [Merged into 17.3p2](https://github.com/dotnet/roslyn/issues/60967) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [jcouv](https://github.com/jcouv) | [MadsTorgersen](https://github.com/MadsTorgersen) | | [Relax ordering of `ref` and `partial` modifiers](https://github.com/dotnet/csharplang/issues/946) | [ref-partial](https://github.com/dotnet/roslyn/tree/features/ref-partial) | In Progress | [alrz](https://github.com/alrz) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) | | [Generic attributes](https://github.com/dotnet/csharplang/issues/124) | [generic-attributes](https://github.com/dotnet/roslyn/tree/features/generic-attributes) | [Merged into 17.0p4 (preview langver)](https://github.com/dotnet/roslyn/issues/36285) | [AviAvni](https://github.com/AviAvni) | [RikkiGibson](https://github.com/RikkiGibson), [jcouv](https://github.com/jcouv) | [mattwar](https://github.com/mattwar) | | [Default in deconstruction](https://github.com/dotnet/roslyn/pull/25562) | [decon-default](https://github.com/dotnet/roslyn/tree/features/decon-default) | [Implemented](https://github.com/dotnet/roslyn/issues/25559) | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) | @@ -31,8 +32,9 @@ efforts behind them. | [Pattern matching on `ReadOnlySpan`](https://github.com/dotnet/csharplang/issues/1881) | [patterns-span-char](https://github.com/dotnet/roslyn/tree/features/patterns-span-char) | [Merged into 17.3p1](https://github.com/dotnet/roslyn/issues/59191) | [YairHalberstadt ](https://github.com/YairHalberstadt) | [cston](https://github.com/cston), [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv) | | [nameof accessing instance members](https://github.com/dotnet/roslyn/issues/40229) | main | [In Progress](https://github.com/dotnet/roslyn/pull/48754) | [YairHalberstadt ](https://github.com/YairHalberstadt) | [333fred](https://github.com/333fred), [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred) | | [ref fields](https://github.com/dotnet/csharplang/blob/main/proposals/low-level-struct-improvements.md) | [ref-fields](https://github.com/dotnet/roslyn/tree/features/ref-fields) | [In Progress](https://github.com/dotnet/roslyn/issues/59194) | [cston](https://github.com/cston) | [RikkiGibson](https://github.com/RikkiGibson), [AlekseyTs](https://github.com/AlekseyTs) | [jaredpar](https://github.com/jaredpar) | -| Numeric IntPtr | [numeric-intptr](https://github.com/dotnet/roslyn/tree/features/numeric-intptr) | [In Progress](https://github.com/dotnet/roslyn/issues/60578) | [jcouv](https://github.com/jcouv) | TBD | [jcouv](https://github.com/jcouv) | +| [Numeric IntPtr](https://github.com/dotnet/csharplang/issues/6065) | [numeric-intptr](https://github.com/dotnet/roslyn/tree/features/numeric-intptr) | [In Progress](https://github.com/dotnet/roslyn/issues/60578) | [jcouv](https://github.com/jcouv) | [cston](https://github.com/cston), [333fred](https://github.com/333fred) | [jcouv](https://github.com/jcouv) | | [File types](https://github.com/dotnet/csharplang/issues/6011) | [file-types](https://github.com/dotnet/roslyn/tree/features/file-types) | [In Progress](https://github.com/dotnet/roslyn/issues/60819) | [RikkiGibson](https://github.com/RikkiGibson) | [333fred](https://github.com/333fred), [cston](https://github.com/cston) | [stephentoub](https://github.com/stephentoub) | +| [DIM for Static Members](https://github.com/dotnet/csharplang/issues/4436) | [DefaultInterfaceImplementation](https://github.com/dotnet/roslyn/tree/features/DefaultInterfaceImplementation) | [In Progress](https://github.com/dotnet/roslyn/issues/60968) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [jcouv](https://github.com/jcouv) | [MadsTorgersen](https://github.com/MadsTorgersen) | # C# 10.0 diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md index 852c70f182f6b..6ef16fbdca75a 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md @@ -1,5 +1,50 @@ # This document lists known breaking changes in Roslyn after .NET 6 all the way to .NET 7. +## Nameof operator in attribute on method or local function + +***Introduced in .NET SDK 7.0.400, Visual Studio 2022 version 17.3.*** + +When the language version is C# 11 or later, a `nameof` operator in an attribute on a method +brings the type parameters of that method in scope. The same applies for local functions. +A `nameof` operator in an attribute on a method, its type parameters or parameters brings +the parameters of that method in scope. The same applies to local functions, lambdas, +delegates and indexers. + +For instance, these will now be errors: +```csharp +class C +{ + class TParameter + { + internal const string Constant = """"; + } + [MyAttribute(nameof(TParameter.Constant))] + void M() { } +} +``` + +```csharp +class C +{ + class parameter + { + internal const string Constant = """"; + } + [MyAttribute(nameof(parameter.Constant))] + void M(int parameter) { } +} +``` + +Possible workarounds are: + +1. Rename the type parameter or parameter to avoid shadowing the name from outer scope. +1. Use a string literal instead of the `nameof` operator. +1. Downgrade the `` element to 9.0 or earlier. + +Note: The break will also apply to C# 10 and earlier when .NET 7 ships, but is +currently scoped down to users of LangVer=preview. +Tracked by https://github.com/dotnet/roslyn/issues/60640 + ## Unsigned right shift operator ***Introduced in .NET SDK 6.0.400, Visual Studio 2022 version 17.3.*** diff --git a/docs/features/source-generators.cookbook.md b/docs/features/source-generators.cookbook.md index e5e8a79626a46..dc390d986c3ea 100644 --- a/docs/features/source-generators.cookbook.md +++ b/docs/features/source-generators.cookbook.md @@ -686,7 +686,7 @@ using VerifyCS = CSharpSourceGeneratorVerifier; And use the following in your test method: ```csharp -var code = "initial code" +var code = "initial code"; var generated = "expected generated code"; await new VerifyCS.Test { diff --git a/eng/build.ps1 b/eng/build.ps1 index 8cb1c38bab99d..6a27f139c80ac 100644 --- a/eng/build.ps1 +++ b/eng/build.ps1 @@ -471,7 +471,7 @@ function TestUsingRunTests() { } if ($lspEditor) { - $lspLogs = Join-Path $TempDir "VisualStudio\LSP" + $lspLogs = Join-Path $TempDir "VSLogs" $telemetryLog = Join-Path $TempDir "VSTelemetryLog" if (Test-Path $lspLogs) { Write-Host "Copying LSP logs to $LogDir" diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json index fbc799f85b436..c76bc4b79c4b8 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -123,6 +123,7 @@ "channels": [], "vsBranch": "rel/d17.3", "vsMajorVersion": 17, + "insertionCreateDraftPR": true, "insertionTitlePrefix": "[d17.3p1]" }, "main": { @@ -132,7 +133,6 @@ ], "vsBranch": "main", "vsMajorVersion": 17, - "insertionCreateDraftPR": false, "insertionTitlePrefix": "[d17.3p2]" } } diff --git a/eng/publish-assets.ps1 b/eng/publish-assets.ps1 index 076294417533b..db7f382c42624 100644 --- a/eng/publish-assets.ps1 +++ b/eng/publish-assets.ps1 @@ -36,11 +36,23 @@ function Publish-Nuget($publishData, [string]$packageDir) { try { # Retrieve the feed name to source mapping. $feedData = GetFeedPublishData + + # Let packageFeeds default to the default set of feeds + $packageFeeds = "default" + if ($publishData.PSobject.Properties.Name -contains "packageFeeds") { + $packageFeeds = $publishData.packageFeeds + } + + # If the configured packageFeeds is arcade, then skip publishing here. Arcade will handle publishing packages to their feeds. + if ($packageFeeds.equals("arcade")) { + Write-Host " Skipping publishing for all packages as they will be published by arcade" + continue + } # Let packageFeeds default to the default set of feeds - $packageFees = $publishData.packageFeeds - if (!$packageFeeds) { - $packageFeeds = "default" + $packageFeeds = "default" + if ($publishData.PSobject.Properties.Name -contains "packageFeeds") { + $packageFeeds = $publishData.packageFeeds } # If the configured packageFeeds is arcade, then skip publishing here. Arcade will handle publishing packages to their feeds. diff --git a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems index 60ed46390e5cd..ae97995d350bd 100644 --- a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems +++ b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems @@ -125,6 +125,7 @@ + diff --git a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx index ebbc461b8bf34..929b1b576d6ef 100644 --- a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx +++ b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx @@ -365,4 +365,10 @@ Convert to top-level statements + + Convert to UTF-8 string literal + + + Use UTF-8 string literal + \ No newline at end of file diff --git a/src/Analyzers/CSharp/Analyzers/SimplifyPropertyPattern/SimplifyPropertyPatternHelpers.cs b/src/Analyzers/CSharp/Analyzers/SimplifyPropertyPattern/SimplifyPropertyPatternHelpers.cs index 1df92a51ae7b3..388276ad945cd 100644 --- a/src/Analyzers/CSharp/Analyzers/SimplifyPropertyPattern/SimplifyPropertyPatternHelpers.cs +++ b/src/Analyzers/CSharp/Analyzers/SimplifyPropertyPattern/SimplifyPropertyPatternHelpers.cs @@ -30,7 +30,7 @@ public static bool IsSimplifiable( Type: null, PositionalPatternClause: null, Designation: null, - PropertyPatternClause: { Subpatterns: { Count: 1 } subpatterns } + PropertyPatternClause.Subpatterns: { Count: 1 } subpatterns } } && subpatterns[0] is { ExpressionColon: { } inner } && diff --git a/src/Analyzers/CSharp/Analyzers/UsePatternCombinators/CSharpUsePatternCombinatorsAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UsePatternCombinators/CSharpUsePatternCombinatorsAnalyzer.cs index f915fa2dd5d4f..0fc5ec3a5e484 100644 --- a/src/Analyzers/CSharp/Analyzers/UsePatternCombinators/CSharpUsePatternCombinatorsAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UsePatternCombinators/CSharpUsePatternCombinatorsAnalyzer.cs @@ -62,7 +62,7 @@ private enum ConstantResult case IIsTypeOperation { Syntax: BinaryExpressionSyntax binaryExpression } op: return Type.TryCreate(binaryExpression, op); - case IIsPatternOperation { Pattern: { Syntax: PatternSyntax pattern } } op: + case IIsPatternOperation { Pattern.Syntax: PatternSyntax pattern } op: return new Source(pattern, op.Value); case IParenthesizedOperation op: diff --git a/src/Analyzers/CSharp/Analyzers/UseUTF8StringLiteral/UseUTF8StringLiteralDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseUTF8StringLiteral/UseUTF8StringLiteralDiagnosticAnalyzer.cs new file mode 100644 index 0000000000000..392cb91c74b0a --- /dev/null +++ b/src/Analyzers/CSharp/Analyzers/UseUTF8StringLiteral/UseUTF8StringLiteralDiagnosticAnalyzer.cs @@ -0,0 +1,199 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.UseUTF8StringLiteral +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + internal sealed class UseUTF8StringLiteralDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer + { + public enum ArrayCreationOperationLocation + { + Ancestors, + Descendants, + Current + } + + public UseUTF8StringLiteralDiagnosticAnalyzer() + : base(IDEDiagnosticIds.UseUTF8StringLiteralDiagnosticId, + EnforceOnBuildValues.UseUTF8StringLiteral, + CSharpCodeStyleOptions.PreferUTF8StringLiterals, + LanguageNames.CSharp, + new LocalizableResourceString(nameof(CSharpAnalyzersResources.Convert_to_UTF8_string_literal), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources)), + new LocalizableResourceString(nameof(CSharpAnalyzersResources.Use_UTF8_string_literal), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources))) + { + } + + public override DiagnosticAnalyzerCategory GetAnalyzerCategory() + => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; + + protected override void InitializeWorker(AnalysisContext context) + => context.RegisterCompilationStartAction(context => + { + if (!context.Compilation.LanguageVersion().IsCSharp11OrAbove()) + return; + + var expressionType = context.Compilation.GetTypeByMetadataName(typeof(System.Linq.Expressions.Expression<>).FullName!); + + context.RegisterOperationAction(c => AnalyzeOperation(c, expressionType), OperationKind.ArrayCreation); + }); + + private void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol? expressionType) + { + var arrayCreationOperation = (IArrayCreationOperation)context.Operation; + + // Don't offer if the user doesn't want it + var option = context.GetOption(CSharpCodeStyleOptions.PreferUTF8StringLiterals); + if (!option.Value) + return; + + // Only replace arrays with initializers + if (arrayCreationOperation.Initializer is null) + return; + + // Using UTF8 string literals as nested array initializers is invalid + if (arrayCreationOperation.DimensionSizes.Length > 1) + return; + + // Must be a byte array + if (arrayCreationOperation.Type is not IArrayTypeSymbol { ElementType.SpecialType: SpecialType.System_Byte }) + return; + + // UTF8 strings are not valid to use in attributes + if (arrayCreationOperation.Syntax.Ancestors().OfType().Any()) + return; + + // Can't use a UTF8 string inside an expression tree. + var semanticModel = context.Operation.SemanticModel; + Contract.ThrowIfNull(semanticModel); + if (arrayCreationOperation.Syntax.IsInExpressionTree(semanticModel, expressionType, context.CancellationToken)) + return; + + var elements = arrayCreationOperation.Initializer.ElementValues; + + // If the compiler has constructed this array creation, then we don't want to do anything + // if there aren't any elements, as we could just end up inserting ""u8 somewhere. + if (arrayCreationOperation.IsImplicit && elements.Length == 0) + return; + + if (!TryConvertToUTF8String(builder: null, elements)) + return; + + if (arrayCreationOperation.Syntax is ImplicitArrayCreationExpressionSyntax or ArrayCreationExpressionSyntax) + { + ReportArrayCreationDiagnostic(context, arrayCreationOperation.Syntax, option.Notification.Severity); + } + else if (elements.Length > 0 && elements[0].Syntax.Parent is ArgumentSyntax) + { + // For regular parameter arrays the code fix will need to search down + ReportParameterArrayDiagnostic(context, arrayCreationOperation.Syntax, elements, option.Notification.Severity, ArrayCreationOperationLocation.Descendants); + } + else if (elements.Length > 0 && elements[0].Syntax.Parent.IsKind(SyntaxKind.CollectionInitializerExpression)) + { + // For collection initializers where the Add method takes a parameter array, the code fix + // will have to search up + ReportParameterArrayDiagnostic(context, arrayCreationOperation.Syntax, elements, option.Notification.Severity, ArrayCreationOperationLocation.Ancestors); + } + } + + private void ReportParameterArrayDiagnostic(OperationAnalysisContext context, SyntaxNode syntaxNode, ImmutableArray elements, ReportDiagnostic severity, ArrayCreationOperationLocation operationLocation) + { + // When the first elements parent is as argument, or an edge case for collection + // initializers where the Add method takes a param array, it means we have a parameter array. + // We raise the diagnostic on all of the parameters that make up the array. We could do just + // the first element, but that might be odd seeing: M(1, 2, [|3|], 4, 5) + var span = TextSpan.FromBounds(elements[0].Syntax.SpanStart, elements[^1].Syntax.Span.End); + var location = Location.Create(syntaxNode.SyntaxTree, span); + + ReportDiagnostic(context, syntaxNode, severity, location, operationLocation); + } + + private void ReportArrayCreationDiagnostic(OperationAnalysisContext context, SyntaxNode syntaxNode, ReportDiagnostic severity) + { + // When the user writes the array creation we raise the diagnostic on the first token, which will be the "new" keyword + var location = syntaxNode.GetFirstToken().GetLocation(); + + ReportDiagnostic(context, syntaxNode, severity, location, ArrayCreationOperationLocation.Current); + } + + private void ReportDiagnostic(OperationAnalysisContext context, SyntaxNode syntaxNode, ReportDiagnostic severity, Location location, ArrayCreationOperationLocation operationLocation) + { + // Store the original syntax location so the code fix can find the operation again + var additionalLocations = ImmutableArray.Create(syntaxNode.GetLocation()); + + // Also let the code fix where to look to find the operation that originally trigger this diagnostic + var properties = ImmutableDictionary.Empty.Add(nameof(ArrayCreationOperationLocation), operationLocation.ToString()); + + context.ReportDiagnostic( + DiagnosticHelper.Create(Descriptor, location, severity, additionalLocations, properties)); + } + + internal static bool TryConvertToUTF8String(StringBuilder? builder, ImmutableArray arrayCreationElements) + { + for (var i = 0; i < arrayCreationElements.Length;) + { + // Need to call a method to do the actual rune decoding as it uses stackalloc, and stackalloc + // in a loop is a bad idea + if (!TryGetNextRune(arrayCreationElements, i, out var rune, out var bytesConsumed)) + return false; + + i += bytesConsumed; + + if (builder is not null) + { + if (rune.TryGetEscapeCharacter(out var escapeChar)) + { + builder.Append('\\'); + builder.Append(escapeChar); + } + else + { + builder.Append(rune.ToString()); + } + } + } + + return true; + } + + private static bool TryGetNextRune(ImmutableArray arrayCreationElements, int startIndex, out Rune rune, out int bytesConsumed) + { + rune = default; + bytesConsumed = 0; + + // We only need max 4 elements for a single Rune + var length = Math.Min(arrayCreationElements.Length - startIndex, 4); + + Span array = stackalloc byte[length]; + for (var i = 0; i < length; i++) + { + var element = arrayCreationElements[startIndex + i]; + + // First basic check is that the array element is actually a byte + if (element.ConstantValue.Value is not byte b) + return false; + + array[i] = b; + } + + // If we can't decode a rune from the array then it can't be represented as a string + return Rune.DecodeFromUtf8(array, out rune, out bytesConsumed) == System.Buffers.OperationStatus.Done; + } + } +} diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf index 32d9a3f07a6bd..b5b10229c5dca 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace Převést na namespace pro celý blok @@ -182,6 +187,11 @@ Byl zjištěn nedosažitelný kód. + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors Pro přístupové objekty používat text bloku diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf index 86583906cdf71..a28cacb0510f3 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace In namespace eines Blockbereichs konvertieren @@ -182,6 +187,11 @@ Unerreichbarer Code wurde entdeckt. + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors Blocktextkörper für Accessoren verwenden diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf index 6265461c5ed10..c97a81c78a541 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace Convertir en namespace con ámbito de bloque @@ -182,6 +187,11 @@ Se detectó código inaccesible + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors Usar cuerpo del bloque para los descriptores de acceso diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf index 015d7d7cc8e64..1bd9aeb7142cb 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace Convertir en namespace bloc inclus dans l'étendue @@ -182,6 +187,11 @@ Code inaccessible détecté + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors Utiliser un corps de bloc pour les accesseurs diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf index d597d6e592152..53b1b9e7efc0a 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace Converti in namespace con ambito blocco @@ -182,6 +187,11 @@ È stato rilevato codice non raggiungibile + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors Usa il corpo del blocco per le funzioni di accesso diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf index 859990b35b94e..a5c1239359af5 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace 範囲指定されたブロックが設定された namespace に変換 @@ -182,6 +187,11 @@ 到達できないコードが検出されました + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors アクセサーにブロック本体を使用する diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf index e3f20a9fcb56a..6df5c0250e218 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace 블록 범위 namespace 스로 변환 @@ -182,6 +187,11 @@ 접근할 수 없는 코드가 있습니다. + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors 접근자에 블록 본문 사용 diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf index 80c3c3a016753..927b421c87b7e 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace Konwertuj do zakresu bloku elementu namespace @@ -182,6 +187,11 @@ Wykryto nieosiągalny kod + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors Użyj treści bloku dla metod dostępu diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf index 90da74c11e533..54898d392cb3a 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace Converter para bloquear o namespace com escopo @@ -182,6 +187,11 @@ Código inacessível detectado + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors Usar o corpo do bloco para acessadores diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf index 7a02ac0433fbd..bdfc04162fee9 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace Преобразовать в namespace с заданной областью видимости блока @@ -182,6 +187,11 @@ Обнаружен недостижимый код + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors Использовать тело блока для методов доступа diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf index 78a4e05c95dcb..7cd153c66da3e 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace Kapsamlı namespace öğesini engellemek için dönüştür @@ -182,6 +187,11 @@ Ulaşılamayan kod algılandı + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors Erişimciler için blok gövdesi kullan diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf index 045fd1f6cd680..c818368b72919 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace 转换为块范围限定的 namespace @@ -182,6 +187,11 @@ 检测到无法访问的代码 + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors 使用访问器的程序块主体 diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf index a879fda099827..8dbe6d1e9dbee 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf @@ -32,6 +32,11 @@ Convert to 'Program.Main' style program {Locked="Program.Main"} this is the C# syntax we are going to generate + + Convert to UTF-8 string literal + Convert to UTF-8 string literal + + Convert to block scoped namespace 轉換為已設定區塊範圍的 namespace @@ -182,6 +187,11 @@ 偵測到執行不到的程式碼 + + Use UTF-8 string literal + Use UTF-8 string literal + + Use block body for accessors 使用存取子的區塊主體 diff --git a/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems b/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems index f5c4b7a5242ae..f3ba41afcb066 100644 --- a/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems +++ b/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems @@ -99,6 +99,7 @@ + diff --git a/src/Analyzers/CSharp/CodeFixes/UseUTF8StringLiteral/UseUTF8StringLiteralCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseUTF8StringLiteral/UseUTF8StringLiteralCodeFixProvider.cs new file mode 100644 index 0000000000000..a0909cbff1fbe --- /dev/null +++ b/src/Analyzers/CSharp/CodeFixes/UseUTF8StringLiteral/UseUTF8StringLiteralCodeFixProvider.cs @@ -0,0 +1,195 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.UseUTF8StringLiteral +{ + [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.UseUTF8StringLiteral), Shared] + internal sealed class UseUTF8StringLiteralCodeFixProvider : SyntaxEditorBasedCodeFixProvider + { + private const char QuoteCharacter = '"'; + private const string Suffix = "u8"; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public UseUTF8StringLiteralCodeFixProvider() + { + } + + public override ImmutableArray FixableDiagnosticIds { get; } = + ImmutableArray.Create(IDEDiagnosticIds.UseUTF8StringLiteralDiagnosticId); + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + RegisterCodeFix(context, CSharpAnalyzersResources.Use_UTF8_string_literal, nameof(CSharpAnalyzersResources.Use_UTF8_string_literal)); + return Task.CompletedTask; + } + + protected override async Task FixAllAsync( + Document document, ImmutableArray diagnostics, + SyntaxEditor editor, CodeActionOptionsProvider options, CancellationToken cancellationToken) + { + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + + foreach (var diagnostic in diagnostics) + { + cancellationToken.ThrowIfCancellationRequested(); + + var node = diagnostic.Location.FindNode(getInnermostNodeForTie: true, cancellationToken); + var stringValue = GetUTF8StringValueForDiagnostic(semanticModel, diagnostic, cancellationToken); + + // If we're replacing a byte array that is passed to a parameter array, not and an explicit array creation + // then node will be the ArgumentListSyntax that the implicit array creation is just a part of, so we have + // to handle that separately, as we can't just replace node with a string literal + // + // eg given a method: + // M(string x, params byte[] b) + // our diagnostic would be reported on: + // M("hi", [|1, 2, 3, 4|]); + // but node will point to: + // M([|"hi", 1, 2, 3, 4|]); + + if (node is BaseArgumentListSyntax argumentList) + { + editor.ReplaceNode(node, CreateArgumentListWithUTF8String(argumentList, diagnostic.Location, stringValue)); + } + else + { + editor.ReplaceNode(node, CreateUTF8String(node, stringValue)); + } + } + } + + private static string GetUTF8StringValueForDiagnostic(SemanticModel semanticModel, Diagnostic diagnostic, CancellationToken cancellationToken) + { + // For computing the UTF8 string we need the original location of the array creation + // operation, which is stored in additional locations. + var location = diagnostic.AdditionalLocations[0]; + var node = location.FindNode(getInnermostNodeForTie: true, cancellationToken); + + var operation = semanticModel.GetRequiredOperation(node, cancellationToken); + + var operationLocationString = diagnostic.Properties[nameof(UseUTF8StringLiteralDiagnosticAnalyzer.ArrayCreationOperationLocation)]; + if (!Enum.TryParse(operationLocationString, out UseUTF8StringLiteralDiagnosticAnalyzer.ArrayCreationOperationLocation operationLocation)) + throw ExceptionUtilities.Unreachable; + + IArrayCreationOperation arrayOp; + + // Because we get the location from an IOperation.Syntax, sometimes we have to look a + // little harder to get back from syntax to the operation that triggered the diagnostic + if (operationLocation == UseUTF8StringLiteralDiagnosticAnalyzer.ArrayCreationOperationLocation.Ancestors) + { + // For collection initializers where the Add method takes a param array, and the array creation + // will be a parent of the operation + arrayOp = FindArrayCreationOperationAncestor(operation); + } + else if (operationLocation == UseUTF8StringLiteralDiagnosticAnalyzer.ArrayCreationOperationLocation.Descendants) + { + // Otherwise, we must have an implicit array creation for a parameter array, so the location + // will be the invocation, or similar, that has the argument, and we need to descend child + // nodes to find the one we are interested in. To make sure we're finding the right one, + // we can use the diagnostic location for that, since the analyzer raises it on the first element. + arrayOp = operation.DescendantsAndSelf() + .OfType() + .Where(a => a.Initializer?.ElementValues.FirstOrDefault()?.Syntax.SpanStart == diagnostic.Location.SourceSpan.Start) + .First(); + } + else + { + arrayOp = (IArrayCreationOperation)operation; + } + + Contract.ThrowIfNull(arrayOp.Initializer); + + // Get our list of bytes from the array elements + using var _ = PooledStringBuilder.GetInstance(out var builder); + builder.Capacity = arrayOp.Initializer.ElementValues.Length; + if (!UseUTF8StringLiteralDiagnosticAnalyzer.TryConvertToUTF8String(builder, arrayOp.Initializer.ElementValues)) + { + // We shouldn't get here, because the code fix shouldn't ask for a string value + // if the analyzer couldn't convert it + throw ExceptionUtilities.Unreachable; + } + + return builder.ToString(); + + static IArrayCreationOperation FindArrayCreationOperationAncestor(IOperation operation) + { + while (operation is not null) + { + if (operation is IArrayCreationOperation arrayOperation) + return arrayOperation; + + operation = operation.Parent!; + } + + throw ExceptionUtilities.Unreachable; + } + } + + private static SyntaxNode CreateArgumentListWithUTF8String(BaseArgumentListSyntax argumentList, Location location, string stringValue) + { + // To construct our new argument list we add any existing tokens before the location + // and then once we hit the location, we add our string literal + // We can't just loop through the arguments, as we want to preserve trivia on the + // comma tokens, if any. + using var _ = ArrayBuilder.GetInstance(out var arguments); + foreach (var argument in argumentList.ChildNodesAndTokens()) + { + // Skip the open paren, its a child token but not an argument + if (argument.Kind() is SyntaxKind.OpenParenToken or SyntaxKind.OpenBracketToken) + { + continue; + } + + // See if we found our first argument + if (argument.Span.Start == location.SourceSpan.Start) + { + // We don't need to worry about leading trivia here, because anything before the current + // argument will have been trailing trivia on the previous comma. + var stringLiteral = CreateUTF8String(SyntaxTriviaList.Empty, stringValue, argumentList.Arguments.Last().GetTrailingTrivia()); + arguments.Add(SyntaxFactory.Argument(stringLiteral)); + break; + } + + arguments.Add(argument); + } + + return argumentList.WithArguments(SyntaxFactory.SeparatedList(arguments)); + } + + private static LiteralExpressionSyntax CreateUTF8String(SyntaxNode nodeToTakeTriviaFrom, string stringValue) + { + return CreateUTF8String(nodeToTakeTriviaFrom.GetLeadingTrivia(), stringValue, nodeToTakeTriviaFrom.GetTrailingTrivia()); + } + + private static LiteralExpressionSyntax CreateUTF8String(SyntaxTriviaList leadingTrivia, string stringValue, SyntaxTriviaList trailingTrivia) + { + var literal = SyntaxFactory.Token( + leading: leadingTrivia, + kind: SyntaxKind.UTF8StringLiteralToken, + text: QuoteCharacter + stringValue + QuoteCharacter + Suffix, + valueText: "", + trailing: trailingTrivia); + + return SyntaxFactory.LiteralExpression(SyntaxKind.UTF8StringLiteralExpression, literal); + } + } +} diff --git a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems index 5e1f5d689eb10..f518510827bf6 100644 --- a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems +++ b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems @@ -123,6 +123,7 @@ + diff --git a/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs b/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs index 3edda225cbc85..4c061bf9c9e87 100644 --- a/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs +++ b/src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs @@ -3230,7 +3230,7 @@ await VerifyCS.VerifyCodeFixAsync( // /0/Test0.cs(10,16): error CS0548: 'C.this[(int y, ?), int]': property or indexer must have at least one accessor DiagnosticResult.CompilerError("CS0548").WithSpan(10, 16, 10, 20).WithArguments("C.this[(int y, ?), int]"), // /0/Test0.cs(10,20): error CS1003: Syntax error, '[' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(10, 20, 10, 21).WithArguments("[", "("), + DiagnosticResult.CompilerError("CS1003").WithSpan(10, 20, 10, 21).WithArguments("["), // /0/Test0.cs(10,27): error CS1750: A value of type 'int' cannot be used as a default parameter because there are no standard conversions to type '(int y, ?)' DiagnosticResult.CompilerError("CS1750").WithSpan(10, 27, 10, 27).WithArguments("int", "(int y, ?)"), // /0/Test0.cs(10,27): error CS1001: Identifier expected @@ -3240,7 +3240,7 @@ await VerifyCS.VerifyCodeFixAsync( // /0/Test0.cs(10,27): error CS8124: Tuple must contain at least two elements. DiagnosticResult.CompilerError("CS8124").WithSpan(10, 27, 10, 28), // /0/Test0.cs(10,41): error CS1003: Syntax error, ']' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(10, 41, 10, 42).WithArguments("]", ")"), + DiagnosticResult.CompilerError("CS1003").WithSpan(10, 41, 10, 42).WithArguments("]"), // /0/Test0.cs(10,41): error CS1014: A get or set accessor expected DiagnosticResult.CompilerError("CS1014").WithSpan(10, 41, 10, 42), // /0/Test0.cs(10,41): error CS1514: { expected diff --git a/src/Analyzers/CSharp/Tests/RemoveUnnecessaryImports/RemoveUnnecessaryImportsTests.cs b/src/Analyzers/CSharp/Tests/RemoveUnnecessaryImports/RemoveUnnecessaryImportsTests.cs index e2f714c21ccc6..c7ef0f6058631 100644 --- a/src/Analyzers/CSharp/Tests/RemoveUnnecessaryImports/RemoveUnnecessaryImportsTests.cs +++ b/src/Analyzers/CSharp/Tests/RemoveUnnecessaryImports/RemoveUnnecessaryImportsTests.cs @@ -1618,7 +1618,7 @@ public static void Main() // Test0.cs(10,31): error CS1002: ; expected DiagnosticResult.CompilerError("CS1002").WithSpan(10, 31, 10, 36), // Test0.cs(10,31): error CS1003: Syntax error, 'in' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(10, 31, 10, 36).WithArguments("in", "fixed"), + DiagnosticResult.CompilerError("CS1003").WithSpan(10, 31, 10, 36).WithArguments("in"), // Test0.cs(10,31): error CS1525: Invalid expression term 'fixed' DiagnosticResult.CompilerError("CS1525").WithSpan(10, 31, 10, 36).WithArguments("fixed"), // Test0.cs(10,31): error CS1525: Invalid expression term 'fixed' @@ -1634,9 +1634,9 @@ public static void Main() // Test0.cs(10,37): error CS1001: Identifier expected DiagnosticResult.CompilerError("CS1001").WithSpan(10, 37, 10, 39), // Test0.cs(10,37): error CS1003: Syntax error, '(' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(10, 37, 10, 39).WithArguments("(", "in"), + DiagnosticResult.CompilerError("CS1003").WithSpan(10, 37, 10, 39).WithArguments("("), // Test0.cs(10,37): error CS1003: Syntax error, ',' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(10, 37, 10, 39).WithArguments(",", "in"), + DiagnosticResult.CompilerError("CS1003").WithSpan(10, 37, 10, 39).WithArguments(","), // Test0.cs(10,37): error CS1031: Type expected DiagnosticResult.CompilerError("CS1031").WithSpan(10, 37, 10, 39), // Test0.cs(10,40): error CS0118: 'expr2' is a variable but is used like a type @@ -1656,7 +1656,7 @@ public static void Main() // Test0.cs(10,64): error CS0246: The type or namespace name 'select' could not be found (are you missing a using directive or an assembly reference?) DiagnosticResult.CompilerError("CS0246").WithSpan(10, 64, 10, 70).WithArguments("select"), // Test0.cs(10,64): error CS1003: Syntax error, '(' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(10, 64, 10, 70).WithArguments("(", ""), + DiagnosticResult.CompilerError("CS1003").WithSpan(10, 64, 10, 70).WithArguments("("), // Test0.cs(10,71): error CS0209: The type of a local declared in a fixed statement must be a pointer type DiagnosticResult.CompilerError("CS0209").WithSpan(10, 71, 10, 71), // Test0.cs(10,71): error CS0210: You must provide an initializer in a fixed or using statement declaration @@ -1682,7 +1682,7 @@ public static void Main() // Test0.cs(10,86): error CS1002: ; expected DiagnosticResult.CompilerError("CS1002").WithSpan(10, 86, 10, 87), // Test0.cs(10,86): error CS1003: Syntax error, '(' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(10, 86, 10, 87).WithArguments("(", "}"), + DiagnosticResult.CompilerError("CS1003").WithSpan(10, 86, 10, 87).WithArguments("("), // Test0.cs(10,86): error CS1026: ) expected DiagnosticResult.CompilerError("CS1026").WithSpan(10, 86, 10, 87), // Test0.cs(10,86): error CS1031: Type expected @@ -1706,7 +1706,7 @@ public static void Main() // Test0.cs(13,30): error CS1002: ; expected DiagnosticResult.CompilerError("CS1002").WithSpan(13, 30, 13, 35), // Test0.cs(13,30): error CS1003: Syntax error, 'in' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 30, 13, 35).WithArguments("in", "fixed"), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 30, 13, 35).WithArguments("in"), // Test0.cs(13,30): error CS1525: Invalid expression term 'fixed' DiagnosticResult.CompilerError("CS1525").WithSpan(13, 30, 13, 35).WithArguments("fixed"), // Test0.cs(13,30): error CS1525: Invalid expression term 'fixed' @@ -1720,9 +1720,9 @@ public static void Main() // Test0.cs(13,36): error CS1001: Identifier expected DiagnosticResult.CompilerError("CS1001").WithSpan(13, 36, 13, 38), // Test0.cs(13,36): error CS1003: Syntax error, ',' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 36, 13, 38).WithArguments(",", "in"), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 36, 13, 38).WithArguments(","), // Test0.cs(13,36): error CS1003: Syntax error, '[' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 36, 13, 38).WithArguments("[", "in"), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 36, 13, 38).WithArguments("["), // Test0.cs(13,36): error CS1031: Type expected DiagnosticResult.CompilerError("CS1031").WithSpan(13, 36, 13, 38), // Test0.cs(13,36): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context @@ -1732,19 +1732,19 @@ public static void Main() // Test0.cs(13,39): error CS0103: The name 'expr2' does not exist in the current context DiagnosticResult.CompilerError("CS0103").WithSpan(13, 39, 13, 44).WithArguments("expr2"), // Test0.cs(13,45): error CS1003: Syntax error, ',' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 45, 13, 47).WithArguments(",", ""), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 45, 13, 47).WithArguments(","), // Test0.cs(13,48): error CS1003: Syntax error, ',' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 48, 13, 49).WithArguments(",", ""), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 48, 13, 49).WithArguments(","), // Test0.cs(13,50): error CS1003: Syntax error, ',' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 50, 13, 56).WithArguments(",", ""), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 50, 13, 56).WithArguments(","), // Test0.cs(13,57): error CS0443: Syntax error; value expected DiagnosticResult.CompilerError("CS0443").WithSpan(13, 57, 13, 57), // Test0.cs(13,57): error CS1002: ; expected DiagnosticResult.CompilerError("CS1002").WithSpan(13, 57, 13, 62), // Test0.cs(13,57): error CS1003: Syntax error, ',' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 57, 13, 62).WithArguments(",", "fixed"), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 57, 13, 62).WithArguments(","), // Test0.cs(13,57): error CS1003: Syntax error, ']' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 57, 13, 62).WithArguments("]", "fixed"), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 57, 13, 62).WithArguments("]"), // Test0.cs(13,63): error CS0246: The type or namespace name 'select' could not be found (are you missing a using directive or an assembly reference?) DiagnosticResult.CompilerError("CS0246").WithSpan(13, 63, 13, 69).WithArguments("select"), // Test0.cs(13,63): error CS1663: Fixed size buffer type must be one of the following: bool, byte, short, int, long, char, sbyte, ushort, uint, ulong, float or double @@ -1758,7 +1758,7 @@ public static void Main() // Test0.cs(13,70): error CS1001: Identifier expected DiagnosticResult.CompilerError("CS1001").WithSpan(13, 70, 13, 73), // Test0.cs(13,70): error CS1003: Syntax error, '[' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 70, 13, 73).WithArguments("[", "new"), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 70, 13, 73).WithArguments("["), // Test0.cs(13,70): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context DiagnosticResult.CompilerError("CS0214").WithSpan(13, 70, 13, 79), // Test0.cs(13,70): error CS7092: A fixed buffer may only have one dimension. @@ -1770,9 +1770,9 @@ public static void Main() // Test0.cs(13,79): error CS1002: ; expected DiagnosticResult.CompilerError("CS1002").WithSpan(13, 79, 13, 84), // Test0.cs(13,79): error CS1003: Syntax error, ',' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 79, 13, 84).WithArguments(",", "fixed"), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 79, 13, 84).WithArguments(","), // Test0.cs(13,79): error CS1003: Syntax error, ']' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 79, 13, 84).WithArguments("]", "fixed"), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 79, 13, 84).WithArguments("]"), // Test0.cs(13,79): error CS1513: } expected DiagnosticResult.CompilerError("CS1513").WithSpan(13, 79, 13, 84), // Test0.cs(13,85): error CS0102: The type 'QueryExpressionTest' already contains a definition for '' @@ -1790,9 +1790,9 @@ public static void Main() // Test0.cs(13,85): error CS1002: ; expected DiagnosticResult.CompilerError("CS1002").WithSpan(13, 85, 13, 86), // Test0.cs(13,85): error CS1003: Syntax error, '[' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 85, 13, 86).WithArguments("[", "}"), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 85, 13, 86).WithArguments("["), // Test0.cs(13,85): error CS1003: Syntax error, ']' expected - DiagnosticResult.CompilerError("CS1003").WithSpan(13, 85, 13, 86).WithArguments("]", "}"), + DiagnosticResult.CompilerError("CS1003").WithSpan(13, 85, 13, 86).WithArguments("]"), // Test0.cs(13,85): error CS1031: Type expected DiagnosticResult.CompilerError("CS1031").WithSpan(13, 85, 13, 86), // Test0.cs(14,3): error CS1022: Type or namespace definition, or end-of-file expected diff --git a/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedParametersTests.cs b/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedParametersTests.cs index d65a510d172c2..b713567ea0c35 100644 --- a/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedParametersTests.cs +++ b/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedParametersTests.cs @@ -1383,6 +1383,8 @@ public async Task RegressionTest_ShouldReportUnusedParameter_02() var options = Option(CodeStyleOptions2.UnusedParameters, new CodeStyleOption2((UnusedParametersPreference)2, NotificationOption2.Suggestion)); + var parameters = new TestParameters(globalOptions: options, retainNonFixableDiagnostics: true); + await TestDiagnosticMissingAsync( @"using System; using System.Threading.Tasks; @@ -1402,7 +1404,7 @@ public C(Task [|task|]) private void myAction() { } public void Dispose() => task.Result.MyAction -= myAction; -}", options); +}", parameters); } #endif diff --git a/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedValueAssignmentTests.cs b/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedValueAssignmentTests.cs index 575d135d0528f..ae4ce4c94002f 100644 --- a/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedValueAssignmentTests.cs +++ b/src/Analyzers/CSharp/Tests/RemoveUnusedParametersAndValues/RemoveUnusedValueAssignmentTests.cs @@ -8750,6 +8750,28 @@ class C await TestExactActionSetOfferedAsync(source, new[] { CodeFixesResources.Remove_redundant_assignment }); } + [WorkItem(38507, "https://github.com/dotnet/roslyn/issues/38507")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)] + public async Task TestCodeFixTitleForPatternMatching() + { + var source = @" +class C +{ + void M() + { + var c = M2(); + if [|(c is object obj)|] + { + } + } + + C M2() => new C(); +} +"; + + await TestExactActionSetOfferedAsync(source, new[] { CodeFixesResources.Remove_redundant_assignment }); + } + [WorkItem(38507, "https://github.com/dotnet/roslyn/issues/46251")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)] public async Task TestCodeFixForAllInDocumentForNestedDiagnostic() diff --git a/src/Analyzers/CSharp/Tests/UseUTF8StringLiteral/UseUTF8StringLiteralTests.cs b/src/Analyzers/CSharp/Tests/UseUTF8StringLiteral/UseUTF8StringLiteralTests.cs new file mode 100644 index 0000000000000..191a6c7eea3fc --- /dev/null +++ b/src/Analyzers/CSharp/Tests/UseUTF8StringLiteral/UseUTF8StringLiteralTests.cs @@ -0,0 +1,1406 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.UseUTF8StringLiteral; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseUTF8StringLiteral +{ + using VerifyCS = CSharpCodeFixVerifier< + UseUTF8StringLiteralDiagnosticAnalyzer, + UseUTF8StringLiteralCodeFixProvider>; + + public class UseUTF8StringLiteralTests + { + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestNotInAttribute() + { + await new VerifyCS.Test + { + TestCode = +@" +public class MyAttribute : System.Attribute +{ + public MyAttribute(byte[] data) + { + } +} + +public class C +{ + [MyAttribute(new byte[] { 65, 66, 67 })] + public void M() + { + } +}", + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestNotInCSharp10() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = new byte[] { 65, 66, 67 }; + } +}", + LanguageVersion = LanguageVersion.CSharp10 + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestNotWithoutInitializer() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = new byte[10]; + } +}", + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestNotInExpressionTree() + { + await new VerifyCS.Test + { + TestCode = +@" +using System; +using System.Linq.Expressions; + +public class C +{ + public void M() + { + N(() => new byte[] { 65, 66, 67 }); + } + + public void N(Expression> f) + { + } +}", + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestNotWhenNotByteArray() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = new int[] { 65, 66, 67 }; + } +}", + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestNotWhenOptionNotSet() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = new byte[] { 65, 66, 67 }; + } +}", + EditorConfig = @" +[*.cs] +csharp_style_prefer_utf8_string_literals = false +", + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestNotWhenNonLiteralElement() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = new byte[] { 65, GetB(), 67 }; + } + + public byte GetB() => 66; +}", + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestNotWhenMultidimensionalArray() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = new byte[,] { { 65, 66 }, { 67, 68 }, { 69, 70 } }; + } +}", + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestSimpleByteArray() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = [|new|] byte[] { 65, 66, 67 }; + } +}", + FixedCode = +@" +public class C +{ + public void M() + { + var x = ""ABC""u8; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestConstant() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + private const byte B = 66; + public void M() + { + var x = [|new|] byte[] { 65, B, 67 }; + } +}", + FixedCode = +@" +public class C +{ + private const byte B = 66; + public void M() + { + var x = ""ABC""u8; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestImplicitArray() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = [|new|] [] { (byte)65, (byte)66, (byte)67 }; + } +}", + FixedCode = +@" +public class C +{ + public void M() + { + var x = ""ABC""u8; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestExplicitCast() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = [|new|] byte[] { 65, (byte)'B', 67 }; + } +}", + FixedCode = +@" +public class C +{ + public void M() + { + var x = ""ABC""u8; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestHexLiteral() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = [|new|] byte[] { 0x41, 0x42, 0x43 }; + } +}", + FixedCode = +@" +public class C +{ + public void M() + { + var x = ""ABC""u8; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestBinaryExpression() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = [|new|] byte[] { 60 + 5, 60 + 6, 60 + 7 }; + } +}", + FixedCode = +@" +public class C +{ + public void M() + { + var x = ""ABC""u8; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestEmptyArray() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = [|new|] byte[] { }; + } +}", + FixedCode = +@" +public class C +{ + public void M() + { + var x = """"u8; + } +}", + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestTrivia1() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = [|new|] byte[] { 65, 66, 67 }; // I wish this byte array was easier to read + } +}", + FixedCode = +@" +public class C +{ + public void M() + { + var x = ""ABC""u8; // I wish this byte array was easier to read + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestTrivia2() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(byte[] b) + { + M(/* arrays are */ [|new|] byte[] { 65, 66, 67 } /* cool */); + } +}", + FixedCode = +@" +public class C +{ + public void M(byte[] b) + { + M(/* arrays are */ ""ABC""u8 /* cool */); + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestMultiple() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = [|new|] byte[] { 0x41, 0x42, 0x43 }; + var y = [|new|] byte[] { 0x44, 0x45, 0x46 }; + var z = [|new|] byte[] { 0x47, 0x48, 0x49 }; + } +}", + FixedCode = +@" +public class C +{ + public void M() + { + var x = ""ABC""u8; + var y = ""DEF""u8; + var z = ""GHI""u8; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestEscapeChars() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = [|new|] byte[] { 34, 92, 0, 7, 8, 12, 10, 13, 9, 11 }; + } +}", + FixedCode = +@" +public class C +{ + public void M() + { + var x = ""\""\\\0\a\b\f\n\r\t\v""u8; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestEmoji() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = [|new|] byte[] { 240, 159, 152, 128 }; + } +}", + FixedCode = +@" +public class C +{ + public void M() + { + var x = ""😀""u8; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestHalfEmoji1() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = new byte[] { 240, 159 }; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestHalfEmoji2() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = new byte[] { 152, 128 }; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestHalfEmoji3() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = new byte[] { 65, 152, 128, 66 }; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestUnicodeReplacementChar() + { + // The unicode replacement character is what is returned when, for example, an unpaired + // surrogate is converted to a UTF8 string. This test just ensures that the presence of + // that character isn't being used to detect a failure state of some kind. + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M() + { + var x = [|new|] byte[] { 239, 191, 189 }; + } +}", + FixedCode = +@" +public class C +{ + public void M() + { + var x = ""�""u8; + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestCollectionInitializer() + { + await new VerifyCS.Test + { + TestCode = +@" +using System.Collections; +using System.Collections.Generic; + +class C : IEnumerable +{ + void M(C c) + { + // Each literal of the three is a separate IArrayCreationOperation + // Lowered code is similar to: + /* + C c = new C(); + c.Add(new byte[] { 65 }); + c.Add(new byte[] { 66 }); + c.Add(new byte[] { 67 }); + */ + c = new() { [|65|], [|66|], [|67|] }; + } + + public void Add(params byte[] bytes) + { + } + + public IEnumerator GetEnumerator() + { + throw new System.NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new System.NotImplementedException(); + } +}", + FixedCode = +@" +using System.Collections; +using System.Collections.Generic; + +class C : IEnumerable +{ + void M(C c) + { + // Each literal of the three is a separate IArrayCreationOperation + // Lowered code is similar to: + /* + C c = new C(); + c.Add(new byte[] { 65 }); + c.Add(new byte[] { 66 }); + c.Add(new byte[] { 67 }); + */ + c = new() { ""A""u8, ""B""u8, ""C""u8 }; + } + + public void Add(params byte[] bytes) + { + } + + public IEnumerator GetEnumerator() + { + throw new System.NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new System.NotImplementedException(); + } +}", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestUsingWithParamArray() + { + // From: https://github.com/dotnet/roslyn/blob/0c7c0b33f0871fc4308eb2d75d77b87fc9293290/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IUsingStatement.cs#L1189-L1194 + // There is an array creation operation for the param array + await new VerifyCS.Test + { + TestCode = +@" +class C +{ + public static void M1() + { + using(var s = new S()) + { + } + } +} +ref struct S +{ + public void Dispose(int a = 1, bool b = true, params byte[] others) { } +}", + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Theory, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + // Various cases copied from https://github.com/dotnet/runtime/blob/main/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs + [InlineData(new byte[] { 0x37, 0x02, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x65 }, "7translate")] + [InlineData(new byte[] { 0x3f, 0x01 }, "?")] + public async Task TestValidUTF8Strings(byte[] bytes, string stringValue) + { + await new VerifyCS.Test + { + TestCode = +$@" +public class C +{{ + private static readonly byte[] _bytes = [|new|] byte[] {{ {string.Join(", ", bytes)} }}; +}} +", + FixedCode = +$@" +public class C +{{ + private static readonly byte[] _bytes = ""{stringValue}""u8; +}} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + + // Lets make sure there aren't any false positives here, and make sure the byte array actually + // correctly round-trips via UTF8 + var newStringValue = Encoding.UTF8.GetString(bytes); + Assert.Equal(stringValue, newStringValue); + var newBytes = Encoding.UTF8.GetBytes(stringValue); + Assert.Equal(bytes, newBytes); + } + + [Theory, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + // Various cases copied from https://github.com/dotnet/runtime/blob/main/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http2/HuffmanDecodingTests.cs + [InlineData(new byte[] { 0xff, 0xcf })] + [InlineData(new byte[] { 0b100111_00, 0b101_10100, 0b0_101000_0, 0b0111_1111 })] + [InlineData(new byte[] { 0xb6, 0xb9, 0xac, 0x1c, 0x85, 0x58, 0xd5, 0x20, 0xa4, 0xb6, 0xc2, 0xad, 0x61, 0x7b, 0x5a, 0x54, 0x25, 0x1f })] + [InlineData(new byte[] { 0xfe, 0x53 })] + [InlineData(new byte[] { 0xff, 0xff, 0xf6, 0xff, 0xff, 0xfd, 0x68 })] + [InlineData(new byte[] { 0xff, 0xff, 0xf9, 0xff, 0xff, 0xfd, 0x86 })] + // _headerNameHuffmanBytes from https://github.com/dotnet/runtime/blob/main/src/libraries/Common/tests/Tests/System/Net/aspnetcore/Http3/QPackDecoderTest.cs + [InlineData(new byte[] { 0xa8, 0xbe, 0x16, 0x9c, 0xa3, 0x90, 0xb6, 0x7f })] + public async Task TestInvalidUTF8Strings(byte[] bytes) + { + await new VerifyCS.Test + { + TestCode = +$@" +public class C +{{ + private static readonly byte[] _bytes = new byte[] {{ {string.Join(", ", bytes)} }}; +}} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + + // Lets make sure there aren't any false negatives here, and see if the byte array would actually + // correctly round-trip via UTF8 + var stringValue = Encoding.UTF8.GetString(bytes); + var newBytes = Encoding.UTF8.GetBytes(stringValue); + Assert.NotEqual(bytes, newBytes); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray1() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(params byte[] b) + { + M([|new|] byte[] { 65, 66, 67 }); + } +} +", + FixedCode = +@" +public class C +{ + public void M(params byte[] b) + { + M(""ABC""u8); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray2() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(int i, params byte[] b) + { + M(1, [|new|] byte[] { 65, 66, 67 }); + } +} +", + FixedCode = +@" +public class C +{ + public void M(int i, params byte[] b) + { + M(1, ""ABC""u8); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray3() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(params byte[] b) + { + M([|65|]); + } +} +", + FixedCode = +@" +public class C +{ + public void M(params byte[] b) + { + M(""A""u8); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray4() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(params byte[] b) + { + M(/* hi */ [|65|] /* there */); + } +} +", + FixedCode = +@" +public class C +{ + public void M(params byte[] b) + { + M(/* hi */ ""A""u8 /* there */); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray5() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(params byte[] b) + { + M([|65, 66, 67|]); + } +} +", + FixedCode = +@" +public class C +{ + public void M(params byte[] b) + { + M(""ABC""u8); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray6() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(params byte[] b) + { + M(/* hi */ [|65, 66, 67|] /* there */); + } +} +", + FixedCode = +@" +public class C +{ + public void M(params byte[] b) + { + M(/* hi */ ""ABC""u8 /* there */); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray7() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(int x, params byte[] b) + { + M(1); + } +} +", + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray8() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(int x, params byte[] b) + { + M(1, [|65, 66, 67|]); + } +} +", + FixedCode = +@" +public class C +{ + public void M(int x, params byte[] b) + { + M(1, ""ABC""u8); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray9() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(int x, params byte[] b) + { + M(1, /* hi */ [|65|] /* there */); + } +} +", + FixedCode = +@" +public class C +{ + public void M(int x, params byte[] b) + { + M(1, /* hi */ ""A""u8 /* there */); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray10() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(int x, params byte[] b) + { + M(1, /* hi */ [|65, 66, 67|] /* there */); + } +} +", + FixedCode = +@" +public class C +{ + public void M(int x, params byte[] b) + { + M(1, /* hi */ ""ABC""u8 /* there */); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray11() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(int x, int y, int z, params byte[] b) + { + M( /* b1 */ 1 /* a1 */, /* b2 */ 2 /* a2 */, /* b3 */ 3 /* a3 */, /* b4 */ [|65, /* x1 */ 66, /* x2 */ 67|] /* a4 */); + } +} +", + FixedCode = +@" +public class C +{ + public void M(int x, int y, int z, params byte[] b) + { + M( /* b1 */ 1 /* a1 */, /* b2 */ 2 /* a2 */, /* b3 */ 3 /* a3 */, /* b4 */ ""ABC""u8 /* a4 */); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray12() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public C(params byte[] b) + { + new C([|65, 66, 67|]); + } +} +", + FixedCode = +@" +public class C +{ + public C(params byte[] b) + { + new C(""ABC""u8); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray13() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public int this[params byte[] bytes] + { + get => 0; + } + + public void M() + { + _ = this[[|65, 66, 67|]]; + } +} +", + FixedCode = +@" +public class C +{ + public int this[params byte[] bytes] + { + get => 0; + } + + public void M() + { + _ = this[""ABC""u8]; + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray14() + { + await new VerifyCS.Test + { + TestCode = +@" +public record C1(int x) : B([|65, 66, 67|]); + +public record C2(params byte[] Bytes) : B(Bytes); + +public record B(params byte[] Bytes) +{ + public void M() + { + new C1(1); + new C2([|65, 66, 67|]); + new B([|65, 66, 67|]); + } +} +namespace System.Runtime.CompilerServices +{ + public sealed class IsExternalInit + { + } +} +", + FixedCode = +@" +public record C1(int x) : B(""ABC""u8); + +public record C2(params byte[] Bytes) : B(Bytes); + +public record B(params byte[] Bytes) +{ + public void M() + { + new C1(1); + new C2(""ABC""u8); + new B(""ABC""u8); + } +} +namespace System.Runtime.CompilerServices +{ + public sealed class IsExternalInit + { + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray15() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C1 : B +{ + public C1(int x) + : base([|65, 66, 67|]) + { + } +} + +public class C2 : B +{ + public C2(params byte[] Bytes) + : base(Bytes) + { + } +} + +public class B +{ + public B(string x, params byte[] bytes) + : this(bytes) + { + } + + public B(int x) + : this([|65, 66, 67|]) + { + } + + public B(params byte[] bytes) + { + new C1(1); + new C2([|65, 66, 67|]); + new B([|65, 66, 67|]); + new B(""a"", [|65, 66, 67|]); + } +} +", + FixedCode = +@" +public class C1 : B +{ + public C1(int x) + : base(""ABC""u8) + { + } +} + +public class C2 : B +{ + public C2(params byte[] Bytes) + : base(Bytes) + { + } +} + +public class B +{ + public B(string x, params byte[] bytes) + : this(bytes) + { + } + + public B(int x) + : this(""ABC""u8) + { + } + + public B(params byte[] bytes) + { + new C1(1); + new C2(""ABC""u8); + new B(""ABC""u8); + new B(""a"", ""ABC""u8); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray16() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(int[] i, byte[] b) + { + M(new int[] { 1 }, [|new|] byte[] { 65, 66, 67 }); + } +} +", + FixedCode = +@" +public class C +{ + public void M(int[] i, byte[] b) + { + M(new int[] { 1 }, ""ABC""u8); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestParamArray17() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(int[] i, params byte[] b) + { + M(new int[] { 1 }, [|65, 66, 67|]); + } +} +", + FixedCode = +@" +public class C +{ + public void M(int[] i, params byte[] b) + { + M(new int[] { 1 }, ""ABC""u8); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseUTF8StringLiteral)] + public async Task TestMultidimensionalArray() + { + await new VerifyCS.Test + { + TestCode = +@" +public class C +{ + public void M(byte[][] i, byte[] b) + { + M(new byte[][] { [|new|] byte[] { 65, 66, 67 }, [|new|] byte[] { 65, 66, 67 } }, [|new|] byte[] { 65, 66, 67 }); + } +} +", + FixedCode = +@" +public class C +{ + public void M(byte[][] i, byte[] b) + { + M(new byte[][] { ""ABC""u8, ""ABC""u8 }, ""ABC""u8); + } +} +", + CodeActionValidationMode = CodeActionValidationMode.None, + LanguageVersion = LanguageVersion.Preview + }.RunAsync(); + } + } +} diff --git a/src/Analyzers/CSharp/Tests/ValidateFormatString/ValidateFormatStringTests.cs b/src/Analyzers/CSharp/Tests/ValidateFormatString/ValidateFormatStringTests.cs index cf6a55645c570..72820d5f111a8 100644 --- a/src/Analyzers/CSharp/Tests/ValidateFormatString/ValidateFormatStringTests.cs +++ b/src/Analyzers/CSharp/Tests/ValidateFormatString/ValidateFormatStringTests.cs @@ -575,15 +575,15 @@ static void Main(string[] args) string.Format(""This [|{1}|] is my test"", ""teststring1""); } }"; - var options = new IdeAnalyzerOptions(ReportInvalidPlaceholdersInStringDotFormatCalls: true); + var options = Option(IdeAnalyzerOptionsStorage.ReportInvalidPlaceholdersInStringDotFormatCalls, true); await TestDiagnosticInfoAsync( source, options: null, + globalOptions: options, diagnosticId: IDEDiagnosticIds.ValidateFormatStringDiagnosticID, diagnosticSeverity: DiagnosticSeverity.Info, - diagnosticMessage: AnalyzersResources.Format_string_contains_invalid_placeholder, - ideAnalyzerOptions: options); + diagnosticMessage: AnalyzersResources.Format_string_contains_invalid_placeholder); } [Fact, Trait(Traits.Feature, Traits.Features.ValidateFormatString)] @@ -596,9 +596,9 @@ static void Main(string[] args) string.Format(""This [|{1}|] is my test"", ""teststring1""); } }"; - var options = new IdeAnalyzerOptions(ReportInvalidPlaceholdersInStringDotFormatCalls: false); + var options = Option(IdeAnalyzerOptionsStorage.ReportInvalidPlaceholdersInStringDotFormatCalls, false); - await TestDiagnosticMissingAsync(source, new TestParameters(ideAnalyzerOptions: options)); + await TestDiagnosticMissingAsync(source, new TestParameters(globalOptions: options)); } #endif [Fact, Trait(Traits.Feature, Traits.Features.ValidateFormatString)] diff --git a/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs b/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs index 3b4584133e91b..f0c2b7d0e03f8 100644 --- a/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs +++ b/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs @@ -99,6 +99,7 @@ internal static class EnforceOnBuildValues public const EnforceOnBuild UseTopLevelStatements = /*IDE0210*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild UseProgramMain = /*IDE0211*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild ForEachCast = /*IDE0220*/ EnforceOnBuild.WhenExplicitlyEnabled; + public const EnforceOnBuild UseUTF8StringLiteral = /*IDE0230*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild MultipleBlankLines = /*IDE2000*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild EmbeddedStatementPlacement = /*IDE2001*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild ConsecutiveBracePlacement = /*IDE2002*/ EnforceOnBuild.WhenExplicitlyEnabled; diff --git a/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs b/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs index 6f72671078e7e..b6127e0153f05 100644 --- a/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs +++ b/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs @@ -10,13 +10,13 @@ internal static class IDEDiagnosticIds { public const string SimplifyNamesDiagnosticId = "IDE0001"; public const string SimplifyMemberAccessDiagnosticId = "IDE0002"; - public const string RemoveQualificationDiagnosticId = "IDE0003"; + public const string RemoveThisOrMeQualificationDiagnosticId = "IDE0003"; public const string RemoveUnnecessaryCastDiagnosticId = "IDE0004"; public const string RemoveUnnecessaryImportsDiagnosticId = "IDE0005"; public const string IntellisenseBuildFailedDiagnosticId = "IDE0006"; public const string UseImplicitTypeDiagnosticId = "IDE0007"; public const string UseExplicitTypeDiagnosticId = "IDE0008"; - public const string AddQualificationDiagnosticId = "IDE0009"; + public const string AddThisOrMeQualificationDiagnosticId = "IDE0009"; public const string PopulateSwitchStatementDiagnosticId = "IDE0010"; public const string AddBracesDiagnosticId = "IDE0011"; @@ -176,6 +176,8 @@ internal static class IDEDiagnosticIds public const string ForEachCastDiagnosticId = "IDE0220"; + public const string UseUTF8StringLiteralDiagnosticId = "IDE0230"; + // Analyzer error Ids public const string AnalyzerChangedId = "IDE1001"; public const string AnalyzerDependencyConflictId = "IDE1002"; diff --git a/src/Analyzers/Core/Analyzers/PopulateSwitch/PopulateSwitchExpressionHelpers.cs b/src/Analyzers/Core/Analyzers/PopulateSwitch/PopulateSwitchExpressionHelpers.cs index 99fd13237f5bd..19f0a1c67247f 100644 --- a/src/Analyzers/Core/Analyzers/PopulateSwitch/PopulateSwitchExpressionHelpers.cs +++ b/src/Analyzers/Core/Analyzers/PopulateSwitch/PopulateSwitchExpressionHelpers.cs @@ -65,7 +65,7 @@ private static void HandleBinaryPattern(IBinaryPatternOperation? binaryPattern, private static void RemoveIfConstantPatternHasValue(IOperation operation, Dictionary enumMembers) { - if (operation is IConstantPatternOperation { Value: { ConstantValue: { HasValue: true, Value: var value } } }) + if (operation is IConstantPatternOperation { Value.ConstantValue: { HasValue: true, Value: var value } }) enumMembers.Remove(IntegerUtilities.ToInt64(value)); } diff --git a/src/Analyzers/Core/Analyzers/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs index 8884e88b26566..a5e4bbd501530 100644 --- a/src/Analyzers/Core/Analyzers/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs @@ -28,7 +28,7 @@ internal abstract class AbstractQualifyMemberAccessDiagnosticAnalyzer< where TSimplifierOptions : SimplifierOptions { protected AbstractQualifyMemberAccessDiagnosticAnalyzer() - : base(IDEDiagnosticIds.AddQualificationDiagnosticId, + : base(IDEDiagnosticIds.AddThisOrMeQualificationDiagnosticId, EnforceOnBuildValues.AddQualification, options: ImmutableHashSet.Create(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOptions2.QualifyPropertyAccess, CodeStyleOptions2.QualifyMethodAccess, CodeStyleOptions2.QualifyEventAccess), new LocalizableResourceString(nameof(AnalyzersResources.Member_access_should_be_qualified), AnalyzersResources.ResourceManager, typeof(AnalyzersResources)), @@ -128,7 +128,8 @@ private void AnalyzeOperation(OperationAnalysisContext context, IOperation opera }; var simplifierOptions = GetSimplifierOptions(context.Options, context.Operation.Syntax.SyntaxTree); - var optionValue = simplifierOptions.QualifyMemberAccess(symbolKind); + if (!simplifierOptions.TryGetQualifyMemberAccessOption(symbolKind, out var optionValue)) + return; var shouldOptionBePresent = optionValue.Value; var severity = optionValue.Notification.Severity; diff --git a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs index c67a79a71a8e4..fcb6875d21240 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnusedParametersAndValues/AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.SymbolStartAnalyzer.cs @@ -272,7 +272,7 @@ parameter.ContainingSymbol is not IMethodSymbol method || // Don't report on valid GetInstance method of ICustomMarshaler. // See https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.icustommarshaler#implementing-the-getinstance-method - if (method is { MetadataName: "GetInstance", IsStatic: true, Parameters: { Length: 1 }, ContainingType: { } containingType } methodSymbol && + if (method is { MetadataName: "GetInstance", IsStatic: true, Parameters.Length: 1, ContainingType: { } containingType } methodSymbol && methodSymbol.Parameters[0].Type.SpecialType == SpecialType.System_String && containingType.AllInterfaces.Any((@interface, marshaler) => @interface.Equals(marshaler), _iCustomMarshaler)) { diff --git a/src/Analyzers/Core/Analyzers/SimplifyInterpolation/AbstractSimplifyInterpolationHelpers.cs b/src/Analyzers/Core/Analyzers/SimplifyInterpolation/AbstractSimplifyInterpolationHelpers.cs index e209bd36a6a9f..59413484b3798 100644 --- a/src/Analyzers/Core/Analyzers/SimplifyInterpolation/AbstractSimplifyInterpolationHelpers.cs +++ b/src/Analyzers/Core/Analyzers/SimplifyInterpolation/AbstractSimplifyInterpolationHelpers.cs @@ -82,7 +82,7 @@ private void UnwrapFormatString( { Contract.ThrowIfNull(expression.SemanticModel); - if (expression is IInvocationOperation { TargetMethod: { Name: nameof(ToString) } } invocation && + if (expression is IInvocationOperation { TargetMethod.Name: nameof(ToString) } invocation && HasNonImplicitInstance(invocation) && !syntaxFacts.IsBaseExpression(invocation.Instance!.Syntax) && !invocation.Instance.Type!.IsRefLikeType) @@ -219,7 +219,7 @@ private void UnwrapAlignmentPadding( var alignmentOp = invocation.Arguments[0].Value; if (PermitNonLiteralAlignmentComponents - ? alignmentOp is { ConstantValue: { HasValue: true } } + ? alignmentOp is { ConstantValue.HasValue: true } : alignmentOp is { Kind: OperationKind.Literal }) { var alignmentSyntax = alignmentOp.Syntax; diff --git a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs index f635a0ad40383..63e9a3e846009 100644 --- a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs +++ b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -39,7 +40,7 @@ private class CustomFixAllProvider : FixAllProvider if (diagnostics.IsDefaultOrEmpty) return null; - var title = FixAllContextHelper.GetDefaultFixAllTitle(fixAllContext); + var title = fixAllContext.GetDefaultFixAllTitle(); return CodeAction.Create( title, cancellationToken => FixAllByDocumentAsync( @@ -47,7 +48,7 @@ private class CustomFixAllProvider : FixAllProvider diagnostics, fixAllContext.GetProgressTracker(), #if CODE_STYLE - options: _ => default, + CodeActionOptions.DefaultProvider, #else fixAllContext.State.CodeActionOptionsProvider, #endif diff --git a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs index 6d7bbd508a55d..347b9d86fe515 100644 --- a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs @@ -62,7 +62,7 @@ private static async Task FixAllInDocumentAsync(Document document, Imm documentWithInvalidFolders, new DocumentRenameOptions(), #if !CODE_STYLE - CodeCleanupOptions.CreateProvider(options), + options, #endif documentWithInvalidFolders.Name, newDocumentFolders: targetFolders, diff --git a/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs b/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs index 8ccb223fa4fec..da49261278a69 100644 --- a/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs +++ b/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs @@ -157,5 +157,6 @@ internal static class PredefinedCodeFixProviderNames public const string UseSystemHashCode = nameof(UseSystemHashCode); public const string UseThrowExpression = nameof(UseThrowExpression); public const string UseTupleSwap = nameof(UseTupleSwap); + public const string UseUTF8StringLiteral = nameof(UseUTF8StringLiteral); } } diff --git a/src/Analyzers/Core/CodeFixes/QualifyMemberAccess/AbstractQualifyMemberAccessCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/QualifyMemberAccess/AbstractQualifyMemberAccessCodeFixProvider.cs index 6a12e8237b70c..889e86d3712ec 100644 --- a/src/Analyzers/Core/CodeFixes/QualifyMemberAccess/AbstractQualifyMemberAccessCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/QualifyMemberAccess/AbstractQualifyMemberAccessCodeFixProvider.cs @@ -23,7 +23,7 @@ internal abstract class AbstractQualifyMemberAccessCodeFixprovider FixableDiagnosticIds - => ImmutableArray.Create(IDEDiagnosticIds.AddQualificationDiagnosticId); + => ImmutableArray.Create(IDEDiagnosticIds.AddThisOrMeQualificationDiagnosticId); public override Task RegisterCodeFixesAsync(CodeFixContext context) { diff --git a/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs index 8cf5f3d9a5e9e..dda8bfc7b1903 100644 --- a/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs @@ -146,20 +146,26 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) title = CodeFixesResources.Use_discard_underscore; + var syntaxFacts = context.Document.GetRequiredLanguageService(); + var root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var node = root.FindNode(context.Span, getInnermostNodeForTie: true); + // Check if this is compound assignment which is not parented by an expression statement, // for example "return x += M();" OR "=> x ??= new C();" // If so, we will be replacing this compound assignment with the underlying binary operation. // For the above examples, it will be "return x + M();" AND "=> x ?? new C();" respectively. // For these cases, we want to show the title as "Remove redundant assignment" instead of "Use discard _". - - var syntaxFacts = context.Document.GetRequiredLanguageService(); - var root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - var node = root.FindNode(context.Span, getInnermostNodeForTie: true); if (syntaxFacts.IsLeftSideOfCompoundAssignment(node) && !syntaxFacts.IsExpressionStatement(node.Parent)) { title = CodeFixesResources.Remove_redundant_assignment; } + // Also we want to show "Remove redundant assignment" title in pattern matching, e.g. + // if (obj is SomeType someType) <-- "someType" will be fully removed here + else if (syntaxFacts.IsDeclarationPattern(node.Parent)) + { + title = CodeFixesResources.Remove_redundant_assignment; + } break; @@ -173,7 +179,6 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) } RegisterCodeFix(context, title, GetEquivalenceKey(preference, isRemovableAssignment)); - return; } private static bool IsForEachIterationVariableDiagnostic(Diagnostic diagnostic, Document document, CancellationToken cancellationToken) diff --git a/src/Analyzers/Core/CodeFixes/UnsealClass/AbstractUnsealClassCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UnsealClass/AbstractUnsealClassCodeFixProvider.cs index d0f0843212cf1..04d21b73e62e3 100644 --- a/src/Analyzers/Core/CodeFixes/UnsealClass/AbstractUnsealClassCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/UnsealClass/AbstractUnsealClassCodeFixProvider.cs @@ -44,10 +44,12 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) type, document.Project.Solution, cancellationToken).ConfigureAwait(false); if (definition != null && definition.DeclaringSyntaxReferences.Length > 0) { + var title = string.Format(TitleFormat, type.Name); context.RegisterCodeFix( - new MyCodeAction( - string.Format(TitleFormat, type.Name), - c => UnsealDeclarationsAsync(document.Project.Solution, definition.DeclaringSyntaxReferences, c)), + CodeAction.Create( + title, + c => UnsealDeclarationsAsync(document.Project.Solution, definition.DeclaringSyntaxReferences, c), + title), context.Diagnostics); } } @@ -83,13 +85,5 @@ private static async Task UnsealDeclarationsAsync( return solution; } - - private sealed class MyCodeAction : CustomCodeActions.SolutionChangeAction - { - public MyCodeAction(string title, Func> createChangedSolution) - : base(title, createChangedSolution, title) - { - } - } } } diff --git a/src/Analyzers/VisualBasic/Tests/ValidateFormatString/ValidateFormatStringTests.vb b/src/Analyzers/VisualBasic/Tests/ValidateFormatString/ValidateFormatStringTests.vb index befad4ad0ac1f..5a96838c6001c 100644 --- a/src/Analyzers/VisualBasic/Tests/ValidateFormatString/ValidateFormatStringTests.vb +++ b/src/Analyzers/VisualBasic/Tests/ValidateFormatString/ValidateFormatStringTests.vb @@ -316,14 +316,12 @@ Class C string.Format(""This {0} [|{2}|] works"", ""test"", ""also"") End Sub End Class" - Dim options = New IdeAnalyzerOptions(ReportInvalidPlaceholdersInStringDotFormatCalls:=True) - Await TestDiagnosticInfoAsync( source, diagnosticId:=IDEDiagnosticIds.ValidateFormatStringDiagnosticID, diagnosticSeverity:=DiagnosticSeverity.Info, diagnosticMessage:=AnalyzersResources.Format_string_contains_invalid_placeholder, - ideAnalyzerOptions:=options) + globalOptions:=[Option](IdeAnalyzerOptionsStorage.ReportInvalidPlaceholdersInStringDotFormatCalls, True)) End Function @@ -334,8 +332,8 @@ Class C string.Format(""This {0} [|{2}|] works"", ""test"", ""also"") End Sub End Class" - Dim options = New IdeAnalyzerOptions(ReportInvalidPlaceholdersInStringDotFormatCalls:=False) - Await TestDiagnosticMissingAsync(source, New TestParameters(ideAnalyzerOptions:=options)) + Await TestDiagnosticMissingAsync(source, New TestParameters(globalOptions:= + [Option](IdeAnalyzerOptionsStorage.ReportInvalidPlaceholdersInStringDotFormatCalls, False))) End Function #End If End Class diff --git a/src/Compilers/.editorconfig b/src/Compilers/.editorconfig index 7d147199d9b27..64a66b58da7b5 100644 --- a/src/Compilers/.editorconfig +++ b/src/Compilers/.editorconfig @@ -15,6 +15,9 @@ dotnet_diagnostic.RS0101.severity = none # RS0102: Braces must not have blank lines between them dotnet_diagnostic.RS0102.severity = none +# IDE0170: Prefer extended property pattern +dotnet_diagnostic.IDE0170.severity = suggestion + # CSharp code style settings: [*.cs] csharp_style_var_for_built_in_types = false:none diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index b61abacd57cd1..c95023e5083e5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -452,10 +452,20 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin return false; case BoundKind.RangeVariable: - // range variables can only be used as RValues - var queryref = (BoundRangeVariable)expr; - Error(diagnostics, GetRangeLvalueError(valueKind), node, queryref.RangeVariableSymbol.Name); - return false; + { + // range variables can only be used as RValues + var queryref = (BoundRangeVariable)expr; + var errorCode = GetRangeLvalueError(valueKind); + if (errorCode is ErrorCode.ERR_InvalidAddrOp or ErrorCode.ERR_RefLocalOrParamExpected) + { + Error(diagnostics, errorCode, node); + } + else + { + Error(diagnostics, errorCode, node, queryref.RangeVariableSymbol.Name); + } + return false; + } case BoundKind.Conversion: var conversion = (BoundConversion)expr; @@ -536,7 +546,15 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin var isValueType = ((BoundThisReference)expr).Type.IsValueType; if (!isValueType || (RequiresAssignableVariable(valueKind) && (this.ContainingMemberOrLambda as MethodSymbol)?.IsEffectivelyReadOnly == true)) { - Error(diagnostics, GetThisLvalueError(valueKind, isValueType), node, node); + var errorCode = GetThisLvalueError(valueKind, isValueType); + if (errorCode is ErrorCode.ERR_InvalidAddrOp or ErrorCode.ERR_IncrementLvalueExpected or ErrorCode.ERR_RefReturnThis or ErrorCode.ERR_RefLocalOrParamExpected or ErrorCode.ERR_RefLvalueExpected) + { + Error(diagnostics, errorCode, node); + } + else + { + Error(diagnostics, errorCode, node, node); + } return false; } @@ -676,7 +694,7 @@ private bool CheckLocalValueKind(SyntaxNode node, BoundLocal local, BindValueKin { if (localSymbol.RefKind == RefKind.None) { - diagnostics.Add(ErrorCode.ERR_RefLocalOrParamExpected, node.Location, localSymbol); + diagnostics.Add(ErrorCode.ERR_RefLocalOrParamExpected, node.Location); return false; } else if (!localSymbol.IsWritableVariable) @@ -956,9 +974,14 @@ private bool CheckEventValueKind(BoundEventAccess boundEvent, BindValueKind valu { // NOTE: Dev11 reports ERR_RefProperty, as if this were a property access (since that's how it will be lowered). // Roslyn reports a new, more specific, error code. - ErrorCode errorCode = valueKind == BindValueKind.RefOrOut ? ErrorCode.ERR_WinRtEventPassedByRef : GetStandardLvalueError(valueKind); - Error(diagnostics, errorCode, eventSyntax, eventSymbol); - + if (valueKind == BindValueKind.RefOrOut) + { + Error(diagnostics, ErrorCode.ERR_WinRtEventPassedByRef, eventSyntax); + } + else + { + Error(diagnostics, GetStandardLvalueError(valueKind), eventSyntax, eventSymbol); + } return false; } else if (RequiresVariableReceiver(receiver, eventSymbol.AssociatedField) && // NOTE: using field, not event @@ -1070,9 +1093,13 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV Debug.Assert(propertySymbol.TypeWithAnnotations.HasType); Error(diagnostics, ErrorCode.ERR_ReturnNotLValue, expr.Syntax, propertySymbol); } + else if (valueKind == BindValueKind.RefOrOut) + { + Error(diagnostics, ErrorCode.ERR_RefProperty, node); + } else { - Error(diagnostics, valueKind == BindValueKind.RefOrOut ? ErrorCode.ERR_RefProperty : GetStandardLvalueError(valueKind), node, propertySymbol); + Error(diagnostics, GetStandardLvalueError(valueKind), node); } return false; @@ -2320,7 +2347,7 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint //"this" is not returnable by reference in a struct. if (escapeTo == Binder.ExternalScope) { - Error(diagnostics, ErrorCode.ERR_RefReturnStructThis, node, ThisParameterSymbol.SymbolName); + Error(diagnostics, ErrorCode.ERR_RefReturnStructThis, node); return false; } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.WithQueryLambdaParametersBinder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.WithQueryLambdaParametersBinder.cs index 8692bae9808d5..0f5ff6b9eea27 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.WithQueryLambdaParametersBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.WithQueryLambdaParametersBinder.cs @@ -117,7 +117,7 @@ internal override void LookupSymbolsInSingleBinder( } } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { if (options.CanConsiderMembers()) { diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.cs index 7cfb2d27fdc34..13d4673264720 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.cs @@ -73,9 +73,9 @@ internal bool IsEarlyAttributeBinder } // Return the nearest enclosing node being bound as a nameof(...) argument, if any, or null if none. - protected virtual SyntaxNode? EnclosingNameofArgument => null; + protected virtual SyntaxNode? EnclosingNameofArgument => NextRequired.EnclosingNameofArgument; - private bool IsInsideNameof => this.EnclosingNameofArgument != null; + internal virtual bool IsInsideNameof => NextRequired.IsInsideNameof; /// /// Get the next binder in which to look up a name, if not found by this binder. diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs index 4f1b05b490c96..cd0036df47884 100644 --- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs +++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs @@ -679,8 +679,11 @@ private Binder VisitTypeDeclarationCore(TypeDeclarationSyntax parent) // and position is more likely to be in the body, so lets check for "inBody" first. if (parent.OpenBraceToken != default && parent.CloseBraceToken != default && - (LookupPosition.IsBetweenTokens(_position, parent.OpenBraceToken, parent.CloseBraceToken) || - LookupPosition.IsInAttributeSpecification(_position, parent.AttributeLists))) + LookupPosition.IsBetweenTokens(_position, parent.OpenBraceToken, parent.CloseBraceToken)) + { + extraInfo = NodeUsage.NamedTypeBodyOrTypeParameters; + } + else if (LookupPosition.IsInAttributeSpecification(_position, parent.AttributeLists)) { extraInfo = NodeUsage.NamedTypeBodyOrTypeParameters; } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs index a9afa27ce0013..f2e60c705dba4 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Crefs.cs @@ -960,11 +960,15 @@ private TypeSymbol BindCrefParameterOrReturnType(TypeSyntax typeSyntax, MemberCr if (HasNonObsoleteError(localDiagnostics.DiagnosticBag)) { Debug.Assert(typeSyntax.Parent is object); - ErrorCode code = typeSyntax.Parent.Kind() == SyntaxKind.ConversionOperatorMemberCref - ? ErrorCode.WRN_BadXMLRefReturnType - : ErrorCode.WRN_BadXMLRefParamType; CrefSyntax crefSyntax = GetRootCrefSyntax(memberCrefSyntax); - diagnostics.Add(code, typeSyntax.Location, typeSyntax.ToString(), crefSyntax.ToString()); + if (typeSyntax.Parent.Kind() == SyntaxKind.ConversionOperatorMemberCref) + { + diagnostics.Add(ErrorCode.WRN_BadXMLRefReturnType, typeSyntax.Location); + } + else + { + diagnostics.Add(ErrorCode.WRN_BadXMLRefParamType, typeSyntax.Location, typeSyntax.ToString(), crefSyntax.ToString()); + } } } else diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 33d5ca7310dd0..68af9cf64a682 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -4234,7 +4234,7 @@ BoundExpression bindObjectCreationExpression(ObjectCreationExpressionSyntax node if (typeWithAnnotations.NullableAnnotation.IsAnnotated() && !type.IsNullableType()) { - diagnostics.Add(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, node.Location, type); + diagnostics.Add(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, node.Location); } switch (type.TypeKind) @@ -4269,7 +4269,7 @@ BoundExpression bindObjectCreationExpression(ObjectCreationExpressionSyntax node case TypeKind.Array: // ex: new ref[] type = new ExtendedErrorTypeSymbol(type, LookupResultKind.NotCreatable, - diagnostics.Add(ErrorCode.ERR_InvalidObjectCreation, node.Type.Location, type)); + diagnostics.Add(ErrorCode.ERR_InvalidObjectCreation, node.Type.Location)); goto case TypeKind.Class; default: diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs index 5f6e4c3a65b0c..20365bf168b13 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs @@ -1859,31 +1859,32 @@ private static TypeSymbol GetCommonTypeOrReturnType(ImmutableArray /// Helper method that checks whether there is an invocable 'nameof' in scope. /// - private bool InvocableNameofInScope() + internal bool InvocableNameofInScope() { var lookupResult = LookupResult.GetInstance(); const LookupOptions options = LookupOptions.AllMethodsOnArityZero | LookupOptions.MustBeInvocableIfMember; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs index 89c01229d000e..53f907f187284 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs @@ -1755,7 +1755,7 @@ internal void AddLookupSymbolsInfo(LookupSymbolsInfo result, LookupOptions optio } } - protected virtual void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo info, LookupOptions options, Binder originalBinder) + internal virtual void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo info, LookupOptions options, Binder originalBinder) { // overridden in other binders } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index 77fa07f7ce3d7..caded00d3be20 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -847,7 +847,7 @@ protected NamespaceOrTypeOrAliasSymbolWithAnnotations BindNonGenericSimpleNamesp { return TypeWithAnnotations.Create(new ExtendedErrorTypeSymbol( Compilation.Assembly.GlobalNamespace, identifierValueText, 0, - new CSDiagnosticInfo(ErrorCode.ERR_SingleTypeNameNotFound))); + new CSDiagnosticInfo(ErrorCode.ERR_SingleTypeNameNotFound, identifierValueText))); } var errorResult = CreateErrorIfLookupOnTypeParameter(node.Parent, qualifierOpt, identifierValueText, 0, diagnostics); @@ -2337,7 +2337,7 @@ private CSDiagnosticInfo NotFound(SyntaxNode where, string simpleName, int arity { Debug.Assert(aliasOpt == null || aliasOpt == SyntaxFacts.GetText(SyntaxKind.GlobalKeyword)); return (object)forwardedToAssembly == null - ? diagnostics.Add(ErrorCode.ERR_GlobalSingleTypeNameNotFound, location, whereText, qualifierOpt) + ? diagnostics.Add(ErrorCode.ERR_GlobalSingleTypeNameNotFound, location, whereText) : diagnostics.Add(ErrorCode.ERR_GlobalSingleTypeNameNotFoundFwd, location, whereText, forwardedToAssembly); } else @@ -2419,6 +2419,26 @@ protected AssemblySymbol GetForwardedToAssembly(string fullName, BindingDiagnost return null; } + internal static ContextualAttributeBinder TryGetContextualAttributeBinder(Binder binder) + { + if ((binder.Flags & BinderFlags.InContextualAttributeBinder) != 0) + { + do + { + if (binder is ContextualAttributeBinder contextualAttributeBinder) + { + return contextualAttributeBinder; + } + + binder = binder.Next; + } + while (binder != null); + Debug.Assert(false); + } + + return null; + } + /// /// Look for a type forwarder for the given type in the containing assembly and any referenced assemblies. /// @@ -2442,28 +2462,10 @@ protected AssemblySymbol GetForwardedToAssembly(string name, int arity, ref Name // might require us to examine types forwarded by this assembly, thus binding assembly level // attributes again. And the cycle continues. // So, we won't do the analysis in this case, at the expense of better diagnostics. - if ((this.Flags & BinderFlags.InContextualAttributeBinder) != 0) + var contextualAttributeBinder = TryGetContextualAttributeBinder(this); + if (contextualAttributeBinder is { AttributeTarget: { Kind: SymbolKind.Assembly } }) { - var current = this; - - do - { - var contextualAttributeBinder = current as ContextualAttributeBinder; - - if (contextualAttributeBinder != null) - { - if ((object)contextualAttributeBinder.AttributeTarget != null && - contextualAttributeBinder.AttributeTarget.Kind == SymbolKind.Assembly) - { - return null; - } - - break; - } - - current = current.Next; - } - while (current != null); + return null; } // NOTE: This won't work if the type isn't using CLS-style generic naming (i.e. `arity), but this code is diff --git a/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs b/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs index 5c78fd6bb40a3..9c3a274d28542 100644 --- a/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs @@ -53,6 +53,8 @@ internal override QuickAttributeChecker QuickAttributeChecker internal override uint LocalScopeDepth => Binder.ExternalScope; protected override bool InExecutableBinder => false; + protected override SyntaxNode? EnclosingNameofArgument => null; + internal override bool IsInsideNameof => false; internal override bool IsAccessibleHelper(Symbol symbol, TypeSymbol accessThroughType, out bool failedThroughTypeCheck, ref CompoundUseSiteInfo useSiteInfo, ConsList basesBeingResolved) { diff --git a/src/Compilers/CSharp/Portable/Binder/ContextualAttributeBinder.cs b/src/Compilers/CSharp/Portable/Binder/ContextualAttributeBinder.cs index 65e10bfc1fcf8..26afb3c266367 100644 --- a/src/Compilers/CSharp/Portable/Binder/ContextualAttributeBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ContextualAttributeBinder.cs @@ -4,6 +4,8 @@ #nullable disable +using System.Diagnostics; + namespace Microsoft.CodeAnalysis.CSharp { /// @@ -11,6 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp /// might have a CallerMemberName parameter, we need to keep track of which method/property/event /// the attribute is on/in (e.g. on a parameter) so that we can use the name of that member as the /// CallerMemberName argument. + /// This binder is also needed when a introduces type parameters to a scope within an attribute. /// internal sealed class ContextualAttributeBinder : Binder { @@ -22,6 +25,7 @@ internal sealed class ContextualAttributeBinder : Binder public ContextualAttributeBinder(Binder enclosing, Symbol symbol) : base(enclosing, enclosing.Flags | BinderFlags.InContextualAttributeBinder) { + Debug.Assert(symbol is not null); _attributeTarget = symbol; _attributedMember = GetAttributedMember(symbol); } diff --git a/src/Compilers/CSharp/Portable/Binder/HostObjectModeBinder.cs b/src/Compilers/CSharp/Portable/Binder/HostObjectModeBinder.cs index 251c55b23f0bb..c4b2f84eaa3ce 100644 --- a/src/Compilers/CSharp/Portable/Binder/HostObjectModeBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/HostObjectModeBinder.cs @@ -49,7 +49,7 @@ internal override void LookupSymbolsInSingleBinder( } } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { var hostObjectType = GetHostObjectType(); if (hostObjectType.Kind != SymbolKind.ErrorType) diff --git a/src/Compilers/CSharp/Portable/Binder/Imports.cs b/src/Compilers/CSharp/Portable/Binder/Imports.cs index e9fe2d7767f0d..232d9831ea704 100644 --- a/src/Compilers/CSharp/Portable/Binder/Imports.cs +++ b/src/Compilers/CSharp/Portable/Binder/Imports.cs @@ -146,6 +146,8 @@ internal static NamespaceSymbol ExpandPreviousSubmissionNamespace(NamespaceSymbo return expandedNamespace; } + public bool IsEmpty => UsingAliases.IsEmpty && Usings.IsEmpty && ExternAliases.IsEmpty; + public static Imports Create( ImmutableDictionary usingAliases, ImmutableArray usings, diff --git a/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs b/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs index 0b8dfac37b64d..771bfb4afaa8b 100644 --- a/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InContainerBinder.cs @@ -128,7 +128,7 @@ internal override void LookupSymbolsInSingleBinder( } } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { this.AddMemberLookupSymbolsInfo(result, _container, options, originalBinder); } diff --git a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs index 8ec045e2d99ee..0c10b8863d4ac 100644 --- a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs @@ -221,7 +221,7 @@ internal override void LookupSymbolsInSingleBinder( } } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { if (options.CanConsiderMembers()) { diff --git a/src/Compilers/CSharp/Portable/Binder/InSubmissionClassBinder.cs b/src/Compilers/CSharp/Portable/Binder/InSubmissionClassBinder.cs index 472da5ace795c..83015b6f6ea20 100644 --- a/src/Compilers/CSharp/Portable/Binder/InSubmissionClassBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InSubmissionClassBinder.cs @@ -52,7 +52,7 @@ internal override void LookupSymbolsInSingleBinder( this.LookupMembersInSubmissions(result, (NamedTypeSymbol)Container, _declarationSyntax, _inUsings, name, arity, basesBeingResolved, options, originalBinder, diagnose, ref useSiteInfo); } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { this.AddMemberLookupSymbolsInfoInSubmissions(result, (NamedTypeSymbol)Container, _inUsings, options, originalBinder); } diff --git a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs index d2a83280e672e..bb8c6252f9b3b 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs @@ -23,7 +23,7 @@ namespace Microsoft.CodeAnalysis.CSharp /// analyzed. /// /// For reasons of lifetime management, this type is distinct from the BinderFactory - /// which also creates a map from CSharpSyntaxNode to Binder. That type owns it's binders + /// which also creates a map from CSharpSyntaxNode to Binder. That type owns its binders /// and that type's lifetime is that of the compilation. Therefore we do not store /// binders local to method bodies in that type's cache. /// @@ -199,6 +199,123 @@ public override void VisitOperatorDeclaration(OperatorDeclarationSyntax node) Visit(node.ExpressionBody); } +#nullable enable + public override void VisitInvocationExpression(InvocationExpressionSyntax node) + { + if (node.MayBeNameofOperator()) + { + var oldEnclosing = _enclosing; + + WithTypeParametersBinder? withTypeParametersBinder; + WithParametersBinder? withParametersBinder; + // The LangVer check will be removed before shipping .NET 7. + // Tracked by https://github.com/dotnet/roslyn/issues/60640 + if (((_enclosing.Flags & BinderFlags.InContextualAttributeBinder) != 0) && _enclosing.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureExtendedNameofScope)) + { + var attributeTarget = getAttributeTarget(_enclosing); + withTypeParametersBinder = getExtraWithTypeParametersBinder(_enclosing, attributeTarget); + withParametersBinder = getExtraWithParametersBinder(_enclosing, attributeTarget); + } + else + { + withTypeParametersBinder = null; + withParametersBinder = null; + } + + var argumentExpression = node.ArgumentList.Arguments[0].Expression; + var possibleNameofBinder = new NameofBinder(argumentExpression, _enclosing, withTypeParametersBinder, withParametersBinder); + AddToMap(node, possibleNameofBinder); + + _enclosing = possibleNameofBinder; + base.VisitInvocationExpression(node); + _enclosing = oldEnclosing; + return; + } + + base.VisitInvocationExpression(node); + return; + + static Symbol getAttributeTarget(Binder current) + { + Debug.Assert((current.Flags & BinderFlags.InContextualAttributeBinder) != 0); + var contextualAttributeBinder = Binder.TryGetContextualAttributeBinder(current); + + Debug.Assert(contextualAttributeBinder is not null); + return contextualAttributeBinder.AttributeTarget; + } + + static WithTypeParametersBinder? getExtraWithTypeParametersBinder(Binder enclosing, Symbol target) + => target.Kind == SymbolKind.Method ? new WithMethodTypeParametersBinder((MethodSymbol)target, enclosing) : null; + + // We're bringing parameters in scope inside `nameof` in attributes on methods, their type parameters and parameters. + // This also applies to local functions, lambdas, indexers and delegates. + static WithParametersBinder? getExtraWithParametersBinder(Binder enclosing, Symbol target) + { + var parameters = target switch + { + SourcePropertyAccessorSymbol { MethodKind: MethodKind.PropertySet } setter => getSetterParameters(setter), + MethodSymbol methodSymbol => methodSymbol.Parameters, + ParameterSymbol parameter => getAllParameters(parameter), + TypeParameterSymbol typeParameter => getMethodParametersFromTypeParameter(typeParameter), + PropertySymbol property => property.Parameters, + NamedTypeSymbol namedType when namedType.IsDelegateType() => getDelegateParameters(namedType), + _ => default + }; + + return parameters.IsDefaultOrEmpty + ? null + : new WithParametersBinder(parameters, enclosing); + } + + static ImmutableArray getAllParameters(ParameterSymbol parameter) + { + switch (parameter.ContainingSymbol) + { + case MethodSymbol method: + return method.Parameters; + case PropertySymbol property: + return property.Parameters; + default: + Debug.Assert(false); + return default; + } + } + + static ImmutableArray getMethodParametersFromTypeParameter(TypeParameterSymbol typeParameter) + { + switch (typeParameter.ContainingSymbol) + { + case MethodSymbol method: + return method.Parameters; + case NamedTypeSymbol namedType when namedType.IsDelegateType(): + return getDelegateParameters(namedType); + default: + Debug.Assert(false); + return default; + } + } + + static ImmutableArray getDelegateParameters(NamedTypeSymbol delegateType) + { + Debug.Assert(delegateType.IsDelegateType()); + if (delegateType.DelegateInvokeMethod is { } invokeMethod) + { + return invokeMethod.Parameters; + } + + Debug.Assert(false); + return default; + } + + static ImmutableArray getSetterParameters(SourcePropertyAccessorSymbol setter) + { + var parameters = setter.Parameters; + Debug.Assert(parameters[^1] is SynthesizedAccessorValueParameterSymbol); + return parameters.RemoveAt(parameters.Length - 1); + } + } +#nullable disable + public override void VisitSimpleLambdaExpression(SimpleLambdaExpressionSyntax node) { VisitLambdaExpression(node); diff --git a/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs b/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs index 27e1d8fdc4376..db889a51721ba 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalScopeBinder.cs @@ -445,7 +445,7 @@ internal override void LookupSymbolsInSingleBinder( } } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { Debug.Assert(options.AreValid()); diff --git a/src/Compilers/CSharp/Portable/Binder/NameofBinder.cs b/src/Compilers/CSharp/Portable/Binder/NameofBinder.cs index c9a3e232f0fcb..9e24e3d374abf 100644 --- a/src/Compilers/CSharp/Portable/Binder/NameofBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/NameofBinder.cs @@ -2,19 +2,95 @@ // 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 Microsoft.CodeAnalysis.CSharp.Symbols; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp { + /// + /// If a proper method named "nameof" exists in the outer scopes, is false and this binder does nothing. + /// Otherwise, it relaxes the instance-vs-static requirement for top-level member access expressions + /// and when inside an attribute on a method it adds type parameters from the target of that attribute. + /// To do so, it works together with . + /// + /// For other attributes (on types, type parameters or parameters) we use a WithTypeParameterBinder directly + /// in the binder chain and some filtering () to keep + /// pre-existing behavior. + /// internal sealed class NameofBinder : Binder { private readonly SyntaxNode _nameofArgument; + private readonly WithTypeParametersBinder? _withTypeParametersBinder; + private readonly WithParametersBinder? _withParametersBinder; + private ThreeState _lazyIsNameofOperator; - public NameofBinder(SyntaxNode nameofArgument, Binder next) : base(next) + internal NameofBinder(SyntaxNode nameofArgument, Binder next, WithTypeParametersBinder? withTypeParametersBinder, WithParametersBinder? withParametersBinder) + : base(next) { _nameofArgument = nameofArgument; + _withTypeParametersBinder = withTypeParametersBinder; + _withParametersBinder = withParametersBinder; } - protected override SyntaxNode EnclosingNameofArgument => _nameofArgument; + private bool IsNameofOperator + { + get + { + if (!_lazyIsNameofOperator.HasValue()) + { + _lazyIsNameofOperator = ThreeStateHelpers.ToThreeState(!NextRequired.InvocableNameofInScope()); + } + + return _lazyIsNameofOperator.Value(); + } + } + + internal override bool IsInsideNameof => IsNameofOperator || base.IsInsideNameof; + + protected override SyntaxNode? EnclosingNameofArgument => IsNameofOperator ? _nameofArgument : base.EnclosingNameofArgument; + + internal override void LookupSymbolsInSingleBinder(LookupResult result, string name, int arity, ConsList basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref CompoundUseSiteInfo useSiteInfo) + { + bool foundParameter = false; + if (_withParametersBinder is not null && IsNameofOperator) + { + _withParametersBinder.LookupSymbolsInSingleBinder(result, name, arity, basesBeingResolved, options, originalBinder, diagnose, ref useSiteInfo); + if (!result.IsClear) + { + if (result.IsMultiViable) + { + return; + } + + foundParameter = true; + } + } + + if (_withTypeParametersBinder is not null && IsNameofOperator) + { + if (foundParameter) + { + var tmp = LookupResult.GetInstance(); + _withTypeParametersBinder.LookupSymbolsInSingleBinder(tmp, name, arity, basesBeingResolved, options, originalBinder, diagnose, ref useSiteInfo); + result.MergeEqual(tmp); + } + else + { + _withTypeParametersBinder.LookupSymbolsInSingleBinder(result, name, arity, basesBeingResolved, options, originalBinder, diagnose, ref useSiteInfo); + } + } + } + + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo info, LookupOptions options, Binder originalBinder) + { + if (_withParametersBinder is not null && IsNameofOperator) + { + _withParametersBinder.AddLookupSymbolsInfoInSingleBinder(info, options, originalBinder); + } + if (_withTypeParametersBinder is not null && IsNameofOperator) + { + _withTypeParametersBinder.AddLookupSymbolsInfoInSingleBinder(info, options, originalBinder); + } + } } } diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs index 7f19e89f285b8..69f7139b05861 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs @@ -102,7 +102,9 @@ internal void BinaryOperatorOverloadResolution_NoEasyOut( } } - if ((object)rightOperatorSourceOpt != null && !rightSourceIsInterface && !rightOperatorSourceOpt.Equals(leftOperatorSourceOpt)) + bool isShift = kind.IsShift(); + + if (!isShift && (object)rightOperatorSourceOpt != null && !rightSourceIsInterface && !rightOperatorSourceOpt.Equals(leftOperatorSourceOpt)) { var rightOperators = ArrayBuilder.GetInstance(); if (GetUserDefinedOperators(kind, isChecked, rightOperatorSourceOpt, left, right, rightOperators, ref useSiteInfo)) @@ -130,7 +132,7 @@ internal void BinaryOperatorOverloadResolution_NoEasyOut( // Always start lookup from a type parameter. This ensures that regardless of the order we always pick up constrained type for // each distinct candidate operator. - if (leftOperatorSourceOpt is null || (leftOperatorSourceOpt is not TypeParameterSymbol && rightOperatorSourceOpt is TypeParameterSymbol)) + if (!isShift && (leftOperatorSourceOpt is null || (leftOperatorSourceOpt is not TypeParameterSymbol && rightOperatorSourceOpt is TypeParameterSymbol))) { firstOperatorSourceOpt = rightOperatorSourceOpt; secondOperatorSourceOpt = leftOperatorSourceOpt; @@ -152,7 +154,7 @@ internal void BinaryOperatorOverloadResolution_NoEasyOut( result.Results.Clear(); } - if ((object)secondOperatorSourceOpt != null && !secondOperatorSourceOpt.Equals(firstOperatorSourceOpt)) + if (!isShift && (object)secondOperatorSourceOpt != null && !secondOperatorSourceOpt.Equals(firstOperatorSourceOpt)) { var rightOperators = ArrayBuilder.GetInstance(); if (GetUserDefinedBinaryOperatorsFromInterfaces(kind, isChecked, diff --git a/src/Compilers/CSharp/Portable/Binder/WithClassTypeParametersBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithClassTypeParametersBinder.cs index ddae06b296cfc..a073d882d9a94 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithClassTypeParametersBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithClassTypeParametersBinder.cs @@ -49,7 +49,7 @@ protected override MultiDictionary TypeParameterMap } } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { if (CanConsiderTypeParameters(options)) { diff --git a/src/Compilers/CSharp/Portable/Binder/WithCrefTypeParametersBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithCrefTypeParametersBinder.cs index a476f3ed7a97d..92a84b73a5f3f 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithCrefTypeParametersBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithCrefTypeParametersBinder.cs @@ -136,7 +136,7 @@ private static void AddTypeParameters(GenericNameSyntax genericNameSyntax, Multi } } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { if (CanConsiderTypeParameters(options)) { diff --git a/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs index c3c00349f6659..0b7fb480bbb8e 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs @@ -47,7 +47,7 @@ internal override void LookupSymbolsInSingleBinder( ref useSiteInfo); } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { // If we are looking only for labels we do not need to search through the imports. if ((options & LookupOptions.LabelsOnly) == 0) diff --git a/src/Compilers/CSharp/Portable/Binder/WithExternAndUsingAliasesBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithExternAndUsingAliasesBinder.cs index e9be64e2660ac..d1e64860628b2 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithExternAndUsingAliasesBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithExternAndUsingAliasesBinder.cs @@ -51,7 +51,7 @@ internal override void LookupSymbolsInSingleBinder( ref useSiteInfo); } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { // If we are looking only for labels we do not need to search through the imports. if ((options & LookupOptions.LabelsOnly) == 0) diff --git a/src/Compilers/CSharp/Portable/Binder/WithLambdaParametersBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithLambdaParametersBinder.cs index 1db796a46d6db..b28e449da0b11 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithLambdaParametersBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithLambdaParametersBinder.cs @@ -99,7 +99,7 @@ internal override void LookupSymbolsInSingleBinder( } } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { if (options.CanConsiderMembers()) { diff --git a/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs index 954f22dce602a..f72176050939d 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs @@ -61,7 +61,7 @@ protected override LookupOptions LookupMask } } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { if (CanConsiderTypeParameters(options)) { diff --git a/src/Compilers/CSharp/Portable/Binder/WithParametersBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithParametersBinder.cs index e941c8641fa39..deac5a964225e 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithParametersBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithParametersBinder.cs @@ -14,7 +14,8 @@ namespace Microsoft.CodeAnalysis.CSharp { /// /// Binder used to place the parameters of a method, property, indexer, or delegate - /// in scope when binding <param> tags inside of XML documentation comments. + /// in scope when binding <param> tags inside of XML documentation comments + /// and `nameof` in certain attribute positions. /// internal sealed class WithParametersBinder : Binder { @@ -27,7 +28,7 @@ internal WithParametersBinder(ImmutableArray parameters, Binder _parameters = parameters; } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { if (options.CanConsiderLocals()) { diff --git a/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs index 7f0159118b522..ce5904372e617 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs @@ -193,7 +193,7 @@ private static bool IsValidLookupCandidateInUsings(Symbol symbol) return true; } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { // If we are looking only for labels we do not need to search through the imports. if ((options & LookupOptions.LabelsOnly) == 0) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 5150812adf15b..2db2cf928bb1b 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -1704,7 +1704,7 @@ If such a class is used as a base class and if the deriving class defines a dest One of the parameters of a binary operator must be the containing type - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + The first operand of an overloaded shift operator must have the same type as the containing type Conversion, equality, or inequality operators declared in interfaces must be abstract @@ -6446,7 +6446,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Cannot use '{0}' as a calling convention modifier. - Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{1}'. Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -6926,7 +6926,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ One of the parameters of a binary operator must be the containing type, or its type parameter constrained to it. - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it A static abstract interface member can be accessed only on a type parameter. @@ -7113,13 +7113,13 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The operator '{0}' requires a matching non-checked version of the operator to also be defined - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} - Utf8 String Literals + UTF-8 string literals - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. @@ -7130,4 +7130,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ unsigned right shift + + relaxed shift operator + diff --git a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs index bddf333acf395..034a0f560e022 100644 --- a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs +++ b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs @@ -956,7 +956,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar } else if (newWarningLevel < 0) { - AddDiagnostic(diagnostics, ErrorCode.ERR_BadWarningLevel, name); + AddDiagnostic(diagnostics, ErrorCode.ERR_BadWarningLevel); } else { @@ -1947,7 +1947,7 @@ private static void ParseAssemblyReferences(string arg, ReadOnlyMemory? va if (pathCount > 1) { commandLineReferences.RemoveRange(commandLineReferences.Count - pathCount, pathCount); - AddDiagnostic(diagnostics, ErrorCode.ERR_OneAliasPerReference, value.ToString()); + AddDiagnostic(diagnostics, ErrorCode.ERR_OneAliasPerReference); return; } diff --git a/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs index ccadc076c3bc8..c6b787d323405 100644 --- a/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/AttributeSemanticModel.cs @@ -35,8 +35,9 @@ private AttributeSemanticModel( /// /// Creates an AttributeSemanticModel that allows asking semantic questions about an attribute node. /// - public static AttributeSemanticModel Create(SyntaxTreeSemanticModel containingSemanticModel, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Binder rootBinder, ImmutableDictionary parentRemappedSymbolsOpt) + public static AttributeSemanticModel Create(SyntaxTreeSemanticModel containingSemanticModel, AttributeSyntax syntax, NamedTypeSymbol attributeType, AliasSymbol aliasOpt, Symbol? attributeTarget, Binder rootBinder, ImmutableDictionary parentRemappedSymbolsOpt) { + rootBinder = attributeTarget is null ? rootBinder : new ContextualAttributeBinder(rootBinder, attributeTarget); return new AttributeSemanticModel(syntax, attributeType, aliasOpt, rootBinder, containingSemanticModel, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt); } @@ -48,7 +49,6 @@ public static AttributeSemanticModel CreateSpeculative(SyntaxTreeSemanticModel p Debug.Assert(parentSemanticModel != null); Debug.Assert(rootBinder != null); Debug.Assert(rootBinder.IsSemanticModelBinder); - return new AttributeSemanticModel(syntax, attributeType, aliasOpt, rootBinder, parentSemanticModelOpt: parentSemanticModel, parentRemappedSymbolsOpt: parentRemappedSymbolsOpt, speculatedPosition: position); } diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 295490a45d495..6b032756ae39e 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -1836,7 +1836,7 @@ bool checkValid(MethodSymbol candidate, bool isCandidate, BindingDiagnosticBag s { if (candidate.IsAsync) { - diagnostics.Add(ErrorCode.ERR_NonTaskMainCantBeAsync, candidate.Locations.First(), candidate); + diagnostics.Add(ErrorCode.ERR_NonTaskMainCantBeAsync, candidate.Locations.First()); } else { diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs index 4abb70effa8fb..8568d088e4512 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs @@ -1599,9 +1599,10 @@ private ImmutableArray LookupSymbolsInternal( // Method type parameters are not in scope outside a method // body unless the position is either: // a) in a type-only context inside an expression, or - // b) inside of an XML name attribute in an XML doc comment. + // b) inside of an XML name attribute in an XML doc comment, + // c) inside a nameof context. var parentExpr = token.Parent as ExpressionSyntax; - if (parentExpr != null && !(parentExpr.Parent is XmlNameAttributeSyntax) && !SyntaxFacts.IsInTypeOnlyContext(parentExpr)) + if (parentExpr != null && !(parentExpr.Parent is XmlNameAttributeSyntax) && !SyntaxFacts.IsInTypeOnlyContext(parentExpr) && !binder.IsInsideNameof) { options |= LookupOptions.MustNotBeMethodTypeParameter; } @@ -5288,6 +5289,32 @@ protected sealed override ISymbol GetEnclosingSymbolCore(int position, Cancellat return this.GetEnclosingSymbol(position, cancellationToken); } + private protected sealed override ImmutableArray GetImportScopesCore(int position, CancellationToken cancellationToken) + { + position = CheckAndAdjustPosition(position); + var binder = GetEnclosingBinder(position); + var builder = ArrayBuilder.GetInstance(); + + for (var chain = binder?.ImportChain; chain != null; chain = chain.ParentOpt) + { + var imports = chain.Imports; + if (imports.IsEmpty) + continue; + + Debug.Assert(imports.Usings.All(static u => u.UsingDirectiveReference != null)); + + // Try to create a node corresponding to the imports of the next higher binder scope. Then create the + // node corresponding to this set of imports and chain it to that. + builder.Add(new SimpleImportScope( + imports.UsingAliases.SelectAsArray(static kvp => kvp.Value.Alias.GetPublicSymbol()), + imports.ExternAliases.SelectAsArray(static e => e.Alias.GetPublicSymbol()), + imports.Usings.SelectAsArray(static n => new ImportedNamespaceOrType(n.NamespaceOrType.GetPublicSymbol(), n.UsingDirectiveReference)), + xmlNamespaces: ImmutableArray.Empty)); + } + + return builder.ToImmutableAndFree(); + } + protected sealed override bool IsAccessibleCore(int position, ISymbol symbol) { return this.IsAccessible(position, symbol.EnsureCSharpSymbolOrNull(nameof(symbol))); diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs index 98198b76f3647..a773d1fa4555a 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs @@ -336,6 +336,10 @@ private static Binder GetEnclosingBinderInternalWithinRoot(SyntaxNode node, int { binder = rootBinder.GetBinder(current); } + else if ((current is InvocationExpressionSyntax invocation) && invocation.MayBeNameofOperator()) + { + binder = rootBinder.GetBinder(current); + } else { // If this ever breaks, make sure that all callers of @@ -698,7 +702,7 @@ internal override LocalSymbol GetAdjustedLocalSymbol(SourceLocalSymbol local) return GetRemappedSymbol(local); } - private LocalFunctionSymbol GetDeclaredLocalFunction(LocalFunctionStatementSyntax declarationSyntax) + internal LocalFunctionSymbol GetDeclaredLocalFunction(LocalFunctionStatementSyntax declarationSyntax) { var originalSymbol = GetDeclaredLocalFunction(this.GetEnclosingBinder(GetAdjustedNodePosition(declarationSyntax)), declarationSyntax.Identifier); return GetRemappedSymbol(originalSymbol); @@ -1169,48 +1173,7 @@ public override SyntaxTree SyntaxTree return _guardedIOperationNodeMap.TryGetValue(node, out var operation) ? operation : null; } } -#nullable disable - - private CSharpSyntaxNode GetBindingRootOrInitializer(CSharpSyntaxNode node) - { - CSharpSyntaxNode bindingRoot = GetBindingRoot(node); - // if binding root is parameter, make it equal value - // we need to do this since node map doesn't contain bound node for parameter - if (bindingRoot is ParameterSyntax parameter && parameter.Default?.FullSpan.Contains(node.Span) == true) - { - return parameter.Default; - } - - // if binding root is field variable declarator, make it initializer - // we need to do this since node map doesn't contain bound node for field/event variable declarator - if (bindingRoot is VariableDeclaratorSyntax variableDeclarator && variableDeclarator.Initializer?.FullSpan.Contains(node.Span) == true) - { - if (variableDeclarator.Parent?.Parent.IsKind(SyntaxKind.FieldDeclaration) == true || - variableDeclarator.Parent?.Parent.IsKind(SyntaxKind.EventFieldDeclaration) == true) - { - return variableDeclarator.Initializer; - } - } - - // if binding root is enum member declaration, make it equal value - // we need to do this since node map doesn't contain bound node for enum member decl - if (bindingRoot is EnumMemberDeclarationSyntax enumMember && enumMember.EqualsValue?.FullSpan.Contains(node.Span) == true) - { - return enumMember.EqualsValue; - } - - // if binding root is property member declaration, make it equal value - // we need to do this since node map doesn't contain bound node for property initializer - if (bindingRoot is PropertyDeclarationSyntax propertyMember && propertyMember.Initializer?.FullSpan.Contains(node.Span) == true) - { - return propertyMember.Initializer; - } - - return bindingRoot; - } - -#nullable enable private IOperation GetRootOperation() { BoundNode highestBoundNode = GetBoundRoot(); @@ -2084,6 +2047,8 @@ internal ImmutableArray GetBoundNodes(CSharpSyntaxNode node) } Debug.Assert(node == GetBindableSyntaxNode(node)); + // Note: This nullability analysis can be distracting when debugging. This can be disabled with a feature flag in parse options: + // `.WithFeature("run-nullable-analysis", "never")` EnsureNullabilityAnalysisPerformedIfNecessary(); // We have one SemanticModel for each method. diff --git a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs index de7e69c328793..1d56e63bbf85e 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs @@ -1273,13 +1273,33 @@ private AttributeSemanticModel CreateModelForAttribute(Binder enclosingBinder, A AliasSymbol aliasOpt; var attributeType = (NamedTypeSymbol)enclosingBinder.BindType(attribute.Name, BindingDiagnosticBag.Discarded, out aliasOpt).Type; + // For attributes where a nameof could introduce some type parameters, we need to track the attribute target + Symbol attributeTarget = getAttributeTarget(attribute.Parent.Parent); + return AttributeSemanticModel.Create( this, attribute, attributeType, aliasOpt, + attributeTarget, enclosingBinder.WithAdditionalFlags(BinderFlags.AttributeArgument), containingModel?.GetRemappedSymbols()); + + Symbol getAttributeTarget(SyntaxNode targetSyntax) + { + return targetSyntax switch + { + BaseMethodDeclarationSyntax methodDeclaration => GetDeclaredMemberSymbol(methodDeclaration), + LocalFunctionStatementSyntax localFunction => GetMemberModel(localFunction)?.GetDeclaredLocalFunction(localFunction), + ParameterSyntax parameterSyntax => ((Symbols.PublicModel.ParameterSymbol)GetDeclaredSymbol(parameterSyntax)).UnderlyingSymbol, + TypeParameterSyntax typeParameterSyntax => ((Symbols.PublicModel.TypeParameterSymbol)GetDeclaredSymbol(typeParameterSyntax)).UnderlyingSymbol, + IndexerDeclarationSyntax indexerSyntax => ((Symbols.PublicModel.PropertySymbol)GetDeclaredSymbol(indexerSyntax)).UnderlyingSymbol, + AccessorDeclarationSyntax accessorSyntax => ((Symbols.PublicModel.MethodSymbol)GetDeclaredSymbol(accessorSyntax)).UnderlyingSymbol, + AnonymousFunctionExpressionSyntax anonymousFunction => ((Symbols.PublicModel.Symbol)GetSymbolInfo(anonymousFunction).Symbol).UnderlyingSymbol, + DelegateDeclarationSyntax delegateSyntax => ((Symbols.PublicModel.NamedTypeSymbol)GetDeclaredSymbol(delegateSyntax)).UnderlyingSymbol, + _ => null + }; + } } private FieldSymbol GetDeclaredFieldSymbol(VariableDeclaratorSyntax variableDecl) @@ -1683,6 +1703,7 @@ private string GetDeclarationName(CSharpSyntaxNode declaration) case SyntaxKind.ClassDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.RecordDeclaration: + case SyntaxKind.RecordStructDeclaration: return ((BaseTypeDeclarationSyntax)declaration).Identifier.ValueText; case SyntaxKind.VariableDeclarator: diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index f0075b5d483df..01417e526878e 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -255,6 +255,8 @@ internal enum MessageID IDS_FeatureUTF8StringLiterals = MessageBase + 12822, IDS_FeatureUnsignedRightShift = MessageBase + 12823, + IDS_FeatureExtendedNameofScope = MessageBase + 12824, + IDS_FeatureRelaxedShiftOperator = MessageBase + 12825, } // Message IDs may refer to strings that need to be localized. @@ -377,6 +379,8 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureCheckedUserDefinedOperators: // semantic check for declarations, parsing check for doc comments case MessageID.IDS_FeatureUTF8StringLiterals: // semantic check case MessageID.IDS_FeatureUnsignedRightShift: // semantic check for declarations and consumption, parsing check for doc comments + case MessageID.IDS_FeatureExtendedNameofScope: // semantic check + case MessageID.IDS_FeatureRelaxedShiftOperator: // semantic check return LanguageVersion.Preview; // C# 10.0 features. diff --git a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs index c718dbd8605e3..ce1e63afcb4c0 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs @@ -145,6 +145,21 @@ public override ReportDiagnostic GetDiagnosticReport(DiagnosticInfo diagnosticIn out hasPragmaSuppression); } +#if DEBUG + internal override bool ShouldAssertExpectedMessageArgumentsLength(int errorCode) + { + return (ErrorCode)errorCode switch + { + 0 => false, + ErrorCode.Unknown => false, + ErrorCode.Void => false, + ErrorCode.ERR_IdentifierExpectedKW => false, // message uses {1} rather than {0} + ErrorCode.WRN_XMLParseError => false, // XmlSyntaxDiagnosticInfo.GetMessage() uses distinct error code + _ => true + }; + } +#endif + public override int ERR_FailedToCreateTempFile => (int)ErrorCode.ERR_CantMakeTempFile; public override int ERR_MultipleAnalyzerConfigsInSameDir => (int)ErrorCode.ERR_MultipleAnalyzerConfigsInSameDir; diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs index 301d1093c7302..d26488e5948d7 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs @@ -59,7 +59,7 @@ internal static BoundStatement Rewrite( { bool containsAwait = AwaitDetector.ContainsAwait(bodyWithAwaitLifted); diagnostics.Add(containsAwait ? ErrorCode.ERR_PossibleAsyncIteratorWithoutYield : ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, - method.Locations[0], method.ReturnTypeWithAnnotations); + method.Locations[0]); stateMachineType = null; return bodyWithAwaitLifted; diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index a86716fe512a6..eb03258a61ac1 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -6667,7 +6667,7 @@ private NameSyntax ParseQualifiedNameRight( case SyntaxKind.ColonColonToken: if (left.Kind != SyntaxKind.IdentifierName) { - separator = this.AddError(separator, ErrorCode.ERR_UnexpectedAliasedName, separator.ToString()); + separator = this.AddError(separator, ErrorCode.ERR_UnexpectedAliasedName); } // If the left hand side is not an identifier name then the user has done @@ -9108,7 +9108,7 @@ private CommonForEachStatementSyntax ParseForEachStatement( if (this.CurrentToken.Kind == SyntaxKind.ForKeyword) { var skippedForToken = this.EatToken(); - skippedForToken = this.AddError(skippedForToken, ErrorCode.ERR_SyntaxError, SyntaxFacts.GetText(SyntaxKind.ForEachKeyword), SyntaxFacts.GetText(SyntaxKind.ForKeyword)); + skippedForToken = this.AddError(skippedForToken, ErrorCode.ERR_SyntaxError, SyntaxFacts.GetText(SyntaxKind.ForEachKeyword)); @foreach = ConvertToMissingWithTrailingTrivia(skippedForToken, SyntaxKind.ForEachKeyword); } else @@ -9980,7 +9980,7 @@ private void ParseDeclarationModifiers(SyntaxListBuilder list) else if (list.Any(mod.RawKind)) { // check for duplicates, can only be const - mod = this.AddError(mod, ErrorCode.ERR_TypeExpected, mod.Text); + mod = this.AddError(mod, ErrorCode.ERR_TypeExpected); } list.Add(mod); diff --git a/src/Compilers/CSharp/Portable/Parser/SyntaxParser.cs b/src/Compilers/CSharp/Portable/Parser/SyntaxParser.cs index 5fd2951f9c5b9..0d571c0fb58eb 100644 --- a/src/Compilers/CSharp/Portable/Parser/SyntaxParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/SyntaxParser.cs @@ -621,9 +621,13 @@ protected SyntaxToken EatContextualToken(SyntaxKind kind, bool reportError = tru protected virtual SyntaxDiagnosticInfo GetExpectedTokenError(SyntaxKind expected, SyntaxKind actual, int offset, int width) { var code = GetExpectedTokenErrorCode(expected, actual); - if (code == ErrorCode.ERR_SyntaxError || code == ErrorCode.ERR_IdentifierExpectedKW) + if (code == ErrorCode.ERR_SyntaxError) { - return new SyntaxDiagnosticInfo(offset, width, code, SyntaxFacts.GetText(expected), SyntaxFacts.GetText(actual)); + return new SyntaxDiagnosticInfo(offset, width, code, SyntaxFacts.GetText(expected)); + } + else if (code == ErrorCode.ERR_IdentifierExpectedKW) + { + return new SyntaxDiagnosticInfo(offset, width, code, /*unused*/string.Empty, SyntaxFacts.GetText(actual)); } else { diff --git a/src/Compilers/CSharp/Portable/Symbols/AliasSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AliasSymbol.cs index 35ede5f6be75e..f41c719dd5d8f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AliasSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AliasSymbol.cs @@ -127,7 +127,9 @@ public override ImmutableArray DeclaringSyntaxReferences { get { - return GetDeclaringSyntaxReferenceHelper(_locations); + return _isExtern + ? GetDeclaringSyntaxReferenceHelper(_locations) + : GetDeclaringSyntaxReferenceHelper(_locations); } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs index 31e2a49a854b4..fc2580001a927 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs @@ -1763,9 +1763,9 @@ internal sealed override bool IsInterface } } - private static ExtendedErrorTypeSymbol CyclicInheritanceError(PENamedTypeSymbol type, TypeSymbol declaredBase) + private static ExtendedErrorTypeSymbol CyclicInheritanceError(TypeSymbol declaredBase) { - var info = new CSDiagnosticInfo(ErrorCode.ERR_ImportedCircularBase, declaredBase, type); + var info = new CSDiagnosticInfo(ErrorCode.ERR_ImportedCircularBase, declaredBase); return new ExtendedErrorTypeSymbol(declaredBase, LookupResultKind.NotReferencable, info, true); } @@ -1781,7 +1781,7 @@ private NamedTypeSymbol MakeAcyclicBaseType() if (BaseTypeAnalysis.TypeDependsOn(declaredBase, this)) { - return CyclicInheritanceError(this, declaredBase); + return CyclicInheritanceError(declaredBase); } this.SetKnownToHaveNoDeclaredBaseCycles(); @@ -1798,7 +1798,7 @@ private ImmutableArray MakeAcyclicInterfaces() } return declaredInterfaces - .SelectAsArray(t => BaseTypeAnalysis.TypeDependsOn(t, this) ? CyclicInheritanceError(this, t) : t); + .SelectAsArray(t => BaseTypeAnalysis.TypeDependsOn(t, this) ? CyclicInheritanceError(t) : t); } public override string GetDocumentationCommentXml(CultureInfo preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default(CancellationToken)) diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs index d8109971d42d8..b0b09dc44586e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs @@ -255,9 +255,9 @@ internal override NamedTypeSymbol LookupMetadataType(ref MetadataTypeName typeNa return this.RetargetingTranslator.Retarget(_underlyingType.LookupMetadataType(ref typeName), RetargetOptions.RetargetPrimitiveTypesByName); } - private static ExtendedErrorTypeSymbol CyclicInheritanceError(RetargetingNamedTypeSymbol type, TypeSymbol declaredBase) + private static ExtendedErrorTypeSymbol CyclicInheritanceError(TypeSymbol declaredBase) { - var info = new CSDiagnosticInfo(ErrorCode.ERR_ImportedCircularBase, declaredBase, type); + var info = new CSDiagnosticInfo(ErrorCode.ERR_ImportedCircularBase, declaredBase); return new ExtendedErrorTypeSymbol(declaredBase, LookupResultKind.NotReferencable, info, true); } @@ -281,7 +281,7 @@ internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics if ((object)acyclicBase != null && BaseTypeAnalysis.TypeDependsOn(acyclicBase, this)) { - return CyclicInheritanceError(this, acyclicBase); + return CyclicInheritanceError(acyclicBase); } Interlocked.CompareExchange(ref _lazyBaseType, acyclicBase, ErrorTypeSymbol.UnknownResultType); @@ -303,7 +303,7 @@ internal override ImmutableArray InterfacesNoUseSiteDiagnostics } ImmutableArray result = declaredInterfaces - .SelectAsArray(t => BaseTypeAnalysis.TypeDependsOn(t, this) ? CyclicInheritanceError(this, t) : t); + .SelectAsArray(t => BaseTypeAnalysis.TypeDependsOn(t, this) ? CyclicInheritanceError(t) : t); ImmutableInterlocked.InterlockedCompareExchange(ref _lazyInterfaces, result, default(ImmutableArray)); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs index da07913a6e0dd..c3dffe96baddf 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs @@ -181,7 +181,7 @@ internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArgu if (this.IsStatic || this.IsConst) { // CS0637: The FieldOffset attribute is not allowed on static or const fields - diagnostics.Add(ErrorCode.ERR_StructOffsetOnBadField, arguments.AttributeSyntaxOpt.Name.Location, arguments.AttributeSyntaxOpt.GetErrorDisplayName()); + diagnostics.Add(ErrorCode.ERR_StructOffsetOnBadField, arguments.AttributeSyntaxOpt.Name.Location); } else { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs index accc895e7d4e0..4483be36fdfbe 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs @@ -55,11 +55,11 @@ internal SourceDestructorSymbol( if (containingType.IsStatic) { - diagnostics.Add(ErrorCode.ERR_DestructorInStaticClass, location, this); + diagnostics.Add(ErrorCode.ERR_DestructorInStaticClass, location); } else if (!containingType.IsReferenceType) { - diagnostics.Add(ErrorCode.ERR_OnlyClassesCanContainDestructors, location, this); + diagnostics.Add(ErrorCode.ERR_OnlyClassesCanContainDestructors, location); } CheckForBlockAndExpressionBody( diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index 938d9c6dc393c..7f62bbe43c20d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -1470,7 +1470,7 @@ internal override void PostDecodeWellKnownAttributes(ImmutableArray> MakeOneDeclaredB if (this.IsStatic) { // '{0}': static classes cannot implement interfaces - diagnostics.Add(ErrorCode.ERR_StaticClassInterfaceImpl, location, this, baseType); + diagnostics.Add(ErrorCode.ERR_StaticClassInterfaceImpl, location, this); } if (this.IsRefLikeType) { // '{0}': ref structs cannot implement interfaces - diagnostics.Add(ErrorCode.ERR_RefStructInterfaceImpl, location, this, baseType); + diagnostics.Add(ErrorCode.ERR_RefStructInterfaceImpl, location, this); } if (baseType.ContainsDynamic()) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index 1cda7689fda72..4bd404d9feb3f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -454,8 +454,14 @@ private TypeWithAnnotations ComputeType(Binder binder, SyntaxNode syntax, Bindin if (type.IsVoidType()) { - ErrorCode errorCode = this.IsIndexer ? ErrorCode.ERR_IndexerCantHaveVoidType : ErrorCode.ERR_PropertyCantHaveVoidType; - diagnostics.Add(errorCode, Location, this); + if (this.IsIndexer) + { + diagnostics.Add(ErrorCode.ERR_IndexerCantHaveVoidType, Location); + } + else + { + diagnostics.Add(ErrorCode.ERR_PropertyCantHaveVoidType, Location, this); + } } return type; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 0d8dba89b0121..bb0698c25979a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -271,11 +271,11 @@ private void CheckInitializer( { if (isInterface && !isStatic) { - diagnostics.Add(ErrorCode.ERR_InstancePropertyInitializerInInterface, location, this); + diagnostics.Add(ErrorCode.ERR_InstancePropertyInitializerInInterface, location); } else if (!isAutoProperty) { - diagnostics.Add(ErrorCode.ERR_InitializerOnNonAutoProperty, location, this); + diagnostics.Add(ErrorCode.ERR_InitializerOnNonAutoProperty, location); } } @@ -699,13 +699,13 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, if (this.RefKind != RefKind.None) { - diagnostics.Add(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, Location, this); + diagnostics.Add(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, Location); } // get-only auto property should not override settable properties if (SetMethod is null && !this.IsReadOnly) { - diagnostics.Add(ErrorCode.ERR_AutoPropertyMustOverrideSet, Location, this); + diagnostics.Add(ErrorCode.ERR_AutoPropertyMustOverrideSet, Location); } } @@ -721,7 +721,7 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, if (_refKind != RefKind.None) { - diagnostics.Add(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, _setMethod.Locations[0], _setMethod); + diagnostics.Add(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, _setMethod.Locations[0]); } else if ((_getMethod.LocalAccessibility != Accessibility.NotApplicable) && (_setMethod.LocalAccessibility != Accessibility.NotApplicable)) @@ -750,12 +750,12 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, { if (!hasGetAccessor) { - diagnostics.Add(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, Location, this); + diagnostics.Add(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, Location); } } else if (!hasGetAccessor && IsAutoProperty) { - diagnostics.Add(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, _setMethod!.Locations[0], _setMethod); + diagnostics.Add(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, _setMethod!.Locations[0]); } if (!this.IsOverride) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs index f43baa583a45d..3142706b07fc4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs @@ -677,17 +677,20 @@ private bool IsSelfConstrainedTypeParameter(TypeSymbol type) private void CheckShiftSignature(BindingDiagnosticBag diagnostics) { // SPEC: A binary <<, >> or >>> operator must take two parameters, the first - // SPEC: of which must have type T or T? and the second of which must - // SPEC: have type int or int?, and can return any type. + // SPEC: of which must have type T or T?, the second of which can + // SPEC: have any type. The operator can return any type. - if (!MatchesContainingType(this.GetParameterType(0).StrippedType()) || - this.GetParameterType(1).StrippedType().SpecialType != SpecialType.System_Int32) + if (!MatchesContainingType(this.GetParameterType(0).StrippedType())) { // CS0546: The first operand of an overloaded shift operator must have the - // same type as the containing type, and the type of the second - // operand must be int + // same type as the containing type diagnostics.Add(IsAbstract ? ErrorCode.ERR_BadAbstractShiftOperatorSignature : ErrorCode.ERR_BadShiftOperatorSignature, this.Locations[0]); } + else if (this.GetParameterType(1).StrippedType().SpecialType != SpecialType.System_Int32) + { + var location = this.Locations[0]; + Binder.CheckFeatureAvailability(location.SourceTree, MessageID.IDS_FeatureRelaxedShiftOperator, diagnostics, location); + } if (this.ReturnsVoid) { diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs index a060593078b12..e85e235ff9d0b 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs @@ -49,6 +49,22 @@ public static bool IsQuery(this SyntaxNode syntax) } } + internal static bool MayBeNameofOperator(this InvocationExpressionSyntax node) + { + if (node.Expression.Kind() == SyntaxKind.IdentifierName && + ((IdentifierNameSyntax)node.Expression).Identifier.ContextualKind() == SyntaxKind.NameOfKeyword && + node.ArgumentList.Arguments.Count == 1) + { + ArgumentSyntax argument = node.ArgumentList.Arguments[0]; + if (argument.NameColon == null && argument.RefOrOutKeyword == default) + { + return true; + } + } + + return false; + } + /// /// This method is used to keep the code that generates binders in sync /// with the code that searches for binders. We don't want the searcher @@ -63,6 +79,8 @@ internal static bool CanHaveAssociatedLocalBinder(this SyntaxNode syntax) SyntaxKind kind = syntax.Kind(); switch (kind) { + case SyntaxKind.InvocationExpression when ((InvocationExpressionSyntax)syntax).MayBeNameofOperator(): + return true; case SyntaxKind.CatchClause: case SyntaxKind.ParenthesizedLambdaExpression: case SyntaxKind.SimpleLambdaExpression: @@ -89,7 +107,6 @@ internal static bool CanHaveAssociatedLocalBinder(this SyntaxNode syntax) default: return syntax is StatementSyntax || IsValidScopeDesignator(syntax as ExpressionSyntax); - } } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 75671ed63c549..7bf2d09a42d16 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - První operand přetěžovaného operátoru shift musí být stejného typu jako obsahující typ nebo jeho parametr typu omezený na něj a druhý operand musí být typu int. + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + První operand přetěžovaného operátoru shift musí být stejného typu jako obsahující typ nebo jeho parametr typu omezený na něj a druhý operand musí být typu int. @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - Skupina &metody {0} se nedá převést na typ delegáta {0}. + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ struktury záznamů 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5921,8 +5926,8 @@ Pokud se taková třída používá jako základní třída a pokud odvozující - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - První operand přetěžovaného operátoru shift musí být stejného typu jako obsahující typ a druhý operand musí být typu int. + The first operand of an overloaded shift operator must have the same type as the containing type + První operand přetěžovaného operátoru shift musí být stejného typu jako obsahující typ a druhý operand musí být typu int. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 342cd973aed8b..15187439c4477 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - Der erste Operand eines überladenen Shift-Operators muss denselben Typ wie der enthaltende Typ oder den Typparameter aufweisen, der auf ihn beschränkt ist, und der Typ des zweiten Operanden muss "int" sein. + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + Der erste Operand eines überladenen Shift-Operators muss denselben Typ wie der enthaltende Typ oder den Typparameter aufweisen, der auf ihn beschränkt ist, und der Typ des zweiten Operanden muss "int" sein. @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - Die &Methodengruppe "{0}" kann nicht in den Delegattyp "{0}" konvertiert werden. + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ Datensatzstrukturen 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5921,8 +5926,8 @@ Wenn solch eine Klasse als Basisklasse verwendet wird und die ableitende Klasse - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - Der erste Operand eines überladenen Schiebeoperators muss den enthaltenden Typ aufweisen, und der zweite Operand muss eine ganze Zahl sein. + The first operand of an overloaded shift operator must have the same type as the containing type + Der erste Operand eines überladenen Schiebeoperators muss den enthaltenden Typ aufweisen, und der zweite Operand muss eine ganze Zahl sein. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 10b171ae10672..9e2f84a5663d0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - El primer operando de un operador de desplazamiento sobrecargado debe tener el mismo tipo que el tipo contenedor o su parámetro de tipo restringido, y el tipo del segundo operando debe ser int + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + El primer operando de un operador de desplazamiento sobrecargado debe tener el mismo tipo que el tipo contenedor o su parámetro de tipo restringido, y el tipo del segundo operando debe ser int @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - No se puede convertir el grupo de &métodos "{0}" en el tipo delegado "{0}". + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ registros 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5921,8 +5926,8 @@ Si se utiliza una clase de este tipo como clase base y si la clase derivada defi - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - El primer operando de un operador de desplazamiento sobrecargado debe tener el mismo tipo que el tipo contenedor, y el tipo del segundo operando debe ser int + The first operand of an overloaded shift operator must have the same type as the containing type + El primer operando de un operador de desplazamiento sobrecargado debe tener el mismo tipo que el tipo contenedor, y el tipo del segundo operando debe ser int diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 5fde23300df40..51dd4d16b9387 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - Le premier opérande d'un opérateur de décalage surchargé doit être du même type que le type conteneur ou son paramètre de type limité, et le type du second opérande doit être int + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + Le premier opérande d'un opérateur de décalage surchargé doit être du même type que le type conteneur ou son paramètre de type limité, et le type du second opérande doit être int @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - Impossible de convertir le groupe de &méthodes '{0}' en type délégué '{0}'. + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ structs d’enregistrement 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5921,8 +5926,8 @@ Si une telle classe est utilisée en tant que classe de base et si la classe dé - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - Le premier opérande d'un opérateur de décalage surchargé doit être du même type que le type conteneur et le type du second opérande doit être int + The first operand of an overloaded shift operator must have the same type as the containing type + Le premier opérande d'un opérateur de décalage surchargé doit être du même type que le type conteneur et le type du second opérande doit être int diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 863af695b52db..025c0559efc20 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - Il primo operando di un operatore shift di overload deve essere dello stesso tipo del tipo che lo contiene o del relativo parametro di tipo vincolato ad esso, mentre il tipo del secondo operando deve essere int + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + Il primo operando di un operatore shift di overload deve essere dello stesso tipo del tipo che lo contiene o del relativo parametro di tipo vincolato ad esso, mentre il tipo del secondo operando deve essere int @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - Non è possibile convertire il gruppo di &metodi '{0}' nel tipo delegato '{0}'. + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ struct di record 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5921,8 +5926,8 @@ Se si usa tale classe come classe base e se la classe di derivazione definisce u - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - Il primo operando di un operatore shift di overload deve essere dello stesso tipo del tipo che lo contiene, mentre il tipo del secondo operando deve essere int + The first operand of an overloaded shift operator must have the same type as the containing type + Il primo operando di un operatore shift di overload deve essere dello stesso tipo del tipo che lo contiene, mentre il tipo del secondo operando deve essere int diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 3f65bd09d8af1..d203290e0e76f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - オーバーロードされたシフト演算子の最初のオペランドは、それを含む型またはそれに制約された型パラメーターと同じ型である必要があり、2 番目のオペランドの型は int でなければなりません + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + オーバーロードされたシフト演算子の最初のオペランドは、それを含む型またはそれに制約された型パラメーターと同じ型である必要があり、2 番目のオペランドの型は int でなければなりません @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - メソッド グループ '{0}' をデリゲート型 '{0}' に変換することはできません。(&M) + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ レコード構造体 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5921,8 +5926,8 @@ If such a class is used as a base class and if the deriving class defines a dest - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - オーバーロードされた shift 演算子の最初のオペランドはそれを含む型と同じ型、2 番目のオペランドの型は int でなければなりません + The first operand of an overloaded shift operator must have the same type as the containing type + オーバーロードされた shift 演算子の最初のオペランドはそれを含む型と同じ型、2 番目のオペランドの型は int でなければなりません diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 09ab26188d046..f04105cc99ac0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - 오버로드된 Shift 연산자의 첫 번째 피연산자는 포함하는 형식 또는 제한된 형식 매개 변수와 동일한 형식이어야 하며 두 번째 피연산자의 형식은 int여야 합니다. + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + 오버로드된 Shift 연산자의 첫 번째 피연산자는 포함하는 형식 또는 제한된 형식 매개 변수와 동일한 형식이어야 하며 두 번째 피연산자의 형식은 int여야 합니다. @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - 메서드 그룹 '{0}'을(를) 대리자 형식 '{0}'(으)로 변환할 수 없습니다(&M). + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ 레코드 구조체 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5920,8 +5925,8 @@ If such a class is used as a base class and if the deriving class defines a dest - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - 오버로드된 시프트 연산자의 첫 번째 피연산자는 포함하는 형식과 동일한 형식이어야 하며 두 번째 피연산자는 정수 형식이어야 합니다. + The first operand of an overloaded shift operator must have the same type as the containing type + 오버로드된 시프트 연산자의 첫 번째 피연산자는 포함하는 형식과 동일한 형식이어야 하며 두 번째 피연산자는 정수 형식이어야 합니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 54701481b7493..c46455c255075 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - Pierwszy operand operatora przeciążonego przesunięcia musi mieć ten sam typ co typ zawierający lub jego parametr typu ograniczony do niego, a typ drugiego operandu musi mieć wartość „int” + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + Pierwszy operand operatora przeciążonego przesunięcia musi mieć ten sam typ co typ zawierający lub jego parametr typu ograniczony do niego, a typ drugiego operandu musi mieć wartość „int” @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - Nie można przekonwertować grupy &metod „{0}” na typ delegata „{0}”. + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ struktury rekordów 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5921,8 +5926,8 @@ Jeśli taka klasa zostanie użyta jako klasa bazowa i klasa pochodna definiuje d - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - Pierwszy argument operacji przeciążonego operatora przesunięcia musi mieć taki sam typ co typ zawierający, a typ drugiego argumentu operacji musi być typem int + The first operand of an overloaded shift operator must have the same type as the containing type + Pierwszy argument operacji przeciążonego operatora przesunięcia musi mieć taki sam typ co typ zawierający, a typ drugiego argumentu operacji musi być typem int diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index e03a31ea48f9b..aa08fce2a0f32 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - O primeiro operando de um operador de deslocamento sobrecarregado deve ser do tipo recipiente ou o parâmetro de tipo restrito a ele, enquanto o do segundo deve ser int + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + O primeiro operando de um operador de deslocamento sobrecarregado deve ser do tipo recipiente ou o parâmetro de tipo restrito a ele, enquanto o do segundo deve ser int @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - Não é possível converter o grupo de &métodos '{0}' no tipo delegado '{0}'. + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ registrar structs 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5921,8 +5926,8 @@ Se tal classe for usada como uma classe base e se a classe derivada definir um d - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - O primeiro operando de um operador de deslocamento sobrecarregado deve ser do tipo recipiente, enquanto o do segundo deve ser int + The first operand of an overloaded shift operator must have the same type as the containing type + O primeiro operando de um operador de deslocamento sobrecarregado deve ser do tipo recipiente, enquanto o do segundo deve ser int diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index d421725d76999..de6db896a5cb6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - Тип первого операнда перегруженного оператора сдвига должен совпадать с содержащим типом или параметр его типа должен быть им ограничен, а тип второго операнда должен быть int. + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + Тип первого операнда перегруженного оператора сдвига должен совпадать с содержащим типом или параметр его типа должен быть им ограничен, а тип второго операнда должен быть int. @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - Не удается преобразовать &группу методов "{0}" в тип делегата "{0}". + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ структуры записей 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5921,8 +5926,8 @@ If such a class is used as a base class and if the deriving class defines a dest - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - Тип первого операнда переопределенного оператора сдвига должен совпадать с вмещающим типом, а тип второго операнда должен быть int. + The first operand of an overloaded shift operator must have the same type as the containing type + Тип первого операнда переопределенного оператора сдвига должен совпадать с вмещающим типом, а тип второго операнда должен быть int. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index bc7160209c1d8..821bd0470140c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - Aşırı yüklenmiş kaydırma işlecinin ilk işleneni, içeren türle aynı türe veya buna kısıtlanmış tür parametresine sahip olmalıdır ve ikinci işlenenin türü int olmalıdır + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + Aşırı yüklenmiş kaydırma işlecinin ilk işleneni, içeren türle aynı türe veya buna kısıtlanmış tür parametresine sahip olmalıdır ve ikinci işlenenin türü int olmalıdır @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - '{0}' &metot grubu, '{0}' temsilci türüne dönüştürülemiyor. + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ kayıt yapıları 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5921,8 +5926,8 @@ Bu sınıf temel sınıf olarak kullanılırsa ve türetilen sınıf bir yıkıc - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - Tekrar yüklenen kaydırma işlecinin ilk işleneninin türü kapsayan tür ile aynı, ikinci işlenenin türü de tamsayı olmalıdır + The first operand of an overloaded shift operator must have the same type as the containing type + Tekrar yüklenen kaydırma işlecinin ilk işleneninin türü kapsayan tür ile aynı, ikinci işlenenin türü de tamsayı olmalıdır diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index a024159a37137..6e88ee65d4277 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - 重载移位运算符的第一个操作数的类型必须与包含类型或约束为该类型的类型参数相同,第二个操作数的类型必须是 int 类型 + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + 重载移位运算符的第一个操作数的类型必须与包含类型或约束为该类型的类型参数相同,第二个操作数的类型必须是 int 类型 @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - 无法将方法组“{0}”转换为委托类型“{0}”(&M)。 + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ 记录结构 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5926,8 +5931,8 @@ If such a class is used as a base class and if the deriving class defines a dest - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - 重载移位运算符的第一个操作数的类型必须与包含类型相同,第二个操作数的类型必须是 int 类型 + The first operand of an overloaded shift operator must have the same type as the containing type + 重载移位运算符的第一个操作数的类型必须与包含类型相同,第二个操作数的类型必须是 int 类型 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index f9fb37b9f8b87..36bd4facdadd6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -133,8 +133,8 @@ - The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - 多載移位運算子的第一個運算元的類型必須和包含的類型相同,或是其型別參數受限於該運算子,而第二個運算元的類型必須是 INT + The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it + 多載移位運算子的第一個運算元的類型必須和包含的類型相同,或是其型別參數受限於該運算子,而第二個運算元的類型必須是 INT @@ -223,8 +223,8 @@ - The input string cannot be converted into the equivalent UTF8 byte representation. {0} - The input string cannot be converted into the equivalent UTF8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} + The input string cannot be converted into the equivalent UTF-8 byte representation. {0} @@ -238,8 +238,8 @@ - Cannot convert &method group '{0}' to delegate type '{0}'. - 無法將方法群組 '{0}' 轉換成委派類型 '{0}'(&M) + Cannot convert &method group '{0}' to delegate type '{1}'. + Cannot convert &method group '{0}' to delegate type '{1}'. @@ -513,8 +513,8 @@ - An expression tree may not contain UTF8 string conversion or literal. - An expression tree may not contain UTF8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. @@ -1607,6 +1607,11 @@ 記錄結構 'record structs' is not localizable. + + relaxed shift operator + relaxed shift operator + + required members required members @@ -1623,8 +1628,8 @@ - Utf8 String Literals - Utf8 String Literals + UTF-8 string literals + UTF-8 string literals @@ -5921,8 +5926,8 @@ If such a class is used as a base class and if the deriving class defines a dest - The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - 多載移位 (Shift) 運算子的第一個運算元的類型必須和包含類型相同,而第二個運算元的類型必須是 int + The first operand of an overloaded shift operator must have the same type as the containing type + 多載移位 (Shift) 運算子的第一個運算元的類型必須和包含類型相同,而第二個運算元的類型必須是 int diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs index d8926d2592afd..188525758e6b0 100644 --- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs +++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs @@ -1228,7 +1228,7 @@ public void Reference_SimpleTests() Assert.Equal("b", parsedArgs.MetadataReferences.Single().Reference); parsedArgs = DefaultParse(new[] { "/r:a=b,,,c", "a.cs" }, WorkingDirectory); - parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_OneAliasPerReference).WithArguments("b,,,c")); + parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_OneAliasPerReference)); parsedArgs = DefaultParse(new[] { "/r:1=b", "a.cs" }, WorkingDirectory); parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_BadExternIdentifier).WithArguments("1")); @@ -5193,7 +5193,7 @@ public void WarningsErrors() parsedArgs = DefaultParse(new string[] { "/w:-1", "a.cs" }, WorkingDirectory); parsedArgs.Errors.Verify( // error CS1900: Warning level must be zero or greater - Diagnostic(ErrorCode.ERR_BadWarningLevel).WithArguments("w")); + Diagnostic(ErrorCode.ERR_BadWarningLevel)); parsedArgs = DefaultParse(new string[] { "/w:5", "a.cs" }, WorkingDirectory); parsedArgs.Errors.Verify(); @@ -5201,7 +5201,7 @@ public void WarningsErrors() parsedArgs = DefaultParse(new string[] { "/warn:-1", "a.cs" }, WorkingDirectory); parsedArgs.Errors.Verify( // error CS1900: Warning level must be zero or greater - Diagnostic(ErrorCode.ERR_BadWarningLevel).WithArguments("warn")); + Diagnostic(ErrorCode.ERR_BadWarningLevel)); parsedArgs = DefaultParse(new string[] { "/warn:5", "a.cs" }, WorkingDirectory); parsedArgs.Errors.Verify(); @@ -9171,7 +9171,7 @@ public void ErrorLineEnd() var comp = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/errorendlocation" }); var loc = new SourceLocation(tree.GetCompilationUnitRoot().FindToken(6)); - var diag = new CSDiagnostic(new DiagnosticInfo(MessageProvider.Instance, (int)ErrorCode.ERR_MetadataNameTooLong), loc); + var diag = new CSDiagnostic(new DiagnosticInfo(MessageProvider.Instance, (int)ErrorCode.ERR_MetadataNameTooLong, ""), loc); var text = comp.DiagnosticFormatter.Format(diag); string stringStart = "goo(1,7,1,8)"; @@ -12181,7 +12181,7 @@ long M(int i) // Diagnostic '{0}: {1}' was programmatically suppressed by a DiagnosticSuppressor with suppression ID '{2}' and justification '{3}' var suppressionMessage = string.Format(CodeAnalysisResources.SuppressionDiagnosticDescriptorMessage, suppressor.SuppressionDescriptor.SuppressedDiagnosticId, - new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.WRN_LowercaseEllSuffix, "l"), Location.None).GetMessage(CultureInfo.InvariantCulture), + new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.WRN_LowercaseEllSuffix), Location.None).GetMessage(CultureInfo.InvariantCulture), suppressor.SuppressionDescriptor.Id, suppressor.SuppressionDescriptor.Justification); Assert.Contains("info SP0001", output, StringComparison.Ordinal); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index 0781f26060308..44950a696d369 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -1766,7 +1766,7 @@ public static async System.Collections.Generic.IAsyncEnumerable M() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(4, 74), // (4,74): error CS8420: The body of an async-iterator method must contain a 'yield' statement. Consider removing 'async' from the method declaration or adding a 'yield' statement. // public static async System.Collections.Generic.IAsyncEnumerable M() - Diagnostic(ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, "M").WithArguments("System.Collections.Generic.IAsyncEnumerable").WithLocation(4, 74) + Diagnostic(ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, "M").WithLocation(4, 74) ); var m = comp.SourceModule.GlobalNamespace.GetMember("C.M"); @@ -1798,7 +1798,7 @@ public static async System.Collections.Generic.IAsyncEnumerator M() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(4, 74), // (4,74): error CS8420: The body of an async-iterator method must contain a 'yield' statement. Consider removing `async` from the method declaration. // public static async System.Collections.Generic.IAsyncEnumerator M() - Diagnostic(ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, "M").WithArguments("System.Collections.Generic.IAsyncEnumerator").WithLocation(4, 74) + Diagnostic(ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, "M").WithLocation(4, 74) ); } @@ -1820,7 +1820,7 @@ async System.Collections.Generic.IAsyncEnumerator M() comp.VerifyEmitDiagnostics( // (4,60): error CS8419: The body of an async-iterator method must contain a 'yield' statement. // async System.Collections.Generic.IAsyncEnumerator M() - Diagnostic(ErrorCode.ERR_PossibleAsyncIteratorWithoutYield, "M").WithArguments("System.Collections.Generic.IAsyncEnumerator").WithLocation(4, 60) + Diagnostic(ErrorCode.ERR_PossibleAsyncIteratorWithoutYield, "M").WithLocation(4, 60) ); } @@ -1849,7 +1849,7 @@ async System.Collections.Generic.IAsyncEnumerator M() Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(4, 60), // (4,60): error CS8420: The body of an async-iterator method must contain a 'yield' statement. Consider removing `async` from the method declaration. // async System.Collections.Generic.IAsyncEnumerator M() - Diagnostic(ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, "M").WithArguments("System.Collections.Generic.IAsyncEnumerator").WithLocation(4, 60) + Diagnostic(ErrorCode.ERR_PossibleAsyncIteratorWithoutYieldOrAwait, "M").WithLocation(4, 60) ); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs index 9c7317c979a22..9352974a34fb8 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncMainTests.cs @@ -810,7 +810,7 @@ async static void Main() compilation.VerifyDiagnostics( // (6,23): error CS8413: Async Main methods must return Task or Task // async static void Main() - Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main()").WithLocation(6, 23), + Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithLocation(6, 23), // error CS5001: Program does not contain a static 'Main' method suitable for an entry point Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); } @@ -835,7 +835,7 @@ async static int Main() Diagnostic(ErrorCode.ERR_BadAsyncReturn, "Main").WithLocation(6, 22), // (6,22): error CS4009: A void or int returning entry point cannot be async // async static int Main() - Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main()").WithLocation(6, 22), + Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithLocation(6, 22), // error CS5001: Program does not contain a static 'Main' method suitable for an entry point Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); var entry = compilation.GetEntryPoint(CancellationToken.None); @@ -862,7 +862,7 @@ async static int Main() Diagnostic(ErrorCode.ERR_BadAsyncReturn, "Main").WithLocation(6, 22), // (6,22): error CS8413: Async Main methods must return Task or Task // async static int Main() - Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main()").WithLocation(6, 22), + Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithLocation(6, 22), // error CS5001: Program does not contain a static 'Main' method suitable for an entry point Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); } @@ -1195,10 +1195,10 @@ async static int Main() Diagnostic(ErrorCode.ERR_BadAsyncReturn, "Main").WithLocation(11, 22), // (11,22): error CS4009: A void or int returning entry point cannot be async // async static int Main() - Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main()").WithLocation(11, 22), + Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithLocation(11, 22), // (6,23): error CS4009: A void or int returning entry point cannot be async // async static void Main(string[] args) - Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main(string[])").WithLocation(6, 23), + Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithLocation(6, 23), // error CS5001: Program does not contain a static 'Main' method suitable for an entry point Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); } @@ -1220,7 +1220,7 @@ static async void Main(string[] args) var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7_1)).VerifyDiagnostics( // (6,23): error CS4009: A void or int returning entry point cannot be async // static async void Main(string[] args) - Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithArguments("A.Main(string[])").WithLocation(6, 23), + Diagnostic(ErrorCode.ERR_NonTaskMainCantBeAsync, "Main").WithLocation(6, 23), // error CS5001: Program does not contain a static 'Main' method suitable for an entry point Diagnostic(ErrorCode.ERR_NoEntryPoint).WithLocation(1, 1)); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs index 180bd46bbf673..3c4d9d745ae24 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenDeconstructTests.cs @@ -7561,7 +7561,7 @@ static void Main() compilation.VerifyDiagnostics( // (6,16): error CS1003: Syntax error, ',' expected // var (p2) = (1, 2); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(",", ")").WithLocation(6, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(",").WithLocation(6, 16), // (6,16): error CS1001: Identifier expected // var (p2) = (1, 2); Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(6, 16) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs index 84d77a6b0063d..228fa4e8dd7cf 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs @@ -3587,10 +3587,10 @@ unsafe void M() // (8,24): error CS0119: 'Action' is a type, which is not valid in the given context // Action ptr1 = (Action)&M; Diagnostic(ErrorCode.ERR_BadSKunknown, "Action").WithArguments("System.Action", "type").WithLocation(8, 24), - // (9,23): error CS8811: Cannot convert &method group 'M' to delegate type 'M'. + // (9,23): error CS8811: Cannot convert &method group 'M' to delegate type 'Action'. // Action ptr2 = (Action)(&M); Diagnostic(ErrorCode.ERR_CannotConvertAddressOfToDelegate, "(Action)(&M)").WithArguments("M", "System.Action").WithLocation(9, 23), - // (10,23): error CS8811: Cannot convert &method group 'M' to delegate type 'M'. + // (10,23): error CS8811: Cannot convert &method group 'M' to delegate type 'Action'. // Action ptr3 = &M; Diagnostic(ErrorCode.ERR_CannotConvertAddressOfToDelegate, "&M").WithArguments("M", "System.Action").WithLocation(10, 23) ); @@ -10466,7 +10466,7 @@ static unsafe void F() Diagnostic(ErrorCode.ERR_NameNotInContext, "Expression", isSuppressed: false).WithArguments("Expression").WithLocation(5, 59), // (5,69): error CS1003: Syntax error, ',' expected // [UnmanagedCallersOnly(CallConvs = new[] { typeof(Bad, Expression) })] - Diagnostic(ErrorCode.ERR_SyntaxError, ")", isSuppressed: false).WithArguments(",", ")").WithLocation(5, 69), + Diagnostic(ErrorCode.ERR_SyntaxError, ")", isSuppressed: false).WithArguments(",").WithLocation(5, 69), // (9,43): error CS8786: Calling convention of 'A.F()' is not compatible with 'Unmanaged'. // delegate* unmanaged ptr2 = &F; Diagnostic(ErrorCode.ERR_WrongFuncPtrCallingConvention, "F", isSuppressed: false).WithArguments("A.F()", "Unmanaged").WithLocation(9, 43) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs index 24e47bd984a45..0e13045b73e20 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefLocalTests.cs @@ -3406,7 +3406,7 @@ public static void Main() { // file.cs(6,28): error CS8386: Invalid object creation // _ = /**/ new ref[] { 1 } /**/ ; - Diagnostic(ErrorCode.ERR_InvalidObjectCreation, "ref[]").WithArguments("?[]").WithLocation(6, 28), + Diagnostic(ErrorCode.ERR_InvalidObjectCreation, "ref[]").WithLocation(6, 28), // file.cs(6,31): error CS1031: Type expected // _ = /**/ new ref[] { 1 } /**/ ; Diagnostic(ErrorCode.ERR_TypeExpected, "[").WithLocation(6, 31) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs index 06bc726ca1ada..94afac4e50016 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefReadonlyReturnTests.cs @@ -1019,10 +1019,10 @@ ref readonly S1 Test() comp.VerifyDiagnostics( // (8,20): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref this; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithArguments("this").WithLocation(8, 20), + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(8, 20), // (11,44): error CS8170: Struct members cannot return 'this' or other instance members by reference // in int this[in int i] => ref x; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithArguments("this").WithLocation(11, 44) + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithLocation(11, 44) ); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs index 3e96547f61c4e..cc488bc615133 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs @@ -25448,7 +25448,7 @@ static void M() Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(6, 41), // (6,41): error CS1003: Syntax error, ':' expected // var x1 = (1, 1) is (int, int a)?; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":", ";").WithLocation(6, 41), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":").WithLocation(6, 41), // (6,41): error CS1525: Invalid expression term ';' // var x1 = (1, 1) is (int, int a)?; Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(6, 41) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/FixedSizeBufferTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/FixedSizeBufferTests.cs index 97e453e6292f8..6f709ef6d664d 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/FixedSizeBufferTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/FixedSizeBufferTests.cs @@ -862,10 +862,10 @@ private static unsafe uint Test( AssemblyRecord* pStruct ) Diagnostic(ErrorCode.ERR_IdentifierExpected, "const").WithLocation(8, 18), // (8,18): error CS1003: Syntax error, '[' expected // public fixed const UInt32 StartOfTables[ 16 ]; - Diagnostic(ErrorCode.ERR_SyntaxError, "const").WithArguments("[", "const").WithLocation(8, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "const").WithArguments("[").WithLocation(8, 18), // (8,18): error CS1003: Syntax error, ']' expected // public fixed const UInt32 StartOfTables[ 16 ]; - Diagnostic(ErrorCode.ERR_SyntaxError, "const").WithArguments("]", "const").WithLocation(8, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "const").WithArguments("]").WithLocation(8, 18), // (8,18): error CS0443: Syntax error; value expected // public fixed const UInt32 StartOfTables[ 16 ]; Diagnostic(ErrorCode.ERR_ValueExpected, "const").WithLocation(8, 18), diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs index efd4dea68e945..6b6ac34fcf5df 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.cs @@ -1732,6 +1732,55 @@ static partial void M2() { } Handle(2, TableIndex.AssemblyRef)); } + [WorkItem(60804, "https://github.com/dotnet/roslyn/issues/60804")] + [Fact] + public void PartialMethod_WithLambda() + { + using var _ = new EditAndContinueTest(options: TestOptions.DebugDll, targetFramework: TargetFramework.NetStandard20) + .AddGeneration( + source: @" +partial class C +{ + partial void M(); + + partial void M() + { + var y = 4; + var x = () => y + 4; + } +} +", + validator: g => + { + g.VerifyTypeDefNames("", "C", "<>c__DisplayClass0_0"); + g.VerifyMethodDefNames("M", ".ctor", ".ctor", "b__0"); + }) + + .AddGeneration( + source: @" +partial class C +{ + partial void M(); + + partial void M() + { + var y = 5; + var x = () => y + 4; + } +} +", + edits: new[] + { + Edit(SemanticEditKind.Update, c => c.GetMember("C.M").PartialImplementationPart) + }, + validator: g => + { + g.VerifyMethodDefNames("M", ".ctor", "b__0#1"); + }) + + .Verify(); + } + [Fact] public void Method_WithAttributes_Add() { diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs index 04d56246eafa4..9db3fac12370a 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs @@ -1780,7 +1780,7 @@ public struct Test comp.VerifyDiagnostics( // (4,13): error CS0637: The FieldOffset attribute is not allowed on static or const fields // [field: System.Runtime.InteropServices.FieldOffset(0)] - Diagnostic(ErrorCode.ERR_StructOffsetOnBadField, "System.Runtime.InteropServices.FieldOffset").WithArguments("System.Runtime.InteropServices.FieldOffset").WithLocation(4, 13) + Diagnostic(ErrorCode.ERR_StructOffsetOnBadField, "System.Runtime.InteropServices.FieldOffset").WithLocation(4, 13) ); } diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_StructLayout.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_StructLayout.cs index b4f3391d0c35a..b598749b1723f 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_StructLayout.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_StructLayout.cs @@ -498,27 +498,38 @@ enum En "; CreateCompilation(source).VerifyDiagnostics( // (7,6): error CS0636: The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit) - Diagnostic(ErrorCode.ERR_StructOffsetOnBadStruct, "FieldOffset"), + // [FieldOffset(4)] + Diagnostic(ErrorCode.ERR_StructOffsetOnBadStruct, "FieldOffset").WithLocation(7, 6), // (14,6): error CS0636: The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit) - Diagnostic(ErrorCode.ERR_StructOffsetOnBadStruct, "FieldOffset"), + // [FieldOffset(4)] + Diagnostic(ErrorCode.ERR_StructOffsetOnBadStruct, "FieldOffset").WithLocation(14, 6), // (17,18): error CS0591: Invalid value for argument to 'FieldOffset' attribute - Diagnostic(ErrorCode.ERR_InvalidAttributeArgument, "-1").WithArguments("FieldOffset"), + // [FieldOffset(-1)] + Diagnostic(ErrorCode.ERR_InvalidAttributeArgument, "-1").WithArguments("FieldOffset").WithLocation(17, 18), // (17,6): error CS0636: The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit) - Diagnostic(ErrorCode.ERR_StructOffsetOnBadStruct, "FieldOffset"), + // [FieldOffset(-1)] + Diagnostic(ErrorCode.ERR_StructOffsetOnBadStruct, "FieldOffset").WithLocation(17, 6), // (24,18): error CS0591: Invalid value for argument to 'FieldOffset' attribute - Diagnostic(ErrorCode.ERR_InvalidAttributeArgument, "-1").WithArguments("FieldOffset"), + // [FieldOffset(-1)] + Diagnostic(ErrorCode.ERR_InvalidAttributeArgument, "-1").WithArguments("FieldOffset").WithLocation(24, 18), // (27,6): error CS0637: The FieldOffset attribute is not allowed on static or const fields - Diagnostic(ErrorCode.ERR_StructOffsetOnBadField, "FieldOffset").WithArguments("FieldOffset"), - // (30,9): error CS0625: 'E.c1': instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute - Diagnostic(ErrorCode.ERR_MissingStructOffset, "c1").WithArguments("E.c1"), - // (30,13): error CS0625: 'E.c2': instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute - Diagnostic(ErrorCode.ERR_MissingStructOffset, "c2").WithArguments("E.c2"), + // [FieldOffset(5)] + Diagnostic(ErrorCode.ERR_StructOffsetOnBadField, "FieldOffset").WithLocation(27, 6), + // (30,9): error CS0625: 'E.c1': instance field in types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute + // int c1, c2; + Diagnostic(ErrorCode.ERR_MissingStructOffset, "c1").WithArguments("E.c1").WithLocation(30, 9), + // (30,13): error CS0625: 'E.c2': instance field in types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute + // int c1, c2; + Diagnostic(ErrorCode.ERR_MissingStructOffset, "c2").WithArguments("E.c2").WithLocation(30, 13), // (39,6): error CS0637: The FieldOffset attribute is not allowed on static or const fields - Diagnostic(ErrorCode.ERR_StructOffsetOnBadField, "FieldOffset").WithArguments("FieldOffset"), + // [FieldOffset(-1)] + Diagnostic(ErrorCode.ERR_StructOffsetOnBadField, "FieldOffset").WithLocation(39, 6), // (42,6): error CS0637: The FieldOffset attribute is not allowed on static or const fields - Diagnostic(ErrorCode.ERR_StructOffsetOnBadField, "FieldOffset").WithArguments("FieldOffset"), + // [FieldOffset(5)] + Diagnostic(ErrorCode.ERR_StructOffsetOnBadField, "FieldOffset").WithLocation(42, 6), // (48,6): error CS0637: The FieldOffset attribute is not allowed on static or const fields - Diagnostic(ErrorCode.ERR_StructOffsetOnBadField, "FieldOffset").WithArguments("FieldOffset")); + // [FieldOffset(5)] + Diagnostic(ErrorCode.ERR_StructOffsetOnBadField, "FieldOffset").WithLocation(48, 6)); } [Fact, WorkItem(546660, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546660"), WorkItem(546662, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546662")] diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs b/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs index a9bc194f86d55..faf119b347e7e 100644 --- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Diagnostics/OperationAnalyzerTests.cs @@ -1670,7 +1670,7 @@ static void Main() Diagnostic(ErrorCode.ERR_NoImplicitConv, "string.Empty").WithArguments("string", "int").WithLocation(10, 17), // (12,25): error CS0400: The type or namespace name 'MyType' could not be found in the global namespace (are you missing an assembly reference?) // int i = global::MyType(); - Diagnostic(ErrorCode.ERR_GlobalSingleTypeNameNotFound, "MyType").WithArguments("MyType", "").WithLocation(12, 25)) + Diagnostic(ErrorCode.ERR_GlobalSingleTypeNameNotFound, "MyType").WithArguments("MyType").WithLocation(12, 25)) .VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new ConversionExpressionCSharpTestAnalyzer() }, null, null, Diagnostic(ConversionExpressionCSharpTestAnalyzer.InvalidConversionExpressionDescriptor.Id, "null.Length").WithLocation(8, 17), Diagnostic(ConversionExpressionCSharpTestAnalyzer.InvalidConversionExpressionDescriptor.Id, "string.Empty").WithLocation(10, 17), diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowDiagnosticTests.cs b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowDiagnosticTests.cs index 3d53102d2a874..a1e1a3f2a1c12 100644 --- a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowDiagnosticTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowDiagnosticTests.cs @@ -1739,55 +1739,55 @@ static void Main(string[] args) var comp = CreateCompilation(text, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (15,17): error CS0206: A property or indexer may not be passed as an out or ref parameter - // Goo(out x1); - Diagnostic(ErrorCode.ERR_RefProperty, "x1").WithArguments("Program.x1").WithLocation(15, 17), - // (16,17): error CS0206: A property or indexer may not be passed as an out or ref parameter - // Goo(ref x1); - Diagnostic(ErrorCode.ERR_RefProperty, "x1").WithArguments("Program.x1").WithLocation(16, 17), - // (17,17): error CS0206: A property or indexer may not be passed as an out or ref parameter - // Goo(out x2); - Diagnostic(ErrorCode.ERR_RefProperty, "x2").WithArguments("Program.x2").WithLocation(17, 17), - // (18,17): error CS0206: A property or indexer may not be passed as an out or ref parameter - // Goo(ref x2); - Diagnostic(ErrorCode.ERR_RefProperty, "x2").WithArguments("Program.x2").WithLocation(18, 17), - // (20,17): error CS1620: Argument 1 must be passed with the 'out' keyword - // Goo(ref x3); - Diagnostic(ErrorCode.ERR_BadArgRef, "x3").WithArguments("1", "out").WithLocation(20, 17), - // (15,17): error CS9014: Use of possibly unassigned auto-implemented property 'x1'. Consider updating to language version 'preview' to auto-default the property. - // Goo(out x1); - Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x1").WithArguments("x1", "preview").WithLocation(15, 17), - // (16,9): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. - // Goo(ref x1); - Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "Goo").WithArguments("preview").WithLocation(16, 9), - // (17,17): error CS9014: Use of possibly unassigned auto-implemented property 'x2'. Consider updating to language version 'preview' to auto-default the property. - // Goo(out x2); - Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x2").WithArguments("x2", "preview").WithLocation(17, 17), - // (6,20): warning CS0649: Field 'Program.S1.x' is never assigned to, and will always have its default value 0 - // public int x; - Diagnostic(ErrorCode.WRN_UnassignedInternalField, "x").WithArguments("Program.S1.x", "0").WithLocation(6, 20) + // (15,17): error CS0206: A property or indexer may not be passed as an out or ref parameter + // Goo(out x1); + Diagnostic(ErrorCode.ERR_RefProperty, "x1").WithLocation(15, 17), + // (16,17): error CS0206: A property or indexer may not be passed as an out or ref parameter + // Goo(ref x1); + Diagnostic(ErrorCode.ERR_RefProperty, "x1").WithLocation(16, 17), + // (17,17): error CS0206: A property or indexer may not be passed as an out or ref parameter + // Goo(out x2); + Diagnostic(ErrorCode.ERR_RefProperty, "x2").WithLocation(17, 17), + // (18,17): error CS0206: A property or indexer may not be passed as an out or ref parameter + // Goo(ref x2); + Diagnostic(ErrorCode.ERR_RefProperty, "x2").WithLocation(18, 17), + // (20,17): error CS1620: Argument 1 must be passed with the 'out' keyword + // Goo(ref x3); + Diagnostic(ErrorCode.ERR_BadArgRef, "x3").WithArguments("1", "out").WithLocation(20, 17), + // (15,17): error CS9014: Use of possibly unassigned auto-implemented property 'x1'. Consider updating to language version 'preview' to auto-default the property. + // Goo(out x1); + Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x1").WithArguments("x1", "preview").WithLocation(15, 17), + // (16,9): error CS0188: The 'this' object cannot be used before all of its fields have been assigned. Consider updating to language version 'preview' to auto-default the unassigned fields. + // Goo(ref x1); + Diagnostic(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, "Goo").WithArguments("preview").WithLocation(16, 9), + // (17,17): error CS9014: Use of possibly unassigned auto-implemented property 'x2'. Consider updating to language version 'preview' to auto-default the property. + // Goo(out x2); + Diagnostic(ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion, "x2").WithArguments("x2", "preview").WithLocation(17, 17), + // (6,20): warning CS0649: Field 'Program.S1.x' is never assigned to, and will always have its default value 0 + // public int x; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "x").WithArguments("Program.S1.x", "0").WithLocation(6, 20) ); comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext); comp.VerifyDiagnostics( - // (15,17): error CS0206: A property or indexer may not be passed as an out or ref parameter - // Goo(out x1); - Diagnostic(ErrorCode.ERR_RefProperty, "x1").WithArguments("Program.x1").WithLocation(15, 17), - // (16,17): error CS0206: A property or indexer may not be passed as an out or ref parameter - // Goo(ref x1); - Diagnostic(ErrorCode.ERR_RefProperty, "x1").WithArguments("Program.x1").WithLocation(16, 17), - // (17,17): error CS0206: A property or indexer may not be passed as an out or ref parameter - // Goo(out x2); - Diagnostic(ErrorCode.ERR_RefProperty, "x2").WithArguments("Program.x2").WithLocation(17, 17), - // (18,17): error CS0206: A property or indexer may not be passed as an out or ref parameter - // Goo(ref x2); - Diagnostic(ErrorCode.ERR_RefProperty, "x2").WithArguments("Program.x2").WithLocation(18, 17), - // (20,17): error CS1620: Argument 1 must be passed with the 'out' keyword - // Goo(ref x3); - Diagnostic(ErrorCode.ERR_BadArgRef, "x3").WithArguments("1", "out").WithLocation(20, 17), - // (6,20): warning CS0649: Field 'Program.S1.x' is never assigned to, and will always have its default value 0 - // public int x; - Diagnostic(ErrorCode.WRN_UnassignedInternalField, "x").WithArguments("Program.S1.x", "0").WithLocation(6, 20) + // (15,17): error CS0206: A property or indexer may not be passed as an out or ref parameter + // Goo(out x1); + Diagnostic(ErrorCode.ERR_RefProperty, "x1").WithLocation(15, 17), + // (16,17): error CS0206: A property or indexer may not be passed as an out or ref parameter + // Goo(ref x1); + Diagnostic(ErrorCode.ERR_RefProperty, "x1").WithLocation(16, 17), + // (17,17): error CS0206: A property or indexer may not be passed as an out or ref parameter + // Goo(out x2); + Diagnostic(ErrorCode.ERR_RefProperty, "x2").WithLocation(17, 17), + // (18,17): error CS0206: A property or indexer may not be passed as an out or ref parameter + // Goo(ref x2); + Diagnostic(ErrorCode.ERR_RefProperty, "x2").WithLocation(18, 17), + // (20,17): error CS1620: Argument 1 must be passed with the 'out' keyword + // Goo(ref x3); + Diagnostic(ErrorCode.ERR_BadArgRef, "x3").WithArguments("1", "out").WithLocation(20, 17), + // (6,20): warning CS0649: Field 'Program.S1.x' is never assigned to, and will always have its default value 0 + // public int x; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "x").WithArguments("Program.S1.x", "0").WithLocation(6, 20) ); } diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IArrayElementReferenceExpression.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IArrayElementReferenceExpression.cs index 2709680fec79e..fb88e38cda955 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IArrayElementReferenceExpression.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IArrayElementReferenceExpression.cs @@ -771,7 +771,7 @@ public void F(string[] args) var expectedDiagnostics = new DiagnosticDescription[] { // CS1003: Syntax error, ']' expected // var a = /**/args[/**/; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]", ";").WithLocation(6, 43), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]").WithLocation(6, 43), // CS0022: Wrong number of indices inside []; expected 1 // var a = /**/args[/**/; Diagnostic(ErrorCode.ERR_BadIndexCount, "args[/**/").WithArguments("1").WithLocation(6, 27) @@ -803,7 +803,7 @@ public void F(string[] args) var expectedDiagnostics = new DiagnosticDescription[] { // CS1003: Syntax error, ']' expected // var a = /**/args[0/**/; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]", ";").WithLocation(6, 44) + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]").WithLocation(6, 44) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IDeclarationExpression.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IDeclarationExpression.cs index 2bae8b804e10d..88a40e4d51533 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IDeclarationExpression.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IDeclarationExpression.cs @@ -37,19 +37,19 @@ public void M2(out int i) Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(6, 16), // CS1003: Syntax error, ':' expected // M2(b ? out var i1 : out var i2); - Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(":", "out").WithLocation(6, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(":").WithLocation(6, 16), // CS1525: Invalid expression term 'out' // M2(b ? out var i1 : out var i2); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(6, 16), // CS1003: Syntax error, ',' expected // M2(b ? out var i1 : out var i2); - Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(6, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(6, 16), // CS1003: Syntax error, ',' expected // M2(b ? out var i1 : out var i2); - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(6, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(6, 27), // CS1003: Syntax error, ',' expected // M2(b ? out var i1 : out var i2); - Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(6, 29) + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(6, 29) }; string expectedFlowGraph = @" diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs index 2947b18096ec5..a515cc28f9774 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIfStatement.cs @@ -931,7 +931,7 @@ private void M() Diagnostic(ErrorCode.ERR_ElseCannotStartStatement, "").WithLocation(7, 6), // file.cs(7,6): error CS1003: Syntax error, '(' expected // { - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(7, 6), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(7, 6), // file.cs(7,6): error CS1525: Invalid expression term 'else' // { Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(7, 6), @@ -1036,7 +1036,7 @@ private void M(bool flag) Diagnostic(ErrorCode.ERR_ElseCannotStartStatement, "").WithLocation(20, 14), // file.cs(20,14): error CS1003: Syntax error, '(' expected // } - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(20, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(20, 14), // file.cs(20,14): error CS1525: Invalid expression term 'else' // } Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(20, 14), @@ -1108,7 +1108,7 @@ private void M(bool flag) Diagnostic(ErrorCode.ERR_ElseCannotStartStatement, "").WithLocation(12, 28), // file.cs(12,28): error CS1003: Syntax error, '(' expected // /**/if (flag) - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(12, 28), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(12, 28), // file.cs(12,28): error CS1525: Invalid expression term 'else' // /**/if (flag) Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(12, 28), @@ -1190,7 +1190,7 @@ private void M() Diagnostic(ErrorCode.ERR_ElseCannotStartStatement, "").WithLocation(12, 20), // file.cs(12,20): error CS1003: Syntax error, '(' expected // /**/{ - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(12, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(12, 20), // file.cs(12,20): error CS1525: Invalid expression term 'else' // /**/{ Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(12, 20), @@ -1208,7 +1208,7 @@ private void M() Diagnostic(ErrorCode.ERR_ElseCannotStartStatement, "").WithLocation(15, 14), // file.cs(15,14): error CS1003: Syntax error, '(' expected // } - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(15, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(15, 14), // file.cs(15,14): error CS1525: Invalid expression term 'else' // } Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(15, 14), @@ -1395,7 +1395,7 @@ private void M() Diagnostic(ErrorCode.ERR_ElseCannotStartStatement, "").WithLocation(10, 30), // file.cs(10,30): error CS1003: Syntax error, '(' expected // /**/if (a == 1) - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "else").WithLocation(10, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(10, 30), // file.cs(10,30): error CS1525: Invalid expression term 'else' // /**/if (a == 1) Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("else").WithLocation(10, 30), diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIsPatternExpression.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIsPatternExpression.cs index 6fe2b772abfe0..fc88acc33facf 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIsPatternExpression.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IIsPatternExpression.cs @@ -1330,10 +1330,10 @@ void M1(object o, bool b) Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "[1]").WithLocation(6, 37), // (6,40): error CS1003: Syntax error, ',' expected // b = /**/o is C1 { Prop[1]: var x }/**/; - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(6, 40), + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(6, 40), // (6,42): error CS1003: Syntax error, ',' expected // b = /**/o is C1 { Prop[1]: var x }/**/; - Diagnostic(ErrorCode.ERR_SyntaxError, "var").WithArguments(",", "").WithLocation(6, 42)); + Diagnostic(ErrorCode.ERR_SyntaxError, "var").WithArguments(",").WithLocation(6, 42)); var expectedOperationTree = @" IIsPatternOperation (OperationKind.IsPattern, Type: System.Boolean, IsInvalid) (Syntax: 'o is C1 { P ... 1]: var x }') diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IObjectCreationExpression.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IObjectCreationExpression.cs index 9addd99965d97..de00a8019ed0c 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IObjectCreationExpression.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IObjectCreationExpression.cs @@ -5189,13 +5189,13 @@ class C3 Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(8, 70), // CS1003: Syntax error, ':' expected // var x = new C1 { C2 = { C31 = { P1 = 1, P2 = 2 }, C32 = b ? ({ P1 = 3, P2 = 4 }) : ({ P1 = 3, P2 = 4 }) - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":", "{").WithLocation(8, 70), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":").WithLocation(8, 70), // CS1525: Invalid expression term '{' // var x = new C1 { C2 = { C31 = { P1 = 1, P2 = 2 }, C32 = b ? ({ P1 = 3, P2 = 4 }) : ({ P1 = 3, P2 = 4 }) Diagnostic(ErrorCode.ERR_InvalidExprTerm, "{").WithArguments("{").WithLocation(8, 70), // CS1003: Syntax error, ',' expected // var x = new C1 { C2 = { C31 = { P1 = 1, P2 = 2 }, C32 = b ? ({ P1 = 3, P2 = 4 }) : ({ P1 = 3, P2 = 4 }) - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(8, 70), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(8, 70), // CS1513: } expected // var x = new C1 { C2 = { C31 = { P1 = 1, P2 = 2 }, C32 = b ? ({ P1 = 3, P2 = 4 }) : ({ P1 = 3, P2 = 4 }) Diagnostic(ErrorCode.ERR_RbraceExpected, ")").WithLocation(8, 88), diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IPatternSwitchCase.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IPatternSwitchCase.cs index d65131c77a69e..d51a4fc5ddb6d 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IPatternSwitchCase.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_IPatternSwitchCase.cs @@ -620,7 +620,7 @@ void M(int? x) Diagnostic(ErrorCode.ERR_InvalidExprTerm, "const").WithArguments("const").WithLocation(9, 39), // CS1003: Syntax error, ':' expected // /**/case /**/const int y: - Diagnostic(ErrorCode.ERR_SyntaxError, "const").WithArguments(":", "const").WithLocation(9, 39), + Diagnostic(ErrorCode.ERR_SyntaxError, "const").WithArguments(":").WithLocation(9, 39), // CS0145: A const field requires a value to be provided // /**/case /**/const int y: Diagnostic(ErrorCode.ERR_ConstValueRequired, "y").WithLocation(9, 49), diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ISwitchExpression.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ISwitchExpression.cs index 5dc4299e1cd95..fc639257eb6f1 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ISwitchExpression.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_ISwitchExpression.cs @@ -349,7 +349,7 @@ void M(int? x, object y) var expectedDiagnostics = new[] { // file.cs(7,43): error CS1003: Syntax error, '=>' expected // y = /**/x switch { _ /*=>*/ 5 }/**/; - Diagnostic(ErrorCode.ERR_SyntaxError, "5").WithArguments("=>", "").WithLocation(7, 43) + Diagnostic(ErrorCode.ERR_SyntaxError, "5").WithArguments("=>").WithLocation(7, 43) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); } diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_InvalidStatement.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_InvalidStatement.cs index cc02edab1f6e3..046aa49022e30 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_InvalidStatement.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_InvalidStatement.cs @@ -54,10 +54,10 @@ static void Main(string[] args) Diagnostic(ErrorCode.ERR_BadVarDecl, "( 1 ").WithLocation(8, 26), // CS1003: Syntax error, '[' expected // /**/int x, ( 1 );/**/ - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(8, 26), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(8, 26), // CS1003: Syntax error, ']' expected // /**/int x, ( 1 );/**/ - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(8, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(8, 30), // CS0168: The variable 'x' is declared but never used // /**/int x, ( 1 );/**/ Diagnostic(ErrorCode.WRN_UnreferencedVar, "x").WithArguments("x").WithLocation(8, 23) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/AnonymousFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/AnonymousFunctionTests.cs index 30e5d81d57e0d..211607e5816cd 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/AnonymousFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/AnonymousFunctionTests.cs @@ -1334,7 +1334,7 @@ unsafe void M() Diagnostic(ErrorCode.ERR_IdentifierExpected, "=>").WithLocation(6, 42), // (6,42): error CS1003: Syntax error, ',' expected // delegate* ptr = &static () => { }; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(6, 42), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(6, 42), // (6,45): error CS1002: ; expected // delegate* ptr = &static () => { }; Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(6, 45) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs index 80447d7cba237..36315f8855be1 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ArglistTests.cs @@ -231,7 +231,7 @@ static void Main() Diagnostic(ErrorCode.ERR_RefLvalueExpected, "123").WithLocation(9, 40), // (10,40): error CS0206: A property or indexer may not be passed as an out or ref parameter // TypedReference tr4 = __makeref(P); // CS0206 - Diagnostic(ErrorCode.ERR_RefProperty, "P").WithArguments("C.P").WithLocation(10, 40), + Diagnostic(ErrorCode.ERR_RefProperty, "P").WithLocation(10, 40), // (11,40): error CS0199: A static readonly field cannot be used as a ref or out value (except in a static constructor) // TypedReference tr5 = __makeref(R); // CS0199 Diagnostic(ErrorCode.ERR_RefReadonlyStatic, "R").WithLocation(11, 40) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs index 9068f5e5c2b8e..22daa4e4315fd 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/BindingTests.cs @@ -678,7 +678,7 @@ public void IncompleteDelegateDecl() Diagnostic(ErrorCode.ERR_IdentifierExpected, ""), // (3,9): error CS1003: Syntax error, '(' expected // delegate - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", ""), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("("), // (3,9): error CS1026: ) expected // delegate Diagnostic(ErrorCode.ERR_CloseParenExpected, ""), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs index 40ee9a8a34913..d677a49d84fb5 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DeconstructionTests.cs @@ -3294,10 +3294,10 @@ static void Main() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(6, 13), // CS1003: Syntax error, ',' expected // var(int x1, x2) = (1, 2); - Diagnostic(ErrorCode.ERR_SyntaxError, "x1").WithArguments(",", "").WithLocation(6, 17), + Diagnostic(ErrorCode.ERR_SyntaxError, "x1").WithArguments(",").WithLocation(6, 17), // CS1003: Syntax error, ',' expected // var(var x3, x4) = (1, 2); - Diagnostic(ErrorCode.ERR_SyntaxError, "x3").WithArguments(",", "").WithLocation(7, 17), + Diagnostic(ErrorCode.ERR_SyntaxError, "x3").WithArguments(",").WithLocation(7, 17), // CS8199: The syntax 'var (...)' as an lvalue is reserved. // var(int x1, x2) = (1, 2); Diagnostic(ErrorCode.ERR_VarInvocationLvalueReserved, "var(int x1, x2)").WithLocation(6, 9), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs index 5dccf6ed0710e..0b16e2255fd11 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs @@ -2565,7 +2565,7 @@ Type Arguments(0) Diagnostic(ErrorCode.ERR_NameNotInContext, "f").WithArguments("f").WithLocation(11, 21), // file.cs(6,26): error CS8382: Invalid object creation // var x = /**/ new dynamic - Diagnostic(ErrorCode.ERR_InvalidObjectCreation, "dynamic").WithArguments("dynamic").WithLocation(6, 26) + Diagnostic(ErrorCode.ERR_InvalidObjectCreation, "dynamic").WithLocation(6, 26) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); @@ -2802,7 +2802,7 @@ static void Main() Diagnostic(ErrorCode.WRN_IsDynamicIsConfusing, "d is dynamic").WithArguments("is", "dynamic", "Object").WithLocation(43, 55), // (46,59): error CS8382: Invalid object creation // Expression> e21 = x => new dynamic(); - Diagnostic(ErrorCode.ERR_InvalidObjectCreation, "dynamic").WithArguments("dynamic").WithLocation(46, 59), + Diagnostic(ErrorCode.ERR_InvalidObjectCreation, "dynamic").WithLocation(46, 59), // (25,52): error CS1963: An expression tree may not contain a dynamic operation // Expression> e0 = () => new C { P = d }; Diagnostic(ErrorCode.ERR_ExpressionTreeContainsDynamicOperation, "d").WithLocation(25, 52), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs index 994c3203d2d31..5f0565e27942c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs @@ -3822,7 +3822,7 @@ static void M(delegate* ptr1, delegate*<__arglist, void> ptr2 Diagnostic(ErrorCode.ERR_TypeExpected, "__arglist").WithLocation(4, 64), // (4,64): error CS1003: Syntax error, ',' expected // static void M(delegate* ptr1, delegate*<__arglist, void> ptr2) - Diagnostic(ErrorCode.ERR_SyntaxError, "__arglist").WithArguments(",", "__arglist").WithLocation(4, 64), + Diagnostic(ErrorCode.ERR_SyntaxError, "__arglist").WithArguments(",").WithLocation(4, 64), // (6,14): error CS1503: Argument 1: cannot convert from '__arglist' to 'string' // ptr1(__arglist(string.Empty, 1), 1); Diagnostic(ErrorCode.ERR_BadArgType, "__arglist(string.Empty, 1)").WithArguments("1", "__arglist", "string").WithLocation(6, 14), @@ -3991,7 +3991,7 @@ void M2() comp.VerifyDiagnostics( // (6,38): error CS1003: Syntax error, ',' expected // delegate* ptr = new () => {}; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(6, 38), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(6, 38), // (6,41): error CS1002: ; expected // delegate* ptr = new () => {}; Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(6, 41), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/IndexAndRangeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/IndexAndRangeTests.cs index 3ff9534660d4e..beff43c54a991 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/IndexAndRangeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/IndexAndRangeTests.cs @@ -265,7 +265,7 @@ void M(S s) comp.VerifyDiagnostics( // (11,34): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference // ref readonly int x = ref s[^2]; - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s[^2]").WithArguments("S.this[int]").WithLocation(11, 34)); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s[^2]").WithLocation(11, 34)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs index 650d058df7015..20d55f8243323 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs @@ -1280,7 +1280,7 @@ void M() comp.VerifyEmitDiagnostics( // (8,16): error CS0206: A property or indexer may not be passed as an out or ref parameter // M2(out Property); // 1 - Diagnostic(ErrorCode.ERR_RefProperty, "Property").WithArguments("C.Property").WithLocation(8, 16) + Diagnostic(ErrorCode.ERR_RefProperty, "Property").WithLocation(8, 16) ); } @@ -1408,19 +1408,19 @@ public class C comp.VerifyEmitDiagnostics( // (4,13): error CS8145: Auto-implemented properties cannot return by reference // ref int Property1 { get; init; } - Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "Property1").WithArguments("C.Property1").WithLocation(4, 13), + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "Property1").WithLocation(4, 13), // (4,30): error CS8147: Properties which return by reference cannot have set accessors // ref int Property1 { get; init; } - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithArguments("C.Property1.init").WithLocation(4, 30), + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(4, 30), // (5,13): error CS8146: Properties which return by reference must have a get accessor // ref int Property2 { init; } - Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "Property2").WithArguments("C.Property2").WithLocation(5, 13), + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "Property2").WithLocation(5, 13), // (6,44): error CS8147: Properties which return by reference cannot have set accessors // ref int Property3 { get => throw null; init => throw null; } - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithArguments("C.Property3.init").WithLocation(6, 44), + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "init").WithLocation(6, 44), // (7,13): error CS8146: Properties which return by reference must have a get accessor // ref int Property4 { init => throw null; } - Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "Property4").WithArguments("C.Property4").WithLocation(7, 13) + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "Property4").WithLocation(7, 13) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index df5ff10699812..26919900014f6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -1973,7 +1973,7 @@ class C { C() { string.Empty.Select(x => Unbound1, Unbound2 Unbound2); } }"; CreateCompilationWithMscorlib40AndSystemCore(source).VerifyDiagnostics( // (2,61): error CS1003: Syntax error, ',' expected // class C { C() { string.Empty.Select(x => Unbound1, Unbound2 Unbound2); } } - Diagnostic(ErrorCode.ERR_SyntaxError, "Unbound2").WithArguments(",", "").WithLocation(2, 61), + Diagnostic(ErrorCode.ERR_SyntaxError, "Unbound2").WithArguments(",").WithLocation(2, 61), // (2,52): error CS0103: The name 'Unbound2' does not exist in the current context // class C { C() { string.Empty.Select(x => Unbound1, Unbound2 Unbound2); } } Diagnostic(ErrorCode.ERR_NameNotInContext, "Unbound2").WithArguments("Unbound2").WithLocation(2, 52), @@ -6373,42 +6373,6 @@ static void Main() Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "int").WithArguments("", "int").WithLocation(6, 29)); } - [Fact] - public void ParameterScope_NotInMethodAttributeNameOf() - { - var comp = CreateCompilation(@" -class C -{ - void M() - { - - var _ = - [My(nameof(parameter))] // 1 - void(int parameter) => { }; - } - - [My(nameof(parameter))] // 2 - void M2(int parameter) { } -} - -public class MyAttribute : System.Attribute -{ - public MyAttribute(string name1) { } -} -"); - comp.VerifyDiagnostics( - // (8,24): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] // 1 - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 24), - // (12,16): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] // 2 - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(12, 16) - ); - - VerifyParameter(comp, 0); - VerifyParameter(comp, 1); - } - /// /// Look for usages of "parameter" and verify the index-th one. /// @@ -6601,38 +6565,6 @@ public MyAttribute(string name1) { } VerifyParameter(comp, 1); } - [Fact] - public void ParameterScope_NotInParameterAttributeNameOf() - { - var comp = CreateCompilation(@" -class C -{ - void M() - { - var _ = void ([My(nameof(parameter))] int parameter) => throw null; - } - - void M2([My(nameof(parameter))] int parameter) => throw null; -} - -public class MyAttribute : System.Attribute -{ - public MyAttribute(string name1) { } -} -"); - comp.VerifyDiagnostics( - // (6,34): error CS0103: The name 'parameter' does not exist in the current context - // var _ = void ([My(nameof(parameter))] int parameter) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 34), - // (9,24): error CS0103: The name 'parameter' does not exist in the current context - // void M2([My(nameof(parameter))] int parameter) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(9, 24) - ); - - VerifyParameter(comp, 0); - VerifyParameter(comp, 1); - } - [Fact] public void ParameterScope_InParameterDefaultValueNameOf() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index 127d02f7d48c7..9a6a8774cdc96 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -12,6 +12,7 @@ using Roslyn.Utilities; using System; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using Xunit; @@ -775,7 +776,7 @@ void local2() { } Diagnostic(ErrorCode.ERR_NameNotInContext, "var").WithArguments("var").WithLocation(18, 16), // (18,20): error CS1003: Syntax error, ',' expected // [A(out var s)] - Diagnostic(ErrorCode.ERR_SyntaxError, "s").WithArguments(",", "").WithLocation(18, 20)); + Diagnostic(ErrorCode.ERR_SyntaxError, "s").WithArguments(",").WithLocation(18, 20)); } [Fact] @@ -3849,7 +3850,7 @@ int Goo Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(8, 16), // (13,17): error CS1003: Syntax error, ',' expected // int Bar => 2; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(13, 17), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(13, 17), // (13,20): error CS1002: ; expected // int Bar => 2; Diagnostic(ErrorCode.ERR_SemicolonExpected, "2").WithLocation(13, 20), @@ -7119,9 +7120,9 @@ async static void B4() { } } [Fact, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] - public void TypeParameterScope_NotInMethodAttributeNameOf() + public void TypeParameterScope_InMethodAttributeNameOf() { - var comp = CreateCompilation(@" + var source = @" class C { void M() @@ -7140,7 +7141,8 @@ public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (8,20): error CS0103: The name 'TParameter' does not exist in the current context // [My(nameof(TParameter))] // 1 @@ -7152,346 +7154,2216 @@ public MyAttribute(string name1) { } VerifyTParameter(comp, 0, null); VerifyTParameter(comp, 1, null); - } - - /// - /// Look for usages of "TParameter" and verify the index-th one. - /// - private void VerifyTParameter(CSharpCompilation comp, int index, string expectedMethod, bool findAnyways = false, bool lookupFailsAnyways = false) - { - var tree = comp.SyntaxTrees.Single(); - var model = comp.GetSemanticModel(tree); - var tParameterUsages = tree.GetRoot().DescendantNodes().OfType() - .Where(i => i.Identifier.ValueText == "TParameter") - .Where(i => i.Ancestors().Any(a => a.IsKind(SyntaxKind.Attribute) || a.IsKind(SyntaxKind.TypeConstraint) || a.IsKind(SyntaxKind.DefaultExpression) || a.IsKind(SyntaxKind.InvocationExpression))) - .ToArray(); - - var tParameterUsage = tParameterUsages[index]; - - var symbol = model.GetSymbolInfo(tParameterUsage).Symbol; - if (expectedMethod is null) - { - Assert.Null(symbol); - var typeInfo = model.GetTypeInfo(tParameterUsage); - if (findAnyways) - { - // In certain cases, like `[TParameter]`, we're able to bind the attribute, find the type but reject it. - // So GetTypeInfo does return a type. - Assert.Equal(SymbolKind.TypeParameter, typeInfo.Type.Kind); - } - else - { - Assert.True(typeInfo.Type.IsErrorType()); - } + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); - Assert.Equal(findAnyways, model.LookupSymbols(tParameterUsage.Position).ToTestDisplayStrings().Contains("TParameter")); - } - else - { - Assert.Equal(expectedMethod, symbol.ContainingSymbol.ToTestDisplayString()); - Assert.Equal(SymbolKind.TypeParameter, model.GetTypeInfo(tParameterUsage).Type.Kind); - Assert.Equal(!lookupFailsAnyways, model.LookupSymbols(tParameterUsage.Position).ToTestDisplayStrings().Contains("TParameter")); - } + VerifyTParameter(comp, 0, "void local()"); + VerifyTParameter(comp, 1, "void C.M2()"); } - [Fact] - public void TypeParameterScope_NotInMethodAttribute() + [Fact, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] + public void TypeParameterScope_InMethodAttributeNameOfNameOf() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { local(); - [My(TParameter)] // 1 + [My(nameof(nameof(TParameter)))] // 1 void local() { } } - [My(TParameter)] // 2 + [My(nameof(nameof(TParameter)))] // 2 void M2() { } } public class MyAttribute : System.Attribute { - public MyAttribute(object o) { } + public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,13): error CS0103: The name 'TParameter' does not exist in the current context - // [My(TParameter)] // 1 - Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(8, 13), - // (12,9): error CS0103: The name 'TParameter' does not exist in the current context - // [My(TParameter)] // 2 - Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(12, 9) + // (8,27): error CS0103: The name 'TParameter' does not exist in the current context + // [My(nameof(nameof(TParameter)))] // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(8, 27), + // (12,23): error CS0103: The name 'TParameter' does not exist in the current context + // [My(nameof(nameof(TParameter)))] // 2 + Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(12, 23) ); VerifyTParameter(comp, 0, null); VerifyTParameter(comp, 1, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (8,20): error CS8081: Expression does not have a name. + // [My(nameof(nameof(TParameter)))] // 1 + Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "nameof(TParameter)").WithLocation(8, 20), + // (12,16): error CS8081: Expression does not have a name. + // [My(nameof(nameof(TParameter)))] // 2 + Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "nameof(TParameter)").WithLocation(12, 16) + ); + + VerifyTParameter(comp, 0, "void local()"); + VerifyTParameter(comp, 1, "void C.M2()"); } - [Fact] - public void TypeParameterScope_NotInMethodAttributeTypeArgument() + [Fact, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] + public void TypeParameterScope_InMethodAttributeNameOf_TopLevel() { - var comp = CreateCompilation(@" -class C -{ - void M() - { - local(); - - [My] // 1 - void local() { } - } + var source = @" +local(); - [My] // 2 - void M2() { } -} +[My(nameof(TParameter))] // 1 +void local() { } -public class MyAttribute : System.Attribute +public class MyAttribute : System.Attribute { + public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,13): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) - // [My] // 1 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 13), - // (12,9): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) - // [My] // 2 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 9) + // (4,12): error CS0103: The name 'TParameter' does not exist in the current context + // [My(nameof(TParameter))] // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(4, 12) ); VerifyTParameter(comp, 0, null); - VerifyTParameter(comp, 1, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyTParameter(comp, 0, "void local()"); } [Fact] - public void TypeParameterScope_NotAsMethodAttributeType() + public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithNewAttribute() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { - local(); + local(); - [TParameter] // 1 - void local() where TParameter : System.Attribute { } + //[My(nameof(TParameter))] + void local() { } } - [TParameter] // 2 - void M2() where TParameter : System.Attribute { } + //[My(nameof(TParameter))] + void M2() { } } -"); - comp.VerifyDiagnostics( - // (8,10): error CS0246: The type or namespace name 'TParameterAttribute' could not be found (are you missing a using directive or an assembly reference?) - // [TParameter] // 1 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameterAttribute").WithLocation(8, 10), - // (8,10): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) - // [TParameter] // 1 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 10), - // (12,6): error CS0246: The type or namespace name 'TParameterAttribute' could not be found (are you missing a using directive or an assembly reference?) - // [TParameter] // 2 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameterAttribute").WithLocation(12, 6), - // (12,6): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) - // [TParameter] // 2 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 6) - ); - VerifyTParameter(comp, 0, null); - VerifyTParameter(comp, 1, null); +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + // C# 10 + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees.Single(); + var parentModel = comp.GetSemanticModel(tree); + // Note: offset by one to the left to get away from return type + var localFuncPosition = tree.GetText().ToString().IndexOf("void local()", StringComparison.Ordinal) - 1; + var methodPosition = tree.GetText().ToString().IndexOf("void M2()", StringComparison.Ordinal) - 1; + + var attr = parseAttributeSyntax("[My(nameof(TParameter))]", TestOptions.Regular10); + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); + + attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.Regular10); + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); + + // C# 11 + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + tree = comp.SyntaxTrees.Single(); + parentModel = comp.GetSemanticModel(tree); + + attr = parseAttributeSyntax("[My(nameof(TParameter))]", TestOptions.RegularNext); + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); + + attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.RegularNext); + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); + + return; + + // Note: this results in an attribute on a method, but that doesn't bring any extra type parameters + static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) + => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType().Single(); + } + + static void VerifyTParameterSpeculation(SemanticModel parentModel, int localFuncPosition, AttributeSyntax attr1, bool found = true) + { + SemanticModel speculativeModel; + var success = parentModel.TryGetSpeculativeSemanticModel(localFuncPosition, attr1, out speculativeModel); + Assert.True(success); + Assert.NotNull(speculativeModel); + + var symbolInfo = speculativeModel.GetSymbolInfo(getTParameter(attr1)); + if (found) + { + Assert.Equal(SymbolKind.TypeParameter, symbolInfo.Symbol.Kind); + } + else + { + Assert.Null(symbolInfo.Symbol); + } + return; + + static IdentifierNameSyntax getTParameter(CSharpSyntaxNode node) + { + return node.DescendantNodes().OfType().Where(i => i.Identifier.ValueText == "TParameter").Single(); + } } [Fact] - public void TypeParameterScope_NotInMethodAttributeDefault() + public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithinAttribute() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { local(); - [My(default(TParameter))] - void local() where TParameter : class => throw null; + [My(a)] + [My(nameof(b))] + void local() { } } - [My(default(TParameter))] - void M2() where TParameter : class => throw null; + [My(c)] + [My(nameof(d))] + void M2() { } } public class MyAttribute : System.Attribute { - public MyAttribute(object o) { } + public MyAttribute(string name1) { } } -"); +"; + // C# 10 + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,21): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) - // [My(default(TParameter))] - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 21), - // (12,17): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) - // [My(default(TParameter))] - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 17) + // (8,13): error CS0103: The name 'a' does not exist in the current context + // [My(a)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "a").WithArguments("a").WithLocation(8, 13), + // (9,20): error CS0103: The name 'b' does not exist in the current context + // [My(nameof(b))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(9, 20), + // (13,9): error CS0103: The name 'c' does not exist in the current context + // [My(c)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "c").WithArguments("c").WithLocation(13, 9), + // (14,16): error CS0103: The name 'd' does not exist in the current context + // [My(nameof(d))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "d").WithArguments("d").WithLocation(14, 16) ); - VerifyTParameter(comp, 0, null); - VerifyTParameter(comp, 1, null); + var tree = comp.SyntaxTrees.Single(); + var parentModel = comp.GetSemanticModel(tree); + + var aPosition = getIdentifierPosition("a"); + var newNameOf = parseNameof("nameof(TParameter)", parseOptions: TestOptions.Regular10); + Assert.Equal("System.String", parentModel.GetSpeculativeTypeInfo(aPosition, newNameOf, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); + + var bPosition = getIdentifierPosition("b"); + var newNameOfArgument = parseIdentifier("TParameter", parseOptions: TestOptions.Regular10); + Assert.True(parentModel.GetSpeculativeTypeInfo(bPosition, newNameOfArgument, SpeculativeBindingOption.BindAsExpression).Type.IsErrorType()); + + var cPosition = getIdentifierPosition("c"); + Assert.Equal("System.String", parentModel.GetSpeculativeTypeInfo(cPosition, newNameOf, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); + + var dPosition = getIdentifierPosition("d"); + Assert.True(parentModel.GetSpeculativeTypeInfo(dPosition, newNameOfArgument, SpeculativeBindingOption.BindAsExpression).Type.IsErrorType()); + + // C# 11 + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (8,13): error CS0103: The name 'a' does not exist in the current context + // [My(a)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "a").WithArguments("a").WithLocation(8, 13), + // (9,20): error CS0103: The name 'b' does not exist in the current context + // [My(nameof(b))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(9, 20), + // (13,9): error CS0103: The name 'c' does not exist in the current context + // [My(c)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "c").WithArguments("c").WithLocation(13, 9), + // (14,16): error CS0103: The name 'd' does not exist in the current context + // [My(nameof(d))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "d").WithArguments("d").WithLocation(14, 16) + ); + + tree = comp.SyntaxTrees.Single(); + parentModel = comp.GetSemanticModel(tree); + + aPosition = getIdentifierPosition("a"); + newNameOf = parseNameof("nameof(TParameter)", parseOptions: TestOptions.RegularNext); + Assert.Equal("System.String", parentModel.GetSpeculativeTypeInfo(aPosition, newNameOf, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); + + bPosition = getIdentifierPosition("b"); + newNameOfArgument = parseIdentifier("TParameter", parseOptions: TestOptions.RegularNext); + Assert.Equal("TParameter", parentModel.GetSpeculativeTypeInfo(bPosition, newNameOfArgument, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); + + cPosition = getIdentifierPosition("c"); + Assert.Equal("System.String", parentModel.GetSpeculativeTypeInfo(cPosition, newNameOf, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); + + dPosition = getIdentifierPosition("d"); + Assert.Equal("TParameter", parentModel.GetSpeculativeTypeInfo(dPosition, newNameOfArgument, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); + + return; + + int getIdentifierPosition(string identifier) + { + return tree.GetRoot().DescendantNodes().OfType().Where(i => i.Identifier.ValueText == identifier).Single().SpanStart; + } + + static ExpressionSyntax parseNameof(string source, CSharpParseOptions parseOptions) + => SyntaxFactory.ParseCompilationUnit($@"{source};", options: parseOptions).DescendantNodes().OfType().Single(); + + static ExpressionSyntax parseIdentifier(string source, CSharpParseOptions parseOptions) + => SyntaxFactory.ParseCompilationUnit($@"{source};", options: parseOptions).DescendantNodes().OfType().Single(); } - [Fact, WorkItem(60110, "https://github.com/dotnet/roslyn/issues/60110")] - public void TypeParameterScope_NotInParameterAttribute() + [Fact] + public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithReplacementAttribute() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { - local(0); + local(); - void local([My(TParameter)] int i) => throw null; + [My(a)] + void local() { } } - void M2([My(TParameter)] int i) => throw null; + [My(b)] + void M2() { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); - // TParameter unexpectedly was found in local function case because of IsInMethodBody logic - // Tracked by https://github.com/dotnet/roslyn/issues/60110 +"; + // C# 10 + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,36): error CS0119: 'TParameter' is a type, which is not valid in the given context - // void local([My(TParameter)] int i) => throw null; - Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(8, 36), - // (11,29): error CS0103: The name 'TParameter' does not exist in the current context - // void M2([My(TParameter)] int i) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(11, 29) + // (8,13): error CS0103: The name 'a' does not exist in the current context + // [My(a)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "a").WithArguments("a").WithLocation(8, 13), + // (12,9): error CS0103: The name 'b' does not exist in the current context + // [My(b)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(12, 9) ); - //VerifyTParameter(comp, 0, null); - VerifyTParameter(comp, 1, null); + var tree = comp.SyntaxTrees.Single(); + var parentModel = comp.GetSemanticModel(tree); + var localFuncPosition = tree.GetText().ToString().IndexOf("[My(a)]", StringComparison.Ordinal); + var methodPosition = tree.GetText().ToString().IndexOf("[My(b)]", StringComparison.Ordinal); + + var attr = parseAttributeSyntax("[My(nameof(TParameter))]", TestOptions.Regular10); + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); + + attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.Regular10); + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); + + // C# 11 + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (8,13): error CS0103: The name 'a' does not exist in the current context + // [My(a)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "a").WithArguments("a").WithLocation(8, 13), + // (12,9): error CS0103: The name 'b' does not exist in the current context + // [My(b)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(12, 9) + ); + + tree = comp.SyntaxTrees.Single(); + parentModel = comp.GetSemanticModel(tree); + + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); + + attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.Regular10); + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); + + return; + + static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) + => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType().Single(); } [Fact] - public void TypeParameterScope_InParameterAttributeNameOf() + public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { - local(0); + local(); - void local([My(nameof(TParameter))] int i) => throw null; + [My(positionA)] + void local() { } } - void M2([My(nameof(TParameter))] int i) => throw null; + [My(positionB)] + void M2() { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); - comp.VerifyDiagnostics(); +"; + // C# 10 + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (8,13): error CS0103: The name 'positionA' does not exist in the current context + // [My(positionA)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 13), + // (12,9): error CS0103: The name 'positionB' does not exist in the current context + // [My(positionB)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(12, 9) + ); - VerifyTParameter(comp, 0, "void local(System.Int32 i)"); - // LookupSymbols fails to find TParameter - // Tracked by https://github.com/dotnet/roslyn/issues/60194 - VerifyTParameter(comp, 1, "void C.M2(System.Int32 i)", lookupFailsAnyways: true); - } + var tree = comp.SyntaxTrees.Single(); + var parentModel = comp.GetSemanticModel(tree); + var localFuncPosition = tree.GetText().ToString().IndexOf("positionA", StringComparison.Ordinal); + var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); - [Fact] - public void TypeParameterScope_InParameterAttributeTypeOf() - { - var comp = CreateCompilation(@" -class C + var attr = parseAttributeSyntax("[My(nameof(TParameter))]", TestOptions.Regular10); + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); + + attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.Regular10); + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); + + // C# 11 + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (8,13): error CS0103: The name 'positionA' does not exist in the current context + // [My(positionA)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 13), + // (12,9): error CS0103: The name 'positionB' does not exist in the current context + // [My(positionB)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(12, 9) + ); + + tree = comp.SyntaxTrees.Single(); + parentModel = comp.GetSemanticModel(tree); + + attr = parseAttributeSyntax("[My(nameof(TParameter))]", TestOptions.Regular10); + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr); + VerifyTParameterSpeculation(parentModel, methodPosition, attr); + + attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.Regular10); + VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); + + return; + + static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) + => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType().Single(); + } + + [Fact, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] + [WorkItem(60194, "https://github.com/dotnet/roslyn/issues/60194")] + public void TypeParameterScope_InMethodAttributeNameOf_CompatBreak() + { + var source = @" +class C +{ + class TParameter + { + public const string Constant = """"; + } + + void M() + { + local(); + + [My(nameof(TParameter.Constant))] // 1 + void local() { } + } + + [My(nameof(TParameter.Constant))] // 2 + void M2() { } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + // The break will also apply to C# 10 and earlier when .NET 7 ships, + // but is currently scoped down to users of LangVer=preview. + // Tracked by https://github.com/dotnet/roslyn/issues/60640 + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + + VerifyTParameter(comp, 0, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "C.TParameter"); + VerifyTParameter(comp, 1, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "C.TParameter"); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (13,20): error CS0119: 'TParameter' is a type parameter, which is not valid in the given context + // [My(nameof(TParameter.Constant))] // 1 + Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type parameter").WithLocation(13, 20), + // (17,16): error CS0119: 'TParameter' is a type parameter, which is not valid in the given context + // [My(nameof(TParameter.Constant))] // 2 + Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type parameter").WithLocation(17, 16) + ); + + VerifyTParameter(comp, 0, "void local()"); + VerifyTParameter(comp, 1, "void C.M2()"); + } + + /// + /// Look for usages of "TParameter" and verify the index-th one. + /// + private void VerifyTParameter(CSharpCompilation comp, int index, string expectedContainer, bool findAnyways = false, string lookupFinds = "TParameter", SymbolKind symbolKind = SymbolKind.TypeParameter) + { + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var tParameterUsages = tree.GetRoot().DescendantNodes().OfType() + .Where(i => i.Identifier.ValueText == "TParameter") + .Where(i => i.Ancestors().Any(a => a.Kind() is SyntaxKind.Attribute or SyntaxKind.TypeConstraint or SyntaxKind.DefaultExpression or SyntaxKind.InvocationExpression or SyntaxKind.EqualsValueClause)) + .ToArray(); + + var tParameterUsage = tParameterUsages[index]; + + var symbol = model.GetSymbolInfo(tParameterUsage).Symbol; + if (expectedContainer is null) + { + Assert.Null(symbol); + + var typeInfo = model.GetTypeInfo(tParameterUsage); + if (findAnyways) + { + // In certain cases, like `[TParameter]`, we're able to bind the attribute, find the type but reject it. + // So GetTypeInfo does return a type. + Assert.Equal(SymbolKind.TypeParameter, typeInfo.Type.Kind); + } + else + { + Assert.True(typeInfo.Type.IsErrorType()); + } + + Assert.Equal(findAnyways, model.LookupSymbols(tParameterUsage.Position).ToTestDisplayStrings().Contains("TParameter")); + } + else + { + Assert.Equal(expectedContainer, symbol.ContainingSymbol.ToTestDisplayString()); + Assert.Equal(symbolKind, model.GetTypeInfo(tParameterUsage).Type.Kind); + + var lookupResults = model.LookupSymbols(tParameterUsage.Position).ToTestDisplayStrings(); + Assert.Contains(lookupFinds, lookupResults); + if (lookupFinds != "TParameter") + { + Assert.DoesNotContain("TParameter", lookupResults); + } + } + } + + [Fact] + public void TypeParameterScope_NotInMethodAttribute() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + [My(TParameter)] // 1 + void local() { } + } + + [My(TParameter)] // 2 + void M2() { } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(object o) { } +} +"); + comp.VerifyDiagnostics( + // (8,13): error CS0103: The name 'TParameter' does not exist in the current context + // [My(TParameter)] // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(8, 13), + // (12,9): error CS0103: The name 'TParameter' does not exist in the current context + // [My(TParameter)] // 2 + Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(12, 9) + ); + + VerifyTParameter(comp, 0, null); + VerifyTParameter(comp, 1, null); + } + + [Fact] + public void TypeParameterScope_NotInMethodAttributeTypeArgument() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + [My] // 1 + void local() { } + } + + [My] // 2 + void M2() { } +} + +public class MyAttribute : System.Attribute +{ +} +"); + comp.VerifyDiagnostics( + // (8,13): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) + // [My] // 1 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 13), + // (12,9): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) + // [My] // 2 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 9) + ); + + VerifyTParameter(comp, 0, null); + VerifyTParameter(comp, 1, null); + } + + [Fact] + public void TypeParameterScope_NotAsMethodAttributeType() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + [TParameter] // 1 + void local() where TParameter : System.Attribute { } + } + + [TParameter] // 2 + void M2() where TParameter : System.Attribute { } +} +"); + comp.VerifyDiagnostics( + // (8,10): error CS0246: The type or namespace name 'TParameterAttribute' could not be found (are you missing a using directive or an assembly reference?) + // [TParameter] // 1 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameterAttribute").WithLocation(8, 10), + // (8,10): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) + // [TParameter] // 1 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 10), + // (12,6): error CS0246: The type or namespace name 'TParameterAttribute' could not be found (are you missing a using directive or an assembly reference?) + // [TParameter] // 2 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameterAttribute").WithLocation(12, 6), + // (12,6): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) + // [TParameter] // 2 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 6) + ); + + VerifyTParameter(comp, 0, null); + VerifyTParameter(comp, 1, null); + } + + [Fact] + public void TypeParameterScope_NotInMethodAttributeDefault() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + [My(default(TParameter))] + void local() where TParameter : class => throw null; + } + + [My(default(TParameter))] + void M2() where TParameter : class => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(object o) { } +} +"); + comp.VerifyDiagnostics( + // (8,21): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) + // [My(default(TParameter))] + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 21), + // (12,17): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) + // [My(default(TParameter))] + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 17) + ); + + VerifyTParameter(comp, 0, null); + VerifyTParameter(comp, 1, null); + } + + [Fact, WorkItem(60110, "https://github.com/dotnet/roslyn/issues/60110")] + public void TypeParameterScope_NotInParameterAttribute() + { + var comp = CreateCompilation(@" +class C { void M() { local(0); - void local([My(typeof(TParameter))] int i) => throw null; + void local([My(TParameter)] int i) => throw null; } - void M2([My(typeof(TParameter))] int i) => throw null; + void M2([My(TParameter)] int i) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } } +"); + // TParameter unexpectedly was found in local function case because of IsInMethodBody logic + // Tracked by https://github.com/dotnet/roslyn/issues/60110 + comp.VerifyDiagnostics( + // (8,36): error CS0119: 'TParameter' is a type, which is not valid in the given context + // void local([My(TParameter)] int i) => throw null; + Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(8, 36), + // (11,29): error CS0103: The name 'TParameter' does not exist in the current context + // void M2([My(TParameter)] int i) => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(11, 29) + ); + + //VerifyTParameter(comp, 0, null); + VerifyTParameter(comp, 1, null); + } + + [Fact, WorkItem(60110, "https://github.com/dotnet/roslyn/issues/60110")] + public void TypeParameterScope_NotInParameterAttribute_NotShadowingConst() + { + var comp = CreateCompilation(@" +class C +{ + const string TParameter = """"; + + void M() + { + local(0); + + void local([My(TParameter)] int i) => throw null; + } + + void M2([My(TParameter)] int i) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + // TParameter unexpectedly was found in local function case because of IsInMethodBody logic + // Tracked by https://github.com/dotnet/roslyn/issues/60110 + comp.VerifyDiagnostics( + // (10,36): error CS0119: 'TParameter' is a type, which is not valid in the given context + // void local([My(TParameter)] int i) => throw null; + Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(10, 36) + ); + + //VerifyTParameter(comp, 0, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "System.String C.TParameter"); + VerifyTParameter(comp, 1, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "System.String C.TParameter"); + } + + [Fact, WorkItem(60194, "https://github.com/dotnet/roslyn/issues/60194")] + public void TypeParameterScope_InParameterAttributeNameOf() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(0); + + void local([My(nameof(TParameter))] int i) => throw null; + } + + void M2([My(nameof(TParameter))] int i) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + comp.VerifyDiagnostics(); + + VerifyTParameter(comp, 0, "void local(System.Int32 i)"); + VerifyTParameter(comp, 1, "void C.M2(System.Int32 i)"); + } + + [Fact] + public void TypeParameterScope_InParameterAttributeTypeOf() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(0); + + void local([My(typeof(TParameter))] int i) => throw null; + } + + void M2([My(typeof(TParameter))] int i) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(System.Type type) { } +} +"); + comp.VerifyDiagnostics( + // (8,36): error CS0416: 'TParameter': an attribute argument cannot use type parameters + // void local([My(typeof(TParameter))] int i) => throw null; + Diagnostic(ErrorCode.ERR_AttrArgWithTypeVars, "typeof(TParameter)").WithArguments("TParameter").WithLocation(8, 36), + // (11,29): error CS0416: 'TParameter': an attribute argument cannot use type parameters + // void M2([My(typeof(TParameter))] int i) => throw null; + Diagnostic(ErrorCode.ERR_AttrArgWithTypeVars, "typeof(TParameter)").WithArguments("TParameter").WithLocation(11, 29) + ); + + VerifyTParameter(comp, 0, "void local(System.Int32 i)"); + VerifyTParameter(comp, 1, "void C.M2(System.Int32 i)"); + } + + [Fact] + public void TypeParameterScope_InParameterAttributeSizeOf() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(0); + + void local([My(sizeof(TParameter))] int i) where TParameter : unmanaged => throw null; + } + + void M2([My(sizeof(TParameter))] int i) where TParameter : unmanaged => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(int i) { } +} +"); + comp.VerifyDiagnostics( + // (8,36): error CS0233: 'TParameter' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // void local([My(sizeof(TParameter))] int i) where TParameter : unmanaged => throw null; + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(TParameter)").WithArguments("TParameter").WithLocation(8, 36), + // (11,29): error CS0233: 'TParameter' does not have a predefined size, therefore sizeof can only be used in an unsafe context + // void M2([My(sizeof(TParameter))] int i) where TParameter : unmanaged => throw null; + Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(TParameter)").WithArguments("TParameter").WithLocation(11, 29) + ); + + VerifyTParameter(comp, 0, "void local(System.Int32 i)"); + VerifyTParameter(comp, 1, "void C.M2(System.Int32 i)"); + } + + [Fact] + public void TypeParameterScope_InParameterAttributeDefault() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(0); + + void local([My(default(TParameter))] int i) where TParameter : class => throw null; + } + + void M2([My(default(TParameter))] int i) where TParameter : class => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(object o) { } +} +"); + comp.VerifyDiagnostics(); + + VerifyTParameter(comp, 0, "void local(System.Int32 i)"); + VerifyTParameter(comp, 1, "void C.M2(System.Int32 i)"); + } + + [Fact] + public void TypeParameterScope_AsParameterAttributeType() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(0); + + void local([TParameter] int i) where TParameter : System.Attribute => throw null; + } + + void M2([TParameter] int i) where TParameter : System.Attribute => throw null; +} +"); + comp.VerifyDiagnostics( + // (8,33): error CS0616: 'TParameter' is not an attribute class + // void local([TParameter] int i) where TParameter : System.Attribute => throw null; + Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(8, 33), + // (11,26): error CS0616: 'TParameter' is not an attribute class + // void M2([TParameter] int i) where TParameter : System.Attribute => throw null; + Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(11, 26) + ); + + VerifyTParameter(comp, 0, null, findAnyways: true); + VerifyTParameter(comp, 1, null, findAnyways: true); + } + + [Fact] + public void TypeParameterScope_InReturnType() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + TParameter local() => throw null; + } + + TParameter M2() => throw null; +} +"); + comp.VerifyDiagnostics(); + } + + [Fact] + public void TypeParameterScope_InParameterType() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(null); + + void local(TParameter p) => throw null; + } + + void M2(TParameter p) => throw null; +} +"); + comp.VerifyDiagnostics(); + } + + [Fact] + public void TypeParameterScope_InTypeConstraint() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + void local() where TParameter2 : TParameter => throw null; + } + + void M2() where TParameter2 : TParameter => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + comp.VerifyDiagnostics(); + + VerifyTParameter(comp, 0, "void local()"); + VerifyTParameter(comp, 1, "void C.M2()"); + } + + [Fact] + public void TypeParameterScope_NotInMethodAttributeTypeOf() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + [My(typeof(TParameter))] + void local() => throw null; + } + + [My(typeof(TParameter))] + void M2() => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + comp.VerifyDiagnostics( + // (8,20): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) + // [My(typeof(TParameter))] + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 20), + // (12,16): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) + // [My(typeof(TParameter))] + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 16) + ); + + VerifyTParameter(comp, 0, null); + VerifyTParameter(comp, 1, null); + } + + [Fact, WorkItem(60110, "https://github.com/dotnet/roslyn/issues/60110")] + public void TypeParameterScope_NotInTypeParameterAttribute() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + void local<[My(TParameter)] TParameter>() => throw null; + } + + void M2<[My(TParameter)] TParameter>() => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + // TParameter unexpectedly was found in local function case because of IsInMethodBody logic + // Tracked by https://github.com/dotnet/roslyn/issues/60110 + comp.VerifyDiagnostics( + // (8,24): error CS0119: 'TParameter' is a type, which is not valid in the given context + // void local<[My(TParameter)] TParameter>() => throw null; + Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(8, 24), + // (11,17): error CS0103: The name 'TParameter' does not exist in the current context + // void M2<[My(TParameter)] TParameter>() => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(11, 17) + ); + + //VerifyTParameter(comp, 0, null); + VerifyTParameter(comp, 1, null); + } + + [Fact, WorkItem(60194, "https://github.com/dotnet/roslyn/issues/60194")] + public void TypeParameterScope_InTypeParameterAttributeNameOf() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + void local<[My(nameof(TParameter))] TParameter>() => throw null; + } + + void M2<[My(nameof(TParameter))] TParameter>() => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + comp.VerifyDiagnostics(); + + VerifyTParameter(comp, 0, "void local()"); + VerifyTParameter(comp, 1, "void C.M2()"); + } + + [Fact] + public void TypeParameterScope_InTypeParameterAttributeDefault() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + void local<[My(default(TParameter))] TParameter>() where TParameter : class => throw null; + } + + void M2<[My(default(TParameter))] TParameter>() where TParameter : class => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(object o) { } +} +"); + comp.VerifyDiagnostics(); + + VerifyTParameter(comp, 0, "void local()"); + VerifyTParameter(comp, 1, "void C.M2()"); + } + + [Fact] + public void TypeParameterScope_AsTypeParameterAttributeType() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + void local<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; + } + + void M2<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + comp.VerifyDiagnostics( + // (8,21): error CS0616: 'TParameter' is not an attribute class + // void local<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; + Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(8, 21), + // (11,14): error CS0616: 'TParameter' is not an attribute class + // void M2<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; + Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(11, 14) + ); + + VerifyTParameter(comp, 0, null, findAnyways: true); + VerifyTParameter(comp, 1, null, findAnyways: true); + } + + [Fact] + public void TypeParameterScope_InParameterDefaultDefaultValue() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + void local(TParameter s = default(TParameter)) => throw null; + } + + void M2(TParameter s = default(TParameter)) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + comp.VerifyDiagnostics(); + + VerifyTParameter(comp, 0, "void local([TParameter s = default(TParameter)])"); + VerifyTParameter(comp, 1, "void C.M2([TParameter s = default(TParameter)])"); + } + + [Fact] + public void TypeParameterScope_InParameterDefaultValue() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + void local(TParameter s = TParameter) => throw null; + } + + void M2(TParameter s = TParameter) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + // TParameter unexpectedly was found in local function case because of IsInMethodBody logic + // Tracked by https://github.com/dotnet/roslyn/issues/60110 + comp.VerifyDiagnostics( + // (8,47): error CS0119: 'TParameter' is a type, which is not valid in the given context + // void local(TParameter s = TParameter) => throw null; + Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(8, 47), + // (11,40): error CS0103: The name 'TParameter' does not exist in the current context + // void M2(TParameter s = TParameter) => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(11, 40) + ); + + //VerifyTParameter(comp, 0, "void local([TParameter s = default(TParameter)])"); + VerifyTParameter(comp, 1, null); + } + + [Fact, WorkItem(60110, "https://github.com/dotnet/roslyn/issues/60110")] + public void TypeParameterScope_InParameterDefaultValue_NotShadowingConstant() + { + var comp = CreateCompilation(@" +class C +{ + const string TParameter = """"; + + void M() + { + local(); + + void local(string s = TParameter) => throw null; + } + + void M2(string s = TParameter) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + // TParameter unexpectedly was found in local function case because of IsInMethodBody logic + // Tracked by https://github.com/dotnet/roslyn/issues/60110 + comp.VerifyDiagnostics( + // (10,43): error CS0119: 'TParameter' is a type, which is not valid in the given context + // void local(string s = TParameter) => throw null; + Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(10, 43) + ); + + //VerifyTParameter(comp, 0, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "System.String C.TParameter"); + VerifyTParameter(comp, 1, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "System.String C.TParameter"); + } + + [Fact, WorkItem(60194, "https://github.com/dotnet/roslyn/issues/60194")] + public void TypeParameterScope_InParameterNameOfDefaultValue() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + void local(string s = nameof(TParameter)) => throw null; + } + + void M2(string s = nameof(TParameter)) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + comp.VerifyDiagnostics(); + + VerifyTParameter(comp, 0, @"void local([System.String s = ""TParameter""])"); + VerifyTParameter(comp, 1, @"void C.M2([System.String s = ""TParameter""])"); + } + + [Fact] + public void TypeParameterScope_InParameterNameOfDefaultValue_NestedLocalFunction() + { + var comp = CreateCompilation(@" +class C +{ + const string TParameter = """"; + + void M() + { + local(); + + void local(string s = TParameter) => throw null; + } + + void M2(string s = TParameter) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + // TParameter unexpectedly was found in local function case because of IsInMethodBody logic + // Tracked by https://github.com/dotnet/roslyn/issues/60110 + comp.VerifyDiagnostics( + // (10,43): error CS0119: 'TParameter' is a type, which is not valid in the given context + // void local(string s = TParameter) => throw null; + Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(10, 43) + ); + + //VerifyTParameter(comp, 0, "C", lookupFinds: "System.String C.TParameter", symbolKind: SymbolKind.NamedType); + VerifyTParameter(comp, 1, "C", lookupFinds: "System.String C.TParameter", symbolKind: SymbolKind.NamedType); + } + + [Fact] + public void TypeParameterScope_InTypeAttributeNameOf() + { + var comp = CreateCompilation(@" +[My(nameof(TParameter))] +class C +{ +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name) { } +} +"); + comp.VerifyDiagnostics(); + + VerifyTParameter(comp, 0, "C"); + } + + [Fact] + public void TypeParameterScope_InTypeAttributeConstant() + { + var comp = CreateCompilation(@" +[My(TParameter.Constant)] +class C where TParameter : I +{ +} + +interface I +{ + const string Constant = ""hello""; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name) { } +} +", targetFramework: TargetFramework.NetCoreApp); + + comp.VerifyDiagnostics( + // (2,5): error CS0119: 'TParameter' is a type parameter, which is not valid in the given context + // [My(TParameter.Constant)] + Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type parameter").WithLocation(2, 5) + ); + + VerifyTParameter(comp, 0, "C"); + } + + [Fact] + public void TypeParameterScope_InTypeAttributeType() + { + var comp = CreateCompilation(@" +[TParameter] +class C where TParameter : MyAttribute +{ +} + +public class MyAttribute : System.Attribute +{ +} +"); + comp.VerifyDiagnostics( + // (2,2): error CS0616: 'TParameter' is not an attribute class + // [TParameter] + Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(2, 2) + ); + + VerifyTParameter(comp, 0, null, findAnyways: true); + } + + [Fact] + public void TypeParameterScope_InRecordAttributeNameOf() + { + var source = @" +[My(nameof(TParameter))] +record R(); + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + VerifyTParameter(comp, 0, "R"); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + VerifyTParameter(comp, 0, "R"); + } + + [Fact] + public void TypeParameterScope_InRecordParameterAttributeNameOf() + { + var source = @" +record R([My(nameof(TParameter))] int I); + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + VerifyTParameter(comp, 0, "R"); + + comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + VerifyTParameter(comp, 0, "R"); + } + + [Fact] + public void TypeParameterScope_InRecordAttributeNameOfConstant() + { + var source = @" +[My(nameof(TParameter.Constant))] +record R() where TParameter : I; + +interface I +{ + const string Constant = ""hello""; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (2,12): error CS0119: 'TParameter' is a type parameter, which is not valid in the given context + // [My(nameof(TParameter.Constant))] + Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type parameter").WithLocation(2, 12) + ); + VerifyTParameter(comp, 0, "R"); + } + + [Fact] + public void TypeParameterScope_InRecordAttributeNameOf_RecordStruct() + { + var source = @" +[My(nameof(TParameter))] +record struct R(); + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + VerifyTParameter(comp, 0, "R"); + } + + [Fact] + public void TypeParameterScope_AsRecordAttributeType() + { + var source = @" +[TParameter] +record R() where TParameter : System.Attribute; +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (2,2): error CS0616: 'TParameter' is not an attribute class + // [TParameter] + Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(2, 2) + ); + VerifyTParameter(comp, 0, null, findAnyways: true); + } + + [Fact] + public void TypeParameterScope_InRecordAttributeTypeArgument() + { + var source = @" +[My] +record R() where TParameter : System.Attribute; + +public class MyAttribute : System.Attribute +{ + public MyAttribute() { } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (2,2): error CS8968: 'TParameter': an attribute type argument cannot use type parameters + // [My] + Diagnostic(ErrorCode.ERR_AttrTypeArgCannotBeTypeVar, "My").WithArguments("TParameter").WithLocation(2, 2) + ); + VerifyTParameter(comp, 0, "R"); + } + + [Fact] + public void TypeParameterScope_InRecordAttributeConstant() + { + var source = @" +[My(TParameter.Constant)] +record R() where TParameter : I; + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name) { } +} + +public interface I +{ + const string Constant = ""hello""; +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); + comp.VerifyDiagnostics( + // (2,5): error CS0119: 'TParameter' is a type parameter, which is not valid in the given context + // [My(TParameter.Constant)] + Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type parameter").WithLocation(2, 5) + ); + VerifyTParameter(comp, 0, "R"); + } + + [Fact] + public void ParameterScope_InMethodAttributeNameOf() + { + var source = @" +class C +{ + void M() + { + local(0); + + [My(nameof(parameter))] // 1 + void local(int parameter) { } + } + + [My(nameof(parameter))] // 2 + void M2(int parameter) { } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (8,20): error CS0103: The name 'parameter' does not exist in the current context + // [My(nameof(parameter))] // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 20), + // (12,16): error CS0103: The name 'parameter' does not exist in the current context + // [My(nameof(parameter))] // 2 + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(12, 16) + ); + + VerifyParameter(comp, 0, null); + VerifyParameter(comp, 1, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); + VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); + } + + /// + /// Look for usages of "parameter" and verify the index-th one. + /// + private void VerifyParameter(CSharpCompilation comp, int index, string expectedMethod, string parameterName = "parameter") + { + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + var parameterUsages = tree.GetRoot().DescendantNodes().OfType() + .Where(i => i.Identifier.ValueText == parameterName) + .Where(i => i.Ancestors().Any(a => a.IsKind(SyntaxKind.Attribute) || a.IsKind(SyntaxKind.TypeConstraint) || a.IsKind(SyntaxKind.DefaultExpression) || a.IsKind(SyntaxKind.InvocationExpression))) + .ToArray(); + + var parameterUsage = parameterUsages[index]; + + var symbol = model.GetSymbolInfo(parameterUsage).Symbol; + if (expectedMethod is null) + { + Assert.Null(symbol); + Assert.True(model.GetTypeInfo(parameterUsage).Type.IsErrorType()); + Assert.DoesNotContain("parameter", model.LookupSymbols(parameterUsage.Position).ToTestDisplayStrings()); + } + else + { + Assert.Equal(expectedMethod, symbol.ContainingSymbol.ToTestDisplayString()); + Assert.Equal("System.Int32", model.GetTypeInfo(parameterUsage).Type.ToTestDisplayString()); + + var lookupResults = model.LookupSymbols(parameterUsage.Position).ToTestDisplayStrings(); + Assert.Contains($"System.Int32 {parameterName}", lookupResults); + } + } + + [Fact] + public void ParameterScope_InMethodAttributeNameOf_GetSymbolInfoOnSpeculativeMethodBodySemanticModel() + { + var source = @" +class C +{ + void M() + { + [My(nameof(parameter))] + void local(int parameter) { } + } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (7,14): warning CS8321: The local function 'local' is declared but never used + // void local(int parameter) { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(7, 14) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + + var tree2 = CSharpSyntaxTree.ParseText(source); + var method = tree2.GetRoot().DescendantNodes().OfType().First(); + Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(method.Body.SpanStart, method, out var speculativeModel)); + + var invocation = tree2.GetRoot().DescendantNodes().OfType().Single(); + Assert.Equal("nameof(parameter)", invocation.ToString()); + var symbolInfo = speculativeModel.GetSymbolInfo(invocation); + Assert.Null(symbolInfo.Symbol); + } + + [Fact] + public void ParameterScope_InMethodAttributeNameOf_LookupInEmptyNameof() + { + var source = @" +class C +{ + void M() + { + [My(nameof())] + void local(int parameter) { } + } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (6,13): error CS0103: The name 'nameof' does not exist in the current context + // [My(nameof())] + Diagnostic(ErrorCode.ERR_NameNotInContext, "nameof").WithArguments("nameof").WithLocation(6, 13), + // (7,14): warning CS8321: The local function 'local' is declared but never used + // void local(int parameter) { } + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(7, 14) + ); + + var tree = comp.SyntaxTrees.Single(); + var model = comp.GetSemanticModel(tree); + var nameofExpression = tree.GetRoot().DescendantNodes().OfType().Single(); + + // An invocation may not be considered a 'nameof' operator unless it has one argument + Assert.False(model.LookupSymbols(nameofExpression.ArgumentList.CloseParenToken.SpanStart).ToTestDisplayStrings().Contains("parameter")); + } + + [Fact] + public void ParameterScope_InMethodAttributeNameOf_ConflictingNames() + { + var source = @" +class C +{ + void M() + { + local(0); + + [My(nameof(parameter))] + void local<@parameter>(int parameter) => throw null; + } + + [My(nameof(parameter))] + void M2<@parameter>(int parameter) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (8,20): error CS0103: The name 'parameter' does not exist in the current context + // [My(nameof(parameter))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 20), + // (9,36): error CS0412: 'parameter': a parameter, local variable, or local function cannot have the same name as a method type parameter + // void local<@parameter>(int parameter) => throw null; + Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "parameter").WithArguments("parameter").WithLocation(9, 36), + // (12,16): error CS0103: The name 'parameter' does not exist in the current context + // [My(nameof(parameter))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(12, 16), + // (13,29): error CS0412: 'parameter': a parameter, local variable, or local function cannot have the same name as a method type parameter + // void M2<@parameter>(int parameter) => throw null; + Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "parameter").WithArguments("parameter").WithLocation(13, 29) + ); + + VerifyParameter(comp, 0, null); + VerifyParameter(comp, 1, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (9,36): error CS0412: 'parameter': a parameter, local variable, or local function cannot have the same name as a method type parameter + // void local<@parameter>(int parameter) => throw null; + Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "parameter").WithArguments("parameter").WithLocation(9, 36), + // (13,29): error CS0412: 'parameter': a parameter, local variable, or local function cannot have the same name as a method type parameter + // void M2<@parameter>(int parameter) => throw null; + Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "parameter").WithArguments("parameter").WithLocation(13, 29) + ); + + VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); + VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); + } + + [Fact] + public void ParameterScope_InMethodAttributeNameOf_CompatBreak() + { + var source = @" +class C +{ + class @parameter + { + internal const int Constant = 0; + } + + void M() + { + local(0); + + [My(nameof(parameter.Constant))] // 1 + void local(int parameter) { } + } + + [My(nameof(parameter.Constant))] // 2 + void M2(int parameter) { } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + // The break will also apply to C# 10 and earlier when .NET 7 ships, + // but is currently scoped down to users of LangVer=preview. + // Tracked by https://github.com/dotnet/roslyn/issues/60640 + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (13,30): error CS1061: 'int' does not contain a definition for 'Constant' and no accessible extension method 'Constant' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) + // [My(nameof(parameter.Constant))] // 1 + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Constant").WithArguments("int", "Constant").WithLocation(13, 30), + // (17,26): error CS1061: 'int' does not contain a definition for 'Constant' and no accessible extension method 'Constant' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) + // [My(nameof(parameter.Constant))] // 2 + Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Constant").WithArguments("int", "Constant").WithLocation(17, 26) + ); + } + + [Fact] + public void ParameterScope_InMethodAttributeNameOf_WithReturnTarget() + { + var source = @" +class C +{ + void M() + { + local(0); + + [return: My(nameof(parameter))] // 1 + void local(int parameter) { } + } + + [return: My(nameof(parameter))] // 2 + void M2(int parameter) { } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (8,28): error CS0103: The name 'parameter' does not exist in the current context + // [return: My(nameof(parameter))] // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 28), + // (12,24): error CS0103: The name 'parameter' does not exist in the current context + // [return: My(nameof(parameter))] // 2 + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(12, 24) + ); + + VerifyParameter(comp, 0, null); + VerifyParameter(comp, 1, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); + VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); + } + + [Fact] + public void ParameterScope_InMethodAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting() + { + var source = @" +class C +{ + void M() + { + local(0); + + [My(positionA)] + void local(int parameter) { } + } + + [My(positionB)] + void M2(int parameter) { } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + // C# 10 + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (8,13): error CS0103: The name 'positionA' does not exist in the current context + // [My(positionA)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 13), + // (12,9): error CS0103: The name 'positionB' does not exist in the current context + // [My(positionB)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(12, 9) + ); + + var tree = comp.SyntaxTrees.Single(); + var parentModel = comp.GetSemanticModel(tree); + var localFuncPosition = tree.GetText().ToString().IndexOf("positionA", StringComparison.Ordinal); + var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); + + var attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); + + attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); + + // C# 11 + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (8,13): error CS0103: The name 'positionA' does not exist in the current context + // [My(positionA)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 13), + // (12,9): error CS0103: The name 'positionB' does not exist in the current context + // [My(positionB)] + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(12, 9) + ); + + tree = comp.SyntaxTrees.Single(); + parentModel = comp.GetSemanticModel(tree); + + attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr); + VerifyParameterSpeculation(parentModel, methodPosition, attr); + + attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); + + return; + + static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) + => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType().Single(); + } + + static void VerifyParameterSpeculation(SemanticModel parentModel, int localFuncPosition, AttributeSyntax attr1, bool found = true) + { + SemanticModel speculativeModel; + var success = parentModel.TryGetSpeculativeSemanticModel(localFuncPosition, attr1, out speculativeModel); + Assert.True(success); + Assert.NotNull(speculativeModel); + + var symbolInfo = speculativeModel.GetSymbolInfo(getParameter(attr1)); + if (found) + { + Assert.Equal(SymbolKind.Parameter, symbolInfo.Symbol.Kind); + } + else + { + Assert.Null(symbolInfo.Symbol); + } + return; + + static IdentifierNameSyntax getParameter(CSharpSyntaxNode node) + { + return node.DescendantNodes().OfType().Where(i => i.Identifier.ValueText == "parameter").Single(); + } + } + + [Fact] + public void ParameterScope_InIndexerAttributeNameOf() + { + var source = @" +class C +{ + [My(nameof(parameter))] + int this[int parameter] => 0; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (4,16): error CS0103: The name 'parameter' does not exist in the current context + // [My(nameof(parameter))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 16) + ); + + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { get; }"); + } + + [Fact] + public void ParameterScope_InIndexerAttributeNameOf_SetterOnly() + { + var source = @" +class C +{ + [My(nameof(parameter))] + int this[int parameter] { set => throw null; } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (4,16): error CS0103: The name 'parameter' does not exist in the current context + // [My(nameof(parameter))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 16) + ); + + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { set; }"); + } + + [Fact] + public void ParameterScope_InIndexerGetterAttributeNameOf() + { + var source = @" +class C +{ + int this[int parameter] + { + [My(nameof(parameter))] + get => throw null; + } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (6,20): error CS0103: The name 'parameter' does not exist in the current context + // [My(nameof(parameter))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 20) + ); + + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter].get"); + } + + [Fact] + public void ParameterScope_InIndexerSetterAttributeNameOf() + { + var source = @" +class C +{ + int this[int parameter] + { + [My(nameof(parameter))] + set => throw null; + } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (6,20): error CS0103: The name 'parameter' does not exist in the current context + // [My(nameof(parameter))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 20) + ); + + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "void C.this[System.Int32 parameter].set"); + } + + [Fact] + public void ParameterScope_InIndexerInitSetterAttributeNameOf() + { + var source = @" +class C +{ + int this[int parameter] + { + [My(nameof(parameter))] + init => throw null; + } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (6,20): error CS0103: The name 'parameter' does not exist in the current context + // [My(nameof(parameter))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 20) + ); + + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "void modreq(System.Runtime.CompilerServices.IsExternalInit) C.this[System.Int32 parameter].init"); + } + + [Fact] + public void ParameterScope_InMethodAttributeNameOf_Lambda() + { + var source = @" +class C +{ + void M() + { + var x = [My(nameof(parameter))] int (int parameter) => 0; + } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (6,28): error CS0103: The name 'parameter' does not exist in the current context + // var x = [My(nameof(parameter))] int (int parameter) => 0; + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 28) + ); + + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "lambda expression"); + } + + [Fact] + public void ParameterScope_InMethodAttributeNameOf_AnonymousFunctionWithImplicitParameters() + { + var source = @" +class C +{ + void M() + { + System.Func x = [My(nameof(parameter))] delegate { return 1; } + } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,35): error CS1525: Invalid expression term '[' + // System.Func x = [My(nameof(parameter))] delegate { return 1; } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "[").WithArguments("[").WithLocation(6, 35), + // (6,36): error CS0103: The name 'My' does not exist in the current context + // System.Func x = [My(nameof(parameter))] delegate { return 1; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "My").WithArguments("My").WithLocation(6, 36), + // (6,46): error CS0103: The name 'parameter' does not exist in the current context + // System.Func x = [My(nameof(parameter))] delegate { return 1; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 46), + // (6,59): error CS1002: ; expected + // System.Func x = [My(nameof(parameter))] delegate { return 1; } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "delegate").WithLocation(6, 59), + // (6,81): error CS1002: ; expected + // System.Func x = [My(nameof(parameter))] delegate { return 1; } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 81) + ); + } + + [Fact] + public void ParameterScope_InMethodAttributeNameOf_Delegate() + { + var source = @" +[My(nameof(parameter))] delegate int MyDelegate(int parameter); + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (2,12): error CS0103: The name 'parameter' does not exist in the current context + // [My(nameof(parameter))] delegate int MyDelegate(int parameter); + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(2, 12) + ); + + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "System.Int32 MyDelegate.Invoke(System.Int32 parameter)"); + } + + [Fact] + public void ParameterScope_InMethodAttributeNameOf_Delegate_ConflictingName() + { + var source = @" +[My(nameof(TParameter))] delegate int MyDelegate(int TParameter); public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); - comp.VerifyDiagnostics( - // (8,36): error CS1503: Argument 1: cannot convert from 'System.Type' to 'string' - // void local([My(typeof(TParameter))] int i) => throw null; - Diagnostic(ErrorCode.ERR_BadArgType, "typeof(TParameter)").WithArguments("1", "System.Type", "string").WithLocation(8, 36), - // (11,29): error CS1503: Argument 1: cannot convert from 'System.Type' to 'string' - // void M2([My(typeof(TParameter))] int i) => throw null; - Diagnostic(ErrorCode.ERR_BadArgType, "typeof(TParameter)").WithArguments("1", "System.Type", "string").WithLocation(11, 29) - ); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(); - VerifyTParameter(comp, 0, "void local(System.Int32 i)"); - VerifyTParameter(comp, 1, "void C.M2(System.Int32 i)"); + VerifyTParameter(comp, 0, "MyDelegate"); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "System.Int32 MyDelegate.Invoke(System.Int32 TParameter)", parameterName: "TParameter"); } [Fact] - public void TypeParameterScope_InParameterAttributeSizeOf() + public void ParameterScope_InMethodAttributeNameOf_Constructor() { - var comp = CreateCompilation(@" + var source = @" class C { - void M() - { - local(0); - - void local([My(sizeof(TParameter))] int i) => throw null; - } - - void M2([My(sizeof(TParameter))] int i) => throw null; + [My(nameof(parameter))] C(int parameter) { } } public class MyAttribute : System.Attribute { - public MyAttribute(int i) { } + public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,36): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('TParameter') - // void local([My(sizeof(TParameter))] int i) => throw null; - Diagnostic(ErrorCode.ERR_ManagedAddr, "sizeof(TParameter)").WithArguments("TParameter").WithLocation(8, 36), - // (8,36): error CS0233: 'TParameter' does not have a predefined size, therefore sizeof can only be used in an unsafe context - // void local([My(sizeof(TParameter))] int i) => throw null; - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(TParameter)").WithArguments("TParameter").WithLocation(8, 36), - // (11,29): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('TParameter') - // void M2([My(sizeof(TParameter))] int i) => throw null; - Diagnostic(ErrorCode.ERR_ManagedAddr, "sizeof(TParameter)").WithArguments("TParameter").WithLocation(11, 29), - // (11,29): error CS0233: 'TParameter' does not have a predefined size, therefore sizeof can only be used in an unsafe context - // void M2([My(sizeof(TParameter))] int i) => throw null; - Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(TParameter)").WithArguments("TParameter").WithLocation(11, 29) + // (4,16): error CS0103: The name 'parameter' does not exist in the current context + // [My(nameof(parameter))] C(int parameter) { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 16) ); - VerifyTParameter(comp, 0, "void local(System.Int32 i)"); - VerifyTParameter(comp, 1, "void C.M2(System.Int32 i)"); + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "C..ctor(System.Int32 parameter)"); } [Fact] - public void TypeParameterScope_InParameterAttributeDefault() + public void ParameterScope_NotInMethodAttribute() { var comp = CreateCompilation(@" class C { void M() { - local(0); + local(0); - void local([My(default(TParameter))] int i) where TParameter : class => throw null; + [My(parameter)] // 1 + void local(int parameter) { } } - void M2([My(default(TParameter))] int i) where TParameter : class => throw null; + [My(parameter)] // 2 + void M2(int parameter) { } } public class MyAttribute : System.Attribute @@ -7499,563 +9371,693 @@ public class MyAttribute : System.Attribute public MyAttribute(object o) { } } "); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (8,13): error CS0103: The name 'parameter' does not exist in the current context + // [My(parameter)] // 1 + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 13), + // (12,9): error CS0103: The name 'parameter' does not exist in the current context + // [My(parameter)] // 2 + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(12, 9) + ); - VerifyTParameter(comp, 0, "void local(System.Int32 i)"); - VerifyTParameter(comp, 1, "void C.M2(System.Int32 i)"); + VerifyParameter(comp, 0, null); + VerifyParameter(comp, 1, null); } [Fact] - public void TypeParameterScope_NotAsParameterAttributeType() + public void ParameterScope_NotInMethodAttributeTypeArgument() { var comp = CreateCompilation(@" class C { void M() { - local(0); + local(0); - void local([TParameter] int i) where TParameter : System.Attribute => throw null; + [My] // 1 + void local(int parameter) { } } - void M2([TParameter] int i) where TParameter : System.Attribute => throw null; + [My] // 2 + void M2(int parameter) { } +} + +public class MyAttribute : System.Attribute +{ } "); comp.VerifyDiagnostics( - // (8,33): error CS0616: 'TParameter' is not an attribute class - // void local([TParameter] int i) where TParameter : System.Attribute => throw null; - Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(8, 33), - // (11,26): error CS0616: 'TParameter' is not an attribute class - // void M2([TParameter] int i) where TParameter : System.Attribute => throw null; - Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(11, 26) + // (8,13): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) + // [My] // 1 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(8, 13), + // (12,9): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) + // [My] // 2 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(12, 9) ); - VerifyTParameter(comp, 0, null, findAnyways: true); - VerifyTParameter(comp, 1, null, findAnyways: true); + VerifyParameter(comp, 0, null); + VerifyParameter(comp, 1, null); } [Fact] - public void TypeParameterScope_InReturnType() + public void ParameterScope_NotAsMethodAttributeType() { var comp = CreateCompilation(@" class C { void M() { - local(); + local(null); - TParameter local() => throw null; + [parameter] // 1 + void local(System.Attribute parameter) { } } - TParameter M2() => throw null; + [parameter] // 2 + void M2(System.Attribute parameter) { } } "); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (8,10): error CS0246: The type or namespace name 'parameterAttribute' could not be found (are you missing a using directive or an assembly reference?) + // [parameter] // 1 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameterAttribute").WithLocation(8, 10), + // (8,10): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) + // [parameter] // 1 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(8, 10), + // (12,6): error CS0246: The type or namespace name 'parameterAttribute' could not be found (are you missing a using directive or an assembly reference?) + // [parameter] // 2 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameterAttribute").WithLocation(12, 6), + // (12,6): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) + // [parameter] // 2 + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(12, 6) + ); + + VerifyParameter(comp, 0, null); + VerifyParameter(comp, 1, null); } [Fact] - public void TypeParameterScope_InParameterType() + public void ParameterScope_NotInParameterAttribute() { var comp = CreateCompilation(@" class C { void M() { - local(null); + local(0); - void local(TParameter p) => throw null; + void local([My(parameter)] int parameter) => throw null; } - void M2(TParameter p) => throw null; + void M2([My(parameter)] int parameter) => throw null; +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } } "); - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (8,24): error CS0103: The name 'parameter' does not exist in the current context + // void local([My(parameter)] int parameter) => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 24), + // (11,17): error CS0103: The name 'parameter' does not exist in the current context + // void M2([My(parameter)] int parameter) => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(11, 17) + ); + + VerifyParameter(comp, 0, null); + VerifyParameter(comp, 1, null); } [Fact] - public void TypeParameterScope_InTypeConstraint() + public void ParameterScope_InParameterAttributeNameOf() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { - local(); + local(0); - void local() where TParameter2 : TParameter => throw null; + void local([My(nameof(parameter))] int parameter) => throw null; } - void M2() where TParameter2 : TParameter => throw null; + void M2([My(nameof(parameter))] int parameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (8,31): error CS0103: The name 'parameter' does not exist in the current context + // void local([My(nameof(parameter))] int parameter) => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 31), + // (11,24): error CS0103: The name 'parameter' does not exist in the current context + // void M2([My(nameof(parameter))] int parameter) => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(11, 24) + ); + + VerifyParameter(comp, 0, null); + VerifyParameter(comp, 1, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); comp.VerifyDiagnostics(); - VerifyTParameter(comp, 0, "void local()"); - VerifyTParameter(comp, 1, "void C.M2()"); + VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); + VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); } [Fact] - public void TypeParameterScope_NotInMethodAttributeTypeOf() + public void ParameterScope_InParameterAttributeNameOf_ConflictingNames() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { - local(); + local(0); - [My(typeof(TParameter))] - void local() => throw null; + void local([My(nameof(TParameter))] int TParameter) => throw null; } - [My(typeof(TParameter))] - void M2() => throw null; + void M2([My(nameof(TParameter))] int TParameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,20): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) - // [My(typeof(TParameter))] - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 20), - // (12,16): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) - // [My(typeof(TParameter))] - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 16) + // (8,61): error CS0412: 'TParameter': a parameter, local variable, or local function cannot have the same name as a method type parameter + // void local([My(nameof(TParameter))] int TParameter) => throw null; + Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "TParameter").WithArguments("TParameter").WithLocation(8, 61), + // (11,54): error CS0412: 'TParameter': a parameter, local variable, or local function cannot have the same name as a method type parameter + // void M2([My(nameof(TParameter))] int TParameter) => throw null; + Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "TParameter").WithArguments("TParameter").WithLocation(11, 54) ); - VerifyTParameter(comp, 0, null); - VerifyTParameter(comp, 1, null); + VerifyTParameter(comp, 0, "void local(System.Int32 TParameter)"); + VerifyTParameter(comp, 1, "void C.M2(System.Int32 TParameter)"); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (8,61): error CS0412: 'TParameter': a parameter, local variable, or local function cannot have the same name as a method type parameter + // void local([My(nameof(TParameter))] int TParameter) => throw null; + Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "TParameter").WithArguments("TParameter").WithLocation(8, 61), + // (11,54): error CS0412: 'TParameter': a parameter, local variable, or local function cannot have the same name as a method type parameter + // void M2([My(nameof(TParameter))] int TParameter) => throw null; + Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "TParameter").WithArguments("TParameter").WithLocation(11, 54) + ); + + VerifyParameter(comp, 0, "void local(System.Int32 TParameter)", parameterName: "TParameter"); + VerifyParameter(comp, 1, "void C.M2(System.Int32 TParameter)", parameterName: "TParameter"); } [Fact] - public void TypeParameterScope_NotInTypeParameterAttribute() + public void ParameterScope_InParameterAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { - local(); + local(0); - void local<[My(TParameter)] TParameter>() => throw null; + void local([My(positionA)] int parameter) { } } - void M2<[My(TParameter)] TParameter>() => throw null; + void M2([My(positionB)] int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); - // TParameter unexpectedly was found in local function case because of IsInMethodBody logic - // Tracked by https://github.com/dotnet/roslyn/issues/60110 +"; + // C# 10 + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,24): error CS0119: 'TParameter' is a type, which is not valid in the given context - // void local<[My(TParameter)] TParameter>() => throw null; - Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(8, 24), - // (11,17): error CS0103: The name 'TParameter' does not exist in the current context - // void M2<[My(TParameter)] TParameter>() => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(11, 17) + // (8,24): error CS0103: The name 'positionA' does not exist in the current context + // void local([My(positionA)] int parameter) { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 24), + // (11,17): error CS0103: The name 'positionB' does not exist in the current context + // void M2([My(positionB)] int parameter) { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(11, 17) ); - //VerifyTParameter(comp, 0, null); - VerifyTParameter(comp, 1, null); + var tree = comp.SyntaxTrees.Single(); + var parentModel = comp.GetSemanticModel(tree); + var localFuncPosition = tree.GetText().ToString().IndexOf("positionA", StringComparison.Ordinal); + var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); + + var attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); + + attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); + + // C# 11 + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (8,24): error CS0103: The name 'positionA' does not exist in the current context + // void local([My(positionA)] int parameter) { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 24), + // (11,17): error CS0103: The name 'positionB' does not exist in the current context + // void M2([My(positionB)] int parameter) { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(11, 17) + ); + + tree = comp.SyntaxTrees.Single(); + parentModel = comp.GetSemanticModel(tree); + + attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr); + VerifyParameterSpeculation(parentModel, methodPosition, attr); + + attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); + + return; + + static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) + => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType().Single(); } [Fact] - public void TypeParameterScope_InTypeParameterAttributeNameOf() + public void ParameterScope_InParameterAttributeNameOf_Indexer() { - var comp = CreateCompilation(@" + var source = @" class C { - void M() - { - local(); - - void local<[My(nameof(TParameter))] TParameter>() => throw null; - } - - void M2<[My(nameof(TParameter))] TParameter>() => throw null; + int this[[My(nameof(parameter))] int parameter] => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (4,25): error CS0103: The name 'parameter' does not exist in the current context + // int this[[My(nameof(parameter))] int parameter] => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 25) + ); + + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); comp.VerifyDiagnostics(); - VerifyTParameter(comp, 0, "void local()"); - // LookupSymbols fails to find TParameter - // Tracked by https://github.com/dotnet/roslyn/issues/60194 - VerifyTParameter(comp, 1, "void C.M2()", lookupFailsAnyways: true); + VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { get; }"); } [Fact] - public void TypeParameterScope_InTypeParameterAttributeDefault() + public void ParameterScope_InParameterAttributeNameOf_Indexer_SetterOnly() { - var comp = CreateCompilation(@" + var source = @" class C { - void M() - { - local(); - - void local<[My(default(TParameter))] TParameter>() where TParameter : class => throw null; - } - - void M2<[My(default(TParameter))] TParameter>() where TParameter : class => throw null; + int this[[My(nameof(parameter))] int parameter] { set => throw null; } } public class MyAttribute : System.Attribute { - public MyAttribute(object o) { } + public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (4,25): error CS0103: The name 'parameter' does not exist in the current context + // int this[[My(nameof(parameter))] int parameter] => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 25) + ); + + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); comp.VerifyDiagnostics(); - VerifyTParameter(comp, 0, "void local()"); - VerifyTParameter(comp, 1, "void C.M2()"); + VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { set; }"); } [Fact] - public void TypeParameterScope_NotAsTypeParameterAttributeType() + public void ParameterScope_ValueLocalNotInPropertyOrAccessorAttributeNameOf() { - var comp = CreateCompilation(@" + var source = @" class C { - void M() - { - local(); + [My(nameof(value))] + int Property { set => throw null; } - void local<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; - } + int Property2 { [My(nameof(value))] get => throw null; } - void M2<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; + int Property3 { [My(nameof(value))] set => throw null; } + + int Property4 { [My(nameof(value))] init => throw null; } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); comp.VerifyDiagnostics( - // (8,21): error CS0616: 'TParameter' is not an attribute class - // void local<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; - Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(8, 21), - // (11,14): error CS0616: 'TParameter' is not an attribute class - // void M2<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; - Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(11, 14) + // (4,16): error CS0103: The name 'value' does not exist in the current context + // [My(nameof(value))] + Diagnostic(ErrorCode.ERR_NameNotInContext, "value").WithArguments("value").WithLocation(4, 16), + // (7,32): error CS0103: The name 'value' does not exist in the current context + // int Property2 { [My(nameof(value))] get => throw null; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "value").WithArguments("value").WithLocation(7, 32), + // (9,32): error CS0103: The name 'value' does not exist in the current context + // int Property3 { [My(nameof(value))] set => throw null; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "value").WithArguments("value").WithLocation(9, 32), + // (11,32): error CS0103: The name 'value' does not exist in the current context + // int Property4 { [My(nameof(value))] init => throw null; } + Diagnostic(ErrorCode.ERR_NameNotInContext, "value").WithArguments("value").WithLocation(11, 32) ); - - VerifyTParameter(comp, 0, null, findAnyways: true); - VerifyTParameter(comp, 1, null, findAnyways: true); } [Fact] - public void TypeParameterScope_AsParameterDefaultDefaultValue() + public void ParameterScope_InParameterAttributeNameOf_Constructor() { - var comp = CreateCompilation(@" + var source = @" class C { - void M() - { - local(); - - void local(TParameter s = default(TParameter)) => throw null; - } - - void M2(TParameter s = default(TParameter)) => throw null; + C([My(nameof(parameter))] int parameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (4,18): error CS0103: The name 'parameter' does not exist in the current context + // C([My(nameof(parameter))] int parameter) => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 18) + ); + + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); comp.VerifyDiagnostics(); - VerifyTParameter(comp, 0, "void local([TParameter s = default(TParameter)])"); - VerifyTParameter(comp, 1, "void C.M2([TParameter s = default(TParameter)])"); + VerifyParameter(comp, 0, "C..ctor(System.Int32 parameter)"); } [Fact] - public void TypeParameterScope_AsParameterNameOfDefaultValue() + public void ParameterScope_InParameterAttributeNameOf_Delegate() { - var comp = CreateCompilation(@" -class C -{ - void M() - { - local(); - - void local(string s = nameof(TParameter)) => throw null; - } - - void M2(string s = nameof(TParameter)) => throw null; -} + var source = @" +delegate void MyDelegate([My(nameof(parameter))] int parameter); public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (2,37): error CS0103: The name 'parameter' does not exist in the current context + // delegate void MyDelegate([My(nameof(parameter))] int parameter); + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(2, 37) + ); + + VerifyParameter(comp, 0, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); comp.VerifyDiagnostics(); - VerifyTParameter(comp, 0, @"void local([System.String s = ""TParameter""])"); - // LookupSymbols fails to find TParameter - // Tracked by https://github.com/dotnet/roslyn/issues/60194 - VerifyTParameter(comp, 1, @"void C.M2([System.String s = ""TParameter""])", lookupFailsAnyways: true); + VerifyParameter(comp, 0, "void MyDelegate.Invoke(System.Int32 parameter)"); } [Fact] - public void ParameterScope_NotInMethodAttributeNameOf() + public void ParameterScope_InParameterAttributeNameOf_ConversionOperator() { - var comp = CreateCompilation(@" + var source = @" class C { - void M() - { - local(0); - - [My(nameof(parameter))] // 1 - void local(int parameter) { } - } - - [My(nameof(parameter))] // 2 - void M2(int parameter) { } + public static implicit operator C([My(nameof(parameter))] int parameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,20): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] // 1 - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 20), - // (12,16): error CS0103: The name 'parameter' does not exist in the current context - // [My(nameof(parameter))] // 2 - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(12, 16) + // (4,50): error CS0103: The name 'parameter' does not exist in the current context + // public static implicit operator C([My(nameof(parameter))] int parameter) => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 50) ); VerifyParameter(comp, 0, null); - VerifyParameter(comp, 1, null); - } - - /// - /// Look for usages of "parameter" and verify the index-th one. - /// - private void VerifyParameter(CSharpCompilation comp, int index, string expectedMethod) - { - var tree = comp.SyntaxTrees.Single(); - var model = comp.GetSemanticModel(tree); - var parameterUsages = tree.GetRoot().DescendantNodes().OfType() - .Where(i => i.Identifier.ValueText == "parameter") - .Where(i => i.Ancestors().Any(a => a.IsKind(SyntaxKind.Attribute) || a.IsKind(SyntaxKind.TypeConstraint) || a.IsKind(SyntaxKind.DefaultExpression) || a.IsKind(SyntaxKind.InvocationExpression))) - .ToArray(); - var parameterUsage = parameterUsages[index]; + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); - var symbol = model.GetSymbolInfo(parameterUsage).Symbol; - if (expectedMethod is null) - { - Assert.Null(symbol); - Assert.True(model.GetTypeInfo(parameterUsage).Type.IsErrorType()); - Assert.DoesNotContain("parameter", model.LookupSymbols(parameterUsage.Position).ToTestDisplayStrings()); - } - else - { - Assert.Equal(expectedMethod, symbol.ContainingSymbol.ToTestDisplayString()); - Assert.Equal(SymbolKind.Parameter, model.GetTypeInfo(parameterUsage).Type.Kind); - Assert.Contains(symbol, model.LookupSymbols(parameterUsage.Position)); - } + VerifyParameter(comp, 0, "C C.op_Implicit(System.Int32 parameter)"); } [Fact] - public void ParameterScope_NotInMethodAttribute() + public void ParameterScope_InParameterAttributeNameOf_Operator() { - var comp = CreateCompilation(@" + var source = @" class C { - void M() - { - local(0); - - [My(parameter)] // 1 - void local(int parameter) { } - } - - [My(parameter)] // 2 - void M2(int parameter) { } + public static C operator +([My(nameof(parameter))] int parameter, C other) => throw null; } public class MyAttribute : System.Attribute { - public MyAttribute(object o) { } + public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,13): error CS0103: The name 'parameter' does not exist in the current context - // [My(parameter)] // 1 - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 13), - // (12,9): error CS0103: The name 'parameter' does not exist in the current context - // [My(parameter)] // 2 - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(12, 9) + // (4,43): error CS0103: The name 'parameter' does not exist in the current context + // public static C operator +([My(nameof(parameter))] int parameter, C other) => throw null; + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(4, 43) ); VerifyParameter(comp, 0, null); - VerifyParameter(comp, 1, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "C C.op_Addition(System.Int32 parameter, C other)"); } [Fact] - public void ParameterScope_NotInMethodAttributeTypeArgument() + public void ParameterScope_InParameterAttributeNameOf_Lambda() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { - local(0); - - [My] // 1 - void local(int parameter) { } + var x = ([My(nameof(parameter))] int parameter) => 0; } - - [My] // 2 - void M2(int parameter) { } } -public class MyAttribute : System.Attribute +public class MyAttribute : System.Attribute { + public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,13): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) - // [My] // 1 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(8, 13), - // (12,9): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) - // [My] // 2 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(12, 9) + // (6,29): error CS0103: The name 'parameter' does not exist in the current context + // var x = ([My(nameof(parameter))] int parameter) => 0; + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 29) ); VerifyParameter(comp, 0, null); - VerifyParameter(comp, 1, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "lambda expression"); } [Fact] - public void ParameterScope_NotAsMethodAttributeType() + public void ParameterScope_InParameterAttributeNameOf_AnonymousDelegate() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { - local(null); - - [parameter] // 1 - void local(System.Attribute parameter) { } + var x = delegate ([My(nameof(parameter))] int parameter) { return 0; }; } +} - [parameter] // 2 - void M2(System.Attribute parameter) { } +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source); comp.VerifyDiagnostics( - // (8,10): error CS0246: The type or namespace name 'parameterAttribute' could not be found (are you missing a using directive or an assembly reference?) - // [parameter] // 1 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameterAttribute").WithLocation(8, 10), - // (8,10): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) - // [parameter] // 1 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(8, 10), - // (12,6): error CS0246: The type or namespace name 'parameterAttribute' could not be found (are you missing a using directive or an assembly reference?) - // [parameter] // 2 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameterAttribute").WithLocation(12, 6), - // (12,6): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) - // [parameter] // 2 - Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(12, 6) + // (6,27): error CS7014: Attributes are not valid in this context. + // var x = delegate ([My(nameof(parameter))] int parameter) { return 0; }; + Diagnostic(ErrorCode.ERR_AttributesNotAllowed, "[My(nameof(parameter))]").WithLocation(6, 27) ); - VerifyParameter(comp, 0, null); - VerifyParameter(comp, 1, null); + VerifyParameter(comp, 0, "lambda expression"); } [Fact] - public void ParameterScope_NotInParameterAttribute() + public void ParameterScope_InTypeParameterAttributeNameOf() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { - local(0); + local(0); - void local([My(parameter)] int parameter) => throw null; + void local<[My(nameof(parameter))] T>(int parameter) { } } - void M2([My(parameter)] int parameter) => throw null; + void M2<[My(nameof(parameter))] T>(int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,24): error CS0103: The name 'parameter' does not exist in the current context - // void local([My(parameter)] int parameter) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 24), - // (11,17): error CS0103: The name 'parameter' does not exist in the current context - // void M2([My(parameter)] int parameter) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(11, 17) + // (8,31): error CS0103: The name 'parameter' does not exist in the current context + // void local<[My(nameof(parameter))] T>(int parameter) { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 31), + // (11,24): error CS0103: The name 'parameter' does not exist in the current context + // void M2<[My(nameof(parameter))] T>(int parameter) { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(11, 24) ); VerifyParameter(comp, 0, null); VerifyParameter(comp, 1, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); + VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); } [Fact] - public void ParameterScope_NotInParameterAttributeNameOf() + public void ParameterScope_InTypeParameterAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting() { - var comp = CreateCompilation(@" + var source = @" class C { void M() { - local(0); + local(0); - void local([My(nameof(parameter))] int parameter) => throw null; + void local<[My(positionA)] T>(int parameter) { } } - void M2([My(nameof(parameter))] int parameter) => throw null; + void M2<[My(positionB)] T>(int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } -"); +"; + // C# 10 + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,31): error CS0103: The name 'parameter' does not exist in the current context - // void local([My(nameof(parameter))] int parameter) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 31), - // (11,24): error CS0103: The name 'parameter' does not exist in the current context - // void M2([My(nameof(parameter))] int parameter) => throw null; - Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(11, 24) + // (8,24): error CS0103: The name 'positionA' does not exist in the current context + // void local([My(positionA)] int parameter) { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 24), + // (11,17): error CS0103: The name 'positionB' does not exist in the current context + // void M2([My(positionB)] int parameter) { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(11, 17) + ); + + var tree = comp.SyntaxTrees.Single(); + var parentModel = comp.GetSemanticModel(tree); + var localFuncPosition = tree.GetText().ToString().IndexOf("positionA", StringComparison.Ordinal); + var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); + + var attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); + + attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); + + // C# 11 + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (8,24): error CS0103: The name 'positionA' does not exist in the current context + // void local([My(positionA)] int parameter) { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 24), + // (11,17): error CS0103: The name 'positionB' does not exist in the current context + // void M2([My(positionB)] int parameter) { } + Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(11, 17) + ); + + tree = comp.SyntaxTrees.Single(); + parentModel = comp.GetSemanticModel(tree); + + attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr); + VerifyParameterSpeculation(parentModel, methodPosition, attr); + + attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); + VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); + VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); + + return; + + static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) + => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType().Single(); + } + + [Fact] + public void ParameterScope_InTypeParameterAttributeNameOf_Delegate() + { + var source = @" +delegate int MyDelegate<[My(nameof(parameter))] T>(int parameter); + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"; + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (2,36): error CS0103: The name 'parameter' does not exist in the current context + // delegate int MyDelegate<[My(nameof(parameter))] T>(int parameter); + Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(2, 36) ); VerifyParameter(comp, 0, null); - VerifyParameter(comp, 1, null); + + comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + + VerifyParameter(comp, 0, "System.Int32 MyDelegate.Invoke(System.Int32 parameter)"); } [Fact] @@ -8090,7 +10092,6 @@ void M() ); VerifyParameter(comp, 0, null); - VerifyParameter(comp, 1, null); } [Fact] @@ -8187,7 +10188,7 @@ public MyAttribute(string name1) { } } [Fact] - public void ParameterScope_NotAsParameterDefaultDefaultValue() + public void ParameterScope_NotInParameterDefaultDefaultValue() { var comp = CreateCompilation(@" class C @@ -8227,7 +10228,7 @@ public MyAttribute(string name1) { } } [Fact] - public void ParameterScope_NotAsParameterNameOfDefaultValue() + public void ParameterScope_NotInParameterNameOfDefaultValue() { var comp = CreateCompilation(@" class C diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index de720a32d6e23..7b672b5e33629 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -267,7 +267,7 @@ class Test Diagnostic(ErrorCode.ERR_NoSuchMember, "Something").WithArguments("object", "Something").WithLocation(24, 27), // (25,28): error CS0400: The type or namespace name 'Something' could not be found in the global namespace (are you missing an assembly reference?) // s = nameof(global::Something); - Diagnostic(ErrorCode.ERR_GlobalSingleTypeNameNotFound, "Something").WithArguments("Something", "").WithLocation(25, 28), + Diagnostic(ErrorCode.ERR_GlobalSingleTypeNameNotFound, "Something").WithArguments("Something").WithLocation(25, 28), // (26,20): error CS0432: Alias 'global2' not found // s = nameof(global2::Something); Diagnostic(ErrorCode.ERR_AliasNotFound, "global2").WithArguments("global2").WithLocation(26, 20), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullCheckedParameterTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullCheckedParameterTests.cs index 5b22538850a77..e016716bd2990 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullCheckedParameterTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullCheckedParameterTests.cs @@ -87,7 +87,7 @@ abstract class C Diagnostic(ErrorCode.WRN_UnreferencedField, "FirstName").WithArguments("C.FirstName").WithLocation(4, 12), // (4,21): error CS1003: Syntax error, ',' expected // string FirstName!! { get; set; } - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(4, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",").WithLocation(4, 21), // (4,26): error CS1002: ; expected // string FirstName!! { get; set; } Diagnostic(ErrorCode.ERR_SemicolonExpected, "get").WithLocation(4, 26), @@ -139,19 +139,19 @@ void M6(string name! != ""a"") { } CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics( // (5,24): error CS1003: Syntax error, '!!' expected // void M1(string name! !="a") { } - Diagnostic(ErrorCode.ERR_SyntaxError, "! !").WithArguments("!!", "!").WithLocation(5, 24), + Diagnostic(ErrorCode.ERR_SyntaxError, "! !").WithArguments("!!").WithLocation(5, 24), // (7,25): error CS1003: Syntax error, '!!' expected // void M3(string name ! !="a") { } - Diagnostic(ErrorCode.ERR_SyntaxError, "! !").WithArguments("!!", "!").WithLocation(7, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "! !").WithArguments("!!").WithLocation(7, 25), // (8,25): error CS1003: Syntax error, '!!' expected // void M4(string name ! ! ="a") { } - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(8, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(8, 25), // (9,24): error CS1003: Syntax error, '!!' expected // void M5(string name! ! ="a") { } - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(9, 24), + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(9, 24), // (10,24): error CS1003: Syntax error, '!!' expected // void M6(string name! != "a") { } - Diagnostic(ErrorCode.ERR_SyntaxError, "! !").WithArguments("!!", "!").WithLocation(10, 24) + Diagnostic(ErrorCode.ERR_SyntaxError, "! !").WithArguments("!!").WithLocation(10, 24) ); } @@ -168,7 +168,7 @@ void M0(string name !/*comment1*/ .VerifyDiagnostics( // (4,25): error CS1003: Syntax error, '!!' expected // void M0(string name !/*comment1*/ - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(4, 25) + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(4, 25) ); } @@ -186,7 +186,7 @@ void M0(string name .VerifyDiagnostics( // (4,12): error CS1003: Syntax error, '!!' expected // void M0(string name - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("!!", "!").WithLocation(4, 12) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("!!").WithLocation(4, 12) ); } @@ -283,7 +283,7 @@ void M2(__arglist!!) CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics( // (8,22): error CS1003: Syntax error, ',' expected // void M2(__arglist!!) - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(8, 22)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",").WithLocation(8, 22)); } [Fact(Skip = "https://github.com/dotnet/roslyn/issues/58335")] @@ -474,22 +474,22 @@ public void M() CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics( // (7,39): error CS1003: Syntax error, '!!' expected // Func func0 = x!=> x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(7, 39), + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(7, 39), // (8,40): error CS1003: Syntax error, '!!' expected // Func func1 = x !=> x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(8, 40), + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(8, 40), // (9,40): error CS1003: Syntax error, '!!' expected // Func func2 = x != > x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(9, 40), + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(9, 40), // (9,41): error CS1003: Syntax error, '=>' expected // Func func2 = x != > x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("=>", "=").WithLocation(9, 41), + Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("=>").WithLocation(9, 41), // (10,38): error CS0103: The name 'x' does not exist in the current context // Func func3 = x! => x; Diagnostic(ErrorCode.ERR_NameNotInContext, "x").WithArguments("x").WithLocation(10, 38), // (10,41): error CS1003: Syntax error, ',' expected // Func func3 = x! => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(10, 41), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(10, 41), // (10,44): error CS1002: ; expected // Func func3 = x! => x; Diagnostic(ErrorCode.ERR_SemicolonExpected, "x").WithLocation(10, 44), @@ -504,7 +504,7 @@ public void M() Diagnostic(ErrorCode.ERR_NameNotInContext, "x").WithArguments("x").WithLocation(11, 38), // (11,42): error CS1003: Syntax error, ',' expected // Func func4 = x ! => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(11, 42), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(11, 42), // (11,45): error CS1002: ; expected // Func func4 = x ! => x; Diagnostic(ErrorCode.ERR_SemicolonExpected, "x").WithLocation(11, 45), @@ -516,13 +516,13 @@ public void M() Diagnostic(ErrorCode.ERR_IllegalStatement, "x").WithLocation(11, 45), // (13,42): error CS1003: Syntax error, '=>' expected // Func func6 = x !!= > x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("=>", "=").WithLocation(13, 42), + Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("=>").WithLocation(13, 42), // (15,39): error CS1003: Syntax error, '!!' expected // Func func8 = x! !=> x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(15, 39), + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(15, 39), // (16,39): error CS1003: Syntax error, '!!' expected // Func func9 = x! ! => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "! ").WithArguments("!!", "!").WithLocation(16, 39)); + Diagnostic(ErrorCode.ERR_SyntaxError, "! ").WithArguments("!!").WithLocation(16, 39)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index 7c0665475b361..275f3a4e6199e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -1115,7 +1115,7 @@ public void M2() comp.VerifyDiagnostics( // (7,23): error CS1003: Syntax error, ',' expected // M(out string y!); - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(7, 23), + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",").WithLocation(7, 23), // (7,24): error CS1525: Invalid expression term ')' // M(out string y!); Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(7, 24) @@ -2686,7 +2686,7 @@ void M() Diagnostic(ErrorCode.ERR_NameNotInContext, "nameof").WithArguments("nameof").WithLocation(6, 13), // (7,19): error CS1003: Syntax error, '(' expected // _ = typeof!(C); - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("(", "!").WithLocation(7, 19), + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("(").WithLocation(7, 19), // (7,19): error CS1031: Type expected // _ = typeof!(C); Diagnostic(ErrorCode.ERR_TypeExpected, "!").WithLocation(7, 19), @@ -15219,7 +15219,7 @@ public override Func P1 { set {} } // warn Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnImplicitImplementation, "set").WithArguments("value", "void C.P1.set", "void A.P1.set").WithLocation(15, 39), // (16,39): error CS8051: Auto-implemented properties must have get accessors. // public override Func P2 { set; } // warn - Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithArguments("C.P2.set").WithLocation(16, 39), + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithLocation(16, 39), // (16,39): warning CS8610: Nullability of reference types in type of parameter 'value' doesn't match overridden member. // public override Func P2 { set; } // warn Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnOverride, "set").WithArguments("value").WithLocation(16, 39), @@ -15431,7 +15431,7 @@ class D : C, B comp.VerifyDiagnostics( // (16,35): error CS8080: Auto-implemented properties must override all accessors of the overridden property. // public override Func? P1 { get; } = null!; // warn - Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithArguments("D.P1").WithLocation(16, 35), + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(16, 35), // (16,40): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes). // public override Func? P1 { get; } = null!; // warn Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "get").WithLocation(16, 40), @@ -33538,7 +33538,7 @@ public void M() Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "field").WithLocation(12, 9), // (14,15): error CS0206: A property or indexer may not be passed as an out or ref parameter // M(ref Property); // 5 - Diagnostic(ErrorCode.ERR_RefProperty, "Property").WithArguments("C.Property").WithLocation(14, 15), + Diagnostic(ErrorCode.ERR_RefProperty, "Property").WithLocation(14, 15), // (15,20): warning CS8625: Cannot convert null literal to non-nullable reference type. // Property = null; // 6 Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(15, 20) @@ -63304,22 +63304,22 @@ static void F5() where T5 : class comp.VerifyDiagnostics( // (6,14): error CS8628: Cannot use a nullable reference type in object creation. // x1 = new object?(); // error 1 - Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new object?()").WithArguments("object").WithLocation(6, 14), + Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new object?()").WithLocation(6, 14), // (7,14): error CS8628: Cannot use a nullable reference type in object creation. // x1 = new object? { }; // error 2 - Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new object? { }").WithArguments("object").WithLocation(7, 14), + Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new object? { }").WithLocation(7, 14), // (9,14): error CS8628: Cannot use a nullable reference type in object creation. // x1 = new object[]? {}; // error 3 - Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new object[]? {}").WithArguments("object[]").WithLocation(9, 14), + Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new object[]? {}").WithLocation(9, 14), // (9,18): error CS8386: Invalid object creation // x1 = new object[]? {}; // error 3 - Diagnostic(ErrorCode.ERR_InvalidObjectCreation, "object[]?").WithArguments("object[]").WithLocation(9, 18), + Diagnostic(ErrorCode.ERR_InvalidObjectCreation, "object[]?").WithLocation(9, 18), // (14,18): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type unless language version '9.0' or greater is used. Consider changing the language version or adding a 'class', 'struct', or type constraint. // x2 = new T2?(); // error 4 Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "T2?").WithArguments("9.0").WithLocation(14, 18), // (14,14): error CS8628: Cannot use a nullable reference type in object creation. // x2 = new T2?(); // error 4 - Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T2?()").WithArguments("T2").WithLocation(14, 14), + Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T2?()").WithLocation(14, 14), // (14,14): error CS0304: Cannot create an instance of the variable type 'T2' because it does not have the new() constraint // x2 = new T2?(); // error 4 Diagnostic(ErrorCode.ERR_NoNewTyvar, "new T2?()").WithArguments("T2").WithLocation(14, 14), @@ -63328,7 +63328,7 @@ static void F5() where T5 : class Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "T2?").WithArguments("9.0").WithLocation(15, 18), // (15,14): error CS8628: Cannot use a nullable reference type in object creation. // x2 = new T2? { }; // error 5 - Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T2? { }").WithArguments("T2").WithLocation(15, 14), + Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T2? { }").WithLocation(15, 14), // (15,14): error CS0304: Cannot create an instance of the variable type 'T2' because it does not have the new() constraint // x2 = new T2? { }; // error 5 Diagnostic(ErrorCode.ERR_NoNewTyvar, "new T2? { }").WithArguments("T2").WithLocation(15, 14), @@ -63337,22 +63337,22 @@ static void F5() where T5 : class Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "T2?").WithArguments("9.0").WithLocation(16, 19), // (21,14): error CS8628: Cannot use a nullable reference type in object creation. // x3 = new T3?(); // error 6 - Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T3?()").WithArguments("T3").WithLocation(21, 14), + Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T3?()").WithLocation(21, 14), // (22,14): error CS8628: Cannot use a nullable reference type in object creation. // x3 = new T3? { }; // error 7 - Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T3? { }").WithArguments("T3").WithLocation(22, 14), + Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T3? { }").WithLocation(22, 14), // (28,18): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type unless language version '9.0' or greater is used. Consider changing the language version or adding a 'class', 'struct', or type constraint. // x4 = new T4?(); // error 8 Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "T4?").WithArguments("9.0").WithLocation(28, 18), // (28,14): error CS8628: Cannot use a nullable reference type in object creation. // x4 = new T4?(); // error 8 - Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T4?()").WithArguments("T4").WithLocation(28, 14), + Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T4?()").WithLocation(28, 14), // (29,18): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type unless language version '9.0' or greater is used. Consider changing the language version or adding a 'class', 'struct', or type constraint. // x4 = new T4? { }; // error 9 Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "T4?").WithArguments("9.0").WithLocation(29, 18), // (29,14): error CS8628: Cannot use a nullable reference type in object creation. // x4 = new T4? { }; // error 9 - Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T4? { }").WithArguments("T4").WithLocation(29, 14), + Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T4? { }").WithLocation(29, 14), // (30,19): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type unless language version '9.0' or greater is used. Consider changing the language version or adding a 'class', 'struct', or type constraint. // x4 = (new T4?[1])[0]; Diagnostic(ErrorCode.ERR_NullableUnconstrainedTypeParameter, "T4?").WithArguments("9.0").WithLocation(30, 19), @@ -63361,13 +63361,13 @@ static void F5() where T5 : class Diagnostic(ErrorCode.ERR_ValConstraintNotSatisfied, "System.Nullable?").WithArguments("System.Nullable", "T", "int?").WithLocation(31, 18), // (36,14): error CS8628: Cannot use a nullable reference type in object creation. // x5 = new T5?(); // error 10 - Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T5?()").WithArguments("T5").WithLocation(36, 14), + Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T5?()").WithLocation(36, 14), // (36,14): error CS0304: Cannot create an instance of the variable type 'T5' because it does not have the new() constraint // x5 = new T5?(); // error 10 Diagnostic(ErrorCode.ERR_NoNewTyvar, "new T5?()").WithArguments("T5").WithLocation(36, 14), // (37,14): error CS8628: Cannot use a nullable reference type in object creation. // x5 = new T5? { }; // error 11 - Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T5? { }").WithArguments("T5").WithLocation(37, 14), + Diagnostic(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, "new T5? { }").WithLocation(37, 14), // (37,14): error CS0304: Cannot create an instance of the variable type 'T5' because it does not have the new() constraint // x5 = new T5? { }; // error 11 Diagnostic(ErrorCode.ERR_NoNewTyvar, "new T5? { }").WithArguments("T5").WithLocation(37, 14) @@ -151676,13 +151676,13 @@ class C {} Diagnostic(ErrorCode.ERR_BadArity, "C x").WithArguments("C", "type", "1").WithLocation(11, 32), // (11,54): error CS1003: Syntax error, ',' expected // public override void M1(C x) - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(11, 54), + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(11, 54), // (11,54): error CS0246: The type or namespace name 'x' could not be found (are you missing a using directive or an assembly reference?) // public override void M1(C x) Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "x").WithArguments("x").WithLocation(11, 54), // (11,55): error CS1003: Syntax error, '>' expected // public override void M1(C x) - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(">", ")").WithLocation(11, 55), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(">").WithLocation(11, 55), // (11,55): error CS1001: Identifier expected // public override void M1(C x) Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(11, 55), @@ -152169,7 +152169,7 @@ void M() comp.VerifyEmitDiagnostics( // (9,15): error CS1003: Syntax error, '=>' expected // 0 = - Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("=>", "=").WithLocation(9, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("=>").WithLocation(9, 15), // (9,15): error CS1525: Invalid expression term '=' // 0 = Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(9, 15), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs index 9dca47172b61b..2bbf936a2b2e2 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs @@ -2854,7 +2854,7 @@ static void Main(string[] args) var expectedDiagnostics = new DiagnosticDescription[] { // CS1003: Syntax error, ',' expected // var x = 1/**/; - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(9, 13), + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(9, 13), // CS1513: } expected // var x = 1/**/; Diagnostic(ErrorCode.ERR_RbraceExpected, ";").WithLocation(9, 29), @@ -2906,7 +2906,7 @@ public static void Main() Diagnostic(ErrorCode.ERR_RbraceExpected, "{").WithLocation(6, 39), // CS1003: Syntax error, ',' expected // /**/new List() { { { 1 } }/**/ }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(6, 39), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(6, 39), // CS1002: ; expected // /**/new List() { { { 1 } }/**/ }; Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(6, 58), @@ -3163,7 +3163,7 @@ public IEnumerator GetEnumerator() Diagnostic(ErrorCode.ERR_RbraceExpected, "{").WithLocation(9, 46), // CS1003: Syntax error, ',' expected // var a = /**/new A { 5, { 1, 2, { 1, 2 } }/**/, 3 }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(9, 46), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(9, 46), // CS1001: Identifier expected // var a = /**/new A { 5, { 1, 2, { 1, 2 } }/**/, 3 }; Diagnostic(ErrorCode.ERR_IdentifierExpected, "3").WithLocation(9, 69), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs index 5a10e80c77e5b..d47b5ee285440 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs @@ -2395,7 +2395,7 @@ class Test : System.Attribute Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "out").WithArguments("", "out").WithLocation(4, 11), // (4,19): error CS1003: Syntax error, ',' expected // [Test(out var x3)] - Diagnostic(ErrorCode.ERR_SyntaxError, "x3").WithArguments(",", "").WithLocation(4, 19), + Diagnostic(ErrorCode.ERR_SyntaxError, "x3").WithArguments(",").WithLocation(4, 19), // (5,11): error CS1041: Identifier expected; 'out' is a keyword // [Test(out int x4)] Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "out").WithArguments("", "out").WithLocation(5, 11), @@ -2404,34 +2404,34 @@ class Test : System.Attribute Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(5, 15), // (5,19): error CS1003: Syntax error, ',' expected // [Test(out int x4)] - Diagnostic(ErrorCode.ERR_SyntaxError, "x4").WithArguments(",", "").WithLocation(5, 19), + Diagnostic(ErrorCode.ERR_SyntaxError, "x4").WithArguments(",").WithLocation(5, 19), // (6,14): error CS1525: Invalid expression term 'out' // [Test(p: out var x5)] Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(6, 14), // (6,14): error CS1003: Syntax error, ',' expected // [Test(p: out var x5)] - Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(6, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(6, 14), // (6,18): error CS1003: Syntax error, ',' expected // [Test(p: out var x5)] - Diagnostic(ErrorCode.ERR_SyntaxError, "var").WithArguments(",", "").WithLocation(6, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "var").WithArguments(",").WithLocation(6, 18), // (6,22): error CS1003: Syntax error, ',' expected // [Test(p: out var x5)] - Diagnostic(ErrorCode.ERR_SyntaxError, "x5").WithArguments(",", "").WithLocation(6, 22), + Diagnostic(ErrorCode.ERR_SyntaxError, "x5").WithArguments(",").WithLocation(6, 22), // (7,14): error CS1525: Invalid expression term 'out' // [Test(p: out int x6)] Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(7, 14), // (7,14): error CS1003: Syntax error, ',' expected // [Test(p: out int x6)] - Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(7, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(7, 14), // (7,18): error CS1003: Syntax error, ',' expected // [Test(p: out int x6)] - Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",", "int").WithLocation(7, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",").WithLocation(7, 18), // (7,18): error CS1525: Invalid expression term 'int' // [Test(p: out int x6)] Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(7, 18), // (7,22): error CS1003: Syntax error, ',' expected // [Test(p: out int x6)] - Diagnostic(ErrorCode.ERR_SyntaxError, "x6").WithArguments(",", "").WithLocation(7, 22), + Diagnostic(ErrorCode.ERR_SyntaxError, "x6").WithArguments(",").WithLocation(7, 22), // (4,15): error CS0103: The name 'var' does not exist in the current context // [Test(out var x3)] Diagnostic(ErrorCode.ERR_NameNotInContext, "var").WithArguments("var").WithLocation(4, 15), @@ -17816,13 +17816,13 @@ static void Test(out int x) Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(6, 14), // (6,18): error CS1003: Syntax error, ',' expected // Test(int x1); - Diagnostic(ErrorCode.ERR_SyntaxError, "x1").WithArguments(",", "").WithLocation(6, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "x1").WithArguments(",").WithLocation(6, 18), // (7,18): error CS1525: Invalid expression term 'int' // Test(ref int x2); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(7, 18), // (7,22): error CS1003: Syntax error, ',' expected // Test(ref int x2); - Diagnostic(ErrorCode.ERR_SyntaxError, "x2").WithArguments(",", "").WithLocation(7, 22), + Diagnostic(ErrorCode.ERR_SyntaxError, "x2").WithArguments(",").WithLocation(7, 22), // (6,18): error CS0103: The name 'x1' does not exist in the current context // Test(int x1); Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(6, 18), @@ -17858,7 +17858,7 @@ static void Test(out int x) compilation.VerifyDiagnostics( // (6,24): error CS1003: Syntax error, ',' expected // Test(out int x1.); - Diagnostic(ErrorCode.ERR_SyntaxError, ".").WithArguments(",", ".").WithLocation(6, 24) + Diagnostic(ErrorCode.ERR_SyntaxError, ".").WithArguments(",").WithLocation(6, 24) ); var tree = compilation.SyntaxTrees.Single(); @@ -20657,10 +20657,10 @@ public static void Main() compilation.VerifyDiagnostics( // (6,13): error CS1003: Syntax error, ',' expected // int[out var x1] a = null; // fatal syntax error - 'out' is skipped - Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(6, 13), + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(6, 13), // (6,21): error CS1003: Syntax error, ',' expected // int[out var x1] a = null; // fatal syntax error - 'out' is skipped - Diagnostic(ErrorCode.ERR_SyntaxError, "x1").WithArguments(",", "").WithLocation(6, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, "x1").WithArguments(",").WithLocation(6, 21), // (7,27): error CS1002: ; expected // int b(out var x2) = null; // parsed as a local function with syntax error Diagnostic(ErrorCode.ERR_SemicolonExpected, "=").WithLocation(7, 27), @@ -20672,13 +20672,13 @@ public static void Main() Diagnostic(ErrorCode.ERR_CStyleArray, "[out var x3]").WithLocation(8, 14), // (8,15): error CS1003: Syntax error, ',' expected // int c[out var x3] = null; // fatal syntax error - 'out' is skipped - Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(8, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(8, 15), // (8,19): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression) // int c[out var x3] = null; // fatal syntax error - 'out' is skipped Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "var").WithLocation(8, 19), // (8,23): error CS1003: Syntax error, ',' expected // int c[out var x3] = null; // fatal syntax error - 'out' is skipped - Diagnostic(ErrorCode.ERR_SyntaxError, "x3").WithArguments(",", "").WithLocation(8, 23), + Diagnostic(ErrorCode.ERR_SyntaxError, "x3").WithArguments(",").WithLocation(8, 23), // (8,23): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression) // int c[out var x3] = null; // fatal syntax error - 'out' is skipped Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "x3").WithLocation(8, 23), @@ -20687,10 +20687,10 @@ public static void Main() Diagnostic(ErrorCode.ERR_BadVarDecl, "(out var x4").WithLocation(10, 17), // (10,17): error CS1003: Syntax error, '[' expected // int d, e(out var x4); // parsed as a broken bracketed argument list on the declarator - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(10, 17), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(10, 17), // (10,28): error CS1003: Syntax error, ']' expected // int d, e(out var x4); // parsed as a broken bracketed argument list on the declarator - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(10, 28), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(10, 28), // (6,12): error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression) // int[out var x1] a = null; // fatal syntax error - 'out' is skipped Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "[out var x1]").WithLocation(6, 12), @@ -20822,10 +20822,10 @@ unsafe struct S compilation.VerifyDiagnostics( // (4,18): error CS1003: Syntax error, ',' expected // fixed int F1[out var x1, x1]; - Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(4, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(4, 18), // (4,26): error CS1003: Syntax error, ',' expected // fixed int F1[out var x1, x1]; - Diagnostic(ErrorCode.ERR_SyntaxError, "x1").WithArguments(",", "").WithLocation(4, 26), + Diagnostic(ErrorCode.ERR_SyntaxError, "x1").WithArguments(",").WithLocation(4, 26), // (4,17): error CS7092: A fixed buffer may only have one dimension. // fixed int F1[out var x1, x1]; Diagnostic(ErrorCode.ERR_FixedBufferTooManyDimensions, "[out var x1, x1]").WithLocation(4, 17), @@ -22946,10 +22946,10 @@ public static void Main() compilation.GetDiagnostics().Where(d => !exclude.Contains(d.Code)).Verify( // (8,28): error CS1003: Syntax error, '[' expected // fixed bool d[2], Test3 (out var x3); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(8, 28), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(8, 28), // (8,39): error CS1003: Syntax error, ']' expected // fixed bool d[2], Test3 (out var x3); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(8, 39), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(8, 39), // (8,33): error CS8185: A declaration is not allowed in this context. // fixed bool d[2], Test3 (out var x3); Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "var x3").WithLocation(8, 33) @@ -22982,10 +22982,10 @@ public static void Main() compilation.VerifyDiagnostics( // (8,22): error CS1003: Syntax error, ',' expected // fixed bool Test3[out var x3]; - Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(8, 22), + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(8, 22), // (8,30): error CS1003: Syntax error, ',' expected // fixed bool Test3[out var x3]; - Diagnostic(ErrorCode.ERR_SyntaxError, "x3").WithArguments(",", "").WithLocation(8, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, "x3").WithArguments(",").WithLocation(8, 30), // (8,21): error CS7092: A fixed buffer may only have one dimension. // fixed bool Test3[out var x3]; Diagnostic(ErrorCode.ERR_FixedBufferTooManyDimensions, "[out var x3]").WithLocation(8, 21), @@ -31702,10 +31702,10 @@ public static bool TakeOutParam(T y, out T x) Diagnostic(ErrorCode.ERR_BadVarDecl, "(out var x1").WithLocation(3, 10), // (3,10): error CS1003: Syntax error, '[' expected // bool a, b(out var x1); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 10), // (3,21): error CS1003: Syntax error, ']' expected // bool a, b(out var x1); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 21), // (3,19): error CS8197: Cannot infer the type of implicitly-typed out variable 'x1'. // bool a, b(out var x1); Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedOutVariable, "x1").WithArguments("x1").WithLocation(3, 19) @@ -31730,10 +31730,10 @@ public static bool TakeOutParam(T y, out T x) Diagnostic(ErrorCode.ERR_BadVarDecl, "(out var x1").WithLocation(3, 10), // (3,10): error CS1003: Syntax error, '[' expected // bool a, b(out var x1); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 10), // (3,21): error CS1003: Syntax error, ']' expected // bool a, b(out var x1); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 21), // (3,6): warning CS0168: The variable 'a' is declared but never used // bool a, b(out var x1); Diagnostic(ErrorCode.WRN_UnreferencedVar, "a").WithArguments("a").WithLocation(3, 6), @@ -31789,10 +31789,10 @@ public static bool TakeOutParam(T y, out T x) Diagnostic(ErrorCode.ERR_BadVarDecl, "(H.TakeOutParam(1, out var x1)").WithLocation(3, 10), // (3,10): error CS1003: Syntax error, '[' expected // bool a, b(H.TakeOutParam(1, out var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 10), // (3,40): error CS1003: Syntax error, ']' expected // bool a, b(H.TakeOutParam(1, out var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 40), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 40), // (2,1): warning CS0164: This label has not been referenced // label: Diagnostic(ErrorCode.WRN_UnreferencedLabel, "label").WithLocation(2, 1) @@ -31817,10 +31817,10 @@ public static bool TakeOutParam(T y, out T x) Diagnostic(ErrorCode.ERR_BadVarDecl, "(H.TakeOutParam(1, out var x1)").WithLocation(3, 10), // (3,10): error CS1003: Syntax error, '[' expected // bool a, b(H.TakeOutParam(1, out var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 10), // (3,40): error CS1003: Syntax error, ']' expected // bool a, b(H.TakeOutParam(1, out var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 40), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 40), // (2,1): warning CS0164: This label has not been referenced // label: Diagnostic(ErrorCode.WRN_UnreferencedLabel, "label").WithLocation(2, 1), @@ -31882,10 +31882,10 @@ public static bool TakeOutParam(T y, out T x) Diagnostic(ErrorCode.ERR_BadVarDecl, "(H.TakeOutParam(1, out var x1)").WithLocation(3, 25), // (3,25): error CS1003: Syntax error, '[' expected // event System.Action a, b(H.TakeOutParam(1, out var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 25), // (3,55): error CS1003: Syntax error, ']' expected // event System.Action a, b(H.TakeOutParam(1, out var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 55) + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 55) ); var tree = compilation.SyntaxTrees.Single(); @@ -31907,10 +31907,10 @@ public static bool TakeOutParam(T y, out T x) Diagnostic(ErrorCode.ERR_BadVarDecl, "(H.TakeOutParam(1, out var x1)").WithLocation(3, 25), // (3,25): error CS1003: Syntax error, '[' expected // event System.Action a, b(H.TakeOutParam(1, out var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 25), // (3,55): error CS1003: Syntax error, ']' expected // event System.Action a, b(H.TakeOutParam(1, out var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 55), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 55), // (4,9): error CS0103: The name 'x1' does not exist in the current context // H.Dummy(x1); Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(4, 9), @@ -35462,7 +35462,7 @@ static void TestOutVar(out int a) compilation.VerifyDiagnostics( // (6,16): error CS1003: Syntax error, '(' expected // foreach - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "").WithLocation(6, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(6, 16), // (7,60): error CS1515: 'in' expected // other(some().F(a => TestOutVar(out var x) ? x : 1)); Diagnostic(ErrorCode.ERR_InExpected, ";").WithLocation(7, 60), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs index 661293bdae97b..7a14b2051524d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests.cs @@ -4782,7 +4782,7 @@ public static void Main(object o) Diagnostic(ErrorCode.ERR_InvalidExprTerm, "").WithArguments("break").WithLocation(9, 32), // (9,32): error CS1003: Syntax error, ':' expected // case Color? Color2: - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "break").WithLocation(9, 32), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(9, 32), // (8,18): error CS0118: 'Color' is a variable but is used like a type // case Color Color: Diagnostic(ErrorCode.ERR_BadSKknown, "Color").WithArguments("Color", "variable", "type").WithLocation(8, 18), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests2.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests2.cs index 0f2f981590401..bbfd05f6c5d4e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests2.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests2.cs @@ -466,7 +466,7 @@ public static void Main() Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(26, 20), // (26,28): error CS1003: Syntax error, ',' expected // if (i is ((default)!)) {} // error 17 - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(26, 28), + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",").WithLocation(26, 28), // (26,29): error CS1525: Invalid expression term ')' // if (i is ((default)!)) {} // error 17 Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(26, 29) @@ -538,13 +538,13 @@ public static void Main() CreatePatternCompilation(source).VerifyDiagnostics( // (6,34): error CS1003: Syntax error, '=>' expected // var r1 = b switch { true ? true : true => true, false => false }; - Diagnostic(ErrorCode.ERR_SyntaxError, "?").WithArguments("=>", "?").WithLocation(6, 34), + Diagnostic(ErrorCode.ERR_SyntaxError, "?").WithArguments("=>").WithLocation(6, 34), // (6,34): error CS1525: Invalid expression term '?' // var r1 = b switch { true ? true : true => true, false => false }; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "?").WithArguments("?").WithLocation(6, 34), // (6,48): error CS1003: Syntax error, ',' expected // var r1 = b switch { true ? true : true => true, false => false }; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(6, 48), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(6, 48), // (6,48): error CS8504: Pattern missing // var r1 = b switch { true ? true : true => true, false => false }; Diagnostic(ErrorCode.ERR_MissingPattern, "=>").WithLocation(6, 48) @@ -2714,7 +2714,7 @@ public void M5(object o) { Diagnostic(ErrorCode.ERR_NameNotInContext, "_").WithArguments("_").WithLocation(13, 30), // (13,31): error CS1003: Syntax error, ':' expected // var t = o is string? _; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":", ";").WithLocation(13, 31), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":").WithLocation(13, 31), // (13,31): error CS1525: Invalid expression term ';' // var t = o is string? _; Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(13, 31), @@ -2723,10 +2723,10 @@ public void M5(object o) { Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(string? _)").WithArguments("object", "2").WithLocation(16, 22), // (16,29): error CS1003: Syntax error, ',' expected // var t = o is (string? _); - Diagnostic(ErrorCode.ERR_SyntaxError, "?").WithArguments(",", "?").WithLocation(16, 29), + Diagnostic(ErrorCode.ERR_SyntaxError, "?").WithArguments(",").WithLocation(16, 29), // (16,31): error CS1003: Syntax error, ',' expected // var t = o is (string? _); - Diagnostic(ErrorCode.ERR_SyntaxError, "_").WithArguments(",", "").WithLocation(16, 31) + Diagnostic(ErrorCode.ERR_SyntaxError, "_").WithArguments(",").WithLocation(16, 31) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests3.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests3.cs index 287caaaeb5f78..ece30c4353e11 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests3.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests3.cs @@ -5939,13 +5939,13 @@ public void M(nuint x) { compilation.VerifyDiagnostics( // (6,18): error CS1003: Syntax error, ',' expected // 2=>2, - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(6, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(6, 18), // (6,18): error CS8504: Pattern missing // 2=>2, Diagnostic(ErrorCode.ERR_MissingPattern, "=>").WithLocation(6, 18), // (13,18): error CS1003: Syntax error, ',' expected // 2=>2, - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(13, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(13, 18), // (13,18): error CS8504: Pattern missing // 2=>2, Diagnostic(ErrorCode.ERR_MissingPattern, "=>").WithLocation(13, 18) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests4.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests4.cs index bcefff4b6cdd7..fcfd622eaf39e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests4.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests4.cs @@ -150,10 +150,10 @@ public void M(T t) Diagnostic(ErrorCode.ERR_MissingDeconstruct, "(() => 0)").WithArguments("T", "2").WithLocation(8, 18), // (8,22): error CS1003: Syntax error, ',' expected // case (() => 0): - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(8, 22), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(8, 22), // (8,25): error CS1003: Syntax error, ',' expected // case (() => 0): - Diagnostic(ErrorCode.ERR_SyntaxError, "0").WithArguments(",", "").WithLocation(8, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "0").WithArguments(",").WithLocation(8, 25), // (10,18): error CS0518: Predefined type 'System.Span`1' is not defined or imported // case stackalloc int[1] { 0 }: Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "stackalloc int[1] { 0 }").WithArguments("System.Span`1").WithLocation(10, 18), @@ -1511,7 +1511,7 @@ class _ compilation.VerifyDiagnostics( // (9,20): error CS1003: Syntax error, ':' expected // case _ x: break; - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(":", "").WithLocation(9, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(":").WithLocation(9, 20), // (9,20): warning CS0164: This label has not been referenced // case _ x: break; Diagnostic(ErrorCode.WRN_UnreferencedLabel, "x").WithLocation(9, 20) @@ -1597,7 +1597,7 @@ class _ Diagnostic(ErrorCode.WRN_IsTypeNamedUnderscore, "_").WithArguments("_").WithLocation(9, 32), // (9,34): error CS1003: Syntax error, ',' expected // Console.Write(e is _ x); - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(9, 34), + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(9, 34), // (9,34): error CS0103: The name 'x' does not exist in the current context // Console.Write(e is _ x); Diagnostic(ErrorCode.ERR_NameNotInContext, "x").WithArguments("x").WithLocation(9, 34) @@ -1718,7 +1718,7 @@ class _ Diagnostic(ErrorCode.ERR_WrongNumberOfSubpatterns, "(_ x, _)").WithArguments("(object, object)", "2", "3").WithLocation(10, 22), // (10,25): error CS1003: Syntax error, ',' expected // if (e is (_ x, _)) - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(10, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(10, 25), // (10,25): error CS0103: The name 'x' does not exist in the current context // if (e is (_ x, _)) Diagnostic(ErrorCode.ERR_NameNotInContext, "x").WithArguments("x").WithLocation(10, 25) @@ -3718,37 +3718,37 @@ static void M(object o, bool c) Diagnostic(ErrorCode.ERR_IsNullableType, "A?").WithArguments("A").WithLocation(7, 18), // (8,23): error CS1003: Syntax error, ':' expected // if (o is A? b1) { } // error 2 (missing :) - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":", ")").WithLocation(8, 23), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":").WithLocation(8, 23), // (8,23): error CS1525: Invalid expression term ')' // if (o is A? b1) { } // error 2 (missing :) Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(8, 23), // (9,28): error CS1003: Syntax error, ':' expected // if (o is A? b2 && c) { } // error 3 (missing :) - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":", ")").WithLocation(9, 28), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":").WithLocation(9, 28), // (9,28): error CS1525: Invalid expression term ')' // if (o is A? b2 && c) { } // error 3 (missing :) Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(9, 28), // (10,25): error CS1003: Syntax error, ':' expected // if (o is A[]? b5) { } // error 4 (missing :) - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":", ")").WithLocation(10, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":").WithLocation(10, 25), // (10,25): error CS1525: Invalid expression term ')' // if (o is A[]? b5) { } // error 4 (missing :) Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(10, 25), // (11,30): error CS1003: Syntax error, ':' expected // if (o is A[]? b6 && c) { } // error 5 (missing :) - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":", ")").WithLocation(11, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":").WithLocation(11, 30), // (11,30): error CS1525: Invalid expression term ')' // if (o is A[]? b6 && c) { } // error 5 (missing :) Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(11, 30), // (12,27): error CS1003: Syntax error, ':' expected // if (o is A[][]? b7) { } // error 6 (missing :) - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":", ")").WithLocation(12, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":").WithLocation(12, 27), // (12,27): error CS1525: Invalid expression term ')' // if (o is A[][]? b7) { } // error 6 (missing :) Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(12, 27), // (13,32): error CS1003: Syntax error, ':' expected // if (o is A[][]? b8 && c) { } // error 7 (missing :) - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":", ")").WithLocation(13, 32), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":").WithLocation(13, 32), // (13,32): error CS1525: Invalid expression term ')' // if (o is A[][]? b8 && c) { } // error 7 (missing :) Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(13, 32), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests5.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests5.cs index ea24eed999d78..2eb874bb6b89b 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests5.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests5.cs @@ -312,10 +312,10 @@ public static void Main() Diagnostic(ErrorCode.ERR_ArraySizeInDeclaration, "[0]").WithLocation(10, 31), // (10,34): error CS1003: Syntax error, ',' expected // _ = new C() is { Prop1[0]: {} }; - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(10, 34), + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(10, 34), // (10,36): error CS1003: Syntax error, ',' expected // _ = new C() is { Prop1[0]: {} }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(10, 36), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(10, 36), // (11,26): error CS8918: Identifier or a simple member access expected. // _ = new C() is { 1: {} }; Diagnostic(ErrorCode.ERR_InvalidNameInSubpattern, "1").WithLocation(11, 26)); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Global.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Global.cs index f7379eddd0b78..eaeab226391a2 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Global.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Global.cs @@ -5928,10 +5928,10 @@ class H Diagnostic(ErrorCode.ERR_BadVarDecl, @"(""5948"" is var x1").WithLocation(3, 10), // (3,10): error CS1003: Syntax error, '[' expected // bool a, b("5948" is var x1); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 10), // (3,27): error CS1003: Syntax error, ']' expected // bool a, b("5948" is var x1); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 27) + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 27) ); var tree = compilation.SyntaxTrees.Single(); @@ -5960,10 +5960,10 @@ class H Diagnostic(ErrorCode.ERR_BadVarDecl, @"(""5948"" is var x1").WithLocation(3, 10), // (3,10): error CS1003: Syntax error, '[' expected // bool a, b("5948" is var x1); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 10), // (3,27): error CS1003: Syntax error, ']' expected // bool a, b("5948" is var x1); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 27), // (4,9): error CS0165: Use of unassigned local variable 'x1' // H.Dummy(x1); Diagnostic(ErrorCode.ERR_UseDefViolation, "x1").WithArguments("x1").WithLocation(4, 9), @@ -6013,10 +6013,10 @@ class H Diagnostic(ErrorCode.ERR_BadVarDecl, "((1 is var x1)").WithLocation(3, 10), // (3,10): error CS1003: Syntax error, '[' expected // bool a, b((1 is var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 10), // (3,24): error CS1003: Syntax error, ']' expected // bool a, b((1 is var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 24), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 24), // (2,1): warning CS0164: This label has not been referenced // label: Diagnostic(ErrorCode.WRN_UnreferencedLabel, "label").WithLocation(2, 1) @@ -6050,10 +6050,10 @@ class H Diagnostic(ErrorCode.ERR_BadVarDecl, "((1 is var x1)").WithLocation(3, 10), // (3,10): error CS1003: Syntax error, '[' expected // bool a, b((1 is var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 10), // (3,24): error CS1003: Syntax error, ']' expected // bool a, b((1 is var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 24), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 24), // (4,9): error CS0165: Use of unassigned local variable 'x1' // H.Dummy(x1); Diagnostic(ErrorCode.ERR_UseDefViolation, "x1").WithArguments("x1").WithLocation(4, 9) @@ -6100,10 +6100,10 @@ class H Diagnostic(ErrorCode.ERR_BadVarDecl, "(H.Dummy(1 is var x1)").WithLocation(3, 25), // (3,25): error CS1003: Syntax error, '[' expected // event System.Action a, b(H.Dummy(1 is var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 25), // (3,46): error CS1003: Syntax error, ']' expected // event System.Action a, b(H.Dummy(1 is var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 46) + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 46) ); var tree = compilation.SyntaxTrees.Single(); @@ -6126,10 +6126,10 @@ class H Diagnostic(ErrorCode.ERR_BadVarDecl, "(H.Dummy(1 is var x1)").WithLocation(3, 25), // (3,25): error CS1003: Syntax error, '[' expected // event System.Action a, b(H.Dummy(1 is var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(3, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 25), // (3,46): error CS1003: Syntax error, ']' expected // event System.Action a, b(H.Dummy(1 is var x1)); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(3, 46), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 46), // (4,9): error CS0103: The name 'x1' does not exist in the current context // H.Dummy(x1); Diagnostic(ErrorCode.ERR_NameNotInContext, "x1").WithArguments("x1").WithLocation(4, 9), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Scope.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Scope.cs index 35a4da69f4655..91a7947e41648 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Scope.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_Scope.cs @@ -13694,10 +13694,10 @@ public static void Main() compilation.GetDiagnostics().Where(d => !exclude.Contains(d.Code)).Verify( // (8,28): error CS1003: Syntax error, '[' expected // fixed bool d[2], Test3 (string.Empty is var x3); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(8, 28), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(8, 28), // (8,51): error CS1003: Syntax error, ']' expected // fixed bool d[2], Test3 (string.Empty is var x3); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(8, 51), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(8, 51), // (8,29): error CS0029: Cannot implicitly convert type 'bool' to 'int' // fixed bool d[2], Test3 (string.Empty is var x3); Diagnostic(ErrorCode.ERR_NoImplicitConv, "string.Empty is var x3").WithArguments("bool", "int").WithLocation(8, 29) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternSwitchTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternSwitchTests.cs index 7add5a8d4a562..3b435c6fe2050 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternSwitchTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternSwitchTests.cs @@ -3214,7 +3214,7 @@ void M() var q ").WithArguments("pattern matching", "7.0").WithLocation(8, 13), // (10,15): error CS1003: Syntax error, ':' expected // var q = 3; - Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments(":", "=").WithLocation(10, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments(":").WithLocation(10, 15), // (10,15): error CS1525: Invalid expression term '=' // var q = 3; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(10, 15), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/QueryTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/QueryTests.cs index 0476d3b9dddde..e661ffa5b6ff8 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/QueryTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/QueryTests.cs @@ -1897,7 +1897,7 @@ Element Values(1): Diagnostic(ErrorCode.ERR_IdentifierExpected, "null").WithLocation(8, 66), // CS1003: Syntax error, 'in' expected // var query = /**/from int i in new int[] { 1 } join null on true equals true select i/**/; //CS1031 - Diagnostic(ErrorCode.ERR_SyntaxError, "null").WithArguments("in", "null").WithLocation(8, 66) + Diagnostic(ErrorCode.ERR_SyntaxError, "null").WithArguments("in").WithLocation(8, 66) }; VerifyOperationTreeAndDiagnosticsForTest(source, expectedOperationTree, expectedDiagnostics); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs index 3f03276b84575..d5570b892e9c5 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs @@ -2046,7 +2046,7 @@ public struct S Diagnostic(ErrorCode.ERR_BadMemberFlag, "S").WithArguments("readonly").WithLocation(4, 15), // (4,15): error CS0575: Only class types can contain destructors // readonly ~S() { } - Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "S").WithArguments("S.~S()").WithLocation(4, 15)); + Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "S").WithLocation(4, 15)); } [Fact] @@ -2148,7 +2148,7 @@ void M2(System.Func a) Diagnostic(ErrorCode.ERR_IdentifierExpected, "=>").WithLocation(6, 24), // (6,24): error CS1003: Syntax error, ',' expected // M2(readonly () => 42); - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(6, 24), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(6, 24), // (6,27): error CS1002: ; expected // M2(readonly () => 42); Diagnostic(ErrorCode.ERR_SemicolonExpected, "42").WithLocation(6, 27), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs index 744fe220c555d..54f632b6f3f96 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordStructTests.cs @@ -1236,7 +1236,7 @@ public record struct S comp.VerifyDiagnostics( // (4,6): error CS0575: Only class types can contain destructors // ~S() { } - Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "S").WithArguments("S.~S()").WithLocation(4, 6) + Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "S").WithLocation(4, 6) ); } @@ -3122,7 +3122,7 @@ public record struct @iii Diagnostic(ErrorCode.ERR_BadDestructorName, "iiii").WithLocation(4, 6), // (4,6): error CS0575: Only class types can contain destructors // ~iiii(){} - Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "iiii").WithArguments("iii.~iii()").WithLocation(4, 6) + Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "iiii").WithLocation(4, 6) ); } @@ -3143,7 +3143,7 @@ public R() : this(0) { } Diagnostic(ErrorCode.ERR_BadMemberFlag, "R").WithArguments("static").WithLocation(2, 22), // (5,6): error CS0575: Only class types can contain destructors // ~R() { } - Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "R").WithArguments("R.~R()").WithLocation(5, 6) + Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "R").WithLocation(5, 6) ); } @@ -4006,14 +4006,14 @@ record struct Pos2(int X) Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "Pos").WithArguments("Pos.x", "preview").WithLocation(2, 15), // (5,16): error CS8050: Only auto-implemented properties can have initializers. // public int X { get { return x; } set { x = value; } } = X; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithArguments("Pos.X").WithLocation(5, 16) + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16) ); comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext); comp.VerifyEmitDiagnostics( // (5,16): error CS8050: Only auto-implemented properties can have initializers. // public int X { get { return x; } set { x = value; } } = X; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithArguments("Pos.X").WithLocation(5, 16) + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "X").WithLocation(5, 16) ); } @@ -10034,7 +10034,7 @@ public static void M() Diagnostic(ErrorCode.ERR_IdentifierExpected, "0").WithLocation(7, 27), // (7,27): error CS1003: Syntax error, ']' expected // var b = a with { [0] = 20 }; - Diagnostic(ErrorCode.ERR_SyntaxError, "0").WithArguments("]", "").WithLocation(7, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, "0").WithArguments("]").WithLocation(7, 27), // (7,28): error CS1002: ; expected // var b = a with { [0] = 20 }; Diagnostic(ErrorCode.ERR_SemicolonExpected, "]").WithLocation(7, 28), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs index 485b43727a94a..f872c316c1810 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RecordTests.cs @@ -9736,7 +9736,7 @@ public static void Main() comp.VerifyDiagnostics( // (9,9): error CS8147: Properties which return by reference cannot have set accessors // set { } - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithArguments("C.X.set").WithLocation(9, 9), + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(9, 9), // (15,32): error CS1525: Invalid expression term 'ref' // var c = new C(0) { X = ref a[0] }; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref a[0]").WithArguments("ref").WithLocation(15, 32), @@ -30377,5 +30377,52 @@ public record C(int I) : B(I);"; }; AssertEx.Equal(expectedMembers, actualMembers); } + + [Fact, WorkItem(60379, "https://github.com/dotnet/roslyn/issues/60379")] + public void RecordPositionalMembersScope() + { + var src = @" +using System; + +[Obsolete(nameof(Id))] +record R1(string Id) { } + +[Obsolete(nameof(Id))] +record R2(string Id); +"; + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + } + + [Fact, WorkItem(60379, "https://github.com/dotnet/roslyn/issues/60379")] + public void TypeParametersAndTypeMembersInScopeOnTypeAttribute() + { + var src = @" +using System; + +[Obsolete(nameof(Id))] +class C1 +{ + int Id { get; set; } +} + +[Obsolete(Constant)] +class C2 +{ + const string Constant = """"; +} + +[Obsolete(T)] +class C3 +{ +} +"; + var comp = CreateCompilation(src); + comp.VerifyDiagnostics( + // (16,11): error CS0119: 'T' is a type, which is not valid in the given context + // [Obsolete(T)] + Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type").WithLocation(16, 11) + ); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs index b3718b18db2e6..31f875dcbadd6 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs @@ -2377,7 +2377,7 @@ ref struct S2{} CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( // (31,28): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref x; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithArguments("this").WithLocation(31, 28) + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithLocation(31, 28) ); } @@ -3625,10 +3625,10 @@ public void M(ref Test obj) Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(6, 9), // (6,20): error CS1510: A ref or out value must be an assignable variable // this = ref this; - Diagnostic(ErrorCode.ERR_RefLvalueExpected, "this").WithArguments("this").WithLocation(6, 20), + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "this").WithLocation(6, 20), // (7,19): error CS1510: A ref or out value must be an assignable variable // obj = ref this; - Diagnostic(ErrorCode.ERR_RefLvalueExpected, "this").WithArguments("this").WithLocation(7, 19), + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "this").WithLocation(7, 19), // (8,9): error CS8373: The left-hand side of a ref assignment must be a ref local or parameter. // this = ref obj; Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(8, 9)); @@ -3676,7 +3676,7 @@ public void M(ref Test obj) Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(6, 9), // (7,19): error CS1510: A ref or out value must be an assignable variable // obj = ref this; - Diagnostic(ErrorCode.ERR_RefLvalueExpected, "this").WithArguments("this").WithLocation(7, 19), + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "this").WithLocation(7, 19), // (8,9): error CS8373: The left-hand side of a ref assignment must be a ref local or parameter. // this = ref obj; Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(8, 9)); @@ -3724,7 +3724,7 @@ public void M(ref Test obj) Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(6, 9), // (7,19): error CS1510: A ref or out value must be an assignable variable // obj = ref this; - Diagnostic(ErrorCode.ERR_RefLvalueExpected, "this").WithArguments("this").WithLocation(7, 19), + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "this").WithLocation(7, 19), // (8,9): error CS8373: The left-hand side of a ref assignment must be a ref local or parameter. // this = ref obj; Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "this").WithLocation(8, 9)); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs index 4f28508796b63..7b2015f7a7035 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs @@ -625,7 +625,7 @@ void M(ref string s) comp.VerifyDiagnostics( // (8,17): error CS1510: A ref or out value must be an assignable variable // s = ref s2; - Diagnostic(ErrorCode.ERR_RefLvalueExpected, "s2").WithArguments("C.s2").WithLocation(8, 17)); + Diagnostic(ErrorCode.ERR_RefLvalueExpected, "s2").WithLocation(8, 17)); } [Fact] @@ -739,7 +739,7 @@ void M() Diagnostic(ErrorCode.ERR_QueryOutRefRangeVariable, "c").WithArguments("c").WithLocation(12, 22), // (13,13): error CS8355: The left-hand side of a ref assignment must be a ref local or parameter. // c = ref x; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "c").WithArguments("c").WithLocation(13, 13)); + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "c").WithLocation(13, 13)); } [Fact] @@ -926,7 +926,7 @@ void M() comp.VerifyDiagnostics( // (8,9): error CS8355: The left-hand side of a ref assignment must be a ref local or parameter. // x = ref y; - Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "x").WithArguments("x").WithLocation(8, 9)); + Diagnostic(ErrorCode.ERR_RefLocalOrParamExpected, "x").WithLocation(8, 9)); } [Fact] @@ -1610,7 +1610,7 @@ ref int E() Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "VoidMethod()").WithLocation(23, 20), // (30,20): error CS8156: An expression cannot be used in this context because it may not be returned by reference // return ref P1; - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "P1").WithArguments("Test.P1").WithLocation(30, 20) + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "P1").WithLocation(30, 20) ); } @@ -1651,7 +1651,7 @@ void VoidMethod(){} Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "VoidMethod()").WithLocation(12, 27), // (13,27): error CS8156: An expression cannot be used in this context because it may not be returned by reference // D1 d5 = () => ref P1; - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "P1").WithArguments("Test.P1").WithLocation(13, 27)); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "P1").WithLocation(13, 27)); } [Fact] @@ -2075,13 +2075,13 @@ public ref C M() comp.VerifyDiagnostics( // (10,24): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref this; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithArguments("this").WithLocation(10, 24), + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(10, 24), // (15,24): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref x; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithArguments("this").WithLocation(15, 24), + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithLocation(15, 24), // (20,24): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref this.x; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this.x").WithArguments("this").WithLocation(20, 24), + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this.x").WithLocation(20, 24), // (36,32): error CS8168: Cannot return local 'M1' by reference because it is not a ref local // return ref Goo(ref M1); Diagnostic(ErrorCode.ERR_RefReturnLocal, "M1").WithArguments("M1").WithLocation(36, 32), @@ -2102,7 +2102,7 @@ public ref C M() Diagnostic(ErrorCode.ERR_EscapeCall2, "Goo(ref M2)").WithArguments("Test.Goo(ref Test.S1)", "arg").WithLocation(46, 24), // (58,24): error CS8354: Cannot return 'this' by reference. // return ref this; - Diagnostic(ErrorCode.ERR_RefReturnThis, "this").WithArguments("this").WithLocation(58, 24) + Diagnostic(ErrorCode.ERR_RefReturnThis, "this").WithLocation(58, 24) ); } @@ -2924,7 +2924,7 @@ static void M() CreateCompilationWithMscorlib46(text).VerifyDiagnostics( // (8,26): error CS0206: A property or indexer may not be passed as an out or ref parameter // ref int rl = ref P; - Diagnostic(ErrorCode.ERR_RefProperty, "P").WithArguments("Program.P").WithLocation(8, 26)); + Diagnostic(ErrorCode.ERR_RefProperty, "P").WithLocation(8, 26)); } [Fact] @@ -2945,7 +2945,7 @@ void M() CreateCompilationWithMscorlib46(text).VerifyDiagnostics( // (8,26): error CS0206: A property or indexer may not be passed as an out or ref parameter // ref int rl = ref this[0]; - Diagnostic(ErrorCode.ERR_RefProperty, "this[0]").WithArguments("Program.this[int]").WithLocation(8, 26)); + Diagnostic(ErrorCode.ERR_RefProperty, "this[0]").WithLocation(8, 26)); } [Fact] @@ -3308,7 +3308,7 @@ static ref int M() CreateCompilationWithMscorlib46(text).VerifyDiagnostics( // (8,20): error CS8900: The argument to a by reference return or assignment must be an assignable variable or a property or call that returns by reference // return ref P; - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "P").WithArguments("Program.P").WithLocation(8, 20)); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "P").WithLocation(8, 20)); } [Fact] @@ -3329,7 +3329,7 @@ ref int M() CreateCompilationWithMscorlib46(text).VerifyDiagnostics( // (8,20): error CS8900: The argument to a by reference return or assignment must be an assignable variable or a property or call that returns by reference // return ref this[0]; - Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "this[0]").WithArguments("Program.this[int]").WithLocation(8, 20)); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "this[0]").WithLocation(8, 20)); } [Fact] @@ -3375,7 +3375,7 @@ ref D M() CreateCompilationWithMscorlib46(text).VerifyDiagnostics( // (10,20): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref d; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "d").WithArguments("this").WithLocation(10, 20) + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "d").WithLocation(10, 20) ); } @@ -3424,7 +3424,7 @@ ref int M() CreateCompilationWithMscorlib46(text).VerifyDiagnostics( // (13,20): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref i; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "i").WithArguments("this").WithLocation(13, 20) + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "i").WithLocation(13, 20) ); } @@ -3538,7 +3538,7 @@ ref Program M() CreateCompilationWithMscorlib46(text).VerifyDiagnostics( // (6,20): error CS8170: Struct members cannot return 'this' or other instance members by reference // return ref this; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithArguments("this").WithLocation(6, 20)); + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(6, 20)); } [Fact] @@ -3557,7 +3557,7 @@ ref Program M() CreateCompilationWithMscorlib46(text).VerifyDiagnostics( // (6,20): error CS8354: Cannot return 'this' by reference. // return ref this; - Diagnostic(ErrorCode.ERR_RefReturnThis, "this").WithArguments("this").WithLocation(6, 20) + Diagnostic(ErrorCode.ERR_RefReturnThis, "this").WithLocation(6, 20) ); } @@ -4014,7 +4014,7 @@ void N() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "out").WithArguments("out").WithLocation(10, 15), // (10,15): error CS1003: Syntax error, ',' expected // M(out out int x); - Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(10, 15)); + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(10, 15)); } [Fact, WorkItem(26418, "https://github.com/dotnet/roslyn/issues/26418")] @@ -4037,13 +4037,13 @@ void N() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "in").WithArguments("in").WithLocation(10, 15), // (10,15): error CS1003: Syntax error, ',' expected // M(out in int x); - Diagnostic(ErrorCode.ERR_SyntaxError, "in").WithArguments(",", "in").WithLocation(10, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "in").WithArguments(",").WithLocation(10, 15), // (10,18): error CS1525: Invalid expression term 'int' // M(out in int x); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(10, 18), // (10,22): error CS1003: Syntax error, ',' expected // M(out in int x); - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(10, 22)); + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(10, 22)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs index fb652c6edd366..da51e69857487 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ScriptSemanticsTests.cs @@ -1159,7 +1159,7 @@ public void FixedBuffer_02() compilation.VerifyDiagnostics( // (1,16): error CS1003: Syntax error, ',' expected // fixed var x[3] = 1; - Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments(",", "=").WithLocation(1, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments(",").WithLocation(1, 16), // (1,11): error CS1642: Fixed size buffer fields may only be members of structs // fixed var x[3] = 1; Diagnostic(ErrorCode.ERR_FixedNotInStruct, "x").WithLocation(1, 11), diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs index de3846c09aa90..44a2f401879ed 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SemanticErrorTests.cs @@ -985,7 +985,7 @@ static void Main(string[] args) "; CreateCompilation(text).VerifyDiagnostics( // (6,30): error CS1003: Syntax error, ',' expected - Diagnostic(ErrorCode.ERR_SyntaxError, "2").WithArguments(",", "")); + Diagnostic(ErrorCode.ERR_SyntaxError, "2").WithArguments(",")); } [WorkItem(542486, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542486")] @@ -1004,7 +1004,7 @@ static void Main(string[] args) // NOTE: Dev10 just gives a parse error on '2' CreateCompilation(text).VerifyDiagnostics( // (6,30): error CS1003: Syntax error, ',' expected - Diagnostic(ErrorCode.ERR_SyntaxError, "2").WithArguments(",", ""), + Diagnostic(ErrorCode.ERR_SyntaxError, "2").WithArguments(","), // (6,35): error CS0846: A nested array initializer is expected Diagnostic(ErrorCode.ERR_ArrayInitializerExpected, "1")); } @@ -8043,9 +8043,11 @@ void M() "; CreateCompilation(text).VerifyDiagnostics( // (14,15): error CS0206: A property or indexer may not be passed as an out or ref parameter - Diagnostic(ErrorCode.ERR_RefProperty, "P").WithArguments("C.P"), + // M(ref P); // CS0206 + Diagnostic(ErrorCode.ERR_RefProperty, "P").WithLocation(14, 15), // (15,15): error CS0206: A property or indexer may not be passed as an out or ref parameter - Diagnostic(ErrorCode.ERR_RefProperty, "this.Q").WithArguments("C.Q")); + // M(out this.Q); // CS0206 + Diagnostic(ErrorCode.ERR_RefProperty, "this.Q").WithLocation(15, 15)); } [Fact] @@ -8071,9 +8073,11 @@ void M() "; CreateCompilation(text).VerifyDiagnostics( // (13,15): error CS0206: A property or indexer may not be passed as an out or ref parameter - Diagnostic(ErrorCode.ERR_RefProperty, "this[0]").WithArguments("C.this[int]"), + // R(ref this[0]); // CS0206 + Diagnostic(ErrorCode.ERR_RefProperty, "this[0]").WithLocation(13, 15), // (14,15): error CS0206: A property or indexer may not be passed as an out or ref parameter - Diagnostic(ErrorCode.ERR_RefProperty, "this[0]").WithArguments("C.this[int]")); + // O(out this[0]); // CS0206 + Diagnostic(ErrorCode.ERR_RefProperty, "this[0]").WithLocation(14, 15)); } [Fact] @@ -13447,27 +13451,38 @@ static void M() "; CreateCompilation(text).VerifyDiagnostics( // (7,11): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "local"), + // ++local; + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "local").WithLocation(7, 11), // (8,9): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "local"), + // local++; + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "local").WithLocation(8, 9), // (9,11): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "field"), + // --field; + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "field").WithLocation(9, 11), // (10,9): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "field"), + // field--; + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "field").WithLocation(10, 9), // (11,12): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "local + 3"), + // ++(local + 3); + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "local + 3").WithLocation(11, 12), // (12,10): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "local + 3"), + // (local + 3)++; + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "local + 3").WithLocation(12, 10), // (13,11): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "2"), + // --2; + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "2").WithLocation(13, 11), // (14,9): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "2"), + // 2--; + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "2").WithLocation(14, 9), // (17,10): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "d + 1"), + // (d + 1)++; + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "d + 1").WithLocation(17, 10), // (18,12): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "d + 1"), + // --(d + 1); + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "d + 1").WithLocation(18, 12), // (19,9): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "d++")); + // d++++; + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "d++").WithLocation(19, 9)); } [Fact] @@ -13486,10 +13501,10 @@ void M() CreateCompilation(text).VerifyDiagnostics( // (6,11): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer // ++this; // CS1059 - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "this").WithArguments("this"), + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "this").WithLocation(6, 11), // (7,9): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer // this--; // CS1059 - Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "this").WithArguments("this")); + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "this").WithLocation(7, 9)); } [Fact] @@ -14308,17 +14323,16 @@ public static void Main() .VerifyDiagnostics( // (5,19): error CS1525: Invalid expression term ';' // var s = 1?; - Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";"), + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(5, 19), // (5,19): error CS1003: Syntax error, ':' expected // var s = 1?; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":", ";"), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":").WithLocation(5, 19), // (5,19): error CS1525: Invalid expression term ';' // var s = 1?; - Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";"), + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(5, 19), // (5,17): error CS0029: Cannot implicitly convert type 'int' to 'bool' // var s = 1?; - Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "bool") - ); + Diagnostic(ErrorCode.ERR_NoImplicitConv, "1").WithArguments("int", "bool").WithLocation(5, 17)); } [Fact] @@ -14338,16 +14352,37 @@ static void Main(string[] args) } } ") - .VerifyDiagnostics(Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")"), - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":", ")"), - Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")"), - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":", ")"), - Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")"), - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":"), - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(",", "("), - Diagnostic(ErrorCode.ERR_InvalidExprTerm, ":").WithArguments(":"), - Diagnostic(ErrorCode.ERR_InvalidExprTerm, ":").WithArguments(":"), - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":")); + .VerifyDiagnostics( + // (7,46): error CS1525: Invalid expression term ')' + // System.Console.WriteLine(((x == y)) ?); // Invalid + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(7, 46), + // (7,46): error CS1003: Syntax error, ':' expected + // System.Console.WriteLine(((x == y)) ?); // Invalid + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":").WithLocation(7, 46), + // (7,46): error CS1525: Invalid expression term ')' + // System.Console.WriteLine(((x == y)) ?); // Invalid + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(7, 46), + // (8,52): error CS1003: Syntax error, ':' expected + // System.Console.WriteLine(((x == y)) ? (x++)); // Invalid + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":").WithLocation(8, 52), + // (8,52): error CS1525: Invalid expression term ')' + // System.Console.WriteLine(((x == y)) ? (x++)); // Invalid + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(8, 52), + // (9,61): error CS1003: Syntax error, ',' expected + // System.Console.WriteLine(((x == y)) ? (x++) : (x++) : ((((y++))))); // Invalid + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(9, 61), + // (9,63): error CS1003: Syntax error, ',' expected + // System.Console.WriteLine(((x == y)) ? (x++) : (x++) : ((((y++))))); // Invalid + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(",").WithLocation(9, 63), + // (10,48): error CS1525: Invalid expression term ':' + // System.Console.WriteLine(((x == y)) ? : :); // Invalid + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ":").WithArguments(":").WithLocation(10, 48), + // (10,50): error CS1525: Invalid expression term ':' + // System.Console.WriteLine(((x == y)) ? : :); // Invalid + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ":").WithArguments(":").WithLocation(10, 50), + // (10,50): error CS1003: Syntax error, ',' expected + // System.Console.WriteLine(((x == y)) ? : :); // Invalid + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(10, 50)); } [WorkItem(528657, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528657")] @@ -21620,12 +21655,12 @@ public class MyClass2 } "; CreateCompilationWithMscorlib40AndDocumentationComments(text).VerifyDiagnostics( - // (15,20): warning CS1581: Invalid return type in XML comment cref attribute + // (15,46): warning CS1581: Invalid return type in XML comment cref attribute // /// // CS1581 - Diagnostic(ErrorCode.WRN_BadXMLRefReturnType, "intt").WithArguments("intt", "MyClass.explicit operator intt(MyClass)"), - // (15,20): warning CS1574: XML comment has cref attribute 'MyClass.explicit operator intt(MyClass)' that could not be resolved + Diagnostic(ErrorCode.WRN_BadXMLRefReturnType, "intt").WithLocation(15, 46), + // (15,20): warning CS1574: XML comment has cref attribute 'explicit operator intt(MyClass)' that could not be resolved // /// // CS1581 - Diagnostic(ErrorCode.WRN_BadXMLRef, "MyClass.explicit operator intt(MyClass)").WithArguments("explicit operator intt(MyClass)")); + Diagnostic(ErrorCode.WRN_BadXMLRef, "MyClass.explicit operator intt(MyClass)").WithArguments("explicit operator intt(MyClass)").WithLocation(15, 20)); } [Fact] @@ -22836,13 +22871,13 @@ static void Test(Func Baz) Diagnostic(ErrorCode.ERR_RefLvalueExpected, "Goo(x => x)").WithLocation(17, 47), // (18,43): error CS0206: A property or indexer may not be passed as an out or ref parameter // var z6 = new Func(ref BarP); - Diagnostic(ErrorCode.ERR_RefProperty, "ref BarP").WithArguments("Program.BarP").WithLocation(18, 43), + Diagnostic(ErrorCode.ERR_RefProperty, "ref BarP").WithLocation(18, 43), // (19,47): error CS1510: A ref or out argument must be an assignable variable // var z7 = new Func(ref new Func(x => x)); Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new Func(x => x)").WithLocation(19, 47), // (20,43): error CS0206: A property or indexer may not be passed as an out or ref parameter // var z8 = new Func(ref Program.BarP); - Diagnostic(ErrorCode.ERR_RefProperty, "ref Program.BarP").WithArguments("Program.BarP").WithLocation(20, 43), + Diagnostic(ErrorCode.ERR_RefProperty, "ref Program.BarP").WithLocation(20, 43), // (21,47): error CS1510: A ref or out argument must be an assignable variable // var z9 = new Func(ref Program.Goo(x => x)); Diagnostic(ErrorCode.ERR_RefLvalueExpected, "Program.Goo(x => x)").WithLocation(21, 47), @@ -22869,13 +22904,13 @@ static void Test(Func Baz) Diagnostic(ErrorCode.ERR_RefLvalueExpected, "Goo(x => x)").WithLocation(17, 47), // (18,47): error CS0206: A property or indexer may not be passed as an out or ref parameter // var z6 = new Func(ref BarP); - Diagnostic(ErrorCode.ERR_RefProperty, "BarP").WithArguments("Program.BarP").WithLocation(18, 47), + Diagnostic(ErrorCode.ERR_RefProperty, "BarP").WithLocation(18, 47), // (19,47): error CS1510: A ref or out argument must be an assignable variable // var z7 = new Func(ref new Func(x => x)); Diagnostic(ErrorCode.ERR_RefLvalueExpected, "new Func(x => x)").WithLocation(19, 47), // (20,47): error CS0206: A property or indexer may not be passed as an out or ref parameter // var z8 = new Func(ref Program.BarP); - Diagnostic(ErrorCode.ERR_RefProperty, "Program.BarP").WithArguments("Program.BarP").WithLocation(20, 47), + Diagnostic(ErrorCode.ERR_RefProperty, "Program.BarP").WithLocation(20, 47), // (21,47): error CS1510: A ref or out argument must be an assignable variable // var z9 = new Func(ref Program.Goo(x => x)); Diagnostic(ErrorCode.ERR_RefLvalueExpected, "Program.Goo(x => x)").WithLocation(21, 47), @@ -22987,7 +23022,7 @@ static void Test(Func Baz) Diagnostic(ErrorCode.ERR_MethodNameExpected, "Baz, ref Baz.Invoke").WithLocation(10, 46), // (11,42): error CS0206: A property or indexer may not be passed as an out or ref parameter // var d = new Func(ref BarP, BarP.Invoke); - Diagnostic(ErrorCode.ERR_RefProperty, "ref BarP").WithArguments("Program.BarP").WithLocation(11, 42), + Diagnostic(ErrorCode.ERR_RefProperty, "ref BarP").WithLocation(11, 42), // (11,46): error CS0149: Method name expected // var d = new Func(ref BarP, BarP.Invoke); Diagnostic(ErrorCode.ERR_MethodNameExpected, "BarP, BarP.Invoke").WithLocation(11, 46), @@ -22996,7 +23031,7 @@ static void Test(Func Baz) Diagnostic(ErrorCode.ERR_MethodNameExpected, "BarP, ref BarP.Invoke").WithLocation(12, 42), // (13,42): error CS0206: A property or indexer may not be passed as an out or ref parameter // var f = new Func(ref BarP, ref BarP.Invoke); - Diagnostic(ErrorCode.ERR_RefProperty, "ref BarP").WithArguments("Program.BarP").WithLocation(13, 42), + Diagnostic(ErrorCode.ERR_RefProperty, "ref BarP").WithLocation(13, 42), // (13,46): error CS0149: Method name expected // var f = new Func(ref BarP, ref BarP.Invoke); Diagnostic(ErrorCode.ERR_MethodNameExpected, "BarP, ref BarP.Invoke").WithLocation(13, 46) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs index 4e84a8101b1af..5e6168f6c8abb 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs @@ -708,7 +708,7 @@ public void Dispose() { } comp.VerifyDiagnostics( // (14,28): error CS8343: 'Program.S1': ref structs cannot implement interfaces // public ref struct S1 : IDisposable - Diagnostic(ErrorCode.ERR_RefStructInterfaceImpl, "IDisposable").WithArguments("Program.S1", "System.IDisposable").WithLocation(14, 28) + Diagnostic(ErrorCode.ERR_RefStructInterfaceImpl, "IDisposable").WithArguments("Program.S1").WithLocation(14, 28) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs index 0a597493a170f..853cac424e3ae 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/StructsTests.cs @@ -675,7 +675,7 @@ public void StructNonAutoPropertyInitializer() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "I").WithArguments("struct field initializers", "10.0").WithLocation(3, 16), // (3,16): error CS8050: Only auto-implemented properties can have initializers. // public int I { get { throw null; } set {} } = 9; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithArguments("S.I").WithLocation(3, 16)); + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(3, 16)); comp = CreateCompilation(text); comp.VerifyDiagnostics( @@ -684,7 +684,7 @@ public void StructNonAutoPropertyInitializer() Diagnostic(ErrorCode.ERR_StructHasInitializersAndNoDeclaredConstructor, "S").WithLocation(1, 8), // (3,16): error CS8050: Only auto-implemented properties can have initializers. // public int I { get { throw null; } set {} } = 9; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithArguments("S.I").WithLocation(3, 16)); + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(3, 16)); } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index ad82a923d0c55..ba82a22701db0 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -3418,7 +3418,7 @@ int M(int param) CreateCompilationWithMscorlib40AndSystemCore(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (8,50): error CS0211: Cannot take the address of the given expression // var z = from x in new int[2] select Goo(&x); - Diagnostic(ErrorCode.ERR_InvalidAddrOp, "x").WithArguments("x")); + Diagnostic(ErrorCode.ERR_InvalidAddrOp, "x")); } [WorkItem(22306, "https://github.com/dotnet/roslyn/issues/22306")] @@ -3612,7 +3612,7 @@ enum Color Diagnostic(ErrorCode.ERR_InvalidAddrOp, "local++").WithLocation(38, 15), // (39,14): error CS0211: Cannot take the address of the given expression // p = &this[0]; //CS0211 - Diagnostic(ErrorCode.ERR_InvalidAddrOp, "this[0]").WithArguments("C.this[int]").WithLocation(39, 14), + Diagnostic(ErrorCode.ERR_InvalidAddrOp, "this[0]").WithLocation(39, 14), // (40,15): error CS0211: Cannot take the address of the given expression // p = &(() => 1); //CS0211 Diagnostic(ErrorCode.ERR_InvalidAddrOp, "() => 1").WithLocation(40, 15), @@ -3624,7 +3624,7 @@ enum Color Diagnostic(ErrorCode.ERR_InvalidAddrOp, "new System.Int32()").WithLocation(42, 15), // (43,14): error CS0211: Cannot take the address of the given expression // p = &P; //CS0211 - Diagnostic(ErrorCode.ERR_InvalidAddrOp, "P").WithArguments("C.P").WithLocation(43, 14), + Diagnostic(ErrorCode.ERR_InvalidAddrOp, "P").WithLocation(43, 14), // (44,14): error CS0211: Cannot take the address of the given expression // p = &sizeof(int); //CS0211 Diagnostic(ErrorCode.ERR_InvalidAddrOp, "sizeof(int)").WithLocation(44, 14), @@ -3666,7 +3666,7 @@ enum Color Diagnostic(ErrorCode.ERR_InvalidAddrOp, "array ?? array").WithLocation(59, 19), // (60,19): error CS0211: Cannot take the address of the given expression // var aa = &this; //CS0208 - Diagnostic(ErrorCode.ERR_InvalidAddrOp, "this").WithArguments("this").WithLocation(60, 19), + Diagnostic(ErrorCode.ERR_InvalidAddrOp, "this").WithLocation(60, 19), // (61,19): error CS0211: Cannot take the address of the given expression // var bb = &typeof(int); //CS0208, CS0211 (managed) Diagnostic(ErrorCode.ERR_InvalidAddrOp, "typeof(int)").WithLocation(61, 19), @@ -7468,7 +7468,7 @@ class Program Diagnostic(ErrorCode.ERR_CloseParenExpected, "null"), // (4,21): error CS1003: Syntax error, ',' expected // int F1 = sizeof(null); - Diagnostic(ErrorCode.ERR_SyntaxError, "null").WithArguments(",", "null"), + Diagnostic(ErrorCode.ERR_SyntaxError, "null").WithArguments(","), // (4,14): error CS0233: '?' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf) // int F1 = sizeof(null); Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(").WithArguments("?")); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs index 11a295a5ac308..a683f5a7998a4 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/Utf8StringsLiteralsTests.cs @@ -129,15 +129,15 @@ .maxstack 2 comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (13,30): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (13,30): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static byte[] Test1() => "hello"; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""hello""").WithArguments("Utf8 String Literals").WithLocation(13, 30), - // (14,34): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""hello""").WithArguments("UTF-8 string literals").WithLocation(13, 30), + // (14,34): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static Span Test2() => "dog"; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""dog""").WithArguments("Utf8 String Literals").WithLocation(14, 34), - // (15,42): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""dog""").WithArguments("UTF-8 string literals").WithLocation(14, 34), + // (15,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => "cat"; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""cat""").WithArguments("Utf8 String Literals").WithLocation(15, 42) + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""cat""").WithArguments("UTF-8 string literals").WithLocation(15, 42) ); } @@ -226,28 +226,28 @@ .maxstack 2 Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" hello """"""").WithArguments("raw string literals").WithLocation(13, 30), - // (13,30): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (13,30): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static byte[] Test1() => "hello"; Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" hello - """"""").WithArguments("Utf8 String Literals").WithLocation(13, 30), + """"""").WithArguments("UTF-8 string literals").WithLocation(13, 30), // (16,34): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static Span Test2() => """dog"""; Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""dog""""""").WithArguments("raw string literals").WithLocation(16, 34), - // (16,34): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (16,34): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static Span Test2() => "dog"; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""dog""""""").WithArguments("Utf8 String Literals").WithLocation(16, 34), + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""dog""""""").WithArguments("UTF-8 string literals").WithLocation(16, 34), // (17,42): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => """ Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" cat """"""").WithArguments("raw string literals").WithLocation(17, 42), - // (17,42): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (17,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => "cat"; Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" cat -""""""").WithArguments("Utf8 String Literals").WithLocation(17, 42) +""""""").WithArguments("UTF-8 string literals").WithLocation(17, 42) ); } @@ -283,12 +283,12 @@ static void Main() comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (7,49): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (7,49): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // (byte[] b, (byte[] d, string e) c) a = ("hello", ("dog", "cat")); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""hello""").WithArguments("Utf8 String Literals").WithLocation(7, 49), - // (7,59): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""hello""").WithArguments("UTF-8 string literals").WithLocation(7, 49), + // (7,59): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // (byte[] b, (byte[] d, string e) c) a = ("hello", ("dog", "cat")); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""dog""").WithArguments("Utf8 String Literals").WithLocation(7, 59) + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""dog""").WithArguments("UTF-8 string literals").WithLocation(7, 59) ); } @@ -324,12 +324,12 @@ static void Main() comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (7,45): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (7,45): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // (byte[] a, (byte[] b, string c)) = ("hello", ("dog", "cat")); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""hello""").WithArguments("Utf8 String Literals").WithLocation(7, 45), - // (7,55): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""hello""").WithArguments("UTF-8 string literals").WithLocation(7, 45), + // (7,55): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // (byte[] a, (byte[] b, string c)) = ("hello", ("dog", "cat")); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""dog""").WithArguments("Utf8 String Literals").WithLocation(7, 55) + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""dog""").WithArguments("UTF-8 string literals").WithLocation(7, 55) ); } @@ -371,15 +371,15 @@ static void Main() comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (7,21): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (7,21): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // var array = (byte[])"hello"; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"(byte[])""hello""").WithArguments("Utf8 String Literals").WithLocation(7, 21), - // (8,20): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"(byte[])""hello""").WithArguments("UTF-8 string literals").WithLocation(7, 21), + // (8,20): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // var span = (Span)"dog"; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"(Span)""dog""").WithArguments("Utf8 String Literals").WithLocation(8, 20), - // (9,28): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"(Span)""dog""").WithArguments("UTF-8 string literals").WithLocation(8, 20), + // (9,28): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // var readonlySpan = (ReadOnlySpan)"cat"; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"(ReadOnlySpan)""cat""").WithArguments("Utf8 String Literals").WithLocation(9, 28) + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"(ReadOnlySpan)""cat""").WithArguments("UTF-8 string literals").WithLocation(9, 28) ); } @@ -415,12 +415,12 @@ static void Main() comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (7,54): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (7,54): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // var a = ((byte[] b, (byte[] d, string e) c))("hello", ("dog", "cat")); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""hello""").WithArguments("Utf8 String Literals").WithLocation(7, 54), - // (7,64): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""hello""").WithArguments("UTF-8 string literals").WithLocation(7, 54), + // (7,64): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // var a = ((byte[] b, (byte[] d, string e) c))("hello", ("dog", "cat")); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""dog""").WithArguments("Utf8 String Literals").WithLocation(7, 64) + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""dog""").WithArguments("UTF-8 string literals").WithLocation(7, 64) ); } @@ -706,15 +706,15 @@ .locals init (System.ReadOnlySpan V_0) comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (15,30): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (15,30): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static byte[] Test1() => nullValue; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "nullValue").WithArguments("Utf8 String Literals").WithLocation(15, 30), - // (16,34): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, "nullValue").WithArguments("UTF-8 string literals").WithLocation(15, 30), + // (16,34): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static Span Test2() => nullValue; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "nullValue").WithArguments("Utf8 String Literals").WithLocation(16, 34), - // (17,42): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, "nullValue").WithArguments("UTF-8 string literals").WithLocation(16, 34), + // (17,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => nullValue; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "nullValue").WithArguments("Utf8 String Literals").WithLocation(17, 42) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "nullValue").WithArguments("UTF-8 string literals").WithLocation(17, 42) ); } @@ -757,15 +757,15 @@ static void Main() comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (8,21): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (8,21): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // var array = (byte[])nullValue; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "(byte[])nullValue").WithArguments("Utf8 String Literals").WithLocation(8, 21), - // (9,20): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, "(byte[])nullValue").WithArguments("UTF-8 string literals").WithLocation(8, 21), + // (9,20): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // var span = (Span)nullValue; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "(Span)nullValue").WithArguments("Utf8 String Literals").WithLocation(9, 20), - // (10,28): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, "(Span)nullValue").WithArguments("UTF-8 string literals").WithLocation(9, 20), + // (10,28): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // var readOnlySpan = (ReadOnlySpan)nullValue; - Diagnostic(ErrorCode.ERR_FeatureInPreview, "(ReadOnlySpan)nullValue").WithArguments("Utf8 String Literals").WithLocation(10, 28) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "(ReadOnlySpan)nullValue").WithArguments("UTF-8 string literals").WithLocation(10, 28) ); } @@ -2205,9 +2205,9 @@ static void Main() comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (7,39): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (7,39): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // System.Console.WriteLine(Test("s", (int)1)); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""s""").WithArguments("Utf8 String Literals").WithLocation(7, 39) + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""s""").WithArguments("UTF-8 string literals").WithLocation(7, 39) ); } @@ -2357,9 +2357,9 @@ static class E comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (9,31): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (9,31): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Console.WriteLine(p.M("")); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""").WithArguments("Utf8 String Literals").WithLocation(9, 31) + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""").WithArguments("UTF-8 string literals").WithLocation(9, 31) ); } @@ -2539,15 +2539,15 @@ .maxstack 2 comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (13,30): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (13,30): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static byte[] Test1() => "hello"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""hello""" + suffix).WithArguments("Utf8 String Literals").WithLocation(13, 30), - // (14,34): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""hello""" + suffix).WithArguments("UTF-8 string literals").WithLocation(13, 30), + // (14,34): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static Span Test2() => "dog"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""dog""" + suffix).WithArguments("Utf8 String Literals").WithLocation(14, 34), - // (15,42): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""dog""" + suffix).WithArguments("UTF-8 string literals").WithLocation(14, 34), + // (15,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => "cat"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""cat""" + suffix).WithArguments("Utf8 String Literals").WithLocation(15, 42) + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""cat""" + suffix).WithArguments("UTF-8 string literals").WithLocation(15, 42) ); } @@ -2629,15 +2629,15 @@ .maxstack 2 comp = CreateCompilation(source + HelpersSource, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (13,30): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (13,30): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static byte[] Test1() => "hello"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"@""hello""" + suffix).WithArguments("Utf8 String Literals").WithLocation(13, 30), - // (14,34): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"@""hello""" + suffix).WithArguments("UTF-8 string literals").WithLocation(13, 30), + // (14,34): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static Span Test2() => "dog"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"@""dog""" + suffix).WithArguments("Utf8 String Literals").WithLocation(14, 34), - // (15,42): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"@""dog""" + suffix).WithArguments("UTF-8 string literals").WithLocation(14, 34), + // (15,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => "cat"u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"@""cat""" + suffix).WithArguments("Utf8 String Literals").WithLocation(15, 42) + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"@""cat""" + suffix).WithArguments("UTF-8 string literals").WithLocation(15, 42) ); } @@ -2722,21 +2722,21 @@ .maxstack 2 // (13,30): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static byte[] Test1() => """hello"""u8; Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""hello""""""" + suffix).WithArguments("raw string literals").WithLocation(13, 30), - // (13,30): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (13,30): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static byte[] Test1() => """hello"""u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""hello""""""" + suffix).WithArguments("Utf8 String Literals").WithLocation(13, 30), + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""hello""""""" + suffix).WithArguments("UTF-8 string literals").WithLocation(13, 30), // (14,34): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static Span Test2() => """dog"""u8; Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""dog""""""" + suffix).WithArguments("raw string literals").WithLocation(14, 34), - // (14,34): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (14,34): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static Span Test2() => """dog"""u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""dog""""""" + suffix).WithArguments("Utf8 String Literals").WithLocation(14, 34), + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""dog""""""" + suffix).WithArguments("UTF-8 string literals").WithLocation(14, 34), // (15,42): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => """cat"""u8; Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""cat""""""" + suffix).WithArguments("raw string literals").WithLocation(15, 42), - // (15,42): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (15,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => """cat"""u8; - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""cat""""""" + suffix).WithArguments("Utf8 String Literals").WithLocation(15, 42) + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""""""cat""""""" + suffix).WithArguments("UTF-8 string literals").WithLocation(15, 42) ); } @@ -2829,31 +2829,31 @@ .maxstack 2 Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" hello """"""" + suffix).WithArguments("raw string literals").WithLocation(13, 30), - // (13,30): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (13,30): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static byte[] Test1() => """ Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" hello - """"""" + suffix).WithArguments("Utf8 String Literals").WithLocation(13, 30), + """"""" + suffix).WithArguments("UTF-8 string literals").WithLocation(13, 30), // (16,34): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static Span Test2() => """ Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" dog """"""" + suffix).WithArguments("raw string literals").WithLocation(16, 34), - // (16,34): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (16,34): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static Span Test2() => """ Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" dog - """"""" + suffix).WithArguments("Utf8 String Literals").WithLocation(16, 34), + """"""" + suffix).WithArguments("UTF-8 string literals").WithLocation(16, 34), // (19,42): error CS8652: The feature 'raw string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => """ Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" cat """"""" + suffix).WithArguments("raw string literals").WithLocation(19, 42), - // (19,42): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (19,42): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // static ReadOnlySpan Test3() => """ Diagnostic(ErrorCode.ERR_FeatureInPreview, @""""""" cat - """"""" + suffix).WithArguments("Utf8 String Literals").WithLocation(19, 42) + """"""" + suffix).WithArguments("UTF-8 string literals").WithLocation(19, 42) ); } @@ -3406,9 +3406,9 @@ static void Main() comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (6,40): error CS8652: The feature 'Utf8 String Literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (6,40): error CS8652: The feature 'UTF-8 string literals' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // System.Console.WriteLine(Test(("s", 1))); - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""s""").WithArguments("Utf8 String Literals").WithLocation(6, 40) + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"""s""").WithArguments("UTF-8 string literals").WithLocation(6, 40) ); } diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs index c826fb8a5df59..5d5703fd21496 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs @@ -2907,5 +2907,156 @@ public void Incremental_Generators_Can_Recover_From_Exceptions() Assert.Single(result.GeneratedTrees); } + + [Fact] + public void Timing_Info_Is_Empty_If_Not_Run() + { + var source = "class C{}"; + + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + compilation.VerifyDiagnostics(); + + var generator = new PipelineCallbackGenerator(ctx => + { + ctx.RegisterSourceOutput(ctx.CompilationProvider, (context, text) => + { + context.AddSource("generated", ""); + }); + }).AsSourceGenerator(); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + + var timing = driver.GetTimingInfo(); + + Assert.Equal(TimeSpan.Zero, timing.ElapsedTime); + + var generatorTiming = Assert.Single(timing.GeneratorTimes); + Assert.Equal(generator, generatorTiming.Generator); + Assert.Equal(TimeSpan.Zero, generatorTiming.ElapsedTime); + } + + [Fact] + public void Can_Get_Timing_Info() + { + var source = "class C{}"; + + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + compilation.VerifyDiagnostics(); + + var generator = new PipelineCallbackGenerator(ctx => + { + ctx.RegisterSourceOutput(ctx.CompilationProvider, (context, text) => + { + context.AddSource("generated", ""); + Thread.Sleep(1); + }); + }).AsSourceGenerator(); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + + driver = driver.RunGenerators(compilation); + var timing = driver.GetTimingInfo(); + + Assert.NotEqual(TimeSpan.Zero, timing.ElapsedTime); + + var generatorTiming = Assert.Single(timing.GeneratorTimes); + Assert.Equal(generator, generatorTiming.Generator); + Assert.NotEqual(TimeSpan.Zero, generatorTiming.ElapsedTime); + Assert.True(timing.ElapsedTime >= generatorTiming.ElapsedTime); + } + + [Fact] + public void Can_Get_Timing_Info_From_Multiple_Generators() + { + var source = "class C{}"; + + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + compilation.VerifyDiagnostics(); + + var generator = new PipelineCallbackGenerator(ctx => + { + ctx.RegisterSourceOutput(ctx.CompilationProvider, (context, text) => + { + context.AddSource("generated", ""); + Thread.Sleep(1); + }); + }).AsSourceGenerator(); + + var generator2 = new PipelineCallbackGenerator2(ctx => + { + ctx.RegisterSourceOutput(ctx.CompilationProvider, (context, text) => + { + context.AddSource("generated", ""); + Thread.Sleep(1); + }); + }).AsSourceGenerator(); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator, generator2 }, parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + + driver = driver.RunGenerators(compilation); + var timing = driver.GetTimingInfo(); + + Assert.NotEqual(TimeSpan.Zero, timing.ElapsedTime); + Assert.Equal(2, timing.GeneratorTimes.Length); + + var timing1 = timing.GeneratorTimes[0]; + Assert.Equal(generator, timing1.Generator); + Assert.NotEqual(TimeSpan.Zero, timing1.ElapsedTime); + Assert.True(timing.ElapsedTime >= timing1.ElapsedTime); + + var timing2 = timing.GeneratorTimes[1]; + Assert.Equal(generator2, timing2.Generator); + Assert.NotEqual(TimeSpan.Zero, timing2.ElapsedTime); + Assert.True(timing.ElapsedTime >= timing2.ElapsedTime); + + Assert.True(timing.ElapsedTime >= timing1.ElapsedTime + timing2.ElapsedTime); + } + + [Fact] + public void Timing_Info_Only_Includes_Last_Run() + { + var source = "class C{}"; + + var parseOptions = TestOptions.RegularPreview; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions); + compilation.VerifyDiagnostics(); + + var generator = new PipelineCallbackGenerator(ctx => + { + ctx.RegisterSourceOutput(ctx.CompilationProvider, (context, text) => + { + Thread.Sleep(50); + context.AddSource("generated", ""); + }); + }).AsSourceGenerator(); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { generator }, parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); + + // run once + driver = driver.RunGenerators(compilation); + var timing = driver.GetTimingInfo(); + + Assert.NotEqual(TimeSpan.Zero, timing.ElapsedTime); + + var generatorTiming = Assert.Single(timing.GeneratorTimes); + Assert.Equal(generator, generatorTiming.Generator); + Assert.NotEqual(TimeSpan.Zero, generatorTiming.ElapsedTime); + Assert.True(timing.ElapsedTime >= generatorTiming.ElapsedTime); + + // run a second time. No steps should be performed, so overall time should be less + driver = driver.RunGenerators(compilation); + var timing2 = driver.GetTimingInfo(); + + Assert.NotEqual(TimeSpan.Zero, timing2.ElapsedTime); + Assert.True(timing.ElapsedTime > timing2.ElapsedTime); + + var generatorTiming2 = Assert.Single(timing2.GeneratorTimes); + Assert.Equal(generator, generatorTiming2.Generator); + Assert.NotEqual(TimeSpan.Zero, generatorTiming2.ElapsedTime); + Assert.True(generatorTiming.ElapsedTime > generatorTiming2.ElapsedTime); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/SyntaxAwareGeneratorTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/SyntaxAwareGeneratorTests.cs index 0fd4decbb606f..d456d7c5f2068 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/SyntaxAwareGeneratorTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/SyntaxAwareGeneratorTests.cs @@ -2077,6 +2077,64 @@ void Function() Assert.Equal("Simulated cancellation from external source", results.Results[0].Exception!.Message); } + [Fact] + public void Syntax_Provider_Doesnt_Attribute_Incorrect_Timing() + { + var source = @" +class C +{ + int Property { get; set; } + + void Function() + { + var x = 5; + x += 4; + } +} +"; + Compilation compilation = CreateCompilation(source, options: TestOptions.DebugDll); + compilation.VerifyDiagnostics(); + + Assert.Single(compilation.SyntaxTrees); + + var sleepTimeInMs = 50; + var testGenerator = new PipelineCallbackGenerator(ctx => + { + ctx.RegisterSourceOutput(ctx.SyntaxProvider.CreateSyntaxProvider((s, _) => s is AssignmentExpressionSyntax, (c, _) => { Thread.Sleep(sleepTimeInMs); return true; }), (spc, s) => { }); + }).AsSourceGenerator(); + + var testGenerator2 = new PipelineCallbackGenerator2(ctx => + { + ctx.RegisterSourceOutput(ctx.SyntaxProvider.CreateSyntaxProvider((s, _) => s is AssignmentExpressionSyntax, (c, _) => { Thread.Sleep(sleepTimeInMs); return true; }), (spc, s) => { }); + ctx.RegisterSourceOutput(ctx.SyntaxProvider.CreateSyntaxProvider((s, _) => s is AssignmentExpressionSyntax, (c, _) => { Thread.Sleep(sleepTimeInMs); return true; }), (spc, s) => { }); + }).AsSourceGenerator(); + + GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { testGenerator, testGenerator2 }); + driver = driver.RunGenerators(compilation); + + var timing = driver.GetTimingInfo(); + + Assert.NotEqual(TimeSpan.Zero, timing.ElapsedTime); + Assert.Equal(2, timing.GeneratorTimes.Length); + + // check generator one took at least 'sleepTimeInMs' + var timing1 = timing.GeneratorTimes[0]; + Assert.Equal(testGenerator, timing1.Generator); + Assert.NotEqual(TimeSpan.Zero, timing1.ElapsedTime); + Assert.True(timing.ElapsedTime >= timing1.ElapsedTime); + Assert.True(timing1.ElapsedTime.TotalMilliseconds >= sleepTimeInMs); + + // check generator two took at least 'sleepTimeInMs' * 2 + var timing2 = timing.GeneratorTimes[1]; + Assert.Equal(testGenerator2, timing2.Generator); + Assert.NotEqual(TimeSpan.Zero, timing2.ElapsedTime); + Assert.True(timing.ElapsedTime >= timing2.ElapsedTime); + Assert.True(timing2.ElapsedTime.TotalMilliseconds >= sleepTimeInMs * 2); + + // now check that generator two took longer than generator one (and one didn't get attributed the time) + Assert.True(timing2.ElapsedTime > timing1.ElapsedTime); + } + private class TestReceiverBase { private readonly Action? _callback; diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/GetImportScopesTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/GetImportScopesTests.cs new file mode 100644 index 0000000000000..19c69bcc3efc9 --- /dev/null +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/GetImportScopesTests.cs @@ -0,0 +1,698 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public class GetImportScopesTests : SemanticModelTestBase +{ + private ImmutableArray GetImportsScopes(string text) + { + var tree = Parse(text); + var comp = CreateCompilation(tree); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + return scopes; + } + + [Fact] + public void TestEmptyFile() + { + var text = @"/*pos*/"; + var scopes = GetImportsScopes(text); + Assert.Empty(scopes); + } + + [Fact] + public void TestNoImportsBeforeMemberDeclaration() + { + var text = @"/*pos*/ +class C {}"; + var scopes = GetImportsScopes(text); + Assert.Empty(scopes); + } + + #region normal imports + + [Fact] + public void TestBeforeImports() + { + var text = @"/*pos*/ +using System;"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Single(scopes.Single().Imports); + Assert.True(scopes.Single().Imports.Single().NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) }); + Assert.True(scopes.Single().Imports.Single().DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax); + Assert.Empty(scopes.Single().Aliases); + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterImportsNoContent() + { + var text = @" +using System; +/*pos*/"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Single(scopes.Single().Imports); + Assert.True(scopes.Single().Imports.Single().NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) }); + Assert.True(scopes.Single().Imports.Single().DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax); + Assert.Empty(scopes.Single().Aliases); + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterImportsBeforeMemberDeclaration() + { + var text = @" +using System; +/*pos*/ +class C +{ +}"; + var scopes = GetImportsScopes(text); + Assert.Empty(scopes); + } + + [Fact] + public void TestBeforeImportsTopLevelStatements() + { + var text = @" +/*pos*/ +using System; + +return;"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Single(scopes.Single().Imports); + Assert.True(scopes.Single().Imports.Single().NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) }); + Assert.True(scopes.Single().Imports.Single().DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax); + Assert.Empty(scopes.Single().Aliases); + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterImportsTopLevelStatements1() + { + var text = @" +using System; +/*pos*/ +return;"; + var scopes = GetImportsScopes(text); + Assert.Empty(scopes); + } + + [Fact] + public void TestAfterImportsTopLevelStatements2() + { + var text = @" +using System; + +return /*pos*/;"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Single(scopes.Single().Imports); + Assert.True(scopes.Single().Imports.Single().NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) }); + Assert.True(scopes.Single().Imports.Single().DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax); + Assert.Empty(scopes.Single().Aliases); + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterMultipleImportsNoContent() + { + var text = @" +using System; +using Microsoft; +/*pos*/"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Equal(2, scopes.Single().Imports.Length); + Assert.True(scopes.Single().Imports.Any(i => i.NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) })); + Assert.True(scopes.Single().Imports.Any(i => i.NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(Microsoft) })); + Assert.True(scopes.Single().Imports.Any(i => i.DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(System) } })); + Assert.True(scopes.Single().Imports.Any(i => i.DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(Microsoft) } })); + Assert.Empty(scopes.Single().Aliases); + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestNestedNamespaceOuterPosition() + { + var text = @" +using System; + +class C +{ + /*pos*/ +} + +namespace N +{ + using Microsoft; +} +"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Single(scopes.Single().Imports); + Assert.True(scopes.Single().Imports.Single().NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) }); + Assert.True(scopes.Single().Imports.Single().DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(System) } }); + } + + [Fact] + public void TestNestedNamespaceInnerPosition() + { + var text = @" +using System; + +namespace N +{ + using Microsoft; + class C + { + /*pos*/ + } +} +"; + var scopes = GetImportsScopes(text); + Assert.Equal(2, scopes.Length); + Assert.Single(scopes[0].Imports); + Assert.Single(scopes[1].Imports); + Assert.True(scopes[0].Imports.Single().NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(Microsoft) }); + Assert.True(scopes[0].Imports.Single().DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(Microsoft) } }); + Assert.True(scopes[1].Imports.Single().NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) }); + Assert.True(scopes[1].Imports.Single().DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(System) } }); + } + + [Fact] + public void TestNestedNamespaceInnerPositionIntermediaryEmptyNamespace() + { + var text = @" +using System; + +namespace Outer +{ + namespace N + { + using Microsoft; + class C + { + /*pos*/ + } + } +} +"; + var scopes = GetImportsScopes(text); + Assert.Equal(2, scopes.Length); + Assert.Single(scopes[0].Imports); + Assert.Single(scopes[1].Imports); + Assert.True(scopes[0].Imports.Single().NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(Microsoft) }); + Assert.True(scopes[0].Imports.Single().DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(Microsoft) } }); + Assert.True(scopes[1].Imports.Single().NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) }); + Assert.True(scopes[1].Imports.Single().DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(System) } }); + } + + #endregion + + #region aliases + + [Fact] + public void TestBeforeAlias() + { + var text = @"/*pos*/ +using S = System;"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Single(scopes.Single().Aliases); + Assert.True(scopes.Single().Aliases.Single() is { Name: "S", Target: INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) } }); + Assert.True(scopes.Single().Aliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax); + Assert.Empty(scopes.Single().Imports); + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterAliasNoContent() + { + var text = @" +using S = System; +/*pos*/"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Single(scopes.Single().Aliases); + Assert.True(scopes.Single().Aliases.Single() is { Name: "S", Target: { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) } }); + Assert.True(scopes.Single().Aliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax); + Assert.Empty(scopes.Single().Imports); + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterAliasBeforeMemberDeclaration() + { + var text = @" +using S = System; +/*pos*/ +class C +{ +}"; + var scopes = GetImportsScopes(text); + Assert.Empty(scopes); + } + + [Fact] + public void TestBeforeAliasTopLevelStatements() + { + var text = @" +/*pos*/ +using S = System; + +return;"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Single(scopes.Single().Aliases); + Assert.True(scopes.Single().Aliases.Single() is { Name: "S", Target: INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) } }); + Assert.True(scopes.Single().Aliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax); + Assert.Empty(scopes.Single().Imports); + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterAliasTopLevelStatements1() + { + var text = @" +using S = System; +/*pos*/ +return;"; + var scopes = GetImportsScopes(text); + Assert.Empty(scopes); + } + + [Fact] + public void TestAfterAliasTopLevelStatements2() + { + var text = @" +using S = System; + +return /*pos*/;"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Single(scopes.Single().Aliases); + Assert.True(scopes.Single().Aliases.Single() is { Name: "S", Target: { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) } }); + Assert.True(scopes.Single().Aliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax); + Assert.Empty(scopes.Single().Imports); + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterMultipleAliasesNoContent() + { + var text = @" +using S = System; +using M = Microsoft; +/*pos*/"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Equal(2, scopes.Single().Aliases.Length); + Assert.True(scopes.Single().Aliases.Any(a => a is { Name: "S", Target: INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) } })); + Assert.True(scopes.Single().Aliases.Any(a => a is { Name: "M", Target: INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(Microsoft) } })); + Assert.True(scopes.Single().Aliases.Any(a => a.DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(System) } })); + Assert.True(scopes.Single().Aliases.Any(a => a.DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(Microsoft) } })); + Assert.Empty(scopes.Single().Imports); + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAliasNestedNamespaceOuterPosition() + { + var text = @" +using S = System; + +class C +{ + /*pos*/ +} + +namespace N +{ + using M = Microsoft; +} +"; + var scopes = GetImportsScopes(text); + Assert.Single(scopes); + Assert.Single(scopes.Single().Aliases); + Assert.True(scopes.Single().Aliases.Single() is { Name: "S", Target: INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) } }); + Assert.True(scopes.Single().Aliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(System) } }); + } + + [Fact] + public void TestAliasNestedNamespaceInnerPosition() + { + var text = @" +using S = System; + +namespace N +{ + using M = Microsoft; + class C + { + /*pos*/ + } +} +"; + var scopes = GetImportsScopes(text); + Assert.Equal(2, scopes.Length); + Assert.Single(scopes[0].Aliases); + Assert.Single(scopes[1].Aliases); + Assert.True(scopes[0].Aliases.Single() is { Name: "M", Target: INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(Microsoft) } }); + Assert.True(scopes[0].Aliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(Microsoft) } }); + Assert.True(scopes[1].Aliases.Single() is { Name: "S", Target: INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) } }); + Assert.True(scopes[1].Aliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(System) } }); + } + + #endregion + + #region extern aliases + + private static CSharpCompilation CreateCompilationWithExternAlias(CSharpTestSource source, params string[] aliases) + { + if (aliases.Length == 0) + aliases = new[] { "CORE" }; + + var comp = CreateCompilation(source); + var reference = comp.References.First(r => r.Display!.StartsWith("System.Core")); + return comp.ReplaceReference(reference, reference.WithAliases(ImmutableArray.CreateRange(aliases))); + } + + [Fact] + public void TestBeforeExternAlias() + { + var text = @"/*pos*/ +extern alias CORE;"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(tree); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + Assert.Single(scopes); + Assert.Single(scopes.Single().ExternAliases); + Assert.True(scopes.Single().ExternAliases.Single() is { Name: "CORE" }); + Assert.True(scopes.Single().ExternAliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is ExternAliasDirectiveSyntax); + Assert.Empty(scopes.Single().Imports); + Assert.Empty(scopes.Single().Aliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterExternAliasNoContent() + { + var text = @" +extern alias CORE; +/*pos*/"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(tree); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + Assert.Single(scopes); + Assert.Single(scopes.Single().ExternAliases); + Assert.True(scopes.Single().ExternAliases.Single() is { Name: "CORE", Target: INamespaceSymbol { IsGlobalNamespace: true } }); + Assert.True(scopes.Single().ExternAliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is ExternAliasDirectiveSyntax); + Assert.Empty(scopes.Single().Imports); + Assert.Empty(scopes.Single().Aliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterExternAliasBeforeMemberDeclaration() + { + var text = @" +extern alias CORE; +/*pos*/ +class C +{ +}"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(tree); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + Assert.Single(scopes); + Assert.Single(scopes.Single().ExternAliases); + Assert.True(scopes.Single().ExternAliases.Single() is { Name: "CORE", Target: INamespaceSymbol { IsGlobalNamespace: true } }); + Assert.True(scopes.Single().ExternAliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is ExternAliasDirectiveSyntax); + Assert.Empty(scopes.Single().Imports); + Assert.Empty(scopes.Single().Aliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestBeforeExternAliasTopLevelStatements() + { + var text = @" +/*pos*/ +extern alias CORE; + +return;"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(tree); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + Assert.Single(scopes); + Assert.Single(scopes.Single().ExternAliases); + Assert.True(scopes.Single().ExternAliases.Single() is { Name: "CORE", Target: INamespaceSymbol { IsGlobalNamespace: true } }); + Assert.True(scopes.Single().ExternAliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is ExternAliasDirectiveSyntax); + Assert.Empty(scopes.Single().Imports); + Assert.Empty(scopes.Single().Aliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterExternAliasTopLevelStatements1() + { + var text = @" +extern alias CORE; +/*pos*/ +return;"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(tree); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + Assert.Single(scopes.Single().ExternAliases); + Assert.True(scopes.Single().ExternAliases.Single() is { Name: "CORE", Target: INamespaceSymbol { IsGlobalNamespace: true } }); + Assert.True(scopes.Single().ExternAliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is ExternAliasDirectiveSyntax); + } + + [Fact] + public void TestAfterExternAliasTopLevelStatements2() + { + var text = @" +extern alias CORE; + +return /*pos*/;"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(tree); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + Assert.Single(scopes); + Assert.Single(scopes.Single().ExternAliases); + Assert.True(scopes.Single().ExternAliases.Single() is { Name: "CORE", Target: INamespaceSymbol { IsGlobalNamespace: true } }); + Assert.True(scopes.Single().ExternAliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is ExternAliasDirectiveSyntax); + Assert.Empty(scopes.Single().Imports); + Assert.Empty(scopes.Single().Aliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestAfterMultipleExternAliasesNoContent() + { + var text = @" +extern alias CORE1; +extern alias CORE2; +/*pos*/"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(tree, "CORE1", "CORE2"); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + Assert.Single(scopes); + Assert.Equal(2, scopes.Single().ExternAliases.Length); + Assert.True(scopes.Single().ExternAliases.Any(a => a is { Name: "CORE1", Target: INamespaceSymbol { IsGlobalNamespace: true } })); + Assert.True(scopes.Single().ExternAliases.Any(a => a is { Name: "CORE2", Target: INamespaceSymbol { IsGlobalNamespace: true } })); + Assert.True(scopes.Single().ExternAliases.Any(a => a.DeclaringSyntaxReferences.Single().GetSyntax() is ExternAliasDirectiveSyntax { Identifier.Text: "CORE1" })); + Assert.True(scopes.Single().ExternAliases.Any(a => a.DeclaringSyntaxReferences.Single().GetSyntax() is ExternAliasDirectiveSyntax { Identifier.Text: "CORE2" })); + Assert.Empty(scopes.Single().Imports); + Assert.Empty(scopes.Single().Aliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestExternAliasNestedNamespaceOuterPosition() + { + var text = @" +extern alias CORE1; + +class C +{ + /*pos*/ +} + +namespace N +{ + extern alias CORE2; +} +"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(tree, "CORE1", "CORE2"); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + Assert.Single(scopes); + Assert.Single(scopes.Single().ExternAliases); + Assert.True(scopes.Single().ExternAliases.Single() is { Name: "CORE1", Target: INamespaceSymbol { IsGlobalNamespace: true } }); + Assert.True(scopes.Single().ExternAliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is ExternAliasDirectiveSyntax { Identifier.Text: "CORE1" }); + } + + [Fact] + public void TestExternAliasNestedNamespaceInnerPosition() + { + var text = @" +extern alias CORE1; + +namespace N +{ + extern alias CORE2; + class C + { + /*pos*/ + } +} +"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(tree, "CORE1", "CORE2"); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + Assert.Equal(2, scopes.Length); + Assert.Single(scopes[0].ExternAliases); + Assert.Single(scopes[1].ExternAliases); + Assert.True(scopes[0].ExternAliases.Single() is { Name: "CORE2", Target: INamespaceSymbol { IsGlobalNamespace: true } }); + Assert.True(scopes[0].ExternAliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is ExternAliasDirectiveSyntax { Identifier.Text: "CORE2" }); + Assert.True(scopes[1].ExternAliases.Single() is { Name: "CORE1", Target: INamespaceSymbol { IsGlobalNamespace: true } }); + Assert.True(scopes[1].ExternAliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is ExternAliasDirectiveSyntax { Identifier.Text: "CORE1" }); + } + + #endregion + + #region global imports + + [Fact] + public void TestEmptyFile_WithGlobalImports() + { + var globalImportsText = @" +extern alias CORE; +global using System; +global using M = Microsoft;"; + var text = @" +/*pos*/"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(new[] { tree, Parse(globalImportsText) }); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + Assert.Single(scopes); + Assert.Single(scopes.Single().Aliases); + Assert.Single(scopes.Single().Imports); + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + + Assert.True(scopes.Single().Aliases.Single() is { Name: "M", Target: INamespaceSymbol { Name: nameof(Microsoft) } }); + Assert.True(scopes.Single().Aliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax { Alias.Name.Identifier.Text: "M" }); + + Assert.True(scopes.Single().Imports.Single().NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) }); + Assert.True(scopes.Single().Imports.Single().DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(System) } }); + } + + [Fact] + public void TestInsideDeclaration_WithGlobalImports() + { + var globalImportsText = @" +extern alias CORE; +global using System; +global using M = Microsoft"; + var text = @" +class C +{ + /*pos*/ +}"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(new[] { tree, Parse(globalImportsText) }); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + Assert.Single(scopes); + + Assert.Single(scopes.Single().Imports); + Assert.True(scopes.Single().Imports.Single().NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) }); + Assert.True(scopes.Single().Imports.Single().DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax); + + Assert.Single(scopes.Single().Aliases); + Assert.True(scopes.Single().Aliases.Single() is { Name: "M", Target: INamespaceSymbol { Name: nameof(Microsoft) } }); + Assert.True(scopes.Single().Aliases.Single().DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax { Alias.Name.Identifier.Text: "M" }); + + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + [Fact] + public void TestGlobalImportsAndFileImports() + { + var globalImportsText = @" +extern alias CORE; +global using System; +global using M = Microsoft"; + var text = @" +using System.IO; +using T = System.Threading; + +class C +{ + /*pos*/ +}"; + var tree = Parse(text); + var comp = CreateCompilationWithExternAlias(new[] { tree, Parse(globalImportsText) }); + var model = comp.GetSemanticModel(tree); + var scopes = model.GetImportScopes(GetPositionForBinding(text)); + + Assert.Single(scopes); + + Assert.Equal(2, scopes.Single().Imports.Length); + Assert.True(scopes.Single().Imports.Any(i => i.NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(System) })); + Assert.True(scopes.Single().Imports.Any(i => i.DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(System) } })); + Assert.True(scopes.Single().Imports.Any(i => i.NamespaceOrType is INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: false, Name: nameof(System.IO) })); + Assert.True(scopes.Single().Imports.Any(i => i.DeclaringSyntaxReference!.GetSyntax() is UsingDirectiveSyntax { Name: QualifiedNameSyntax { Right: IdentifierNameSyntax { Identifier.Text: nameof(System.IO) } } })); + + Assert.Equal(2, scopes.Single().Aliases.Length); + Assert.True(scopes.Single().Aliases.Any(i => i is { Name: "M", Target: INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: true, Name: nameof(Microsoft) } })); + Assert.True(scopes.Single().Aliases.Any(i => i.DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax { Name: IdentifierNameSyntax { Identifier.Text: nameof(Microsoft) } })); + Assert.True(scopes.Single().Aliases.Any(i => i is { Name: "T", Target: INamespaceSymbol { ContainingNamespace.IsGlobalNamespace: false, Name: nameof(System.Threading) } })); + Assert.True(scopes.Single().Aliases.Any(i => i.DeclaringSyntaxReferences.Single().GetSyntax() is UsingDirectiveSyntax { Name: QualifiedNameSyntax { Right: IdentifierNameSyntax { Identifier.Text: nameof(System.Threading) } } })); + + Assert.Empty(scopes.Single().ExternAliases); + Assert.Empty(scopes.Single().XmlNamespaces); + } + + #endregion +} diff --git a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs index 86d5cf053e13e..88e374b2888b5 100644 --- a/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Compilation/SemanticModelGetSemanticInfoTests.cs @@ -8985,7 +8985,7 @@ public static int Main(string[] args) CreateCompilation(sourceCode).VerifyDiagnostics( // (12,30): error CS1003: Syntax error, ':' expected // case /**/()=>3/**/: - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(":", "=>").WithLocation(12, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(":").WithLocation(12, 30), // (12,30): error CS1513: } expected // case /**/()=>3/**/: Diagnostic(ErrorCode.ERR_RbraceExpected, "=>").WithLocation(12, 30), @@ -9032,7 +9032,7 @@ public static int Main(string[] args) CreateCompilation(sourceCode).VerifyDiagnostics( // (13,30): error CS1003: Syntax error, ':' expected // case /**/()=>/**/: - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(":", "=>").WithLocation(13, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(":").WithLocation(13, 30), // (13,30): error CS1513: } expected // case /**/()=>/**/: Diagnostic(ErrorCode.ERR_RbraceExpected, "=>").WithLocation(13, 30), diff --git a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs index efc98e7c4e494..5afb19fbf2390 100644 --- a/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/DocumentationComments/CrefTests.cs @@ -4485,30 +4485,30 @@ class C // BREAK: dev11 doesn't report CS1581 for "Q[]" or "Q*" because it only checks for error // types and it finds an array type and a pointer type, respectively. CreateCompilationWithMscorlib40AndDocumentationComments(source).VerifyDiagnostics( - // (2,16): warning CS1581: Invalid return type in XML comment cref attribute + // (2,34): warning CS1581: Invalid return type in XML comment cref attribute // /// - Diagnostic(ErrorCode.WRN_BadXMLRefReturnType, "Q").WithArguments("Q", "explicit operator Q"), + Diagnostic(ErrorCode.WRN_BadXMLRefReturnType, "Q").WithLocation(2, 34), // (2,16): warning CS1574: XML comment has cref attribute 'explicit operator Q' that could not be resolved // /// - Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator Q").WithArguments("explicit operator Q"), - // (3,16): warning CS1581: Invalid return type in XML comment cref attribute + Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator Q").WithArguments("explicit operator Q").WithLocation(2, 16), + // (3,34): warning CS1581: Invalid return type in XML comment cref attribute // /// - Diagnostic(ErrorCode.WRN_BadXMLRefReturnType, "C{Q}").WithArguments("C{Q}", "explicit operator C{Q}"), + Diagnostic(ErrorCode.WRN_BadXMLRefReturnType, "C{Q}").WithLocation(3, 34), // (3,16): warning CS1574: XML comment has cref attribute 'explicit operator C{Q}' that could not be resolved // /// - Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator C{Q}").WithArguments("explicit operator C{Q}"), - // (4,16): warning CS1581: Invalid return type in XML comment cref attribute + Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator C{Q}").WithArguments("explicit operator C{Q}").WithLocation(3, 16), + // (4,34): warning CS1581: Invalid return type in XML comment cref attribute // /// - Diagnostic(ErrorCode.WRN_BadXMLRefReturnType, "Q[]").WithArguments("Q[]", "explicit operator Q[]"), + Diagnostic(ErrorCode.WRN_BadXMLRefReturnType, "Q[]").WithLocation(4, 34), // (4,16): warning CS1574: XML comment has cref attribute 'explicit operator Q[]' that could not be resolved // /// - Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator Q[]").WithArguments("explicit operator Q[]"), - // (5,16): warning CS1581: Invalid return type in XML comment cref attribute + Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator Q[]").WithArguments("explicit operator Q[]").WithLocation(4, 16), + // (5,34): warning CS1581: Invalid return type in XML comment cref attribute // /// - Diagnostic(ErrorCode.WRN_BadXMLRefReturnType, "Q*").WithArguments("Q*", "explicit operator Q*"), + Diagnostic(ErrorCode.WRN_BadXMLRefReturnType, "Q*").WithLocation(5, 34), // (5,16): warning CS1574: XML comment has cref attribute 'explicit operator Q*' that could not be resolved // /// - Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator Q*").WithArguments("explicit operator Q*")); + Diagnostic(ErrorCode.WRN_BadXMLRef, "explicit operator Q*").WithArguments("explicit operator Q*").WithLocation(5, 16)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs index 701c038729cd3..f20afd3a3dfa6 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CheckedUserDefinedOperatorsTests.cs @@ -450,7 +450,7 @@ class C Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "(").WithLocation(4, 38), // (4,39): error CS1003: Syntax error, '(' expected // public static C operator checked (C x) => default; - Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(", "").WithLocation(4, 39) + Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(").WithLocation(4, 39) ); var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C"); @@ -477,7 +477,7 @@ class C Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "(").WithLocation(4, 30), // (4,31): error CS1003: Syntax error, '(' expected // public static C operator (C x) => default; - Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(", "").WithLocation(4, 31) + Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(").WithLocation(4, 31) ); var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C"); @@ -1629,7 +1629,7 @@ class C Diagnostic(ErrorCode.ERR_OvlBinaryOperatorExpected, "(").WithLocation(4, 38), // (4,39): error CS1003: Syntax error, '(' expected // public static C operator checked (C x, C y) => default; - Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(", "").WithLocation(4, 39) + Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(").WithLocation(4, 39) ); var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C"); @@ -1656,7 +1656,7 @@ class C Diagnostic(ErrorCode.ERR_OvlBinaryOperatorExpected, "(").WithLocation(4, 30), // (4,31): error CS1003: Syntax error, '(' expected // public static C operator (C x, C y) => default; - Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(", "").WithLocation(4, 31) + Diagnostic(ErrorCode.ERR_SyntaxError, "C").WithArguments("(").WithLocation(4, 31) ); var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C"); @@ -2434,7 +2434,7 @@ class C Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "(").WithLocation(4, 38), // (4,39): error CS1003: Syntax error, '(' expected // public static C operator checked () => default; - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(", ")").WithLocation(4, 39) + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(4, 39) ); var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C"); @@ -2461,7 +2461,7 @@ class C Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "(").WithLocation(4, 30), // (4,31): error CS1003: Syntax error, '(' expected // public static C operator () => default; - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(", ")").WithLocation(4, 31) + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(4, 31) ); var c = compilation1.SourceModule.GlobalNamespace.GetTypeMember("C"); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs index 575f4d1fa2929..46d6060ce41c4 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DefaultInterfaceImplementationTests.cs @@ -2213,7 +2213,7 @@ public interface I1 Diagnostic(ErrorCode.ERR_GetOrSetExpected, "remove").WithLocation(4, 18), // (4,9): error CS8053: Instance properties in interfaces cannot have initializers. // int P1 {add; remove;} = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithArguments("I1.P1").WithLocation(4, 9), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithLocation(4, 9), // (4,9): error CS0548: 'I1.P1': property or indexer must have at least one accessor // int P1 {add; remove;} = 0; Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "P1").WithArguments("I1.P1").WithLocation(4, 9) @@ -2244,7 +2244,7 @@ public interface I1 compilation1.VerifyEmitDiagnostics( // (4,9): error CS8053: Instance properties in interfaces cannot have initializers.. // int P1 {get; set;} = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithArguments("I1.P1").WithLocation(4, 9) + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithLocation(4, 9) ); var p1 = compilation1.GetMember("I1.P1"); @@ -11761,7 +11761,7 @@ public interface I1 compilation1.VerifyEmitDiagnostics( // (4,24): error CS8053: Instance properties in interfaces cannot have initializers. // public virtual int P1 { get; } = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithArguments("I1.P1").WithLocation(4, 24), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithLocation(4, 24), // (4,29): error CS0501: 'I1.P1.get' must declare a body because it is not marked abstract, extern, or partial // public virtual int P1 { get; } = 0; Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("I1.P1.get").WithLocation(4, 29) @@ -12578,7 +12578,7 @@ class Test1 : I1 Diagnostic(ErrorCode.ERR_SealedNonOverride, "P3").WithArguments("I1.P3").WithLocation(8, 24), // (14,17): error CS8053: Instance properties in interfaces cannot have initializers. // private int P4 {get;} = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P4").WithArguments("I1.P4").WithLocation(14, 17), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P4").WithLocation(14, 17), // (14,21): error CS0501: 'I1.P4.get' must declare a body because it is not marked abstract, extern, or partial // private int P4 {get;} = 0; Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("I1.P4.get").WithLocation(14, 21), @@ -14023,7 +14023,7 @@ class Test2 : I1, I2, I3 ValidatePropertyModifiers_14(source1, // (4,23): error CS8053: Instance properties in interfaces cannot have initializers. // public sealed int P1 {get;} = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithArguments("I1.P1").WithLocation(4, 23), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithLocation(4, 23), // (4,27): error CS0501: 'I1.P1.get' must declare a body because it is not marked abstract, extern, or partial // public sealed int P1 {get;} = 0; Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("I1.P1.get").WithLocation(4, 27), @@ -14286,7 +14286,7 @@ class Test2 : I0, I1, I2, I3, I4, I5, I6, I7, I8 Diagnostic(ErrorCode.ERR_AbstractNotVirtual, "P8").WithArguments("property", "I8.P8").WithLocation(44, 26), // (44,26): error CS8053: Instance properties in interfaces cannot have initializers. // abstract virtual int P8 {get;} = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P8").WithArguments("I8.P8").WithLocation(44, 26), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P8").WithLocation(44, 26), // (90,15): error CS0535: 'Test2' does not implement interface member 'I0.P0' // class Test2 : I0, I1, I2, I3, I4, I5, I6, I7, I8 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I0").WithArguments("Test2", "I0.P0").WithLocation(90, 15), @@ -14734,7 +14734,7 @@ class Test2 : I1, I2, I3, I4, I5 Diagnostic(ErrorCode.ERR_ExternHasBody, "set").WithArguments("I4.P4.set").WithLocation(16, 47), // (20,23): error CS8053: Instance properties in interfaces cannot have initializers. // extern sealed int P5 {get;} = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P5").WithArguments("I5.P5").WithLocation(20, 23), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P5").WithLocation(20, 23), // (23,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' // class Test1 : I1, I2, I3, I4, I5 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I1").WithArguments("Test1", "I1.P1").WithLocation(23, 15), @@ -14966,7 +14966,7 @@ class Test2 : I1, I2, I3, I4, I5 Diagnostic(ErrorCode.ERR_BadMemberFlag, "P5").WithArguments("override").WithLocation(20, 25), // (20,25): error CS8053: Instance properties in interfaces cannot have initializers. // override sealed int P5 {get;} = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P5").WithArguments("I5.P5").WithLocation(20, 25), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P5").WithLocation(20, 25), // (20,29): error CS0501: 'I5.P5.get' must declare a body because it is not marked abstract, extern, or partial // override sealed int P5 {get;} = 0; Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("I5.P5.get").WithLocation(20, 29), @@ -34108,7 +34108,7 @@ class Test2 : I4 Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "set").WithArguments("I4.I3.M3.set").WithLocation(43, 21), // (44,12): error CS8053: Instance properties in interfaces cannot have initializers. // int I3.M4 {get; set;} = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "M4").WithArguments("I4.I3.M4").WithLocation(44, 12), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "M4").WithLocation(44, 12), // (44,16): error CS0501: 'I4.I3.M4.get' must declare a body because it is not marked abstract, extern, or partial // int I3.M4 {get; set;} = 0; Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("I4.I3.M4.get").WithLocation(44, 16), @@ -39771,7 +39771,7 @@ public interface I1 Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "set").WithArguments("I1.F1.set").WithLocation(4, 26), // (5,17): error CS8053: Instance properties in interfaces cannot have initializers. // private int F5 {get;} = 5; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "F5").WithArguments("I1.F5").WithLocation(5, 17), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "F5").WithLocation(5, 17), // (5,21): error CS0501: 'I1.F5.get' must declare a body because it is not marked abstract, extern, or partial // private int F5 {get;} = 5; Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("I1.F5.get").WithLocation(5, 21) @@ -43927,10 +43927,10 @@ public interface I1 // (19,31): error CS0563: One of the parameters of a binary operator must be the containing type // public static I1 operator ^(int x, int y) => throw null; Diagnostic(ErrorCode.ERR_BadBinaryOperatorSignature, "^").WithLocation(19, 31), - // (20,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // (20,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type // public static I1 operator <<(int x, int y) => throw null; Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, "<<").WithLocation(20, 31), - // (21,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // (21,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type // public static I1 operator >>(int x, int y) => throw null; Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>").WithLocation(21, 31), // (22,31): error CS0563: One of the parameters of a binary operator must be the containing type @@ -43980,18 +43980,9 @@ public interface I4 "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularNext, targetFramework: TargetFramework.NetCoreApp); + parseOptions: TestOptions.RegularPreview, targetFramework: TargetFramework.NetCoreApp); compilation1.VerifyDiagnostics( - // (4,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - // public static I1 operator <<(I1 x, I1 y) => throw null; - Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, "<<").WithLocation(4, 31), - // (5,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - // public static I1 operator >>(I1 x, I1 y) => throw null; - Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>").WithLocation(5, 31), - // (6,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - // public static I1 operator >>>(I1 x, I1 y) => throw null; - Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>>").WithLocation(6, 31), // (10,33): error CS0216: The operator 'I2.operator true(I2)' requires a matching operator 'false' to also be defined // public static bool operator true(I2 x) => throw null; Diagnostic(ErrorCode.ERR_OperatorNeedsMatch, "true").WithArguments("I2.operator true(I2)", "false").WithLocation(10, 33), @@ -50600,7 +50591,7 @@ public class C2 : I1 Diagnostic(ErrorCode.ERR_BadMemberFlag, "P1").WithArguments("abstract").WithLocation(9, 21), // (9,26): error CS8051: Auto-implemented properties must have get accessors. // abstract int I1.P1 { set; } - Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithArguments("C2.I1.P1.set").WithLocation(9, 26) + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithLocation(9, 26) ); } @@ -50625,7 +50616,7 @@ public struct C2 : I1 Diagnostic(ErrorCode.ERR_BadMemberFlag, "P1").WithArguments("abstract").WithLocation(9, 21), // (9,26): error CS8051: Auto-implemented properties must have get accessors. // abstract int I1.P1 { set; } - Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithArguments("C2.I1.P1.set").WithLocation(9, 26) + Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithLocation(9, 26) ); } @@ -50714,7 +50705,7 @@ class Test1 : I2 ValidatePropertyReAbstraction_014(source1, // (9,21): error CS8053: Instance properties in interfaces cannot have initializers. // abstract int I1.P1 { get; set; } = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithArguments("I2.I1.P1").WithLocation(9, 21), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithLocation(9, 21), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' // class Test1 : I2 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I2").WithArguments("Test1", "I1.P1").WithLocation(12, 15) @@ -50743,7 +50734,7 @@ class Test1 : I2 ValidatePropertyReAbstraction_014(source1, // (9,21): error CS8053: Instance properties in interfaces cannot have initializers. // abstract int I1.P1 { get; } = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithArguments("I2.I1.P1").WithLocation(9, 21), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithLocation(9, 21), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' // class Test1 : I2 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I2").WithArguments("Test1", "I1.P1").WithLocation(12, 15) @@ -50772,7 +50763,7 @@ class Test1 : I2 ValidatePropertyReAbstraction_014(source1, // (9,21): error CS8053: Instance properties in interfaces cannot have initializers. // abstract int I1.P1 { set; } = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithArguments("I2.I1.P1").WithLocation(9, 21), + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P1").WithLocation(9, 21), // (12,15): error CS0535: 'Test1' does not implement interface member 'I1.P1' // class Test1 : I2 Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I2").WithArguments("Test1", "I1.P1").WithLocation(12, 15) @@ -61022,16 +61013,16 @@ interface IC compilation1.VerifyDiagnostics( // (4,20): error CS8145: Auto-implemented properties cannot return by reference // static ref int PA { get;} - Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PA").WithArguments("IA.PA").WithLocation(4, 20), + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PA").WithLocation(4, 20), // (9,20): error CS8145: Auto-implemented properties cannot return by reference // static ref int PB { get; set;} - Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PB").WithArguments("IB.PB").WithLocation(9, 20), + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "PB").WithLocation(9, 20), // (9,30): error CS8147: Properties which return by reference cannot have set accessors // static ref int PB { get; set;} - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithArguments("IB.PB.set").WithLocation(9, 30), + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(9, 30), // (14,20): error CS8146: Properties which return by reference must have a get accessor // static ref int PC { set;} - Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PC").WithArguments("IC.PC").WithLocation(14, 20) + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PC").WithLocation(14, 20) ); } @@ -61061,10 +61052,10 @@ interface IC compilation1.VerifyDiagnostics( // (9,23): error CS8147: Properties which return by reference cannot have set accessors // ref int PB { get; set;} - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithArguments("IB.PB.set").WithLocation(9, 23), + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(9, 23), // (14,13): error CS8146: Properties which return by reference must have a get accessor // ref int PC { set;} - Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PC").WithArguments("IC.PC").WithLocation(14, 13) + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PC").WithLocation(14, 13) ); } @@ -61100,13 +61091,13 @@ interface IC Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "get").WithArguments("IB.PB.get").WithLocation(9, 25), // (9,30): error CS8147: Properties which return by reference cannot have set accessors // sealed ref int PB { get; set;} - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithArguments("IB.PB.set").WithLocation(9, 30), + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(9, 30), // (9,30): error CS0501: 'IB.PB.set' must declare a body because it is not marked abstract, extern, or partial // sealed ref int PB { get; set;} Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "set").WithArguments("IB.PB.set").WithLocation(9, 30), // (14,20): error CS8146: Properties which return by reference must have a get accessor // sealed ref int PC { set;} - Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PC").WithArguments("IC.PC").WithLocation(14, 20), + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "PC").WithLocation(14, 20), // (14,25): error CS0501: 'IC.PC.set' must declare a body because it is not marked abstract, extern, or partial // sealed ref int PC { set;} Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "set").WithArguments("IC.PC.set").WithLocation(14, 25) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/DestructorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/DestructorTests.cs index 3b73251cc95ea..4ebfa0fcc97bc 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/DestructorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/DestructorTests.cs @@ -74,10 +74,15 @@ interface I ~I(); }"; CreateCompilation(source).VerifyDiagnostics( - // error CS0575: Only class types can contain destructors - Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "S").WithArguments("S.~S()"), - Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "I").WithArguments("I.~I()"), - Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "I")); + // (4,6): error CS0575: Only class types can contain destructors + // ~S() { } + Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "S").WithLocation(4, 6), + // (9,6): error CS0501: 'I.~I()' must declare a body because it is not marked abstract, extern, or partial + // ~I(); + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "I").WithArguments("I.~I()").WithLocation(9, 6), + // (9,6): error CS0575: Only class types can contain destructors + // ~I(); + Diagnostic(ErrorCode.ERR_OnlyClassesCanContainDestructors, "I").WithLocation(9, 6)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/RelaxedShiftOperatorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/RelaxedShiftOperatorTests.cs new file mode 100644 index 0000000000000..8539478c2ce51 --- /dev/null +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/RelaxedShiftOperatorTests.cs @@ -0,0 +1,329 @@ +// Licensed to the .NET Foundation under one or more agreements. +// 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.Linq; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols +{ + public class RelaxedShiftOperatorTests : CSharpTestBase + { + [Theory] + [InlineData("<<")] + [InlineData(">>")] + [InlineData(">>>")] + public void Relaxed_01(string op) + { + var source0 = @" +public class C1 +{ + public static C1 operator " + op + @"(C1 x, C1 y) + { + System.Console.WriteLine(""" + op + @"""); + return x; + } +} +"; + + var source1 = +@" +class C +{ + static void Main() + { + Test1(new C1(), new C1()); + } + + static C1 Test1(C1 x, C1 y) => x " + op + @" y; +} +"; + var compilation1 = CreateCompilation(source0 + source1, options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview); + CompileAndVerify(compilation1, expectedOutput: op).VerifyDiagnostics(); + + var compilation0 = CreateCompilation(source0, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + + var compilation2 = CreateCompilation(source1, options: TestOptions.DebugExe, references: new[] { compilation0.ToMetadataReference() }, + parseOptions: TestOptions.RegularPreview); + + CompileAndVerify(compilation2, expectedOutput: op).VerifyDiagnostics(); + + + var compilation3 = CreateCompilation(source1, options: TestOptions.DebugExe, references: new[] { compilation0.EmitToImageReference() }, + parseOptions: TestOptions.RegularPreview); + CompileAndVerify(compilation3, expectedOutput: op).VerifyDiagnostics(); + } + + [Theory] + [InlineData("<<")] + [InlineData(">>")] + [InlineData(">>>")] + public void OverloadResolution_01(string op) + { + var source1 = @" +public class C1 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +public class C2 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +class C +{ + static C1 Test1(C1 x, C2 y) => x " + op + @" y; +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyDiagnostics( + // (12,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type + // public static C1 operator >>>(C1 x, C2 y) + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, op).WithLocation(12, 31) + ); + + var tree = compilation1.SyntaxTrees.Single(); + var model = compilation1.GetSemanticModel(tree); + var shift = tree.GetRoot().DescendantNodes().OfType().Single(); + + Assert.Equal("x " + op + " y", shift.ToString()); + Assert.Equal("C1.operator " + op + "(C1, C2)", model.GetSymbolInfo(shift).Symbol.ToDisplayString()); + } + + [Theory] + [InlineData("<<")] + [InlineData(">>")] + [InlineData(">>>")] + public void OverloadResolution_02(string op) + { + var source1 = @" +public interface C1 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +public interface C2 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +class C +{ + static C1 Test1(C1 x, C2 y) => x " + op + @" y; +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.NetCoreApp, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyDiagnostics( + // (12,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type + // public static C1 operator >>>(C1 x, C2 y) + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, op).WithLocation(12, 31) + ); + + var tree = compilation1.SyntaxTrees.Single(); + var model = compilation1.GetSemanticModel(tree); + var shift = tree.GetRoot().DescendantNodes().OfType().Single(); + + Assert.Equal("x " + op + " y", shift.ToString()); + Assert.Equal("C1.operator " + op + "(C1, C2)", model.GetSymbolInfo(shift).Symbol.ToDisplayString()); + } + + [Theory] + [InlineData("<<")] + [InlineData(">>")] + [InlineData(">>>")] + public void OverloadResolution_03(string op) + { + var source1 = @" +public interface C1 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +public interface C2 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +class C +{ + static C1 Test1(T x, C2 y) where T : C1 => x " + op + @" y; +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.NetCoreApp, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyDiagnostics( + // (12,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type + // public static C1 operator >>>(C1 x, C2 y) + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, op).WithLocation(12, 31) + ); + + var tree = compilation1.SyntaxTrees.Single(); + var model = compilation1.GetSemanticModel(tree); + var shift = tree.GetRoot().DescendantNodes().OfType().Single(); + + Assert.Equal("x " + op + " y", shift.ToString()); + Assert.Equal("C1.operator " + op + "(C1, C2)", model.GetSymbolInfo(shift).Symbol.ToDisplayString()); + } + + [Theory] + [InlineData("<<")] + [InlineData(">>")] + [InlineData(">>>")] + public void OverloadResolution_04(string op) + { + var source1 = @" +public interface C1 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +public interface C2 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +class C +{ + static C1 Test1(C1 x, T y) where T : C2 => x " + op + @" y; +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.NetCoreApp, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyDiagnostics( + // (12,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type + // public static C1 operator >>>(C1 x, C2 y) + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, op).WithLocation(12, 31) + ); + + var tree = compilation1.SyntaxTrees.Single(); + var model = compilation1.GetSemanticModel(tree); + var shift = tree.GetRoot().DescendantNodes().OfType().Single(); + + Assert.Equal("x " + op + " y", shift.ToString()); + Assert.Equal("C1.operator " + op + "(C1, C2)", model.GetSymbolInfo(shift).Symbol.ToDisplayString()); + } + + [Theory] + [InlineData("<<")] + [InlineData(">>")] + [InlineData(">>>")] + public void OverloadResolution_05(string op) + { + var source1 = @" +public interface C1 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +public class C2 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +class C +{ + static C1 Test1(C1 x, C2 y) => x " + op + @" y; +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.NetCoreApp, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyDiagnostics( + // (12,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type + // public static C1 operator >>>(C1 x, C2 y) + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, op).WithLocation(12, 31) + ); + + var tree = compilation1.SyntaxTrees.Single(); + var model = compilation1.GetSemanticModel(tree); + var shift = tree.GetRoot().DescendantNodes().OfType().Single(); + + Assert.Equal("x " + op + " y", shift.ToString()); + Assert.Equal("C1.operator " + op + "(C1, C2)", model.GetSymbolInfo(shift).Symbol.ToDisplayString()); + } + + [Theory] + [InlineData("<<")] + [InlineData(">>")] + [InlineData(">>>")] + public void OverloadResolution_06(string op) + { + var source1 = @" +public class C1 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +public interface C2 +{ + public static C1 operator " + op + @"(C1 x, C2 y) + { + return x; + } +} + +class C +{ + static C1 Test1(C1 x, C2 y) => x " + op + @" y; +} +"; + var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, targetFramework: TargetFramework.NetCoreApp, + parseOptions: TestOptions.RegularPreview); + compilation1.VerifyDiagnostics( + // (12,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type + // public static C1 operator >>>(C1 x, C2 y) + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, op).WithLocation(12, 31) + ); + + var tree = compilation1.SyntaxTrees.Single(); + var model = compilation1.GetSemanticModel(tree); + var shift = tree.GetRoot().DescendantNodes().OfType().Single(); + + Assert.Equal("x " + op + " y", shift.ToString()); + Assert.Equal("C1.operator " + op + "(C1, C2)", model.GetSymbolInfo(shift).Symbol.ToDisplayString()); + } + } +} diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs index 1f9a31e9f441c..233240f250df1 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs @@ -155,7 +155,7 @@ class C2 : I2 Diagnostic(ErrorCode.ERR_IdentifierExpected, "int").WithLocation(4, 30), // (4,30): error CS1003: Syntax error, ',' expected // required void M(required int i) - Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",", "int").WithLocation(4, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",").WithLocation(4, 30), // (8,14): error CS0106: The modifier 'required' is not valid for this item // required C1() { } Diagnostic(ErrorCode.ERR_BadMemberFlag, "C1").WithArguments("required").WithLocation(8, 14), diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExternAliasTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExternAliasTests.cs index be724a657844b..1b282cfa41c8b 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExternAliasTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/ExternAliasTests.cs @@ -488,6 +488,8 @@ static void Main() var externAliasSymbol = model.GetDeclaredSymbol(externAliasSyntax); Assert.Equal("A", externAliasSymbol.Name); Assert.Equal(aliasedGlobalNamespace, externAliasSymbol.Target); + Assert.Equal(1, externAliasSymbol.DeclaringSyntaxReferences.Length); + Assert.Same(externAliasSyntax, externAliasSymbol.DeclaringSyntaxReferences.Single().GetSyntax()); var usingAliasSymbol = model.GetDeclaredSymbol(usingSyntax); Assert.Equal("C", usingAliasSymbol.Name); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs index eff7c789939f4..302eb01b969fe 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FieldTests.cs @@ -300,7 +300,7 @@ protected virtual void Finalize const () { } Diagnostic(ErrorCode.ERR_ConstValueRequired, "{").WithLocation(5, 46), // (5,46): error CS1003: Syntax error, ',' expected // protected virtual void Finalize const () { } - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(5, 46), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(5, 46), // (5,48): error CS1002: ; expected // protected virtual void Finalize const () { } Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(5, 48), @@ -368,7 +368,7 @@ protected virtual void Finalize const () { } Diagnostic(ErrorCode.ERR_ConstValueRequired, "{").WithLocation(5, 46), // (5,46): error CS1003: Syntax error, ',' expected // protected virtual void Finalize const () { } - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(5, 46), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(5, 46), // (5,48): error CS1002: ; expected // protected virtual void Finalize const () { } Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(5, 48), diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs index 86097b7a6e966..8653e604b1e63 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/PropertyTests.cs @@ -72,12 +72,12 @@ public C() } }").VerifyDiagnostics( - // (12,25): error CS8080: "Auto-implemented properties must override all accessors of the overridden property." - // public override int P { get; } - Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P").WithArguments("C.P").WithLocation(12, 25), - // (13,25): error CS8080: "Auto-implemented properties must override all accessors of the overridden property." - // public override int P1 { get; } - Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithArguments("C.P1").WithLocation(13, 25) + // (12,25): error CS8080: "Auto-implemented properties must override all accessors of the overridden property." + // public override int P { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P").WithLocation(12, 25), + // (13,25): error CS8080: "Auto-implemented properties must override all accessors of the overridden property." + // public override int P1 { get; } + Diagnostic(ErrorCode.ERR_AutoPropertyMustOverrideSet, "P1").WithLocation(13, 25) ); } @@ -268,7 +268,7 @@ public void AutoInitializerInInterface() comp.VerifyDiagnostics( // (3,9): error CS8053: Instance properties in interfaces cannot have initializers. // int P { get; } = 0; - Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P").WithArguments("I.P").WithLocation(3, 9)); + Diagnostic(ErrorCode.ERR_InstancePropertyInitializerInInterface, "P").WithLocation(3, 9)); } [Fact] @@ -297,10 +297,10 @@ public int P { set {} } comp.VerifyDiagnostics( // (4,20): error CS8051: Auto-implemented properties must have get accessors. // public int Q { set; } = 0; -Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithArguments("C.Q.set").WithLocation(4, 20), +Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithLocation(4, 20), // (5,20): error CS8051: Auto-implemented properties must have get accessors. // public int R { set; } -Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithArguments("C.R.set").WithLocation(5, 20)); +Diagnostic(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, "set").WithLocation(5, 20)); } [Fact] @@ -315,7 +315,7 @@ public void AutoRefReturn() comp.VerifyDiagnostics( // (3,20): error CS8080: Auto-implemented properties cannot return by reference // public ref int P { get; } -Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P").WithArguments("C.P").WithLocation(3, 20)); +Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P").WithLocation(3, 20)); } [Fact] @@ -329,10 +329,10 @@ class C var comp = CreateCompilation(text).VerifyDiagnostics( // (4,29): error CS8145: Auto-implemented properties cannot return by reference // public ref readonly int P1 { get; set; } - Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithArguments("C.P1").WithLocation(4, 29), + Diagnostic(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, "P1").WithLocation(4, 29), // (4,39): error CS8147: Properties which return by reference cannot have set accessors // public ref readonly int P1 { get; set; } - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithArguments("C.P1.set").WithLocation(4, 39)); + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(4, 39)); } [WorkItem(542745, "DevDiv")] @@ -1165,12 +1165,12 @@ static void Main() { } "; CreateCompilationWithILAndMscorlib40(cSharpSource, ilSource).VerifyDiagnostics( - // (5,11): error CS0268: Imported type 'E' is invalid. It contains a circular base type dependency. - // B y = A.Goo; - Diagnostic(ErrorCode.ERR_ImportedCircularBase, "A.Goo").WithArguments("E", "E"), - // (5,11): error CS0029: Cannot implicitly convert type 'E' to 'B' - // B y = A.Goo; - Diagnostic(ErrorCode.ERR_NoImplicitConv, "A.Goo").WithArguments("E", "B") + // (5,11): error CS0268: Imported type 'E' is invalid. It contains a circular base type dependency. + // B y = A.Goo; + Diagnostic(ErrorCode.ERR_ImportedCircularBase, "A.Goo").WithArguments("E").WithLocation(5, 11), + // (5,11): error CS0029: Cannot implicitly convert type 'E' to 'B' + // B y = A.Goo; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "A.Goo").WithArguments("E", "B").WithLocation(5, 11) ); // Dev10 errors: // error CS0268: Imported type 'E' is invalid. It contains a circular base type dependency. @@ -2913,7 +2913,7 @@ ref int P { set { } } CreateCompilationWithMscorlib45(source).VerifyDiagnostics( // (4,17): error CS8080: Properties with by-reference returns must have a get accessor. // ref int P { set { } } - Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "P").WithArguments("C.P").WithLocation(4, 17)); + Diagnostic(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, "P").WithLocation(4, 17)); } [Fact] @@ -2930,7 +2930,7 @@ class C CreateCompilationWithMscorlib45(source).VerifyDiagnostics( // (5,47): error CS8081: Properties with by-reference returns cannot have set accessors. // ref int P { get { return ref field; } set { } } - Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithArguments("C.P.set").WithLocation(5, 47)); + Diagnostic(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, "set").WithLocation(5, 47)); } [Fact, WorkItem(4696, "https://github.com/dotnet/roslyn/issues/4696")] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs index d7ec48e8e7ae9..6b2cee8ab36e8 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs @@ -5903,33 +5903,30 @@ interface I14 parseOptions: TestOptions.RegularPreview, targetFramework: _supportingFramework); compilation1.GetDiagnostics().Where(d => d.Code is not (int)ErrorCode.ERR_OperatorNeedsMatch).Verify( - // (4,26): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // (4,26): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type // static bool operator <<(T1 x, int y) => throw null; Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, op).WithLocation(4, 26), - // (9,26): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // (9,26): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type // static bool operator <<(T2? x, int y) => throw null; Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, op).WithLocation(9, 26), - // (26,39): error CS8925: The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int + // (26,39): error CS8925: The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it // static abstract bool operator <<(T5 x, int y); Diagnostic(ErrorCode.ERR_BadAbstractShiftOperatorSignature, op).WithLocation(26, 39), - // (32,35): error CS8925: The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int + // (32,35): error CS8925: The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it // static abstract bool operator <<(T71 x, int y); Diagnostic(ErrorCode.ERR_BadAbstractShiftOperatorSignature, op).WithLocation(32, 35), - // (37,35): error CS8925: The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int + // (37,35): error CS8925: The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it // static abstract bool operator <<(T8 x, int y); Diagnostic(ErrorCode.ERR_BadAbstractShiftOperatorSignature, op).WithLocation(37, 35), - // (44,35): error CS8925: The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int + // (44,35): error CS8925: The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it // static abstract bool operator <<(T10 x, int y); Diagnostic(ErrorCode.ERR_BadAbstractShiftOperatorSignature, op).WithLocation(44, 35), // (47,18): error CS0535: 'C11' does not implement interface member 'I10.operator >>(T11, int)' // class C11 : I10 where T11 : C11 {} Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "I10").WithArguments("C11", "I10.operator " + op + "(T11, int)").WithLocation(47, 18), - // (51,35): error CS8925: The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int + // (51,35): error CS8925: The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it // static abstract bool operator <<(int x, int y); - Diagnostic(ErrorCode.ERR_BadAbstractShiftOperatorSignature, op).WithLocation(51, 35), - // (61,35): error CS8925: The first operand of an overloaded shift operator must have the same type as the containing type or its type parameter constrained to it, and the type of the second operand must be int - // static abstract bool operator <<(I14 x, bool y); - Diagnostic(ErrorCode.ERR_BadAbstractShiftOperatorSignature, op).WithLocation(61, 35) + Diagnostic(ErrorCode.ERR_BadAbstractShiftOperatorSignature, op).WithLocation(51, 35) ); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index 4e3cae08714dc..acc9b3f00cb1f 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -1120,19 +1120,19 @@ int F() { } // CS0081 Diagnostic(ErrorCode.ERR_IdentifierExpected, "int").WithLocation(5, 11), // (5,11): error CS1003: Syntax error, '>' expected // int F() { } // CS0081 - Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(">", "int").WithLocation(5, 11), + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(">").WithLocation(5, 11), // (5,11): error CS1003: Syntax error, '(' expected // int F() { } // CS0081 - Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments("(", "int").WithLocation(5, 11), + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments("(").WithLocation(5, 11), // (5,14): error CS1001: Identifier expected // int F() { } // CS0081 Diagnostic(ErrorCode.ERR_IdentifierExpected, ">").WithLocation(5, 14), // (5,14): error CS1003: Syntax error, ',' expected // int F() { } // CS0081 - Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments(",", ">").WithLocation(5, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments(",").WithLocation(5, 14), // (5,15): error CS1003: Syntax error, ',' expected // int F() { } // CS0081 - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(",", "(").WithLocation(5, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(",").WithLocation(5, 15), // (5,16): error CS8124: Tuple must contain at least two elements. // int F() { } // CS0081 Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(5, 16), @@ -1171,19 +1171,19 @@ int F() { } // CS0081 Diagnostic(ErrorCode.ERR_IdentifierExpected, "int").WithLocation(5, 11), // (5,11): error CS1003: Syntax error, '>' expected // int F() { } // CS0081 - Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(">", "int").WithLocation(5, 11), + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(">").WithLocation(5, 11), // (5,11): error CS1003: Syntax error, '(' expected // int F() { } // CS0081 - Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments("(", "int").WithLocation(5, 11), + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments("(").WithLocation(5, 11), // (5,14): error CS1001: Identifier expected // int F() { } // CS0081 Diagnostic(ErrorCode.ERR_IdentifierExpected, ">").WithLocation(5, 14), // (5,14): error CS1003: Syntax error, ',' expected // int F() { } // CS0081 - Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments(",", ">").WithLocation(5, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments(",").WithLocation(5, 14), // (5,15): error CS1003: Syntax error, ',' expected // int F() { } // CS0081 - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(",", "(").WithLocation(5, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(",").WithLocation(5, 15), // (5,15): error CS8059: Feature 'tuples' is not available in C# 6. Please use language version 7.0 or greater. // int F() { } // CS0081 Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "()").WithArguments("tuples", "7.0").WithLocation(5, 15), @@ -3880,10 +3880,10 @@ public interface I3 : I1 { } comp.VerifyDiagnostics( // (3,23): error CS0268: Imported type 'C2' is invalid. It contains a circular base type dependency. // public class C3 : C1 { } - Diagnostic(ErrorCode.ERR_ImportedCircularBase, "C1").WithArguments("C2", "C1"), + Diagnostic(ErrorCode.ERR_ImportedCircularBase, "C1").WithArguments("C2"), // (4,22): error CS0268: Imported type 'I2' is invalid. It contains a circular base type dependency. // public interface I3 : I1 { } - Diagnostic(ErrorCode.ERR_ImportedCircularBase, "I3").WithArguments("I2", "I1") + Diagnostic(ErrorCode.ERR_ImportedCircularBase, "I3").WithArguments("I2") ); var ns = comp.SourceModule.GlobalNamespace.GetMembers("NS").Single() as NamespaceSymbol; @@ -4573,7 +4573,7 @@ struct S comp.VerifyDiagnostics( // (14,17): error CS0400: The type or namespace name 'G' could not be found in the global namespace (are you missing an assembly reference?) // global::G field; - Diagnostic(ErrorCode.ERR_GlobalSingleTypeNameNotFound, "G").WithArguments("G", ""), + Diagnostic(ErrorCode.ERR_GlobalSingleTypeNameNotFound, "G").WithArguments("G"), // (14,19): warning CS0169: The field 'NS.S.field' is never used // global::G field; Diagnostic(ErrorCode.WRN_UnreferencedField, "field").WithArguments("NS.S.field") @@ -10556,15 +10556,54 @@ static void Main() { } } + +class C1 +{ + public static int operator <<(C1 c1, int c2) + { + return 0; + } +} + +class C2 +{ + public static int operator <<(C2 c1, int? c2) + { + return 0; + } +} "; - var comp = CreateCompilation(text); + var comp = CreateCompilation(text, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (8,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type + // public static int operator >>(int c1, int c2) // CS0564 + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>").WithLocation(8, 32), + // (12,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // public static int operator >>>(int c1, int c2) // CS0564 + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>>").WithLocation(12, 32) + ); + + comp = CreateCompilation(text, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( - // (4,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // (4,32): error CS8652: The feature 'relaxed shift operator' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public static int operator <<(C c1, C c2) // CS0564 - Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, "<<"), - // (8,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + Diagnostic(ErrorCode.ERR_FeatureInPreview, "<<").WithArguments("relaxed shift operator").WithLocation(4, 32), + // (8,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type + // public static int operator >>(int c1, int c2) // CS0564 + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>").WithLocation(8, 32), + // (12,32): error CS8652: The feature 'unsigned right shift' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static int operator >>>(int c1, int c2) // CS0564 + Diagnostic(ErrorCode.ERR_FeatureInPreview, ">>>").WithArguments("unsigned right shift").WithLocation(12, 32), + // (12,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // public static int operator >>>(int c1, int c2) // CS0564 + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>>").WithLocation(12, 32) + ); + + comp = CreateCompilation(text, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics( + // (8,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type // public static int operator >>(int c1, int c2) // CS0564 - Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>"), + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>").WithLocation(8, 32), // (12,32): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int // public static int operator >>>(int c1, int c2) // CS0564 Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>>").WithLocation(12, 32) @@ -12993,10 +13032,12 @@ static class D : IGoo } "; CreateCompilation(text).VerifyDiagnostics( - // (7,29): error CS0714: 'NS.C': static classes cannot implement interfaces - Diagnostic(ErrorCode.ERR_StaticClassInterfaceImpl, "I").WithArguments("NS.C", "NS.I"), - // (15,25): error CS0714: 'NS.D': static classes cannot implement interfaces - Diagnostic(ErrorCode.ERR_StaticClassInterfaceImpl, "IGoo").WithArguments("NS.D", "NS.IGoo")); + // (7,29): error CS0714: 'C': static classes cannot implement interfaces + // public static class C : I + Diagnostic(ErrorCode.ERR_StaticClassInterfaceImpl, "I").WithArguments("NS.C").WithLocation(7, 29), + // (15,25): error CS0714: 'D': static classes cannot implement interfaces + // static class D : IGoo + Diagnostic(ErrorCode.ERR_StaticClassInterfaceImpl, "IGoo").WithArguments("NS.D").WithLocation(15, 25)); } [Fact] @@ -15463,7 +15504,7 @@ static unsafe void Error_UseAsLocal() CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( // (8,15): error CS1003: Syntax error, '(' expected // fixed bool _buffer[2]; // error CS1001: Identifier expected - Diagnostic(ErrorCode.ERR_SyntaxError, "bool").WithArguments("(", "bool"), + Diagnostic(ErrorCode.ERR_SyntaxError, "bool").WithArguments("("), // (8,27): error CS0650: Bad array declarator: To declare a managed array the rank specifier precedes the variable's identifier. To declare a fixed size buffer field, use the fixed keyword before the field type. // fixed bool _buffer[2]; // error CS1001: Identifier expected Diagnostic(ErrorCode.ERR_CStyleArray, "[2]"), @@ -16574,13 +16615,13 @@ public void CS8050ERR_InitializerOnNonAutoProperty() CreateCompilation(source).VerifyDiagnostics( // (5,9): error CS8050: Only auto-implemented properties can have initializers. // int I { get { throw null; } set { } } = 1; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithArguments("C.I").WithLocation(5, 9), + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "I").WithLocation(5, 9), // (6,16): error CS8050: Only auto-implemented properties can have initializers. // static int S { get { throw null; } set { } } = 1; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "S").WithArguments("C.S").WithLocation(6, 16), + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "S").WithLocation(6, 16), // (7,19): error CS8050: Only auto-implemented properties can have initializers. // protected int P { get { throw null; } set { } } = 1; - Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P").WithArguments("C.P").WithLocation(7, 19) + Diagnostic(ErrorCode.ERR_InitializerOnNonAutoProperty, "P").WithLocation(7, 19) ); } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs index b917946ec0fb9..d13cb91d68d30 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/UnsignedRightShiftTests.cs @@ -2138,18 +2138,12 @@ public class C4 // (9,33): error CS0590: User-defined operators cannot return void // public static void operator >>(C1 x, int y) Diagnostic(ErrorCode.ERR_OperatorCantReturnVoid, ">>").WithLocation(9, 33), - // (17,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // (17,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type // public static C2 operator >>>(C1 x, int y) Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>>").WithLocation(17, 31), - // (22,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int + // (22,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type // public static C2 operator >>(C1 x, int y) - Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>").WithLocation(22, 31), - // (30,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - // public static C3 operator >>>(C3 x, C2 y) - Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>>").WithLocation(30, 31), - // (35,31): error CS0564: The first operand of an overloaded shift operator must have the same type as the containing type, and the type of the second operand must be int - // public static C3 operator >>(C3 x, C2 y) - Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>").WithLocation(35, 31) + Diagnostic(ErrorCode.ERR_BadShiftOperatorSignature, ">>").WithLocation(22, 31) ); } diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs index fa8c75eb718a3..cc92c05f00e5a 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs @@ -2686,7 +2686,7 @@ public CustomErrorInfo(CommonMessageProvider provider, object otherSymbol, Locat } } - internal class MockMessageProvider : TestMessageProvider + internal sealed class MockMessageProvider : TestMessageProvider { public override DiagnosticSeverity GetSeverity(int code) { @@ -2768,6 +2768,10 @@ public override bool GetIsEnabledByDefault(int code) { return true; } + +#if DEBUG + internal override bool ShouldAssertExpectedMessageArgumentsLength(int errorCode) => false; +#endif } #endregion diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/LocationsTests.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/LocationsTests.cs index 9355bfdd78b55..2e2e0f46ed92f 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/LocationsTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/LocationsTests.cs @@ -514,7 +514,7 @@ public void TestDiagnosticsLocationsExistInsideTreeSpan() var node = SyntaxFactory.IdentifierName(SyntaxFactory.Identifier(SyntaxFactory.TriviaList(SyntaxFactory.Whitespace(" ")), "x", default(SyntaxTriviaList))); // create node with error that would place itself outside the tree. - var nodeWithBadError = node.Green.WithDiagnosticsGreen(new DiagnosticInfo[] { new SyntaxDiagnosticInfo(10, 10, ErrorCode.ERR_AbstractAndExtern) }).CreateRed(); + var nodeWithBadError = node.Green.WithDiagnosticsGreen(new DiagnosticInfo[] { new SyntaxDiagnosticInfo(10, 10, ErrorCode.ERR_NoBaseClass) }).CreateRed(); var tree = SyntaxFactory.SyntaxTree(nodeWithBadError); @@ -543,7 +543,7 @@ public void TestDiagnosticsLocationsExistInsideTreeSpan_ZeroWidthTree() var node = SyntaxFactory.MissingToken(SyntaxKind.IdentifierToken); // create node with error that would place itself outside the tree. - var nodeWithBadError = SyntaxFactory.IdentifierName(new SyntaxToken(node.Node.WithDiagnosticsGreen(new DiagnosticInfo[] { new SyntaxDiagnosticInfo(10, 10, ErrorCode.ERR_AbstractAndExtern) }))); + var nodeWithBadError = SyntaxFactory.IdentifierName(new SyntaxToken(node.Node.WithDiagnosticsGreen(new DiagnosticInfo[] { new SyntaxDiagnosticInfo(10, 10, ErrorCode.ERR_NoBaseClass) }))); var tree = SyntaxFactory.SyntaxTree(nodeWithBadError); var treeSpan = tree.GetRoot().FullSpan; diff --git a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalErrorTests.cs b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalErrorTests.cs index 500aefe3e39aa..cfde161c6bfc8 100644 --- a/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalErrorTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/LexicalAndXml/LexicalErrorTests.cs @@ -195,13 +195,13 @@ public static void Main() ParserErrorMessageTests.ParseAndValidate(test, // (7,15): error CS1031: Type expected // const const double d = 0; - Diagnostic(ErrorCode.ERR_TypeExpected, "const").WithArguments("const").WithLocation(7, 15), + Diagnostic(ErrorCode.ERR_TypeExpected, "const").WithLocation(7, 15), // (8,15): error CS1031: Type expected // const const const long l = 0; - Diagnostic(ErrorCode.ERR_TypeExpected, "const").WithArguments("const").WithLocation(8, 15), + Diagnostic(ErrorCode.ERR_TypeExpected, "const").WithLocation(8, 15), // (8,21): error CS1031: Type expected // const const const long l = 0; - Diagnostic(ErrorCode.ERR_TypeExpected, "const").WithArguments("const").WithLocation(8, 21), + Diagnostic(ErrorCode.ERR_TypeExpected, "const").WithLocation(8, 21), // (9,15): error CS0106: The modifier 'readonly' is not valid for this item // const readonly readonly readonly const double r = 0; Diagnostic(ErrorCode.ERR_BadMemberFlag, "readonly").WithArguments("readonly").WithLocation(9, 15), @@ -213,7 +213,7 @@ public static void Main() Diagnostic(ErrorCode.ERR_BadMemberFlag, "readonly").WithArguments("readonly").WithLocation(9, 33), // (9,42): error CS1031: Type expected // const readonly readonly readonly const double r = 0; - Diagnostic(ErrorCode.ERR_TypeExpected, "const").WithArguments("const").WithLocation(9, 42) + Diagnostic(ErrorCode.ERR_TypeExpected, "const").WithLocation(9, 42) ); } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/AnonymousFunctionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/AnonymousFunctionParsingTests.cs index 23191eed27d62..57c18f3c7fb05 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/AnonymousFunctionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/AnonymousFunctionParsingTests.cs @@ -1182,7 +1182,7 @@ public void StaticLambdaRankSpecifier_Incomplete_01(bool useCsharp9) UsingStatement(test, options: useCsharp9 ? TestOptions.Regular9 : TestOptions.Regular8, // (1,13): error CS1003: Syntax error, ',' expected // _ = new int[static]; - Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",", "static").WithLocation(1, 13) + Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",").WithLocation(1, 13) ); N(SyntaxKind.ExpressionStatement); @@ -1229,7 +1229,7 @@ public void StaticLambdaRankSpecifier_Incomplete_02(bool useCsharp9) UsingStatement(test, options: useCsharp9 ? TestOptions.Regular9 : TestOptions.Regular8, // (1,13): error CS1003: Syntax error, ',' expected // _ = new int[static x]; - Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",", "static").WithLocation(1, 13)); + Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",").WithLocation(1, 13)); N(SyntaxKind.ExpressionStatement); { @@ -1408,7 +1408,7 @@ public void StaticLambdaArrayInitializer_Incomplete_01(bool useCsharp9) UsingStatement(test, options: useCsharp9 ? TestOptions.Regular9 : TestOptions.Regular8, // (1,20): error CS1003: Syntax error, ',' expected // _ = new Action[] { static } - Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",", "static").WithLocation(1, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",").WithLocation(1, 20), // (1,28): error CS1002: ; expected // _ = new Action[] { static } Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 28) @@ -1463,7 +1463,7 @@ public void StaticLambdaArrayInitializer_Incomplete_02(bool useCsharp9) UsingStatement(test, options: useCsharp9 ? TestOptions.Regular9 : TestOptions.Regular8, // (1,20): error CS1003: Syntax error, ',' expected // _ = new Action[] { static x } - Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",", "static").WithLocation(1, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",").WithLocation(1, 20), // (1,30): error CS1002: ; expected // _ = new Action[] { static x } Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 30) @@ -1761,7 +1761,7 @@ public void LambdaFunctionPointer() Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(1, 25), // (1,27): error CS1003: Syntax error, ',' expected // delegate* ptr = &() => { }; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 27) + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 27) ); verify(); @@ -1774,7 +1774,7 @@ public void LambdaFunctionPointer() Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(1, 25), // (1,27): error CS1003: Syntax error, ',' expected // delegate* ptr = &() => { }; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 27)); + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 27)); verify(); void verify() @@ -1842,7 +1842,7 @@ public void StaticLambdaFunctionPointer() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "static").WithArguments("static").WithLocation(1, 24), // (1,24): error CS1003: Syntax error, ',' expected // delegate* ptr = &static () => { }; - Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",", "static").WithLocation(1, 24), + Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",").WithLocation(1, 24), // (1,32): error CS1002: ; expected // delegate* ptr = &static () => { }; Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(1, 32) @@ -1861,7 +1861,7 @@ public void StaticLambdaFunctionPointer() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "static").WithArguments("static").WithLocation(1, 24), // (1,24): error CS1003: Syntax error, ',' expected // delegate* ptr = &static () => { }; - Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",", "static").WithLocation(1, 24), + Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments(",").WithLocation(1, 24), // (1,32): error CS1002: ; expected // delegate* ptr = &static () => { }; Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(1, 32) @@ -2073,7 +2073,7 @@ static void Main() Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(4, 25), // (4,25): error CS1003: Syntax error, ']' expected // [ObsoleteAttribute(x - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]", "static").WithLocation(4, 25) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(4, 25) ); N(SyntaxKind.CompilationUnit); @@ -2148,13 +2148,13 @@ async static Task Main() tree.GetDiagnostics().Verify( // (4,25): error CS1003: Syntax error, ',' expected // [ObsoleteAttribute(x - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",", "").WithLocation(4, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(4, 25), // (5,11): error CS1026: ) expected // async static Task Main() Diagnostic(ErrorCode.ERR_CloseParenExpected, "static").WithLocation(5, 11), // (5,11): error CS1003: Syntax error, ']' expected // async static Task Main() - Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments("]", "static").WithLocation(5, 11) + Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments("]").WithLocation(5, 11) ); N(SyntaxKind.CompilationUnit); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationExpressionTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationExpressionTests.cs index f2cbc2893e72a..a8dc74a200040 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationExpressionTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationExpressionTests.cs @@ -140,7 +140,7 @@ public void NullableTypeTest_03() UsingStatement("if (e is int? x) {}", // (1,16): error CS1003: Syntax error, ':' expected // if (e is int? x) {} - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":", ")").WithLocation(1, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(":").WithLocation(1, 16), // (1,16): error CS1525: Invalid expression term ')' // if (e is int? x) {} Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(1, 16) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs index 148c673be1b20..650a6a1f0f381 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs @@ -7336,7 +7336,7 @@ public void TestMethodDeclarationNullValidation_SingleExclamation() UsingStatement(@"void M(string name!) { }", options: TestOptions.RegularPreview, // (1,19): error CS1003: Syntax error, '!!' expected // void M(string name!) { } - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(1, 19)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(1, 19)); N(SyntaxKind.LocalFunctionStatement); { @@ -7375,7 +7375,7 @@ public void TestMethodDeclarationNullValidation_SingleExclamation_ExtraTrivia() /*comment1*/!/*comment2*/) { }", options: TestOptions.RegularPreview, // (2,1): error CS1003: Syntax error, '!!' expected // /*comment1*/!/*comment2*/) { } - Diagnostic(ErrorCode.ERR_SyntaxError, " ").WithArguments("!!", "!").WithLocation(2, 1)); + Diagnostic(ErrorCode.ERR_SyntaxError, " ").WithArguments("!!").WithLocation(2, 1)); N(SyntaxKind.LocalFunctionStatement); { @@ -7495,7 +7495,7 @@ public void TestNullCheckedArgList1() UsingStatement(@"void M(__arglist!) { }", options: TestOptions.RegularPreview, // (1,17): error CS1003: Syntax error, ',' expected // void M(__arglist!) { } - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(1, 17)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",").WithLocation(1, 17)); N(SyntaxKind.LocalFunctionStatement); { N(SyntaxKind.PredefinedType); @@ -7527,7 +7527,7 @@ public void TestNullCheckedArgList2() UsingStatement(@"void M(__arglist!!) { }", options: TestOptions.RegularPreview, // (1,17): error CS1003: Syntax error, ',' expected // void M(__arglist!!) { } - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(1, 17)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",").WithLocation(1, 17)); N(SyntaxKind.LocalFunctionStatement); { N(SyntaxKind.PredefinedType); @@ -7559,7 +7559,7 @@ public void TestNullCheckedArgList3() UsingStatement(@"void M(__arglist!! = null) { }", options: TestOptions.RegularPreview, // (1,17): error CS1003: Syntax error, ',' expected // void M(__arglist!! = null) { } - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(1, 17)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",").WithLocation(1, 17)); N(SyntaxKind.LocalFunctionStatement); { N(SyntaxKind.PredefinedType); @@ -7591,7 +7591,7 @@ public void TestNullCheckedArgList4() UsingStatement(@"void M(__arglist!!= null) { }", options: TestOptions.RegularPreview, // (1,17): error CS1003: Syntax error, ',' expected // void M(__arglist!!= null) { } - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(1, 17)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",").WithLocation(1, 17)); N(SyntaxKind.LocalFunctionStatement); { N(SyntaxKind.PredefinedType); @@ -7623,7 +7623,7 @@ public void TestNullCheckedArgList5() UsingStatement(@"void M(__arglist[]!!= null) { }", options: TestOptions.RegularPreview, // (1,17): error CS1003: Syntax error, ',' expected // void M(__arglist[]!!= null) { } - Diagnostic(ErrorCode.ERR_SyntaxError, "[").WithArguments(",", "[").WithLocation(1, 17), + Diagnostic(ErrorCode.ERR_SyntaxError, "[").WithArguments(",").WithLocation(1, 17), // (1,18): error CS1001: Identifier expected // void M(__arglist[]!!= null) { } Diagnostic(ErrorCode.ERR_IdentifierExpected, "]").WithLocation(1, 18), @@ -7694,7 +7694,7 @@ public void TestArgListWithBrackets() UsingStatement(@"void M(__arglist[]) { }", options: TestOptions.RegularPreview, // (1,17): error CS1003: Syntax error, ',' expected // void M(__arglist[]) { } - Diagnostic(ErrorCode.ERR_SyntaxError, "[").WithArguments(",", "[").WithLocation(1, 17), + Diagnostic(ErrorCode.ERR_SyntaxError, "[").WithArguments(",").WithLocation(1, 17), // (1,18): error CS1001: Identifier expected // void M(__arglist[]) { } Diagnostic(ErrorCode.ERR_IdentifierExpected, "]").WithLocation(1, 18), @@ -7756,7 +7756,7 @@ public void TestArgListWithDefaultValue() UsingStatement(@"void M(__arglist = null) { }", options: TestOptions.RegularPreview, // (1,18): error CS1003: Syntax error, ',' expected // void M(__arglist = null) { } - Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments(",", "=").WithLocation(1, 18)); + Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments(",").WithLocation(1, 18)); N(SyntaxKind.LocalFunctionStatement); { N(SyntaxKind.PredefinedType); @@ -7952,7 +7952,7 @@ public void TestNullCheckedArgWithSpaceInbetween() UsingStatement(@"void M(string name! !=null) { }", options: TestOptions.RegularPreview, // (1,19): error CS1003: Syntax error, '!!' expected // void M(string name! !=null) { } - Diagnostic(ErrorCode.ERR_SyntaxError, "! !=").WithArguments("!!", "!").WithLocation(1, 19)); + Diagnostic(ErrorCode.ERR_SyntaxError, "! !=").WithArguments("!!").WithLocation(1, 19)); N(SyntaxKind.LocalFunctionStatement); { N(SyntaxKind.PredefinedType); @@ -8038,7 +8038,7 @@ public void TestNullCheckedArgWithSpaceAfterBangs() UsingStatement(@"void M(string name! ! =null) { }", options: TestOptions.RegularPreview, // (1,19): error CS1003: Syntax error, '!!' expected // void M(string name! ! =null) { } - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(1, 19)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(1, 19)); N(SyntaxKind.LocalFunctionStatement); { N(SyntaxKind.PredefinedType); @@ -8083,7 +8083,7 @@ public void TestNullCheckedArgWithSpaceBeforeBangs() UsingStatement(@"void M(string name ! !=null) { }", options: TestOptions.RegularPreview, // (1,20): error CS1003: Syntax error, '!!' expected // void M(string name ! !=null) { } - Diagnostic(ErrorCode.ERR_SyntaxError, "! !=").WithArguments("!!", "!").WithLocation(1, 20)); + Diagnostic(ErrorCode.ERR_SyntaxError, "! !=").WithArguments("!!").WithLocation(1, 20)); N(SyntaxKind.LocalFunctionStatement); { N(SyntaxKind.PredefinedType); @@ -8476,7 +8476,7 @@ class B : A' expected // class B : A", "{").WithLocation(2, 16)); + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(">").WithLocation(2, 16)); N(SyntaxKind.CompilationUnit); { @@ -8569,7 +8569,7 @@ class B : A' expected // class B : A", "").WithLocation(2, 22)); + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(">").WithLocation(2, 22)); N(SyntaxKind.CompilationUnit); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs index c167d2bc46bc0..fee620a78b8cb 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeconstructionTests.cs @@ -3245,7 +3245,7 @@ public void BadTypeForDeconstruct_06() UsingStatement(@"var? (x, y) = e;", // (1,16): error CS1003: Syntax error, ':' expected // var? (x, y) = e; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":", ";").WithLocation(1, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":").WithLocation(1, 16), // (1,16): error CS1525: Invalid expression term ';' // var? (x, y) = e; Diagnostic(ErrorCode.ERR_InvalidExprTerm, ";").WithArguments(";").WithLocation(1, 16) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs index 6773ef3c060f8..61aff46fd40a4 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs @@ -2775,7 +2775,7 @@ async void M() Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(6, 14), // (6,24): error CS1003: Syntax error, ',' expected // Task.await Task.Delay(); - Diagnostic(ErrorCode.ERR_SyntaxError, ".").WithArguments(",", ".").WithLocation(6, 24), + Diagnostic(ErrorCode.ERR_SyntaxError, ".").WithArguments(",").WithLocation(6, 24), // (6,25): error CS1002: ; expected // Task.await Task.Delay(); Diagnostic(ErrorCode.ERR_SemicolonExpected, "Delay").WithLocation(6, 25)); @@ -5489,7 +5489,7 @@ public void RangeExpression_ConditionalAccessExpression() UsingExpression("c?..b", // (1,6): error CS1003: Syntax error, ':' expected // c?..b - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 6), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 6), // (1,6): error CS1733: Expected expression // c?..b Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 6)); @@ -5946,7 +5946,7 @@ public void ArrayCreation_BadInElementAccess() UsingExpression("new[] { in[] }", // (1,9): error CS1003: Syntax error, ',' expected // new[] { in[] } - Diagnostic(ErrorCode.ERR_SyntaxError, "in").WithArguments(",", "in").WithLocation(1, 9)); + Diagnostic(ErrorCode.ERR_SyntaxError, "in").WithArguments(",").WithLocation(1, 9)); N(SyntaxKind.ImplicitArrayCreationExpression); { @@ -5969,7 +5969,7 @@ public void ArrayCreation_BadOutElementAccess() UsingExpression("new[] { out[] }", // (1,9): error CS1003: Syntax error, ',' expected // new[] { out[] } - Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",", "out").WithLocation(1, 9)); + Diagnostic(ErrorCode.ERR_SyntaxError, "out").WithArguments(",").WithLocation(1, 9)); N(SyntaxKind.ImplicitArrayCreationExpression); { @@ -6057,7 +6057,7 @@ void M() Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(")").WithLocation(7, 33), // (7,33): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}"); - Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(",", "}").WithLocation(7, 33), + Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(",").WithLocation(7, 33), // (7,34): error CS1026: ) expected // A B = new C($@"{D(.E}"); Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 34) @@ -6094,37 +6094,37 @@ void M() Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(")").WithLocation(7, 33), // (7,33): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); - Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(",", "}").WithLocation(7, 33), + Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(",").WithLocation(7, 33), // (7,34): error CS1056: Unexpected character '\' // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "").WithArguments("\\").WithLocation(7, 34), // (7,35): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); - Diagnostic(ErrorCode.ERR_SyntaxError, "F").WithArguments(",", "").WithLocation(7, 35), + Diagnostic(ErrorCode.ERR_SyntaxError, "F").WithArguments(",").WithLocation(7, 35), // (7,36): error CS1056: Unexpected character '\' // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); Diagnostic(ErrorCode.ERR_UnexpectedCharacter, "").WithArguments("\\").WithLocation(7, 36), // (7,37): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); - Diagnostic(ErrorCode.ERR_SyntaxError, "G").WithArguments(",", "").WithLocation(7, 37), + Diagnostic(ErrorCode.ERR_SyntaxError, "G").WithArguments(",").WithLocation(7, 37), // (7,38): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(7, 38), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(7, 38), // (7,39): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); - Diagnostic(ErrorCode.ERR_SyntaxError, "H").WithArguments(",", "").WithLocation(7, 39), + Diagnostic(ErrorCode.ERR_SyntaxError, "H").WithArguments(",").WithLocation(7, 39), // (7,40): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); - Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(",", "}").WithLocation(7, 40), + Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments(",").WithLocation(7, 40), // (7,41): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); - Diagnostic(ErrorCode.ERR_SyntaxError, "_").WithArguments(",", "").WithLocation(7, 41), + Diagnostic(ErrorCode.ERR_SyntaxError, "_").WithArguments(",").WithLocation(7, 41), // (7,42): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(7, 42), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(7, 42), // (7,43): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); - Diagnostic(ErrorCode.ERR_SyntaxError, "I").WithArguments(",", "").WithLocation(7, 43), + Diagnostic(ErrorCode.ERR_SyntaxError, "I").WithArguments(",").WithLocation(7, 43), // (7,49): error CS1026: ) expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 49), @@ -6133,10 +6133,10 @@ void M() Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(7, 49), // (7,50): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); - Diagnostic(ErrorCode.ERR_SyntaxError, "L").WithArguments(",", "").WithLocation(7, 50), + Diagnostic(ErrorCode.ERR_SyntaxError, "L").WithArguments(",").WithLocation(7, 50), // (7,51): error CS1003: Syntax error, ',' expected // A B = new C($@"{D(.E}\F\G{H}_{I.J.K("L")}.M"); - Diagnostic(ErrorCode.ERR_SyntaxError, @""")}.M""").WithArguments(",", "").WithLocation(7, 51) + Diagnostic(ErrorCode.ERR_SyntaxError, @""")}.M""").WithArguments(",").WithLocation(7, 51) ); } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FunctionPointerTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FunctionPointerTests.cs index 4b05f249edeb9..63e162322c70f 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/FunctionPointerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FunctionPointerTests.cs @@ -143,7 +143,7 @@ public void KeywordInCallingConventionList() Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "void").WithArguments("", "void").WithLocation(1, 21), // (1,21): error CS1003: Syntax error, ',' expected // delegate* unmanaged[void] ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments(",", "void").WithLocation(1, 21) + Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments(",").WithLocation(1, 21) ); N(SyntaxKind.LocalDeclarationStatement); @@ -289,7 +289,7 @@ public void InvalidConventionWithUnmanagedSpecifiers() UsingStatement("delegate* invalid[Cdecl] ptr;", options: TestOptions.RegularPreview, // (1,11): error CS1003: Syntax error, 'unmanaged' expected // delegate* invalid[Cdecl] ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, "invalid").WithArguments("unmanaged", "").WithLocation(1, 11) + Diagnostic(ErrorCode.ERR_SyntaxError, "invalid").WithArguments("unmanaged").WithLocation(1, 11) ); N(SyntaxKind.LocalDeclarationStatement); { @@ -341,7 +341,7 @@ public void InvalidConventionFollowedByTypeArguments() UsingStatement("delegate* invalid ptr;", options: TestOptions.RegularPreview, // (1,11): error CS1003: Syntax error, 'managed' expected // delegate* invalid - Diagnostic(ErrorCode.ERR_SyntaxError, "invalid").WithArguments("managed", "").WithLocation(1, 11)); + Diagnostic(ErrorCode.ERR_SyntaxError, "invalid").WithArguments("managed").WithLocation(1, 11)); N(SyntaxKind.LocalDeclarationStatement); { N(SyntaxKind.VariableDeclaration); @@ -851,7 +851,7 @@ public void Unterminated_01() Diagnostic(ErrorCode.ERR_TypeExpected, ";").WithLocation(1, 12), // (1,12): error CS1003: Syntax error, '>' expected // delegate*< ; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">", ";").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">").WithLocation(1, 12), // (1,12): error CS1001: Identifier expected // delegate*< ; Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 12)); @@ -895,7 +895,7 @@ public void Unterminated_02() Diagnostic(ErrorCode.ERR_TypeExpected, ";").WithLocation(1, 15), // (1,15): error CS1003: Syntax error, '>' expected // delegate*", ";").WithLocation(1, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">").WithLocation(1, 15), // (1,15): error CS1001: Identifier expected // delegate*' expected // delegate*", ";").WithLocation(1, 19), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">").WithLocation(1, 19), // (1,19): error CS1001: Identifier expected // delegate*' expected // delegate*", ";").WithLocation(1, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">").WithLocation(1, 20), // (1,20): error CS1001: Identifier expected // delegate*' expected // delegate*( ; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">", ";").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">").WithLocation(1, 12), // (1,12): error CS1001: Identifier expected // delegate*( ; Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 12)); @@ -1358,10 +1358,10 @@ public void Unterminated_11() UsingStatement("delegate* @cdecl>", options: TestOptions.Regular9, // (1,11): error CS1003: Syntax error, '<' expected // delegate* @cdecl> - Diagnostic(ErrorCode.ERR_SyntaxError, "@cdecl").WithArguments("<", "").WithLocation(1, 11), + Diagnostic(ErrorCode.ERR_SyntaxError, "@cdecl").WithArguments("<").WithLocation(1, 11), // (1,17): error CS1003: Syntax error, ',' expected // delegate* @cdecl> - Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments(",", ">").WithLocation(1, 17), + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments(",").WithLocation(1, 17), // (1,18): error CS1002: ; expected // delegate* @cdecl> Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 18)); @@ -1405,10 +1405,10 @@ public void Unterminated_12() Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 22), // (1,22): error CS1003: Syntax error, ']' expected // delegate* unmanaged[ ; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]", ";").WithLocation(1, 22), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]").WithLocation(1, 22), // (1,22): error CS1003: Syntax error, '<' expected // delegate* unmanaged[ ; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("<", "").WithLocation(1, 22), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("<").WithLocation(1, 22), // (1,22): error CS1001: Identifier expected // delegate* unmanaged[ ; Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 22) @@ -1463,10 +1463,10 @@ public void Unterminated_13() UsingStatement("delegate* unmanaged[Cdecl ;", options: TestOptions.RegularPreview, // (1,27): error CS1003: Syntax error, ']' expected // delegate* unmanaged[Cdecl ; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]", ";").WithLocation(1, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]").WithLocation(1, 27), // (1,27): error CS1003: Syntax error, '<' expected // delegate* unmanaged[Cdecl ; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("<", "").WithLocation(1, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("<").WithLocation(1, 27), // (1,27): error CS1001: Identifier expected // delegate* unmanaged[Cdecl ; Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 27) @@ -1524,10 +1524,10 @@ public void Unterminated_14() Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 27), // (1,27): error CS1003: Syntax error, ']' expected // delegate* unmanaged[Cdecl, - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]", "").WithLocation(1, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(1, 27), // (1,27): error CS1003: Syntax error, '<' expected // delegate* unmanaged[Cdecl, - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<", "").WithLocation(1, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<").WithLocation(1, 27), // (1,27): error CS1001: Identifier expected // delegate* unmanaged[Cdecl, Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 27), @@ -1628,10 +1628,10 @@ public void UsingParensInsteadOfAngles() UsingStatement("delegate*(int, void)", options: TestOptions.Regular9, // (1,10): error CS1003: Syntax error, '<' expected // delegate*(int, void) - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("<", "(").WithLocation(1, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("<").WithLocation(1, 10), // (1,20): error CS1003: Syntax error, '>' expected // delegate*(int, void) - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(">", ")").WithLocation(1, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(">").WithLocation(1, 20), // (1,21): error CS1001: Identifier expected // delegate*(int, void) Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 21), @@ -3046,10 +3046,10 @@ public void SpecifiedParameterNamesAndDefaults() UsingStatement("delegate* ptr;", options: TestOptions.Regular9, // (1,15): error CS1003: Syntax error, ',' expected // delegate* ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, "param1").WithArguments(",", "").WithLocation(1, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "param1").WithArguments(",").WithLocation(1, 15), // (1,30): error CS1003: Syntax error, ',' expected // delegate* ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, "param2").WithArguments(",", "").WithLocation(1, 30)); + Diagnostic(ErrorCode.ERR_SyntaxError, "param2").WithArguments(",").WithLocation(1, 30)); N(SyntaxKind.LocalDeclarationStatement); { N(SyntaxKind.VariableDeclaration); @@ -3103,13 +3103,13 @@ public void MissingListStart_01() UsingStatement("delegate*void> ptr;", options: TestOptions.Regular9, // (1,10): error CS1003: Syntax error, '<' expected // delegate*void> ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments("<", "").WithLocation(1, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments("<").WithLocation(1, 10), // (1,10): error CS1001: Identifier expected // delegate*void> ptr; Diagnostic(ErrorCode.ERR_IdentifierExpected, "void").WithLocation(1, 10), // (1,10): error CS1003: Syntax error, ',' expected // delegate*void> ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments(",", "void").WithLocation(1, 10)); + Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments(",").WithLocation(1, 10)); N(SyntaxKind.LocalDeclarationStatement); { N(SyntaxKind.VariableDeclaration); @@ -3147,13 +3147,13 @@ public void MissingListStart_02() UsingStatement("delegate* unmanaged[cdecl] void> ptr;", options: TestOptions.Regular9, // (1,28): error CS1003: Syntax error, '<' expected // delegate* unmanaged[cdecl] void> ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments("<", "").WithLocation(1, 28), + Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments("<").WithLocation(1, 28), // (1,28): error CS1001: Identifier expected // delegate* unmanaged[cdecl] void> ptr; Diagnostic(ErrorCode.ERR_IdentifierExpected, "void").WithLocation(1, 28), // (1,28): error CS1003: Syntax error, ',' expected // delegate* unmanaged[cdecl] void> ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments(",", "void").WithLocation(1, 28)); + Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments(",").WithLocation(1, 28)); N(SyntaxKind.LocalDeclarationStatement); { N(SyntaxKind.VariableDeclaration); @@ -3204,7 +3204,7 @@ public void MissingListStart_03() UsingStatement("delegate*> ptr;", options: TestOptions.Regular9, // (1,10): error CS1003: Syntax error, '<' expected // delegate*> ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments("<", "").WithLocation(1, 10)); + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments("<").WithLocation(1, 10)); N(SyntaxKind.LocalDeclarationStatement); { N(SyntaxKind.VariableDeclaration); @@ -3242,10 +3242,10 @@ public void MissingListStart_04() UsingStatement("delegate* unmanaged Cdecl] ptr;", options: TestOptions.RegularPreview, // (1,21): error CS1003: Syntax error, '<' expected // delegate* unmanaged Cdecl] ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, "Cdecl").WithArguments("<", "").WithLocation(1, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, "Cdecl").WithArguments("<").WithLocation(1, 21), // (1,26): error CS1003: Syntax error, ',' expected // delegate* unmanaged Cdecl] ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, "]").WithArguments(",", "]").WithLocation(1, 26) + Diagnostic(ErrorCode.ERR_SyntaxError, "]").WithArguments(",").WithLocation(1, 26) ); N(SyntaxKind.LocalDeclarationStatement); { @@ -3628,7 +3628,7 @@ public void IncompleteAtEndOfFile() UsingStatement("delegate*", options: TestOptions.Regular9, // (1,10): error CS1003: Syntax error, '<' expected // delegate* - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<", "").WithLocation(1, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<").WithLocation(1, 10), // (1,10): error CS1001: Identifier expected // delegate* Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 10), @@ -3672,7 +3672,7 @@ public void IncompleteAtEndOfFileWithCallingConvention() UsingStatement("delegate* unmanaged[cdecl]", options: TestOptions.Regular9, // (1,27): error CS1003: Syntax error, '<' expected // delegate* unmanaged[cdecl] - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<", "").WithLocation(1, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<").WithLocation(1, 27), // (1,27): error CS1001: Identifier expected // delegate* unmanaged[cdecl] Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 27), @@ -3729,10 +3729,10 @@ public void MixedParensAndAngles_01() UsingStatement("delegate* unmanaged[cdecl]' expected // delegate* unmanaged[cdecl]", ";").WithLocation(1, 37), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">").WithLocation(1, 37), // (1,37): error CS1001: Identifier expected // delegate* unmanaged[cdecl] ptr;", options: TestOptions.Regular9, // (1,27): error CS1003: Syntax error, '<' expected // delegate* unmanaged[cdecl](void> ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("<", "(").WithLocation(1, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("<").WithLocation(1, 27), // (1,32): error CS1003: Syntax error, ',' expected // delegate* unmanaged[cdecl](void> ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments(",", ">").WithLocation(1, 32), + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments(",").WithLocation(1, 32), // (1,37): error CS1003: Syntax error, '>' expected // delegate* unmanaged[cdecl](void> ptr; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">", ";").WithLocation(1, 37), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">").WithLocation(1, 37), // (1,37): error CS1001: Identifier expected // delegate* unmanaged[cdecl](void> ptr; Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 37)); @@ -3851,7 +3851,7 @@ void C() }}", options: TestOptions.Regular9, // (5,21): error CS1003: Syntax error, '<' expected // unmanaged[Cdecl] - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<", "").WithLocation(5, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<").WithLocation(5, 21), // (5,21): error CS1001: Identifier expected // unmanaged[Cdecl] Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(5, 21), @@ -3938,7 +3938,7 @@ void C() }", options: TestOptions.Regular9, // (4,14): error CS1003: Syntax error, '<' expected // delegate* - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<", "").WithLocation(4, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<").WithLocation(4, 14), // (4,14): error CS1001: Identifier expected // delegate* Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 14), diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs index 005d2a46705eb..a857a655ae249 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs @@ -1063,7 +1063,7 @@ public void CollectionInitializer_01() UsingExpression("new B { [A] x => y }", TestOptions.RegularPreview, // (1,13): error CS1003: Syntax error, '=' expected // new B { [A] x => y } - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments("=", "").WithLocation(1, 13)); + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments("=").WithLocation(1, 13)); N(SyntaxKind.ObjectCreationExpression); { @@ -1945,7 +1945,7 @@ public void Range_02() UsingExpression("s[..[A] () => { }]", TestOptions.RegularPreview, // (1,5): error CS1003: Syntax error, ',' expected // s[..[A] () => { }] - Diagnostic(ErrorCode.ERR_SyntaxError, "[").WithArguments(",", "[").WithLocation(1, 5)); + Diagnostic(ErrorCode.ERR_SyntaxError, "[").WithArguments(",").WithLocation(1, 5)); N(SyntaxKind.ElementAccessExpression); { @@ -2381,7 +2381,7 @@ public void NullableType_Is_05() Diagnostic(ErrorCode.ERR_UnexpectedToken, "_ = x is string ? [return: A] y").WithArguments("=>").WithLocation(1, 1), // (1,20): error CS1003: Syntax error, ',' expected // _ = x is string ? [return: A] y => y : z - Diagnostic(ErrorCode.ERR_SyntaxError, "return").WithArguments(",", "return").WithLocation(1, 20)); + Diagnostic(ErrorCode.ERR_SyntaxError, "return").WithArguments(",").WithLocation(1, 20)); N(SyntaxKind.SimpleAssignmentExpression); { @@ -2686,10 +2686,10 @@ public void CollectionInitializer_03() UsingExpression(source, // (1,13): error CS1003: Syntax error, '=' expected // new() { [A] x => x, [B] () => { } } - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments("=", "").WithLocation(1, 13), + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments("=").WithLocation(1, 13), // (1,25): error CS1003: Syntax error, '=' expected // new() { [A] x => x, [B] () => { } } - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("=", "(").WithLocation(1, 25)); + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("=").WithLocation(1, 25)); N(SyntaxKind.ImplicitObjectCreationExpression); { @@ -2949,7 +2949,7 @@ public void AnonymousType_02() UsingExpression(source, // (1,13): error CS1003: Syntax error, ',' expected // new { x [B] y => y } - Diagnostic(ErrorCode.ERR_SyntaxError, "y").WithArguments(",", "").WithLocation(1, 13)); + Diagnostic(ErrorCode.ERR_SyntaxError, "y").WithArguments(",").WithLocation(1, 13)); N(SyntaxKind.AnonymousObjectCreationExpression); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs index bae5578b1a96e..1014024de9675 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaParameterParsingTests.cs @@ -1119,7 +1119,7 @@ public void TestNullCheckedNoParams() Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(1, 22), // (1,24): error CS1003: Syntax error, ',' expected // Func func1 = (!!) => 42; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 24) + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 24) }); N(SyntaxKind.FieldDeclaration); { @@ -1229,7 +1229,7 @@ public void TestNullCheckedSyntaxCorrection0() UsingDeclaration("Func func0 = x!=> x;", options: TestOptions.RegularPreview, // (1,31): error CS1003: Syntax error, '!!' expected // Func func0 = x!=> x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(1, 31)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(1, 31)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -1285,7 +1285,7 @@ public void TestNullCheckedSyntaxCorrection1() UsingDeclaration("Func func1 = x !=> x;", options: TestOptions.RegularPreview, // (1,32): error CS1003: Syntax error, '!!' expected // Func func1 = x !=> x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(1, 32)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(1, 32)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -1341,10 +1341,10 @@ public void TestNullCheckedSyntaxCorrection2() UsingDeclaration("Func func2 = x != > x;", options: TestOptions.RegularPreview, // (1,32): error CS1003: Syntax error, '!!' expected // Func func2 = x != > x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(1, 32), + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(1, 32), // (1,33): error CS1003: Syntax error, '=>' expected // Func func2 = x != > x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("=>", "=").WithLocation(1, 33)); + Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("=>").WithLocation(1, 33)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -1400,7 +1400,7 @@ public void TestNullCheckedSyntaxCorrection3() UsingDeclaration("Func func3 = x! => x;", options: TestOptions.RegularPreview, // (1,33): error CS1003: Syntax error, ',' expected // Func func3 = x! => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 33)); + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 33)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -1450,7 +1450,7 @@ public void TestNullCheckedSyntaxCorrection4() UsingDeclaration("Func func4 = x ! => x;", options: TestOptions.RegularPreview, // (1,34): error CS1003: Syntax error, ',' expected // Func func4 = x ! => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 34)); + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 34)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -1552,7 +1552,7 @@ public void TestNullCheckedSyntaxCorrection6() UsingDeclaration("Func func6 = x !!= > x;", options: TestOptions.RegularPreview, // (1,34): error CS1003: Syntax error, '=>' expected // Func func6 = x !!= > x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("=>", "=").WithLocation(1, 34)); + Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("=>").WithLocation(1, 34)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -1660,7 +1660,7 @@ public void TestNullCheckedSyntaxCorrection8() UsingDeclaration("Func func8 = x! !=> x;", options: TestOptions.RegularPreview, // (1,31): error CS1003: Syntax error, '!!' expected // Func func8 = x! !=> x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(1, 31)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(1, 31)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -1716,7 +1716,7 @@ public void TestNullCheckedSyntaxCorrection9() UsingDeclaration("Func func9 = x! ! => x;", options: TestOptions.RegularPreview, // (1,31): error CS1003: Syntax error, '!!' expected // Func func9 = x! ! => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "! ").WithArguments("!!", "!").WithLocation(1, 31)); + Diagnostic(ErrorCode.ERR_SyntaxError, "! ").WithArguments("!!").WithLocation(1, 31)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -1775,7 +1775,7 @@ public void TestBracesAfterSimpleLambdaName() Diagnostic(ErrorCode.ERR_ValueExpected, "]").WithLocation(1, 34), // (1,36): error CS1003: Syntax error, ',' expected // Func func0 = x[] => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 36)); + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 36)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -1943,7 +1943,7 @@ public void TestBracesAfterParenthesizedLambdaTypeAndName() Diagnostic(ErrorCode.ERR_CloseParenExpected, "x").WithLocation(1, 40), // (1,40): error CS1003: Syntax error, ',' expected // Func func0 = (string x[]) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 40)); + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(1, 40)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2007,7 +2007,7 @@ public void TestDefaultValueSimpleLambda() UsingDeclaration("Func func0 = x = null => x;", options: TestOptions.RegularPreview, // (1,39): error CS1003: Syntax error, ',' expected // Func func0 = x = null => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 39)); + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 39)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2324,7 +2324,7 @@ public void TestNullCheckedDefaultValueSimpleLambda() UsingDeclaration("Func func0 = x!! = null => x;", options: TestOptions.RegularPreview, // (1,41): error CS1003: Syntax error, ',' expected // Func func0 = x!! = null => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 41)); + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 41)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2653,7 +2653,7 @@ public void TestNullCheckedSpaceBetweenSimpleLambda() UsingDeclaration("Func func0 = x! ! => x;", options: TestOptions.RegularPreview, // (1,31): error CS1003: Syntax error, '!!' expected // Func func0 = x! ! => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "! ").WithArguments("!!", "!").WithLocation(1, 31)); + Diagnostic(ErrorCode.ERR_SyntaxError, "! ").WithArguments("!!").WithLocation(1, 31)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2709,7 +2709,7 @@ public void TestNullCheckedSpaceBetweenParenthesizedLambda1() UsingDeclaration("Func func0 = (x! !) => x;", options: TestOptions.RegularPreview, // (1,32): error CS1003: Syntax error, '!!' expected // Func func0 = (x! !) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(1, 32)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(1, 32)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2770,7 +2770,7 @@ public void TestNullCheckedSpaceBetweenParenthesizedLambda2() UsingDeclaration("Func func0 = (y, x! !) => x;", options: TestOptions.RegularPreview, // (1,35): error CS1003: Syntax error, '!!' expected // Func func0 = (y, x! !) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(1, 35)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(1, 35)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2836,7 +2836,7 @@ public void TestNullCheckedSpaceBetweenLambdaWithType1() UsingDeclaration("Func func0 = (string x! !) => x;", options: TestOptions.RegularPreview, // (1,39): error CS1003: Syntax error, '!!' expected // Func func0 = (string x! !) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(1, 39)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(1, 39)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -2901,7 +2901,7 @@ public void TestNullCheckedSpaceBetweenLambdaWithType2() UsingDeclaration("Func func0 = (string y, string x! !) => x;", options: TestOptions.RegularPreview, // (1,49): error CS1003: Syntax error, '!!' expected // Func func0 = (string y, string x! !) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!", "!").WithLocation(1, 49)); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("!!").WithLocation(1, 49)); N(SyntaxKind.FieldDeclaration); { N(SyntaxKind.VariableDeclaration); @@ -3484,13 +3484,13 @@ public void MissingParameterName_02() Diagnostic(ErrorCode.ERR_IdentifierExpected, "=>").WithLocation(1, 3), // (1,9): error CS1003: Syntax error, ']' expected // [ => { } - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]", "").WithLocation(1, 9), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(1, 9), // (1,9): error CS1001: Identifier expected // [ => { } Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 9), // (1,9): error CS1003: Syntax error, '=>' expected // [ => { } - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("=>", "").WithLocation(1, 9), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("=>").WithLocation(1, 9), // (1,9): error CS1733: Expected expression // [ => { } Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9)); @@ -3535,7 +3535,7 @@ public void MissingParameterName_03() Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 9), // (1,9): error CS1003: Syntax error, '=>' expected // ( => { } - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("=>", "").WithLocation(1, 9), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("=>").WithLocation(1, 9), // (1,9): error CS1733: Expected expression // ( => { } Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 9)); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs index b0609099684ab..97e33c6f1b152 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs @@ -818,7 +818,7 @@ public void NullableReturnTypeOrConditional_05() UsingExpression(source, // (1,25): error CS1003: Syntax error, ':' expected // int.MaxValue? () => null - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 25), // (1,25): error CS1733: Expected expression // int.MaxValue? () => null Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 25)); @@ -1167,7 +1167,7 @@ public void NullableReturnTypeOrConditional_13() UsingExpression(source, // (1,14): error CS1003: Syntax error, ':' expected // T[0]? () => x - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 14), // (1,14): error CS1733: Expected expression // T[0]? () => x Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 14)); @@ -1362,7 +1362,7 @@ public void NullableReturnTypeOrConditional_17() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "?").WithArguments("?").WithLocation(1, 5), // (1,14): error CS1003: Syntax error, ':' expected // int*? () => x - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 14), // (1,14): error CS1733: Expected expression // int*? () => x Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 14)); @@ -1475,7 +1475,7 @@ public void NullableReturnTypeOrConditional_19() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "?").WithArguments("?").WithLocation(1, 16), // (1,25): error CS1003: Syntax error, ':' expected // delegate*? () => x - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 25), // (1,25): error CS1733: Expected expression // delegate*? () => x Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 25)); @@ -1888,7 +1888,7 @@ public void NullableReturnTypeOrConditional_29() UsingExpression(source, // (1,18): error CS1003: Syntax error, ':' expected // b? c? () => x : y - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 18), // (1,18): error CS1733: Expected expression // b? c? () => x : y Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 18)); @@ -3805,10 +3805,10 @@ public void InvocationOrLambda_05() UsingExpression(source, // (1,5): error CS1003: Syntax error, ',' expected // F(A a, B b) - Diagnostic(ErrorCode.ERR_SyntaxError, "a").WithArguments(",", "").WithLocation(1, 5), + Diagnostic(ErrorCode.ERR_SyntaxError, "a").WithArguments(",").WithLocation(1, 5), // (1,10): error CS1003: Syntax error, ',' expected // F(A a, B b) - Diagnostic(ErrorCode.ERR_SyntaxError, "b").WithArguments(",", "").WithLocation(1, 10)); + Diagnostic(ErrorCode.ERR_SyntaxError, "b").WithArguments(",").WithLocation(1, 10)); N(SyntaxKind.InvocationExpression); { @@ -3863,10 +3863,10 @@ public void InvocationOrLambda_06() UsingExpression(source, // (1,9): error CS1003: Syntax error, ',' expected // F(ref A a, out B b, in C c) - Diagnostic(ErrorCode.ERR_SyntaxError, "a").WithArguments(",", "").WithLocation(1, 9), + Diagnostic(ErrorCode.ERR_SyntaxError, "a").WithArguments(",").WithLocation(1, 9), // (1,26): error CS1003: Syntax error, ',' expected // F(ref A a, out B b, in C c) - Diagnostic(ErrorCode.ERR_SyntaxError, "c").WithArguments(",", "").WithLocation(1, 26)); + Diagnostic(ErrorCode.ERR_SyntaxError, "c").WithArguments(",").WithLocation(1, 26)); N(SyntaxKind.InvocationExpression); { @@ -3939,7 +3939,7 @@ public void InvocationOrLambda_07() UsingExpression(source, // (1,9): error CS1003: Syntax error, ',' expected // F(ref A a, - Diagnostic(ErrorCode.ERR_SyntaxError, "a").WithArguments(",", "").WithLocation(1, 9), + Diagnostic(ErrorCode.ERR_SyntaxError, "a").WithArguments(",").WithLocation(1, 9), // (1,11): error CS1733: Expected expression // F(ref A a, Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 11), @@ -4271,7 +4271,7 @@ public void SwitchExpression_01() UsingExpression(source, // (1,24): error CS1003: Syntax error, ',' expected // x switch { int () => 0 => 1 } - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 24), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 24), // (1,24): error CS8504: Pattern missing // x switch { int () => 0 => 1 } Diagnostic(ErrorCode.ERR_MissingPattern, "=>").WithLocation(1, 24)); @@ -4335,7 +4335,7 @@ public void SwitchExpression_02() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "{").WithArguments("{").WithLocation(1, 20), // (1,20): error CS1003: Syntax error, ',' expected // x switch { T () => { } => 1 } - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(1, 20)); + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(1, 20)); N(SyntaxKind.SwitchExpression); { @@ -4397,10 +4397,10 @@ public void SwitchExpression_03() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "static").WithArguments("static").WithLocation(1, 12), // (1,12): error CS1003: Syntax error, '=>' expected // x switch { static T? () => { } => 1 } - Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments("=>", "static").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_SyntaxError, "static").WithArguments("=>").WithLocation(1, 12), // (1,32): error CS1003: Syntax error, ',' expected // x switch { static T? () => { } => 1 } - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 32), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 32), // (1,32): error CS8504: Pattern missing // x switch { static T? () => { } => 1 } Diagnostic(ErrorCode.ERR_MissingPattern, "=>").WithLocation(1, 32)); @@ -4719,7 +4719,7 @@ public void Range_01() UsingExpression(source, // (1,10): error CS1003: Syntax error, ',' expected // s[..x () => { }] - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 10)); + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 10)); N(SyntaxKind.ElementAccessExpression); { @@ -5241,7 +5241,7 @@ void verify(string source, ParseOptions? parseOptions = null) UsingExpression(source, parseOptions, // (1,7): error CS1003: Syntax error, ',' expected // F(var x => x) - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 7)); + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(1, 7)); N(SyntaxKind.InvocationExpression); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LineSpanDirectiveParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LineSpanDirectiveParsingTests.cs index 5e9d8ca1f9b9d..c640a6dbd6a91 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LineSpanDirectiveParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LineSpanDirectiveParsingTests.cs @@ -350,7 +350,7 @@ public void Incomplete_02() UsingLineDirective(source, options: null, // (1,9): error CS1003: Syntax error, ',' expected // #line (1 - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",", "").WithLocation(1, 9)); + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(1, 9)); N(SyntaxKind.LineSpanDirectiveTrivia); { @@ -461,7 +461,7 @@ public void Incomplete_05() UsingLineDirective(source, options: null, // (1,13): error CS1003: Syntax error, '-' expected // #line (1, 2) - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("-", "").WithLocation(1, 13)); + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("-").WithLocation(1, 13)); N(SyntaxKind.LineSpanDirectiveTrivia); { @@ -498,7 +498,7 @@ public void Incomplete_06() UsingLineDirective(source, options: null, // (1,15): error CS1003: Syntax error, '(' expected // #line (1, 2) - - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "").WithLocation(1, 15)); + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(1, 15)); N(SyntaxKind.LineSpanDirectiveTrivia); { @@ -572,7 +572,7 @@ public void Incomplete_08() UsingLineDirective(source, options: null, // (1,18): error CS1003: Syntax error, ',' expected // #line (1, 2) - (3 - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",", "").WithLocation(1, 18)); + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(1, 18)); N(SyntaxKind.LineSpanDirectiveTrivia); { @@ -821,7 +821,7 @@ public void Missing_03() UsingLineDirective(source, options: null, // (1,10): error CS1003: Syntax error, ',' expected // #line (1 2) - (3, 4) "file.cs" - Diagnostic(ErrorCode.ERR_SyntaxError, "2").WithArguments(",", "").WithLocation(1, 10)); + Diagnostic(ErrorCode.ERR_SyntaxError, "2").WithArguments(",").WithLocation(1, 10)); N(SyntaxKind.LineSpanDirectiveTrivia); { @@ -932,7 +932,7 @@ public void Missing_06() UsingLineDirective(source, options: null, // (1,14): error CS1003: Syntax error, '-' expected // #line (1, 2) (3, 4) "file.cs" - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("-", "(").WithLocation(1, 14)); + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("-").WithLocation(1, 14)); N(SyntaxKind.LineSpanDirectiveTrivia); { @@ -969,7 +969,7 @@ public void Missing_07() UsingLineDirective(source, options: null, // (1,16): error CS1003: Syntax error, '(' expected // #line (1, 2) - 3, 4) "file.cs" - Diagnostic(ErrorCode.ERR_SyntaxError, "3").WithArguments("(", "").WithLocation(1, 16)); + Diagnostic(ErrorCode.ERR_SyntaxError, "3").WithArguments("(").WithLocation(1, 16)); N(SyntaxKind.LineSpanDirectiveTrivia); { @@ -1043,7 +1043,7 @@ public void Missing_09() UsingLineDirective(source, options: null, // (1,19): error CS1003: Syntax error, ',' expected // #line (1, 2) - (3 4) "file.cs" - Diagnostic(ErrorCode.ERR_SyntaxError, "4").WithArguments(",", "").WithLocation(1, 19)); + Diagnostic(ErrorCode.ERR_SyntaxError, "4").WithArguments(",").WithLocation(1, 19)); N(SyntaxKind.LineSpanDirectiveTrivia); { @@ -1413,7 +1413,7 @@ public void UnexpectedToken_08() UsingLineDirective(source, options: null, // (1,9): error CS1003: Syntax error, ',' expected // #line (1u, 2) - (3, 4) "file.cs" - Diagnostic(ErrorCode.ERR_SyntaxError, "u").WithArguments(",", "").WithLocation(1, 9)); + Diagnostic(ErrorCode.ERR_SyntaxError, "u").WithArguments(",").WithLocation(1, 9)); N(SyntaxKind.LineSpanDirectiveTrivia); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs index 6932b167ff190..7931cc1c4080d 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LocalFunctionParsingTests.cs @@ -1098,7 +1098,7 @@ void M() CreateCompilation(errorText).VerifyDiagnostics( // (11,19): error CS1003: Syntax error, '(' expected // goo) { } - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(", ")").WithLocation(11, 19), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(11, 19), // (7,19): error CS0080: Constraints are not allowed on non-generic declarations // goo() where T : IFace => 5; Diagnostic(ErrorCode.ERR_ConstraintOnlyAllowedOnGenericDecl, "where").WithLocation(7, 19), @@ -1768,7 +1768,7 @@ static async static void F2() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "static").WithArguments("static local functions", "8.0").WithLocation(5, 9), // (5,16): error CS1031: Type expected // static static void F1() { } - Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithArguments("static").WithLocation(5, 16), + Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithLocation(5, 16), // (5,16): error CS8652: The feature 'static local functions' is not available in C# 7.3. Please use language version 8.0 or greater. // static static void F1() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "static").WithArguments("static local functions", "8.0").WithLocation(5, 16), @@ -1777,7 +1777,7 @@ static async static void F2() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "static").WithArguments("static local functions", "8.0").WithLocation(6, 9), // (6,22): error CS1031: Type expected // static async static void F2() { } - Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithArguments("static").WithLocation(6, 22), + Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithLocation(6, 22), // (6,22): error CS8652: The feature 'static local functions' is not available in C# 7.3. Please use language version 8.0 or greater. // static async static void F2() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "static").WithArguments("static local functions", "8.0").WithLocation(6, 22) @@ -1789,19 +1789,19 @@ static async static void F2() { } UsingDeclaration(text, options: TestOptions.Regular8, // (5,16): error CS1031: Type expected // static static void F1() { } - Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithArguments("static").WithLocation(5, 16), + Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithLocation(5, 16), // (6,22): error CS1031: Type expected // static async static void F2() { } - Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithArguments("static").WithLocation(6, 22)); + Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithLocation(6, 22)); checkNodes(); UsingDeclaration(text, options: TestOptions.Regular9, // (5,16): error CS1031: Type expected // static static void F1() { } - Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithArguments("static").WithLocation(5, 16), + Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithLocation(5, 16), // (6,22): error CS1031: Type expected // static async static void F2() { } - Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithArguments("static").WithLocation(6, 22)); + Diagnostic(ErrorCode.ERR_TypeExpected, "static").WithLocation(6, 22)); checkNodes(); void checkNodes() diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs index 1ff541884e5ad..16450a921b738 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs @@ -491,7 +491,7 @@ public void UnsignedRightShiftOperator_02() UsingDeclaration("C operator > >>(C x, C y) => x;", options: options, // (1,14): error CS1003: Syntax error, '(' expected // C operator > >>(C x, C y) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments("(", ">").WithLocation(1, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments("(").WithLocation(1, 14), // (1,14): error CS1001: Identifier expected // C operator > >>(C x, C y) => x; Diagnostic(ErrorCode.ERR_IdentifierExpected, ">").WithLocation(1, 14), @@ -500,10 +500,10 @@ public void UnsignedRightShiftOperator_02() Diagnostic(ErrorCode.ERR_IdentifierExpected, "=>").WithLocation(1, 27), // (1,27): error CS1003: Syntax error, ',' expected // C operator > >>(C x, C y) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 27), // (1,30): error CS1003: Syntax error, ',' expected // C operator > >>(C x, C y) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(1, 30), // (1,31): error CS1001: Identifier expected // C operator > >>(C x, C y) => x; Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 31), @@ -574,7 +574,7 @@ public void UnsignedRightShiftOperator_03() UsingDeclaration("C operator >> >(C x, C y) => x;", options: options, // (1,15): error CS1003: Syntax error, '(' expected // C operator >> >(C x, C y) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments("(", ">").WithLocation(1, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments("(").WithLocation(1, 15), // (1,15): error CS1001: Identifier expected // C operator >> >(C x, C y) => x; Diagnostic(ErrorCode.ERR_IdentifierExpected, ">").WithLocation(1, 15), @@ -583,10 +583,10 @@ public void UnsignedRightShiftOperator_03() Diagnostic(ErrorCode.ERR_IdentifierExpected, "=>").WithLocation(1, 27), // (1,27): error CS1003: Syntax error, ',' expected // C operator >> >(C x, C y) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 27), // (1,30): error CS1003: Syntax error, ',' expected // C operator >> >(C x, C y) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(1, 30), // (1,31): error CS1001: Identifier expected // C operator >> >(C x, C y) => x; Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 31), @@ -657,7 +657,7 @@ public void UnsignedRightShiftOperator_04() UsingDeclaration("C operator >>>=(C x, C y) => x;", options: options, // (1,14): error CS1003: Syntax error, '(' expected // C operator >>>=(C x, C y) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, ">=").WithArguments("(", ">=").WithLocation(1, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, ">=").WithArguments("(").WithLocation(1, 14), // (1,14): error CS1001: Identifier expected // C operator >>>=(C x, C y) => x; Diagnostic(ErrorCode.ERR_IdentifierExpected, ">=").WithLocation(1, 14), @@ -666,10 +666,10 @@ public void UnsignedRightShiftOperator_04() Diagnostic(ErrorCode.ERR_IdentifierExpected, "=>").WithLocation(1, 27), // (1,27): error CS1003: Syntax error, ',' expected // C operator >>>=(C x, C y) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(1, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(1, 27), // (1,30): error CS1003: Syntax error, ',' expected // C operator >>>=(C x, C y) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",", "").WithLocation(1, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, "x").WithArguments(",").WithLocation(1, 30), // (1,31): error CS1001: Identifier expected // C operator >>>=(C x, C y) => x; Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 31), @@ -791,10 +791,10 @@ public void GenericAsyncTask_01() Diagnostic(ErrorCode.ERR_UnexpectedToken, "async Task' expected // async Task", "(").WithLocation(1, 41) + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(">").WithLocation(1, 41) ); N(SyntaxKind.IncompleteMember); { @@ -842,10 +842,10 @@ public void GenericPublicTask_01() Diagnostic(ErrorCode.ERR_UnexpectedToken, "public Task' expected // public Task", "(").WithLocation(1, 42) + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(">").WithLocation(1, 42) ); N(SyntaxKind.IncompleteMember); { @@ -893,7 +893,7 @@ public void GenericAsyncTask_02() Diagnostic(ErrorCode.ERR_UnexpectedToken, "async Task' expected // async Task", "(").WithLocation(1, 33) + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(">").WithLocation(1, 33) ); N(SyntaxKind.IncompleteMember); { @@ -936,7 +936,7 @@ public void GenericPublicTask_02() Diagnostic(ErrorCode.ERR_UnexpectedToken, "public Task' expected // public Task", "(").WithLocation(1, 34) + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(">").WithLocation(1, 34) ); N(SyntaxKind.IncompleteMember); { @@ -1613,7 +1613,7 @@ public void RequiredModifierConversion_02(CSharpParseOptions parseOptions) Diagnostic(ErrorCode.ERR_FeatureInPreview, "required ").WithArguments("static abstract members in interfaces").WithLocation(1, 17), // (1,26): error CS1003: Syntax error, '.' expected // static implicit required operator C(S s) {} - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 26) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 26) ); N(SyntaxKind.ConversionOperatorDeclaration); { @@ -1907,7 +1907,7 @@ public void OperatorDeclaration_ExplicitImplementation_02() Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(1, 8), // (1,16): error CS1003: Syntax error, 'operator' expected // public int N.I.implicit (int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator", "implicit").WithLocation(1, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(1, 16), // (1,16): error CS1019: Overloadable unary operator expected // public int N.I.implicit (int x) => x; Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "implicit").WithLocation(1, 16) @@ -1988,7 +1988,7 @@ public void OperatorDeclaration_ExplicitImplementation_03() Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(1, 8), // (1,16): error CS1003: Syntax error, 'operator' expected // public int N.I.explicit (int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator", "explicit").WithLocation(1, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator").WithLocation(1, 16), // (1,16): error CS1019: Overloadable unary operator expected // public int N.I.explicit (int x) => x; Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "explicit").WithLocation(1, 16) @@ -2066,7 +2066,7 @@ public void OperatorDeclaration_ExplicitImplementation_04() var errors = new[] { // (1,16): error CS1003: Syntax error, '.' expected // public int N.I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 16) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 16) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -2141,7 +2141,7 @@ public void OperatorDeclaration_ExplicitImplementation_05() var errors = new[] { // (1,14): error CS1003: Syntax error, '.' expected // public int I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 14) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 14) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -2617,7 +2617,7 @@ public void OperatorDeclaration_ExplicitImplementation_12() Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(1, 8), // (1,16): error CS1003: Syntax error, 'operator' expected // public int N.I.implicit (int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator", "implicit").WithLocation(1, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(1, 16), // (1,16): error CS1019: Overloadable unary operator expected // public int N.I.implicit (int x) => x; Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "implicit").WithLocation(1, 16) @@ -2702,7 +2702,7 @@ public void OperatorDeclaration_ExplicitImplementation_13() Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(1, 8), // (1,16): error CS1003: Syntax error, 'operator' expected // public int N.I.explicit (int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator", "explicit").WithLocation(1, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator").WithLocation(1, 16), // (1,16): error CS1019: Overloadable unary operator expected // public int N.I.explicit (int x) => x; Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "explicit").WithLocation(1, 16) @@ -2784,7 +2784,7 @@ public void OperatorDeclaration_ExplicitImplementation_14() var errors = new[] { // (1,16): error CS1003: Syntax error, '.' expected // public int N.I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 16) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 16) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -2863,7 +2863,7 @@ public void OperatorDeclaration_ExplicitImplementation_15() var errors = new[] { // (1,14): error CS1003: Syntax error, '.' expected // public int I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 14) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 14) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -3484,7 +3484,7 @@ public void OperatorDeclaration_ExplicitImplementation_24() Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(1, 1), // (1,9): error CS1003: Syntax error, 'operator' expected // int N.I.implicit (int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator", "implicit").WithLocation(1, 9), + Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(1, 9), // (1,9): error CS1019: Overloadable unary operator expected // int N.I.implicit (int x) => x; Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "implicit").WithLocation(1, 9) @@ -3564,7 +3564,7 @@ public void OperatorDeclaration_ExplicitImplementation_25() Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(1, 1), // (1,9): error CS1003: Syntax error, 'operator' expected // int N.I.explicit (int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator", "explicit").WithLocation(1, 9), + Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator").WithLocation(1, 9), // (1,16): error CS1019: Overloadable unary operator expected // int N.I.explicit (int x) => x; Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "explicit").WithLocation(1, 9) @@ -3641,7 +3641,7 @@ public void OperatorDeclaration_ExplicitImplementation_26() var errors = new[] { // (1,9): error CS1003: Syntax error, '.' expected // int N.I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 9) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 9) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -3715,7 +3715,7 @@ public void OperatorDeclaration_ExplicitImplementation_27() var errors = new[] { // (1,7): error CS1003: Syntax error, '.' expected // int I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 7) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 7) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -4184,7 +4184,7 @@ public void OperatorDeclaration_ExplicitImplementation_34() Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(1, 1), // (1,9): error CS1003: Syntax error, 'operator' expected // int N.I.implicit (int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator", "implicit").WithLocation(1, 9), + Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(1, 9), // (1,9): error CS1019: Overloadable unary operator expected // int N.I.implicit (int x) => x; Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "implicit").WithLocation(1, 9) @@ -4268,7 +4268,7 @@ public void OperatorDeclaration_ExplicitImplementation_35() Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(1, 1), // (1,9): error CS1003: Syntax error, 'operator' expected // int N.I.explicit (int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator", "explicit").WithLocation(1, 9), + Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator").WithLocation(1, 9), // (1,9): error CS1019: Overloadable unary operator expected // int N.I.explicit (int x) => x; Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "explicit").WithLocation(1, 9) @@ -4349,7 +4349,7 @@ public void OperatorDeclaration_ExplicitImplementation_36() var errors = new[] { // (1,9): error CS1003: Syntax error, '.' expected // int N.I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 9) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 9) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -4427,7 +4427,7 @@ public void OperatorDeclaration_ExplicitImplementation_37() var errors = new[] { // (1,7): error CS1003: Syntax error, '.' expected // int I operator +(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 7) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 7) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -5203,7 +5203,7 @@ public void ConversionDeclaration_ExplicitImplementation_02() var errors = new[] { // (1,1): error CS1003: Syntax error, 'explicit' expected // N.I.operator int(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "N").WithArguments("explicit", "").WithLocation(1, 1) + Diagnostic(ErrorCode.ERR_SyntaxError, "N").WithArguments("explicit").WithLocation(1, 1) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -5277,7 +5277,7 @@ public void ConversionDeclaration_ExplicitImplementation_03() var errors = new[] { // (1,1): error CS1003: Syntax error, 'explicit' expected // operator int(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("explicit", "operator").WithLocation(1, 1) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("explicit").WithLocation(1, 1) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -5328,7 +5328,7 @@ public void ConversionDeclaration_ExplicitImplementation_04() var errors = new[] { // (1,14): error CS1003: Syntax error, '.' expected // implicit N.I operator int(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 14) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 14) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -5402,7 +5402,7 @@ public void ConversionDeclaration_ExplicitImplementation_05() var errors = new[] { // (1,12): error CS1003: Syntax error, '.' expected // explicit I operator int(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 12) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -5834,10 +5834,10 @@ public void ConversionDeclaration_ExplicitImplementation_12() var errors = new[] { // (1,14): error CS1003: Syntax error, '.' expected // implicit N.I int(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(".", "int").WithLocation(1, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(".").WithLocation(1, 14), // (1,14): error CS1003: Syntax error, 'operator' expected // implicit N.I int(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments("operator", "int").WithLocation(1, 14) + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments("operator").WithLocation(1, 14) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -5915,7 +5915,7 @@ public void ConversionDeclaration_ExplicitImplementation_13() var errors = new[] { // (1,15): error CS1003: Syntax error, 'operator' expected // explicit N.I. int(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments("operator", "int").WithLocation(1, 15) + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments("operator").WithLocation(1, 15) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -5993,7 +5993,7 @@ public void ConversionDeclaration_ExplicitImplementation_14() var errors = new[] { // (1,14): error CS1003: Syntax error, '.' expected // implicit N.I operator int(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 14) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 14) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -6071,7 +6071,7 @@ public void ConversionDeclaration_ExplicitImplementation_15() var errors = new[] { // (1,12): error CS1003: Syntax error, '.' expected // explicit I operator int(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".", "operator").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 12) }; foreach (var options in new[] { TestOptions.Script, TestOptions.Regular }) @@ -6582,10 +6582,10 @@ public void ConversionDeclaration_ExplicitImplementation_23() UsingDeclaration("explicit I T(int x) => x;", options: options.WithLanguageVersion(LanguageVersion.Preview), // (1,12): error CS1003: Syntax error, '.' expected // explicit I T(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "T").WithArguments(".", "").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_SyntaxError, "T").WithArguments(".").WithLocation(1, 12), // (1,12): error CS1003: Syntax error, 'operator' expected // explicit I T(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "T").WithArguments("operator", "").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_SyntaxError, "T").WithArguments("operator").WithLocation(1, 12) ); N(SyntaxKind.ConversionOperatorDeclaration); @@ -6639,7 +6639,7 @@ public void ConversionDeclaration_ExplicitImplementation_24() UsingDeclaration("explicit I.T(int x) => x;", options: options.WithLanguageVersion(LanguageVersion.Preview), // (1,12): error CS1003: Syntax error, 'operator' expected // explicit I.T(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "T").WithArguments("operator", "").WithLocation(1, 12) + Diagnostic(ErrorCode.ERR_SyntaxError, "T").WithArguments("operator").WithLocation(1, 12) ); N(SyntaxKind.ConversionOperatorDeclaration); @@ -6852,10 +6852,10 @@ public void ConversionDeclaration_ExplicitImplementation_28() UsingDeclaration("explicit I.T1 T2(int x) => x;", options: options.WithLanguageVersion(LanguageVersion.Preview), // (1,15): error CS1003: Syntax error, '.' expected // explicit I.T1 T2(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "T2").WithArguments(".", "").WithLocation(1, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "T2").WithArguments(".").WithLocation(1, 15), // (1,15): error CS1003: Syntax error, 'operator' expected // explicit I.T1 T2(int x) => x; - Diagnostic(ErrorCode.ERR_SyntaxError, "T2").WithArguments("operator", "").WithLocation(1, 15) + Diagnostic(ErrorCode.ERR_SyntaxError, "T2").WithArguments("operator").WithLocation(1, 15) ); N(SyntaxKind.ConversionOperatorDeclaration); @@ -6969,7 +6969,7 @@ public void ConversionDeclaration_ExplicitImplementation_30() Diagnostic(ErrorCode.ERR_TypeExpected, ")").WithLocation(1, 29), // (1,30): error CS1003: Syntax error, '(' expected // explicit I.operator (int x, ); - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("(", ";").WithLocation(1, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("(").WithLocation(1, 30), // (1,30): error CS1026: ) expected // explicit I.operator (int x, ); Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(1, 30) @@ -7027,7 +7027,7 @@ public void ConversionDeclaration_ExplicitImplementation_31() UsingDeclaration("explicit I.operator (int x, int y);", options: options.WithLanguageVersion(LanguageVersion.Preview), // (1,35): error CS1003: Syntax error, '(' expected // explicit I.operator (int x, int y); - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("(", ";").WithLocation(1, 35), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("(").WithLocation(1, 35), // (1,35): error CS1026: ) expected // explicit I.operator (int x, int y); Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(1, 35) @@ -7135,7 +7135,7 @@ public void ConversionDeclaration_ExplicitImplementation_33() Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(1, 21), // (1,28): error CS1003: Syntax error, ',' expected // explicit I.operator (int x int y); - Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",", "int").WithLocation(1, 28) + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",").WithLocation(1, 28) ); N(SyntaxKind.ConversionOperatorDeclaration); @@ -7258,7 +7258,7 @@ public void ConversionDeclaration_ExplicitImplementation_35() var error = new[] { // (2,9): error CS1003: Syntax error, 'operator' expected // explicit - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("operator", "").WithLocation(2, 9), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("operator").WithLocation(2, 9), // (2,9): error CS1001: Identifier expected // explicit Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(2, 9) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs index 0b1b4d09bf01c..9df274fda8355 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/NullableParsingTests.cs @@ -541,7 +541,7 @@ public void NullCoalescingOperator_NullableType_Invalid() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "?").WithArguments("?").WithLocation(1, 9), // (1,12): error CS1003: Syntax error, ':' expected // x as T??? y - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 12), // (1,12): error CS1733: Expected expression // x as T??? y Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 12)); @@ -672,7 +672,7 @@ public void DeclarationPattern_NullableType() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "break").WithArguments("break").WithLocation(1, 25), // (1,25): error CS1003: Syntax error, ':' expected // switch (e) { case T? t: break; } - Diagnostic(ErrorCode.ERR_SyntaxError, "break").WithArguments(":", "break").WithLocation(1, 25)); + Diagnostic(ErrorCode.ERR_SyntaxError, "break").WithArguments(":").WithLocation(1, 25)); N(SyntaxKind.SwitchStatement); { N(SyntaxKind.SwitchKeyword); @@ -727,7 +727,7 @@ public void DeclarationPattern_NullableArray() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "T[]").WithArguments("type pattern", "9.0").WithLocation(1, 19), // (1,22): error CS1003: Syntax error, ':' expected // switch (e) { case T[]? t: break; } - Diagnostic(ErrorCode.ERR_SyntaxError, "?").WithArguments(":", "?").WithLocation(1, 22), + Diagnostic(ErrorCode.ERR_SyntaxError, "?").WithArguments(":").WithLocation(1, 22), // (1,22): error CS1513: } expected // switch (e) { case T[]? t: break; } Diagnostic(ErrorCode.ERR_RbraceExpected, "?").WithLocation(1, 22)); @@ -1273,7 +1273,7 @@ public void CreateNullableArray_01() Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 17), // (1,17): error CS1003: Syntax error, ':' expected // new object[,][]? - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 17), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 17), // (1,17): error CS1733: Expected expression // new object[,][]? Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 17) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs index 34a2ec972c160..b3473604b0dcb 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs @@ -269,13 +269,13 @@ public static int Main() Diagnostic(ErrorCode.ERR_InvalidArray, "5").WithLocation(6, 32), // (6,33): error CS1003: Syntax error, ',' expected // int[] arr = new int[5][5; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",", ";").WithLocation(6, 33), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",").WithLocation(6, 33), // (6,33): error CS0443: Syntax error; value expected // int[] arr = new int[5][5; Diagnostic(ErrorCode.ERR_ValueExpected, "").WithLocation(6, 33), // (6,33): error CS1003: Syntax error, ']' expected // int[] arr = new int[5][5; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]", ";").WithLocation(6, 33), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]").WithLocation(6, 33), // (6,33): error CS0178: Invalid rank specifier: expected ',' or ']' // int[] arr = new int[5][5; Diagnostic(ErrorCode.ERR_InvalidArray, "").WithLocation(6, 33) @@ -350,7 +350,7 @@ void Goo() { Diagnostic(ErrorCode.ERR_InvalidArray, "3").WithLocation(4, 22), // (4,24): error CS1003: Syntax error, ']' expected // var x = new[,3 { 1, 2, 3 }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]", "{").WithLocation(4, 24)); + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]").WithLocation(4, 24)); } [Fact, WorkItem(24701, "https://github.com/dotnet/roslyn/issues/24701")] @@ -370,7 +370,7 @@ void Goo() { Diagnostic(ErrorCode.ERR_InvalidArray, "3").WithLocation(4, 21), // (4,23): error CS1003: Syntax error, ']' expected // var x = new[3 { 1, 2, 3 }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]", "{").WithLocation(4, 23)); + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]").WithLocation(4, 23)); } [Fact, WorkItem(24701, "https://github.com/dotnet/roslyn/issues/24701")] @@ -390,7 +390,7 @@ void Goo() { Diagnostic(ErrorCode.ERR_InvalidArray, "3").WithLocation(4, 21), // (4,24): error CS1003: Syntax error, ']' expected // var x = new[3, { 1, 2, 3 }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]", "{").WithLocation(4, 24)); + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]").WithLocation(4, 24)); } [Fact, WorkItem(24701, "https://github.com/dotnet/roslyn/issues/24701")] @@ -478,7 +478,7 @@ void Goo() { ParseAndValidate(test, // (4,22): error CS1003: Syntax error, ']' expected // var x = new[ { 1, 2, 3 }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]", "{").WithLocation(4, 22)); + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]").WithLocation(4, 22)); } [Fact] @@ -647,7 +647,7 @@ partial delegate E { } Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(2, 20), // (2,20): error CS1003: Syntax error, '(' expected // partial delegate E { } - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("(", "{").WithLocation(2, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("(").WithLocation(2, 20), // (2,20): error CS1026: ) expected // partial delegate E { } Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(2, 20), @@ -1090,7 +1090,7 @@ public static int Main() // Semantic error // (6,25): error CS0400: The type or namespace name 'MyType' could not be found in the global namespace (are you missing an assembly reference?) CreateCompilation(test).VerifyDiagnostics( - Diagnostic(ErrorCode.ERR_GlobalSingleTypeNameNotFound, "MyType").WithArguments("MyType", "") + Diagnostic(ErrorCode.ERR_GlobalSingleTypeNameNotFound, "MyType").WithArguments("MyType") ); } @@ -1436,7 +1436,7 @@ static void ExampleMethod(int required, string 1 = ""default string"",int option Diagnostic(ErrorCode.ERR_IdentifierExpected, "1"), // (9,52): error CS1003: Syntax error, ',' expected // static void ExampleMethod(int required, string 1 = "default string",int optionalint = 10) - Diagnostic(ErrorCode.ERR_SyntaxError, "1").WithArguments(",", "")); + Diagnostic(ErrorCode.ERR_SyntaxError, "1").WithArguments(",")); } [Fact, WorkItem(542416, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542416")] @@ -1485,7 +1485,7 @@ static void Main() ParseAndValidate(test, // (5,40): error CS1003: Syntax error, ':' expected // static void M(int p2 = max is int?1,) - Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments(":", ","), + Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments(":"), // (5,40): error CS1525: Invalid expression term ',' // static void M(int p2 = max is int?1,) Diagnostic(ErrorCode.ERR_InvalidExprTerm, ",").WithArguments(","), @@ -1652,7 +1652,7 @@ public static void Main() { ParseAndValidate(test, // (8,15): error CS1003: Syntax error, ']' expected // a[); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(8, 15) + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(8, 15) ); } @@ -1674,7 +1674,7 @@ public void Main() var parsedTree = ParseWithRoundTripCheck(test); var firstDiag = parsedTree.GetDiagnostics().Take(1); - firstDiag.Verify(Diagnostic(ErrorCode.ERR_SyntaxError, "for").WithArguments("foreach", "for")); + firstDiag.Verify(Diagnostic(ErrorCode.ERR_SyntaxError, "for").WithArguments("foreach")); } [Fact] @@ -2678,7 +2678,7 @@ public operator ii(a aa) ParseAndValidate(test, // (13,16): error CS1003: Syntax error, 'explicit' expected // public operator ii(a aa) - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("explicit", "operator") + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("explicit") ); } @@ -2867,13 +2867,13 @@ public static A operator () Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(4, 19), // (4,23): error CS1003: Syntax error, 'operator' expected // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator", "explicit").WithLocation(4, 23), + Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator").WithLocation(4, 23), // (4,23): error CS1019: Overloadable unary operator expected // public static int explicit operator () Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "explicit").WithLocation(4, 23), // (4,32): error CS1003: Syntax error, '(' expected // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(", "operator").WithLocation(4, 32), + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(4, 32), // (4,32): error CS1041: Identifier expected; 'operator' is a keyword // public static int explicit operator () Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(4, 32), @@ -2885,7 +2885,7 @@ public static A operator () Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 43), // (4,43): error CS1003: Syntax error, ',' expected // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",", "{").WithLocation(4, 43), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(4, 43), // (6,17): error CS1026: ) expected // return 0; Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(6, 17), @@ -2894,7 +2894,7 @@ public static A operator () Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "(").WithLocation(8, 30), // (8,31): error CS1003: Syntax error, '(' expected // public static A operator () - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(", ")").WithLocation(8, 31), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(8, 31), // (12,1): error CS1022: Type or namespace definition, or end-of-file expected // } Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(12, 1) @@ -2922,13 +2922,13 @@ public static A operator () Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(4, 19), // (4,23): error CS1003: Syntax error, 'operator' expected // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator", "explicit").WithLocation(4, 23), + Diagnostic(ErrorCode.ERR_SyntaxError, "explicit").WithArguments("operator").WithLocation(4, 23), // (4,23): error CS1019: Overloadable unary operator expected // public static int explicit operator () Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "explicit").WithLocation(4, 23), // (4,32): error CS1003: Syntax error, '(' expected // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(", "operator").WithLocation(4, 32), + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(4, 32), // (4,32): error CS1041: Identifier expected; 'operator' is a keyword // public static int explicit operator () Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(4, 32), @@ -2943,7 +2943,7 @@ public static A operator () Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 43), // (4,43): error CS1003: Syntax error, ',' expected // public static int explicit operator () - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",", "{").WithLocation(4, 43), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(4, 43), // (6,17): error CS1026: ) expected // return 0; Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(6, 17), @@ -2952,7 +2952,7 @@ public static A operator () Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "(").WithLocation(8, 30), // (8,31): error CS1003: Syntax error, '(' expected // public static A operator () - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(", ")").WithLocation(8, 31), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(8, 31), // (12,1): error CS1022: Type or namespace definition, or end-of-file expected // } Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(12, 1) @@ -2993,7 +2993,7 @@ public static int Main() { Diagnostic(ErrorCode.ERR_IdentifierExpected, "long"), // (3,23): error CS1003: Syntax error, ',' expected // public void f(int long) { // CS1041 - Diagnostic(ErrorCode.ERR_SyntaxError, "long").WithArguments(",", "long"), + Diagnostic(ErrorCode.ERR_SyntaxError, "long").WithArguments(","), // (3,27): error CS1001: Identifier expected // public void f(int long) { // CS1041 Diagnostic(ErrorCode.ERR_IdentifierExpected, ")")); @@ -4243,30 +4243,30 @@ static void Main(string[] args) "; ParseAndValidate(test, - // (7,27): error CS1003: Syntax error, ':' expected - // int s = true ? x++, y++ : y++; // Invalid - Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments(":", ","), - // (7,27): error CS1525: Invalid expression term ',' - // int s = true ? x++, y++ : y++; // Invalid - Diagnostic(ErrorCode.ERR_InvalidExprTerm, ",").WithArguments(","), - // (7,30): error CS1002: ; expected - // int s = true ? x++, y++ : y++; // Invalid - Diagnostic(ErrorCode.ERR_SemicolonExpected, "++"), - // (7,33): error CS1525: Invalid expression term ':' - // int s = true ? x++, y++ : y++; // Invalid - Diagnostic(ErrorCode.ERR_InvalidExprTerm, ":").WithArguments(":"), - // (7,33): error CS1002: ; expected - // int s = true ? x++, y++ : y++; // Invalid - Diagnostic(ErrorCode.ERR_SemicolonExpected, ":"), - // (7,33): error CS1513: } expected - // int s = true ? x++, y++ : y++; // Invalid - Diagnostic(ErrorCode.ERR_RbraceExpected, ":"), - // (8,29): error CS1002: ; expected - // s = true ? x++ : x++, y++; // Invalid - Diagnostic(ErrorCode.ERR_SemicolonExpected, ","), - // (8,29): error CS1513: } expected - // s = true ? x++ : x++, y++; // Invalid - Diagnostic(ErrorCode.ERR_RbraceExpected, ",")); + // (7,27): error CS1003: Syntax error, ':' expected + // int s = true ? x++, y++ : y++; // Invalid + Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments(":").WithLocation(7, 27), + // (7,27): error CS1525: Invalid expression term ',' + // int s = true ? x++, y++ : y++; // Invalid + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ",").WithArguments(",").WithLocation(7, 27), + // (7,30): error CS1002: ; expected + // int s = true ? x++, y++ : y++; // Invalid + Diagnostic(ErrorCode.ERR_SemicolonExpected, "++").WithLocation(7, 30), + // (7,33): error CS1525: Invalid expression term ':' + // int s = true ? x++, y++ : y++; // Invalid + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ":").WithArguments(":").WithLocation(7, 33), + // (7,33): error CS1002: ; expected + // int s = true ? x++, y++ : y++; // Invalid + Diagnostic(ErrorCode.ERR_SemicolonExpected, ":").WithLocation(7, 33), + // (7,33): error CS1513: } expected + // int s = true ? x++, y++ : y++; // Invalid + Diagnostic(ErrorCode.ERR_RbraceExpected, ":").WithLocation(7, 33), + // (8,29): error CS1002: ; expected + // s = true ? x++ : x++, y++; // Invalid + Diagnostic(ErrorCode.ERR_SemicolonExpected, ",").WithLocation(8, 29), + // (8,29): error CS1513: } expected + // s = true ? x++ : x++, y++; // Invalid + Diagnostic(ErrorCode.ERR_RbraceExpected, ",").WithLocation(8, 29)); } [WorkItem(542229, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542229")] @@ -4297,24 +4297,24 @@ static void Main(string[] args) } "; ParseAndValidate(test, - // (5,23): error CS1525: Invalid expression term 'return' - // int s = 1>2 ? return 0: return 1; // Invalid - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "return").WithArguments("return"), - // (5,23): error CS1003: Syntax error, ':' expected - // int s = 1>2 ? return 0: return 1; // Invalid - Diagnostic(ErrorCode.ERR_SyntaxError, "return").WithArguments(":", "return"), - // (5,23): error CS1525: Invalid expression term 'return' - // int s = 1>2 ? return 0: return 1; // Invalid - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "return").WithArguments("return"), - // (5,23): error CS1002: ; expected - // int s = 1>2 ? return 0: return 1; // Invalid - Diagnostic(ErrorCode.ERR_SemicolonExpected, "return"), - // (5,31): error CS1002: ; expected - // int s = 1>2 ? return 0: return 1; // Invalid - Diagnostic(ErrorCode.ERR_SemicolonExpected, ":"), - // (5,31): error CS1513: } expected - // int s = 1>2 ? return 0: return 1; // Invalid - Diagnostic(ErrorCode.ERR_RbraceExpected, ":")); + // (5,23): error CS1525: Invalid expression term 'return' + // int s = 1>2 ? return 0: return 1; // Invalid + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "return").WithArguments("return").WithLocation(5, 23), + // (5,23): error CS1003: Syntax error, ':' expected + // int s = 1>2 ? return 0: return 1; // Invalid + Diagnostic(ErrorCode.ERR_SyntaxError, "return").WithArguments(":").WithLocation(5, 23), + // (5,23): error CS1525: Invalid expression term 'return' + // int s = 1>2 ? return 0: return 1; // Invalid + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "return").WithArguments("return").WithLocation(5, 23), + // (5,23): error CS1002: ; expected + // int s = 1>2 ? return 0: return 1; // Invalid + Diagnostic(ErrorCode.ERR_SemicolonExpected, "return").WithLocation(5, 23), + // (5,31): error CS1002: ; expected + // int s = 1>2 ? return 0: return 1; // Invalid + Diagnostic(ErrorCode.ERR_SemicolonExpected, ":").WithLocation(5, 31), + // (5,31): error CS1513: } expected + // int s = 1>2 ? return 0: return 1; // Invalid + Diagnostic(ErrorCode.ERR_RbraceExpected, ":").WithLocation(5, 31)); } [Fact] @@ -4333,24 +4333,24 @@ static int Main(string[] args) } "; ParseAndValidate(test, - // (5,24): error CS1525: Invalid expression term 'goto' - // int s = true ? goto lab1: goto lab2; // Invalid - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "goto").WithArguments("goto"), - // (5,24): error CS1003: Syntax error, ':' expected - // int s = true ? goto lab1: goto lab2; // Invalid - Diagnostic(ErrorCode.ERR_SyntaxError, "goto").WithArguments(":", "goto"), - // (5,24): error CS1525: Invalid expression term 'goto' - // int s = true ? goto lab1: goto lab2; // Invalid - Diagnostic(ErrorCode.ERR_InvalidExprTerm, "goto").WithArguments("goto"), - // (5,24): error CS1002: ; expected - // int s = true ? goto lab1: goto lab2; // Invalid - Diagnostic(ErrorCode.ERR_SemicolonExpected, "goto"), - // (5,33): error CS1002: ; expected - // int s = true ? goto lab1: goto lab2; // Invalid - Diagnostic(ErrorCode.ERR_SemicolonExpected, ":"), - // (5,33): error CS1513: } expected - // int s = true ? goto lab1: goto lab2; // Invalid - Diagnostic(ErrorCode.ERR_RbraceExpected, ":")); + // (5,24): error CS1525: Invalid expression term 'goto' + // int s = true ? goto lab1: goto lab2; // Invalid + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "goto").WithArguments("goto").WithLocation(5, 24), + // (5,24): error CS1003: Syntax error, ':' expected + // int s = true ? goto lab1: goto lab2; // Invalid + Diagnostic(ErrorCode.ERR_SyntaxError, "goto").WithArguments(":").WithLocation(5, 24), + // (5,24): error CS1525: Invalid expression term 'goto' + // int s = true ? goto lab1: goto lab2; // Invalid + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "goto").WithArguments("goto").WithLocation(5, 24), + // (5,24): error CS1002: ; expected + // int s = true ? goto lab1: goto lab2; // Invalid + Diagnostic(ErrorCode.ERR_SemicolonExpected, "goto").WithLocation(5, 24), + // (5,33): error CS1002: ; expected + // int s = true ? goto lab1: goto lab2; // Invalid + Diagnostic(ErrorCode.ERR_SemicolonExpected, ":").WithLocation(5, 33), + // (5,33): error CS1513: } expected + // int s = true ? goto lab1: goto lab2; // Invalid + Diagnostic(ErrorCode.ERR_RbraceExpected, ":").WithLocation(5, 33)); } [Fact] @@ -4425,10 +4425,10 @@ class C Diagnostic(ErrorCode.ERR_BadVarDecl, "(").WithLocation(4, 26), // (4,26): error CS1003: Syntax error, '[' expected // event System.Action E(); - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(4, 26), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(4, 26), // (4,27): error CS1003: Syntax error, ']' expected // event System.Action E(); - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(4, 27) + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(4, 27) ); } @@ -4625,13 +4625,13 @@ public static int Main () Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(3, 19), // (3,23): error CS1003: Syntax error, 'operator' expected // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator", "implicit").WithLocation(3, 23), + Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(3, 23), // (3,23): error CS1019: Overloadable unary operator expected // public static int implicit operator (goo f) { return 6; } // Error Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "implicit").WithLocation(3, 23), // (3,32): error CS1003: Syntax error, '(' expected // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(", "operator").WithLocation(3, 32), + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(3, 32), // (3,32): error CS1041: Identifier expected; 'operator' is a keyword // public static int implicit operator (goo f) { return 6; } // Error Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(3, 32), @@ -4643,7 +4643,7 @@ public static int Main () Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 49), // (3,49): error CS1003: Syntax error, ',' expected // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(3, 49), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 49), // (3,59): error CS1026: ) expected // public static int implicit operator (goo f) { return 6; } // Error Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(3, 59), @@ -4676,13 +4676,13 @@ public static int Main () Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "int").WithArguments("+").WithLocation(3, 19), // (3,23): error CS1003: Syntax error, 'operator' expected // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator", "implicit").WithLocation(3, 23), + Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(3, 23), // (3,23): error CS1019: Overloadable unary operator expected // public static int implicit operator (goo f) { return 6; } // Error Diagnostic(ErrorCode.ERR_OvlUnaryOperatorExpected, "implicit").WithLocation(3, 23), // (3,32): error CS1003: Syntax error, '(' expected // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(", "operator").WithLocation(3, 32), + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments("(").WithLocation(3, 32), // (3,32): error CS1041: Identifier expected; 'operator' is a keyword // public static int implicit operator (goo f) { return 6; } // Error Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "operator").WithArguments("", "operator").WithLocation(3, 32), @@ -4697,7 +4697,7 @@ public static int Main () Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 49), // (3,49): error CS1003: Syntax error, ',' expected // public static int implicit operator (goo f) { return 6; } // Error - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(3, 49), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 49), // (3,59): error CS1026: ) expected // public static int implicit operator (goo f) { return 6; } // Error Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(3, 59), @@ -5259,7 +5259,7 @@ static void Main(string[] args) Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(9, 36), // (9,36): error CS1003: Syntax error, ':' expected // Console.WriteLine("Hello")? - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(9, 36), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(9, 36), // (9,36): error CS1733: Expected expression // Console.WriteLine("Hello")? Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(9, 36), @@ -5447,7 +5447,7 @@ public static void Main() Diagnostic(ErrorCode.ERR_ConstValueRequired, "in"), // (12,35): error CS1003: Syntax error, ',' expected // var query13 = from const in expr1 join i in expr2 on const equals i select new { const, i }; - Diagnostic(ErrorCode.ERR_SyntaxError, "in").WithArguments(",", "in"), + Diagnostic(ErrorCode.ERR_SyntaxError, "in").WithArguments(","), // (12,38): error CS1002: ; expected // var query13 = from const in expr1 join i in expr2 on const equals i select new { const, i }; Diagnostic(ErrorCode.ERR_SemicolonExpected, "expr1"), @@ -5703,7 +5703,7 @@ class TestClass { }"; tree.GetDiagnostics().Verify( // (1,6): error CS1003: Syntax error, ',' expected // [One Two] // error: missing comma - Diagnostic(ErrorCode.ERR_SyntaxError, "Two").WithArguments(",", "").WithLocation(1, 6) + Diagnostic(ErrorCode.ERR_SyntaxError, "Two").WithArguments(",").WithLocation(1, 6) ); N(SyntaxKind.CompilationUnit); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserRegressionTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserRegressionTests.cs index ce56ecd88690e..2a397b1c693ac 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserRegressionTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserRegressionTests.cs @@ -745,7 +745,7 @@ static void Main() ParseAndValidate(source, // (5,13): error CS7000: Unexpected use of an aliased name // A::C d; - Diagnostic(ErrorCode.ERR_UnexpectedAliasedName, "::").WithArguments("::").WithLocation(5, 13)); + Diagnostic(ErrorCode.ERR_UnexpectedAliasedName, "::").WithLocation(5, 13)); UsingTree(source); N(SyntaxKind.CompilationUnit); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs index 2439a888450a3..5430e695e6ac8 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingErrorRecoveryTests.cs @@ -271,9 +271,9 @@ public void TestGlobalAttributeWithGarbageBetweenAttributes() // error CS1056: Unexpected character '$' Diagnostic(ErrorCode.ERR_UnexpectedCharacter).WithArguments("$"), // error CS1003: Syntax error, ',' expected - Diagnostic(ErrorCode.ERR_SyntaxError).WithArguments(",", ""), + Diagnostic(ErrorCode.ERR_SyntaxError).WithArguments(","), // error CS1003: Syntax error, ']' expected - Diagnostic(ErrorCode.ERR_SyntaxError).WithArguments("]", "") + Diagnostic(ErrorCode.ERR_SyntaxError).WithArguments("]") ); } @@ -1870,7 +1870,7 @@ public void TestEndBraceAfterIndexerParameterStart() CreateCompilation(text).VerifyDiagnostics( // (1,21): error CS1003: Syntax error, ']' expected // class c { int this[ } - Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments("]", "}").WithLocation(1, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, "}").WithArguments("]").WithLocation(1, 21), // (1,21): error CS1514: { expected // class c { int this[ } Diagnostic(ErrorCode.ERR_LbraceExpected, "}").WithLocation(1, 21), @@ -2073,7 +2073,7 @@ public void TestMethodAfterIndexerParameterStart() CreateCompilation(text).VerifyDiagnostics( // (1,21): error CS1003: Syntax error, ']' expected // class c { int this[ public void m() { } } - Diagnostic(ErrorCode.ERR_SyntaxError, "public").WithArguments("]", "public").WithLocation(1, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, "public").WithArguments("]").WithLocation(1, 21), // (1,21): error CS1514: { expected // class c { int this[ public void m() { } } Diagnostic(ErrorCode.ERR_LbraceExpected, "public").WithLocation(1, 21), @@ -4181,7 +4181,7 @@ public void TestCloseParenAfterDoWhileExpressionIndexerStart() Assert.Equal(SyntaxKind.DoStatement, ms.Body.Statements[0].Kind()); file.Errors().Verify( // error CS1003: Syntax error, ']' expected - Diagnostic(ErrorCode.ERR_SyntaxError).WithArguments("]", ")").WithLocation(1, 1), + Diagnostic(ErrorCode.ERR_SyntaxError).WithArguments("]").WithLocation(1, 1), // error CS1026: ) expected Diagnostic(ErrorCode.ERR_CloseParenExpected).WithLocation(1, 1) ); @@ -4351,7 +4351,7 @@ public void TestCloseParenAfterForStatementIncrementerStart() Assert.Equal(SyntaxKind.ForStatement, ms.Body.Statements[0].Kind()); file.Errors().Verify( // error CS1003: Syntax error, ']' expected - Diagnostic(ErrorCode.ERR_SyntaxError).WithArguments("]", ")").WithLocation(1, 1), + Diagnostic(ErrorCode.ERR_SyntaxError).WithArguments("]").WithLocation(1, 1), // error CS1026: ) expected Diagnostic(ErrorCode.ERR_CloseParenExpected).WithLocation(1, 1) ); @@ -6754,13 +6754,13 @@ public void ColonColonInExplicitInterfaceMember() syntaxTree.GetDiagnostics().Verify( // (2,4): error CS1003: Syntax error, '.' expected // _ _::this - Diagnostic(ErrorCode.ERR_SyntaxError, "::").WithArguments(".", "::"), + Diagnostic(ErrorCode.ERR_SyntaxError, "::").WithArguments("."), // (2,10): error CS1003: Syntax error, '[' expected // _ _::this - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("[", ""), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("["), // (2,10): error CS1003: Syntax error, ']' expected // _ _::this - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]", ""), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]"), // (2,10): error CS1514: { expected // _ _::this Diagnostic(ErrorCode.ERR_LbraceExpected, ""), @@ -6771,13 +6771,13 @@ public void ColonColonInExplicitInterfaceMember() CreateCompilation(text).VerifyDiagnostics( // (2,4): error CS1003: Syntax error, '.' expected // _ _::this - Diagnostic(ErrorCode.ERR_SyntaxError, "::").WithArguments(".", "::").WithLocation(2, 4), + Diagnostic(ErrorCode.ERR_SyntaxError, "::").WithArguments(".").WithLocation(2, 4), // (2,10): error CS1003: Syntax error, '[' expected // _ _::this - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("[", "").WithLocation(2, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("[").WithLocation(2, 10), // (2,10): error CS1003: Syntax error, ']' expected // _ _::this - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]", "").WithLocation(2, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(2, 10), // (2,10): error CS1514: { expected // _ _::this Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(2, 10), @@ -6936,7 +6936,7 @@ int I./*missing*/< { Diagnostic(ErrorCode.ERR_UnexpectedGenericName, "<"), // (4,24): error CS1003: Syntax error, '>' expected // int I./*missing*/< { - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(">", "{"), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(">"), // (4,25): error CS1513: } expected // int I./*missing*/< { Diagnostic(ErrorCode.ERR_RbraceExpected, ""), @@ -6967,7 +6967,7 @@ event D I./*missing*/< { Diagnostic(ErrorCode.ERR_IdentifierExpected, "<"), // (4,28): error CS1003: Syntax error, '>' expected // event D I./*missing*/< { - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(">", "{"), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(">"), // (4,26): error CS7002: Unexpected use of a generic name // event D I./*missing*/< { Diagnostic(ErrorCode.ERR_UnexpectedGenericName, "<"), diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests.cs index 6ab590092da35..8f83d832de362 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests.cs @@ -2120,7 +2120,7 @@ public void BrokenPattern_06() Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(1, 22), // (1,22): error CS1003: Syntax error, ':' expected // switch (e) { case (: ; } - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":", ";").WithLocation(1, 22) + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":").WithLocation(1, 22) ); N(SyntaxKind.SwitchStatement); { @@ -2169,7 +2169,7 @@ public void BrokenPattern_07() Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(1, 20), // (1,20): error CS1003: Syntax error, ':' expected // switch (e) { case ( - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 20), // (1,20): error CS1513: } expected // switch (e) { case ( Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 20) @@ -2253,7 +2253,7 @@ public void BrokenPattern_08() Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 18), // (1,18): error CS1003: Syntax error, ':' expected // switch (e) { case - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 18), // (1,18): error CS1513: } expected // switch (e) { case Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 18) @@ -2432,7 +2432,7 @@ public void SwitchExpression02() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "1 switch { a?b:c => d }").WithArguments("recursive patterns", "8.0").WithLocation(1, 1), // (1,13): error CS1003: Syntax error, '=>' expected // 1 switch { a?b:c => d } - Diagnostic(ErrorCode.ERR_SyntaxError, "?").WithArguments("=>", "?").WithLocation(1, 13), + Diagnostic(ErrorCode.ERR_SyntaxError, "?").WithArguments("=>").WithLocation(1, 13), // (1,13): error CS1525: Invalid expression term '?' // 1 switch { a?b:c => d } Diagnostic(ErrorCode.ERR_InvalidExprTerm, "?").WithArguments("?").WithLocation(1, 13) @@ -2569,16 +2569,16 @@ public void BrokenRecursivePattern01() Diagnostic(ErrorCode.ERR_IdentifierExpected, ":").WithLocation(1, 22), // (1,28): error CS1003: Syntax error, ',' expected // switch (e) { case T( : Q x = n; break; } - Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments(",", "=").WithLocation(1, 28), + Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments(",").WithLocation(1, 28), // (1,30): error CS1003: Syntax error, ',' expected // switch (e) { case T( : Q x = n; break; } - Diagnostic(ErrorCode.ERR_SyntaxError, "n").WithArguments(",", "").WithLocation(1, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, "n").WithArguments(",").WithLocation(1, 30), // (1,31): error CS1026: ) expected // switch (e) { case T( : Q x = n; break; } Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(1, 31), // (1,31): error CS1003: Syntax error, ':' expected // switch (e) { case T( : Q x = n; break; } - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":", ";").WithLocation(1, 31) + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(":").WithLocation(1, 31) ); N(SyntaxKind.SwitchStatement); { @@ -6228,7 +6228,7 @@ public void IsNullableArray02() UsingExpression("o is A[] ? b && c", // (1,18): error CS1003: Syntax error, ':' expected // o is A[] ? b && c - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":", "").WithLocation(1, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(":").WithLocation(1, 18), // (1,18): error CS1733: Expected expression // o is A[] ? b && c Diagnostic(ErrorCode.ERR_ExpressionExpected, "").WithLocation(1, 18) @@ -6576,7 +6576,7 @@ public void TrailingCommaInSwitchExpression_02() Diagnostic(ErrorCode.ERR_MissingPattern, ",").WithLocation(1, 12), // (1,12): error CS1003: Syntax error, '=>' expected // 1 switch { , } - Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments("=>", ",").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments("=>").WithLocation(1, 12), // (1,12): error CS1525: Invalid expression term ',' // 1 switch { , } Diagnostic(ErrorCode.ERR_InvalidExprTerm, ",").WithArguments(",").WithLocation(1, 12) @@ -6806,7 +6806,7 @@ public void ExtraCommaInSwitchExpression() Diagnostic(ErrorCode.ERR_MissingPattern, ",").WithLocation(1, 19), // (1,19): error CS1003: Syntax error, '=>' expected // e switch { 1 => 2,, } - Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments("=>", ",").WithLocation(1, 19), + Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments("=>").WithLocation(1, 19), // (1,19): error CS1525: Invalid expression term ',' // e switch { 1 => 2,, } Diagnostic(ErrorCode.ERR_InvalidExprTerm, ",").WithArguments(",").WithLocation(1, 19) @@ -7746,7 +7746,7 @@ public void BrokenSwitchExpression_02() Diagnostic(ErrorCode.ERR_MissingPattern, ",").WithLocation(1, 12), // (1,12): error CS1003: Syntax error, '=>' expected // (e switch {,) - Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments("=>", ",").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments("=>").WithLocation(1, 12), // (1,12): error CS1525: Invalid expression term ',' // (e switch {,) Diagnostic(ErrorCode.ERR_InvalidExprTerm, ",").WithArguments(",").WithLocation(1, 12), @@ -7797,7 +7797,7 @@ public void BrokenSwitchExpression_03() Diagnostic(ErrorCode.ERR_MissingPattern, ",").WithLocation(1, 11), // (1,11): error CS1003: Syntax error, '=>' expected // e switch {, - Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments("=>", ",").WithLocation(1, 11), + Diagnostic(ErrorCode.ERR_SyntaxError, ",").WithArguments("=>").WithLocation(1, 11), // (1,11): error CS1525: Invalid expression term ',' // e switch {, Diagnostic(ErrorCode.ERR_InvalidExprTerm, ",").WithArguments(",").WithLocation(1, 11), @@ -7877,7 +7877,7 @@ public void SwitchCaseArmErrorRecovery_01() UsingExpression("e switch { 1 => 1; 2 => 2 }", // (1,18): error CS1003: Syntax error, ',' expected // e switch { 1 => 1; 2 => 2 } - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",", ";").WithLocation(1, 18) + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",").WithLocation(1, 18) ); N(SyntaxKind.SwitchExpression); { @@ -7929,7 +7929,7 @@ public void SwitchCaseArmErrorRecovery_02() UsingExpression("e switch { 1 => 1, 2 => 2; }", // (1,26): error CS1003: Syntax error, ',' expected // e switch { 1 => 1, 2 => 2; } - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",", ";").WithLocation(1, 26) + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",").WithLocation(1, 26) ); N(SyntaxKind.SwitchExpression); { @@ -8581,37 +8581,37 @@ public void RelationalPatternPrecedence_01() TestOptions.RegularWithPatternCombinators, // (2,9): error CS1003: Syntax error, '=>' expected // < 0 < 0 => 0, - Diagnostic(ErrorCode.ERR_SyntaxError, "<").WithArguments("=>", "<").WithLocation(2, 9), + Diagnostic(ErrorCode.ERR_SyntaxError, "<").WithArguments("=>").WithLocation(2, 9), // (2,9): error CS1525: Invalid expression term '<' // < 0 < 0 => 0, Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(2, 9), // (2,13): error CS1003: Syntax error, ',' expected // < 0 < 0 => 0, - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(2, 13), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(2, 13), // (2,13): error CS8504: Pattern missing // < 0 < 0 => 0, Diagnostic(ErrorCode.ERR_MissingPattern, "=>").WithLocation(2, 13), // (3,10): error CS1003: Syntax error, '=>' expected // == 4 < 4 => 4, - Diagnostic(ErrorCode.ERR_SyntaxError, "<").WithArguments("=>", "<").WithLocation(3, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "<").WithArguments("=>").WithLocation(3, 10), // (3,10): error CS1525: Invalid expression term '<' // == 4 < 4 => 4, Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(3, 10), // (3,14): error CS1003: Syntax error, ',' expected // == 4 < 4 => 4, - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(3, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(3, 14), // (3,14): error CS8504: Pattern missing // == 4 < 4 => 4, Diagnostic(ErrorCode.ERR_MissingPattern, "=>").WithLocation(3, 14), // (4,10): error CS1003: Syntax error, '=>' expected // != 5 < 5 => 5, - Diagnostic(ErrorCode.ERR_SyntaxError, "<").WithArguments("=>", "<").WithLocation(4, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, "<").WithArguments("=>").WithLocation(4, 10), // (4,10): error CS1525: Invalid expression term '<' // != 5 < 5 => 5, Diagnostic(ErrorCode.ERR_InvalidExprTerm, "<").WithArguments("<").WithLocation(4, 10), // (4,14): error CS1003: Syntax error, ',' expected // != 5 < 5 => 5, - Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",", "=>").WithLocation(4, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(4, 14), // (4,14): error CS8504: Pattern missing // != 5 < 5 => 5, Diagnostic(ErrorCode.ERR_MissingPattern, "=>").WithLocation(4, 14) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests2.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests2.cs index f3cfaf16a92c6..e5abcc5f6dd11 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests2.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests2.cs @@ -96,10 +96,10 @@ public void ExtendedPropertySubpattern_02() UsingExpression(@"e is { {}: p }", // (1,10): error CS1003: Syntax error, ',' expected // e is { {}: p } - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(1, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(1, 10), // (1,12): error CS1003: Syntax error, ',' expected // e is { {}: p } - Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",", "").WithLocation(1, 12)); + Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",").WithLocation(1, 12)); N(SyntaxKind.IsPatternExpression); { @@ -199,10 +199,10 @@ public void ExtendedPropertySubpattern_04() UsingExpression(@"e is { name[0]: p }", // (1,15): error CS1003: Syntax error, ',' expected // e is { name[0]: p } - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(1, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(1, 15), // (1,17): error CS1003: Syntax error, ',' expected // e is { name[0]: p } - Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",", "").WithLocation(1, 17)); + Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",").WithLocation(1, 17)); N(SyntaxKind.IsPatternExpression); { @@ -366,10 +366,10 @@ public void ExtendedPropertySubpattern_07() UsingExpression(@"e is { [0]: p }", // (1,11): error CS1003: Syntax error, ',' expected // e is { [0]: p } - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(1, 11), + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(1, 11), // (1,13): error CS1003: Syntax error, ',' expected // e is { [0]: p } - Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",", "").WithLocation(1, 13)); + Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",").WithLocation(1, 13)); N(SyntaxKind.IsPatternExpression); { @@ -422,10 +422,10 @@ public void ExtendedPropertySubpattern_08() UsingExpression(@"e is { not a: p }", // (1,13): error CS1003: Syntax error, ',' expected // e is { not a: p } - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(1, 13), + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(1, 13), // (1,15): error CS1003: Syntax error, ',' expected // e is { not a: p } - Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",", "").WithLocation(1, 15)); + Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",").WithLocation(1, 15)); N(SyntaxKind.IsPatternExpression); { @@ -477,10 +477,10 @@ public void ExtendedPropertySubpattern_09() UsingExpression(@"e is { x or y: p }", // (1,14): error CS1003: Syntax error, ',' expected // e is { x or y: p } - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(1, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(1, 14), // (1,16): error CS1003: Syntax error, ',' expected // e is { x or y: p } - Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",", "").WithLocation(1, 16)); + Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",").WithLocation(1, 16)); N(SyntaxKind.IsPatternExpression); { @@ -581,10 +581,10 @@ public void ExtendedPropertySubpattern_11() UsingExpression(@"e is { >1: p }", // (1,10): error CS1003: Syntax error, ',' expected // e is { >1: p } - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(1, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(1, 10), // (1,12): error CS1003: Syntax error, ',' expected // e is { >1: p } - Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",", "").WithLocation(1, 12)); + Diagnostic(ErrorCode.ERR_SyntaxError, "p").WithArguments(",").WithLocation(1, 12)); N(SyntaxKind.IsPatternExpression); { @@ -752,10 +752,10 @@ public void ExtendedPropertySubpattern_14() UsingExpression(@"e is { [0].b: p }", // (1,11): error CS1003: Syntax error, ',' expected // e is { [0].b: p } - Diagnostic(ErrorCode.ERR_SyntaxError, ".").WithArguments(",", ".").WithLocation(1, 11), + Diagnostic(ErrorCode.ERR_SyntaxError, ".").WithArguments(",").WithLocation(1, 11), // (1,12): error CS1003: Syntax error, ',' expected // e is { [0].b: p } - Diagnostic(ErrorCode.ERR_SyntaxError, "b").WithArguments(",", "").WithLocation(1, 12)); + Diagnostic(ErrorCode.ERR_SyntaxError, "b").WithArguments(",").WithLocation(1, 12)); N(SyntaxKind.IsPatternExpression); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests_ListPatterns.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests_ListPatterns.cs index b83cebde3d770..f6c5ca5d9d153 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests_ListPatterns.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/PatternParsingTests_ListPatterns.cs @@ -99,10 +99,10 @@ public void ListPattern_02() UsingExpression(@"c is [ 1, prop: 0 ]", // (1,15): error CS1003: Syntax error, ',' expected // c is [ 1, prop: 0 ] - Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",", ":").WithLocation(1, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, ":").WithArguments(",").WithLocation(1, 15), // (1,17): error CS1003: Syntax error, ',' expected // c is [ 1, prop: 0 ] - Diagnostic(ErrorCode.ERR_SyntaxError, "0").WithArguments(",", "").WithLocation(1, 17)); + Diagnostic(ErrorCode.ERR_SyntaxError, "0").WithArguments(",").WithLocation(1, 17)); N(SyntaxKind.IsPatternExpression); @@ -769,7 +769,7 @@ public void SlicePattern_11() UsingExpression(@"c is [var x ..]", // (1,13): error CS1003: Syntax error, ',' expected // c is {var x ..} - Diagnostic(ErrorCode.ERR_SyntaxError, "..").WithArguments(",", "..").WithLocation(1, 13)); + Diagnostic(ErrorCode.ERR_SyntaxError, "..").WithArguments(",").WithLocation(1, 13)); N(SyntaxKind.IsPatternExpression); { @@ -837,7 +837,7 @@ public void SlicePattern_13() UsingExpression(@"c is [[]..]", // (1,9): error CS1003: Syntax error, ',' expected // c is {{}..} - Diagnostic(ErrorCode.ERR_SyntaxError, "..").WithArguments(",", "..").WithLocation(1, 9)); + Diagnostic(ErrorCode.ERR_SyntaxError, "..").WithArguments(",").WithLocation(1, 9)); N(SyntaxKind.IsPatternExpression); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs index 9c12584fa20a2..5bb3c7b81878c 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs @@ -453,7 +453,7 @@ public void RecordParsing_ConstraintAndSemiColon_MissingColon() UsingTree("record R where T class;", // (1,23): error CS1003: Syntax error, ':' expected // record R where T class; - Diagnostic(ErrorCode.ERR_SyntaxError, "class").WithArguments(":", "class").WithLocation(1, 23) + Diagnostic(ErrorCode.ERR_SyntaxError, "class").WithArguments(":").WithLocation(1, 23) ); N(SyntaxKind.CompilationUnit); @@ -555,7 +555,7 @@ public void RecordParsing_ConstraintAndSemiColon_Class() UsingTree("abstract class C where T : class;", // (1,36): error CS1003: Syntax error, ',' expected // abstract class C where T : class; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",", ";").WithLocation(1, 36), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",").WithLocation(1, 36), // (1,37): error CS1514: { expected // abstract class C where T : class; Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(1, 37), @@ -607,7 +607,7 @@ public void RecordParsing_TwoConstraintsAndSemiColon_Class() UsingTree("abstract class C where T1 : class where T2 : class;", // (1,59): error CS1003: Syntax error, ',' expected // abstract class C where T1 : class where T2 : class; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",", ";").WithLocation(1, 59), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",").WithLocation(1, 59), // (1,60): error CS1514: { expected // abstract class C where T1 : class where T2 : class; Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(1, 60), @@ -755,7 +755,7 @@ public void TestClassWithMultipleConstraints001() UsingTree("class a where b : c where b { }", // (1,32): error CS1003: Syntax error, ':' expected // class a where b : c where b { } - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":", "{").WithLocation(1, 32), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":").WithLocation(1, 32), // (1,32): error CS1031: Type expected // class a where b : c where b { } Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(1, 32) @@ -825,7 +825,7 @@ public void TestClassWithMultipleConstraints002() Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(1, 30), // (1,30): error CS1003: Syntax error, ':' expected // class a where b : c where { } - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":", "{").WithLocation(1, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":").WithLocation(1, 30), // (1,30): error CS1031: Type expected // class a where b : c where { } Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(1, 30) @@ -1032,10 +1032,10 @@ public void TestWhereWhere() UsingTree("public class Goo : System.Object where where { }", // (1,37): error CS1003: Syntax error, ',' expected // public class Goo : System.Object where where { } - Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(",", "").WithLocation(1, 37), + Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(",").WithLocation(1, 37), // (1,43): error CS1003: Syntax error, ',' expected // public class Goo : System.Object where where { } - Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(",", "").WithLocation(1, 43) + Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(",").WithLocation(1, 43) ); N(SyntaxKind.CompilationUnit); @@ -1103,13 +1103,13 @@ public void TestWhereWhereWhere() UsingTree("public class Goo : System.Object where where where { }", // (1,37): error CS1003: Syntax error, ',' expected // public class Goo : System.Object where where where { } - Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(",", "").WithLocation(1, 37), + Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(",").WithLocation(1, 37), // (1,43): error CS1003: Syntax error, ',' expected // public class Goo : System.Object where where where { } - Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(",", "").WithLocation(1, 43), + Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(",").WithLocation(1, 43), // (1,49): error CS1003: Syntax error, ',' expected // public class Goo : System.Object where where where { } - Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(",", "").WithLocation(1, 49) + Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(",").WithLocation(1, 49) ); N(SyntaxKind.CompilationUnit); @@ -1221,7 +1221,7 @@ class C Diagnostic(ErrorCode.ERR_TopLevelStatementAfterNamespaceOrType, "int x = with { ").WithLocation(6, 5), // (6,18): error CS1003: Syntax error, ',' expected // int x = with { }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(6, 18), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(6, 18), // (6,20): error CS1002: ; expected // int x = with { }; Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(6, 20), @@ -1495,7 +1495,7 @@ public void WithParsing5() UsingExpression(text, // (1,12): error CS1003: Syntax error, ',' expected // 0 with { X 3 =, - Diagnostic(ErrorCode.ERR_SyntaxError, "3").WithArguments(",", "").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_SyntaxError, "3").WithArguments(",").WithLocation(1, 12), // (1,15): error CS1525: Invalid expression term ',' // 0 with { X 3 =, Diagnostic(ErrorCode.ERR_InvalidExprTerm, ",").WithArguments(",").WithLocation(1, 15), @@ -1914,7 +1914,7 @@ public void WithParsing16() UsingStatement(text, // (1,8): error CS1003: Syntax error, ',' expected // x with { X = "2" }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",", "{").WithLocation(1, 8)); + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(1, 8)); N(SyntaxKind.LocalDeclarationStatement); { N(SyntaxKind.VariableDeclaration); @@ -1985,7 +1985,7 @@ public void WithParsing18() UsingExpression(text, // (1,23): error CS1003: Syntax error, ',' expected // x with { A = e is T y B = y } - Diagnostic(ErrorCode.ERR_SyntaxError, "B").WithArguments(",", "").WithLocation(1, 23)); + Diagnostic(ErrorCode.ERR_SyntaxError, "B").WithArguments(",").WithLocation(1, 23)); N(SyntaxKind.WithExpression); { N(SyntaxKind.IdentifierName); @@ -2318,13 +2318,13 @@ public void Base_02([CombinatorialValues(true, false)] bool withBody) UsingTree(text, // (2,7): error CS1003: Syntax error, ',' expected // : B, D(X, Y) - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(",", "(").WithLocation(2, 7), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments(",").WithLocation(2, 7), // (2,8): error CS1003: Syntax error, ',' expected // : B, D(X, Y) - Diagnostic(ErrorCode.ERR_SyntaxError, "X").WithArguments(",", "").WithLocation(2, 8), + Diagnostic(ErrorCode.ERR_SyntaxError, "X").WithArguments(",").WithLocation(2, 8), // (2,12): error CS1003: Syntax error, ',' expected // : B, D(X, Y) - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(",", ")").WithLocation(2, 12) + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(",").WithLocation(2, 12) ); N(SyntaxKind.CompilationUnit); @@ -2412,7 +2412,7 @@ public void Base_03() UsingTree(text, // (1,16): error CS1003: Syntax error, ',' expected // interface C : B; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",", ";").WithLocation(1, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",").WithLocation(1, 16), // (1,17): error CS1514: { expected // interface C : B; Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(1, 17), @@ -2541,7 +2541,7 @@ public void Base_05() UsingTree(text, // (1,22): error CS1003: Syntax error, ',' expected // interface C : B(X, Y); - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",", ";").WithLocation(1, 22), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(",").WithLocation(1, 22), // (1,23): error CS1514: { expected // interface C : B(X, Y); Diagnostic(ErrorCode.ERR_LbraceExpected, "").WithLocation(1, 23), @@ -3072,13 +3072,13 @@ public void RecordRecordParsing() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(1, 17), // (1,21): error CS1003: Syntax error, ',' expected // record record C(int X, int Y); - Diagnostic(ErrorCode.ERR_SyntaxError, "X").WithArguments(",", "").WithLocation(1, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, "X").WithArguments(",").WithLocation(1, 21), // (1,24): error CS1525: Invalid expression term 'int' // record record C(int X, int Y); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(1, 24), // (1,28): error CS1003: Syntax error, ',' expected // record record C(int X, int Y); - Diagnostic(ErrorCode.ERR_SyntaxError, "Y").WithArguments(",", "").WithLocation(1, 28) + Diagnostic(ErrorCode.ERR_SyntaxError, "Y").WithArguments(",").WithLocation(1, 28) ); N(SyntaxKind.CompilationUnit); @@ -3209,13 +3209,13 @@ public void RecordStructParsing_WrongOrder_CSharp9() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(1, 17), // (1,21): error CS1003: Syntax error, ',' expected // struct record C(int X, int Y); - Diagnostic(ErrorCode.ERR_SyntaxError, "X").WithArguments(",", "").WithLocation(1, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, "X").WithArguments(",").WithLocation(1, 21), // (1,24): error CS1525: Invalid expression term 'int' // struct record C(int X, int Y); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(1, 24), // (1,28): error CS1003: Syntax error, ',' expected // struct record C(int X, int Y); - Diagnostic(ErrorCode.ERR_SyntaxError, "Y").WithArguments(",", "").WithLocation(1, 28) + Diagnostic(ErrorCode.ERR_SyntaxError, "Y").WithArguments(",").WithLocation(1, 28) ); N(SyntaxKind.CompilationUnit); @@ -3406,13 +3406,13 @@ public void RecordClassParsing_WrongOrder_CSharp9() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(1, 16), // (1,20): error CS1003: Syntax error, ',' expected // class record C(int X, int Y); - Diagnostic(ErrorCode.ERR_SyntaxError, "X").WithArguments(",", "").WithLocation(1, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, "X").WithArguments(",").WithLocation(1, 20), // (1,23): error CS1525: Invalid expression term 'int' // class record C(int X, int Y); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(1, 23), // (1,27): error CS1003: Syntax error, ',' expected // class record C(int X, int Y); - Diagnostic(ErrorCode.ERR_SyntaxError, "Y").WithArguments(",", "").WithLocation(1, 27) + Diagnostic(ErrorCode.ERR_SyntaxError, "Y").WithArguments(",").WithLocation(1, 27) ); N(SyntaxKind.CompilationUnit); @@ -3498,13 +3498,13 @@ public void RecordInterfaceParsing_WrongOrder() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(1, 20), // (1,24): error CS1003: Syntax error, ',' expected // interface record C(int X, int Y); - Diagnostic(ErrorCode.ERR_SyntaxError, "X").WithArguments(",", "").WithLocation(1, 24), + Diagnostic(ErrorCode.ERR_SyntaxError, "X").WithArguments(",").WithLocation(1, 24), // (1,27): error CS1525: Invalid expression term 'int' // interface record C(int X, int Y); Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(1, 27), // (1,31): error CS1003: Syntax error, ',' expected // interface record C(int X, int Y); - Diagnostic(ErrorCode.ERR_SyntaxError, "Y").WithArguments(",", "").WithLocation(1, 31) + Diagnostic(ErrorCode.ERR_SyntaxError, "Y").WithArguments(",").WithLocation(1, 31) ); N(SyntaxKind.CompilationUnit); @@ -3968,10 +3968,10 @@ public void RecordStructParsing_Fixed() Diagnostic(ErrorCode.ERR_IdentifierExpected, "struct").WithLocation(1, 14), // (1,14): error CS1003: Syntax error, '[' expected // fixed record struct S; - Diagnostic(ErrorCode.ERR_SyntaxError, "struct").WithArguments("[", "struct").WithLocation(1, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "struct").WithArguments("[").WithLocation(1, 14), // (1,14): error CS1003: Syntax error, ']' expected // fixed record struct S; - Diagnostic(ErrorCode.ERR_SyntaxError, "struct").WithArguments("]", "struct").WithLocation(1, 14), + Diagnostic(ErrorCode.ERR_SyntaxError, "struct").WithArguments("]").WithLocation(1, 14), // (1,14): error CS0443: Syntax error; value expected // fixed record struct S; Diagnostic(ErrorCode.ERR_ValueExpected, "struct").WithLocation(1, 14), diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RefReadonlyTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RefReadonlyTests.cs index f6a22989d091c..1e2c699bf8bbe 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RefReadonlyTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RefReadonlyTests.cs @@ -136,7 +136,7 @@ static async ref readonly Task M() ParseAndValidate(text, TestOptions.Regular9, // (9,27): error CS1003: Syntax error, '(' expected // ref readonly int Field; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("(", ";").WithLocation(9, 27), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("(").WithLocation(9, 27), // (9,27): error CS1026: ) expected // ref readonly int Field; Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(9, 27), @@ -325,7 +325,7 @@ void M() Diagnostic(ErrorCode.ERR_IdentifierExpected, "in").WithLocation(8, 32), // (8,32): error CS1003: Syntax error, ',' expected // foreach(ref readonly v in ar) - Diagnostic(ErrorCode.ERR_SyntaxError, "in").WithArguments(",", "in").WithLocation(8, 32), + Diagnostic(ErrorCode.ERR_SyntaxError, "in").WithArguments(",").WithLocation(8, 32), // (8,35): error CS1002: ; expected // foreach(ref readonly v in ar) Diagnostic(ErrorCode.ERR_SemicolonExpected, "ar").WithLocation(8, 35), @@ -427,7 +427,7 @@ void M(readonly ref int p) Diagnostic(ErrorCode.ERR_SemicolonExpected, "readonly").WithLocation(4, 12), // (4,30): error CS1003: Syntax error, '(' expected // void M(readonly ref int p) - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(", ")").WithLocation(4, 30)); + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("(").WithLocation(4, 30)); } [Fact] @@ -487,7 +487,7 @@ class Test Diagnostic(ErrorCode.ERR_SemicolonExpected, "readonly").WithLocation(4, 16), // (4,30): error CS1003: Syntax error, ',' expected // void M(ref readonly int p) => throw null; - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(",", ")").WithLocation(4, 30), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(",").WithLocation(4, 30), // (4,10): error CS0501: 'Test.M(ref ?)' must declare a body because it is not marked abstract, extern, or partial // void M(ref readonly int p) => throw null; Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M").WithArguments("Test.M(ref ?)").WithLocation(4, 10), diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs index 512dff612c5ae..6f29acb3999dd 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs @@ -1688,13 +1688,13 @@ public void Error_IndexerDefinition() CreateCompilation(test).VerifyDiagnostics( // (1,13): error CS1003: Syntax error, '[' expected // string this =""; - Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("[", "=").WithLocation(1, 13), + Diagnostic(ErrorCode.ERR_SyntaxError, "=").WithArguments("[").WithLocation(1, 13), // (1,13): error CS1001: Identifier expected // string this =""; Diagnostic(ErrorCode.ERR_IdentifierExpected, "=").WithLocation(1, 13), // (1,16): error CS1003: Syntax error, ']' expected // string this =""; - Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]", ";").WithLocation(1, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("]").WithLocation(1, 16), // (1,16): error CS1514: { expected // string this =""; Diagnostic(ErrorCode.ERR_LbraceExpected, ";").WithLocation(1, 16), diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/StackAllocInitializerParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/StackAllocInitializerParsingTests.cs index 8b3901f69bbf6..1274c30c8e929 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/StackAllocInitializerParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/StackAllocInitializerParsingTests.cs @@ -222,7 +222,7 @@ void Goo() { Diagnostic(ErrorCode.ERR_InvalidStackAllocArray, ",").WithLocation(4, 28), // (4,31): error CS1003: Syntax error, ']' expected // var x = stackalloc[,3 { 1, 2, 3 }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]", "{").WithLocation(4, 31) + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]").WithLocation(4, 31) ); } @@ -243,7 +243,7 @@ void Goo() { Diagnostic(ErrorCode.ERR_InvalidStackAllocArray, "3").WithLocation(4, 28), // (4,30): error CS1003: Syntax error, ']' expected // var x = stackalloc[3 { 1, 2, 3 }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]", "{").WithLocation(4, 30) + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]").WithLocation(4, 30) ); } @@ -267,7 +267,7 @@ void Goo() { Diagnostic(ErrorCode.ERR_InvalidStackAllocArray, ",").WithLocation(4, 29), // (4,31): error CS1003: Syntax error, ']' expected // var x = stackalloc[3, { 1, 2, 3 }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]", "{").WithLocation(4, 31) + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]").WithLocation(4, 31) ); } @@ -384,7 +384,7 @@ void Goo() { ParseAndValidate(test, // (4,29): error CS1003: Syntax error, ']' expected // var x = stackalloc[ { 1, 2, 3 }; - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]", "{").WithLocation(4, 29) + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("]").WithLocation(4, 29) ); } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementAttributeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementAttributeParsingTests.cs index 56246b7da4a46..69a16ccc72b80 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementAttributeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementAttributeParsingTests.cs @@ -2872,7 +2872,7 @@ void Goo() Diagnostic(ErrorCode.ERR_AttributesNotAllowed, "[A]").WithLocation(6, 17), // (6,21): error CS1003: Syntax error, 'try' expected // try { } [A] finally { } - Diagnostic(ErrorCode.ERR_SyntaxError, "finally").WithArguments("try", "finally").WithLocation(6, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, "finally").WithArguments("try").WithLocation(6, 21), // (6,21): error CS1514: { expected // try { } [A] finally { } Diagnostic(ErrorCode.ERR_LbraceExpected, "finally").WithLocation(6, 21), @@ -3060,7 +3060,7 @@ void Goo() Diagnostic(ErrorCode.ERR_AttributesNotAllowed, "[A]").WithLocation(6, 17), // (6,21): error CS1003: Syntax error, 'try' expected // try { } [A] catch { } - Diagnostic(ErrorCode.ERR_SyntaxError, "catch").WithArguments("try", "catch").WithLocation(6, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, "catch").WithArguments("try").WithLocation(6, 21), // (6,21): error CS1514: { expected // try { } [A] catch { } Diagnostic(ErrorCode.ERR_LbraceExpected, "catch").WithLocation(6, 21), @@ -6695,7 +6695,7 @@ void Goo() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(6, 21), // (6,25): error CS1003: Syntax error, ',' expected // [A]int this[int i] => 0; - Diagnostic(ErrorCode.ERR_SyntaxError, "i").WithArguments(",", "").WithLocation(6, 25), + Diagnostic(ErrorCode.ERR_SyntaxError, "i").WithArguments(",").WithLocation(6, 25), // (6,25): error CS0103: The name 'i' does not exist in the current context // [A]int this[int i] => 0; Diagnostic(ErrorCode.ERR_NameNotInContext, "i").WithArguments("i").WithLocation(6, 25), diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs index cc89cfa55363b..edd597c2033db 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/StatementParsingTests.cs @@ -3454,7 +3454,7 @@ void M() tree.GetDiagnostics(root).Verify( // (7,36): error CS1003: Syntax error, 'when' expected // catch (System.Exception e) if (true) { } - CSharpTestBase.Diagnostic(ErrorCode.ERR_SyntaxError, "if").WithArguments("when", "if").WithLocation(7, 36)); + CSharpTestBase.Diagnostic(ErrorCode.ERR_SyntaxError, "if").WithArguments("when").WithLocation(7, 36)); var filterClause = root.DescendantNodes().OfType().Single(); Assert.Equal(SyntaxKind.WhenKeyword, filterClause.WhenKeyword.Kind()); @@ -3591,7 +3591,7 @@ public void ParseElseWithoutPrecedingIfStatement() Diagnostic(ErrorCode.ERR_ElseCannotStartStatement, "else").WithLocation(1, 1), // (1,1): error CS1003: Syntax error, '(' expected // else {} - Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(", "else").WithLocation(1, 1), + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(").WithLocation(1, 1), // (1,1): error CS1525: Invalid expression term 'else' // else {} Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 1), @@ -3645,7 +3645,7 @@ public void ParseElseAndElseWithoutPrecedingIfStatement() Diagnostic(ErrorCode.ERR_ElseCannotStartStatement, "else").WithLocation(1, 3), // (1,3): error CS1003: Syntax error, '(' expected // { else {} else {} } - Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(", "else").WithLocation(1, 3), + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(").WithLocation(1, 3), // (1,3): error CS1525: Invalid expression term 'else' // { else {} else {} } Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 3), @@ -3663,7 +3663,7 @@ public void ParseElseAndElseWithoutPrecedingIfStatement() Diagnostic(ErrorCode.ERR_ElseCannotStartStatement, "else").WithLocation(1, 11), // (1,11): error CS1003: Syntax error, '(' expected // { else {} else {} } - Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(", "else").WithLocation(1, 11), + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(").WithLocation(1, 11), // (1,11): error CS1525: Invalid expression term 'else' // { else {} else {} } Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 11), @@ -3749,7 +3749,7 @@ public void ParseSubsequentElseWithoutPrecedingIfStatement() Diagnostic(ErrorCode.ERR_ElseCannotStartStatement, "else").WithLocation(1, 23), // (1,23): error CS1003: Syntax error, '(' expected // { if (a) { } else { } else { } } - Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(", "else").WithLocation(1, 23), + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(").WithLocation(1, 23), // (1,23): error CS1525: Invalid expression term 'else' // { if (a) { } else { } else { } } Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 23), @@ -3832,7 +3832,7 @@ public void ParseElseKeywordPlacedAsIfEmbeddedStatement() Diagnostic(ErrorCode.ERR_ElseCannotStartStatement, "else").WithLocation(1, 8), // (1,8): error CS1003: Syntax error, '(' expected // if (a) else {} - Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(", "else").WithLocation(1, 8), + Diagnostic(ErrorCode.ERR_SyntaxError, "else").WithArguments("(").WithLocation(1, 8), // (1,8): error CS1525: Invalid expression term 'else' // if (a) else {} Diagnostic(ErrorCode.ERR_InvalidExprTerm, "else").WithArguments("else").WithLocation(1, 8), @@ -4179,7 +4179,7 @@ public void ParsePointerToArray() Diagnostic(ErrorCode.ERR_IdentifierExpected, "*").WithLocation(1, 7), // (1,7): error CS1003: Syntax error, ',' expected // int []* p; - Diagnostic(ErrorCode.ERR_SyntaxError, "*").WithArguments(",", "*").WithLocation(1, 7) + Diagnostic(ErrorCode.ERR_SyntaxError, "*").WithArguments(",").WithLocation(1, 7) ); N(SyntaxKind.LocalDeclarationStatement); { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/SuppressNullableWarningExpressionParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/SuppressNullableWarningExpressionParsingTests.cs index afcfc6f8a1210..4a7a1920c0d79 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/SuppressNullableWarningExpressionParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/SuppressNullableWarningExpressionParsingTests.cs @@ -373,7 +373,7 @@ public void ConditionalAccess_04() Diagnostic(ErrorCode.ERR_InvalidExprTerm, ".", isSuppressed: false).WithArguments(".").WithLocation(1, 7), // (1,20): error CS1003: Syntax error, ':' expected // x?.y?!.z.ToString() - Diagnostic(ErrorCode.ERR_SyntaxError, "", isSuppressed: false).WithArguments(":", "").WithLocation(1, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, "", isSuppressed: false).WithArguments(":").WithLocation(1, 20), // (1,20): error CS1733: Expected expression // x?.y?!.z.ToString() Diagnostic(ErrorCode.ERR_ExpressionExpected, "", isSuppressed: false).WithLocation(1, 20)); @@ -447,7 +447,7 @@ public void ConditionalAccess_05() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "[", isSuppressed: false).WithArguments("[").WithLocation(1, 7), // (1,21): error CS1003: Syntax error, ':' expected // x?.y?![0].ToString() - Diagnostic(ErrorCode.ERR_SyntaxError, "", isSuppressed: false).WithArguments(":", "").WithLocation(1, 21), + Diagnostic(ErrorCode.ERR_SyntaxError, "", isSuppressed: false).WithArguments(":").WithLocation(1, 21), // (1,21): error CS1733: Expected expression // x?.y?![0].ToString() Diagnostic(ErrorCode.ERR_ExpressionExpected, "", isSuppressed: false).WithLocation(1, 21)); @@ -528,7 +528,7 @@ public void ConditionalAccess_06() Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")", isSuppressed: false).WithArguments(")").WithLocation(1, 8), // (1,20): error CS1003: Syntax error, ':' expected // x?.y?!().ToString() - Diagnostic(ErrorCode.ERR_SyntaxError, "", isSuppressed: false).WithArguments(":", "").WithLocation(1, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, "", isSuppressed: false).WithArguments(":").WithLocation(1, 20), // (1,20): error CS1733: Expected expression // x?.y?!().ToString() Diagnostic(ErrorCode.ERR_ExpressionExpected, "", isSuppressed: false).WithLocation(1, 20)); @@ -599,7 +599,7 @@ public void ConditionalAccess_07() Diagnostic(ErrorCode.ERR_InvalidExprTerm, ".", isSuppressed: false).WithArguments(".").WithLocation(1, 8), // (1,19): error CS1003: Syntax error, ':' expected // x?.y!?!.ToString() - Diagnostic(ErrorCode.ERR_SyntaxError, "", isSuppressed: false).WithArguments(":", "").WithLocation(1, 19), + Diagnostic(ErrorCode.ERR_SyntaxError, "", isSuppressed: false).WithArguments(":").WithLocation(1, 19), // (1,19): error CS1733: Expected expression // x?.y!?!.ToString() Diagnostic(ErrorCode.ERR_ExpressionExpected, "", isSuppressed: false).WithLocation(1, 19)); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/TopLevelStatementsParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/TopLevelStatementsParsingTests.cs index a829a2b420bb7..6b4ac8aa74fb3 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/TopLevelStatementsParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/TopLevelStatementsParsingTests.cs @@ -126,7 +126,7 @@ class C Diagnostic(ErrorCode.ERR_TopLevelStatementAfterNamespaceOrType, "[a]fod;").WithLocation(15, 1), // (16,3): error CS1003: Syntax error, ']' expected // [b - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]", "").WithLocation(16, 3) + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("]").WithLocation(16, 3) ); N(SyntaxKind.CompilationUnit); @@ -227,13 +227,13 @@ class C { } Diagnostic(ErrorCode.ERR_BadOperatorSyntax, "fg").WithArguments("+").WithLocation(2, 1), // (2,4): error CS1003: Syntax error, 'operator' expected // fg implicit// - Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator", "implicit").WithLocation(2, 4), + Diagnostic(ErrorCode.ERR_SyntaxError, "implicit").WithArguments("operator").WithLocation(2, 4), // (2,4): error CS1037: Overloadable operator expected // fg implicit// Diagnostic(ErrorCode.ERR_OvlOperatorExpected, "implicit").WithLocation(2, 4), // (2,12): error CS1003: Syntax error, '(' expected // fg implicit// - Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(", "class").WithLocation(2, 12), + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("(").WithLocation(2, 12), // (2,12): error CS1026: ) expected // fg implicit// Diagnostic(ErrorCode.ERR_CloseParenExpected, "").WithLocation(2, 12), @@ -941,7 +941,7 @@ partial delegate E { } Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(2, 20), // (2,20): error CS1003: Syntax error, '(' expected // partial delegate E { } - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("(", "{").WithLocation(2, 20), + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("(").WithLocation(2, 20), // (2,20): error CS1026: ) expected // partial delegate E { } Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(2, 20), @@ -1302,7 +1302,7 @@ public void TopLevelIndexer() Diagnostic(ErrorCode.ERR_InvalidExprTerm, "double").WithArguments("double").WithLocation(2, 6), // (2,13): error CS1003: Syntax error, ',' expected // this[double E] { get { return /**/E/**/; } } - Diagnostic(ErrorCode.ERR_SyntaxError, "E").WithArguments(",", "").WithLocation(2, 13), + Diagnostic(ErrorCode.ERR_SyntaxError, "E").WithArguments(",").WithLocation(2, 13), // (2,16): error CS1002: ; expected // this[double E] { get { return /**/E/**/; } } Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(2, 16), @@ -2155,7 +2155,7 @@ public void UsingDirective_06() Diagnostic(ErrorCode.ERR_IdentifierExpected, ".").WithLocation(1, 10), // (1,10): error CS1003: Syntax error, ',' expected // using int.Parse name = value; - Diagnostic(ErrorCode.ERR_SyntaxError, ".").WithArguments(",", ".").WithLocation(1, 10), + Diagnostic(ErrorCode.ERR_SyntaxError, ".").WithArguments(",").WithLocation(1, 10), // (1,11): error CS1002: ; expected // using int.Parse name = value; Diagnostic(ErrorCode.ERR_SemicolonExpected, "Parse").WithLocation(1, 11) @@ -2227,10 +2227,10 @@ public void UsingDirective_07() Diagnostic(ErrorCode.ERR_BadVarDecl, "(x, y").WithLocation(1, 11), // (1,11): error CS1003: Syntax error, '[' expected // using int (x, y) - Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[", "(").WithLocation(1, 11), + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(1, 11), // (1,16): error CS1003: Syntax error, ']' expected // using int (x, y) - Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]", ")").WithLocation(1, 16), + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(1, 16), // (1,17): error CS1002: ; expected // using int (x, y) Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 17) @@ -2334,19 +2334,19 @@ public void Repro611177() Diagnostic(ErrorCode.ERR_LbraceExpected, "using").WithLocation(1, 15), // (1,15): error CS1003: Syntax error, ',' expected // [_<_[delegate using' - Diagnostic(ErrorCode.ERR_SyntaxError, "using").WithArguments(",", "using").WithLocation(1, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "using").WithArguments(",").WithLocation(1, 15), // (1,15): error CS0443: Syntax error; value expected // [_<_[delegate using' Diagnostic(ErrorCode.ERR_ValueExpected, "").WithLocation(1, 15), // (1,15): error CS1003: Syntax error, ']' expected // [_<_[delegate using' - Diagnostic(ErrorCode.ERR_SyntaxError, "using").WithArguments("]", "using").WithLocation(1, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "using").WithArguments("]").WithLocation(1, 15), // (1,15): error CS1003: Syntax error, '>' expected // [_<_[delegate using' - Diagnostic(ErrorCode.ERR_SyntaxError, "using").WithArguments(">", "using").WithLocation(1, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "using").WithArguments(">").WithLocation(1, 15), // (1,15): error CS1003: Syntax error, ']' expected // [_<_[delegate using' - Diagnostic(ErrorCode.ERR_SyntaxError, "using").WithArguments("]", "using").WithLocation(1, 15), + Diagnostic(ErrorCode.ERR_SyntaxError, "using").WithArguments("]").WithLocation(1, 15), // (1,20): error CS1031: Type expected // [_<_[delegate using' Diagnostic(ErrorCode.ERR_TypeExpected, "'").WithLocation(1, 20), diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/GreenNodeTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/GreenNodeTests.cs index 33c6b968a047a..802c4947f68e0 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/GreenNodeTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/GreenNodeTests.cs @@ -14,12 +14,12 @@ public partial class GreenNodeTests { private static void AttachAndCheckDiagnostics(InternalSyntax.CSharpSyntaxNode node) { - var nodeWithDiags = node.SetDiagnostics(new DiagnosticInfo[] { new CSDiagnosticInfo(ErrorCode.ERR_AbstractAndExtern) }); + var nodeWithDiags = node.SetDiagnostics(new DiagnosticInfo[] { new CSDiagnosticInfo(ErrorCode.ERR_NoBaseClass) }); var diags = nodeWithDiags.GetDiagnostics(); Assert.NotEqual(node, nodeWithDiags); Assert.Equal(1, diags.Length); - Assert.Equal(ErrorCode.ERR_AbstractAndExtern, (ErrorCode)diags[0].Code); + Assert.Equal(ErrorCode.ERR_NoBaseClass, (ErrorCode)diags[0].Code); } private class TokenDeleteRewriter : InternalSyntax.CSharpSyntaxRewriter diff --git a/src/Compilers/CSharp/Test/WinRT/Metadata/WinMdEventTests.cs b/src/Compilers/CSharp/Test/WinRT/Metadata/WinMdEventTests.cs index 44eb7a532aa3d..8d986c357980a 100644 --- a/src/Compilers/CSharp/Test/WinRT/Metadata/WinMdEventTests.cs +++ b/src/Compilers/CSharp/Test/WinRT/Metadata/WinMdEventTests.cs @@ -3379,16 +3379,16 @@ void Out(out System.Action a) CreateEmptyCompilation(source, WinRtRefs, TestOptions.ReleaseWinMD).VerifyDiagnostics( // (9,17): error CS7084: A Windows Runtime event may not be passed as an out or ref parameter. // Ref(ref Instance); - Diagnostic(ErrorCode.ERR_WinRtEventPassedByRef, "Instance").WithArguments("C.Instance"), + Diagnostic(ErrorCode.ERR_WinRtEventPassedByRef, "Instance").WithLocation(9, 17), // (10,17): error CS7084: A Windows Runtime event may not be passed as an out or ref parameter. // Out(out Instance); - Diagnostic(ErrorCode.ERR_WinRtEventPassedByRef, "Instance").WithArguments("C.Instance"), + Diagnostic(ErrorCode.ERR_WinRtEventPassedByRef, "Instance").WithLocation(10, 17), // (11,17): error CS7084: A Windows Runtime event may not be passed as an out or ref parameter. // Ref(ref Static); - Diagnostic(ErrorCode.ERR_WinRtEventPassedByRef, "Static").WithArguments("C.Static"), + Diagnostic(ErrorCode.ERR_WinRtEventPassedByRef, "Static").WithLocation(11, 17), // (12,17): error CS7084: A Windows Runtime event may not be passed as an out or ref parameter. // Out(out Static); - Diagnostic(ErrorCode.ERR_WinRtEventPassedByRef, "Static").WithArguments("C.Static")); + Diagnostic(ErrorCode.ERR_WinRtEventPassedByRef, "Static").WithLocation(12, 17)); } [Fact] diff --git a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/CompilationWithAnalyzersTests.cs b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/CompilationWithAnalyzersTests.cs index 803a84662d002..764b282bf749b 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/CompilationWithAnalyzersTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/CompilationWithAnalyzersTests.cs @@ -40,8 +40,8 @@ public void GetEffectiveDiagnostics() WithSpecificDiagnosticOptions( new[] { KeyValuePairUtil.Create($"CS{(int)ErrorCode.WRN_AlwaysNull:D4}", ReportDiagnostic.Suppress) })); - var d1 = SimpleDiagnostic.Create(MessageProvider.Instance, (int)ErrorCode.WRN_AlignmentMagnitude); - var d2 = SimpleDiagnostic.Create(MessageProvider.Instance, (int)ErrorCode.WRN_AlwaysNull); + var d1 = SimpleDiagnostic.Create(MessageProvider.Instance, (int)ErrorCode.WRN_AlignmentMagnitude, "1", "2"); + var d2 = SimpleDiagnostic.Create(MessageProvider.Instance, (int)ErrorCode.WRN_AlwaysNull, "1"); var ds = new[] { null, d1, d2 }; var filtered = CompilationWithAnalyzers.GetEffectiveDiagnostics(ds, c); diff --git a/src/Compilers/Core/MSBuildTaskTests/DotNetSdkTests.cs b/src/Compilers/Core/MSBuildTaskTests/DotNetSdkTests.cs index 0261f3bf7ba54..13038c587f1aa 100644 --- a/src/Compilers/Core/MSBuildTaskTests/DotNetSdkTests.cs +++ b/src/Compilers/Core/MSBuildTaskTests/DotNetSdkTests.cs @@ -398,7 +398,7 @@ public void ClearEmbedInteropTypes() }); } - [ConditionalFact(typeof(DotNetSdkAvailable))] + [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestDiscoverEditorConfigFiles() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); @@ -428,7 +428,7 @@ public void TestDiscoverEditorConfigFiles() })); } - [ConditionalFact(typeof(DotNetSdkAvailable))] + [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestDiscoverEditorConfigFilesCanBeDisabled() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); @@ -456,7 +456,7 @@ public void TestDiscoverEditorConfigFilesCanBeDisabled() expectedResults: AppendExtraEditorConfigs(new[] { "" }, findEditorConfigs: false)); } - [ConditionalFact(typeof(DotNetSdkAvailable))] + [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestDiscoverGlobalConfigFiles() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); @@ -490,7 +490,7 @@ public void TestDiscoverGlobalConfigFiles() })); } - [ConditionalFact(typeof(DotNetSdkAvailable))] + [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestDiscoverGlobalConfigFilesCanBeDisabled() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); @@ -523,7 +523,7 @@ public void TestDiscoverGlobalConfigFilesCanBeDisabled() }, findGlobalConfigs: false)); } - [ConditionalFact(typeof(DotNetSdkAvailable))] + [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestDiscoverGlobalConfigFilesWhenEditorConfigDisabled() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); @@ -617,7 +617,7 @@ public void TestDiscoverEditorAndGlobalConfigFilesCanBeDisabled() expectedResults: new[] { "" }); } - [ConditionalFact(typeof(DotNetSdkAvailable))] + [ConditionalFact(typeof(DotNetSdkAvailable), typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/61017")] public void TestGlobalConfigsCanBeManuallyAdded() { var srcFile = ProjectDir.CreateFile("lib1.cs").WriteAllText("class C { }"); diff --git a/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs b/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs index e79db74edf510..d378489b3457f 100644 --- a/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs +++ b/src/Compilers/Core/Portable/CommandLine/CommandLineParser.cs @@ -354,7 +354,7 @@ protected ImmutableArray> ParsePathMap(string pathM var kv = SplitWithDoubledSeparatorEscaping(kEqualsV, '='); if (kv.Length != 2) { - errors.Add(Diagnostic.Create(_messageProvider, _messageProvider.ERR_InvalidPathMap, kEqualsV)); + errors.Add(Diagnostic.Create(_messageProvider, _messageProvider.ERR_InvalidPathMap)); continue; } @@ -363,7 +363,7 @@ protected ImmutableArray> ParsePathMap(string pathM if (from.Length == 0 || to.Length == 0) { - errors.Add(Diagnostic.Create(_messageProvider, _messageProvider.ERR_InvalidPathMap, kEqualsV)); + errors.Add(Diagnostic.Create(_messageProvider, _messageProvider.ERR_InvalidPathMap)); } else { diff --git a/src/Compilers/Core/Portable/Compilation/IImportScope.cs b/src/Compilers/Core/Portable/Compilation/IImportScope.cs new file mode 100644 index 0000000000000..0650f2b8bb070 --- /dev/null +++ b/src/Compilers/Core/Portable/Compilation/IImportScope.cs @@ -0,0 +1,147 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Diagnostics; + +namespace Microsoft.CodeAnalysis; + +/// +/// Represents the set of symbols that are imported to a particular position in a source file. Each import has a +/// reference to the location the import directive was declared at. For the import, the +/// location can be found using either or on the itself. For +/// or the location is found through or respectively. +/// +/// +/// +/// Scopes returned will always have at least one non-empty property value in them. +/// Symbols may be imported, but may not necessarily be available at that location (for example, an alias +/// symbol hidden by another symbol). +/// +/// In C# there will be an for every containing namespace-declarations that include any +/// import directives. There will also be an for the containing compilation-unit if it +/// includes any import directives or if there are global import directives pulled in from other files. +/// +/// +/// In Visual Basic there will commonly be one or two s returned for any position. This will +/// commonly be a scope for the containing compilation unit if it includes any import directives. As well as a scope +/// representing any imports specified at the project level. +/// +/// +/// Elements of any property have no defined order. Even if they represent items from a single document, they are +/// not guaranteed to be returned in any specific file-oriented order. +/// +/// There is no guarantee that the same scope instances will be returned from successive calls to . +/// +/// +public interface IImportScope +{ + /// + /// Aliases defined at this level of the chain. This corresponds to using X = TypeOrNamespace; in C# or + /// Imports X = TypeOrNamespace in Visual Basic. This will include global aliases if present for both + /// languages. + /// + /// May be , will never be . + ImmutableArray Aliases { get; } + + /// + /// Extern aliases defined at this level of the chain. This corresponds to extern alias X; in C#. It + /// will be empty in Visual Basic. + /// + /// May be , will never be . + ImmutableArray ExternAliases { get; } + + /// + /// Types or namespaces imported at this level of the chain. This corresponds to using Namespace; or + /// using static Type; in C#, or Imports TypeOrNamespace in Visual Basic. This will include + /// global namespace or type imports for both languages. + /// + /// May be , will never be . + ImmutableArray Imports { get; } + + /// + /// Xml namespaces imported at this level of the chain. This corresponds to Imports <xmlns:prefix = + /// "name"> in Visual Basic. It will be empty in C#. + /// + /// May be , will never be . + ImmutableArray XmlNamespaces { get; } +} + +/// +/// Represents an that has been imported, and the location the import was +/// declared at. This corresponds to using Namespace; or using static Type; in C#, or Imports +/// TypeOrNamespace in Visual Basic. +/// +public readonly struct ImportedNamespaceOrType +{ + public INamespaceOrTypeSymbol NamespaceOrType { get; } + + /// + /// Location in source where the using directive or Imports clause was declared. Will never be + /// null for C#, may be null for Visual Basic for a project-level import directive. + /// + public SyntaxReference? DeclaringSyntaxReference { get; } + + internal ImportedNamespaceOrType(INamespaceOrTypeSymbol namespaceOrType, SyntaxReference? declaringSyntaxReference) + { + NamespaceOrType = namespaceOrType; + DeclaringSyntaxReference = declaringSyntaxReference; + } +} + +/// +/// Represents an imported xml namespace name. This corresponds to Imports <xmlns:prefix = "name"> in +/// Visual Basic. It does not exist for C#. +/// +public readonly struct ImportedXmlNamespace +{ + public string XmlNamespace { get; } + + /// + /// Location in source where the Imports clause was declared. May be null for a project-level import + /// directive. + /// + public SyntaxReference? DeclaringSyntaxReference { get; } + + internal ImportedXmlNamespace(string xmlNamespace, SyntaxReference? declaringSyntaxReference) + { + XmlNamespace = xmlNamespace; + DeclaringSyntaxReference = declaringSyntaxReference; + } +} + +/// +/// Simple POCO implementation of the import scope, usable by both C# and VB. +/// +internal sealed class SimpleImportScope : IImportScope +{ + public SimpleImportScope( + ImmutableArray aliases, + ImmutableArray externAliases, + ImmutableArray imports, + ImmutableArray xmlNamespaces) + { + Debug.Assert(!aliases.IsDefault); + Debug.Assert(!externAliases.IsDefault); + Debug.Assert(!imports.IsDefault); + Debug.Assert(!xmlNamespaces.IsDefault); + Debug.Assert(aliases.Length + externAliases.Length + imports.Length + xmlNamespaces.Length > 0); + + // We make no guarantees about order of these arrays. So intentionally reorder them in debug to help find any + // cases where code may be depending on a particular order. + Aliases = aliases.ConditionallyDeOrder(); + ExternAliases = externAliases.ConditionallyDeOrder(); + Imports = imports.ConditionallyDeOrder(); + XmlNamespaces = xmlNamespaces.ConditionallyDeOrder(); + } + + public ImmutableArray Aliases { get; } + public ImmutableArray ExternAliases { get; } + public ImmutableArray Imports { get; } + public ImmutableArray XmlNamespaces { get; } +} diff --git a/src/Compilers/Core/Portable/Compilation/SemanticModel.cs b/src/Compilers/Core/Portable/Compilation/SemanticModel.cs index 61204b54280c5..1b7160d8f17cf 100644 --- a/src/Compilers/Core/Portable/Compilation/SemanticModel.cs +++ b/src/Compilers/Core/Portable/Compilation/SemanticModel.cs @@ -773,6 +773,16 @@ internal DataFlowAnalysis AnalyzeDataFlow(SyntaxNode statementOrExpression) /// protected abstract ISymbol? GetEnclosingSymbolCore(int position, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// Given a position in the SyntaxTree for this SemanticModel returns the s at that + /// point. Scopes are ordered from closest to the passed in to the furthest. See + /// for a deeper description of what information is available for each scope. + /// + public ImmutableArray GetImportScopes(int position, CancellationToken cancellationToken = default) + => GetImportScopesCore(position, cancellationToken); + + private protected abstract ImmutableArray GetImportScopesCore(int position, CancellationToken cancellationToken); + /// /// Determines if the symbol is accessible from the specified location. /// diff --git a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs index 8a49a6741599d..bf19bca37db59 100644 --- a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs +++ b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs @@ -150,6 +150,10 @@ public string GetIdForErrorCode(int errorCode) } } +#if DEBUG + internal abstract bool ShouldAssertExpectedMessageArgumentsLength(int errorCode); +#endif + // Common error messages public abstract int ERR_FailedToCreateTempFile { get; } diff --git a/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs b/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs index 433e23d507e5b..a1394dc9feb3f 100644 --- a/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs +++ b/src/Compilers/Core/Portable/Diagnostic/DiagnosticInfo.cs @@ -8,8 +8,8 @@ using System.Diagnostics; using System.Globalization; using System.Reflection; +using System.Text.RegularExpressions; using Roslyn.Utilities; -using System.Threading; using Microsoft.CodeAnalysis.Symbols; namespace Microsoft.CodeAnalysis @@ -43,20 +43,20 @@ static DiagnosticInfo() // Only the compiler creates instances. internal DiagnosticInfo(CommonMessageProvider messageProvider, int errorCode) + : this(messageProvider, errorCode, Array.Empty()) { - _messageProvider = messageProvider; - _errorCode = errorCode; - _defaultSeverity = messageProvider.GetSeverity(errorCode); - _effectiveSeverity = _defaultSeverity; - _arguments = Array.Empty(); } // Only the compiler creates instances. internal DiagnosticInfo(CommonMessageProvider messageProvider, int errorCode, params object[] arguments) - : this(messageProvider, errorCode) { AssertMessageSerializable(arguments); + AssertExpectedMessageArgumentsLength(messageProvider, errorCode, arguments.Length); + _messageProvider = messageProvider; + _errorCode = errorCode; + _defaultSeverity = messageProvider.GetSeverity(errorCode); + _effectiveSeverity = _defaultSeverity; _arguments = arguments; } @@ -122,6 +122,32 @@ internal static void AssertMessageSerializable(object[] args) } } + [Conditional("DEBUG")] + private static void AssertExpectedMessageArgumentsLength(CommonMessageProvider messageProvider, int errorCode, int actualLength) + { +#if DEBUG + if (!messageProvider.ShouldAssertExpectedMessageArgumentsLength(errorCode)) + { + return; + } + string message = messageProvider.LoadMessage(errorCode, language: null); + var matches = Regex.Matches(message, @"\{\d+[}:]"); + int expectedLength = 0; + var bits = BitVector.Create(actualLength); + foreach (object? m in matches) + { + if (m is Match match) + { + int value = int.Parse(match.Value[1..^1]); + expectedLength = Math.Max(value + 1, expectedLength); + bits[value] = true; + } + } + Debug.Assert(expectedLength == actualLength); + Debug.Assert(bits == BitVector.AllSet(actualLength)); +#endif + } + // Only the compiler creates instances. internal DiagnosticInfo(CommonMessageProvider messageProvider, bool isWarningAsError, int errorCode, params object[] arguments) : this(messageProvider, errorCode, arguments) diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs index 6ebeddb3acb4d..b3ba75805e72e 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/SymbolChanges.cs @@ -191,6 +191,15 @@ public SymbolChange GetChange(IDefinition def) private SymbolChange GetChange(ISymbol symbol) { + // In CalculateChanges we always store definitions for partial methods, so we have to + // make sure we do the same thing here when we try to retrieve a change, as the compiler + // associates synthesized methods with the implementation of the method that caused it + // to be generated. + if (symbol is IMethodSymbol method) + { + symbol = method.PartialDefinitionPart ?? symbol; + } + if (_changes.TryGetValue(symbol, out var change)) { return change; diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 3d4f710284bf8..54e2766c89e34 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,6 +1,28 @@ *REMOVED*override abstract Microsoft.CodeAnalysis.Diagnostic.Equals(object? obj) -> bool abstract Microsoft.CodeAnalysis.SymbolVisitor.DefaultResult.get -> TResult Microsoft.CodeAnalysis.Compilation.GetTypesByMetadataName(string! fullyQualifiedMetadataName) -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.IImportScope +Microsoft.CodeAnalysis.IImportScope.Aliases.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.IImportScope.ExternAliases.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.IImportScope.Imports.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.IImportScope.XmlNamespaces.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.ImportedNamespaceOrType +Microsoft.CodeAnalysis.ImportedNamespaceOrType.DeclaringSyntaxReference.get -> Microsoft.CodeAnalysis.SyntaxReference? +Microsoft.CodeAnalysis.ImportedNamespaceOrType.ImportedNamespaceOrType() -> void +Microsoft.CodeAnalysis.ImportedNamespaceOrType.NamespaceOrType.get -> Microsoft.CodeAnalysis.INamespaceOrTypeSymbol! +Microsoft.CodeAnalysis.ImportedXmlNamespace +Microsoft.CodeAnalysis.ImportedXmlNamespace.DeclaringSyntaxReference.get -> Microsoft.CodeAnalysis.SyntaxReference? +Microsoft.CodeAnalysis.ImportedXmlNamespace.ImportedXmlNamespace() -> void +Microsoft.CodeAnalysis.ImportedXmlNamespace.XmlNamespace.get -> string! +Microsoft.CodeAnalysis.GeneratorDriver.GetTimingInfo() -> Microsoft.CodeAnalysis.GeneratorDriverTimingInfo +Microsoft.CodeAnalysis.GeneratorDriverTimingInfo +Microsoft.CodeAnalysis.GeneratorDriverTimingInfo.ElapsedTime.get -> System.TimeSpan +Microsoft.CodeAnalysis.GeneratorDriverTimingInfo.GeneratorDriverTimingInfo() -> void +Microsoft.CodeAnalysis.GeneratorDriverTimingInfo.GeneratorTimes.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.GeneratorTimingInfo +Microsoft.CodeAnalysis.GeneratorTimingInfo.ElapsedTime.get -> System.TimeSpan +Microsoft.CodeAnalysis.GeneratorTimingInfo.Generator.get -> Microsoft.CodeAnalysis.ISourceGenerator! +Microsoft.CodeAnalysis.GeneratorTimingInfo.GeneratorTimingInfo() -> void Microsoft.CodeAnalysis.IOperation.ChildOperations.get -> Microsoft.CodeAnalysis.IOperation.OperationList Microsoft.CodeAnalysis.IOperation.OperationList Microsoft.CodeAnalysis.IOperation.OperationList.Any() -> bool @@ -26,6 +48,7 @@ Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Reversed() -> void Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Count.get -> int Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.GetEnumerator() -> Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Enumerator Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.ToImmutableArray() -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.SemanticModel.GetImportScopes(int position, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.ISymbol.Accept(Microsoft.CodeAnalysis.SymbolVisitor! visitor, TArgument argument) -> TResult Microsoft.CodeAnalysis.SymbolVisitor Microsoft.CodeAnalysis.SymbolVisitor.SymbolVisitor() -> void diff --git a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs index c5600031fc264..eabe61bc42efd 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GeneratorDriver.cs @@ -158,6 +158,12 @@ static ImmutableArray getGeneratorSources(GeneratorState } } + public GeneratorDriverTimingInfo GetTimingInfo() + { + var generatorTimings = _state.Generators.ZipAsArray(_state.GeneratorStates, (generator, generatorState) => new GeneratorTimingInfo(generator, generatorState.ElapsedTime)); + return new GeneratorDriverTimingInfo(_state.RunTime, generatorTimings); + } + internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, DiagnosticBag? diagnosticsBag, CancellationToken cancellationToken = default) { // with no generators, there is no work to do @@ -252,7 +258,7 @@ internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, Diagnos continue; } - using var generatorTimer = CodeAnalysisEventSource.Log.CreateSingleGeneratorRunTimer(state.Generators[i]); + using var generatorTimer = CodeAnalysisEventSource.Log.CreateSingleGeneratorRunTimer(state.Generators[i], (t) => t.Add(syntaxStoreBuilder.GetRuntimeAdjustment(stateBuilder[i].InputNodes))); try { // We do not support incremental step tracking for v1 generators, as the pipeline is implicitly defined. diff --git a/src/Compilers/Core/Portable/SourceGeneration/GeneratorTimerExtensions.cs b/src/Compilers/Core/Portable/SourceGeneration/GeneratorTimerExtensions.cs index 2b050708aed55..399e25f2c79a9 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/GeneratorTimerExtensions.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/GeneratorTimerExtensions.cs @@ -27,18 +27,18 @@ public static RunTimer CreateGeneratorDriverRunTimer(this CodeAnalysisEventSourc } } - public static RunTimer CreateSingleGeneratorRunTimer(this CodeAnalysisEventSource eventSource, ISourceGenerator generator) + public static RunTimer CreateSingleGeneratorRunTimer(this CodeAnalysisEventSource eventSource, ISourceGenerator generator, Func adjustRunTime) { if (eventSource.IsEnabled(EventLevel.Informational, Keywords.Performance)) { var id = Guid.NewGuid().ToString(); var type = generator.GetGeneratorType(); eventSource.StartSingleGeneratorRunTime(type.FullName!, type.Assembly.Location, id); - return new RunTimer(t => eventSource.StopSingleGeneratorRunTime(type.FullName!, type.Assembly.Location, t.Ticks, id)); + return new RunTimer(t => eventSource.StopSingleGeneratorRunTime(type.FullName!, type.Assembly.Location, t.Ticks, id), adjustRunTime); } else { - return new RunTimer(); + return new RunTimer(adjustRunTime); } } @@ -46,17 +46,25 @@ public static RunTimer CreateSingleGeneratorRunTimer(this CodeAnalysisEventSourc { private readonly SharedStopwatch _timer; private readonly Action? _callback; + private readonly Func? _adjustRunTime; - public TimeSpan Elapsed => _timer.Elapsed; + public TimeSpan Elapsed => _adjustRunTime is not null ? _adjustRunTime(_timer.Elapsed) : _timer.Elapsed; public RunTimer() { _timer = SharedStopwatch.StartNew(); _callback = null; + _adjustRunTime = null; } - public RunTimer(Action callback) + public RunTimer(Func? adjustRunTime) : this() + { + _adjustRunTime = adjustRunTime; + } + + public RunTimer(Action callback, Func? adjustRunTime = null) + : this(adjustRunTime) { _callback = callback; } @@ -65,8 +73,7 @@ public void Dispose() { if (_callback is not null) { - var elapsed = _timer.Elapsed; - _callback(elapsed); + _callback(Elapsed); } } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/RunResults.cs b/src/Compilers/Core/Portable/SourceGeneration/RunResults.cs index 1f5eb4b9573a9..dda8cb5da2406 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/RunResults.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/RunResults.cs @@ -164,4 +164,51 @@ internal GeneratedSourceResult(SyntaxTree tree, SourceText text, string hintName /// public string HintName { get; } } + + /// + /// Contains timing information for a full generation pass. + /// + public readonly struct GeneratorDriverTimingInfo + { + internal GeneratorDriverTimingInfo(TimeSpan elapsedTime, ImmutableArray generatorTimes) + { + ElapsedTime = elapsedTime; + GeneratorTimes = generatorTimes; + } + + /// + /// The wall clock time that the entire generation pass took. + /// + /// + /// This can be more than the sum of times in as it includes other costs such as setup. + /// + public TimeSpan ElapsedTime { get; } + + /// + /// Individual timings per generator. + /// + public ImmutableArray GeneratorTimes { get; } + } + + /// + /// Contains timing information for a single generator. + /// + public readonly struct GeneratorTimingInfo + { + internal GeneratorTimingInfo(ISourceGenerator generator, TimeSpan elapsedTime) + { + Generator = generator; + ElapsedTime = elapsedTime; + } + + /// + /// The that was running during the recorded time. + /// + public ISourceGenerator Generator { get; } + + /// + /// The wall clock time the generator spent running. + /// + public TimeSpan ElapsedTime { get; } + } } diff --git a/src/Compilers/Core/Portable/SourceGeneration/SyntaxStore.cs b/src/Compilers/Core/Portable/SourceGeneration/SyntaxStore.cs index 0a04c950e7617..0a29746b15902 100644 --- a/src/Compilers/Core/Portable/SourceGeneration/SyntaxStore.cs +++ b/src/Compilers/Core/Portable/SourceGeneration/SyntaxStore.cs @@ -28,6 +28,7 @@ private SyntaxStore(StateTableStore tables, Compilation? compilation) public sealed class Builder { private readonly ImmutableDictionary.Builder _syntaxExceptions = ImmutableDictionary.CreateBuilder(); + private readonly ImmutableDictionary.Builder _syntaxTimes = ImmutableDictionary.CreateBuilder(); private readonly StateTableStore.Builder _tableBuilder = new StateTableStore.Builder(); private readonly Compilation _compilation; private readonly ImmutableArray _syntaxInputNodes; @@ -69,13 +70,12 @@ public IStateTable GetSyntaxInputTable(SyntaxInputNode syntaxInputNode, NodeStat else { syntaxInputBuilders.Add((node, node.GetBuilder(_previous._tables, _enableTracking))); + _syntaxTimes[node] = TimeSpan.Zero; } } if (syntaxInputBuilders.Count > 0) { - GeneratorRunStateTable.Builder temporaryRunStateBuilder = new GeneratorRunStateTable.Builder(_enableTracking); - // at this point we need to grab the syntax trees from the new compilation, and optionally diff them against the old ones NodeStateTable syntaxTreeState = syntaxTreeTable; @@ -86,17 +86,33 @@ public IStateTable GetSyntaxInputTable(SyntaxInputNode syntaxInputNode, NodeStat var model = state != EntryState.Removed ? _compilation.GetSemanticModel(tree) : null; for (int i = 0; i < syntaxInputBuilders.Count; i++) { + var currentNode = syntaxInputBuilders[i].node; try { - _cancellationToken.ThrowIfCancellationRequested(); - syntaxInputBuilders[i].builder.VisitTree(root, state, model, _cancellationToken); + Stopwatch sw = Stopwatch.StartNew(); + try + { + _cancellationToken.ThrowIfCancellationRequested(); + syntaxInputBuilders[i].builder.VisitTree(root, state, model, _cancellationToken); + } + finally + { + var elapsed = sw.Elapsed; + + // if this node isn't the one that caused the update, ensure we remember it and remove the time it took from the requester + if (currentNode != syntaxInputNode) + { + _syntaxTimes[syntaxInputNode] = _syntaxTimes[syntaxInputNode].Subtract(elapsed); + _syntaxTimes[currentNode] = _syntaxTimes[currentNode].Add(elapsed); + } + } } catch (UserFunctionException ufe) { // we're evaluating this node ahead of time, so we can't just throw the exception // instead we'll hold onto it, and throw the exception when a downstream node actually // attempts to read the value - _syntaxExceptions[syntaxInputBuilders[i].node] = ufe; + _syntaxExceptions[currentNode] = ufe; syntaxInputBuilders.RemoveAt(i); i--; } @@ -121,6 +137,34 @@ public IStateTable GetSyntaxInputTable(SyntaxInputNode syntaxInputNode, NodeStat return result; } + /// + /// Gets the adjustment to wall clock time that should be applied for a set of input nodes. + /// + /// + /// The syntax store updates all input nodes in parallel the first time an input node is asked to update, + /// so that it can share the semantic model between multiple nodes and improve perf. + /// + /// Unfortunately that means that the first generator to request the results of a syntax node will incorrectly + /// have its wall clock time contain the time of all other syntax nodes. And conversely other input nodes will + /// not have the true time taken. + /// + /// This method gets the adjustment that should be applied to the wall clock time for a set of input nodes + /// so that the correct time is attributed to each. + /// + public TimeSpan GetRuntimeAdjustment(ImmutableArray inputNodes) + { + TimeSpan result = TimeSpan.Zero; + foreach (var node in inputNodes) + { + // only add if this node ran at all during this pass + if (_syntaxTimes.TryGetValue(node, out var adjustment)) + { + result = result.Add(adjustment); + } + } + return result; + } + public SyntaxStore ToImmutable() { return new SyntaxStore(_tableBuilder.ToImmutable(), _compilation); diff --git a/src/Compilers/Shared/BuildServerConnection.cs b/src/Compilers/Shared/BuildServerConnection.cs index 5ca8f328d0c77..de785fd8fb004 100644 --- a/src/Compilers/Shared/BuildServerConnection.cs +++ b/src/Compilers/Shared/BuildServerConnection.cs @@ -96,7 +96,7 @@ internal static async Task RunServerShutdownRequestAsync( try { var process = Process.GetProcessById(shutdownBuildResponse.ServerProcessId); -#if NET50_OR_GREATER +#if NET5_0_OR_GREATER await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false); #else process.WaitForExit(); diff --git a/src/Compilers/Test/Core/Traits/Traits.cs b/src/Compilers/Test/Core/Traits/Traits.cs index 942c762f2247a..586fa4ae36379 100644 --- a/src/Compilers/Test/Core/Traits/Traits.cs +++ b/src/Compilers/Test/Core/Traits/Traits.cs @@ -208,6 +208,7 @@ public static class Features public const string CodeActionsUseSimpleUsingStatement = "CodeActions.UseSimpleUsingStatement"; public const string CodeActionsUseSystemHashCode = "CodeActions.UseSystemHashCode"; public const string CodeActionsUseThrowExpression = "CodeActions.UseThrowExpression"; + public const string CodeActionsUseUTF8StringLiteral = "CodeActions.CodeActionsUseUTF8StringLiteral"; public const string CodeActionsWrapping = "CodeActions.Wrapping"; public const string CodeCleanup = nameof(CodeCleanup); public const string CodeDefinitionWindow = nameof(CodeDefinitionWindow); diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binder_Expressions.vb b/src/Compilers/VisualBasic/Portable/Binding/Binder_Expressions.vb index 5bc2260ba44d6..3c75d173d686f 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binder_Expressions.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binder_Expressions.vb @@ -3934,7 +3934,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Else err = ERRID.ERR_TooFewIndices End If - ReportDiagnostic(diagnostics, node.ArgumentList, err, node.ToString()) + ReportDiagnostic(diagnostics, node.ArgumentList, err) Return New BoundArrayAccess(node, expr, boundArguments, arrayType.ElementType, hasErrors:=True) End If diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binder_Imports.vb b/src/Compilers/VisualBasic/Portable/Binding/Binder_Imports.vb index 1fac97ea78be9..bb1fb82ab5128 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binder_Imports.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binder_Imports.vb @@ -30,7 +30,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public ReadOnly Aliases As Dictionary(Of String, AliasAndImportsClausePosition) Public ReadOnly XmlNamespaces As Dictionary(Of String, XmlNamespaceAndImportsClausePosition) - Public MustOverride Sub AddMember(syntaxRef As SyntaxReference, member As NamespaceOrTypeSymbol, importsClausePosition As Integer, dependencies As IReadOnlyCollection(Of AssemblySymbol)) + Public MustOverride Sub AddMember(syntaxRef As SyntaxReference, member As NamespaceOrTypeSymbol, importsClausePosition As Integer, dependencies As IReadOnlyCollection(Of AssemblySymbol), isProjectImportsDeclaration As Boolean) Public MustOverride Sub AddAlias(syntaxRef As SyntaxReference, name As String, [alias] As AliasSymbol, importsClausePosition As Integer, dependencies As IReadOnlyCollection(Of AssemblySymbol)) End Class @@ -206,7 +206,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End If If importedSymbolIsValid Then - data.AddMember(binder.GetSyntaxReference(importsName), importedSymbol, membersImportsSyntax.SpanStart, dependenciesBag) + data.AddMember(binder.GetSyntaxReference(importsName), importedSymbol, membersImportsSyntax.SpanStart, dependenciesBag, binder.BindingLocation = BindingLocation.ProjectImportsDeclaration) End If End If End If @@ -237,7 +237,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ' "XML namespace prefix '{0}' is already declared." Binder.ReportDiagnostic(diagBag, syntax, ERRID.ERR_DuplicatePrefix, prefix) Else - data.XmlNamespaces.Add(prefix, New XmlNamespaceAndImportsClausePosition(namespaceName, syntax.SpanStart)) + ' Do not expose any locations for project level xml namespaces. This matches the effective + ' logic we have for aliases, which are given NoLocation.Singleton (which never translates to a + ' DeclaringSyntaxReference). + Dim reference = If(binder.BindingLocation = BindingLocation.ProjectImportsDeclaration, + Nothing, + binder.GetSyntaxReference(syntax)) + data.XmlNamespaces.Add(prefix, New XmlNamespaceAndImportsClausePosition(namespaceName, syntax.SpanStart, reference)) End If End If #If DEBUG Then diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binder_Statements.vb b/src/Compilers/VisualBasic/Portable/Binding/Binder_Statements.vb index 3e92634817dd9..604ad8d2dc236 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binder_Statements.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binder_Statements.vb @@ -5191,7 +5191,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic If Not exceptionType.IsOrDerivedFromWellKnownClass(WellKnownType.System_Exception, Compilation, useSiteInfo) Then hasError = True - ReportDiagnostic(diagnostics, node, ERRID.ERR_CantThrowNonException, exceptionType) + ReportDiagnostic(diagnostics, node, ERRID.ERR_CantThrowNonException) End If diagnostics.Add(node, useSiteInfo) diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binder_XmlLiterals.vb b/src/Compilers/VisualBasic/Portable/Binding/Binder_XmlLiterals.vb index 18066d1b30fe6..c4b652f056ce8 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binder_XmlLiterals.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binder_XmlLiterals.vb @@ -1432,6 +1432,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic _namespaces = namespaces End Sub + Public Function GetImportChainData() As ImmutableArray(Of ImportedXmlNamespace) + Return _namespaces.SelectAsArray(Function(kvp) New ImportedXmlNamespace(kvp.Value.XmlNamespace, kvp.Value.SyntaxReference)) + End Function + Friend Overrides ReadOnly Property HasImportedXmlNamespaces As Boolean Get Return True diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binders/AliasAndImportsClause.vb b/src/Compilers/VisualBasic/Portable/Binding/Binders/AliasAndImportsClause.vb index c360834dac25b..4eb5ccc853e04 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binders/AliasAndImportsClause.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binders/AliasAndImportsClause.vb @@ -17,11 +17,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Friend Structure AliasAndImportsClausePosition Public ReadOnly [Alias] As AliasSymbol Public ReadOnly ImportsClausePosition As Integer + Public ReadOnly SyntaxReference As SyntaxReference Public ReadOnly Dependencies As ImmutableArray(Of AssemblySymbol) - Public Sub New([alias] As AliasSymbol, importsClausePosition As Integer, dependencies As ImmutableArray(Of AssemblySymbol)) + Public Sub New([alias] As AliasSymbol, importsClausePosition As Integer, syntaxReference As SyntaxReference, dependencies As ImmutableArray(Of AssemblySymbol)) Me.Alias = [alias] Me.ImportsClausePosition = importsClausePosition + Me.SyntaxReference = syntaxReference Me.Dependencies = dependencies End Sub End Structure diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binders/NamespaceOrTypeAndImportsClause.vb b/src/Compilers/VisualBasic/Portable/Binding/Binders/NamespaceOrTypeAndImportsClause.vb index 0727b65cc8f67..7dd6fff8de129 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binders/NamespaceOrTypeAndImportsClause.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binders/NamespaceOrTypeAndImportsClause.vb @@ -2,27 +2,20 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Concurrent -Imports System.Collections.Generic Imports System.Collections.Immutable -Imports System.Runtime.InteropServices -Imports System.Threading -Imports Microsoft.CodeAnalysis.RuntimeMembers -Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Namespace Microsoft.CodeAnalysis.VisualBasic - Friend Structure NamespaceOrTypeAndImportsClausePosition Public ReadOnly NamespaceOrType As NamespaceOrTypeSymbol Public ReadOnly ImportsClausePosition As Integer + Public ReadOnly SyntaxReference As SyntaxReference Public ReadOnly Dependencies As ImmutableArray(Of AssemblySymbol) - Public Sub New(namespaceOrType As NamespaceOrTypeSymbol, importsClausePosition As Integer, dependencies As ImmutableArray(Of AssemblySymbol)) + Public Sub New(namespaceOrType As NamespaceOrTypeSymbol, importsClausePosition As Integer, syntaxReference As SyntaxReference, dependencies As ImmutableArray(Of AssemblySymbol)) Me.NamespaceOrType = namespaceOrType Me.ImportsClausePosition = importsClausePosition + Me.SyntaxReference = syntaxReference Me.Dependencies = dependencies End Sub End Structure diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binders/XmlNamespaceAndImportsClause.vb b/src/Compilers/VisualBasic/Portable/Binding/Binders/XmlNamespaceAndImportsClause.vb index d06fc76bf02bd..7c0b90c3736bd 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binders/XmlNamespaceAndImportsClause.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binders/XmlNamespaceAndImportsClause.vb @@ -2,24 +2,17 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Generic -Imports System.Runtime.InteropServices -Imports System.Text -Imports Microsoft.CodeAnalysis.Collections -Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic.Symbols -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Imports TypeKind = Microsoft.CodeAnalysis.TypeKind - Namespace Microsoft.CodeAnalysis.VisualBasic Friend Structure XmlNamespaceAndImportsClausePosition Public ReadOnly XmlNamespace As String Public ReadOnly ImportsClausePosition As Integer + Public ReadOnly SyntaxReference As SyntaxReference - Public Sub New(xmlNamespace As String, importsClausePosition As Integer) + Public Sub New(xmlNamespace As String, importsClausePosition As Integer, syntaxReference As SyntaxReference) Me.XmlNamespace = xmlNamespace Me.ImportsClausePosition = importsClausePosition + Me.SyntaxReference = syntaxReference End Sub End Structure End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Binding/ImportAliasesBinder.vb b/src/Compilers/VisualBasic/Portable/Binding/ImportAliasesBinder.vb index 8a4c6ed667f22..070b160a16925 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/ImportAliasesBinder.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/ImportAliasesBinder.vb @@ -7,6 +7,7 @@ Imports System.Collections.Generic Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports System.Threading +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.RuntimeMembers Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols @@ -40,6 +41,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic TypeOf containingBinder.ContainingBinder.ContainingBinder Is SourceModuleBinder))) End Sub + Public Function GetImportChainData() As ImmutableArray(Of IAliasSymbol) + Return ImmutableArray(Of IAliasSymbol).CastUp(_importedAliases.SelectAsArray(Function(kvp) kvp.Value.Alias)) + End Function + Friend Overrides Sub LookupInSingleBinder(lookupResult As LookupResult, name As String, arity As Integer, diff --git a/src/Compilers/VisualBasic/Portable/Binding/LookupResult.vb b/src/Compilers/VisualBasic/Portable/Binding/LookupResult.vb index 0dacf21ade200..53d57a3db6151 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/LookupResult.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/LookupResult.vb @@ -146,7 +146,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ' Gets a bad result for a symbol that doesn't match static/instance Public Shared Function MustNotBeInstance(sym As Symbol, err As ERRID) As SingleLookupResult - Return New SingleLookupResult(LookupResultKind.MustNotBeInstance, sym, New BadSymbolDiagnostic(sym, err)) + Return New SingleLookupResult(LookupResultKind.MustNotBeInstance, sym, New BadSymbolDiagnostic(sym, err, Array.Empty(Of Object))) End Function ' Gets a bad result for a symbol that doesn't match static/instance, with no error message (special case for API-access) diff --git a/src/Compilers/VisualBasic/Portable/Binding/TypesOfImportedNamespacesMembersBinder.vb b/src/Compilers/VisualBasic/Portable/Binding/TypesOfImportedNamespacesMembersBinder.vb index 4a53e66b42276..25cb9d310d9f6 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/TypesOfImportedNamespacesMembersBinder.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/TypesOfImportedNamespacesMembersBinder.vb @@ -54,6 +54,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Next End Sub + Public Function GetImportChainData() As ImmutableArray(Of ImportedNamespaceOrType) + Return _importedSymbols.SelectAsArray(Function(n) New ImportedNamespaceOrType(n.NamespaceOrType, n.SyntaxReference)) + End Function + ''' ''' Collect extension methods with the given name that are in scope in this binder. ''' The passed in ArrayBuilder must be empty. Extension methods from the same containing type diff --git a/src/Compilers/VisualBasic/Portable/Compilation/SemanticModel.vb b/src/Compilers/VisualBasic/Portable/Compilation/SemanticModel.vb index 04993b31fb4b9..e9baf4278ddcf 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/SemanticModel.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/SemanticModel.vb @@ -6,7 +6,6 @@ Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects -Imports Microsoft.CodeAnalysis.Operations Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -3409,6 +3408,78 @@ _Default: Return GetEnclosingSymbol(position, cancellationToken) End Function + Private Protected NotOverridable Overrides Function GetImportScopesCore(position As Integer, cancellationToken As CancellationToken) As ImmutableArray(Of IImportScope) + CheckPosition(position) + Dim binder = Me.GetEnclosingBinder(position) + + Dim importScopes = ArrayBuilder(Of IImportScope).GetInstance() + AddImportScopes(binder, importScopes) + Return importScopes.ToImmutableAndFree() + End Function + + Private Shared Sub AddImportScopes(binder As Binder, scopes As ArrayBuilder(Of IImportScope)) + ' The binder chain has the following in it (walking from the innermost level outwards) + ' + ' 1. Optional binders for the compilation unit of the present source file. + ' 2. SourceFileBinder. Required. + ' 3. Optional binders for the imports brought in by the compilation options. + ' + ' Both '1' and '3' are the same binders. Specifically: + ' + ' a. XmlNamespaceImportsBinder. Optional. Present if source file has xml imports present. + ' b. ImportAliasesBinder. Optional. Present if source file has import aliases present. + ' c. TypesOfImportedNamespacesMembersBinder. Optional. Present if source file has type or namespace imports present. + ' + ' As such, we can walk upwards looking for any of these binders if present until we hit the end of the + ' binder chain. We know which set we're in depending on if we've seen the SourceFileBinder or not. + ' + ' This also means that in VB the max length of the import chain is two, while in C# it can be unbounded + ' in length. + + Dim typesOfImportedNamespacesMembers As TypesOfImportedNamespacesMembersBinder = Nothing + Dim importAliases As ImportAliasesBinder = Nothing + Dim xmlNamespaceImports As XmlNamespaceImportsBinder = Nothing + + While binder IsNot Nothing + If TypeOf binder Is SourceFileBinder Then + ' We hit the source file binder. That means anything we found up till now were the imports for this + ' file. Recurse and try to create the outer optional node, and then create a potential node for + ' this level to chain onto that. + AddImportScopeNode( + typesOfImportedNamespacesMembers, importAliases, xmlNamespaceImports, scopes) + + AddImportScopes(binder.ContainingBinder, scopes) + Return + End If + + typesOfImportedNamespacesMembers = If(typesOfImportedNamespacesMembers, TryCast(binder, TypesOfImportedNamespacesMembersBinder)) + importAliases = If(importAliases, TryCast(binder, ImportAliasesBinder)) + xmlNamespaceImports = If(xmlNamespaceImports, TryCast(binder, XmlNamespaceImportsBinder)) + + binder = binder.ContainingBinder + End While + + ' We hit the end of the binder chain. Anything we found up till now are the compilation option imports + AddImportScopeNode( + typesOfImportedNamespacesMembers, importAliases, xmlNamespaceImports, scopes) + End Sub + + Private Shared Sub AddImportScopeNode( + typesOfImportedNamespacesMembers As TypesOfImportedNamespacesMembersBinder, + importAliases As ImportAliasesBinder, + xmlNamespaceImports As XmlNamespaceImportsBinder, + scopes As ArrayBuilder(Of IImportScope)) + + Dim aliases = If(importAliases?.GetImportChainData(), ImmutableArray(Of IAliasSymbol).Empty) + Dim [imports] = If(typesOfImportedNamespacesMembers?.GetImportChainData(), ImmutableArray(Of ImportedNamespaceOrType).Empty) + Dim xmlNamespaces = If(xmlNamespaceImports?.GetImportChainData(), ImmutableArray(Of ImportedXmlNamespace).Empty) + If aliases.Length = 0 AndAlso [imports].Length = 0 AndAlso xmlNamespaces.Length = 0 Then + Return + End If + + scopes.Add(New SimpleImportScope(aliases, ExternAliases:=ImmutableArray(Of IAliasSymbol).Empty, [imports], xmlNamespaces)) + End Sub + Protected NotOverridable Overrides Function IsAccessibleCore(position As Integer, symbol As ISymbol) As Boolean Return Me.IsAccessible(position, symbol.EnsureVbSymbolOrNothing(Of Symbol)(NameOf(symbol))) End Function diff --git a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb index be62b4a41e8e6..050ce25184283 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb @@ -142,6 +142,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic hasSourceSuppression) End Function +#If DEBUG Then + Friend Overrides Function ShouldAssertExpectedMessageArgumentsLength(errorCode As Integer) As Boolean + ' Consider enabling. + Return False + End Function +#End If Public Overrides ReadOnly Property ERR_FailedToCreateTempFile As Integer Get diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFile.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFile.vb index 502865f355b0e..a7993516f79f0 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFile.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceFile.vb @@ -295,15 +295,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols _membersSyntaxBuilder = membersSyntaxBuilder End Sub - Public Overrides Sub AddMember(syntaxRef As SyntaxReference, member As NamespaceOrTypeSymbol, importsClausePosition As Integer, dependencies As IReadOnlyCollection(Of AssemblySymbol)) - Dim pair = New NamespaceOrTypeAndImportsClausePosition(member, importsClausePosition, dependencies.ToImmutableArray()) + Public Overrides Sub AddMember( + syntaxRef As SyntaxReference, + member As NamespaceOrTypeSymbol, + importsClausePosition As Integer, + dependencies As IReadOnlyCollection(Of AssemblySymbol), + isProjectImportDeclaration As Boolean) + + ' Do not expose any locations for project level imports. This matches the effective logic + ' we have for aliases, which are given NoLocation.Singleton (which never translates to a + ' DeclaringSyntaxReference). + Dim pair = New NamespaceOrTypeAndImportsClausePosition( + member, importsClausePosition, If(isProjectImportDeclaration, Nothing, syntaxRef), dependencies.ToImmutableArray()) Members.Add(member) _membersBuilder.Add(pair) _membersSyntaxBuilder.Add(syntaxRef) End Sub Public Overrides Sub AddAlias(syntaxRef As SyntaxReference, name As String, [alias] As AliasSymbol, importsClausePosition As Integer, dependencies As IReadOnlyCollection(Of AssemblySymbol)) - Aliases.Add(name, New AliasAndImportsClausePosition([alias], importsClausePosition, dependencies.ToImmutableArray())) + Aliases.Add(name, New AliasAndImportsClausePosition([alias], importsClausePosition, syntaxRef, dependencies.ToImmutableArray())) End Sub End Class diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceModuleSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceModuleSymbol.vb index 8d7702da67d2e..7d175e19ed26b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceModuleSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceModuleSymbol.vb @@ -439,8 +439,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols _dependencies = dependencies End Sub - Public Overrides Sub AddMember(syntaxRef As SyntaxReference, member As NamespaceOrTypeSymbol, importsClausePosition As Integer, dependencies As IReadOnlyCollection(Of AssemblySymbol)) - Dim pair = New NamespaceOrTypeAndImportsClausePosition(member, importsClausePosition, ImmutableArray(Of AssemblySymbol).Empty) + Public Overrides Sub AddMember( + syntaxRef As SyntaxReference, + member As NamespaceOrTypeSymbol, + importsClausePosition As Integer, + dependencies As IReadOnlyCollection(Of AssemblySymbol), + isPrjectImportDeclaration As Boolean) + ' Do not expose any locations for project level imports. This matches the effective logic + ' we have for aliases, which are given NoLocation.Singleton (which never translates to a + ' DeclaringSyntaxReference). + Dim pair = New NamespaceOrTypeAndImportsClausePosition( + member, importsClausePosition, If(isPrjectImportDeclaration, Nothing, syntaxRef), ImmutableArray(Of AssemblySymbol).Empty) Members.Add(member) _membersBuilder.Add(pair) _membersInfoBuilder.Add(New GlobalImportInfo(_globalImport, syntaxRef)) @@ -454,7 +463,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Sub Public Overrides Sub AddAlias(syntaxRef As SyntaxReference, name As String, [alias] As AliasSymbol, importsClausePosition As Integer, dependencies As IReadOnlyCollection(Of AssemblySymbol)) - Dim pair = New AliasAndImportsClausePosition([alias], importsClausePosition, ImmutableArray(Of AssemblySymbol).Empty) + Dim pair = New AliasAndImportsClausePosition([alias], importsClausePosition, syntaxRef, ImmutableArray(Of AssemblySymbol).Empty) Aliases.Add(name, pair) _aliasesBuilder.Add(pair) _aliasesInfoBuilder.Add(New GlobalImportInfo(_globalImport, syntaxRef)) diff --git a/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingErrorTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingErrorTests.vb index a80379fb6f3a1..3e08551734917 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingErrorTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Binding/BindingErrorTests.vb @@ -5584,7 +5584,7 @@ BC30375: 'New' cannot be used on an interface. End Class ).VerifyDiagnostics(Diagnostic(ERRID.ERR_NewOnAbstractClass, "New C1"), - Diagnostic(ERRID.ERR_CantThrowNonException, "Throw (New C1)").WithArguments("C1")) + Diagnostic(ERRID.ERR_CantThrowNonException, "Throw (New C1)")) End Sub diff --git a/src/Compilers/VisualBasic/Test/Semantic/Compilation/GetImportScopesTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Compilation/GetImportScopesTests.vb new file mode 100644 index 0000000000000..eed91824cef11 --- /dev/null +++ b/src/Compilers/VisualBasic/Test/Semantic/Compilation/GetImportScopesTests.vb @@ -0,0 +1,615 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Collections.Immutable +Imports System.Linq +Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports Roslyn.Test.Utilities + +Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests + + Public Class GetImportScopesTests + Inherits SemanticModelTestBase + + Private Shared Function GetImportScopes(text As String) As ImmutableArray(Of IImportScope) + Dim tree = Parse(text) + Dim comp = CreateCompilation(tree) + Dim model = comp.GetSemanticModel(tree) + Dim scopes = model.GetImportScopes(FindPositionFromText(tree, "'pos")) + Return scopes + End Function + + + Public Sub TestEmptyFile() + Dim text = "'pos" + Dim scopes = GetImportScopes(text) + Assert.Empty(scopes) + End Sub + + + Public Sub TestNoImportsBeforeMemberDeclaration() + Dim Text = "'pos +class C +end class" + Dim scopes = GetImportScopes(Text) + Assert.Empty(scopes) + End Sub + + Private Shared Function IsNamespaceWithName(symbol As INamespaceOrTypeSymbol, name As String) As Boolean + Return TryCast(symbol, INamespaceSymbol)?.Name = name + End Function + + Private Shared Function IsAliasWithName(symbol As IAliasSymbol, aliasName As String, targetName As String, inGlobalNamespace As Boolean) As Boolean + Return symbol.Name = aliasName AndAlso symbol.Target.Name = targetName AndAlso TypeOf symbol.Target Is INamespaceSymbol AndAlso DirectCast(symbol.Target, INamespaceSymbol).ContainingNamespace.IsGlobalNamespace = inGlobalNamespace + End Function + + Private Shared Function IsSimpleImportsClauseWithName(declaringSyntaxReference As SyntaxReference, name As String) As Boolean + Dim syntax = declaringSyntaxReference.GetSyntax() + Return TypeOf syntax Is IdentifierNameSyntax AndAlso + TypeOf syntax.Parent Is SimpleImportsClauseSyntax AndAlso + name = DirectCast(syntax, IdentifierNameSyntax).Identifier.Text + End Function + + Private Shared Function IsAliasImportsClauseWithName(aliasSymbol As IAliasSymbol, name As String) As Boolean + Dim syntax = aliasSymbol.DeclaringSyntaxReferences.Single().GetSyntax() + Return TypeOf syntax Is SimpleImportsClauseSyntax AndAlso DirectCast(syntax, SimpleImportsClauseSyntax).Alias.Identifier.Text = name + End Function + +#Region "normal Imports" + + + Public Sub TestBeforeImports() + Dim Text = "'pos +imports System" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().Imports) + Assert.True(IsNamespaceWithName(scopes.Single().Imports.Single().NamespaceOrType, NameOf(System))) + Assert.True(IsSimpleImportsClauseWithName(scopes.Single().Imports.Single().DeclaringSyntaxReference, NameOf(System))) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + + + Public Sub TestAfterImportsNoContent() + Dim Text = " +imports System +'pos" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().Imports) + Assert.True(IsNamespaceWithName(scopes.Single().Imports.Single().NamespaceOrType, NameOf(System))) + Assert.True(IsSimpleImportsClauseWithName(scopes.Single().Imports.Single().DeclaringSyntaxReference, NameOf(System))) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + + + Public Sub TestAfterImportsBeforeMemberDeclaration() + Dim Text = " +imports System +'pos +class C +end class +" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + Assert.True(IsNamespaceWithName(scopes.Single().Imports.Single().NamespaceOrType, NameOf(System))) + Assert.True(IsSimpleImportsClauseWithName(scopes.Single().Imports.Single().DeclaringSyntaxReference, NameOf(System))) + End Sub + + + Public Sub TestAfterMultipleImportsNoContent() + Dim Text = " +imports System +imports Microsoft +'pos" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Equal(2, scopes.Single().Imports.Length) + + Assert.True(scopes.Single().Imports.Any(Function(i) IsNamespaceWithName(i.NamespaceOrType, NameOf(System)))) + Assert.True(scopes.Single().Imports.Any(Function(i) IsNamespaceWithName(i.NamespaceOrType, NameOf(Microsoft)))) + + Assert.True(scopes.Single().Imports.Any(Function(i) IsSimpleImportsClauseWithName(i.DeclaringSyntaxReference, NameOf(System)))) + Assert.True(scopes.Single().Imports.Any(Function(i) IsSimpleImportsClauseWithName(i.DeclaringSyntaxReference, NameOf(Microsoft)))) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + + + Public Sub TestNestedNamespaceOuterPosition() + Dim Text = " +imports System + +class C + 'pos +end class + +namespace N + class D + end class +end namespace +" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().Imports) + Assert.True(IsNamespaceWithName(scopes.Single().Imports.Single().NamespaceOrType, NameOf(System))) + Assert.True(IsSimpleImportsClauseWithName(scopes.Single().Imports.Single().DeclaringSyntaxReference, NameOf(System))) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + + + Public Sub TestNestedNamespaceInnerPosition() + Dim Text = " +imports System + +namespace N + class C + 'pos + end class +end namespace +" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single.Imports) + Assert.True(IsNamespaceWithName(scopes.Single().Imports.Single().NamespaceOrType, NameOf(System))) + Assert.True(IsSimpleImportsClauseWithName(scopes.Single().Imports.Single().DeclaringSyntaxReference, NameOf(System))) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + + + Public Sub TestNestedNamespaceInnerPositionIntermediaryEmptyNamespace() + Dim Text = " +imports System + +namespace Outer + namespace N + class C + 'pos + end class + end namespace +end namespace +" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().Imports) + Assert.True(IsNamespaceWithName(scopes.Single().Imports.Single().NamespaceOrType, NameOf(System))) + Assert.True(IsSimpleImportsClauseWithName(scopes.Single().Imports.Single().DeclaringSyntaxReference, NameOf(System))) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + +#End Region + +#Region "aliases" + + + Public Sub TestBeforeAlias() + Dim Text = "'pos +imports S = System" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().Aliases) + Assert.True(IsAliasWithName(scopes.Single.Aliases().Single(), "S", NameOf(System), inGlobalNamespace:=True)) + Assert.True(IsAliasImportsClauseWithName(scopes.Single.Aliases().Single(), "S")) + + Assert.Empty(scopes.Single().Imports) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + + + Public Sub TestAfterAliasNoContent() + Dim Text = " +imports S = System +'pos" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().Aliases) + Assert.True(IsAliasWithName(scopes.Single.Aliases().Single(), "S", NameOf(System), inGlobalNamespace:=True)) + Assert.True(IsAliasImportsClauseWithName(scopes.Single.Aliases().Single(), "S")) + + Assert.Empty(scopes.Single().Imports) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + + + Public Sub TestAfterAliasBeforeMemberDeclaration() + Dim Text = " +imports S = System +'pos +class C +end class +" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().Aliases) + Assert.True(IsAliasWithName(scopes.Single.Aliases().Single(), "S", NameOf(System), inGlobalNamespace:=True)) + Assert.True(IsAliasImportsClauseWithName(scopes.Single.Aliases().Single(), "S")) + + Assert.Empty(scopes.Single().Imports) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + + + Public Sub TestAfterMultipleAliasesNoContent() + Dim Text = " +imports S = System +imports M = Microsoft +'pos" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Equal(2, scopes.Single().Aliases.Length) + + Assert.True(scopes.Single().Aliases.Any(Function(a) IsAliasWithName(a, "S", NameOf(System), inGlobalNamespace:=True))) + Assert.True(scopes.Single().Aliases.Any(Function(a) IsAliasImportsClauseWithName(a, "S"))) + Assert.True(scopes.Single().Aliases.Any(Function(a) IsAliasWithName(a, "M", NameOf(Microsoft), inGlobalNamespace:=True))) + Assert.True(scopes.Single().Aliases.Any(Function(a) IsAliasImportsClauseWithName(a, "M"))) + + Assert.Empty(scopes.Single().Imports) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + + + Public Sub TestAliasNestedNamespaceOuterPosition() + Dim Text = " +imports S = System + +class C + 'pos +end lass + +namespace N +end namespace +" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().Aliases) + Assert.True(IsAliasWithName(scopes.Single.Aliases().Single(), "S", NameOf(System), inGlobalNamespace:=True)) + Assert.True(IsAliasImportsClauseWithName(scopes.Single.Aliases().Single(), "S")) + + Assert.Empty(scopes.Single().Imports) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + + + Public Sub TestAliasNestedNamespaceInnerPosition() + Dim text = " +imports S = System + +namespace N + class C + 'pos + end class +end namespace +" + Dim scopes = GetImportScopes(text) + + Assert.Single(scopes) + + Assert.Single(scopes.Single().Aliases) + Assert.True(IsAliasWithName(scopes.Single.Aliases().Single(), "S", NameOf(System), inGlobalNamespace:=True)) + Assert.True(IsAliasImportsClauseWithName(scopes.Single.Aliases().Single(), "S")) + + Assert.Empty(scopes.Single().Imports) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().XmlNamespaces) + End Sub + +#End Region + + ' Imports + + +#Region "xml namespace" + + + Public Sub TestBeforeXmlNamespae() + Dim Text = "'pos +Imports " + Dim scopes = GetImportScopes(Text) + + Assert.Single(scopes) + + Assert.Single(scopes.Single().XmlNamespaces) + Assert.Equal("http://roslyn", scopes.Single().XmlNamespaces.Single().XmlNamespace) + Assert.True(TypeOf scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax() Is XmlNamespaceImportsClauseSyntax) + Assert.Equal("", scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax().ToString()) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().Imports) + End Sub + + + Public Sub TestAfterXmlNamespaceNoContent() + Dim Text = " +Imports +'pos" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().XmlNamespaces) + Assert.Equal("http://roslyn", scopes.Single().XmlNamespaces.Single().XmlNamespace) + Assert.True(TypeOf scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax() Is XmlNamespaceImportsClauseSyntax) + Assert.Equal("", scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax().ToString()) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().Imports) + End Sub + + + Public Sub TestAfterXmlNamespaceBeforeMemberDeclaration() + Dim Text = " +Imports +'pos +class C +end class +" + Dim scopes = GetImportScopes(Text) + + Assert.Single(scopes) + + Assert.Single(scopes.Single().XmlNamespaces) + Assert.Equal("http://roslyn", scopes.Single().XmlNamespaces.Single().XmlNamespace) + Assert.True(TypeOf scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax() Is XmlNamespaceImportsClauseSyntax) + Assert.Equal("", scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax().ToString()) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().Imports) + End Sub + + + Public Sub TestAfterMultipleXmlNamespacesNoContent() + Dim Text = " +Imports +Imports +'pos" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Equal(2, scopes.Single().XmlNamespaces.Length) + + Assert.True(scopes.Single().XmlNamespaces.Any(Function(x) x.XmlNamespace = "http://roslyn")) + Assert.True(TypeOf scopes.Single().XmlNamespaces.First().DeclaringSyntaxReference.GetSyntax() Is XmlNamespaceImportsClauseSyntax) + Assert.True(scopes.Single().XmlNamespaces.Any(Function(x) x.DeclaringSyntaxReference.GetSyntax().ToString() = "")) + + Assert.True(scopes.Single().XmlNamespaces.Any(Function(X) X.XmlNamespace = "http://roslyn2")) + Assert.True(TypeOf scopes.Single().XmlNamespaces.Last().DeclaringSyntaxReference.GetSyntax() Is XmlNamespaceImportsClauseSyntax) + Assert.True(scopes.Single().XmlNamespaces.Any(Function(x) x.DeclaringSyntaxReference.GetSyntax().ToString() = "")) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().Imports) + End Sub + + + Public Sub TestXmlNamespaceNestedNamespaceOuterPosition() + Dim Text = " +Imports + +class C + 'pos +end class + +namespace N + class D + end class +end namespace +" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().XmlNamespaces) + Assert.Equal("http://roslyn", scopes.Single().XmlNamespaces.Single().XmlNamespace) + Assert.True(TypeOf scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax() Is XmlNamespaceImportsClauseSyntax) + Assert.Equal("", scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax().ToString()) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().Imports) + End Sub + + + Public Sub TestXmlNamespaceNestedNamespaceInnerPosition() + Dim Text = " +Imports + +namespace N + class C + 'pos + end class +end namespace +" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().XmlNamespaces) + Assert.Equal("http://roslyn", scopes.Single().XmlNamespaces.Single().XmlNamespace) + Assert.True(TypeOf scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax() Is XmlNamespaceImportsClauseSyntax) + Assert.Equal("", scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax().ToString()) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().Imports) + End Sub + + + Public Sub TestXmlNamespaceNestedNamespaceInnerPositionIntermediaryEmptyNamespace() + Dim Text = " +Imports + +namespace Outer + namespace N + class C + 'pos + end class + end namespace +end namespace +" + Dim scopes = GetImportScopes(Text) + Assert.Single(scopes) + + Assert.Single(scopes.Single().XmlNamespaces) + Assert.Equal("http://roslyn", scopes.Single().XmlNamespaces.Single().XmlNamespace) + Assert.True(TypeOf scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax() Is XmlNamespaceImportsClauseSyntax) + Assert.Equal("", scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax().ToString()) + + Assert.Empty(scopes.Single().Aliases) + Assert.Empty(scopes.Single().ExternAliases) + Assert.Empty(scopes.Single().Imports) + End Sub + +#End Region + +#Region "global imports" + + Public Shared Function GetGlobalImportsOptions(ParamArray values As String()) As VisualBasicCompilationOptions + Return TestOptions.ReleaseDll.WithGlobalImports( + values.Select(Function(v) GlobalImport.Parse(v))) + End Function + + + Public Sub TestEmptyFile_WithGlobalImports() + Dim Text = " +'pos" + Dim tree = Parse(Text) + Dim comp = CreateCompilation(tree, options:=GetGlobalImportsOptions("System", "M = Microsoft", "")) + Dim model = comp.GetSemanticModel(tree) + Dim scopes = model.GetImportScopes(FindPositionFromText(tree, "'pos")) + + Assert.Single(scopes) + + Assert.Single(scopes.Single().Aliases) + Assert.True(IsAliasWithName(scopes.Single().Aliases.Single(), "M", "Microsoft", inGlobalNamespace:=True)) + Assert.Empty(scopes.Single.Aliases().Single().DeclaringSyntaxReferences) + + Assert.Single(scopes.Single().Imports) + Assert.True(IsNamespaceWithName(scopes.Single().Imports.Single().NamespaceOrType, "System")) + Assert.Null(scopes.Single().Imports.Single.DeclaringSyntaxReference) + + Assert.Single(scopes.Single().XmlNamespaces) + Assert.Equal("http://roslyn", scopes.Single().XmlNamespaces.Single().XmlNamespace) + Assert.Null(scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference) + + Assert.Empty(scopes.Single().ExternAliases) + End Sub + + + Public Sub TestInsideDeclaration_WithGlobalImports() + Dim Text = " +class C + 'pos +end class" + Dim tree = Parse(Text) + Dim comp = CreateCompilation(tree, options:=GetGlobalImportsOptions("System", "M = Microsoft", "")) + Dim model = comp.GetSemanticModel(tree) + Dim scopes = model.GetImportScopes(FindPositionFromText(tree, "'pos")) + Assert.Single(scopes) + + Assert.Single(scopes.Single().Aliases) + Assert.True(IsAliasWithName(scopes.Single().Aliases.Single(), "M", "Microsoft", inGlobalNamespace:=True)) + Assert.Empty(scopes.Single.Aliases().Single().DeclaringSyntaxReferences) + + Assert.Single(scopes.Single().Imports) + Assert.True(IsNamespaceWithName(scopes.Single().Imports.Single().NamespaceOrType, "System")) + Assert.Null(scopes.Single().Imports.Single.DeclaringSyntaxReference) + + Assert.Single(scopes.Single().XmlNamespaces) + Assert.Equal("http://roslyn", scopes.Single().XmlNamespaces.Single().XmlNamespace) + Assert.Null(scopes.Single().XmlNamespaces.Single().DeclaringSyntaxReference) + + Assert.Empty(scopes.Single().ExternAliases) + End Sub + + + Public Sub TestGlobalImportsAndFileImports() + Dim text = " +imports System.IO +imports T = System.Threading +imports + +class C + 'pos +end class +" + Dim tree = Parse(text) + Dim comp = CreateCompilation(tree, options:=GetGlobalImportsOptions("System", "M = Microsoft", "")) + Dim model = comp.GetSemanticModel(tree) + dim scopes = model.GetImportScopes(FindPositionFromText(tree, "'pos")) + + Assert.Equal(2, scopes.Length) + + Assert.Single(scopes(0).Aliases) + Assert.True(IsAliasWithName(scopes(0).Aliases.Single(), "T", "Threading", inGlobalNamespace:=False)) + Assert.True(IsAliasImportsClauseWithName(scopes(0).Aliases().Single(), "T")) + + Assert.Single(scopes(0).Imports) + Assert.True(IsNamespaceWithName(scopes(0).Imports.Single().NamespaceOrType, "IO")) + Dim syntax = scopes(0).Imports.Single.DeclaringSyntaxReference.GetSyntax() + Assert.True(TypeOf syntax Is QualifiedNameSyntax) + Assert.True(TypeOf syntax.Parent Is SimpleImportsClauseSyntax) + Assert.Equal("System.IO", syntax.ToString()) + + Assert.Single(scopes(0).XmlNamespaces) + Assert.Equal("http://roslyn2", scopes(0).XmlNamespaces.Single().XmlNamespace) + Assert.True(TypeOf scopes(0).XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax() Is XmlNamespaceImportsClauseSyntax) + Assert.Equal("", scopes(0).XmlNamespaces.Single().DeclaringSyntaxReference.GetSyntax().ToString()) + + Assert.Single(scopes(1).Aliases) + Assert.True(IsAliasWithName(scopes(1).Aliases.Single(), "M", "Microsoft", inGlobalNamespace:=True)) + Assert.Empty(scopes(1).Aliases().Single().DeclaringSyntaxReferences) + + Assert.Single(scopes(1).Imports) + Assert.True(IsNamespaceWithName(scopes(1).Imports.Single().NamespaceOrType, "System")) + Assert.Null(scopes(1).Imports.Single.DeclaringSyntaxReference) + + Assert.Single(scopes(1).XmlNamespaces) + Assert.Equal("http://roslyn", scopes(1).XmlNamespaces.Single().XmlNamespace) + Assert.Null(scopes(1).XmlNamespaces.Single().DeclaringSyntaxReference) + + Assert.Empty(scopes(0).ExternAliases) + Assert.Empty(scopes(1).ExternAliases) + End Sub + +#End Region + + End Class +End Namespace diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/RelaxedShiftOperatorTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/RelaxedShiftOperatorTests.vb new file mode 100644 index 0000000000000..e6bb4425e4f74 --- /dev/null +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/RelaxedShiftOperatorTests.vb @@ -0,0 +1,70 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols +Imports Roslyn.Test.Utilities + +Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests + + Public Class RelaxedShiftOperatorTests + Inherits BasicTestBase + + + Public Sub Consumption_01() + + Dim csSource = +" +public class C1 +{ + public static C1 operator <<(C1 x, C1 y) + { + System.Console.WriteLine(""<<""); + return x; + } +} +" + Dim csCompilation = CreateCSharpCompilation(csSource, + parseOptions:=CSharp.CSharpParseOptions.Default.WithLanguageVersion(CSharp.LanguageVersion.Preview), + referencedAssemblies:=TargetFrameworkUtil.GetReferences(TargetFramework.Standard)).EmitToImageReference() + + Dim source1 = + + + + + Dim comp1 = CreateCompilation(source1, references:={csCompilation}) + comp1.AssertTheseDiagnostics( + + ) + + Dim source2 = + + + + + Dim comp2 = CreateCompilation(source2, references:={csCompilation}, options:=TestOptions.DebugExe) + CompileAndVerify(comp2, expectedOutput:="<<").VerifyDiagnostics() + End Sub + + End Class +End Namespace diff --git a/src/Compilers/VisualBasic/Test/Syntax/Syntax/GeneratedTests.vb b/src/Compilers/VisualBasic/Test/Syntax/Syntax/GeneratedTests.vb index e8ff76e2f4a47..cebf4911c7448 100644 --- a/src/Compilers/VisualBasic/Test/Syntax/Syntax/GeneratedTests.vb +++ b/src/Compilers/VisualBasic/Test/Syntax/Syntax/GeneratedTests.vb @@ -90,6 +90,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Overrides Function GetIsEnabledByDefault(code As Integer) As Boolean Return True End Function + +#If DEBUG Then + Friend Overrides Function ShouldAssertExpectedMessageArgumentsLength(errorCode As Integer) As Boolean + Return False + End Function +#End If End Class Friend Class RedIdentityRewriter diff --git a/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb b/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb index 585ebc41b336a..8c78b3e4172f2 100644 --- a/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb +++ b/src/Compilers/VisualBasic/Test/Syntax/TestSyntaxNodes.vb @@ -1061,7 +1061,7 @@ End Class End Function ' A mock message provider - Private Class MockMessageProvider + Private NotInheritable Class MockMessageProvider Inherits TestMessageProvider Public Overrides ReadOnly Property CodePrefix As String @@ -1109,6 +1109,12 @@ End Class Public Overrides Function GetIsEnabledByDefault(code As Integer) As Boolean Return True End Function + +#If DEBUG Then + Friend Overrides Function ShouldAssertExpectedMessageArgumentsLength(errorCode As Integer) As Boolean + Return False + End Function +#End If End Class ' A test rewriting visitor diff --git a/src/EditorFeatures/CSharp/AddImports/CSharpAddImportsPasteCommandHandler.cs b/src/EditorFeatures/CSharp/AddImports/CSharpAddImportsPasteCommandHandler.cs index 7404845619259..343b529897968 100644 --- a/src/EditorFeatures/CSharp/AddImports/CSharpAddImportsPasteCommandHandler.cs +++ b/src/EditorFeatures/CSharp/AddImports/CSharpAddImportsPasteCommandHandler.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Utilities; @@ -29,8 +30,8 @@ internal class CSharpAddImportsPasteCommandHandler : AbstractAddImportsPasteComm { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public CSharpAddImportsPasteCommandHandler(IThreadingContext threadingContext, IGlobalOptionService globalOptions) - : base(threadingContext, globalOptions) + public CSharpAddImportsPasteCommandHandler(IThreadingContext threadingContext, IGlobalOptionService globalOptions, IAsynchronousOperationListenerProvider listnerProvider) + : base(threadingContext, globalOptions, listnerProvider) { } diff --git a/src/EditorFeatures/CSharp/CSharpEditorResources.resx b/src/EditorFeatures/CSharp/CSharpEditorResources.resx index 2e8072dc4f4d2..c22d2abcf5e65 100644 --- a/src/EditorFeatures/CSharp/CSharpEditorResources.resx +++ b/src/EditorFeatures/CSharp/CSharpEditorResources.resx @@ -191,4 +191,7 @@ Grow raw string + + Fixing string literal after paste + \ No newline at end of file diff --git a/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs b/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs index c4a28fd2f1197..eee69d201f5b1 100644 --- a/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs +++ b/src/EditorFeatures/CSharp/CodeCleanup/CSharpCodeCleanupService.cs @@ -36,8 +36,8 @@ internal class CSharpCodeCleanupService : AbstractCodeCleanupService // dotnet_style_qualification_for_method // dotnet_style_qualification_for_property new DiagnosticSet(AnalyzersResources.Add_this_or_Me_qualification, - IDEDiagnosticIds.AddQualificationDiagnosticId, - IDEDiagnosticIds.RemoveQualificationDiagnosticId), + IDEDiagnosticIds.AddThisOrMeQualificationDiagnosticId, + IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId), // Language keywords vs BCL types preferences // dotnet_style_predefined_type_for_locals_parameters_members @@ -241,6 +241,10 @@ internal class CSharpCodeCleanupService : AbstractCodeCleanupService new DiagnosticSet(CSharpFeaturesResources.Apply_throw_expression_preferences, IDEDiagnosticIds.UseThrowExpressionDiagnosticId), + // csharp_style_prefer_utf8_string_literals + new DiagnosticSet(CSharpFeaturesResources.Apply_utf8_string_literal_preferences, + IDEDiagnosticIds.UseUTF8StringLiteralDiagnosticId), + // csharp_style_unused_value_assignment_preference // csharp_style_unused_value_expression_statement_preference new DiagnosticSet(FeaturesResources.Apply_unused_value_preferences, diff --git a/src/EditorFeatures/CSharp/CodeGeneration/CSharpCodeGenerationOptionsStorage.cs b/src/EditorFeatures/CSharp/CodeGeneration/CSharpCodeGenerationOptionsStorage.cs new file mode 100644 index 0000000000000..bcc22b55fd833 --- /dev/null +++ b/src/EditorFeatures/CSharp/CodeGeneration/CSharpCodeGenerationOptionsStorage.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration; + +internal static class CSharpCodeGenerationOptionsStorage +{ + [ExportLanguageService(typeof(ICodeGenerationOptionsStorage), LanguageNames.CSharp), Shared] + private sealed class Service : ICodeGenerationOptionsStorage + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public Service() + { + } + + public CodeGenerationOptions GetOptions(IGlobalOptionService globalOptions) + => GetCSharpCodeGenerationOptions(globalOptions); + } + + public static CSharpCodeGenerationOptions GetCSharpCodeGenerationOptions(this IGlobalOptionService globalOptions) + => new( + preferExpressionBodiedMethods: globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedMethods), + preferExpressionBodiedAccessors: globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors), + preferExpressionBodiedProperties: globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties), + preferExpressionBodiedIndexers: globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedIndexers), + preferExpressionBodiedConstructors: globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors), + preferExpressionBodiedOperators: globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedOperators), + preferExpressionBodiedLocalFunctions: globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedLocalFunctions), + preferExpressionBodiedLambdas: globalOptions.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedLambdas), + preferStaticLocalFunction: globalOptions.GetOption(CSharpCodeStyleOptions.PreferStaticLocalFunction), + namespaceDeclarations: globalOptions.GetOption(CSharpCodeStyleOptions.NamespaceDeclarations)); +} diff --git a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs index e9023d6a70ab9..71248fcde3133 100644 --- a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs +++ b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs @@ -252,7 +252,7 @@ private static bool CanHaveSemicolon(SyntaxNode currentNode) return true; } - if (currentNode is RecordDeclarationSyntax { OpenBraceToken: { IsMissing: true } }) + if (currentNode is RecordDeclarationSyntax { OpenBraceToken.IsMissing: true }) { return true; } diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs index 18f705e09e137..b597251b2495f 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs @@ -20,6 +20,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Rename; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; @@ -125,15 +126,13 @@ private void GenerateAndAddEventHandler(ITextView textView, ITextBuffer subjectB var document = textView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges(); Contract.ThrowIfNull(document, "Event Hookup could not find the document for the IBufferView."); - var cleanupOptions = document.GetCodeCleanupOptionsAsync(_globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); - var position = textView.GetCaretPoint(subjectBuffer).Value.Position; var solutionWithEventHandler = CreateSolutionWithEventHandler( document, eventHandlerMethodName, position, out var plusEqualTokenEndPosition, - cleanupOptions, + _globalOptions, cancellationToken); Contract.ThrowIfNull(solutionWithEventHandler, "Event Hookup could not create solution with event handler."); @@ -153,7 +152,7 @@ private Solution CreateSolutionWithEventHandler( string eventHandlerMethodName, int position, out int plusEqualTokenEndPosition, - CodeCleanupOptions cleanupOptions, + IGlobalOptionService globalOptions, CancellationToken cancellationToken) { _threadingContext.ThrowIfNotOnUIThread(); @@ -163,8 +162,8 @@ private Solution CreateSolutionWithEventHandler( var documentWithNameAndAnnotationsAdded = AddMethodNameAndAnnotationsToSolution(document, eventHandlerMethodName, position, plusEqualsTokenAnnotation, cancellationToken); var semanticDocument = SemanticDocument.CreateAsync(documentWithNameAndAnnotationsAdded, cancellationToken).WaitAndGetResult(cancellationToken); - var preferences = CSharpCodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).WaitAndGetResult(cancellationToken); - var updatedRoot = AddGeneratedHandlerMethodToSolution(semanticDocument, preferences, eventHandlerMethodName, plusEqualsTokenAnnotation, cancellationToken); + var options = (CSharpCodeGenerationOptions)document.GetCodeGenerationOptionsAsync(globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); + var updatedRoot = AddGeneratedHandlerMethodToSolution(semanticDocument, options, eventHandlerMethodName, plusEqualsTokenAnnotation, cancellationToken); if (updatedRoot == null) { @@ -172,6 +171,7 @@ private Solution CreateSolutionWithEventHandler( return null; } + var cleanupOptions = documentWithNameAndAnnotationsAdded.GetCodeCleanupOptionsAsync(globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); var simplifiedDocument = Simplifier.ReduceAsync(documentWithNameAndAnnotationsAdded.WithSyntaxRoot(updatedRoot), Simplifier.Annotation, cleanupOptions.SimplifierOptions, cancellationToken).WaitAndGetResult(cancellationToken); var formattedDocument = Formatter.FormatAsync(simplifiedDocument, Formatter.Annotation, cleanupOptions.FormattingOptions, cancellationToken).WaitAndGetResult(cancellationToken); @@ -224,7 +224,7 @@ private static Document AddMethodNameAndAnnotationsToSolution( private static SyntaxNode AddGeneratedHandlerMethodToSolution( SemanticDocument document, - CSharpCodeGenerationPreferences preferences, + CSharpCodeGenerationOptions options, string eventHandlerMethodName, SyntaxAnnotation plusEqualsTokenAnnotation, CancellationToken cancellationToken) @@ -244,10 +244,7 @@ private static SyntaxNode AddGeneratedHandlerMethodToSolution( var container = (SyntaxNode)typeDecl ?? eventHookupExpression.GetAncestor(); var codeGenerator = document.Document.GetRequiredLanguageService(); - - var codeGenOptions = preferences.GetOptions( - new CodeGenerationContext(afterThisLocation: eventHookupExpression.GetLocation())); - + var codeGenOptions = options.GetInfo(new CodeGenerationContext(afterThisLocation: eventHookupExpression.GetLocation()), document.Project); var newContainer = codeGenerator.AddMethod(container, generatedMethodSymbol, codeGenOptions, cancellationToken); return root.ReplaceNode(container, newContainer); diff --git a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs index 13e11cf3c2aff..023e5695f872d 100644 --- a/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs +++ b/src/EditorFeatures/CSharp/EventHookup/EventHookupSessionManager_EventHookupSession.cs @@ -41,7 +41,7 @@ internal class EventHookupSession { public readonly Task GetEventNameTask; private readonly IThreadingContext _threadingContext; - private readonly CancellationTokenSource _cancellationTokenSource; + private readonly CancellationTokenSource _cancellationTokenSource = new(); private readonly ITrackingPoint _trackingPoint; private readonly ITrackingSpan _trackingSpan; private readonly ITextView _textView; @@ -103,7 +103,6 @@ public EventHookupSession( Mutex testSessionHookupMutex) { _threadingContext = eventHookupSessionManager.ThreadingContext; - _cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = _cancellationTokenSource.Token; _textView = textView; _subjectBuffer = subjectBuffer; @@ -257,18 +256,17 @@ private string GetNameObjectPart(IEventSymbol eventSymbol, SyntaxToken plusEqual // This is expected -- it means the last thing is(probably) the event name. We // already have that in eventSymbol. What we need is the LHS of that dot. - var lhs = memberAccessExpression.Expression; + var lhs = memberAccessExpression.Expression.GetRightmostName(); - if (lhs is MemberAccessExpressionSyntax lhsMemberAccessExpression) + if (lhs is GenericNameSyntax lhsGenericNameSyntax) { - // Okay, cool. The name we're after is in the RHS of this dot. - return lhsMemberAccessExpression.Name.ToString(); + // For generic we must exclude type variables + return lhsGenericNameSyntax.Identifier.Text; } - if (lhs is NameSyntax lhsNameSyntax) + if (lhs != null) { - // Even easier -- the LHS of the dot is the name itself - return lhsNameSyntax.ToString(); + return lhs.ToString(); } } diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/AbstractPasteProcessor.cs b/src/EditorFeatures/CSharp/StringCopyPaste/AbstractPasteProcessor.cs new file mode 100644 index 0000000000000..1efd0af4edfbd --- /dev/null +++ b/src/EditorFeatures/CSharp/StringCopyPaste/AbstractPasteProcessor.cs @@ -0,0 +1,154 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.VisualStudio.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.StringCopyPaste +{ + using static StringCopyPasteHelpers; + + /// + /// Holds core before/after state related to the paste to allow subclasses to decide what text changes to make + /// without having to pass around tons of common values. + /// + internal abstract class AbstractPasteProcessor + { + /// + /// The buffer's snapshot prior to the paste application. + /// + protected readonly ITextSnapshot SnapshotBeforePaste; + + /// + /// The buffer's snapshot right after the paste application. Guaranteed to be exactly one version ahead of . + /// + protected readonly ITextSnapshot SnapshotAfterPaste; + + /// + /// Roslyn SourceText corresponding to . + /// + protected readonly SourceText TextBeforePaste; + + /// + /// Roslyn SourceText corresponding to . + /// + protected readonly SourceText TextAfterPaste; + + /// + /// Roslyn document corresponding to . + /// + protected readonly Document DocumentBeforePaste; + + /// + /// Roslyn document corresponding to . + /// + protected readonly Document DocumentAfterPaste; + + /// + /// The or that the + /// changes were pasted into. All changes in the paste will be in the same 'content text span' in that string + /// expression. + /// + protected readonly ExpressionSyntax StringExpressionBeforePaste; + + /// + /// User's desired new-line sequence if we need to add newlines to our text changes. + /// + protected readonly string NewLine; + + /// + /// Spans of text-content within . These represent the spans where + /// text can go within a string literal/interpolation. Note that these spans may be empty. For example, this + /// happens for cases like the empty string "", or between interpolation holes like $"x{a}{b}y". + /// These spans can be examined to determine if pasted content is only impacting the content portion of a + /// string, and not the delimiters or interpolation-holes. + /// + protected readonly ImmutableArray TextContentsSpansBeforePaste; + + /// + /// All the spans of mapped forward () to in an inclusive manner. This + /// can be used to determine what content exists post paste, and if that content requires the literal to revised + /// to be legal. For example, if the text content in a raw-literal contains a longer sequence of quotes after + /// pasting, then the delimiters of the raw literal may need to be increased accordingly. + /// + protected readonly ImmutableArray TextContentsSpansAfterPaste; + + protected readonly IndentationOptions IndentationOptions; + + /// + /// Whether or not the string expression remained successfully parseable after the paste. . If it can still be successfully parsed subclasses + /// can adjust their view on which pieces of content need to be escaped or not. + /// + protected readonly bool PasteWasSuccessful; + + /// + /// Number of quotes in the delimiter of the string being pasted into. Given that the string should have no + /// errors in it, this quote count should be the same for the start and end delimiter. + /// + protected readonly int DelimiterQuoteCount; + + /// + /// Number of dollar signs ($) in the starting delimiter of the string being pasted into. + /// + protected readonly int DelimiterDollarCount; + + /// + /// The set of 's that produced from . + /// + protected INormalizedTextChangeCollection Changes => SnapshotBeforePaste.Version.Changes; + + protected AbstractPasteProcessor( + ITextSnapshot snapshotBeforePaste, + ITextSnapshot snapshotAfterPaste, + Document documentBeforePaste, + Document documentAfterPaste, + ExpressionSyntax stringExpressionBeforePaste, + string newLine, + IndentationOptions indentationOptions, + bool pasteWasSuccessful) + { + SnapshotBeforePaste = snapshotBeforePaste; + SnapshotAfterPaste = snapshotAfterPaste; + + TextBeforePaste = SnapshotBeforePaste.AsText(); + TextAfterPaste = SnapshotAfterPaste.AsText(); + + DocumentBeforePaste = documentBeforePaste; + DocumentAfterPaste = documentAfterPaste; + + StringExpressionBeforePaste = stringExpressionBeforePaste; + NewLine = newLine; + + IndentationOptions = indentationOptions; + PasteWasSuccessful = pasteWasSuccessful; + + TextContentsSpansBeforePaste = GetTextContentSpans(TextBeforePaste, stringExpressionBeforePaste, out DelimiterQuoteCount, out DelimiterDollarCount); + TextContentsSpansAfterPaste = TextContentsSpansBeforePaste.SelectAsArray(MapSpanForward); + + Contract.ThrowIfTrue(TextContentsSpansBeforePaste.IsEmpty); + } + + /// + /// Takes a span in and maps it appropriately (in an manner) to . + /// + protected TextSpan MapSpanForward(TextSpan span) + { + var trackingSpan = SnapshotBeforePaste.CreateTrackingSpan(span.ToSpan(), SpanTrackingMode.EdgeInclusive); + return trackingSpan.GetSpan(SnapshotAfterPaste).Span.ToTextSpan(); + } + } +} diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler.cs b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler.cs new file mode 100644 index 0000000000000..9c39957d5038c --- /dev/null +++ b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteCommandHandler.cs @@ -0,0 +1,330 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Options; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.VisualStudio.Commanding; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Microsoft.VisualStudio.Text.Editor.OptionsExtensionMethods; +using Microsoft.VisualStudio.Text.Operations; +using Roslyn.Utilities; +using VSUtilities = Microsoft.VisualStudio.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.StringCopyPaste +{ + using static StringCopyPasteHelpers; + + /// + /// Command handler that both tracks 'copy' commands within VS to see what text the user copied (and from where), + /// but also then handles pasting that text back in a sensible fashion (e.g. escaping/unescaping/wrapping/indenting) + /// inside a string-literal. Can also handle pasting code from unknown sources as well, though heuristics must be + /// applied in that case to make a best effort guess as to what the original text meant and how to preserve that + /// in the final context. + /// + /// + /// Because we are revising what the normal editor does, we follow the standard behavior of first allowing the + /// editor to process paste commands, and then adding our own changes as an edit after that. That way if the user + /// doesn't want the change we made, they can always undo to get the prior paste behavior. + /// + [Export(typeof(ICommandHandler))] + [VSUtilities.ContentType(ContentTypeNames.CSharpContentType)] + [VSUtilities.Name(nameof(StringCopyPasteCommandHandler))] + internal partial class StringCopyPasteCommandHandler : IChainedCommandHandler, IChainedCommandHandler + { + private readonly ITextUndoHistoryRegistry _undoHistoryRegistry; + private readonly IEditorOperationsFactoryService _editorOperationsFactoryService; + private readonly IGlobalOptionService _globalOptions; + + private NormalizedSnapshotSpanCollection? _lastSelectedSpans; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public StringCopyPasteCommandHandler( + ITextUndoHistoryRegistry undoHistoryRegistry, + IEditorOperationsFactoryService editorOperationsFactoryService, + IGlobalOptionService globalOptions) + { + _undoHistoryRegistry = undoHistoryRegistry; + _editorOperationsFactoryService = editorOperationsFactoryService; + _globalOptions = globalOptions; + } + + public string DisplayName => nameof(StringCopyPasteCommandHandler); + + #region Copy + + public CommandState GetCommandState(CopyCommandArgs args, Func nextCommandHandler) + => nextCommandHandler(); + + public void ExecuteCommand(CopyCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext) + { + // Ensure that the copy always goes through all other handlers. + nextCommandHandler(); + + var textView = args.TextView; + var subjectBuffer = args.SubjectBuffer; + + _lastSelectedSpans = textView.Selection.GetSnapshotSpansOnBuffer(subjectBuffer); + } + + public CommandState GetCommandState(PasteCommandArgs args, Func nextCommandHandler) + => nextCommandHandler(); + + #endregion + + public void ExecuteCommand(PasteCommandArgs args, Action nextCommandHandler, CommandExecutionContext executionContext) + { + var textView = args.TextView; + var subjectBuffer = args.SubjectBuffer; + + var selectionsBeforePaste = textView.Selection.GetSnapshotSpansOnBuffer(subjectBuffer); + var snapshotBeforePaste = subjectBuffer.CurrentSnapshot; + + // Always let the real paste go through. That way we always have a version of the document that doesn't + // include our changes that we can undo back to. + nextCommandHandler(); + + // If the user has the option off, then don't bother doing anything once we've sent the paste through. + if (!_globalOptions.GetOption(FeatureOnOffOptions.AutomaticallyFixStringContentsOnPaste, LanguageNames.CSharp)) + return; + + // if we're not even sure where the user caret/selection is on this buffer, we can't proceed. + if (selectionsBeforePaste.Count == 0) + return; + + var snapshotAfterPaste = subjectBuffer.CurrentSnapshot; + + // If there were multiple changes that already happened, then don't make any changes. Some other component + // already did something advanced. + if (snapshotAfterPaste.Version != snapshotBeforePaste.Version.Next) + return; + + // Have to even be in a C# doc to be able to have special space processing here. + + var documentBeforePaste = snapshotBeforePaste.GetOpenDocumentInCurrentContextWithChanges(); + var documentAfterPaste = snapshotAfterPaste.GetOpenDocumentInCurrentContextWithChanges(); + if (documentBeforePaste == null || documentAfterPaste == null) + return; + + var cancellationToken = executionContext.OperationContext.UserCancellationToken; + + var rootBeforePaste = documentBeforePaste.GetRequiredSyntaxRootSynchronously(cancellationToken); + + // When pasting, only do anything special if the user selections were entirely inside a single string + // literal token. Otherwise, we have a multi-selection across token kinds which will be extremely + // complex to try to reconcile. + var stringExpressionBeforePaste = TryGetCompatibleContainingStringExpression( + rootBeforePaste, snapshotBeforePaste.AsText(), selectionsBeforePaste); + if (stringExpressionBeforePaste == null) + return; + + // TODO: add support for pasting content that came from within the editor. We can exactly know what that + // content meant, and how to insert it into our string expression. + + var pasteWasSuccessful = PasteWasSuccessful( + snapshotBeforePaste, snapshotAfterPaste, documentAfterPaste, stringExpressionBeforePaste, cancellationToken); + + var indentationOptions = documentBeforePaste.GetIndentationOptionsAsync(_globalOptions, cancellationToken).WaitAndGetResult(cancellationToken); + var processor = new UnknownSourcePasteProcessor( + snapshotBeforePaste, + snapshotAfterPaste, + documentBeforePaste, + documentAfterPaste, + stringExpressionBeforePaste, + textView.Options.GetNewLineCharacter(), + indentationOptions, + pasteWasSuccessful); + + var textChanges = processor.GetEdits(cancellationToken); + + // If we didn't get any viable changes back, don't do anything. + if (textChanges.IsDefaultOrEmpty) + return; + + var newTextAfterChanges = snapshotBeforePaste.AsText().WithChanges(textChanges); + + // If we end up making the same changes as what the paste did, then no need to proceed. + if (ContentsAreSame(snapshotBeforePaste, snapshotAfterPaste, stringExpressionBeforePaste, newTextAfterChanges)) + return; + + // Create two edits to make the change. The first restores the buffer to the original snapshot (effectively + // undoing the first set of changes). Then the second actually applies the change. + // + // Do this as direct edits, passing 'EditOptions.None' for the options, as we want to control the edits + // precisely and don't want any strange interpretation of where the caret should end up. Other options + // (like DefaultMinimalChange) will attempt to diff/merge edits oddly sometimes which can lead the caret + // ending up before/after some merged change, which will no longer match the behavior of precise pastes. + // + // Wrap this all as a transaction so that these two edits appear to be one single change. This also allows + // the user to do a single 'undo' that gets them back to the original paste made at the start of this + // method. + + using var transaction = new CaretPreservingEditTransaction( + CSharpEditorResources.Fixing_string_literal_after_paste, + textView, _undoHistoryRegistry, _editorOperationsFactoryService); + + { + var edit = subjectBuffer.CreateEdit(EditOptions.None, reiteratedVersionNumber: null, editTag: null); + foreach (var change in snapshotBeforePaste.Version.Changes) + edit.Replace(change.NewSpan, change.OldText); + edit.Apply(); + } + + { + var edit = subjectBuffer.CreateEdit(EditOptions.None, reiteratedVersionNumber: null, editTag: null); + foreach (var selection in selectionsBeforePaste) + edit.Replace(selection.Span, ""); + + foreach (var change in textChanges) + edit.Replace(change.Span.ToSpan(), change.NewText); + edit.Apply(); + } + + transaction.Complete(); + } + + /// + /// Returns true if the paste resulted in legal code for the string literal. The string literal is + /// considered legal if it has the same span as the original string (adjusted as per the edit) and that + /// there are no errors in it. For this purposes of this check, errors in interpolation holes are not + /// considered. We only care about the textual content of the string. + /// + internal static bool PasteWasSuccessful( + ITextSnapshot snapshotBeforePaste, + ITextSnapshot snapshotAfterPaste, + Document documentAfterPaste, + ExpressionSyntax stringExpressionBeforePaste, + CancellationToken cancellationToken) + { + var rootAfterPaste = documentAfterPaste.GetRequiredSyntaxRootSynchronously(cancellationToken); + var stringExpressionAfterPaste = FindContainingSupportedStringExpression(rootAfterPaste, stringExpressionBeforePaste.SpanStart); + if (stringExpressionAfterPaste == null) + return false; + + if (ContainsError(stringExpressionAfterPaste)) + return false; + + var spanAfterPaste = MapSpan(stringExpressionBeforePaste.Span, snapshotBeforePaste, snapshotAfterPaste); + return spanAfterPaste == stringExpressionAfterPaste.Span; + } + + /// + /// Given the snapshots before/after pasting, and the source-text our manual fixup edits produced, see if our + /// manual application actually produced the same results as the paste. If so, we don't need to actually do + /// anything. To optimize this check, we pass in the original string expression as that's all we have to check + /// (adjusting for where it now ends up) in both the 'after' documents. + /// + private static bool ContentsAreSame( + ITextSnapshot snapshotBeforePaste, + ITextSnapshot snapshotAfterPaste, + ExpressionSyntax stringExpressionBeforePaste, + SourceText newTextAfterChanges) + { + // We ended up with documents of different length after we escaped/manipulated the pasted text. So the + // contents are definitely not the same. + if (newTextAfterChanges.Length != snapshotAfterPaste.Length) + return false; + + var spanAfterPaste = MapSpan(stringExpressionBeforePaste.Span, snapshotBeforePaste, snapshotAfterPaste); + + var originalStringContentsAfterPaste = snapshotAfterPaste.AsText().GetSubText(spanAfterPaste); + var newStringContentsAfterEdit = newTextAfterChanges.GetSubText(spanAfterPaste); + + return originalStringContentsAfterPaste.ContentEquals(newStringContentsAfterEdit); + } + + /// + /// Returns the or if the + /// selections were all contained within a single literal in a compatible fashion. This means all the + /// selections have to start/end in a content-span portion of the literal. For example, if we paste into an + /// interpolated string and have half of the selection outside an interpolation and half inside, we don't do + /// anything special as trying to correct in this scenario is too difficult. + /// + private static ExpressionSyntax? TryGetCompatibleContainingStringExpression( + SyntaxNode root, + SourceText text, + NormalizedSnapshotSpanCollection selectionsBeforePaste) + { + // First, try to see if all the selections are at least contained within a single string literal expression. + var stringExpression = FindCommonContainingStringExpression(root, selectionsBeforePaste); + if (stringExpression == null) + return null; + + // Now, given that string expression, find the inside 'text' spans of the expression. These are the parts + // of the literal between the quotes. It does not include the interpolation holes in an interpolated + // string. These spans may be empty (for an empty string, or empty text gap between interpolations). + var contentSpans = GetTextContentSpans(text, stringExpression, out _, out _); + + foreach (var snapshotSpan in selectionsBeforePaste) + { + var startIndex = contentSpans.BinarySearch(snapshotSpan.Span.Start, FindIndex); + var endIndex = contentSpans.BinarySearch(snapshotSpan.Span.End, FindIndex); + + if (startIndex < 0 || endIndex < 0) + return null; + } + + return stringExpression; + + static int FindIndex(TextSpan span, int position) + { + if (span.IntersectsWith(position)) + return 0; + + if (span.End < position) + return -1; + + return 1; + } + } + +#if false + private bool PastedTextEqualsLastCopiedText(ITextBuffer subjectBuffer) + { + // If we have no history of any copied text, then there's nothing in the past we can compare to. + if (_lastSelectedSpans == null) + return false; + + var copiedSpans = _lastSelectedSpans; + var pastedChanges = subjectBuffer.CurrentSnapshot.Version.Changes; + + // If we don't have any actual changes to compare, we can't consider these the same. + if (copiedSpans.Count == 0 || pastedChanges.Count == 0) + return false; + + // Both the copied and pasted data is normalized. So we should be able to compare counts to see + // if they look the same. + if (copiedSpans.Count != pastedChanges.Count) + return false; + + // Validate each copied span from the source matches what was pasted into the destination. + for (int i = 0, n = copiedSpans.Count; i < n; i++) + { + var copiedSpan = copiedSpans[i]; + var pastedChange = pastedChanges[i]; + + if (copiedSpan.Length != pastedChange.NewLength) + return false; + + if (copiedSpan.GetText() != pastedChange.NewText) + return false; + } + + return true; + } +#endif + } +} diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteHelpers.cs b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteHelpers.cs new file mode 100644 index 0000000000000..61bffe8142939 --- /dev/null +++ b/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteHelpers.cs @@ -0,0 +1,626 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.VisualStudio.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.StringCopyPaste +{ + internal static class StringCopyPasteHelpers + { + public static bool HasNewLine(TextLine line) + => line.Span.End != line.SpanIncludingLineBreak.End; + + /// + /// True if the string literal contains an error diagnostic that indicates a parsing problem with it. For + /// interpolated strings, this only includes the text sections, and not any interpolation holes in the literal. + /// + public static bool ContainsError(ExpressionSyntax stringExpression) + { + if (stringExpression is LiteralExpressionSyntax) + return NodeOrTokenContainsError(stringExpression); + + if (stringExpression is InterpolatedStringExpressionSyntax interpolatedString) + { + using var _ = PooledHashSet.GetInstance(out var errors); + foreach (var diagnostic in interpolatedString.GetDiagnostics()) + { + if (diagnostic.Severity == DiagnosticSeverity.Error) + errors.Add(diagnostic); + } + + // we don't care about errors in holes. Only errors in the content portions of the string. + for (int i = 0, n = interpolatedString.Contents.Count; i < n && errors.Count > 0; i++) + { + if (interpolatedString.Contents[i] is InterpolatedStringTextSyntax text) + { + foreach (var diagnostic in text.GetDiagnostics()) + errors.Remove(diagnostic); + } + } + + return errors.Count > 0; + } + + throw ExceptionUtilities.UnexpectedValue(stringExpression); + } + + public static bool NodeOrTokenContainsError(SyntaxNodeOrToken nodeOrToken) + { + foreach (var diagnostic in nodeOrToken.GetDiagnostics()) + { + if (diagnostic.Severity == DiagnosticSeverity.Error) + return true; + } + + return false; + } + + public static bool AllWhitespace(INormalizedTextChangeCollection changes) + { + foreach (var change in changes) + { + if (!AllWhitespace(change.NewText)) + return false; + } + + return true; + } + + private static bool AllWhitespace(string text) + { + foreach (var ch in text) + { + if (!SyntaxFacts.IsWhitespace(ch)) + return false; + } + + return true; + } + + /// + /// Given a TextLine, returns the index (in the SourceText) of the first character of it that is not a + /// Whitespace character. The LineBreak parts of the line are not considered here. If the line is empty/blank + /// (again, not counting LineBreak characters) then -1 is returned. + /// + public static int GetFirstNonWhitespaceIndex(SourceText text, TextLine line) + { + for (int i = line.Start, n = line.End; i < n; i++) + { + if (!SyntaxFacts.IsWhitespace(text[i])) + return i; + } + + return -1; + } + + public static bool ContainsControlCharacter(INormalizedTextChangeCollection changes) + { + foreach (var change in changes) + { + if (ContainsControlCharacter(change.NewText)) + return true; + } + + return false; + } + + public static bool ContainsControlCharacter(string newText) + { + foreach (var c in newText) + { + if (char.IsControl(c)) + return true; + } + + return false; + } + + /// + /// Removes all characters matching from the start of . + /// + public static (string whitespace, string contents) ExtractWhitespace(string value) + { + var start = 0; + while (start < value.Length && SyntaxFacts.IsWhitespace(value[start])) + start++; + + return (value[..start], value[start..]); + } + + public static bool IsVerbatimStringExpression(ExpressionSyntax stringExpression) + => stringExpression is LiteralExpressionSyntax literalExpression && literalExpression.Token.IsVerbatimStringLiteral() || + stringExpression is InterpolatedStringExpressionSyntax { StringStartToken.RawKind: (int)SyntaxKind.InterpolatedVerbatimStringStartToken }; + + public static bool IsAnyRawStringExpression(ExpressionSyntax expression) + => expression is LiteralExpressionSyntax literal + ? IsRawStringLiteral(literal) + : IsRawStringLiteral((InterpolatedStringExpressionSyntax)expression); + + public static bool IsRawStringLiteral(InterpolatedStringExpressionSyntax interpolatedString) + => interpolatedString.StringStartToken.Kind() is SyntaxKind.InterpolatedSingleLineRawStringStartToken or SyntaxKind.InterpolatedMultiLineRawStringStartToken; + + public static bool IsRawStringLiteral(LiteralExpressionSyntax literal) + => literal.Token.Kind() is SyntaxKind.SingleLineRawStringLiteralToken or SyntaxKind.MultiLineRawStringLiteralToken; + + /// + /// Given a string literal or interpolated string, returns the subspans of those expressions that are actual + /// text content spans. For a string literal, this is the span between the quotes. For an interpolated string + /// this is the text regions between the holes. Note that for interpolated strings the content spans may be + /// empty (for example, between two adjacent holes). We still want to know about those empty spans so that if a + /// paste happens into that empty region that we still escape properly. + /// + public static ImmutableArray GetTextContentSpans( + SourceText text, ExpressionSyntax stringExpression, + out int delimiterQuoteCount, out int delimiterDollarCount) + { + if (stringExpression is LiteralExpressionSyntax literal) + { + delimiterDollarCount = 0; + return ImmutableArray.Create(GetStringLiteralTextContentSpan(text, literal, out delimiterQuoteCount)); + } + else if (stringExpression is InterpolatedStringExpressionSyntax interpolatedString) + { + return GetInterpolatedStringTextContentSpans(text, interpolatedString, out delimiterQuoteCount, out delimiterDollarCount); + } + else + { + throw ExceptionUtilities.UnexpectedValue(stringExpression); + } + } + + private static int SkipU8Suffix(SourceText text, int start, int end) + { + if (end > start && text[end - 1] == '8') + end--; + if (end > start && text[end - 1] is 'u' or 'U') + end--; + return end; + } + + private static ImmutableArray GetInterpolatedStringTextContentSpans( + SourceText text, InterpolatedStringExpressionSyntax interpolatedString, + out int delimiterQuoteCount, out int delimiterDollarCount) + { + // Interpolated string. Normal, verbatim, or raw. + // + // Skip past the leading and trailing delimiters. + var start = interpolatedString.SpanStart; + while (start < text.Length && text[start] is '@' or '$') + start++; + delimiterDollarCount = start - interpolatedString.SpanStart; + + var position = start; + while (start < interpolatedString.StringStartToken.Span.End && text[start] == '"') + start++; + delimiterQuoteCount = start - position; + + var end = interpolatedString.Span.End; + + end = SkipU8Suffix(text, start, end); + while (end > interpolatedString.StringEndToken.Span.Start && text[end - 1] == '"') + end--; + + using var result = TemporaryArray.Empty; + var currentPosition = start; + for (var i = 0; i < interpolatedString.Contents.Count; i++) + { + var content = interpolatedString.Contents[i]; + if (content is InterpolationSyntax) + { + result.Add(TextSpan.FromBounds(currentPosition, content.SpanStart)); + currentPosition = content.Span.End; + } + } + + // Then, once through the body, add a final span from the end of the last interpolation to the end delimiter. + result.Add(TextSpan.FromBounds(currentPosition, end)); + return result.ToImmutableAndClear(); + } + + private static TextSpan GetStringLiteralTextContentSpan(SourceText text, LiteralExpressionSyntax literal, out int delimiterQuoteCount) + { + // simple string literal (normal, verbatim or raw). + // + // Skip past the leading and trailing delimiters and add the span in between. + // + // The two cases look similar but are subtly different. Ignoring the fact that raw strings don't start with + // '@', there's also the issue that normal strings just have a single starting/ending quote, where as + // raw-strings can have an unbounded number of them. + if (IsRawStringLiteral(literal)) + { + var start = literal.SpanStart; + while (start < text.Length && text[start] == '"') + start++; + delimiterQuoteCount = start - literal.SpanStart; + + var end = literal.Span.End; + + end = SkipU8Suffix(text, start, end); + while (end > start && text[end - 1] == '"') + end--; + + return TextSpan.FromBounds(start, end); + } + else + { + var start = literal.SpanStart; + if (start < text.Length && text[start] == '@') + start++; + + var position = start; + if (start < text.Length && text[start] == '"') + start++; + delimiterQuoteCount = start - position; + + var end = literal.Span.End; + + end = SkipU8Suffix(text, start, end); + if (end > start && text[end - 1] == '"') + end--; + + return TextSpan.FromBounds(start, end); + } + } + + /// + /// Given a section of a document, finds the longest sequence of quote (") characters in it. Used to + /// determine if a raw string literal needs to grow its delimiters to ensure that the quote sequence will no + /// longer be a problem. + /// + public static int GetLongestQuoteSequence(SourceText text, TextSpan span) + => GetLongestCharacterSequence(text, span, '"'); + + public static int GetLongestOpenBraceSequence(SourceText text, TextSpan span) + => GetLongestCharacterSequence(text, span, '{'); + + public static int GetLongestCloseBraceSequence(SourceText text, TextSpan span) + => GetLongestCharacterSequence(text, span, '}'); + + /// + /// Given a section of a document, finds the longest sequence of of a given in it. + /// Used to determine if a raw string literal needs to grow its delimiters to ensure that the sequence + /// will no longer be a problem. + /// + private static int GetLongestCharacterSequence(SourceText text, TextSpan span, char character) + { + var longestCount = 0; + for (int currentIndex = span.Start, contentEnd = span.End; currentIndex < contentEnd;) + { + if (text[currentIndex] == character) + { + var endQuoteIndex = currentIndex; + while (endQuoteIndex < contentEnd && text[endQuoteIndex] == character) + endQuoteIndex++; + + longestCount = Math.Max(longestCount, endQuoteIndex - currentIndex); + currentIndex = endQuoteIndex; + } + else + { + currentIndex++; + } + } + + return longestCount; + } + + /// + /// Given a set of selections, finds the innermost string-literal/interpolation that they are all contained in. + /// If no such literal/interpolation exists, this returns null. + /// + public static ExpressionSyntax? FindCommonContainingStringExpression( + SyntaxNode root, NormalizedSnapshotSpanCollection selectionsBeforePaste) + { + ExpressionSyntax? expression = null; + foreach (var snapshotSpan in selectionsBeforePaste) + { + var container = FindContainingSupportedStringExpression(root, snapshotSpan.Start.Position); + if (container == null) + return null; + + expression ??= container; + if (expression != container) + return null; + } + + return expression; + } + + public static ExpressionSyntax? FindContainingSupportedStringExpression(SyntaxNode root, int position) + { + var node = root.FindToken(position).Parent; + for (var current = node; current != null; current = current.Parent) + { + if (current is LiteralExpressionSyntax literalExpression) + return IsSupportedStringExpression(literalExpression) ? literalExpression : null; + + if (current is InterpolatedStringExpressionSyntax interpolatedString) + return IsSupportedStringExpression(interpolatedString) ? interpolatedString : null; + } + + return null; + } + + public static bool IsSupportedStringExpression(ExpressionSyntax expression) + { + // When new string forms are added, support for them can be introduced here. However, by checking the exact + // types of strings supported, downstream code can know exactly what forms they should be looking for and + // that nothing else may flow down to them. + + if (expression is LiteralExpressionSyntax + { + RawKind: (int)SyntaxKind.StringLiteralExpression, + Token.RawKind: (int)SyntaxKind.StringLiteralToken or + (int)SyntaxKind.SingleLineRawStringLiteralToken or + (int)SyntaxKind.MultiLineRawStringLiteralToken, + }) + { + return true; + } + + if (expression is InterpolatedStringExpressionSyntax + { + StringStartToken.RawKind: (int)SyntaxKind.InterpolatedStringStartToken or + (int)SyntaxKind.InterpolatedVerbatimStringStartToken or + (int)SyntaxKind.InterpolatedSingleLineRawStringStartToken or + (int)SyntaxKind.InterpolatedMultiLineRawStringStartToken, + }) + { + return true; + } + + return false; + } + + public static string EscapeForNonRawStringLiteral(bool isVerbatim, bool isInterpolated, string value) + { + if (isVerbatim) + return EscapeForNonRawVerbatimStringLiteral(isInterpolated, value); + + // Standard strings have a much larger set of cases to consider. + using var _ = PooledStringBuilder.GetInstance(out var builder); + + // taken from object-display + for (var i = 0; i < value.Length; i++) + { + var ch = value[i]; + var nextCh = i == value.Length - 1 ? 0 : value[i + 1]; + + if (CharUnicodeInfo.GetUnicodeCategory(ch) == UnicodeCategory.Surrogate) + { + var category = CharUnicodeInfo.GetUnicodeCategory(value, i); + if (category == UnicodeCategory.Surrogate) + { + // an unpaired surrogate + builder.Append("\\u" + ((int)ch).ToString("x4")); + } + else if (NeedsEscaping(category)) + { + // a surrogate pair that needs to be escaped + var unicode = char.ConvertToUtf32(value, i); + builder.Append("\\U" + unicode.ToString("x8")); + i++; // skip the already-encoded second surrogate of the pair + } + else + { + // copy a printable surrogate pair directly + builder.Append(ch); + builder.Append(value[++i]); + } + } + else if (TryReplaceChar(ch, out var replaceWith)) + { + builder.Append(replaceWith); + } + else + { + builder.Append(ch); + + // if we see a special character then skip the following one if the following one already escapes it. + // Otherwise, if it's not already escaped, then escape it. + if (isInterpolated && ch is '{' or '}') + { + if (nextCh == ch) + i++; + else + builder.Append(ch); + } + } + } + + return builder.ToString(); + + static bool TryReplaceChar(char c, [NotNullWhen(true)] out string? replaceWith) + { + replaceWith = null; + switch (c) + { + case '\\': + replaceWith = "\\\\"; + break; + case '\0': + replaceWith = "\\0"; + break; + case '\a': + replaceWith = "\\a"; + break; + case '\b': + replaceWith = "\\b"; + break; + case '\f': + replaceWith = "\\f"; + break; + case '\n': + replaceWith = "\\n"; + break; + case '\r': + replaceWith = "\\r"; + break; + case '\t': + replaceWith = "\\t"; + break; + case '\v': + replaceWith = "\\v"; + break; + case '"': + replaceWith = "\\\""; + break; + } + + if (replaceWith != null) + return true; + + if (NeedsEscaping(CharUnicodeInfo.GetUnicodeCategory(c))) + { + replaceWith = "\\u" + ((int)c).ToString("x4"); + return true; + } + + return false; + } + + static bool NeedsEscaping(UnicodeCategory category) + { + switch (category) + { + case UnicodeCategory.Control: + case UnicodeCategory.OtherNotAssigned: + case UnicodeCategory.ParagraphSeparator: + case UnicodeCategory.LineSeparator: + case UnicodeCategory.Surrogate: + return true; + default: + return false; + } + } + } + + private static string EscapeForNonRawVerbatimStringLiteral(bool isInterpolated, string value) + { + using var _ = PooledStringBuilder.GetInstance(out var builder); + + for (var i = 0; i < value.Length; i++) + { + var ch = value[i]; + var nextCh = i == value.Length - 1 ? 0 : value[i + 1]; + + builder.Append(ch); + + // if we see a special character then skip the following one if the following one already escapes it. + // Otherwise, if it's not already escaped, then escape it. + if (ch == '"') + { + if (nextCh == ch) + i++; + else + builder.Append(ch); + } + else if (isInterpolated && ch is '{' or '}') + { + if (nextCh == ch) + i++; + else + builder.Append(ch); + } + } + + return builder.ToString(); + } + + /// + /// Given a set of source text lines, determines what common whitespace prefix each line has. Note that this + /// does *not* include the first line as it's super common for someone to copy a set of lines while only + /// starting the selection at the start of the content on the first line. This also does not include empty + /// lines as they're also very common, but are clearly not a way of indicating indentation indent for the normal + /// lines. + /// + public static string? GetCommonIndentationPrefix(INormalizedTextChangeCollection textChanges) + { + string? commonIndentPrefix = null; + var first = true; + + foreach (var change in textChanges) + { + var text = SourceText.From(change.NewText); + foreach (var line in text.Lines) + { + if (first) + { + first = false; + continue; + } + + var nonWhitespaceIndex = GetFirstNonWhitespaceIndex(text, line); + if (nonWhitespaceIndex >= 0) + commonIndentPrefix = GetCommonIndentationPrefix(commonIndentPrefix, text, TextSpan.FromBounds(line.Start, nonWhitespaceIndex)); + } + } + + return commonIndentPrefix; + } + + private static string? GetCommonIndentationPrefix(string? commonIndentPrefix, SourceText text, TextSpan lineWhitespaceSpan) + { + // first line with indentation whitespace we're seeing. Just keep track of that. + if (commonIndentPrefix == null) + return text.ToString(lineWhitespaceSpan); + + // we have indentation whitespace from a previous line. Figure out the max commonality between it and the + // line we're currently looking at. + var commonPrefixLength = 0; + for (var n = Math.Min(commonIndentPrefix.Length, lineWhitespaceSpan.Length); commonPrefixLength < n; commonPrefixLength++) + { + if (commonIndentPrefix[commonPrefixLength] != text[lineWhitespaceSpan.Start + commonPrefixLength]) + break; + } + + return commonIndentPrefix[..commonPrefixLength]; + } + + public static TextSpan MapSpan(TextSpan span, ITextSnapshot from, ITextSnapshot to) + => from.CreateTrackingSpan(span.ToSpan(), SpanTrackingMode.EdgeInclusive).GetSpan(to).Span.ToTextSpan(); + + public static bool RawContentMustBeMultiLine(SourceText text, ImmutableArray spans) + { + Contract.ThrowIfTrue(spans.Length == 0); + + // Empty raw string must be multiline. + if (spans.Length == 1 && spans[0].IsEmpty) + return true; + + // Or if it starts/ends with a quote + if (spans.First().Length > 0 && text[spans.First().Start] == '"') + return true; + + if (spans.Last().Length > 0 && text[spans.Last().End - 1] == '"') + return true; + + // or contains a newline + foreach (var span in spans) + { + for (var i = span.Start; i < span.End; i++) + { + if (SyntaxFacts.IsNewLine(text[i])) + return true; + } + } + + return false; + } + } +} diff --git a/src/EditorFeatures/CSharp/StringCopyPaste/UnknownSourcePasteProcessor.cs b/src/EditorFeatures/CSharp/StringCopyPaste/UnknownSourcePasteProcessor.cs new file mode 100644 index 0000000000000..e53f00bfa4c07 --- /dev/null +++ b/src/EditorFeatures/CSharp/StringCopyPaste/UnknownSourcePasteProcessor.cs @@ -0,0 +1,357 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Indentation; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.StringCopyPaste +{ + using static StringCopyPasteHelpers; + + /// + /// Paste processor responsible for determining how text should be treated if it came from a source outside of the + /// editor we're in. In that case, we don't know what any particular piece of text means. For example, \t + /// might be a tab or it could be the literal two characters \ and t. + /// + internal class UnknownSourcePasteProcessor : AbstractPasteProcessor + { + public UnknownSourcePasteProcessor( + ITextSnapshot snapshotBeforePaste, + ITextSnapshot snapshotAfterPaste, + Document documentBeforePaste, + Document documentAfterPaste, + ExpressionSyntax stringExpressionBeforePaste, + string newLine, + IndentationOptions indentationOptions, + bool pasteWasSuccessful) + : base(snapshotBeforePaste, snapshotAfterPaste, documentBeforePaste, documentAfterPaste, stringExpressionBeforePaste, newLine, indentationOptions, pasteWasSuccessful) + { + } + + public ImmutableArray GetEdits(CancellationToken cancellationToken) + { + // If we have a raw-string, then we always want to check for changes to make, even if the paste was + // technically legal. This is because we may want to touch up things like indentation to make the + // pasted text look good for raw strings. + // + // Check for certain things we always think we should escape. + if (!IsAnyRawStringExpression(StringExpressionBeforePaste) && !ShouldAlwaysEscapeTextForNonRawString()) + { + // If the pasting was successful, then no need to change anything. + if (PasteWasSuccessful) + return default; + } + + // Ok, the user pasted text that couldn't cleanly be added to this token without issue. Repaste the + // contents, but this time properly escaped/manipulated so that it follows the rule of the particular token + // kind. + + // For pastes into non-raw strings, we can just determine how the change should be escaped in-line at that + // same location the paste originally happened at. For raw-strings things get more complex as we have to + // deal with things like indentation and potentially adding newlines to make things legal. + return IsAnyRawStringExpression(StringExpressionBeforePaste) + ? GetEditsForRawString(cancellationToken) + : GetEditsForNonRawString(); + } + + private bool ShouldAlwaysEscapeTextForNonRawString() + { + // Pasting a control character into a normal string literal is normally not desired. So even if this + // is legal, we still escape the contents to make the pasted code clear. + return !IsVerbatimStringExpression(StringExpressionBeforePaste) && ContainsControlCharacter(Changes); + } + + private ImmutableArray GetEditsForNonRawString() + { + var isVerbatim = IsVerbatimStringExpression(StringExpressionBeforePaste); + var isInterpolated = StringExpressionBeforePaste is InterpolatedStringExpressionSyntax; + + using var textChanges = TemporaryArray.Empty; + + foreach (var change in Changes) + textChanges.Add(new TextChange(change.OldSpan.ToTextSpan(), EscapeForNonRawStringLiteral(isVerbatim, isInterpolated, change.NewText))); + + return textChanges.ToImmutableAndClear(); + } + + /// + /// Given an initial raw string literal, and the changes made to it by the paste, determines how many quotes to + /// add to the start and end to keep things parsing properly. + /// + private string? GetQuotesToAddToRawString() + { + Contract.ThrowIfFalse(IsAnyRawStringExpression(StringExpressionBeforePaste)); + + var longestQuoteSequence = TextContentsSpansAfterPaste.Max(ts => GetLongestQuoteSequence(TextAfterPaste, ts)); + + var quotesToAddCount = (longestQuoteSequence - DelimiterQuoteCount) + 1; + return quotesToAddCount <= 0 ? null : new string('"', quotesToAddCount); + } + + /// + /// Given an initial raw string literal, and the changes made to it by the paste, determines how many dollar + /// signs to add to the start to keep things parsing properly. + /// + private string? GetDollarSignsToAddToRawString() + { + Contract.ThrowIfFalse(IsAnyRawStringExpression(StringExpressionBeforePaste)); + + // Only have to do this for interpolated strings. Other strings never have a $ in their starting delimiter. + if (StringExpressionBeforePaste is not InterpolatedStringExpressionSyntax) + return null; + + var longestBraceSequence = TextContentsSpansAfterPaste.Max( + ts => Math.Max( + GetLongestOpenBraceSequence(TextAfterPaste, ts), + GetLongestCloseBraceSequence(TextAfterPaste, ts))); + + var dollarsToAddCount = (longestBraceSequence - DelimiterDollarCount) + 1; + return dollarsToAddCount <= 0 ? null : new string('$', dollarsToAddCount); + } + + private ImmutableArray GetEditsForRawString(CancellationToken cancellationToken) + { + // Can't really figure anything out if the raw string is in error. + if (NodeOrTokenContainsError(StringExpressionBeforePaste)) + return default; + + // If all we're going to do is insert whitespace, then don't make any adjustments to the text. We don't want + // to end up inserting nothing and having the user very confused why their paste did nothing. + if (AllWhitespace(SnapshotBeforePaste.Version.Changes)) + return default; + + // if the content we're going to add itself contains quotes, then figure out how many start/end quotes the + // final string literal will need (which also gives us the number of quotes to add to the start/end). + // + // note: we don't have to do this if the paste was successful. Instead, we'll just process the contents, + // adjusting whitespace below. + var quotesToAdd = PasteWasSuccessful ? null : GetQuotesToAddToRawString(); + var dollarSignsToAdd = PasteWasSuccessful ? null : GetDollarSignsToAddToRawString(); + + using var _ = ArrayBuilder.GetInstance(out var editsToMake); + + // First, add any extra dollar signs needed. + if (dollarSignsToAdd != null) + editsToMake.Add(new TextChange(new TextSpan(StringExpressionBeforePaste.Span.Start, 0), dollarSignsToAdd)); + + // Then any quotes to your starting delimiter + if (quotesToAdd != null) + editsToMake.Add(new TextChange(new TextSpan(TextContentsSpansBeforePaste.First().Start, 0), quotesToAdd)); + + // Then add the actual changes in the content. + var isSingleLine = + StringExpressionBeforePaste is LiteralExpressionSyntax { Token.RawKind: (int)SyntaxKind.SingleLineRawStringLiteralToken } || + StringExpressionBeforePaste is InterpolatedStringExpressionSyntax { StringStartToken.RawKind: (int)SyntaxKind.InterpolatedSingleLineRawStringStartToken }; + + if (isSingleLine) + AdjustWhitespaceAndAddTextChangesForSingleLineRawStringLiteral(editsToMake, cancellationToken); + else + AdjustWhitespaceAndAddTextChangesForMultiLineRawStringLiteral(editsToMake); + + // Then add any extra end quotes needed. + if (quotesToAdd != null) + editsToMake.Add(new TextChange(new TextSpan(TextContentsSpansBeforePaste.Last().End, 0), quotesToAdd)); + + return editsToMake.ToImmutable(); + } + + // Pasting with single line case. + + private void AdjustWhitespaceAndAddTextChangesForSingleLineRawStringLiteral( + ArrayBuilder editsToMake, + CancellationToken cancellationToken) + { + // When pasting into a single-line raw literal we will keep it a single line if we can. If the content + // we're pasting starts/ends with a quote, or contains a newline, then we have to convert to a multiline. + // + // Pasting any other content into a single-line raw literal is always legal and needs no extra work on our + // part. + + var mustBeMultiLine = RawContentMustBeMultiLine(TextAfterPaste, TextContentsSpansAfterPaste); + + var indentationWhitespace = StringExpressionBeforePaste.GetFirstToken().GetPreferredIndentation(DocumentBeforePaste, IndentationOptions, cancellationToken); + + using var _ = PooledStringBuilder.GetInstance(out var buffer); + + // Then a newline and the indentation to start with. + if (mustBeMultiLine) + editsToMake.Add(new TextChange(new TextSpan(TextContentsSpansBeforePaste.First().Start, 0), NewLine + indentationWhitespace)); + + SourceText? textOfCurrentChange = null; + var commonIndentationPrefix = GetCommonIndentationPrefix(Changes) ?? ""; + + foreach (var change in Changes) + { + // Create a text object around the change text we're making. This is a very simple way to get + // a nice view of the text lines in the change. + textOfCurrentChange = SourceText.From(change.NewText); + + buffer.Clear(); + + for (var i = 0; i < textOfCurrentChange.Lines.Count; i++) + { + // The actual full line that was pasted in. + var currentChangeLine = textOfCurrentChange.Lines[i]; + var fullChangeLineText = textOfCurrentChange.ToString(currentChangeLine.SpanIncludingLineBreak); + + if (i == 0) + { + // on the first line, remove the common indentation if we can. Otherwise leave alone. + if (fullChangeLineText.StartsWith(commonIndentationPrefix, StringComparison.OrdinalIgnoreCase)) + buffer.Append(fullChangeLineText[commonIndentationPrefix.Length..]); + else + buffer.Append(fullChangeLineText); + } + else + { + // on all the rest of the lines, always remove the common indentation. + buffer.Append(fullChangeLineText[commonIndentationPrefix.Length..]); + } + + // if we ended with a newline, make sure the next line is indented enough. + if (HasNewLine(currentChangeLine)) + buffer.Append(indentationWhitespace); + } + + editsToMake.Add(new TextChange(change.OldSpan.ToTextSpan(), buffer.ToString())); + } + + // if the last change ended at the closing delimiter *and* ended with a newline, then we don't need to add a + // final newline-space at the end because we will have already done that. + if (mustBeMultiLine && !LastPastedLineAddedNewLine()) + editsToMake.Add(new TextChange(new TextSpan(TextContentsSpansBeforePaste.Last().End, 0), NewLine + indentationWhitespace)); + + return; + + bool LastPastedLineAddedNewLine() + { + return textOfCurrentChange != null && + Changes.Last().OldEnd == TextContentsSpansBeforePaste.Last().End && + HasNewLine(textOfCurrentChange.Lines.Last()); + } + } + + // Pasting into multi line case. + + private void AdjustWhitespaceAndAddTextChangesForMultiLineRawStringLiteral( + ArrayBuilder editsToMake) + { + var endLine = TextBeforePaste.Lines.GetLineFromPosition(StringExpressionBeforePaste.Span.End); + + // The indentation whitespace every line of the final raw string needs. + var indentationWhitespace = endLine.GetLeadingWhitespace(); + + using var _ = PooledStringBuilder.GetInstance(out var buffer); + + var commonIndentationPrefix = GetCommonIndentationPrefix(Changes); + + for (int changeIndex = 0, lastChangeIndex = Changes.Count; changeIndex < lastChangeIndex; changeIndex++) + { + var change = Changes[changeIndex]; + + // Create a text object around the change text we're making. This is a very simple way to get + // a nice view of the text lines in the change. + var textOfCurrentChange = SourceText.From(change.NewText); + buffer.Clear(); + + for (int lineIndex = 0, lastLineIndex = textOfCurrentChange.Lines.Count; lineIndex < lastLineIndex; lineIndex++) + { + var firstChange = changeIndex == 0 && lineIndex == 0; + var lastChange = (changeIndex == lastChangeIndex - 1) && (lineIndex == lastLineIndex - 1); + + // The actual full line that was pasted in. + var currentChangeLine = textOfCurrentChange.Lines[lineIndex]; + var fullChangeLineText = textOfCurrentChange.ToString(currentChangeLine.SpanIncludingLineBreak); + // The contents of the line, with all leading whitespace removed. + var (lineLeadingWhitespace, lineWithoutLeadingWhitespace) = ExtractWhitespace(fullChangeLineText); + + // This entire if-chain is only concerned with inserting the necessary whitespace a line should have. + + if (firstChange) + { + // The first line is often special. It may be copied without any whitespace (e.g. the user + // starts their selection at the start of text on that line, not the start of the line itself). + // So we use some heuristics to try to decide what to do depending on how much whitespace we see + // on that first copied line. + + TextBeforePaste.GetLineAndOffset(change.OldSpan.Start, out var line, out var offset); + + // First, ensure that the indentation whitespace of the *inserted* first line is sufficient. + if (line == TextBeforePaste.Lines.GetLineFromPosition(StringExpressionBeforePaste.SpanStart).LineNumber) + { + // if the first chunk was pasted into the space after the first `"""` then we need to actually + // insert a newline, then the indentation whitespace, then the first line of the change. + buffer.Append(NewLine); + buffer.Append(indentationWhitespace); + } + else if (offset < indentationWhitespace.Length) + { + // On the first line, we were pasting into the indentation whitespace. Ensure we add enough + // whitespace so that the trimmed line starts at an acceptable position. + buffer.Append(indentationWhitespace[offset..]); + } + + // Now, we want to actually insert any whitespace the line itself should have *if* it's got more + // than the common indentation whitespace. + if (commonIndentationPrefix != null && lineLeadingWhitespace.StartsWith(commonIndentationPrefix, StringComparison.OrdinalIgnoreCase)) + buffer.Append(lineLeadingWhitespace[commonIndentationPrefix.Length..]); + } + else if (!lastChange && lineWithoutLeadingWhitespace.Length > 0 && SyntaxFacts.IsNewLine(lineWithoutLeadingWhitespace[0])) + { + // if it's just an empty line, don't bother adding any whitespace at all. This will just end up + // inserting the blank line here. We don't do this on the last line as we want to still insert + // the right amount of indentation so that the user's caret is placed properly in the text. We + // could technically not insert the whitespace and attempt to place the caret using a virtual + // position, but this adds a lot of complexity to this system, so we avoid that for now and go + // for the simpler approach.. + } + else + { + // On any other line we're adding, ensure we have enough indentation whitespace to proceed. + // Add the necessary whitespace the literal needs, then add the line contents without + // the common whitespace included. + buffer.Append(indentationWhitespace); + if (commonIndentationPrefix != null) + buffer.Append(lineLeadingWhitespace[commonIndentationPrefix.Length..]); + } + + // After the necessary whitespace has been added, add the actual non-whitespace contents of the + // line. + buffer.Append(lineWithoutLeadingWhitespace); + + if (lastChange) + { + // Similar to the check we do for the first-change, if the last change was pasted into the space + // before the last `"""` then we need potentially insert a newline, then enough indentation + // whitespace to keep delimiter in the right location. + + TextBeforePaste.GetLineAndOffset(change.OldSpan.End, out var line, out var offset); + + if (line == TextBeforePaste.Lines.GetLineFromPosition(StringExpressionBeforePaste.Span.End).LineNumber) + { + if (!HasNewLine(currentChangeLine)) + buffer.Append(NewLine); + + buffer.Append(TextBeforePaste.ToString(new TextSpan(TextBeforePaste.Lines[line].Start, offset))); + } + } + } + + editsToMake.Add(new TextChange(change.OldSpan.ToTextSpan(), buffer.ToString())); + } + } + } +} diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf index 5e664298f8684..9b50d8d7f36f7 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf @@ -37,6 +37,11 @@ Opravit interpolovaný doslovný řetězec + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': Pro {1} se našlo několik ({0}) sestavení: diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf index 87091422c4aaa..b4a3f81acabf7 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf @@ -37,6 +37,11 @@ Interpolierte ausführliche Zeichenfolge korrigieren + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': {0} Assemblys für "{1}" gefunden: diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf index 77c6a7933a9b8..239d9293361e0 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf @@ -37,6 +37,11 @@ Corregir cadena textual interpolada + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': Se encontraron "{0}" ensamblados para "{1}": diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf index a633932b58c83..76bcab05a732e 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf @@ -37,6 +37,11 @@ Corriger la chaîne verbatim interpolée + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': '{0}' assemblys trouvés pour '{1}' : diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf index ddfab0bf495e4..3777480604bf2 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf @@ -37,6 +37,11 @@ Correggi stringa verbatim interpolata + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': Sono stati trovati '{0}' assembly per '{1}': diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf index fc1d9068b323a..57d8169573f5e 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf @@ -37,6 +37,11 @@ 挿入された逐語的文字列を修正します + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': '{1}' の '{0}' 個のアセンブリが見つかりました: diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf index b9e1402605fef..3e9ea626b2f78 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf @@ -37,6 +37,11 @@ 보간된 축자 문자열 수정 + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': '{1}'의 어셈블리를 '{0}'개 찾았습니다. diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf index e778a2338fb17..d5fc431a750c0 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf @@ -37,6 +37,11 @@ Napraw interpolowany ciąg dosłowny wyrażenia + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': Znaleziono zestawy („{0}”) dla elementu „{1}”: diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf index cd41f69017a24..a7ee73062221d 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf @@ -37,6 +37,11 @@ Corrigir cadeia de caracteres verbatim interpolada + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': Foram encontrados '{0}' assemblies para '{1}': diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf index 011021a61f4c3..82548636d70ba 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf @@ -37,6 +37,11 @@ Исправить интерполированную буквальную строку + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': Обнаружены сборки ("{0}") для "{1}": diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf index c531d0d68dbac..ec3c3dd361ee9 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf @@ -37,6 +37,11 @@ Ara değer olarak eklenmiş tam dizeyi düzelt + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': '{1}' için '{0}' bütünleştirilmiş kod bulundu: diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf index cde743d9c534c..c92527c6cde21 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf @@ -37,6 +37,11 @@ 修复插值的逐字字符串 + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': 找到 “{1}”的“{0}”个程序集: diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf index 12cc6a6d89125..c3f19125f5761 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf @@ -37,6 +37,11 @@ 修正插入的逐字字串 + + Fixing string literal after paste + Fixing string literal after paste + + Found '{0}' assemblies for '{1}': 找到 '{0}' 個 '{1}' 的組件: diff --git a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs index 8139305e4ba92..fcdd61c5e14ce 100644 --- a/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs +++ b/src/EditorFeatures/CSharpTest/AddUsing/AddUsingTests.cs @@ -6531,7 +6531,7 @@ static void Main(string[] args) "; await TestMissingAsync(initialWorkspace, new TestParameters( - codeActionOptions: CodeActionOptions.Default with { HideAdvancedMembers = true }, + globalOptions: Option(CompletionOptionsStorage.HideAdvancedMembers, true), testHost: testHost)); } } diff --git a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveScope.cs b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveScope.cs index 613542f651947..b56e246cd1437 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveScope.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/MoveType/MoveTypeTests.MoveScope.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings.MoveType; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Formatting; @@ -920,7 +921,7 @@ private async Task TestNamespaceMove(string originalCode, string expectedCode, b var moveTypeService = documentToModify.GetLanguageService(); Assert.NotNull(moveTypeService); - var modifiedSolution = await moveTypeService.GetModifiedSolutionAsync(documentToModify, textSpan, MoveTypeOperationKind.MoveTypeNamespaceScope, SyntaxFormattingOptions.GetDefaultAsync, CancellationToken.None).ConfigureAwait(false); + var modifiedSolution = await moveTypeService.GetModifiedSolutionAsync(documentToModify, textSpan, MoveTypeOperationKind.MoveTypeNamespaceScope, CodeActionOptions.DefaultProvider, CancellationToken.None).ConfigureAwait(false); if (expectOperation) { diff --git a/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs index c9cb8ab98b1dd..8f0061371aedd 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewExceptionTests.cs @@ -72,7 +72,7 @@ private static async Task GetPreview(TestWorkspace workspace, CodeRefactoringPro var suggestedAction = new CodeRefactoringSuggestedAction( workspace.ExportProvider.GetExportedValue(), workspace.ExportProvider.GetExportedValue(), - workspace, textBuffer, provider, codeActions.First()); + workspace, textBuffer, provider, codeActions.First(), fixAllFlavors: null); await suggestedAction.GetPreviewAsync(CancellationToken.None); Assert.True(extensionManager.IsDisabled(provider)); Assert.False(extensionManager.IsIgnored(provider)); @@ -85,7 +85,7 @@ private static void DisplayText(TestWorkspace workspace, CodeRefactoringProvider var suggestedAction = new CodeRefactoringSuggestedAction( workspace.ExportProvider.GetExportedValue(), workspace.ExportProvider.GetExportedValue(), - workspace, textBuffer, provider, codeActions.First()); + workspace, textBuffer, provider, codeActions.First(), fixAllFlavors: null); _ = suggestedAction.DisplayText; Assert.True(extensionManager.IsDisabled(provider)); Assert.False(extensionManager.IsIgnored(provider)); @@ -98,7 +98,7 @@ private static async Task ActionSets(TestWorkspace workspace, CodeRefactoringPro var suggestedAction = new CodeRefactoringSuggestedAction( workspace.ExportProvider.GetExportedValue(), workspace.ExportProvider.GetExportedValue(), - workspace, textBuffer, provider, codeActions.First()); + workspace, textBuffer, provider, codeActions.First(), fixAllFlavors: null); _ = await suggestedAction.GetActionSetsAsync(CancellationToken.None); Assert.True(extensionManager.IsDisabled(provider)); Assert.False(extensionManager.IsIgnored(provider)); diff --git a/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewTests.cs index 1991f04438d6a..da7c6f1f51d1e 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/Preview/PreviewTests.cs @@ -49,16 +49,16 @@ private class MyCodeRefactoringProvider : CodeRefactoringProvider { public sealed override Task ComputeRefactoringsAsync(CodeRefactoringContext context) { - var codeAction = new MyCodeAction(context.Document); + var codeAction = new TestCodeAction(context.Document); context.RegisterRefactoring(codeAction, context.Span); return Task.CompletedTask; } - private class MyCodeAction : CodeAction + private class TestCodeAction : CodeAction { private readonly Document _oldDocument; - public MyCodeAction(Document document) + public TestCodeAction(Document document) => _oldDocument = document; public override string Title diff --git a/src/EditorFeatures/CSharpTest/CodeActions/ReplaceMethodWithProperty/ReplaceMethodWithPropertyTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/ReplaceMethodWithProperty/ReplaceMethodWithPropertyTests.cs index c716feadef23c..b7c453c5ffc8b 100644 --- a/src/EditorFeatures/CSharpTest/CodeActions/ReplaceMethodWithProperty/ReplaceMethodWithPropertyTests.cs +++ b/src/EditorFeatures/CSharpTest/CodeActions/ReplaceMethodWithProperty/ReplaceMethodWithPropertyTests.cs @@ -2490,5 +2490,75 @@ bool M() "); } + + [WorkItem(37991, "https://github.com/dotnet/roslyn/issues/37991")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsReplaceMethodWithProperty)] + public async Task AllowIfNestedNullableIsSame() + { + await TestInRegularAndScriptAsync( +@" +#nullable enable + +using System.Linq; + +class C +{ + private IEnumerable names; + + public void SetNames(IEnumerable names) + { + this.names = names; + } + + public IEnumerable [||]GetNames() + { + return this.names.Where(n => n is object); + } +}", +@" +#nullable enable + +using System.Linq; + +class C +{ + private IEnumerable names; + + public IEnumerable Names { get => this.names.Where(n => n is object); set => this.names = value; } +}", index: 1); + } + + [WorkItem(37991, "https://github.com/dotnet/roslyn/issues/37991")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsReplaceMethodWithProperty)] + public async Task TestGetSetWithGeneric() + { + await TestInRegularAndScriptAsync( +@" +using System.Threading.Tasks; + +class C +{ + private Task someTask; + + public void SetSomeTask(Task t) + { + this.someTask = t; + } + + public Task [||]GetSomeTask() + { + return this.someTask; + } +}", +@" +using System.Threading.Tasks; + +class C +{ + private Task someTask; + + public Task SomeTask { get => this.someTask; set => this.someTask = value; } +}", index: 1); + } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs index f8b5c5f6e83b9..b678981c1a3cd 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs @@ -51,13 +51,13 @@ private protected override Task BaseVerifyWorkerAsync( SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, - List matchingFilters = null, CompletionItemFlags? flags = null) + List matchingFilters = null, CompletionItemFlags? flags = null, bool skipSpeculation = false) { return base.VerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, skipSpeculation: skipSpeculation); } private protected override async Task VerifyWorkerAsync( @@ -66,18 +66,18 @@ private protected override async Task VerifyWorkerAsync( SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, - bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) + bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null, bool skipSpeculation = false) { - await VerifyAtPositionAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); - await VerifyInFrontOfCommentAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); + await VerifyAtPositionAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, skipSpeculation: skipSpeculation); + await VerifyInFrontOfCommentAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, skipSpeculation: skipSpeculation); await VerifyAtEndOfFileAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); // Items cannot be partially written if we're checking for their absence, // or if we're verifying that the list will show up (without specifying an actual item) if (!checkForAbsence && expectedItemOrNull != null) { - await VerifyAtPosition_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); - await VerifyInFrontOfComment_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); + await VerifyAtPosition_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, skipSpeculation: skipSpeculation); + await VerifyInFrontOfComment_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, skipSpeculation: skipSpeculation); await VerifyAtEndOfFile_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); } } @@ -90,7 +90,7 @@ private async Task VerifyInFrontOfCommentAsync( string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, List matchingFilters) + string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, List matchingFilters, bool skipSpeculation = false) { code = code.Substring(0, position) + insertText + "/**/" + code.Substring(position); position += insertText.Length; @@ -99,7 +99,7 @@ await base.VerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, - inlineDescription, isComplexTextEdit, matchingFilters, flags: null); + inlineDescription, isComplexTextEdit, matchingFilters, flags: null, skipSpeculation: skipSpeculation); } private async Task VerifyInFrontOfCommentAsync( @@ -108,13 +108,13 @@ private async Task VerifyInFrontOfCommentAsync( SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, - List matchingFilters) + List matchingFilters, bool skipSpeculation = false) { await VerifyInFrontOfCommentAsync( code, position, string.Empty, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, skipSpeculation: skipSpeculation); } private protected async Task VerifyInFrontOfComment_ItemPartiallyWrittenAsync( @@ -123,13 +123,13 @@ private protected async Task VerifyInFrontOfComment_ItemPartiallyWrittenAsync( SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, - List matchingFilters) + List matchingFilters, bool skipSpeculation = false) { await VerifyInFrontOfCommentAsync( code, position, ItemPartiallyWritten(expectedItemOrNull), usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, skipSpeculation: skipSpeculation); } protected static string AddInsideMethod(string text) diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs index 7bf6a90253c83..f528845711a88 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs @@ -34,7 +34,7 @@ private protected override async Task VerifyWorkerAsync( SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, - List matchingFilters = null, CompletionItemFlags? flags = null) + List matchingFilters = null, CompletionItemFlags? flags = null, bool skipSpeculation = false) { await VerifyAtPositionAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs index 66f70c8b796df..72bf2ff1a344c 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs @@ -2852,6 +2852,20 @@ await VerifyItemExistsAsync(markup, "classB", glyph: (int)Glyph.Local, expectedDescriptionOrNull: CSharpFeaturesResources.Suggested_name); } + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task TestNotForUnboundAsync() + { + var markup = @" +class C +{ + async $$ +} +"; + await VerifyItemIsAbsentAsync(markup, "async"); + await VerifyItemIsAbsentAsync(markup, "Async"); + await VerifyItemIsAbsentAsync(markup, "GetAsync"); + } + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] [WorkItem(43816, "https://github.com/dotnet/roslyn/pull/43816")] public async Task ConflictingLocalVariable() @@ -2894,8 +2908,8 @@ private static NamingStylePreferences MultipleCamelCaseLocalRules() static (SymbolSpecification specification, NamingStyle style) SpecificationStyle(SymbolKindOrTypeKind kind, string name) { var symbolSpecification = new SymbolSpecification( - id: null, - symbolSpecName: name, + Guid.NewGuid(), + name, ImmutableArray.Create(kind)); var namingStyle = new NamingStyle( @@ -2928,8 +2942,8 @@ private static NamingStylePreferences NamesEndWithSuffixPreferences() static (SymbolSpecification specification, NamingStyle style) SpecificationStyle(SymbolKindOrTypeKind kind, string suffix) { var symbolSpecification = new SymbolSpecification( - id: null, - symbolSpecName: suffix, + Guid.NewGuid(), + name: suffix, ImmutableArray.Create(kind), accessibilityList: default, modifiers: default); @@ -2951,13 +2965,13 @@ private static NamingStylePreferences ParameterCamelCaseWithPascalCaseFallback() var symbolSpecifications = ImmutableArray.Create( new SymbolSpecification( id: Guid.NewGuid(), - symbolSpecName: "parameters", + name: "parameters", ImmutableArray.Create(new SymbolKindOrTypeKind(SymbolKind.Parameter)), accessibilityList: default, modifiers: default), new SymbolSpecification( id: Guid.NewGuid(), - symbolSpecName: "fallback", + name: "fallback", ImmutableArray.Create(new SymbolKindOrTypeKind(SymbolKind.Parameter), new SymbolKindOrTypeKind(SymbolKind.Local)), accessibilityList: default, modifiers: default)); diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs index a5460b6c00618..64b49d5e68b12 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs @@ -35,7 +35,7 @@ private protected override Task VerifyWorkerAsync( SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, - List matchingFilters = null, CompletionItemFlags? flags = null) + List matchingFilters = null, CompletionItemFlags? flags = null, bool skipSpeculation = false) { return BaseVerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs index 495eac7f70905..01eeb2900f505 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs @@ -38,7 +38,7 @@ private protected override Task VerifyWorkerAsync( SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, - List matchingFilters = null, CompletionItemFlags? flags = null) + List matchingFilters = null, CompletionItemFlags? flags = null, bool skipSpeculation = false) { return BaseVerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs index ebd748860d147..e1e54a030304a 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs @@ -11999,5 +11999,161 @@ public static void F() await VerifyItemIsAbsentAsync(source, "goo"); await VerifyItemIsAbsentAsync(source, "Bar"); } + + [Fact] + public async Task ParameterAvailableInMethodAttributeNameof() + { + var source = @" +class C +{ + [Some(nameof(p$$))] + void M(int parameter) { } +} +"; + await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); + + await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + } + + [Fact] + public async Task ParameterNotAvailableInMethodAttributeNameofWithNoArgument() + { + var source = @" +class C +{ + [Some(nameof($$))] + void M(int parameter) { } +} +"; + // Tracked by https://github.com/dotnet/roslyn/issues/60812 + await VerifyItemIsAbsentAsync(MakeMarkup(source), "parameter"); + } + + [Fact] + public async Task ParameterAvailableInMethodParameterAttributeNameof() + { + var source = @" +class C +{ + void M([Some(nameof(p$$))] int parameter) { } +} +"; + await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); + } + + [Fact] + public async Task ParameterAvailableInLocalFunctionAttributeNameof() + { + var source = @" +class C +{ + void M() + { + [Some(nameof(p$$))] + void local(int parameter) { } + } +} +"; + // Speculation within attributes on local functions is broken + // Tracked by https://github.com/dotnet/roslyn/issues/60801 + await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); + + await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + } + + [Fact] + public async Task ParameterAvailableInLocalFunctionParameterAttributeNameof() + { + var source = @" +class C +{ + void M() + { + void local([Some(nameof(p$$))] int parameter) { } + } +} +"; + // Speculation within attributes on local functions is broken + // Tracked by https://github.com/dotnet/roslyn/issues/60801 + await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); + + await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + } + + [Fact] + public async Task ParameterAvailableInLambdaAttributeNameof() + { + var source = @" +class C +{ + void M() + { + _ = [Some(nameof(p$$))] void(int parameter) => { }; + } +} +"; + // Speculation within attributes on local functions is broken + // Tracked by https://github.com/dotnet/roslyn/issues/60801 + await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); + + await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + } + + [Fact] + public async Task ParameterAvailableInLambdaParameterAttributeNameof() + { + var source = @" +class C +{ + void M() + { + _ = void([Some(nameof(p$$))] int parameter) => { }; + } +} +"; + // Speculation within attributes on local functions is broken + // Tracked by https://github.com/dotnet/roslyn/issues/60801 + await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); + + await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + } + + [Fact] + public async Task ParameterAvailableInDelegateAttributeNameof() + { + var source = @" +[Some(nameof(p$$))] +delegate void MyDelegate(int parameter); +"; + await VerifyItemExistsAsync(MakeMarkup(source), "parameter"); + + await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + } + + [Fact] + public async Task ParameterAvailableInDelegateParameterAttributeNameof() + { + var source = @" +delegate void MyDelegate([Some(nameof(p$$))] int parameter); +"; + // Speculation within attributes on local functions is broken + // Tracked by https://github.com/dotnet/roslyn/issues/60801 + await VerifyItemExistsAsync(MakeMarkup(source), "parameter", skipSpeculation: true); + + await VerifyItemIsAbsentAsync(MakeMarkup(source, languageVersion: "10"), "parameter"); + } + + private static string MakeMarkup(string source, string languageVersion = "Preview") + { + return $$""" + + + +{{source}} + + + +"""; + } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs index 880595bc1bb14..96782593c5ee6 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs @@ -32,7 +32,7 @@ private protected override Task VerifyWorkerAsync( SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, - List matchingFilters, CompletionItemFlags? flags = null) + List matchingFilters, CompletionItemFlags? flags = null, bool skipSpeculation = false) { return base.VerifyWorkerAsync(code, position, expectedItemOrNull, expectedDescriptionOrNull, diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs index 52cbea5299e13..3968c9abbeb8b 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs @@ -43,7 +43,7 @@ private protected override async Task VerifyWorkerAsync( SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, - List matchingFilters = null, CompletionItemFlags? flags = null) + List matchingFilters = null, CompletionItemFlags? flags = null, bool skipSpeculation = false) { // We don't need to try writing comments in from of items in doc comments. await VerifyAtPositionAsync( diff --git a/src/EditorFeatures/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests_OptionSets.cs b/src/EditorFeatures/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests_OptionSets.cs index ee7dff1727d13..6ab74c89276ad 100644 --- a/src/EditorFeatures/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests_OptionSets.cs +++ b/src/EditorFeatures/CSharpTest/ConvertAutoPropertyToFullProperty/ConvertAutoPropertyToFullPropertyTests_OptionSets.cs @@ -74,7 +74,7 @@ private OptionsCollection UseCustomStaticFieldName private static NamingStylePreferences CreateCustomFieldNamingStylePreference() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.Field)), accessibilityList: default, @@ -106,7 +106,7 @@ private static NamingStylePreferences CreateCustomFieldNamingStylePreference() private static NamingStylePreferences CreateUnderscorePrefixedFieldNamingStylePreference() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create(new SymbolKindOrTypeKind(SymbolKind.Field)), accessibilityList: default, @@ -138,7 +138,7 @@ private static NamingStylePreferences CreateUnderscorePrefixedFieldNamingStylePr private static NamingStylePreferences CreateCustomStaticFieldNamingStylePreference() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create(new SymbolKindOrTypeKind(SymbolKind.Field)), accessibilityList: default, diff --git a/src/EditorFeatures/CSharpTest/ConvertToRawString/ConvertToRegularStringToRawStringStringTests.cs b/src/EditorFeatures/CSharpTest/ConvertToRawString/ConvertToRegularStringToRawStringStringTests.cs index 2b45607483b73..87f7a0b79ec2e 100644 --- a/src/EditorFeatures/CSharpTest/ConvertToRawString/ConvertToRegularStringToRawStringStringTests.cs +++ b/src/EditorFeatures/CSharpTest/ConvertToRawString/ConvertToRegularStringToRawStringStringTests.cs @@ -246,26 +246,6 @@ void M() }"); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentStringWithQuoteAtStart() - { - await VerifyRefactoringAsync(@"public class C -{ - void M() - { - var v = [||]""\""goobar""; - } -}", @"public class C -{ - void M() - { - var v = """""" -""goobar -""""""; - } -}", index: 1); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] public async Task TestVerbatimStringWithQuoteAtStart() { @@ -286,26 +266,6 @@ void M() }"); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentVerbatimStringWithQuoteAtStart() - { - await VerifyRefactoringAsync(@"public class C -{ - void M() - { - var v = [||]@""""""goobar""; - } -}", @"public class C -{ - void M() - { - var v = """""" -""goobar -""""""; - } -}", index: 1); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] public async Task TestStringWithQuoteAtEnd() { @@ -326,26 +286,6 @@ void M() }"); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentStringWithQuoteAtEnd() - { - await VerifyRefactoringAsync(@"public class C -{ - void M() - { - var v = [||]""goobar\""""; - } -}", @"public class C -{ - void M() - { - var v = """""" -goobar"" -""""""; - } -}", index: 1); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] public async Task TestVerbatimStringWithQuoteAtEnd() { @@ -366,26 +306,6 @@ void M() }"); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentVerbatimStringWithQuoteAtEnd() - { - await VerifyRefactoringAsync(@"public class C -{ - void M() - { - var v = [||]@""goobar""""""; - } -}", @"public class C -{ - void M() - { - var v = """""" -goobar"" -""""""; - } -}", index: 1); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] public async Task TestStringWithNewLine() { @@ -407,27 +327,6 @@ void M() }"); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentStringWithNewLine() - { - await VerifyRefactoringAsync(@"public class C -{ - void M() - { - var v = [||]""goo\r\nbar""; - } -}", @"public class C -{ - void M() - { - var v = """""" -goo -bar -""""""; - } -}", index: 1); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] public async Task TestVerbatimStringWithNewLine() { @@ -450,28 +349,6 @@ void M() }"); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentVerbatimStringWithNewLine() - { - await VerifyRefactoringAsync(@"public class C -{ - void M() - { - var v = [||]@""goo -bar""; - } -}", @"public class C -{ - void M() - { - var v = """""" -goo -bar -""""""; - } -}", index: 1); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] public async Task TestStringWithNewLineAtStartAndEnd() { @@ -494,28 +371,6 @@ void M() }"); } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentStringWithNewLineAtStartAndEnd() - { - await VerifyRefactoringAsync(@"public class C -{ - void M() - { - var v = [||]""\r\ngoobar\r\n""; - } -}", @"public class C -{ - void M() - { - var v = """""" - -goobar - -""""""; - } -}", index: 1); - } - [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] public async Task TestVerbatimStringWithNewLineAtStartAndEnd() { @@ -556,10 +411,8 @@ void M() void M() { var v = """""" - -goobar - -""""""; + goobar + """"""; } }", index: 1); } @@ -586,22 +439,26 @@ void M() } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentedString() + public async Task TestWithoutLeadingWhitespace1() { await VerifyRefactoringAsync(@"public class C { void M() { - var v = [||]""goo\r\nbar""; + var v = [||]@"" +from x in y +where x > 0 +select x""; } }", @"public class C { void M() { var v = """""" -goo -bar -""""""; + from x in y + where x > 0 + select x + """"""; } }", index: 1); } @@ -620,15 +477,19 @@ await VerifyRefactoringAsync(@" } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentedStringTopLevel() + public async Task TestWithoutLeadingWhitespaceTopLevel() { await VerifyRefactoringAsync(@" -var v = [||]""goo\r\nbar""; +var v = [||]@"" +from x in y +where x > 0 +select x""; ", @" var v = """""" -goo -bar -""""""; + from x in y + where x > 0 + select x + """"""; ", index: 1, outputKind: OutputKind.ConsoleApplication); } @@ -655,36 +516,38 @@ void M() } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentVerbatimIndentedString() + public async Task TestIndentedStringOnOwnLine() { await VerifyRefactoringAsync(@"public class C { void M() { - var v = [||]@""goo -bar""; + var v = + [||]""goo\r\nbar""; } }", @"public class C { void M() { - var v = """""" -goo -bar -""""""; + var v = + """""" + goo + bar + """"""; } -}", index: 1); +}"); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestIndentedStringOnOwnLine() + public async Task TestVerbatimIndentedStringOnOwnLine() { await VerifyRefactoringAsync(@"public class C { void M() { var v = - [||]""goo\r\nbar""; + [||]@""goo +bar""; } }", @"public class C { @@ -700,72 +563,134 @@ void M() } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentedStringOnOwnLine() + public async Task TestWithoutLeadingWhitespace2() { await VerifyRefactoringAsync(@"public class C { void M() { - var v = - [||]""goo\r\nbar""; + var v = [||]@"" + from x in y + where x > 0 + select x""; } }", @"public class C { void M() { - var v = - """""" -goo -bar -""""""; + var v = """""" + from x in y + where x > 0 + select x + """"""; } }", index: 1); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestVerbatimIndentedStringOnOwnLine() + public async Task TestWithoutLeadingWhitespace3() { await VerifyRefactoringAsync(@"public class C { void M() { - var v = - [||]@""goo -bar""; + var v = [||]@"" + from x in y + where x > 0 + select x + ""; } }", @"public class C { void M() { - var v = - """""" - goo - bar - """"""; + var v = """""" + from x in y + where x > 0 + select x + """"""; } -}"); +}", index: 1); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] - public async Task TestNoIndentVerbatimIndentedStringOnOwnLine() + public async Task TestWithoutLeadingWhitespace4() { await VerifyRefactoringAsync(@"public class C { void M() { - var v = - [||]@""goo -bar""; + var v = [||]@"" + from x in y + where x > 0 + select x + ""; } }", @"public class C { void M() { - var v = - """""" -goo -bar -""""""; + var v = """""" + from x in y + where x > 0 + select x + """"""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestWithoutLeadingWhitespace5() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@"" + from x in y + where x > 0 + select x + ""; + } +}", @"public class C +{ + void M() + { + var v = """""" + from x in y + where x > 0 + select x + """"""; + } +}", index: 1); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertRegularToRawString)] + public async Task TestWithoutLeadingWhitespace6() + { + await VerifyRefactoringAsync(@"public class C +{ + void M() + { + var v = [||]@"" + from x in y + + where x > 0 + + select x + ""; + } +}", @"public class C +{ + void M() + { + var v = """""" + from x in y + + where x > 0 + + select x + """"""; } }", index: 1); } diff --git a/src/EditorFeatures/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs b/src/EditorFeatures/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs index 9ad2925b2719e..17b3e42ce59f4 100644 --- a/src/EditorFeatures/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs +++ b/src/EditorFeatures/CSharpTest/ConvertTupleToStruct/ConvertTupleToStructTests.cs @@ -375,7 +375,7 @@ public static implicit operator NewStruct((int A, int B) value) } }"; var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name2", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.Parameter)), accessibilityList: default, diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs index 5f660b4ef5fbe..99a81b7a362ae 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/Suppression/SuppressionTests.cs @@ -467,8 +467,7 @@ void Method() var diagnostics = await diagnosticService.GetDiagnosticsForSpanAsync(document, span); Assert.Equal(2, diagnostics.Where(d => d.Id == "CS0219").Count()); - var options = CodeActionOptions.Default; - var allFixes = (await fixService.GetFixesAsync(document, span, _ => options, CancellationToken.None)) + var allFixes = (await fixService.GetFixesAsync(document, span, CodeActionOptions.DefaultProvider, CancellationToken.None)) .SelectMany(fixCollection => fixCollection.Fixes); var cs0219Fixes = allFixes.Where(fix => fix.PrimaryDiagnostic.Id == "CS0219").ToArray(); diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateJsonStringTests.cs b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateJsonStringTests.cs index 8b50c83eeb4e7..dfbadb3e4d1aa 100644 --- a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateJsonStringTests.cs +++ b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateJsonStringTests.cs @@ -25,8 +25,8 @@ public ValidateJsonStringTests(ITestOutputHelper logger) : base(logger) internal override (DiagnosticAnalyzer, CodeFixProvider?) CreateDiagnosticProviderAndFixer(Workspace workspace) => (new CSharpJsonDiagnosticAnalyzer(), null); - private static IdeAnalyzerOptions OptionOn() - => new(ReportInvalidJsonPatterns: true); + private OptionsCollection OptionOn() + => Option(IdeAnalyzerOptionsStorage.ReportInvalidJsonPatterns, true); [Fact, Trait(Traits.Feature, Traits.Features.ValidateJsonString)] public async Task TestWarning1() @@ -39,7 +39,7 @@ void Main() var r = /*lang=json,strict*/ ""[|new|] Json()""; } }", - ideAnalyzerOptions: OptionOn(), + globalOptions: OptionOn(), diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning, diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, FeaturesResources.Constructors_not_allowed)); @@ -56,7 +56,7 @@ void Main() var r = /*lang=json,strict*/ """"""[|new|] Json()""""""; } }", - ideAnalyzerOptions: OptionOn(), + globalOptions: OptionOn(), diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning, diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, FeaturesResources.Constructors_not_allowed)); @@ -73,7 +73,7 @@ void Main() var r = /*lang=json*/ ""[|}|]""; } }", - ideAnalyzerOptions: OptionOn(), + globalOptions: OptionOn(), diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning, diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, @@ -98,7 +98,7 @@ void Main() ", - ideAnalyzerOptions: OptionOn(), + globalOptions: OptionOn(), diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning, diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, @@ -123,7 +123,7 @@ void Main() ", - ideAnalyzerOptions: OptionOn(), + globalOptions: OptionOn(), diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning, diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, @@ -188,7 +188,7 @@ void Main() ", - ideAnalyzerOptions: OptionOn(), + globalOptions: OptionOn(), diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning, diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, @@ -213,7 +213,7 @@ void Main() ", - ideAnalyzerOptions: OptionOn(), + globalOptions: OptionOn(), diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning, diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, @@ -284,7 +284,7 @@ void M([StringSyntax(StringSyntaxAttribute.Json)] string p) ", - ideAnalyzerOptions: OptionOn(), + globalOptions: OptionOn(), diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning, diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, @@ -315,7 +315,7 @@ void M([StringSyntax(StringSyntaxAttribute.Json)] string p, JsonDocumentOptions ", - ideAnalyzerOptions: OptionOn(), + globalOptions: OptionOn(), diagnosticId: AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning, diagnosticMessage: string.Format(FeaturesResources.JSON_issue_0, diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateRegexStringTests.cs b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateRegexStringTests.cs index 17c81160aac77..a48ebb753a756 100644 --- a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateRegexStringTests.cs +++ b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateRegexStringTests.cs @@ -25,8 +25,8 @@ public ValidateRegexStringTests(ITestOutputHelper logger) internal override (DiagnosticAnalyzer, CodeFixProvider?) CreateDiagnosticProviderAndFixer(Workspace workspace) => (new CSharpRegexDiagnosticAnalyzer(), null); - private static IdeAnalyzerOptions OptionOn() - => new(ReportInvalidRegexPatterns: true); + private OptionsCollection OptionOn() + => Option(IdeAnalyzerOptionsStorage.ReportInvalidRegexPatterns, true); [Fact, Trait(Traits.Feature, Traits.Features.ValidateRegexString)] public async Task TestWarning1() @@ -41,7 +41,7 @@ void Main() var r = new Regex(@""[|)|]""); } }", - ideAnalyzerOptions: OptionOn(), + globalOptions: OptionOn(), diagnosticId: AbstractRegexDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning, diagnosticMessage: string.Format(FeaturesResources.Regex_issue_0, FeaturesResources.Too_many_close_parens)); @@ -60,7 +60,7 @@ void Main() var r = new Regex(""[|\u0029|]""); } }", - ideAnalyzerOptions: OptionOn(), + globalOptions: OptionOn(), diagnosticId: AbstractRegexDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning, diagnosticMessage: string.Format(FeaturesResources.Regex_issue_0, FeaturesResources.Too_many_close_parens)); diff --git a/src/EditorFeatures/CSharpTest/EventHookup/EventHookupCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/EventHookup/EventHookupCommandHandlerTests.cs index 0d57db3ad040d..de73ed9029c26 100644 --- a/src/EditorFeatures/CSharpTest/EventHookup/EventHookupCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/EventHookup/EventHookupCommandHandlerTests.cs @@ -1080,6 +1080,122 @@ void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEv testState.AssertCodeIs(expectedCode); } + [WpfFact, Trait(Traits.Feature, Traits.Features.EventHookup)] + [WorkItem(59935, "https://github.com/dotnet/roslyn/issues/59935")] + public async Task HandlerName_EventInGenericClass() + { + var markup = @" +using System; + +class C +{ + void M() + { + Generic<int>.MyEvent +$$ + } +} + +class Generic<T> +{ + public static event EventHandler MyEvent; +}"; + using var testState = EventHookupTestState.CreateTestState(markup); + testState.SendTypeChar('='); + await testState.WaitForAsynchronousOperationsAsync(); + testState.AssertShowing("Generic_MyEvent"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.EventHookup)] + public async Task HandlerName_GlobalAlias01() + { + var markup = @" +using System; + +class C +{ + void M() + { + global::D.MyEvent +$$ + } +} + +class D +{ + public static event EventHandler MyEvent; +}"; + using var testState = EventHookupTestState.CreateTestState(markup); + testState.SendTypeChar('='); + await testState.WaitForAsynchronousOperationsAsync(); + testState.AssertShowing("D_MyEvent"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.EventHookup)] + public async Task HandlerName_GlobalAlias02() + { + var markup = @" +using System; + +class C +{ + void M() + { + global::Generic<int>.MyEvent +$$ + } +} + +class Generic<T> +{ + public static event EventHandler MyEvent; +}"; + using var testState = EventHookupTestState.CreateTestState(markup); + testState.SendTypeChar('='); + await testState.WaitForAsynchronousOperationsAsync(); + testState.AssertShowing("Generic_MyEvent"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.EventHookup)] + public async Task HandlerName_GlobalAlias03() + { + var markup = @" +class Program +{ + void Main(string[] args) + { + global::System.Console.CancelKeyPress +$$ + } +}"; + using var testState = EventHookupTestState.CreateTestState(markup); + testState.SendTypeChar('='); + await testState.WaitForAsynchronousOperationsAsync(); + testState.AssertShowing("Console_CancelKeyPress"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.EventHookup)] + public async Task HandlerName_InvocationExpression() + { + var markup = @" +using System; + +class C +{ + public event EventHandler MyEvent; + + public static C CreateC() + { + return new C(); + } + + public void M2() + { + CreateC().MyEvent +$$ + } +}"; + using var testState = EventHookupTestState.CreateTestState(markup); + testState.SendTypeChar('='); + await testState.WaitForAsynchronousOperationsAsync(); + testState.AssertShowing("C_MyEvent"); + } + private static OptionsCollection QualifyMethodAccessWithNotification(NotificationOption2 notification) => new OptionsCollection(LanguageNames.CSharp) { { CodeStyleOptions2.QualifyMethodAccess, true, notification } }; } diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs index 2098716e9366f..19610dfd66bab 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodBase.cs @@ -8,10 +8,13 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.ExtractMethod; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.Test.Utilities; @@ -127,9 +130,14 @@ protected static async Task ExtractMethodAsync( var document = workspace.CurrentSolution.GetDocument(testDocument.Id); Assert.NotNull(document); - var options = new ExtractMethodOptions(DontPutOutOrRefOnStruct: dontPutOutOrRefOnStruct); + var options = new ExtractMethodGenerationOptions( + ExtractOptions: new ExtractMethodOptions(dontPutOutOrRefOnStruct), + CodeGenerationOptions: CodeGenerationOptions.GetDefault(document.Project.LanguageServices), + AddImportOptions: AddImportPlacementOptions.Default, + NamingPreferences: _ => NamingStylePreferences.Default); + var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None); - var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), localFunction: false, options); + var validator = new CSharpSelectionValidator(semanticDocument, testDocument.SelectedSpans.Single(), options.ExtractOptions, localFunction: false); var selectedCode = await validator.GetValidSelectionAsync(CancellationToken.None); if (!succeed && selectedCode.Status.FailedWithNoBestEffortSuggestion()) @@ -140,7 +148,7 @@ protected static async Task ExtractMethodAsync( Assert.True(selectedCode.ContainsValidContext); // extract method - var extractor = new CSharpMethodExtractor((CSharpSelectionResult)selectedCode, localFunction: false); + var extractor = new CSharpMethodExtractor((CSharpSelectionResult)selectedCode, options, localFunction: false); var result = await extractor.ExtractMethodAsync(CancellationToken.None); Assert.NotNull(result); Assert.Equal(succeed, @@ -164,7 +172,7 @@ protected static async Task TestSelectionAsync(string codeWithMarker, bool expec Assert.NotNull(document); var semanticDocument = await SemanticDocument.CreateAsync(document, CancellationToken.None); - var validator = new CSharpSelectionValidator(semanticDocument, textSpanOverride ?? namedSpans["b"].Single(), localFunction: false, ExtractMethodOptions.Default); + var validator = new CSharpSelectionValidator(semanticDocument, textSpanOverride ?? namedSpans["b"].Single(), ExtractMethodOptions.Default, localFunction: false); var result = await validator.GetValidSelectionAsync(CancellationToken.None); Assert.True(expectedFail ? result.Status.Failed() : result.Status.Succeeded()); @@ -187,7 +195,7 @@ protected static async Task IterateAllAsync(string code) foreach (var node in iterator) { - var validator = new CSharpSelectionValidator(semanticDocument, node.Span, localFunction: false, ExtractMethodOptions.Default); + var validator = new CSharpSelectionValidator(semanticDocument, node.Span, ExtractMethodOptions.Default, localFunction: false); var result = await validator.GetValidSelectionAsync(CancellationToken.None); // check the obvious case diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs index da7cadbf52e68..4791bac6b8cdc 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs @@ -10375,7 +10375,7 @@ public async Task ExtractMethod_Argument1() var service = new CSharpExtractMethodService(); Assert.NotNull(await Record.ExceptionAsync(async () => { - var tree = await service.ExtractMethodAsync(document: null, textSpan: default, localFunction: false, options: ExtractMethodOptions.Default, CancellationToken.None); + var tree = await service.ExtractMethodAsync(document: null, textSpan: default, localFunction: false, options: default, CancellationToken.None); })); } @@ -10391,7 +10391,7 @@ public async Task ExtractMethod_Argument2() var service = new CSharpExtractMethodService() as IExtractMethodService; - await service.ExtractMethodAsync(document, textSpan: default, localFunction: false, ExtractMethodOptions.Default, CancellationToken.None); + await service.ExtractMethodAsync(document, textSpan: default, localFunction: false, ExtractMethodGenerationOptions.GetDefault(project.LanguageServices), CancellationToken.None); } [WpfFact] diff --git a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs index 6ca5918c82918..3dd3a6319fc83 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs @@ -557,7 +557,7 @@ private void Method() [Theory] [Trait(Traits.Feature, Traits.Features.CodeCleanup)] [InlineData(LanguageNames.CSharp, 35)] - [InlineData(LanguageNames.VisualBasic, 70)] + [InlineData(LanguageNames.VisualBasic, 71)] public void VerifyAllCodeStyleFixersAreSupportedByCodeCleanup(string language, int expectedNumberOfUnsupportedDiagnosticIds) { var supportedDiagnostics = GetSupportedDiagnosticIdsForCodeCleanupService(language); @@ -654,7 +654,7 @@ private protected static async Task AssertCodeCleanupResult(string expected, str }); var newDoc = await codeCleanupService.CleanupAsync( - document, enabledDiagnostics, new ProgressTracker(), _ => fallbackOptions, CancellationToken.None); + document, enabledDiagnostics, new ProgressTracker(), fallbackOptions.CreateProvider(), CancellationToken.None); var actual = await newDoc.GetTextAsync(); diff --git a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs index 7694d0b1e544e..5a64eb7def58d 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; @@ -31,13 +32,13 @@ public class FormattingEngineTests : CSharpFormattingEngineTestBase { public FormattingEngineTests(ITestOutputHelper output) : base(output) { } - private static Dictionary SmartIndentButDoNotFormatWhileTyping() + private static OptionsCollection SmartIndentButDoNotFormatWhileTyping() { - return new Dictionary + return new OptionsCollection(LanguageNames.CSharp) { - { new OptionKey2(IndentationOptionsStorage.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.Smart }, - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnTyping, LanguageNames.CSharp), false }, - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnCloseBrace, LanguageNames.CSharp), false }, + { IndentationOptionsStorage.SmartIndent, FormattingOptions2.IndentStyle.Smart }, + { AutoFormattingOptionsStorage.FormatOnTyping, false }, + { AutoFormattingOptionsStorage.FormatOnCloseBrace, false }, }; } @@ -1071,9 +1072,9 @@ class C1 class C1 { }"; - var globalOptions = new Dictionary + var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { new OptionKey2(IndentationOptionsStorage.SmartIndent, LanguageNames.CSharp), FormattingOptions.IndentStyle.None } + { IndentationOptionsStorage.SmartIndent, FormattingOptions2.IndentStyle.None } }; AssertFormatAfterTypeChar(code, expected, globalOptions); } @@ -1102,9 +1103,9 @@ class C } "; - var globalOptions = new Dictionary + var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnCloseBrace, LanguageNames.CSharp), false } + { AutoFormattingOptionsStorage.FormatOnCloseBrace, false } }; AssertFormatAfterTypeChar(code, expected, globalOptions); @@ -1134,9 +1135,9 @@ class C } "; - var globalOptions = new Dictionary + var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnTyping, LanguageNames.CSharp), false } + { AutoFormattingOptionsStorage.FormatOnTyping, false } }; AssertFormatAfterTypeChar(code, expected, globalOptions); @@ -1166,9 +1167,9 @@ static void Main() } }"; - var globalOptions = new Dictionary + var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnTyping, LanguageNames.CSharp), false } + { AutoFormattingOptionsStorage.FormatOnTyping, false } }; AssertFormatAfterTypeChar(code, expected, globalOptions); @@ -1224,9 +1225,9 @@ class C } "; - var globalOptions = new Dictionary + var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnSemicolon, LanguageNames.CSharp), false } + { AutoFormattingOptionsStorage.FormatOnSemicolon, false } }; AssertFormatAfterTypeChar(code, expected, globalOptions); @@ -1256,9 +1257,9 @@ class C } "; - var globalOptions = new Dictionary + var globalOptions = new OptionsCollection(LanguageNames.CSharp) { - { new OptionKey2(AutoFormattingOptionsStorage.FormatOnTyping, LanguageNames.CSharp), false } + { AutoFormattingOptionsStorage.FormatOnTyping, false } }; AssertFormatAfterTypeChar(code, expected, globalOptions); @@ -2563,17 +2564,11 @@ interface I1 AssertFormatAfterTypeChar(code, expected); } - private static void AssertFormatAfterTypeChar(string code, string expected, Dictionary globalOptions = null, ParseOptions parseOptions = null) + private static void AssertFormatAfterTypeChar(string code, string expected, OptionsCollection globalOptions = null, ParseOptions parseOptions = null) { using var workspace = TestWorkspace.CreateCSharp(code, parseOptions: parseOptions); - if (globalOptions != null) - { - var options = workspace.GlobalOptions; - foreach (var entry in globalOptions) - { - options.SetGlobalOption((OptionKey)entry.Key, entry.Value); - } - } + + globalOptions?.SetGlobalOptions(workspace.GlobalOptions); var subjectDocument = workspace.Documents.Single(); diff --git a/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs b/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs index 68f5385c5b729..bef39bc5c8f17 100644 --- a/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs +++ b/src/EditorFeatures/CSharpTest/FullyQualify/FullyQualifyTests.cs @@ -1645,7 +1645,7 @@ static void Main(string[] args) "; await TestMissingAsync(initialWorkspace, new TestParameters( - codeActionOptions: CodeActionOptions.Default with { HideAdvancedMembers = true })); + globalOptions: Option(CompletionOptionsStorage.HideAdvancedMembers, true))); } } } diff --git a/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs b/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs index d6624d0d75a81..99716e7d0f9a6 100644 --- a/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs +++ b/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.ImplementAbstractClass; @@ -1469,10 +1470,7 @@ class T : A [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] public async Task TestWithGroupingOff1() { - var options = CodeActionOptions.Default with - { - ImplementTypeOptions = new ImplementTypeOptions(InsertionBehavior: ImplementTypeInsertionBehavior.AtTheEnd) - }; + var options = Option(ImplementTypeOptionsStorage.InsertionBehavior, ImplementTypeInsertionBehavior.AtTheEnd); await TestInRegularAndScriptAsync( @"abstract class Base @@ -1494,7 +1492,7 @@ class Derived : Base void Goo() { } public override int Prop => throw new System.NotImplementedException(); -}", codeActionOptions: options); +}", globalOptions: options); } [WorkItem(17274, "https://github.com/dotnet/roslyn/issues/17274")] @@ -1647,9 +1645,10 @@ public override void M2(T? i = null) [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] public async Task TestAutoProperties() { - var options = CodeActionOptions.Default with + var options = new OptionsCollection(GetLanguage()) { - ImplementTypeOptions = new ImplementTypeOptions(PropertyGenerationBehavior: ImplementTypePropertyGenerationBehavior.PreferAutoProperties) + Option(ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties), + Option(CompletionOptionsStorage.HideAdvancedMembers, true), }; await TestInRegularAndScript1Async( @@ -1675,7 +1674,7 @@ class C : AbstractClass public override int ReadOnlyProp { get; } public override int ReadWriteProp { get; set; } public override int WriteOnlyProp { set => throw new System.NotImplementedException(); } -}", parameters: new TestParameters(codeActionOptions: options)); +}", parameters: new TestParameters(globalOptions: options)); } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] diff --git a/src/EditorFeatures/CSharpTest/InvertConditional/InvertConditionalTests_FixAll.cs b/src/EditorFeatures/CSharpTest/InvertConditional/InvertConditionalTests_FixAll.cs new file mode 100644 index 0000000000000..db4852821cef7 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/InvertConditional/InvertConditionalTests_FixAll.cs @@ -0,0 +1,412 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.InvertConditional +{ + [Trait(Traits.Feature, Traits.Features.CodeActionsInvertConditional)] + public partial class InvertConditionalTests : AbstractCSharpCodeActionTest + { + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task InvertConditional_FixAllInDocument() + { + await TestInRegularAndScriptAsync( +@"class C +{ + void M(bool x, int a, int b) + { + var c = {|FixAllInDocument:|}x ? a : b; + } + + void M2(bool x, int a, int b) + { + var c = x ? a : b; + } +}", +@"class C +{ + void M(bool x, int a, int b) + { + var c = !x ? b : a; + } + + void M2(bool x, int a, int b) + { + var c = !x ? b : a; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task InvertConditional_FixAllInProject() + { + await TestInRegularAndScriptAsync( +@" + + + +class Program1 +{ + void M1(bool x, int a, int b) + { + var c = {|FixAllInProject:|}x ? a : b; + } +} + + +class Program2 +{ + void M2(bool x, int a, int b) + { + var c = x ? a : b; + } +} + + + + +class Program3 +{ + void M3(bool x, int a, int b) + { + var c = x ? a : b; + } +} + + +", +@" + + +class Program1 +{ + void M1(bool x, int a, int b) + { + var c = !x ? b : a; + } +} + + +class Program2 +{ + void M2(bool x, int a, int b) + { + var c = !x ? b : a; + } +} + + + + +class Program3 +{ + void M3(bool x, int a, int b) + { + var c = x ? a : b; + } +} + + +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task InvertConditional_FixAllInSolution() + { + await TestInRegularAndScriptAsync( +@" + + + +class Program1 +{ + void M1(bool x, int a, int b) + { + var c = {|FixAllInSolution:|}x ? a : b; + } +} + + +class Program2 +{ + void M2(bool x, int a, int b) + { + var c = x ? a : b; + } +} + + + + +class Program3 +{ + void M3(bool x, int a, int b) + { + var c = x ? a : b; + } +} + + +", +@" + + +class Program1 +{ + void M1(bool x, int a, int b) + { + var c = !x ? b : a; + } +} + + +class Program2 +{ + void M2(bool x, int a, int b) + { + var c = !x ? b : a; + } +} + + + + +class Program3 +{ + void M3(bool x, int a, int b) + { + var c = !x ? b : a; + } +} + + +"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task InvertConditional_FixAllInContainingMember() + { + await TestInRegularAndScriptAsync( +@"class C +{ + void M(bool x, int a, int b) + { + var c = {|FixAllInContainingMember:|}x ? a : b; + var c2 = x ? a : b; + } + + void M2(bool x, int a, int b) + { + var c = x ? a : b; + var c2 = x ? a : b; + } +} + +class C2 +{ + void M(bool x, int a, int b) + { + var c = x ? a : b; + var c2 = x ? a : b; + } +}", +@"class C +{ + void M(bool x, int a, int b) + { + var c = !x ? b : a; + var c2 = !x ? b : a; + } + + void M2(bool x, int a, int b) + { + var c = x ? a : b; + var c2 = x ? a : b; + } +} + +class C2 +{ + void M(bool x, int a, int b) + { + var c = x ? a : b; + var c2 = x ? a : b; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task InvertConditional_FixAllInContainingType() + { + await TestInRegularAndScriptAsync( +@"partial class C +{ + void M(bool x, int a, int b) + { + var c = {|FixAllInContainingType:|}x ? a : b; + var c2 = x ? a : b; + } + + void M2(bool x, int a, int b) + { + var c = x ? a : b; + var c2 = x ? a : b; + } +} + +class C2 +{ + void M(bool x, int a, int b) + { + var c = x ? a : b; + var c2 = x ? a : b; + } +} + +partial class C +{ + void M3(bool x, int a, int b) + { + var c = x ? a : b; + var c2 = x ? a : b; + } +}", +@"partial class C +{ + void M(bool x, int a, int b) + { + var c = !x ? b : a; + var c2 = !x ? b : a; + } + + void M2(bool x, int a, int b) + { + var c = !x ? b : a; + var c2 = !x ? b : a; + } +} + +class C2 +{ + void M(bool x, int a, int b) + { + var c = x ? a : b; + var c2 = x ? a : b; + } +} + +partial class C +{ + void M3(bool x, int a, int b) + { + var c = !x ? b : a; + var c2 = !x ? b : a; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + public async Task InvertConditional_FixAllInContainingType_AcrossFiles() + { + await TestInRegularAndScriptAsync( +@" + + + +partial class Program1 +{ + void M1(bool x, int a, int b) + { + var c = {|FixAllInContainingType:|}x ? a : b; + } + + void M2(bool x, int a, int b) + { + var c = x ? a : b; + } +} + + +partial class Program1 +{ + void M3(bool x, int a, int b) + { + var c = x ? a : b; + } +} + +class Program2 +{ + void M2(bool x, int a, int b) + { + var c = x ? a : b; + } +} + + + + +class Program3 +{ + void M3(bool x, int a, int b) + { + var c = x ? a : b; + } +} + + +", +@" + + +partial class Program1 +{ + void M1(bool x, int a, int b) + { + var c = !x ? b : a; + } + + void M2(bool x, int a, int b) + { + var c = !x ? b : a; + } +} + + +partial class Program1 +{ + void M3(bool x, int a, int b) + { + var c = !x ? b : a; + } +} + +class Program2 +{ + void M2(bool x, int a, int b) + { + var c = x ? a : b; + } +} + + + + +class Program3 +{ + void M3(bool x, int a, int b) + { + var c = x ? a : b; + } +} + + +"); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs index e66959e700b9a..f1800e8c194ce 100644 --- a/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs +++ b/src/EditorFeatures/CSharpTest/MoveToNamespace/MoveToNamespaceTests.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ChangeNamespace; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics; @@ -1176,7 +1177,7 @@ void Method() { } var actions = await testState.MoveToNamespaceService.GetCodeActionsAsync( testState.InvocationDocument, testState.TestInvocationDocument.SelectedSpans.Single(), - CodeCleanupOptions.GetDefaultAsync, + CodeActionOptions.DefaultProvider, CancellationToken.None); Assert.Empty(actions); diff --git a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs index 44f331b0e60c4..3bce152b83464 100644 --- a/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/PdbSourceDocument/PdbSourceDocumentLoaderServiceTests.cs @@ -37,7 +37,7 @@ await RunTestAsync(async path => var sourceFilePath = Path.Combine(path, "SourceLink.cs"); File.Move(GetSourceFilePath(path), sourceFilePath); - var sourceLinkService = new Lazy(() => new TestSourceLinkService(sourceFilePath: sourceFilePath)); + var sourceLinkService = new Lazy(() => new TestSourceLinkService(sourceFilePath: sourceFilePath)); var service = new PdbSourceDocumentLoaderService(sourceLinkService, logger: null); using var hash = SHA256.Create(); @@ -71,7 +71,7 @@ await RunTestAsync(async path => var sourceFilePath = Path.Combine(path, "SourceLink.cs"); File.Move(GetSourceFilePath(path), sourceFilePath); - var sourceLinkService = new Lazy(() => new TestSourceLinkService(sourceFilePath: sourceFilePath)); + var sourceLinkService = new Lazy(() => new TestSourceLinkService(sourceFilePath: sourceFilePath)); var service = new PdbSourceDocumentLoaderService(sourceLinkService, logger: null); var sourceDocument = new SourceDocument("goo.cs", Text.SourceHashAlgorithm.None, default, null, SourceLinkUrl: null); diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index 3068af158087f..b3f5d30d790e6 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -8535,5 +8535,49 @@ static void Main(string[] args) await TestAsync(markup, MainDescription($"({FeaturesResources.parameter}) string[] args")); } + + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestParameterInMethodAttributeNameof() + { + var source = @" +class Program +{ + [My(nameof($$s))] + void M(string s) { } +} +"; + await TestWithOptionsAsync(Options.Regular.WithLanguageVersion(LanguageVersionFacts.CSharpNext), source, + MainDescription($"({FeaturesResources.parameter}) string s")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestParameterInMethodParameterAttributeNameof() + { + var source = @" +class Program +{ + void M([My(nameof($$s))] string s) { } +} +"; + await TestWithOptionsAsync(Options.Regular.WithLanguageVersion(LanguageVersionFacts.CSharpNext), source, + MainDescription($"({FeaturesResources.parameter}) string s")); + } + + [Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)] + public async Task TestParameterInLocalFunctionAttributeNameof() + { + var source = @" +class Program +{ + void M() + { + [My(nameof($$s))] + void local(string s) { } + } +} +"; + await TestWithOptionsAsync(Options.Regular.WithLanguageVersion(LanguageVersionFacts.CSharpNext), source, + MainDescription($"({FeaturesResources.parameter}) string s")); + } } } diff --git a/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs index 6d5763ad601b9..27d4061557951 100644 --- a/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs @@ -34,12 +34,12 @@ public static RawStringLiteralTestState CreateTestState(string markup) => new(GetWorkspaceXml(markup)); public static XElement GetWorkspaceXml(string markup) - => XElement.Parse(string.Format(@" + => XElement.Parse($@" - {0} + {markup} -", markup)); +"); internal void AssertCodeIs(string expectedCode) { diff --git a/src/EditorFeatures/CSharpTest/SimplifyThisOrMe/SimplifyThisOrMeTests.cs b/src/EditorFeatures/CSharpTest/SimplifyThisOrMe/SimplifyThisOrMeTests.cs index eee66adcfaf91..46e35e125546a 100644 --- a/src/EditorFeatures/CSharpTest/SimplifyThisOrMe/SimplifyThisOrMeTests.cs +++ b/src/EditorFeatures/CSharpTest/SimplifyThisOrMe/SimplifyThisOrMeTests.cs @@ -95,7 +95,7 @@ void M() } }", options: Option(CodeStyleOptions2.QualifyPropertyAccess, false, NotificationOption2.Warning), - diagnosticId: IDEDiagnosticIds.RemoveQualificationDiagnosticId, + diagnosticId: IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId, diagnosticSeverity: DiagnosticSeverity.Warning); } diff --git a/src/EditorFeatures/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs b/src/EditorFeatures/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs index d0613a9d41ad1..768ea78a39f75 100644 --- a/src/EditorFeatures/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs +++ b/src/EditorFeatures/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs @@ -123,6 +123,63 @@ class A }"); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)] + public async Task UseGlobalAlias00() + { + await TestInRegularAndScriptAsync( +@" +global using MyType = System.IO.File; + +namespace Root +{ + class A + { + [|System.IO.File|] c; + } +}", +@" +global using MyType = System.IO.File; + +namespace Root +{ + class A + { + MyType c; + } +}"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)] + public async Task UseGlobalAlias01() + { + await TestInRegularAndScriptAsync( +@" + + +global using MyType = System.IO.File; + + +namespace Root +{ + class A + { + [|System.IO.File|] c; + } +} + + +", +@" +namespace Root +{ + class A + { + MyType c; + } +} +"); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)] public async Task UseAlias00_FileScopedNamespace() { @@ -3465,7 +3522,7 @@ public static void Main() [WorkItem(568043, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/568043")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)] - public async Task DontSimplifyNamesWhenThereAreParseErrors() + public async Task DoNotSimplifyNamesWhenThereAreParseErrors() { var markup = @" @@ -3601,7 +3658,7 @@ class D [WorkItem(578686, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/578686")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)] - public async Task DontUseAlias1() + public async Task DoNotUseAlias1() { await TestMissingInRegularAndScriptAsync( @"using System.Collections.Generic; @@ -3950,7 +4007,7 @@ static void Main(string[] args) [WorkItem(736377, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/736377")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)] - public async Task DontSimplifyTypeNameBrokenCode() + public async Task DoNotSimplifyTypeNameBrokenCode() { await TestMissingInRegularAndScriptAsync( @"using System; @@ -3970,7 +4027,7 @@ public static ISet GetAllFilesInSolution() [WorkItem(813385, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/813385")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)] - public async Task DontSimplifyAliases() + public async Task DoNotSimplifyAliases() { await TestMissingInRegularAndScriptAsync( @"using Goo = System.Int32; @@ -4008,7 +4065,7 @@ class OtherClass [WorkItem(878773, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/878773")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)] - public async Task DontSimplifyAttributeNameWithJustAttribute() + public async Task DoNotSimplifyAttributeNameWithJustAttribute() { await TestMissingInRegularAndScriptAsync( @"[[|Attribute|]] diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoMultiLineInterpolatedRawStringTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoMultiLineInterpolatedRawStringTests.cs new file mode 100644 index 0000000000000..273050270222d --- /dev/null +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoMultiLineInterpolatedRawStringTests.cs @@ -0,0 +1,715 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.StringCopyPaste +{ + public class PasteUnknownSourceIntoMultiLineInterpolatedRawStringTests + : StringCopyPasteCommandHandlerUnknownSourceTests + { + [WpfFact] + public void TestNewLineIntoMultiLineRawString1() + { + TestPasteUnknownSource( + pasteText: "\n", +@"var x = $"""""" + [||] + """"""", +"var x = $\"\"\"\r\n \n [||]\r\n \"\"\"", + afterUndo: +"var x = $\"\"\"\r\n \n[||]\r\n \"\"\""); + } + + [WpfFact] + public void TestNewLineIntoMultiLineRawString2() + { + TestPasteUnknownSource( + pasteText: "\r\n", +@"var x = $"""""" + [||] + """"""", +"var x = $\"\"\"\r\n \r\n [||]\r\n \"\"\"", + afterUndo: +"var x = $\"\"\"\r\n \r\n[||]\r\n \"\"\""); + } + + [WpfFact] + public void TestSpacesIntoMultiLineRawString1() + { + TestPasteUnknownSource( + pasteText: " ", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + [||] + """"""", + afterUndo: +@"var x = $"""""" + [||] + """""""); + } + + [WpfFact] + public void TestSpacesIntoMultiLineRawString2() + { + TestPasteUnknownSource( + pasteText: " \r\n", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + + [||] + """"""", + afterUndo: +@"var x = $"""""" + +[||] + """""""); + } + + [WpfFact] + public void TestSingleQuoteIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "'", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + '[||] + """"""", + afterUndo: +@"var x = $"""""" + [||] + """""""); + } + + [WpfFact] + public void TestDoubleQuoteIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "\"", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + ""[||] + """"""", + afterUndo: +@"var x = $"""""" + [||] + """""""); + } + + [WpfFact] + public void TestTripleQuoteIntoMultiLineRawString1() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""""" + """"""[||] + """"""""", + afterUndo: +@"var x = $"""""" + """"""[||] + """""""); + } + + [WpfFact] + public void TestTripleQuoteIntoMultiLineRawString2() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $"""""" + [||] + """""" ", +@"var x = $"""""""" + """"""[||] + """""""" ", + afterUndo: +@"var x = $"""""" + """"""[||] + """""" "); + } + + [WpfFact] + public void TestTripleQuoteIntoMultiLineRawString3() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $"""""" + ""[||] + """""" ", +@"var x = $"""""""""" + """"""""[||] + """""""""" ", + afterUndo: +@"var x = $"""""" + """"""""[||] + """""" "); + } + + [WpfFact] + public void TestTripleQuoteIntoMultiLineRawString4() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $"""""" + ""[||]"" + """""" ", +@"var x = $"""""""""""" + """"""""[||]"" + """""""""""" ", + afterUndo: +@"var x = $"""""" + """"""""[||]"" + """""" "); + } + + [WpfFact] + public void TestTripleQuoteIntoMultiLineRawString5() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $"""""" + [||]"" + """""" ", +@"var x = $"""""""""" + """"""[||]"" + """""""""" ", + afterUndo: +@"var x = $"""""" + """"""[||]"" + """""" "); + } + + [WpfFact] + public void TestQuadrupleQuoteIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "\"\"\"\"", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""""""" + """"""""[||] + """"""""""", + afterUndo: +@"var x = $"""""" + """"""""[||] + """""""); + } + + [WpfFact] + public void TestOpenBraceIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "{", +@"var x = $"""""" + [||] + """"""", +@"var x = $$"""""" + {[||] + """"""", + afterUndo: +@"var x = $"""""" + {[||] + """""""); + } + + [WpfFact] + public void TestTripleOpenBraceIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "{{{", +@"var x = $"""""" + [||] + """"""", +@"var x = $$$$"""""" + {{{[||] + """"""", + afterUndo: +@"var x = $"""""" + {{{[||] + """""""); + } + + [WpfFact] + public void TestTripleOpenBraceIntoMultiLineRawString2() + { + TestPasteUnknownSource( + pasteText: "{{{", +@"var x = $$"""""" + [||] + """"""", +@"var x = $$$$"""""" + {{{[||] + """"""", + afterUndo: +@"var x = $$"""""" + {{{[||] + """""""); + } + + [WpfFact] + public void TestOpenBraceIntoMultiLineRawString2() + { + TestPasteUnknownSource( + pasteText: "{", +@"var x = $$$"""""" + {[||]{ + """""" ", +@"var x = $$$$"""""" + {{[||]{ + """""" ", + afterUndo: +@"var x = $$$"""""" + {{[||]{ + """""" "); + } + + [WpfFact] + public void TestInterpolationIntoMultiLineRawString3() + { + TestPasteUnknownSource( + pasteText: "{0}", +@"var x = $"""""" + [||] + """""" ", +@"var x = $"""""" + {0}[||] + """""" ", + afterUndo: +@"var x = $"""""" + [||] + """""" "); + } + + [WpfFact] + public void TestOpenCloseIntoMultiLineRawString4() + { + TestPasteUnknownSource( + pasteText: "{}", +@"var x = $"""""" + [||] + """""" ", +@"var x = $$"""""" + {}[||] + """""" ", + afterUndo: +@"var x = $"""""" + {}[||] + """""" "); + } + + [WpfFact] + public void TestOpenCloseBraceIntoMultiLineRawString5() + { + TestPasteUnknownSource( + pasteText: "{{}", +@"var x = $$"""""" + [||] + """""" ", +@"var x = $$$"""""" + {{}[||] + """""" ", + afterUndo: +@"var x = $$"""""" + {{}[||] + """""" "); + } + + [WpfFact] + public void TestOpenCloseBraceIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "{}}", +@"var x = $"""""" + [||] + """"""", +@"var x = $$$"""""" + {}}[||] + """"""", + afterUndo: +@"var x = $"""""" + {}}[||] + """""""); + } + + [WpfFact] + public void TestOpenCloseBraceIntoMultiLineRawString2() + { + TestPasteUnknownSource( + pasteText: "{{}}", +@"var x = $"""""" + [||] + """"""", +@"var x = $$$"""""" + {{}}[||] + """"""", + afterUndo: +@"var x = $"""""" + {{}}[||] + """""""); + } + + [WpfFact] + public void TestTripleQuoteTripleOpenBraceIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "\"\"\"{{{", +@"var x = $"""""" + [||] + """"""", +@"var x = $$$$"""""""" + """"""{{{[||] + """"""""", + afterUndo: +@"var x = $"""""" + """"""{{{[||] + """""""); + } + + [WpfFact] + public void TestComplexStringIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: " \"\" ", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + """" [||] + """"""", + afterUndo: +@"var x = $"""""" + """" [||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "abc", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + abc[||] + """"""", + afterUndo: +@"var x = $"""""" + [||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine1() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + abc + def[||] + """"""", + afterUndo: +@"var x = $"""""" + abc +def[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine2() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $"""""" +[||] + """"""", +@"var x = $"""""" + abc + def[||] + """"""", + afterUndo: +@"var x = $"""""" +abc +def[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine3() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $""""""[||] + + """"""", +@"var x = $"""""" + abc + def[||] + + """"""", + afterUndo: +@"var x = $""""""abc +def[||] + + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine4() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $"""""" + goo[||] + """"""", +@"var x = $"""""" + gooabc + def[||] + """"""", + afterUndo: +@"var x = $"""""" + gooabc +def[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine5() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $"""""" + goo[||]bar + """"""", +@"var x = $"""""" + gooabc + def[||]bar + """"""", + afterUndo: +@"var x = $"""""" + gooabc +def[||]bar + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine6() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef\r\n", +@"var x = $"""""" + goo[||]bar + """"""", +@"var x = $"""""" + gooabc + def + [||]bar + """"""", + afterUndo: +@"var x = $"""""" + gooabc +def +[||]bar + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine7() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\nghi", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = $"""""" + abc + def +ghi[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine8() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\n ghi", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = $"""""" + [||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine9() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = $"""""" + abc + def + ghi[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine10() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = $"""""" + abc + def + ghi[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine11() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $""""""[||]{|Selection: + + |}""""""", +@"var x = $"""""" + abc + def + [||]""""""", + afterUndo: +@"var x = $""""""abc +def[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine12() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef\r\n", +@"var x = $""""""[||]{|Selection: + + |}""""""", +@"var x = $"""""" + abc + def + + [||]""""""", + afterUndo: +@"var x = $""""""abc +def +[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine13() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $""""""[||]{|Selection: + + |} """"""", +@"var x = $"""""" + abc + def + [||] """"""", + afterUndo: +@"var x = $""""""abc +def[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringHeader1() + { + TestPasteUnknownSource( + pasteText: "bar", +@"var x = $""""""[||] + goo + """"""", +@"var x = $"""""" + bar[||] + goo + """"""", + afterUndo: +@"var x = $""""""bar[||] + goo + """""""); + } + + [WpfFact] + public void TestQuotesIntoHeader1() + { + TestPasteUnknownSource( + pasteText: "\"\"", +@"var x = $""""""[||]{|Selection: + + |}""""""", +@"var x = $"""""" + """" + [||]""""""", + afterUndo: +@"var x = $""""""""""[||]"""""""); + } + + [WpfFact] + public void TestQuotesIntoHeader2() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $""""""[||]{|Selection: + + |}""""""", +@"var x = $"""""""" + """""" + ""[||]""""""", + afterUndo: +@"var x = $""""""""""""[||]"""""""); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoMultiLineRawStringTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoMultiLineRawStringTests.cs new file mode 100644 index 0000000000000..1173ff5d8ffc3 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoMultiLineRawStringTests.cs @@ -0,0 +1,545 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.StringCopyPaste +{ + public class PasteUnknownSourceIntoMultiLineRawStringTests + : StringCopyPasteCommandHandlerUnknownSourceTests + { + [WpfFact] + public void TestNewLineIntoMultiLineRawString1() + { + TestPasteUnknownSource( + pasteText: "\n", +@"var x = """""" + [||] + """"""", +"var x = \"\"\"\r\n \n [||]\r\n \"\"\"", + afterUndo: +"var x = \"\"\"\r\n \n[||]\r\n \"\"\""); + } + + [WpfFact] + public void TestNewLineIntoMultiLineRawString2() + { + TestPasteUnknownSource( + pasteText: "\r\n", +@"var x = """""" + [||] + """"""", +"var x = \"\"\"\r\n \r\n [||]\r\n \"\"\"", + afterUndo: +"var x = \"\"\"\r\n \r\n[||]\r\n \"\"\""); + } + + [WpfFact] + public void TestSpacesIntoMultiLineRawString1() + { + TestPasteUnknownSource( + pasteText: " ", +@"var x = """""" + [||] + """"""", +@"var x = """""" + [||] + """"""", + afterUndo: +@"var x = """""" + [||] + """""""); + } + + [WpfFact] + public void TestSpacesIntoMultiLineRawString2() + { + TestPasteUnknownSource( + pasteText: " \r\n", +@"var x = """""" + [||] + """"""", +@"var x = """""" + + [||] + """"""", + afterUndo: +@"var x = """""" + +[||] + """""""); + } + + [WpfFact] + public void TestSingleQuoteIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "'", +@"var x = """""" + [||] + """"""", +@"var x = """""" + '[||] + """"""", + afterUndo: +@"var x = """""" + [||] + """""""); + } + + [WpfFact] + public void TestDoubleQuoteIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "\"", +@"var x = """""" + [||] + """"""", +@"var x = """""" + ""[||] + """"""", + afterUndo: +@"var x = """""" + [||] + """""""); + } + + [WpfFact] + public void TestTripleQuoteIntoMultiLineRawString1() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """""" + [||] + """"""", +@"var x = """""""" + """"""[||] + """"""""", + afterUndo: +@"var x = """""" + """"""[||] + """""""); + } + + [WpfFact] + public void TestTripleQuoteIntoMultiLineRawString2() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """""" + [||] + """""" ", +@"var x = """""""" + """"""[||] + """""""" ", + afterUndo: +@"var x = """""" + """"""[||] + """""" "); + } + + [WpfFact] + public void TestTripleQuoteIntoMultiLineRawString3() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """""" + ""[||] + """""" ", +@"var x = """""""""" + """"""""[||] + """""""""" ", + afterUndo: +@"var x = """""" + """"""""[||] + """""" "); + } + + [WpfFact] + public void TestTripleQuoteIntoMultiLineRawString4() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """""" + ""[||]"" + """""" ", +@"var x = """""""""""" + """"""""[||]"" + """""""""""" ", + afterUndo: +@"var x = """""" + """"""""[||]"" + """""" "); + } + + [WpfFact] + public void TestTripleQuoteIntoMultiLineRawString5() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """""" + [||]"" + """""" ", +@"var x = """""""""" + """"""[||]"" + """""""""" ", + afterUndo: +@"var x = """""" + """"""[||]"" + """""" "); + } + + [WpfFact] + public void TestQuadrupleQuoteIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "\"\"\"\"", +@"var x = """""" + [||] + """"""", +@"var x = """""""""" + """"""""[||] + """"""""""", + afterUndo: +@"var x = """""" + """"""""[||] + """""""); + } + + [WpfFact] + public void TestComplexStringIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: " \"\" ", +@"var x = """""" + [||] + """"""", +@"var x = """""" + """" [||] + """"""", + afterUndo: +@"var x = """""" + """" [||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawString() + { + TestPasteUnknownSource( + pasteText: "abc", +@"var x = """""" + [||] + """"""", +@"var x = """""" + abc[||] + """"""", + afterUndo: +@"var x = """""" + [||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine1() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """""" + [||] + """"""", +@"var x = """""" + abc + def[||] + """"""", + afterUndo: +@"var x = """""" + abc +def[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine2() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """""" +[||] + """"""", +@"var x = """""" + abc + def[||] + """"""", + afterUndo: +@"var x = """""" +abc +def[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine3() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """"""[||] + + """"""", +@"var x = """""" + abc + def[||] + + """"""", + afterUndo: +@"var x = """"""abc +def[||] + + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine4() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """""" + goo[||] + """"""", +@"var x = """""" + gooabc + def[||] + """"""", + afterUndo: +@"var x = """""" + gooabc +def[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine5() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """""" + goo[||]bar + """"""", +@"var x = """""" + gooabc + def[||]bar + """"""", + afterUndo: +@"var x = """""" + gooabc +def[||]bar + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine6() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef\r\n", +@"var x = """""" + goo[||]bar + """"""", +@"var x = """""" + gooabc + def + [||]bar + """"""", + afterUndo: +@"var x = """""" + gooabc +def +[||]bar + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine7() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\nghi", +@"var x = """""" + [||] + """"""", +@"var x = """""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = """""" + abc + def +ghi[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine8() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\n ghi", +@"var x = """""" + [||] + """"""", +@"var x = """""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = """""" + [||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine9() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = """""" + [||] + """"""", +@"var x = """""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = """""" + abc + def + ghi[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine10() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = """""" + [||] + """"""", +@"var x = """""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = """""" + abc + def + ghi[||] + """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine11() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """"""[||]{|Selection: + + |}""""""", +@"var x = """""" + abc + def + [||]""""""", + afterUndo: +@"var x = """"""abc +def[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine12() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef\r\n", +@"var x = """"""[||]{|Selection: + + |}""""""", +@"var x = """""" + abc + def + + [||]""""""", + afterUndo: +@"var x = """"""abc +def +[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringMultiLine13() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """"""[||]{|Selection: + + |} """"""", +@"var x = """""" + abc + def + [||] """"""", + afterUndo: +@"var x = """"""abc +def[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoMultiLineRawStringHeader1() + { + TestPasteUnknownSource( + pasteText: "bar", +@"var x = """"""[||] + goo + """"""", +@"var x = """""" + bar[||] + goo + """"""", + afterUndo: +@"var x = """"""bar[||] + goo + """""""); + } + + [WpfFact] + public void TestQuotesIntoHeader1() + { + TestPasteUnknownSource( + pasteText: "\"\"", +@"var x = """"""[||]{|Selection: + + |}""""""", +@"var x = """""" + """" + [||]""""""", + afterUndo: +@"var x = """"""""""[||]"""""""); + } + + [WpfFact] + public void TestQuotesIntoHeader2() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """"""[||]{|Selection: + + |}""""""", +@"var x = """""""" + """""" + ""[||]""""""", + afterUndo: +@"var x = """"""""""""[||]"""""""); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoNormalInterpolatedStringTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoNormalInterpolatedStringTests.cs new file mode 100644 index 0000000000000..f230eea528fde --- /dev/null +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoNormalInterpolatedStringTests.cs @@ -0,0 +1,475 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.StringCopyPaste +{ + public class PasteUnknownSourceIntoNormalInterpolatedStringTests + : StringCopyPasteCommandHandlerUnknownSourceTests + { + #region Paste from external source into normal interpolated string no hole + + [WpfFact] + public void TestNewLineIntoNormalInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "\n", + @"var x = $""[||]""", + @"var x = $""\n[||]""", + afterUndo: "var x = $\"\n[||]\""); + } + + [WpfFact] + public void TestNewLineIntoNormalInterpolatedString2() + { + TestPasteUnknownSource( + pasteText: "\r\n", + @"var x = $""[||]""", + @"var x = $""\r\n[||]""", + afterUndo: "var x = $\"\r\n[||]\""); + } + + [WpfFact] + public void TestTabIntoNormalInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "\t", + @"var x = $""[||]""", + @"var x = $""\t[||]""", + afterUndo: "var x = $\"\t[||]\""); + } + + [WpfFact] + public void TestSingleQuoteIntoNormalInterpolatedString() + { + TestPasteUnknownSource( + pasteText: "'", + @"var x = $""[||]""", + @"var x = $""'[||]""", + afterUndo: "var x = $\"[||]\""); + } + + [WpfFact] + public void TestDoubleQuoteIntoNormalInterpolatedString() + { + TestPasteUnknownSource( + pasteText: "\"", + @"var x = $""[||]""", + @"var x = $""\""[||]""", + afterUndo: "var x = $\"\"[||]\""); + } + + [WpfFact] + public void TestComplexStringIntoNormalInterpolatedString() + { + TestPasteUnknownSource( + pasteText: "\t\"\"\t", + @"var x = $""[||]""", + @"var x = $""\t\""\""\t[||]""", + afterUndo: "var x = $\"\t\"\"\t[||]\""); + } + + [WpfFact] + public void TestNormalTextIntoNormalInterpolatedString() + { + TestPasteUnknownSource( + pasteText: "abc", + @"var x = $""[||]""", + @"var x = $""abc[||]""", + afterUndo: @"var x = $""[||]"""); + } + + [WpfFact] + public void TestOpenCurlyIntoNormalInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "{", + @"var x = $""[||]""", + @"var x = $""{{[||]""", + afterUndo: "var x = $\"{[||]\""); + } + + [WpfFact] + public void TestTwoOpenCurliesIntoNormalInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "{{", + @"var x = $""[||]""", + @"var x = $""{{[||]""", + afterUndo: "var x = $\"[||]\""); + } + + [WpfFact] + public void TestTwoOpenCurliesAndContentIntoNormalInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "{{0", + @"var x = $""[||]""", + @"var x = $""{{0[||]""", + afterUndo: "var x = $\"[||]\""); + } + + [WpfFact] + public void TestCloseCurlyIntoNormalInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "}", + @"var x = $""[||]""", + @"var x = $""}}[||]""", + afterUndo: "var x = $\"}[||]\""); + } + + [WpfFact] + public void TestTwoCloseCurliesIntoNormalInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "}}", + @"var x = $""[||]""", + @"var x = $""}}[||]""", + afterUndo: "var x = $\"[||]\""); + } + + [WpfFact] + public void TestTwoCloseCurliesAndContentIntoNormalInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "}}0", + @"var x = $""[||]""", + @"var x = $""}}0[||]""", + afterUndo: "var x = $\"[||]\""); + } + + [WpfFact] + public void TestCurlyWithContentIntoNormalInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "x{0}y", + @"var x = $""[||]""", + @"var x = $""x{0}y[||]""", + afterUndo: "var x = $\"[||]\""); + } + + [WpfFact] + public void TestCurliesWithContentIntoNormalInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "x{{0}}y", + @"var x = $""[||]""", + @"var x = $""x{{0}}y[||]""", + afterUndo: "var x = $\"[||]\""); + } + + #endregion + + #region Paste from external source into normal interpolated string before hole + + [WpfFact] + public void TestNewLineIntoNormalInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "\n", + @"var x = $""[||]{0}""", + @"var x = $""\n[||]{0}""", + afterUndo: "var x = $\"\n[||]{0}\""); + } + + [WpfFact] + public void TestNewLineIntoNormalInterpolatedStringBeforeHole2() + { + TestPasteUnknownSource( + pasteText: "\r\n", + @"var x = $""[||]{0}""", + @"var x = $""\r\n[||]{0}""", + afterUndo: "var x = $\"\r\n[||]{0}\""); + } + + [WpfFact] + public void TestTabIntoNormalInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "\t", + @"var x = $""[||]{0}""", + @"var x = $""\t[||]{0}""", + afterUndo: "var x = $\"\t[||]{0}\""); + } + + [WpfFact] + public void TestSingleQuoteIntoNormalInterpolatedStringBeforeHole() + { + TestPasteUnknownSource( + pasteText: "'", + @"var x = $""[||]{0}""", + @"var x = $""'[||]{0}""", + afterUndo: "var x = $\"[||]{0}\""); + } + + [WpfFact] + public void TestDoubleQuoteIntoNormalInterpolatedStringBeforeHole() + { + TestPasteUnknownSource( + pasteText: "\"", + @"var x = $""[||]{0}""", + @"var x = $""\""[||]{0}""", + afterUndo: "var x = $\"\"[||]{0}\""); + } + + [WpfFact] + public void TestComplexStringIntoNormalInterpolatedStringBeforeHole() + { + TestPasteUnknownSource( + pasteText: "\t\"\"\t", + @"var x = $""[||]{0}""", + @"var x = $""\t\""\""\t[||]{0}""", + afterUndo: "var x = $\"\t\"\"\t[||]{0}\""); + } + + [WpfFact] + public void TestNormalTextIntoNormalInterpolatedStringBeforeHole() + { + TestPasteUnknownSource( + pasteText: "abc", + @"var x = $""[||]{0}""", + @"var x = $""abc[||]{0}""", + afterUndo: @"var x = $""[||]{0}"""); + } + + [WpfFact] + public void TestOpenCurlyIntoNormalInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "{", + @"var x = $""[||]{0}""", + @"var x = $""{{[||]{0}""", + afterUndo: "var x = $\"{[||]{0}\""); + } + + [WpfFact] + public void TestTwoOpenCurliesIntoNormalInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "{{", + @"var x = $""[||]{0}""", + @"var x = $""{{[||]{0}""", + afterUndo: "var x = $\"[||]{0}\""); + } + + [WpfFact] + public void TestTwoOpenCurliesAndContentIntoNormalInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "{{0", + @"var x = $""[||]{0}""", + @"var x = $""{{0[||]{0}""", + afterUndo: "var x = $\"[||]{0}\""); + } + + [WpfFact] + public void TestCloseCurlyIntoNormalInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "}", + @"var x = $""[||]{0}""", + @"var x = $""}}[||]{0}""", + afterUndo: "var x = $\"}[||]{0}\""); + } + + [WpfFact] + public void TestTwoCloseCurliesIntoNormalInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "}}", + @"var x = $""[||]{0}""", + @"var x = $""}}[||]{0}""", + afterUndo: "var x = $\"[||]{0}\""); + } + + [WpfFact] + public void TestTwoCloseCurliesAndContentIntoNormalInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "}}0", + @"var x = $""[||]{0}""", + @"var x = $""}}0[||]{0}""", + afterUndo: "var x = $\"[||]{0}\""); + } + + [WpfFact] + public void TestCurlyWithContentIntoNormalInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "x{0}y", + @"var x = $""[||]{0}""", + @"var x = $""x{0}y[||]{0}""", + afterUndo: "var x = $\"[||]{0}\""); + } + + [WpfFact] + public void TestCurliesWithContentIntoNormalInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "x{{0}}y", + @"var x = $""[||]{0}""", + @"var x = $""x{{0}}y[||]{0}""", + afterUndo: "var x = $\"[||]{0}\""); + } + + #endregion + + #region Paste from external source into normal interpolated string after hole + + [WpfFact] + public void TestNewLineIntoNormalInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "\n", + @"var x = $""{0}[||]""", + @"var x = $""{0}\n[||]""", + afterUndo: "var x = $\"{0}\n[||]\""); + } + + [WpfFact] + public void TestNewLineIntoNormalInterpolatedStringAfterHole2() + { + TestPasteUnknownSource( + pasteText: "\r\n", + @"var x = $""{0}[||]""", + @"var x = $""{0}\r\n[||]""", + afterUndo: "var x = $\"{0}\r\n[||]\""); + } + + [WpfFact] + public void TestTabIntoNormalInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "\t", + @"var x = $""{0}[||]""", + @"var x = $""{0}\t[||]""", + afterUndo: "var x = $\"{0}\t[||]\""); + } + + [WpfFact] + public void TestSingleQuoteIntoNormalInterpolatedStringAfterHole() + { + TestPasteUnknownSource( + pasteText: "'", + @"var x = $""{0}[||]""", + @"var x = $""{0}'[||]""", + afterUndo: "var x = $\"{0}[||]\""); + } + + [WpfFact] + public void TestDoubleQuoteIntoNormalInterpolatedStringAfterHole() + { + TestPasteUnknownSource( + pasteText: "\"", + @"var x = $""{0}[||]""", + @"var x = $""{0}\""[||]""", + afterUndo: "var x = $\"{0}\"[||]\""); + } + + [WpfFact] + public void TestComplexStringIntoNormalInterpolatedStringAfterHole() + { + TestPasteUnknownSource( + pasteText: "\t\"\"\t", + @"var x = $""{0}[||]""", + @"var x = $""{0}\t\""\""\t[||]""", + afterUndo: "var x = $\"{0}\t\"\"\t[||]\""); + } + + [WpfFact] + public void TestNormalTextIntoNormalInterpolatedStringAfterHole() + { + TestPasteUnknownSource( + pasteText: "abc", + @"var x = $""{0}[||]""", + @"var x = $""{0}abc[||]""", + afterUndo: @"var x = $""{0}[||]"""); + } + + [WpfFact] + public void TestOpenCurlyIntoNormalInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "{", + @"var x = $""{0}[||]""", + @"var x = $""{0}{{[||]""", + afterUndo: "var x = $\"{0}{[||]\""); + } + + [WpfFact] + public void TestTwoOpenCurliesIntoNormalInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "{{", + @"var x = $""{0}[||]""", + @"var x = $""{0}{{[||]""", + afterUndo: "var x = $\"{0}[||]\""); + } + + [WpfFact] + public void TestTwoOpenCurliesAndContentIntoNormalInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "{{0", + @"var x = $""{0}[||]""", + @"var x = $""{0}{{0[||]""", + afterUndo: "var x = $\"{0}[||]\""); + } + + [WpfFact] + public void TestCloseCurlyIntoNormalInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "}", + @"var x = $""{0}[||]""", + @"var x = $""{0}}}[||]""", + afterUndo: "var x = $\"{0}}[||]\""); + } + + [WpfFact] + public void TestTwoCloseCurliesIntoNormalInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "}}", + @"var x = $""{0}[||]""", + @"var x = $""{0}}}[||]""", + afterUndo: "var x = $\"{0}[||]\""); + } + + [WpfFact] + public void TestTwoCloseCurliesAndContentIntoNormalInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "}}0", + @"var x = $""{0}[||]""", + @"var x = $""{0}}}0[||]""", + afterUndo: "var x = $\"{0}[||]\""); + } + + [WpfFact] + public void TestCurlyWithContentIntoNormalInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "x{0}y", + @"var x = $""{0}[||]""", + @"var x = $""{0}x{0}y[||]""", + afterUndo: "var x = $\"{0}[||]\""); + } + + [WpfFact] + public void TestCurliesWithContentIntoNormalInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "x{{0}}y", + @"var x = $""{0}[||]""", + @"var x = $""{0}x{{0}}y[||]""", + afterUndo: "var x = $\"{0}[||]\""); + } + + #endregion + } +} diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoNormalStringTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoNormalStringTests.cs new file mode 100644 index 0000000000000..748403b963629 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoNormalStringTests.cs @@ -0,0 +1,93 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.StringCopyPaste +{ + public class PasteUnknownSourceIntoNormalStringTests + : StringCopyPasteCommandHandlerUnknownSourceTests + { + [WpfFact] + public void TestNewLineIntoNormalString1() + { + TestPasteUnknownSource( + pasteText: "\n", + @"var x = ""[||]""", + @"var x = ""\n[||]""", + afterUndo: "var x = \"\n[||]\""); + } + + [WpfFact] + public void TestNewLineIntoNormalString2() + { + TestPasteUnknownSource( + pasteText: "\r\n", + @"var x = ""[||]""", + @"var x = ""\r\n[||]""", + afterUndo: "var x = \"\r\n[||]\""); + } + + [WpfFact] + public void TestTabIntoNormalString1() + { + TestPasteUnknownSource( + pasteText: "\t", + @"var x = ""[||]""", + @"var x = ""\t[||]""", + afterUndo: "var x = \"\t[||]\""); + } + + [WpfFact] + public void TestBackslashTIntoNormalString1() + { + TestPasteUnknownSource( + pasteText: @"\t", + @"var x = ""[||]""", + @"var x = ""\t[||]""", + afterUndo: @"var x = ""[||]"""); + } + + [WpfFact] + public void TestSingleQuoteIntoNormalString() + { + TestPasteUnknownSource( + pasteText: "'", + @"var x = ""[||]""", + @"var x = ""'[||]""", + afterUndo: "var x = \"[||]\""); + } + + [WpfFact] + public void TestDoubleQuoteIntoNormalString() + { + TestPasteUnknownSource( + pasteText: "\"", + @"var x = ""[||]""", + @"var x = ""\""[||]""", + afterUndo: "var x = \"\"[||]\""); + } + + [WpfFact] + public void TestComplexStringIntoNormalString() + { + TestPasteUnknownSource( + pasteText: "\t\"\"\t", + @"var x = ""[||]""", + @"var x = ""\t\""\""\t[||]""", + afterUndo: "var x = \"\t\"\"\t[||]\""); + } + + [WpfFact] + public void TestNormalTextIntoNormalString() + { + TestPasteUnknownSource( + pasteText: "abc", + @"var x = ""[||]""", + @"var x = ""abc[||]""", + afterUndo: @"var x = ""[||]"""); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoSingleLineInterpolatedRawStringTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoSingleLineInterpolatedRawStringTests.cs new file mode 100644 index 0000000000000..99cb1894d2d85 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoSingleLineInterpolatedRawStringTests.cs @@ -0,0 +1,794 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.StringCopyPaste +{ + public class PasteUnknownSourceIntoSingleLineInterpolatedRawStringTests + : StringCopyPasteCommandHandlerUnknownSourceTests + { + [WpfFact] + public void TestNewLineIntoSingleLineRawString1_A() + { + TestPasteUnknownSource( + pasteText: "\n", +@"var x = $""""""[||] """"""", +"var x = $\"\"\"\r\n \n [||] \r\n \"\"\"", + afterUndo: +"var x = $\"\"\"\n[||] \"\"\""); + } + + [WpfFact] + public void TestNewLineIntoSingleLineRawString1_B() + { + TestPasteUnknownSource( + pasteText: "\n", +@"var x = $"""""" [||]""""""", +"var x = $\"\"\"\r\n \n \r\n [||]\"\"\"", + afterUndo: +"var x = $\"\"\" \n[||]\"\"\""); + } + + [WpfFact] + public void TestNewLineIntoSingleLineRawString2_A() + { + TestPasteUnknownSource( + pasteText: "\r\n", +@"var x = $""""""[||] """"""", +"var x = $\"\"\"\r\n \r\n [||] \r\n \"\"\"", + afterUndo: +"var x = $\"\"\"\r\n[||] \"\"\""); + } + + [WpfFact] + public void TestNewLineIntoSingleLineRawString2_B() + { + TestPasteUnknownSource( + pasteText: "\r\n", +@"var x = $"""""" [||]""""""", +"var x = $\"\"\"\r\n \r\n \r\n [||]\"\"\"", + afterUndo: +"var x = $\"\"\" \r\n[||]\"\"\""); + } + + [WpfFact] + public void TestSpacesIntoSingleLineRawString1_A() + { + TestPasteUnknownSource( + pasteText: " ", +@"var x = $""""""[||] """"""", +@"var x = $"""""" [||] """"""", + afterUndo: +@"var x = $""""""[||] """""""); + } + + [WpfFact] + public void TestSpacesIntoSingleLineRawString1_B() + { + TestPasteUnknownSource( + pasteText: " ", +@"var x = $"""""" [||]""""""", +@"var x = $"""""" [||]""""""", + afterUndo: +@"var x = $"""""" [||]"""""""); + } + + [WpfFact] + public void TestSpacesIntoSingleLineRawString2() + { + TestPasteUnknownSource( + pasteText: " \r\n", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""" + + [||] + """"""", + afterUndo: +@"var x = $"""""" + +[||] + """""""); + } + + [WpfFact] + public void TestSingleQuoteIntoSingleLineRawString_A() + { + TestPasteUnknownSource( + pasteText: "'", +@"var x = $""""""[||] """"""", +@"var x = $""""""'[||] """"""", + afterUndo: +@"var x = $""""""[||] """""""); + } + + [WpfFact] + public void TestSingleQuoteIntoSingleLineRawString_B() + { + TestPasteUnknownSource( + pasteText: "'", +@"var x = $"""""" [||]""""""", +@"var x = $"""""" '[||]""""""", + afterUndo: +@"var x = $"""""" [||]"""""""); + } + + [WpfFact] + public void TestDoubleQuoteIntoSingleLineRawString_A() + { + TestPasteUnknownSource( + pasteText: "\"", +@"var x = $""""""[||] """"""", +@"var x = $"""""" + ""[||] + """"""", + afterUndo: +@"var x = $""""""""[||] """""""); + } + + [WpfFact] + public void TestDoubleQuoteIntoSingleLineRawString_B() + { + TestPasteUnknownSource( + pasteText: "\"", +@"var x = $"""""" [||]""""""", +@"var x = $"""""" + "" + [||]""""""", + afterUndo: +@"var x = $"""""" ""[||]"""""""); + } + + [WpfFact] + public void TestTripleQuoteIntoSingleLineRawString1_A() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $""""""[||] """"""", +@"var x = $"""""""" + """"""[||] + """"""""", + afterUndo: +@"var x = $""""""""""""[||] """""""); + } + + [WpfFact] + public void TestTripleQuoteIntoSingleLineRawString1_B() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $"""""" [||]""""""", +@"var x = $"""""""" + """""" + ""[||]""""""", + afterUndo: +@"var x = $"""""" """"""[||]"""""""); + } + + [WpfFact] + public void TestTripleQuoteIntoSingleLineRawString3() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $"""""" ""[||] """"""", +@"var x = $"""""""""" """"""""[||] """"""""""", + afterUndo: +@"var x = $"""""" """"""""[||] """""""); + } + + [WpfFact] + public void TestTripleQuoteIntoSingleLineRawString4() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $"""""" ""[||]"" """"""", +@"var x = $"""""""""""" """"""""[||]"" """"""""""""", + afterUndo: +@"var x = $"""""" """"""""[||]"" """""""); + } + + [WpfFact] + public void TestTripleQuoteIntoSingleLineRawString5() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $"""""" [||]"" """"""", +@"var x = $"""""""""" """"""[||]"" """"""""""", + afterUndo: +@"var x = $"""""" """"""[||]"" """""""); + } + + [WpfFact] + public void TestQuadrupleQuoteIntoSingleLineRawString() + { + TestPasteUnknownSource( + pasteText: "\"\"\"\"", +@"var x = $"""""" + [||] + """"""", +@"var x = $"""""""""" + """"""""[||] + """"""""""", + afterUndo: +@"var x = $"""""" + """"""""[||] + """""""); + } + + [WpfFact] + public void TestOpenCurlyIntoSingleLineRawString_A() + { + TestPasteUnknownSource( + pasteText: "{", +@"var x = $""""""[||] """"""", +@"var x = $$""""""{[||] """"""", + afterUndo: +@"var x = $""""""{[||] """""""); + } + + [WpfFact] + public void TestOpenCurlyIntoSingleLineRawString_B() + { + TestPasteUnknownSource( + pasteText: "{", +@"var x = $"""""" [||]""""""", +@"var x = $$"""""" {[||]""""""", + afterUndo: +@"var x = $"""""" {[||]"""""""); + } + + [WpfFact] + public void TestOpenQuoteAndTripleOpenBraceIntoSingleLineRawString1() + { + TestPasteUnknownSource( + pasteText: "\"{{{", +@"var x = $""""""[||] """"""", +@"var x = $$$$"""""" + ""{{{[||] + """"""", + afterUndo: +@"var x = $""""""""{{{[||] """""""); + } + + [WpfFact] + public void TestTripleOpenQuoteAndTripleOpenBraceIntoSingleLineRawString1() + { + TestPasteUnknownSource( + pasteText: "\"\"\"{{{", +@"var x = $""""""[||] """"""", +@"var x = $$$$"""""""" + """"""{{{[||] + """"""""", + afterUndo: +@"var x = $""""""""""""{{{[||] """""""); + } + + [WpfFact] + public void TestTripleOpenQuoteAndTripleOpenBraceIntoSingleLineRawString2() + { + TestPasteUnknownSource( + pasteText: " \"\"\"{{{", +@"var x = $""""""[||] """"""", +@"var x = $$$$"""""""" """"""{{{[||] """"""""", + afterUndo: +@"var x = $"""""" """"""{{{[||] """""""); + } + + [WpfFact] + public void TestTripleOpenBraceIntoSingleLineRawString1_A() + { + TestPasteUnknownSource( + pasteText: "{{{", +@"var x = $""""""[||] """"""", +@"var x = $$$$""""""{{{[||] """"""", + afterUndo: +@"var x = $""""""{{{[||] """""""); + } + + [WpfFact] + public void TestTripleOpenBraceIntoSingleLineRawString1_B() + { + TestPasteUnknownSource( + pasteText: "{{{", +@"var x = $"""""" [||]""""""", +@"var x = $$$$"""""" {{{[||]""""""", + afterUndo: +@"var x = $"""""" {{{[||]"""""""); + } + + [WpfFact] + public void TestTripleOpenBraceIntoSingleLineRawString3() + { + TestPasteUnknownSource( + pasteText: "{{{", +@"var x = $"""""" ""[||] """"""", +@"var x = $$$$"""""" ""{{{[||] """"""", + afterUndo: +@"var x = $"""""" ""{{{[||] """""""); + } + + [WpfFact] + public void TestTripleOpenBraceIntoSingleLineRawString4() + { + TestPasteUnknownSource( + pasteText: "{{{", +@"var x = $"""""" ""[||]"" """"""", +@"var x = $$$$"""""" ""{{{[||]"" """"""", + afterUndo: +@"var x = $"""""" ""{{{[||]"" """""""); + } + + [WpfFact] + public void TestTripleOpenBraceIntoSingleLineRawString5() + { + TestPasteUnknownSource( + pasteText: "{{{", +@"var x = $"""""" [||]"" """"""", +@"var x = $$$$"""""" {{{[||]"" """"""", + afterUndo: +@"var x = $"""""" {{{[||]"" """""""); + } + + [WpfFact] + public void TestInterpolationIntoSingleLineRawString1() + { + TestPasteUnknownSource( + pasteText: "{0}", +@"var x = $"""""" [||] """"""", +@"var x = $"""""" {0}[||] """"""", + afterUndo: +@"var x = $"""""" [||] """""""); + } + + [WpfFact] + public void TestOpenCloseBraceIntoSingleLineRawString1() + { + TestPasteUnknownSource( + pasteText: "{}", +@"var x = $"""""" [||] """"""", +@"var x = $$"""""" {}[||] """"""", + afterUndo: +@"var x = $"""""" {}[||] """""""); + } + + [WpfFact] + public void TestOpenCloseBraceIntoSingleLineRawString2() + { + TestPasteUnknownSource( + pasteText: "{}", +@"var x = $$"""""" [||] """"""", +@"var x = $$"""""" {}[||] """"""", + afterUndo: +@"var x = $$"""""" [||] """""""); + } + + [WpfFact] + public void TestOpenCloseBraceIntoSingleLineRawString3() + { + TestPasteUnknownSource( + pasteText: "{{}", +@"var x = $$"""""" [||] """"""", +@"var x = $$$"""""" {{}[||] """"""", + afterUndo: +@"var x = $$"""""" {{}[||] """""""); + } + + [WpfFact] + public void TestOpenCloseBraceIntoSingleLineRawString4() + { + TestPasteUnknownSource( + pasteText: "{}}", +@"var x = $$"""""" [||] """"""", +@"var x = $$$"""""" {}}[||] """"""", + afterUndo: +@"var x = $$"""""" {}}[||] """""""); + } + + [WpfFact] + public void TestOpenCloseBraceIntoSingleLineRawString5() + { + TestPasteUnknownSource( + pasteText: "{{}}", +@"var x = $$"""""" [||] """"""", +@"var x = $$$"""""" {{}}[||] """"""", + afterUndo: +@"var x = $$"""""" {{}}[||] """""""); + } + + [WpfFact] + public void TestComplexStringIntoSingleLineRawString() + { + TestPasteUnknownSource( + pasteText: " \"\" ", +@"var x = $""""""[||] """"""", +@"var x = $"""""" """" [||] """"""", + afterUndo: +@"var x = $""""""[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawString_A() + { + TestPasteUnknownSource( + pasteText: "abc", +@"var x = $""""""[||] """"""", +@"var x = $""""""abc[||] """"""", + afterUndo: +@"var x = $""""""[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawString_B() + { + TestPasteUnknownSource( + pasteText: "abc", +@"var x = $"""""" [||]""""""", +@"var x = $"""""" abc[||]""""""", + afterUndo: +@"var x = $"""""" [||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine1_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $""""""[||] """"""", +@"var x = $"""""" + abc + def[||] + """"""", + afterUndo: +@"var x = $""""""abc +def[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine1_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $"""""" [||]""""""", +@"var x = $"""""" + abc + def + [||]""""""", + afterUndo: +@"var x = $"""""" abc +def[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine4() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $""""""goo[||]""""""", +@"var x = $"""""" + gooabc + def + [||]""""""", + afterUndo: +@"var x = $""""""gooabc +def[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine5() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $""""""goo[||]bar""""""", +@"var x = $"""""" + gooabc + def[||]bar + """"""", + afterUndo: +@"var x = $""""""gooabc +def[||]bar"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine6() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef\r\n", +@"var x = $""""""goo[||]bar""""""", +@"var x = $"""""" + gooabc + def + [||]bar + """"""", + afterUndo: +@"var x = $""""""gooabc +def +[||]bar"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine7_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\nghi", +@"var x = $""""""[||] """"""", +@"var x = $"""""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = $""""""abc + def +ghi[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine7_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\nghi", +@"var x = $"""""" [||]""""""", +@"var x = $"""""" + abc + def + ghi + [||]""""""", + afterUndo: +@"var x = $"""""" abc + def +ghi[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine8_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\n ghi", +@"var x = $""""""[||] """"""", +@"var x = $"""""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = $""""""abc + def + ghi[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine8_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\n ghi", +@"var x = $""""""[||] """"""", +@"var x = $"""""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = $""""""abc + def + ghi[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine9_A() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = $""""""[||] """"""", +@"var x = $"""""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = $"""""" abc + def + ghi[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine9_B() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = $"""""" [||]""""""", +@"var x = $"""""" + abc + def + ghi + [||]""""""", + afterUndo: +@"var x = $"""""" abc + def + ghi[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine10_A() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = $""""""[||] """"""", +@"var x = $"""""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = $"""""" abc + def + ghi[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine10_B() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = $"""""" [||]""""""", +@"var x = $"""""" + abc + def + ghi + [||]""""""", + afterUndo: +@"var x = $"""""" abc + def + ghi[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine11_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $""""""[||]{|Selection: |}""""""", +@"var x = $"""""" + abc + def + [||]""""""", + afterUndo: +@"var x = $""""""abc +def[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine11_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $"""""" [||]{|Selection: |} """"""", +@"var x = $"""""" + abc + def[||] + """"""", + afterUndo: +@"var x = $"""""" abc +def[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine12_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef\r\n", +@"var x = $""""""[||]{|Selection: |}""""""", +@"var x = $"""""" + abc + def + + [||]""""""", + afterUndo: +@"var x = $""""""abc +def +[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine12_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef\r\n", +@"var x = $"""""" [||]{|Selection: |} """"""", +@"var x = $"""""" + abc + def + [||] + """"""", + afterUndo: +@"var x = $"""""" abc +def +[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine13_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $""""""[||]{|Selection: |} """"""", +@"var x = $"""""" + abc + def[||] + """"""", + afterUndo: +@"var x = $""""""abc +def[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine13_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = $"""""" [||]{|Selection: |}""""""", +@"var x = $"""""" + abc + def + [||]""""""", + afterUndo: +@"var x = $"""""" abc +def[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringHeader1_A() + { + TestPasteUnknownSource( + pasteText: "\"bar", +@"var x = $""""""[||]goo""""""", +@"var x = $"""""" + ""bar[||]goo + """"""", + afterUndo: +@"var x = $""""""""bar[||]goo"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringHeader1_B() + { + TestPasteUnknownSource( + pasteText: "bar\"", +@"var x = $""""""goo[||]""""""", +@"var x = $"""""" + goobar"" + [||]""""""", + afterUndo: +@"var x = $""""""goobar""[||]"""""""); + } + + [WpfFact] + public void TestQuotesIntoHeader1() + { + TestPasteUnknownSource( + pasteText: "\"\"", +@"var x = $""""""[||]{|Selection: |}""""""", +@"var x = $"""""" + """" + [||]""""""", + afterUndo: +@"var x = $""""""""""[||]"""""""); + } + + [WpfFact] + public void TestQuotesIntoHeader2() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = $""""""[||]{|Selection: |}""""""", +@"var x = $"""""""" + """""" + ""[||]""""""", + afterUndo: +@"var x = $""""""""""""[||]"""""""); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoSingleLineRawStringTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoSingleLineRawStringTests.cs new file mode 100644 index 0000000000000..f9b3175204aeb --- /dev/null +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoSingleLineRawStringTests.cs @@ -0,0 +1,614 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.StringCopyPaste +{ + public class PasteUnknownSourceIntoSingleLineRawStringTests + : StringCopyPasteCommandHandlerUnknownSourceTests + { + [WpfFact] + public void TestNewLineIntoSingleLineRawString1_A() + { + TestPasteUnknownSource( + pasteText: "\n", +@"var x = """"""[||] """"""", +"var x = \"\"\"\r\n \n [||] \r\n \"\"\"", + afterUndo: +"var x = \"\"\"\n[||] \"\"\""); + } + + [WpfFact] + public void TestNewLineIntoSingleLineRawString1_B() + { + TestPasteUnknownSource( + pasteText: "\n", +@"var x = """""" [||]""""""", +"var x = \"\"\"\r\n \n \r\n [||]\"\"\"", + afterUndo: +"var x = \"\"\" \n[||]\"\"\""); + } + + [WpfFact] + public void TestNewLineIntoSingleLineRawString2_A() + { + TestPasteUnknownSource( + pasteText: "\r\n", +@"var x = """"""[||] """"""", +"var x = \"\"\"\r\n \r\n [||] \r\n \"\"\"", + afterUndo: +"var x = \"\"\"\r\n[||] \"\"\""); + } + + [WpfFact] + public void TestNewLineIntoSingleLineRawString2_B() + { + TestPasteUnknownSource( + pasteText: "\r\n", +@"var x = """""" [||]""""""", +"var x = \"\"\"\r\n \r\n \r\n [||]\"\"\"", + afterUndo: +"var x = \"\"\" \r\n[||]\"\"\""); + } + + [WpfFact] + public void TestSpacesIntoSingleLineRawString1_A() + { + TestPasteUnknownSource( + pasteText: " ", +@"var x = """"""[||] """"""", +@"var x = """""" [||] """"""", + afterUndo: +@"var x = """"""[||] """""""); + } + + [WpfFact] + public void TestSpacesIntoSingleLineRawString1_B() + { + TestPasteUnknownSource( + pasteText: " ", +@"var x = """""" [||]""""""", +@"var x = """""" [||]""""""", + afterUndo: +@"var x = """""" [||]"""""""); + } + + [WpfFact] + public void TestSpacesIntoSingleLineRawString2() + { + TestPasteUnknownSource( + pasteText: " \r\n", +@"var x = """""" + [||] + """"""", +@"var x = """""" + + [||] + """"""", + afterUndo: +@"var x = """""" + +[||] + """""""); + } + + [WpfFact] + public void TestSingleQuoteIntoSingleLineRawString_A() + { + TestPasteUnknownSource( + pasteText: "'", +@"var x = """"""[||] """"""", +@"var x = """"""'[||] """"""", + afterUndo: +@"var x = """"""[||] """""""); + } + + [WpfFact] + public void TestSingleQuoteIntoSingleLineRawString_B() + { + TestPasteUnknownSource( + pasteText: "'", +@"var x = """""" [||]""""""", +@"var x = """""" '[||]""""""", + afterUndo: +@"var x = """""" [||]"""""""); + } + + [WpfFact] + public void TestDoubleQuoteIntoSingleLineRawString_A() + { + TestPasteUnknownSource( + pasteText: "\"", +@"var x = """"""[||] """"""", +@"var x = """""" + ""[||] + """"""", + afterUndo: +@"var x = """"""""[||] """""""); + } + + [WpfFact] + public void TestDoubleQuoteIntoSingleLineRawString_B() + { + TestPasteUnknownSource( + pasteText: "\"", +@"var x = """""" [||]""""""", +@"var x = """""" + "" + [||]""""""", + afterUndo: +@"var x = """""" ""[||]"""""""); + } + + [WpfFact] + public void TestTripleQuoteIntoSingleLineRawString1_A() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """"""[||] """"""", +@"var x = """""""" + """"""[||] + """"""""", + afterUndo: +@"var x = """"""""""""[||] """""""); + } + + [WpfFact] + public void TestTripleQuoteIntoSingleLineRawString1_B() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """""" [||]""""""", +@"var x = """""""" + """""" + ""[||]""""""", + afterUndo: +@"var x = """""" """"""[||]"""""""); + } + + [WpfFact] + public void TestTripleQuoteIntoSingleLineRawString3() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """""" ""[||] """"""", +@"var x = """""""""" """"""""[||] """"""""""", + afterUndo: +@"var x = """""" """"""""[||] """""""); + } + + [WpfFact] + public void TestTripleQuoteIntoSingleLineRawString4() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """""" ""[||]"" """"""", +@"var x = """""""""""" """"""""[||]"" """"""""""""", + afterUndo: +@"var x = """""" """"""""[||]"" """""""); + } + + [WpfFact] + public void TestTripleQuoteIntoSingleLineRawString5() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """""" [||]"" """"""", +@"var x = """""""""" """"""[||]"" """"""""""", + afterUndo: +@"var x = """""" """"""[||]"" """""""); + } + + [WpfFact] + public void TestQuadrupleQuoteIntoSingleLineRawString() + { + TestPasteUnknownSource( + pasteText: "\"\"\"\"", +@"var x = """""" + [||] + """"""", +@"var x = """""""""" + """"""""[||] + """"""""""", + afterUndo: +@"var x = """""" + """"""""[||] + """""""); + } + + [WpfFact] + public void TestComplexStringIntoSingleLineRawString() + { + TestPasteUnknownSource( + pasteText: " \"\" ", +@"var x = """"""[||] """"""", +@"var x = """""" """" [||] """"""", + afterUndo: +@"var x = """"""[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawString_A() + { + TestPasteUnknownSource( + pasteText: "abc", +@"var x = """"""[||] """"""", +@"var x = """"""abc[||] """"""", + afterUndo: +@"var x = """"""[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawString_B() + { + TestPasteUnknownSource( + pasteText: "abc", +@"var x = """""" [||]""""""", +@"var x = """""" abc[||]""""""", + afterUndo: +@"var x = """""" [||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine1_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """"""[||] """"""", +@"var x = """""" + abc + def[||] + """"""", + afterUndo: +@"var x = """"""abc +def[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine1_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """""" [||]""""""", +@"var x = """""" + abc + def + [||]""""""", + afterUndo: +@"var x = """""" abc +def[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine4() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """"""goo[||]""""""", +@"var x = """""" + gooabc + def + [||]""""""", + afterUndo: +@"var x = """"""gooabc +def[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine5() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """"""goo[||]bar""""""", +@"var x = """""" + gooabc + def[||]bar + """"""", + afterUndo: +@"var x = """"""gooabc +def[||]bar"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine6() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef\r\n", +@"var x = """"""goo[||]bar""""""", +@"var x = """""" + gooabc + def + [||]bar + """"""", + afterUndo: +@"var x = """"""gooabc +def +[||]bar"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine7_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\nghi", +@"var x = """"""[||] """"""", +@"var x = """""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = """"""abc + def +ghi[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine7_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\nghi", +@"var x = """""" [||]""""""", +@"var x = """""" + abc + def + ghi + [||]""""""", + afterUndo: +@"var x = """""" abc + def +ghi[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine8_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\n ghi", +@"var x = """"""[||] """"""", +@"var x = """""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = """"""abc + def + ghi[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine8_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\n def\r\n ghi", +@"var x = """"""[||] """"""", +@"var x = """""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = """"""abc + def + ghi[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine9_A() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = """"""[||] """"""", +@"var x = """""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = """""" abc + def + ghi[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine9_B() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = """""" [||]""""""", +@"var x = """""" + abc + def + ghi + [||]""""""", + afterUndo: +@"var x = """""" abc + def + ghi[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine10_A() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = """"""[||] """"""", +@"var x = """""" + abc + def + ghi[||] + """"""", + afterUndo: +@"var x = """""" abc + def + ghi[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine10_B() + { + TestPasteUnknownSource( + pasteText: " abc\r\n def\r\n ghi", +@"var x = """""" [||]""""""", +@"var x = """""" + abc + def + ghi + [||]""""""", + afterUndo: +@"var x = """""" abc + def + ghi[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine11_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """"""[||]{|Selection: |}""""""", +@"var x = """""" + abc + def + [||]""""""", + afterUndo: +@"var x = """"""abc +def[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine11_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """""" [||]{|Selection: |} """"""", +@"var x = """""" + abc + def[||] + """"""", + afterUndo: +@"var x = """""" abc +def[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine12_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef\r\n", +@"var x = """"""[||]{|Selection: |}""""""", +@"var x = """""" + abc + def + + [||]""""""", + afterUndo: +@"var x = """"""abc +def +[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine12_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef\r\n", +@"var x = """""" [||]{|Selection: |} """"""", +@"var x = """""" + abc + def + [||] + """"""", + afterUndo: +@"var x = """""" abc +def +[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine13_A() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """"""[||]{|Selection: |} """"""", +@"var x = """""" + abc + def[||] + """"""", + afterUndo: +@"var x = """"""abc +def[||] """""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringSingleLine13_B() + { + TestPasteUnknownSource( + pasteText: "abc\r\ndef", +@"var x = """""" [||]{|Selection: |}""""""", +@"var x = """""" + abc + def + [||]""""""", + afterUndo: +@"var x = """""" abc +def[||]"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringHeader1_A() + { + TestPasteUnknownSource( + pasteText: "\"bar", +@"var x = """"""[||]goo""""""", +@"var x = """""" + ""bar[||]goo + """"""", + afterUndo: +@"var x = """"""""bar[||]goo"""""""); + } + + [WpfFact] + public void TestNormalTextIntoSingleLineRawStringHeader1_B() + { + TestPasteUnknownSource( + pasteText: "bar\"", +@"var x = """"""goo[||]""""""", +@"var x = """""" + goobar"" + [||]""""""", + afterUndo: +@"var x = """"""goobar""[||]"""""""); + } + + [WpfFact] + public void TestQuotesIntoHeader1() + { + TestPasteUnknownSource( + pasteText: "\"\"", +@"var x = """"""[||]{|Selection: |}""""""", +@"var x = """""" + """" + [||]""""""", + afterUndo: +@"var x = """"""""""[||]"""""""); + } + + [WpfFact] + public void TestQuotesIntoHeader2() + { + TestPasteUnknownSource( + pasteText: "\"\"\"", +@"var x = """"""[||]{|Selection: |}""""""", +@"var x = """""""" + """""" + ""[||]""""""", + afterUndo: +@"var x = """"""""""""[||]"""""""); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoVerbatimInterpolatedStringTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoVerbatimInterpolatedStringTests.cs new file mode 100644 index 0000000000000..aa00f842b9380 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoVerbatimInterpolatedStringTests.cs @@ -0,0 +1,478 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.StringCopyPaste +{ + public class PasteUnknownSourceIntoVerbatimInterpolatedStringTests + : StringCopyPasteCommandHandlerUnknownSourceTests + { + #region Paste from external source into verbatim interpolated string no hole + + [WpfFact] + public void TestNewLineIntoVerbatimInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "\n", + @"var x = $@""[||]""", + "var x = $@\"\n[||]\"", + afterUndo: @"var x = $@""[||]"""); + } + + [WpfFact] + public void TestNewLineIntoVerbatimInterpolatedString2() + { + TestPasteUnknownSource( + pasteText: "\r\n", + @"var x = $@""[||]""", + "var x = $@\"\r\n[||]\"", + afterUndo: @"var x = $@""[||]"""); + } + + [WpfFact] + public void TestTabIntoVerbatimInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "\t", + @"var x = $@""[||]""", + "var x = $@\"\t[||]\"", + afterUndo: @"var x = $@""[||]"""); + } + + [WpfFact] + public void TestSingleQuoteIntoVerbatimInterpolatedString() + { + TestPasteUnknownSource( + pasteText: "'", + @"var x = $@""[||]""", + @"var x = $@""'[||]""", + afterUndo: "var x = $@\"[||]\""); + } + + [WpfFact] + public void TestDoubleQuoteIntoVerbatimInterpolatedString() + { + TestPasteUnknownSource( + pasteText: "\"", + @"var x = $@""[||]""", + "var x = $@\"\"\"[||]\"", + afterUndo: "var x = $@\"\"[||]\""); + } + + [WpfFact] + public void TestComplexStringIntoVerbatimInterpolatedString() + { + TestPasteUnknownSource( + pasteText: "\t\"\"\t", + @"var x = $@""[||]""", + "var x = $@\"\t\"\"\t[||]\"", + afterUndo: @"var x = $@""[||]"""); + } + + [WpfFact] + public void TestVerbatimTextIntoVerbatimInterpolatedString() + { + TestPasteUnknownSource( + pasteText: "abc", + @"var x = $@""[||]""", + @"var x = $@""abc[||]""", + afterUndo: @"var x = $@""[||]"""); + } + + [WpfFact] + public void TestOpenCurlyIntoVerbatimInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "{", + @"var x = $@""[||]""", + @"var x = $@""{{[||]""", + afterUndo: "var x = $@\"{[||]\""); + } + + [WpfFact] + public void TestTwoOpenCurliesIntoVerbatimInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "{{", + @"var x = $@""[||]""", + @"var x = $@""{{[||]""", + afterUndo: "var x = $@\"[||]\""); + } + + [WpfFact] + public void TestTwoOpenCurliesAndContentIntoVerbatimInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "{{0", + @"var x = $@""[||]""", + @"var x = $@""{{0[||]""", + afterUndo: "var x = $@\"[||]\""); + } + + [WpfFact] + public void TestCloseCurlyIntoVerbatimInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "}", + @"var x = $@""[||]""", + @"var x = $@""}}[||]""", + afterUndo: "var x = $@\"}[||]\""); + } + + [WpfFact] + public void TestTwoCloseCurliesIntoVerbatimInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "}}", + @"var x = $@""[||]""", + @"var x = $@""}}[||]""", + afterUndo: "var x = $@\"[||]\""); + } + + [WpfFact] + public void TestTwoCloseCurliesAndContentIntoVerbatimInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "}}0", + @"var x = $@""[||]""", + @"var x = $@""}}0[||]""", + afterUndo: "var x = $@\"[||]\""); + } + + [WpfFact] + public void TestCurlyWithContentIntoVerbatimInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "x{0}y", + @"var x = $@""[||]""", + @"var x = $@""x{0}y[||]""", + afterUndo: "var x = $@\"[||]\""); + } + + [WpfFact] + public void TestCurliesWithContentIntoVerbatimInterpolatedString1() + { + TestPasteUnknownSource( + pasteText: "x{{0}}y", + @"var x = $@""[||]""", + @"var x = $@""x{{0}}y[||]""", + afterUndo: "var x = $@\"[||]\""); + } + + #endregion + + #region Paste from external source into verbatim interpolated string before hole + + [WpfFact] + public void TestNewLineIntoVerbatimInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "\n", + @"var x = $@""[||]{0}""", + "var x = $@\"\n[||]{0}\"", + afterUndo: @"var x = $@""[||]{0}"""); + } + + [WpfFact] + public void TestNewLineIntoVerbatimInterpolatedStringBeforeHole2() + { + TestPasteUnknownSource( + pasteText: "\r\n", + @"var x = $@""[||]{0}""", + "var x = $@\"\r\n[||]{0}\"", + afterUndo: @"var x = $@""[||]{0}"""); + } + + [WpfFact] + public void TestTabIntoVerbatimInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "\t", + @"var x = $@""[||]{0}""", + "var x = $@\"\t[||]{0}\"", + afterUndo: @"var x = $@""[||]{0}"""); + } + + [WpfFact] + public void TestSingleQuoteIntoVerbatimInterpolatedStringBeforeHole() + { + TestPasteUnknownSource( + pasteText: "'", + @"var x = $@""[||]{0}""", + @"var x = $@""'[||]{0}""", + afterUndo: "var x = $@\"[||]{0}\""); + } + + [WpfFact] + public void TestDoubleQuoteIntoVerbatimInterpolatedStringBeforeHole() + { + TestPasteUnknownSource( + pasteText: "\"", + @"var x = $@""[||]{0}""", + @"var x = $@""""""[||]{0}""", + afterUndo: @"var x = $@""""[||]{0}"""); + } + + [WpfFact] + public void TestComplexStringIntoVerbatimInterpolatedStringBeforeHole() + { + TestPasteUnknownSource( + pasteText: "\t\"\"\t", + @"var x = $@""[||]{0}""", + "var x = $@\"\t\"\"\t[||]{0}\"", + afterUndo: @"var x = $@""[||]{0}"""); + } + + [WpfFact] + public void TestVerbatimTextIntoVerbatimInterpolatedStringBeforeHole() + { + TestPasteUnknownSource( + pasteText: "abc", + @"var x = $@""[||]{0}""", + @"var x = $@""abc[||]{0}""", + afterUndo: @"var x = $@""[||]{0}"""); + } + + [WpfFact] + public void TestOpenCurlyIntoVerbatimInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "{", + @"var x = $@""[||]{0}""", + @"var x = $@""{{[||]{0}""", + afterUndo: "var x = $@\"{[||]{0}\""); + } + + [WpfFact] + public void TestTwoOpenCurliesIntoVerbatimInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "{{", + @"var x = $@""[||]{0}""", + @"var x = $@""{{[||]{0}""", + afterUndo: "var x = $@\"[||]{0}\""); + } + + [WpfFact] + public void TestTwoOpenCurliesAndContentIntoVerbatimInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "{{0", + @"var x = $@""[||]{0}""", + @"var x = $@""{{0[||]{0}""", + afterUndo: "var x = $@\"[||]{0}\""); + } + + [WpfFact] + public void TestCloseCurlyIntoVerbatimInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "}", + @"var x = $@""[||]{0}""", + @"var x = $@""}}[||]{0}""", + afterUndo: "var x = $@\"}[||]{0}\""); + } + + [WpfFact] + public void TestTwoCloseCurliesIntoVerbatimInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "}}", + @"var x = $@""[||]{0}""", + @"var x = $@""}}[||]{0}""", + afterUndo: "var x = $@\"[||]{0}\""); + } + + [WpfFact] + public void TestTwoCloseCurliesAndContentIntoVerbatimInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "}}0", + @"var x = $@""[||]{0}""", + @"var x = $@""}}0[||]{0}""", + afterUndo: "var x = $@\"[||]{0}\""); + } + + [WpfFact] + public void TestCurlyWithContentIntoVerbatimInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "x{0}y", + @"var x = $@""[||]{0}""", + @"var x = $@""x{0}y[||]{0}""", + afterUndo: "var x = $@\"[||]{0}\""); + } + + [WpfFact] + public void TestCurliesWithContentIntoVerbatimInterpolatedStringBeforeHole1() + { + TestPasteUnknownSource( + pasteText: "x{{0}}y", + @"var x = $@""[||]{0}""", + @"var x = $@""x{{0}}y[||]{0}""", + afterUndo: "var x = $@\"[||]{0}\""); + } + + #endregion + + #region Paste from external source into verbatim interpolated string after hole + + [WpfFact] + public void TestNewLineIntoVerbatimInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "\n", + @"var x = $@""{0}[||]""", + "var x = $@\"{0}\n[||]\"", + afterUndo: @"var x = $@""{0}[||]"""); + } + + [WpfFact] + public void TestNewLineIntoVerbatimInterpolatedStringAfterHole2() + { + TestPasteUnknownSource( + pasteText: "\r\n", + @"var x = $@""{0}[||]""", + "var x = $@\"{0}\r\n[||]\"", + afterUndo: @"var x = $@""{0}[||]"""); + } + + [WpfFact] + public void TestTabIntoVerbatimInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "\t", + @"var x = $@""{0}[||]""", + "var x = $@\"{0}\t[||]\"", + afterUndo: @"var x = $@""{0}[||]"""); + } + + [WpfFact] + public void TestSingleQuoteIntoVerbatimInterpolatedStringAfterHole() + { + TestPasteUnknownSource( + pasteText: "'", + @"var x = $@""{0}[||]""", + @"var x = $@""{0}'[||]""", + afterUndo: "var x = $@\"{0}[||]\""); + } + + [WpfFact] + public void TestDoubleQuoteIntoVerbatimInterpolatedStringAfterHole() + { + TestPasteUnknownSource( + pasteText: "\"", + @"var x = $@""{0}[||]""", + @"var x = $@""{0}""""[||]""", + afterUndo: @"var x = $@""{0}""[||]"""); + } + + [WpfFact] + public void TestComplexStringIntoVerbatimInterpolatedStringAfterHole() + { + TestPasteUnknownSource( + pasteText: "\t\"\"\t", + @"var x = $@""{0}[||]""", + "var x = $@\"{0}\t\"\"\t[||]\"", + afterUndo: "var x = $@\"{0}[||]\""); + } + + [WpfFact] + public void TestVerbatimTextIntoVerbatimInterpolatedStringAfterHole() + { + TestPasteUnknownSource( + pasteText: "abc", + @"var x = $@""{0}[||]""", + @"var x = $@""{0}abc[||]""", + afterUndo: @"var x = $@""{0}[||]"""); + } + + [WpfFact] + public void TestOpenCurlyIntoVerbatimInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "{", + @"var x = $@""{0}[||]""", + @"var x = $@""{0}{{[||]""", + afterUndo: "var x = $@\"{0}{[||]\""); + } + + [WpfFact] + public void TestTwoOpenCurliesIntoVerbatimInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "{{", + @"var x = $@""{0}[||]""", + @"var x = $@""{0}{{[||]""", + afterUndo: "var x = $@\"{0}[||]\""); + } + + [WpfFact] + public void TestTwoOpenCurliesAndContentIntoVerbatimInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "{{0", + @"var x = $@""{0}[||]""", + @"var x = $@""{0}{{0[||]""", + afterUndo: "var x = $@\"{0}[||]\""); + } + + [WpfFact] + public void TestCloseCurlyIntoVerbatimInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "}", + @"var x = $@""{0}[||]""", + @"var x = $@""{0}}}[||]""", + afterUndo: "var x = $@\"{0}}[||]\""); + } + + [WpfFact] + public void TestTwoCloseCurliesIntoVerbatimInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "}}", + @"var x = $@""{0}[||]""", + @"var x = $@""{0}}}[||]""", + afterUndo: "var x = $@\"{0}[||]\""); + } + + [WpfFact] + public void TestTwoCloseCurliesAndContentIntoVerbatimInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "}}0", + @"var x = $@""{0}[||]""", + @"var x = $@""{0}}}0[||]""", + afterUndo: "var x = $@\"{0}[||]\""); + } + + [WpfFact] + public void TestCurlyWithContentIntoVerbatimInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "x{0}y", + @"var x = $@""{0}[||]""", + @"var x = $@""{0}x{0}y[||]""", + afterUndo: "var x = $@\"{0}[||]\""); + } + + [WpfFact] + public void TestCurliesWithContentIntoVerbatimInterpolatedStringAfterHole1() + { + TestPasteUnknownSource( + pasteText: "x{{0}}y", + @"var x = $@""{0}[||]""", + @"var x = $@""{0}x{{0}}y[||]""", + afterUndo: "var x = $@\"{0}[||]\""); + } + + #endregion + } +} diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoVerbatimStringTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoVerbatimStringTests.cs new file mode 100644 index 0000000000000..2a7752dd050b3 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/PasteUnknownSourceIntoVerbatimStringTests.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.StringCopyPaste +{ + public class PasteUnknownSourceIntoVerbatimStringTests + : StringCopyPasteCommandHandlerUnknownSourceTests + { + [WpfFact] + public void TestNewLineIntoVerbatimString1() + { + TestPasteUnknownSource( + pasteText: "\n", + @"var x = @""[||]""", + "var x = @\"\n[||]\"", + afterUndo: @"var x = @""[||]"""); + } + + [WpfFact] + public void TestNewLineIntoVerbatimString2() + { + TestPasteUnknownSource( + pasteText: "\r\n", + @"var x = @""[||]""", + "var x = @\"\r\n[||]\"", + afterUndo: @"var x = @""[||]"""); + } + + [WpfFact] + public void TestTabIntoVerbatimString1() + { + TestPasteUnknownSource( + pasteText: "\t", + @"var x = @""[||]""", + "var x = @\"\t[||]\"", + afterUndo: @"var x = @""[||]"""); + } + + [WpfFact] + public void TestSingleQuoteIntoVerbatimString() + { + TestPasteUnknownSource( + pasteText: "'", + @"var x = @""[||]""", + @"var x = @""'[||]""", + afterUndo: @"var x = @""[||]"""); + } + + [WpfFact] + public void TestDoubleQuoteIntoVerbatimString() + { + TestPasteUnknownSource( + pasteText: "\"", + @"var x = @""[||]""", + @"var x = @""""""[||]""", + afterUndo: @"var x = @""""[||]"""); + } + + [WpfFact] + public void TestComplexStringIntoVerbatimString() + { + TestPasteUnknownSource( + pasteText: "\t\"\"\t", + @"var x = @""[||]""", + "var x = @\"\t\"\"\t[||]\"", + afterUndo: @"var x = @""[||]"""); + } + + [WpfFact] + public void TestNormalTextIntoVerbatimString() + { + TestPasteUnknownSource( + pasteText: "abc", + @"var x = @""[||]""", + @"var x = @""abc[||]""", + afterUndo: @"var x = @""[||]"""); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/StringCopyPasteCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/StringCopyPasteCommandHandlerTests.cs new file mode 100644 index 0000000000000..1b2ffa0196088 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/StringCopyPasteCommandHandlerTests.cs @@ -0,0 +1,174 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Linq; +using System.Xml.Linq; +using Microsoft.CodeAnalysis.Editor.CSharp.StringCopyPaste; +using Microsoft.CodeAnalysis.Editor.UnitTests; +using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; +using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.VisualStudio.Commanding; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Microsoft.VisualStudio.Text.Operations; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.StringCopyPaste +{ + [UseExportProvider] + public abstract class StringCopyPasteCommandHandlerTests + { + internal sealed class StringCopyPasteTestState : AbstractCommandHandlerTestState + { + private static readonly TestComposition s_composition = EditorTestCompositions.EditorFeaturesWpf.AddParts( + typeof(StringCopyPasteCommandHandler)); + + private readonly StringCopyPasteCommandHandler _commandHandler; + + public StringCopyPasteTestState(XElement workspaceElement) + : base(workspaceElement, s_composition) + { + _commandHandler = (StringCopyPasteCommandHandler)GetExportedValues(). + Single(c => c is StringCopyPasteCommandHandler); + } + + public static StringCopyPasteTestState CreateTestState(string markup) + => new(GetWorkspaceXml(markup)); + + public static XElement GetWorkspaceXml(string markup) + => markup.Contains("") + ? XElement.Parse(markup) + : XElement.Parse($@" + + + {markup} + +"); + + internal void AssertCodeIs(string expectedCode) + { + TestFileMarkupParser.GetPositionAndSpans( + expectedCode, out var massaged, out int? caretPosition, out ImmutableDictionary> spans); + Assert.Equal(massaged, TextView.TextSnapshot.GetText()); + Assert.Equal(caretPosition, TextView.Caret.Position.BufferPosition.Position); + + var virtualSpaces = spans.SingleOrDefault(kvp => kvp.Key.StartsWith("VirtualSpaces#")); + if (virtualSpaces.Key != null) + { + var virtualOffset = int.Parse(virtualSpaces.Key.Substring("VirtualSpaces-".Length)); + Assert.True(TextView.Caret.InVirtualSpace); + Assert.Equal(virtualOffset, TextView.Caret.Position.VirtualBufferPosition.VirtualSpaces); + } + } + + public void TestCopyPaste(string expectedMarkup, string? pasteText, string afterUndoMarkup) + { + var workspace = this.Workspace; + + var copyDocument = this.Workspace.Documents.FirstOrDefault(d => d.AnnotatedSpans.ContainsKey("Copy")); + if (copyDocument != null) + { + Assert.Null(pasteText); + var copySpans = copyDocument.AnnotatedSpans["Copy"]; + + SetSelection(copyDocument, copySpans, out var copyTextView, out var copyTextBuffer); + + _commandHandler.ExecuteCommand( + new CopyCommandArgs(copyTextView, copyTextBuffer), () => + { + var copyEditorOperations = GetService().GetEditorOperations(copyTextView); + Assert.True(copyEditorOperations.CopySelection()); + }, TestCommandExecutionContext.Create()); + } + else + { + // If we don't have a file to copy text from, then the paste text must be explicitly provided."); + Assert.NotNull(pasteText); + } + + if (pasteText == null) + { + // if the user didn't supply text to paste, then just paste in what we put in the clipboard above. + _commandHandler.ExecuteCommand( + new PasteCommandArgs(this.TextView, this.SubjectBuffer), () => EditorOperations.Paste(), TestCommandExecutionContext.Create()); + } + else + { + // otherwise, this is a test of text coming in from another source. Do the edit manually. + _commandHandler.ExecuteCommand( + new PasteCommandArgs(this.TextView, this.SubjectBuffer), () => + { + EditorOperations.ReplaceSelection(pasteText); + }, TestCommandExecutionContext.Create()); + } + + ValidateBefore(expectedMarkup); + + this.SendUndo(); + + ValidateAfter(afterUndoMarkup); + } + + private void ValidateBefore(string expectedMarkup) + { + GetCodeAndCaretPosition(expectedMarkup, out var expected, out var caretPosition); + var finalText = this.SubjectBuffer.CurrentSnapshot.GetText(); + + Assert.Equal(expected, finalText); + Assert.Equal(caretPosition, this.TextView.Caret.Position.BufferPosition.Position); + } + + private static void GetCodeAndCaretPosition(string expectedMarkup, out string expected, out int caretPosition) + { + // Used so test can contain `$$` (for raw interpolations) without us thinking that it is an actual caret + // position + const string NON_TEST_CHARACTER = "\uD7FF"; + + expectedMarkup = expectedMarkup.Replace("$", NON_TEST_CHARACTER); + + TestFileMarkupParser.GetSpan(expectedMarkup, out expected, out var caretSpan); + + expected = expected.Replace(NON_TEST_CHARACTER, "$"); + + caretPosition = caretSpan.Start; + } + + private void ValidateAfter(string afterUndoMarkup) + { + GetCodeAndCaretPosition(afterUndoMarkup, out var expected, out var caretPosition); + var finalText = this.SubjectBuffer.CurrentSnapshot.GetText(); + + Assert.Equal(expected, finalText); + Assert.Equal(caretPosition, this.TextView.Caret.Position.BufferPosition.Position); + } + + private static void SetSelection( + TestHostDocument document, + ImmutableArray copySpans, out IWpfTextView textView, out ITextBuffer2 textBuffer2) + { + textView = document.GetTextView(); + var textBuffer = document.GetTextBuffer(); + textBuffer2 = textBuffer; + var broker = textView.GetMultiSelectionBroker(); + + broker.AddSelectionRange(copySpans.Select(s => new Selection(s.ToSnapshotSpan(textBuffer.CurrentSnapshot)))); + } + } + +#if false + private static void TestCopyPaste(string markup, string expectedMarkup, string afterUndo) + { + using var state = StringCopyPasteTestState.CreateTestState(markup); + + state.TestCopyPaste(expectedMarkup, pasteText: null, afterUndo); + } +#endif + } +} diff --git a/src/EditorFeatures/CSharpTest/StringCopyPaste/StringCopyPasteCommandHandlerUnknownSourceTests.cs b/src/EditorFeatures/CSharpTest/StringCopyPaste/StringCopyPasteCommandHandlerUnknownSourceTests.cs new file mode 100644 index 0000000000000..942ce97c4bc56 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/StringCopyPaste/StringCopyPasteCommandHandlerUnknownSourceTests.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.StringCopyPaste +{ + public abstract class StringCopyPasteCommandHandlerUnknownSourceTests + : StringCopyPasteCommandHandlerTests + { + protected static void TestPasteUnknownSource(string pasteText, string markup, string expectedMarkup, string afterUndo) + { + using var state = StringCopyPasteTestState.CreateTestState(markup); + + state.TestCopyPaste(expectedMarkup, pasteText, afterUndo); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/Wrapping/AbstractWrappingTests.cs b/src/EditorFeatures/CSharpTest/Wrapping/AbstractWrappingTests.cs index 3deec5f47d93a..762e2c2a170a2 100644 --- a/src/EditorFeatures/CSharpTest/Wrapping/AbstractWrappingTests.cs +++ b/src/EditorFeatures/CSharpTest/Wrapping/AbstractWrappingTests.cs @@ -20,34 +20,21 @@ public abstract class AbstractWrappingTests : AbstractCSharpCodeActionTest protected sealed override ImmutableArray MassageActions(ImmutableArray actions) => FlattenActions(actions); - private protected static CodeActionOptions GetIndentionColumn(int column) - => new(SymbolSearchOptions.Default, - ImplementTypeOptions.Default, - ExtractMethodOptions.Default, - WrappingColumn: column); + private protected TestParameters GetIndentionColumn(int column) + => new(globalOptions: Option(CodeActionOptionsStorage.WrappingColumn, column)); protected Task TestAllWrappingCasesAsync( string input, params string[] outputs) { - return TestAllWrappingCasesAsync(input, options: CodeActionOptions.Default, outputs); + return TestAllWrappingCasesAsync(input, parameters: null, outputs); } private protected Task TestAllWrappingCasesAsync( string input, - CodeActionOptions options, + TestParameters parameters, params string[] outputs) { - var parameters = new TestParameters(codeActionOptions: options); - return TestAllInRegularAndScriptAsync(input, parameters, outputs); - } - - private protected Task TestAllWrappingCasesAsync( - string input, - OptionsCollection options, - params string[] outputs) - { - var parameters = new TestParameters(options: options); return TestAllInRegularAndScriptAsync(input, parameters, outputs); } } diff --git a/src/EditorFeatures/CSharpTest/Wrapping/BinaryExpressionWrappingTests.cs b/src/EditorFeatures/CSharpTest/Wrapping/BinaryExpressionWrappingTests.cs index c8d3fe738a6bf..9130c203f3a29 100644 --- a/src/EditorFeatures/CSharpTest/Wrapping/BinaryExpressionWrappingTests.cs +++ b/src/EditorFeatures/CSharpTest/Wrapping/BinaryExpressionWrappingTests.cs @@ -20,21 +20,17 @@ public class BinaryExpressionWrappingTests : AbstractWrappingTests protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters) => new CSharpWrappingCodeRefactoringProvider(); - private OptionsCollection EndOfLine => Option( - CodeStyleOptions2.OperatorPlacementWhenWrapping, - OperatorPlacementWhenWrappingPreference.EndOfLine); + private TestParameters EndOfLine + => new(options: Option(CodeStyleOptions2.OperatorPlacementWhenWrapping, OperatorPlacementWhenWrappingPreference.EndOfLine)); - private OptionsCollection BeginningOfLine => Option( - CodeStyleOptions2.OperatorPlacementWhenWrapping, - OperatorPlacementWhenWrappingPreference.BeginningOfLine); + private TestParameters BeginningOfLine + => new(options: Option(CodeStyleOptions2.OperatorPlacementWhenWrapping, OperatorPlacementWhenWrappingPreference.BeginningOfLine)); private Task TestEndOfLine(string markup, string expected) - => TestInRegularAndScript1Async(markup, expected, parameters: new TestParameters( - options: EndOfLine)); + => TestInRegularAndScript1Async(markup, expected, EndOfLine); private Task TestBeginningOfLine(string markup, string expected) - => TestInRegularAndScript1Async(markup, expected, parameters: new TestParameters( - options: BeginningOfLine)); + => TestInRegularAndScript1Async(markup, expected, BeginningOfLine); [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsWrapping)] public async Task TestMissingWithSyntaxError() diff --git a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTag.cs b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTag.cs index 1c3e00d2ad40c..d8b59aa9c5108 100644 --- a/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTag.cs +++ b/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTag.cs @@ -17,10 +17,10 @@ using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.InlineHints; -using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Adornments; using Microsoft.VisualStudio.Text.Classification; @@ -266,13 +266,16 @@ private void Adornment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e if (e.ClickCount == 2) { e.Handled = true; - var replacementValue = _hint.ReplacementTextChange!.Value; - var subjectBuffer = _span.Snapshot.TextBuffer; + var textChange = _hint.ReplacementTextChange!.Value; + + var snapshot = _span.Snapshot; + var subjectBuffer = snapshot.TextBuffer; // Selected SpanTrackingMode to be EdgeExclusive by default. // Will revise if there are some scenarios we did not think of that produce undesirable behavior. - var currentSnapshotSpan = _span.TranslateTo(subjectBuffer.CurrentSnapshot, SpanTrackingMode.EdgeExclusive); - subjectBuffer.Replace(currentSnapshotSpan.Span, replacementValue.NewText); + subjectBuffer.Replace( + textChange.Span.ToSnapshotSpan(snapshot).TranslateTo(subjectBuffer.CurrentSnapshot, SpanTrackingMode.EdgeExclusive), + textChange.NewText); } } } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixAllGetFixesService.cs b/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixAllGetFixesService.cs index c00c7499b38a3..730fd837e97ca 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixAllGetFixesService.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixAllGetFixesService.cs @@ -5,18 +5,18 @@ #nullable disable using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { @@ -32,7 +32,7 @@ public FixAllGetFixesService() public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) => this; - public async Task GetFixAllChangedSolutionAsync(FixAllContext fixAllContext) + public async Task GetFixAllChangedSolutionAsync(IFixAllContext fixAllContext) { var codeAction = await GetFixAllCodeActionAsync(fixAllContext).ConfigureAwait(false); if (codeAction == null) @@ -45,7 +45,7 @@ public async Task GetFixAllChangedSolutionAsync(FixAllContext fixAllCo } public async Task> GetFixAllOperationsAsync( - FixAllContext fixAllContext, bool showPreviewChangesDialog) + IFixAllContext fixAllContext, bool showPreviewChangesDialog) { var codeAction = await GetFixAllCodeActionAsync(fixAllContext).ConfigureAwait(false); if (codeAction == null) @@ -57,10 +57,18 @@ public async Task> GetFixAllOperationsAsync( codeAction, showPreviewChangesDialog, fixAllContext.State, fixAllContext.CancellationToken).ConfigureAwait(false); } - private static async Task GetFixAllCodeActionAsync(FixAllContext fixAllContext) + private static async Task GetFixAllCodeActionAsync(IFixAllContext fixAllContext) { + var fixAllKind = fixAllContext.State.FixAllKind; + var functionId = fixAllKind switch + { + FixAllKind.CodeFix => FunctionId.CodeFixes_FixAllOccurrencesComputation, + FixAllKind.Refactoring => FunctionId.Refactoring_FixAllOccurrencesComputation, + _ => throw ExceptionUtilities.UnexpectedValue(fixAllKind) + }; + using (Logger.LogBlock( - FunctionId.CodeFixes_FixAllOccurrencesComputation, + functionId, KeyValueLogMessage.Create(LogType.UserAction, m => { m[FixAllLogger.CorrelationId] = fixAllContext.State.CorrelationId; @@ -75,17 +83,17 @@ private static async Task GetFixAllCodeActionAsync(FixAllContext fix } catch (OperationCanceledException) { - FixAllLogger.LogComputationResult(fixAllContext.State.CorrelationId, completed: false); + FixAllLogger.LogComputationResult(fixAllKind, fixAllContext.State.CorrelationId, completed: false); } finally { if (action != null) { - FixAllLogger.LogComputationResult(fixAllContext.State.CorrelationId, completed: true); + FixAllLogger.LogComputationResult(fixAllKind, fixAllContext.State.CorrelationId, completed: true); } else { - FixAllLogger.LogComputationResult(fixAllContext.State.CorrelationId, completed: false, timedOut: true); + FixAllLogger.LogComputationResult(fixAllKind, fixAllContext.State.CorrelationId, completed: false, timedOut: true); } } @@ -95,7 +103,7 @@ private static async Task GetFixAllCodeActionAsync(FixAllContext fix private static async Task> GetFixAllOperationsAsync( CodeAction codeAction, bool showPreviewChangesDialog, - FixAllState fixAllState, CancellationToken cancellationToken) + IFixAllState fixAllState, CancellationToken cancellationToken) { // We have computed the fix all occurrences code fix. // Now fetch the new solution with applied fix and bring up the Preview changes dialog. @@ -119,6 +127,7 @@ private static async Task> GetFixAllOperatio newSolution, FeaturesResources.Fix_all_occurrences, codeAction.Title, + fixAllState.FixAllKind, fixAllState.Project.Language, workspace, fixAllState.CorrelationId, @@ -138,14 +147,23 @@ internal static Solution PreviewChanges( Solution newSolution, string fixAllPreviewChangesTitle, string fixAllTopLevelHeader, + FixAllKind fixAllKind, string languageOpt, Workspace workspace, int? correlationId = null, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); + + var functionId = fixAllKind switch + { + FixAllKind.CodeFix => FunctionId.CodeFixes_FixAllOccurrencesPreviewChanges, + FixAllKind.Refactoring => FunctionId.Refactoring_FixAllOccurrencesPreviewChanges, + _ => throw ExceptionUtilities.UnexpectedValue(fixAllKind) + }; + using (Logger.LogBlock( - FunctionId.CodeFixes_FixAllOccurrencesPreviewChanges, + functionId, KeyValueLogMessage.Create(LogType.UserAction, m => { // only set when correlation id is given @@ -187,11 +205,11 @@ internal static Solution PreviewChanges( if (changedSolution == null) { // User clicked cancel. - FixAllLogger.LogPreviewChangesResult(correlationId, applied: false); + FixAllLogger.LogPreviewChangesResult(fixAllKind, correlationId, applied: false); return null; } - FixAllLogger.LogPreviewChangesResult(correlationId, applied: true, allChangesApplied: changedSolution == newSolution); + FixAllLogger.LogPreviewChangesResult(fixAllKind, correlationId, applied: true, allChangesApplied: changedSolution == newSolution); return changedSolution; } } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs index e99140f804ffb..51f5466d78777 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs @@ -26,7 +26,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions /// Base type for all SuggestedActions that have 'flavors'. 'Flavors' are child actions that /// are presented as simple links, not as menu-items, in the light-bulb. Examples of 'flavors' /// include 'preview changes' (for refactorings and fixes) and 'fix all in document, project, solution' - /// (for fixes). + /// (for refactorings and fixes). /// /// Because all derivations support 'preview changes', we bake that logic into this base type. /// @@ -40,7 +40,7 @@ public SuggestedActionWithNestedFlavors( SuggestedActionsSourceProvider sourceProvider, Workspace workspace, ITextBuffer subjectBuffer, object provider, CodeAction codeAction, - SuggestedActionSet additionalFlavors = null) + SuggestedActionSet additionalFlavors) : base(threadingContext, sourceProvider, workspace, subjectBuffer, provider, codeAction) { diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllSuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs similarity index 54% rename from src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllSuggestedAction.cs rename to src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs index 93f22d2cdc34d..d09b011255ac2 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllSuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs @@ -2,53 +2,39 @@ // 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; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; -using Microsoft.CodeAnalysis.UnifiedSuggestions.UnifiedSuggestedActions; -using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions { /// - /// Suggested action for fix all occurrences code fix. Note: this is only used - /// as a 'flavor' inside CodeFixSuggestionAction. + /// Suggested action for fix all occurrences for a code fix or a code refactoring. /// - internal sealed partial class FixAllSuggestedAction : SuggestedAction, ITelemetryDiagnosticID, IFixAllSuggestedAction + internal abstract class AbstractFixAllSuggestedAction : SuggestedAction { - public Diagnostic Diagnostic { get; } - - /// - /// The original code-action that we are a fix-all for. i.e. _originalCodeAction - /// would be something like "use 'var' instead of 'int'", this suggestion action - /// and our is the actual action that - /// will perform the fix in the appropriate document/project/solution scope. - /// public CodeAction OriginalCodeAction { get; } - public FixAllState FixAllState { get; } + public IFixAllState FixAllState { get; } - internal FixAllSuggestedAction( + protected AbstractFixAllSuggestedAction( IThreadingContext threadingContext, SuggestedActionsSourceProvider sourceProvider, Workspace workspace, ITextBuffer subjectBuffer, - FixAllState fixAllState, - Diagnostic originalFixedDiagnostic, - CodeAction originalCodeAction) + IFixAllState fixAllState, + CodeAction originalCodeAction, + AbstractFixAllCodeAction fixAllCodeAction) : base(threadingContext, sourceProvider, workspace, subjectBuffer, - fixAllState.FixAllProvider, new FixAllCodeAction(fixAllState)) + fixAllState.FixAllProvider, fixAllCodeAction) { - Diagnostic = originalFixedDiagnostic; OriginalCodeAction = originalCodeAction; FixAllState = fixAllState; } @@ -62,15 +48,20 @@ public override bool TryGetTelemetryId(out Guid telemetryId) return true; } - public string GetDiagnosticID() - => Diagnostic.GetTelemetryDiagnosticID(); - protected override async Task InnerInvokeAsync( IProgressTracker progressTracker, CancellationToken cancellationToken) { await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - using (Logger.LogBlock(FunctionId.CodeFixes_FixAllOccurrencesSession, FixAllLogger.CreateCorrelationLogMessage(FixAllState.CorrelationId), cancellationToken)) + var fixAllKind = FixAllState.FixAllKind; + var functionId = fixAllKind switch + { + FixAllKind.CodeFix => FunctionId.CodeFixes_FixAllOccurrencesSession, + FixAllKind.Refactoring => FunctionId.Refactoring_FixAllOccurrencesSession, + _ => throw ExceptionUtilities.UnexpectedValue(fixAllKind) + }; + + using (Logger.LogBlock(functionId, FixAllLogger.CreateCorrelationLogMessage(FixAllState.CorrelationId), cancellationToken)) { await base.InnerInvokeAsync(progressTracker, cancellationToken).ConfigureAwait(false); } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs index 1770c5ec683f5..ac14b9c18cd06 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.UnifiedSuggestions.UnifiedSuggestedActions; +using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions @@ -25,8 +26,9 @@ public CodeRefactoringSuggestedAction( Workspace workspace, ITextBuffer subjectBuffer, CodeRefactoringProvider provider, - CodeAction codeAction) - : base(threadingContext, sourceProvider, workspace, subjectBuffer, provider, codeAction) + CodeAction codeAction, + SuggestedActionSet fixAllFlavors) + : base(threadingContext, sourceProvider, workspace, subjectBuffer, provider, codeAction, fixAllFlavors) { CodeRefactoringProvider = provider; } diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.FixAllCodeAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.FixAllCodeAction.cs new file mode 100644 index 0000000000000..fe826091b3f24 --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.FixAllCodeAction.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions +{ + internal partial class FixAllCodeFixSuggestedAction + { + private sealed partial class FixAllCodeAction : AbstractFixAllCodeFixCodeAction + { + public FixAllCodeAction(IFixAllState fixAllState) + : base(fixAllState, showPreviewChangesDialog: true) + { + } + } + } +} diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.cs new file mode 100644 index 0000000000000..9148893d8ab65 --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.UnifiedSuggestions.UnifiedSuggestedActions; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions +{ + /// + /// Suggested action for fix all occurrences code fix. Note: this is only used + /// as a 'flavor' inside CodeFixSuggestionAction. + /// + internal sealed partial class FixAllCodeFixSuggestedAction : AbstractFixAllSuggestedAction, ITelemetryDiagnosticID, IFixAllCodeFixSuggestedAction + { + public Diagnostic Diagnostic { get; } + + public FixAllCodeFixSuggestedAction( + IThreadingContext threadingContext, + SuggestedActionsSourceProvider sourceProvider, + Workspace workspace, + ITextBuffer subjectBuffer, + IFixAllState fixAllState, + Diagnostic diagnostic, + CodeAction originalCodeAction) + : base(threadingContext, sourceProvider, workspace, subjectBuffer, fixAllState, + originalCodeAction, new FixAllCodeAction(fixAllState)) + { + Diagnostic = diagnostic; + } + + public string GetDiagnosticID() + => Diagnostic.GetTelemetryDiagnosticID(); + } +} diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeRefactoringSuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeRefactoringSuggestedAction.cs new file mode 100644 index 0000000000000..fa7b3a833dfa5 --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeRefactoringSuggestedAction.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.UnifiedSuggestions.UnifiedSuggestedActions; +using Microsoft.VisualStudio.Text; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions +{ + /// + /// Suggested action for fix all occurrences for a code refactoring. Note: this is only used + /// as a 'flavor' inside CodeRefactoringSuggestionAction. + /// + internal sealed class FixAllCodeRefactoringSuggestedAction : AbstractFixAllSuggestedAction, IFixAllCodeRefactoringSuggestedAction + { + public FixAllCodeRefactoringSuggestedAction( + IThreadingContext threadingContext, + SuggestedActionsSourceProvider sourceProvider, + Workspace workspace, + ITextBuffer subjectBuffer, + IFixAllState fixAllState, + CodeAction originalCodeAction) + : base(threadingContext, sourceProvider, workspace, subjectBuffer, fixAllState, + originalCodeAction, new FixAllCodeRefactoringCodeAction(fixAllState)) + { + } + } +} diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllSuggestedAction.FixAllCodeAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllSuggestedAction.FixAllCodeAction.cs deleted file mode 100644 index d918422951fca..0000000000000 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllSuggestedAction.FixAllCodeAction.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// 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 Microsoft.CodeAnalysis.CodeFixes; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions -{ - internal partial class FixAllSuggestedAction - { - private sealed partial class FixAllCodeAction : FixSomeCodeAction - { - public FixAllCodeAction(FixAllState fixAllState) - : base(fixAllState, showPreviewChangesDialog: true) - { - } - - public override string Title - => this.FixAllState.Scope switch - { - FixAllScope.Document => FeaturesResources.Document, - FixAllScope.Project => FeaturesResources.Project, - FixAllScope.Solution => FeaturesResources.Solution, - FixAllScope.ContainingMember => FeaturesResources.Containing_Member, - FixAllScope.ContainingType => FeaturesResources.Containing_Type, - _ => throw new NotSupportedException(), - }; - - internal override string Message => FeaturesResources.Computing_fix_all_occurrences_code_fix; - } - } -} diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs index cc8cc3fea3e6e..1152683034ec6 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs @@ -11,19 +11,17 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.Extensions; using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Core.Imaging; using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Threading; using Microsoft.VisualStudio.Utilities; using Roslyn.Utilities; @@ -176,7 +174,7 @@ await EditHandler.ApplyAsync( private void CreateLogProperties(Dictionary map) { // set various correlation info - if (CodeAction is FixSomeCodeAction fixSome) + if (CodeAction is AbstractFixAllCodeFixCodeAction fixSome) { // fix all correlation info map[FixAllLogger.CorrelationId] = fixSome.FixAllState.CorrelationId; diff --git a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs index c2ef69da65011..e3f1eef0979f8 100644 --- a/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs +++ b/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs @@ -235,10 +235,14 @@ ISuggestedAction ConvertToSuggestedAction(IUnifiedSuggestedAction unifiedSuggest ConvertToSuggestedActionSet(codeFixAction.FixAllFlavors, owner, subjectBuffer)), UnifiedCodeRefactoringSuggestedAction codeRefactoringAction => new CodeRefactoringSuggestedAction( ThreadingContext, owner, codeRefactoringAction.Workspace, subjectBuffer, - codeRefactoringAction.CodeRefactoringProvider, codeRefactoringAction.OriginalCodeAction), - UnifiedFixAllSuggestedAction fixAllAction => new FixAllSuggestedAction( + codeRefactoringAction.CodeRefactoringProvider, codeRefactoringAction.OriginalCodeAction, + ConvertToSuggestedActionSet(codeRefactoringAction.FixAllFlavors, owner, subjectBuffer)), + UnifiedFixAllCodeFixSuggestedAction fixAllAction => new FixAllCodeFixSuggestedAction( ThreadingContext, owner, fixAllAction.Workspace, subjectBuffer, fixAllAction.FixAllState, fixAllAction.Diagnostic, fixAllAction.OriginalCodeAction), + UnifiedFixAllCodeRefactoringSuggestedAction fixAllCodeRefactoringAction => new FixAllCodeRefactoringSuggestedAction( + ThreadingContext, owner, fixAllCodeRefactoringAction.Workspace, subjectBuffer, + fixAllCodeRefactoringAction.FixAllState, fixAllCodeRefactoringAction.OriginalCodeAction), UnifiedSuggestedActionWithNestedActions nestedAction => new SuggestedActionWithNestedActions( ThreadingContext, owner, nestedAction.Workspace, subjectBuffer, nestedAction.Provider ?? this, nestedAction.OriginalCodeAction, diff --git a/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs b/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs index 370335e5799db..06c9643439d34 100644 --- a/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs +++ b/src/EditorFeatures/Core/AddImports/AbstractAddImportsPasteCommandHandler.cs @@ -3,19 +3,25 @@ // See the LICENSE file in the project root for more information. using System; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddMissingImports; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Editor.BackgroundWorkIndicator; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Commanding; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.AddImport { @@ -33,11 +39,16 @@ internal abstract class AbstractAddImportsPasteCommandHandler : IChainedCommandH private readonly IThreadingContext _threadingContext; private readonly IGlobalOptionService _globalOptions; + private readonly IAsynchronousOperationListener _listener; - public AbstractAddImportsPasteCommandHandler(IThreadingContext threadingContext, IGlobalOptionService globalOptions) + public AbstractAddImportsPasteCommandHandler( + IThreadingContext threadingContext, + IGlobalOptionService globalOptions, + IAsynchronousOperationListenerProvider listenerProvider) { _threadingContext = threadingContext; _globalOptions = globalOptions; + _listener = listenerProvider.GetListener(FeatureAttribute.AddImportsOnPaste); } public CommandState GetCommandState(PasteCommandArgs args, Func nextCommandHandler) @@ -101,7 +112,6 @@ private void ExecuteCommandWorker( // Applying the post-paste snapshot to the tracking span gives us the span of pasted text. var snapshotSpan = trackingSpan.GetSpan(args.SubjectBuffer.CurrentSnapshot); - var textSpan = snapshotSpan.Span.ToTextSpan(); var sourceTextContainer = args.SubjectBuffer.AsTextContainer(); if (!Workspace.TryGetWorkspace(sourceTextContainer, out var workspace)) @@ -115,32 +125,53 @@ private void ExecuteCommandWorker( return; } - using var _ = executionContext.OperationContext.AddScope(allowCancellation: true, DialogText); - var cancellationToken = executionContext.OperationContext.UserCancellationToken; + // We're showing our own UI, ensure the editor doesn't show anything itself. + executionContext.OperationContext.TakeOwnership(); + + var token = _listener.BeginAsyncOperation(nameof(ExecuteAsync)); + + ExecuteAsync(document, snapshotSpan, args.TextView) + .ReportNonFatalErrorAsync() + .CompletesAsyncOperation(token); + } + + private async Task ExecuteAsync(Document document, SnapshotSpan snapshotSpan, ITextView textView) + { + _threadingContext.ThrowIfNotOnUIThread(); + + var indicatorFactory = document.Project.Solution.Workspace.Services.GetRequiredService(); + using var backgroundWorkContext = indicatorFactory.Create( + textView, + snapshotSpan, + DialogText, + cancelOnEdit: true, + cancelOnFocusLost: true); + + var cancellationToken = backgroundWorkContext.UserCancellationToken; // We're going to log the same thing on success or failure since this blocks the UI thread. This measurement is // intended to tell us how long we're blocking the user from typing with this action. using var blockLogger = Logger.LogBlock(FunctionId.CommandHandler_Paste_ImportsOnPaste, KeyValueLogMessage.Create(LogType.UserAction), cancellationToken); var addMissingImportsService = document.GetRequiredLanguageService(); -#pragma warning disable VSTHRD102 // Implement internal logic asynchronously - var updatedDocument = _threadingContext.JoinableTaskFactory.Run(async () => - { - var cleanupOptions = await document.GetCodeCleanupOptionsAsync(_globalOptions, cancellationToken).ConfigureAwait(false); - var options = new AddMissingImportsOptions( - CleanupOptions: cleanupOptions, - HideAdvancedMembers: _globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, document.Project.Language)); + var cleanupOptions = await document.GetCodeCleanupOptionsAsync(_globalOptions, cancellationToken).ConfigureAwait(false); + + var options = new AddMissingImportsOptions( + CleanupOptions: cleanupOptions, + HideAdvancedMembers: _globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, document.Project.Language)); + + var textSpan = snapshotSpan.Span.ToTextSpan(); + var updatedDocument = await addMissingImportsService.AddMissingImportsAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); - return await addMissingImportsService.AddMissingImportsAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); - }); -#pragma warning restore VSTHRD102 // Implement internal logic asynchronously if (updatedDocument is null) { return; } - workspace.TryApplyChanges(updatedDocument.Project.Solution); + // Required to switch back to the UI thread to call TryApplyChanges + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + document.Project.Solution.Workspace.TryApplyChanges(updatedDocument.Project.Solution); } } } diff --git a/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs b/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs index 8f11792bd02a1..c4d13cb114611 100644 --- a/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs +++ b/src/EditorFeatures/Core/ChangeSignature/AbstractChangeSignatureCommandHandler.cs @@ -85,7 +85,7 @@ private bool ExecuteCommand(ITextView textView, ITextBuffer subjectBuffer, Comma document, caretPoint.Value.Position, restrictToDeclarations: false, - _globalOptions.GetCodeCleanupOptionsProvider(), + _globalOptions.CreateProvider(), cancellationToken).WaitAndGetResult(context.OperationContext.UserCancellationToken); // UI thread bound operation to show the change signature dialog. diff --git a/src/EditorFeatures/Core/Editor/EditorLayerExtensionManager.cs b/src/EditorFeatures/Core/Editor/EditorLayerExtensionManager.cs index 54c3cdacdadfd..c398cfa65ab82 100644 --- a/src/EditorFeatures/Core/Editor/EditorLayerExtensionManager.cs +++ b/src/EditorFeatures/Core/Editor/EditorLayerExtensionManager.cs @@ -69,7 +69,7 @@ public ExtensionManager( public override void HandleException(object provider, Exception exception) { - if (provider is CodeFixProvider or FixAllProvider or CodeRefactoringProvider) + if (provider is CodeFixProvider or CodeFixes.FixAllProvider or CodeRefactoringProvider or CodeRefactorings.FixAllProvider) { if (!IsIgnored(provider) && _globalOptions.GetOption(ExtensionManagerOptions.DisableCrashingExtensions)) diff --git a/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs b/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs index 0bdd99d48676a..e89c27b9aa4d0 100644 --- a/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs +++ b/src/EditorFeatures/Core/EncapsulateField/AbstractEncapsulateFieldCommandHandler.cs @@ -6,6 +6,7 @@ using System.Linq; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -71,12 +72,7 @@ private bool Execute(EncapsulateFieldCommandArgs args, IUIThreadOperationScope w var service = document.GetLanguageService(); - // The formatting and simplification options are only applied within the given document (and all linked documents). - // We can therefore fetch all necessary options for the language now rather then lazily, - // which would be needed if we had to apply them to documents of different languages. - var fallbackOptions = _globalOptions.GetCodeCleanupOptionsProvider(); - - var result = service.EncapsulateFieldsInSpanAsync(document, spans.First().Span.ToTextSpan(), fallbackOptions, useDefaultBehavior: true, cancellationToken).WaitAndGetResult(cancellationToken); + var result = service.EncapsulateFieldsInSpanAsync(document, spans.First().Span.ToTextSpan(), _globalOptions.CreateProvider(), useDefaultBehavior: true, cancellationToken).WaitAndGetResult(cancellationToken); // We are about to show a modal UI dialog so we should take over the command execution // wait context. That means the command system won't attempt to show its own wait dialog diff --git a/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs b/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs index 94b13eccf6795..193291410bdcd 100644 --- a/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs +++ b/src/EditorFeatures/Core/ExternalAccess/IntelliCode/IntentProcessor.cs @@ -9,11 +9,14 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.ExternalAccess.IntelliCode.Api; using Microsoft.CodeAnalysis.Features.Intents; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServer; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -25,12 +28,16 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.IntelliCode internal class IntentSourceProvider : IIntentSourceProvider { private readonly ImmutableDictionary<(string LanguageName, string IntentName), Lazy> _lazyIntentProviders; + private readonly IGlobalOptionService _globalOptions; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public IntentSourceProvider([ImportMany] IEnumerable> lazyIntentProviders) + public IntentSourceProvider( + [ImportMany] IEnumerable> lazyIntentProviders, + IGlobalOptionService globalOptions) { _lazyIntentProviders = CreateProviderMap(lazyIntentProviders); + _globalOptions = globalOptions; } private static ImmutableDictionary<(string LanguageName, string IntentName), Lazy> CreateProviderMap( @@ -70,8 +77,11 @@ public async Task> ComputeIntentsAsync(IntentReques originalDocument, selectionTextSpan, currentDocument, - new IntentDataProvider(intentRequestContext.IntentData), + new IntentDataProvider( + intentRequestContext.IntentData, + _globalOptions.CreateProvider()), cancellationToken).ConfigureAwait(false); + if (results.IsDefaultOrEmpty) { return ImmutableArray.Empty; diff --git a/src/EditorFeatures/Core/ExtractInterface/AbstractExtractInterfaceCommandHandler.cs b/src/EditorFeatures/Core/ExtractInterface/AbstractExtractInterfaceCommandHandler.cs index ff279827e1d60..5e3ce81d926ee 100644 --- a/src/EditorFeatures/Core/ExtractInterface/AbstractExtractInterfaceCommandHandler.cs +++ b/src/EditorFeatures/Core/ExtractInterface/AbstractExtractInterfaceCommandHandler.cs @@ -6,6 +6,7 @@ using System.Threading; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Navigation; @@ -68,7 +69,7 @@ public bool ExecuteCommand(ExtractInterfaceCommandArgs args, CommandExecutionCon var result = await extractInterfaceService.ExtractInterfaceAsync( document, caretPoint.Value.Position, - _globalOptions.GetCodeCleanupOptionsProvider(), + _globalOptions.CreateProvider(), (errorMessage, severity) => workspace.Services.GetService().SendNotification(errorMessage, severity: severity), CancellationToken.None).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core/ExtractMethod/AbstractExtractMethodCommandHandler.cs b/src/EditorFeatures/Core/ExtractMethod/AbstractExtractMethodCommandHandler.cs index 633737d0cbc42..d9f0fa895e64c 100644 --- a/src/EditorFeatures/Core/ExtractMethod/AbstractExtractMethodCommandHandler.cs +++ b/src/EditorFeatures/Core/ExtractMethod/AbstractExtractMethodCommandHandler.cs @@ -107,7 +107,7 @@ private bool Execute( return false; } - var options = _globalOptions.GetExtractMethodOptions(document.Project.Language); + var options = document.GetExtractMethodGenerationOptionsAsync(_globalOptions, cancellationToken).AsTask().WaitAndGetResult(cancellationToken); var result = ExtractMethodService.ExtractMethodAsync( document, spans.Single().Span.ToTextSpan(), localFunction: false, options, cancellationToken).WaitAndGetResult(cancellationToken); Contract.ThrowIfNull(result); @@ -217,9 +217,9 @@ private bool TryNotifyFailureToUser(Document document, ExtractMethodResult resul } private static ExtractMethodResult TryWithoutMakingValueTypesRef( - Document document, NormalizedSnapshotSpanCollection spans, ExtractMethodResult result, ExtractMethodOptions options, CancellationToken cancellationToken) + Document document, NormalizedSnapshotSpanCollection spans, ExtractMethodResult result, ExtractMethodGenerationOptions options, CancellationToken cancellationToken) { - if (options.DontPutOutOrRefOnStruct || !result.Reasons.IsSingle()) + if (options.ExtractOptions.DontPutOutOrRefOnStruct || !result.Reasons.IsSingle()) { return null; } @@ -232,7 +232,7 @@ private static ExtractMethodResult TryWithoutMakingValueTypesRef( document, spans.Single().Span.ToTextSpan(), localFunction: false, - options with { DontPutOutOrRefOnStruct = true }, + options with { ExtractOptions = options.ExtractOptions with { DontPutOutOrRefOnStruct = true } }, cancellationToken).WaitAndGetResult(cancellationToken); // retry succeeded, return new result diff --git a/src/EditorFeatures/Core/InheritanceMargin/AbstractInheritanceMarginService.cs b/src/EditorFeatures/Core/InheritanceMargin/AbstractInheritanceMarginService.cs deleted file mode 100644 index 19ccfd66c8666..0000000000000 --- a/src/EditorFeatures/Core/InheritanceMargin/AbstractInheritanceMarginService.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.SymbolMapping; -using Microsoft.CodeAnalysis.Text; -using static Microsoft.CodeAnalysis.InheritanceMargin.InheritanceMarginServiceHelper; - -namespace Microsoft.CodeAnalysis.InheritanceMargin -{ - internal abstract class AbstractInheritanceMarginService : IInheritanceMarginService - { - /// - /// Given the syntax nodes to search, - /// get all the method, event, property and type declaration syntax nodes. - /// - protected abstract ImmutableArray GetMembers(IEnumerable nodesToSearch); - - /// - /// Get the token that represents declaration node. - /// e.g. Identifier for method/property/event and this keyword for indexer. - /// - protected abstract SyntaxToken GetDeclarationToken(SyntaxNode declarationNode); - - public async ValueTask> GetInheritanceMemberItemsAsync( - Document document, - TextSpan spanToSearch, - CancellationToken cancellationToken) - { - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var allDeclarationNodes = GetMembers(root.DescendantNodes(spanToSearch)); - if (allDeclarationNodes.IsEmpty) - { - return ImmutableArray.Empty; - } - - var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - - var mappingService = document.Project.Solution.Workspace.Services.GetRequiredService(); - using var _ = ArrayBuilder<(SymbolKey symbolKey, int lineNumber)>.GetInstance(out var builder); - - Project? project = null; - - foreach (var memberDeclarationNode in allDeclarationNodes) - { - var member = semanticModel.GetDeclaredSymbol(memberDeclarationNode, cancellationToken); - if (member == null || !CanHaveInheritanceTarget(member)) - { - continue; - } - - // Use mapping service to find correct solution & symbol. (e.g. metadata symbol) - var mappingResult = await mappingService.MapSymbolAsync(document, member, cancellationToken).ConfigureAwait(false); - if (mappingResult == null) - { - continue; - } - - // All the symbols here are declared in the same document, they should belong to the same project. - // So here it is enough to get the project once. - project ??= mappingResult.Project; - builder.Add((mappingResult.Symbol.GetSymbolKey(cancellationToken), sourceText.Lines.GetLineFromPosition(GetDeclarationToken(memberDeclarationNode).SpanStart).LineNumber)); - } - - var symbolKeyAndLineNumbers = builder.ToImmutable(); - if (symbolKeyAndLineNumbers.IsEmpty || project == null) - { - return ImmutableArray.Empty; - } - - var solution = project.Solution; - var serializedInheritanceMarginItems = await GetInheritanceMemberItemAsync( - solution, - project.Id, - symbolKeyAndLineNumbers, - cancellationToken).ConfigureAwait(false); - return await serializedInheritanceMarginItems.SelectAsArrayAsync( - (serializedItem, _) => InheritanceMarginItem.ConvertAsync(solution, serializedItem, cancellationToken), cancellationToken).ConfigureAwait(false); - } - - private static bool CanHaveInheritanceTarget(ISymbol symbol) - { - if (symbol is INamedTypeSymbol namedType) - { - return !symbol.IsStatic && namedType.TypeKind is TypeKind.Interface or TypeKind.Class or TypeKind.Struct; - } - - if (symbol is IEventSymbol or IPropertySymbol - or IMethodSymbol - { - MethodKind: MethodKind.Ordinary or MethodKind.ExplicitInterfaceImplementation or MethodKind.UserDefinedOperator or MethodKind.Conversion - }) - { - return true; - } - - return false; - } - } -} diff --git a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs index 579c35e6894b8..a89dc3270fcf8 100644 --- a/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs +++ b/src/EditorFeatures/Core/InlineRename/AbstractEditorInlineRenameService.cs @@ -165,7 +165,7 @@ private async Task GetRenameInfoAsync( var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var triggerText = sourceText.ToString(triggerToken.Span); - var fallbackOptions = _globalOptions.GetCodeCleanupOptionsProvider(); + var fallbackOptions = _globalOptions.CreateProvider(); return new SymbolInlineRenameInfo( refactorNotifyServices, document, triggerToken.Span, triggerText, diff --git a/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs b/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs index a8e9fe805822e..21482d0df91f7 100644 --- a/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs +++ b/src/EditorFeatures/Core/Remote/SolutionChecksumUpdater.cs @@ -25,8 +25,8 @@ internal sealed class SolutionChecksumUpdater : GlobalOperationAwareIdleProcesso { private readonly Workspace _workspace; private readonly TaskQueue _textChangeQueue; - private readonly AsyncQueue _workQueue; - private readonly object _gate; + private readonly AsyncQueue _workQueue = new(); + private readonly object _gate = new(); private CancellationTokenSource _globalOperationCancellationSource; @@ -41,9 +41,6 @@ public SolutionChecksumUpdater(Workspace workspace, IGlobalOptionService globalO _workspace = workspace; _textChangeQueue = new TaskQueue(Listener, TaskScheduler.Default); - _workQueue = new AsyncQueue(); - _gate = new object(); - // start listening workspace change event _workspace.WorkspaceChanged += OnWorkspaceChanged; diff --git a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs index 0fcfd77ae9f4d..3b78bb71fba2e 100644 --- a/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs +++ b/src/EditorFeatures/Core/RenameTracking/RenameTrackingTaggerProvider.TrackingSession.cs @@ -38,7 +38,7 @@ private class TrackingSession { private static readonly Task s_notRenamableTask = Task.FromResult(TriggerIdentifierKind.NotRenamable); private readonly Task _isRenamableIdentifierTask; - private readonly CancellationTokenSource _cancellationTokenSource; + private readonly CancellationTokenSource _cancellationTokenSource = new(); private readonly CancellationToken _cancellationToken; private readonly IThreadingContext _threadingContext; private readonly IAsynchronousOperationListener _asyncListener; @@ -62,7 +62,6 @@ public TrackingSession( _threadingContext = stateMachine.ThreadingContext; _asyncListener = asyncListener; _trackingSpan = snapshotSpan.Snapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeInclusive); - _cancellationTokenSource = new CancellationTokenSource(); _cancellationToken = _cancellationTokenSource.Token; if (snapshotSpan.Length > 0) diff --git a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs index c212a035f2aed..f54e8a00d40ab 100644 --- a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs +++ b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs @@ -114,10 +114,18 @@ public FeatureOnOffOptions() FeatureName, "InheritanceMarginCombinedWithIndicatorMargin", defaultValue: false, new RoamingProfileStorageLocation("TextEditor.InheritanceMarginCombinedWithIndicatorMargin")); + public static readonly PerLanguageOption2 InheritanceMarginIncludeGlobalImports = new( + FeatureName, "InheritanceMarginIncludeGlobalImports", defaultValue: true, + new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.InheritanceMarginIncludeGlobalImports")); + public static readonly Option2 AutomaticallyCompleteStatementOnSemicolon = new( FeatureName, "AutomaticallyCompleteStatementOnSemicolon", defaultValue: true, storageLocation: new RoamingProfileStorageLocation("TextEditor.AutomaticallyCompleteStatementOnSemicolon")); + public static readonly PerLanguageOption2 AutomaticallyFixStringContentsOnPaste = new( + FeatureName, "AutomaticallyFixStringContentsOnPaste", defaultValue: true, + storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.AutomaticallyFixStringContentsOnPaste")); + /// /// Not used by Roslyn but exposed in C# and VB option UI. Used by TestWindow and Project System. /// TODO: remove https://github.com/dotnet/roslyn/issues/57253 diff --git a/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs b/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs index 493641992f764..55417f60feac4 100644 --- a/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs +++ b/src/EditorFeatures/Core/Shared/Preview/PreviewSolutionCrawlerRegistrationService.cs @@ -45,7 +45,7 @@ internal class Service : ISolutionCrawlerRegistrationService { private readonly PreviewSolutionCrawlerRegistrationServiceFactory _owner; private readonly Workspace _workspace; - private readonly CancellationTokenSource _source; + private readonly CancellationTokenSource _source = new(); // since we now have one service for each one specific instance of workspace, // we can have states for this specific workspace. @@ -55,7 +55,6 @@ public Service(PreviewSolutionCrawlerRegistrationServiceFactory owner, Workspace { _owner = owner; _workspace = workspace; - _source = new CancellationTokenSource(); } public void Register(Workspace workspace) diff --git a/src/EditorFeatures/Core/Shared/Utilities/HACK_TextUndoTransactionThatRollsBackProperly.cs b/src/EditorFeatures/Core/Shared/Utilities/HACK_TextUndoTransactionThatRollsBackProperly.cs index 50cd40d6b7c7b..55c19087b5b34 100644 --- a/src/EditorFeatures/Core/Shared/Utilities/HACK_TextUndoTransactionThatRollsBackProperly.cs +++ b/src/EditorFeatures/Core/Shared/Utilities/HACK_TextUndoTransactionThatRollsBackProperly.cs @@ -20,14 +20,13 @@ namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities internal sealed class HACK_TextUndoTransactionThatRollsBackProperly : ITextUndoTransaction { private readonly ITextUndoTransaction _innerTransaction; - private readonly RollbackDetectingUndoPrimitive _undoPrimitive; + private readonly RollbackDetectingUndoPrimitive _undoPrimitive = new(); private bool _transactionOpen = true; public HACK_TextUndoTransactionThatRollsBackProperly(ITextUndoTransaction innerTransaction) { _innerTransaction = innerTransaction; - _undoPrimitive = new RollbackDetectingUndoPrimitive(); } public bool CanRedo => _innerTransaction.CanRedo; diff --git a/src/EditorFeatures/Core/Shared/Utilities/LinkedEditsTracker.cs b/src/EditorFeatures/Core/Shared/Utilities/LinkedEditsTracker.cs index 9e8ce6bcd621f..d47bf18bc794a 100644 --- a/src/EditorFeatures/Core/Shared/Utilities/LinkedEditsTracker.cs +++ b/src/EditorFeatures/Core/Shared/Utilities/LinkedEditsTracker.cs @@ -20,13 +20,12 @@ internal class LinkedEditsTracker /// /// The list of active tracking spans. /// - private readonly List _trackingSpans; + private readonly List _trackingSpans = new(); public LinkedEditsTracker(ITextBuffer subjectBuffer) { Contract.ThrowIfNull(subjectBuffer); - _trackingSpans = new List(); _subjectBuffer = subjectBuffer; } diff --git a/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs b/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs index 1c7bc23867509..0aafb145bcaeb 100644 --- a/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs +++ b/src/EditorFeatures/Core/Shared/Utilities/ResettableDelay.cs @@ -15,7 +15,7 @@ internal class ResettableDelay public static readonly ResettableDelay CompletedDelay = new(); private readonly int _delayInMilliseconds; - private readonly TaskCompletionSource _taskCompletionSource; + private readonly TaskCompletionSource _taskCompletionSource = new(); private int _lastSetTime; @@ -30,7 +30,6 @@ public ResettableDelay(int delayInMilliseconds, IExpeditableDelaySource expedita Contract.ThrowIfFalse(delayInMilliseconds >= 50, "Perf, only use delays >= 50ms"); _delayInMilliseconds = delayInMilliseconds; - _taskCompletionSource = new TaskCompletionSource(); Reset(); _ = StartTimerAsync(expeditableDelaySource, cancellationToken); diff --git a/src/EditorFeatures/Core/Tagging/CompilationAvailableTaggerEventSource.cs b/src/EditorFeatures/Core/Tagging/CompilationAvailableTaggerEventSource.cs index e50b367f1defb..831e25d6e8df9 100644 --- a/src/EditorFeatures/Core/Tagging/CompilationAvailableTaggerEventSource.cs +++ b/src/EditorFeatures/Core/Tagging/CompilationAvailableTaggerEventSource.cs @@ -3,11 +3,13 @@ // See the LICENSE file in the project root for more information. using System; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Tagging; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Tagging; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; @@ -29,7 +31,6 @@ namespace Microsoft.CodeAnalysis.Editor.Tagging internal sealed class CompilationAvailableTaggerEventSource : ITaggerEventSource { private readonly ITextBuffer _subjectBuffer; - private readonly IAsynchronousOperationListener _asyncListener; /// /// Other event sources we're composing over. If they fire, we should reclassify. However, after they fire, we @@ -37,10 +38,9 @@ internal sealed class CompilationAvailableTaggerEventSource : ITaggerEventSource /// private readonly ITaggerEventSource _underlyingSource; - /// - /// Cancellation tokens controlling background computation of the compilation. - /// - private readonly ReferenceCountedDisposable _cancellationSeries = new(new CancellationSeries()); + private readonly CompilationAvailableEventSource _eventSource; + + private readonly Action _onCompilationAvailable; public CompilationAvailableTaggerEventSource( ITextBuffer subjectBuffer, @@ -48,8 +48,9 @@ public CompilationAvailableTaggerEventSource( params ITaggerEventSource[] eventSources) { _subjectBuffer = subjectBuffer; - _asyncListener = asyncListener; + _eventSource = new CompilationAvailableEventSource(asyncListener); _underlyingSource = TaggerEventSources.Compose(eventSources); + _onCompilationAvailable = () => this.Changed?.Invoke(this, new TaggerEventArgs()); } public event EventHandler? Changed; @@ -58,14 +59,14 @@ public void Connect() { // When we are connected to, connect to all our underlying sources and have them notify us when they've changed. _underlyingSource.Connect(); - _underlyingSource.Changed += OnEventSourceChanged; + _underlyingSource.Changed += OnUnderlyingSourceChanged; } public void Disconnect() { - _underlyingSource.Changed -= OnEventSourceChanged; + _underlyingSource.Changed -= OnUnderlyingSourceChanged; _underlyingSource.Disconnect(); - _cancellationSeries.Dispose(); + _eventSource.Dispose(); } public void Pause() @@ -74,7 +75,7 @@ public void Pause() public void Resume() => _underlyingSource.Resume(); - private void OnEventSourceChanged(object? sender, TaggerEventArgs args) + private void OnUnderlyingSourceChanged(object? sender, TaggerEventArgs args) { // First, notify anyone listening to us that something definitely changed. this.Changed?.Invoke(this, args); @@ -83,55 +84,7 @@ private void OnEventSourceChanged(object? sender, TaggerEventArgs args) if (document == null) return; - if (!document.SupportsSemanticModel) - return; - - using var cancellationSeries = _cancellationSeries.TryAddReference(); - if (cancellationSeries is null) - { - // Already in the process of disposing this instance - return; - } - - // Cancel any existing tasks that are computing the compilation and spawn a new one to compute - // it and notify any listening clients. - var cancellationToken = cancellationSeries.Target.CreateNext(); - - var token = _asyncListener.BeginAsyncOperation(nameof(OnEventSourceChanged)); - var task = Task.Run(async () => - { - // Support cancellation without throwing. - // - // We choose a long delay here so that we can avoid this work as long as the user is continually making - // changes to their code. During that time, features that use this are already kicking off fast work - // with frozen-partial semantics and we'd like that to not have to contend with more expensive work - // kicked off in OOP to compute full compilations. - await _asyncListener.Delay(DelayTimeSpan.NonFocus, cancellationToken).NoThrowAwaitable(captureContext: false); - if (cancellationToken.IsCancellationRequested) - return; - - var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); - if (client != null) - { - var result = await client.TryInvokeAsync( - document.Project, - (service, solutionInfo, cancellationToken) => service.ComputeCompilationAsync(solutionInfo, document.Project.Id, cancellationToken), - cancellationToken).ConfigureAwait(false); - - if (!result) - return; - } - else - { - // if we can't get the client, just compute the compilation locally and fire the event once we have it. - await CompilationAvailableHelpers.ComputeCompilationInCurrentProcessAsync(document.Project, cancellationToken).ConfigureAwait(false); - } - - // now that we know we have an full compilation, retrigger the tagger so it can show accurate results with the - // full information about this project. - this.Changed?.Invoke(this, new TaggerEventArgs()); - }, cancellationToken); - task.CompletesAsyncOperation(token); + _eventSource.EnsureCompilationAvailability(document.Project, _onCompilationAvailable); } } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs index a727777fbd24a..f2c748ac30d8c 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/ChangeSignature/ChangeSignatureTestState.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.CodeAnalysis.ChangeSignature; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; @@ -80,14 +81,14 @@ public TestChangeSignatureOptionsService TestChangeSignatureOptionsService public async Task ChangeSignatureAsync() { - var context = await ChangeSignatureService.GetChangeSignatureContextAsync(InvocationDocument, _testDocument.CursorPosition.Value, restrictToDeclarations: false, CodeCleanupOptions.GetDefaultAsync, CancellationToken.None).ConfigureAwait(false); + var context = await ChangeSignatureService.GetChangeSignatureContextAsync(InvocationDocument, _testDocument.CursorPosition.Value, restrictToDeclarations: false, CodeActionOptions.DefaultProvider, CancellationToken.None).ConfigureAwait(false); var options = AbstractChangeSignatureService.GetChangeSignatureOptions(context); return await ChangeSignatureService.ChangeSignatureWithContextAsync(context, options, CancellationToken.None); } public async Task GetParameterConfigurationAsync() { - var context = await ChangeSignatureService.GetChangeSignatureContextAsync(InvocationDocument, _testDocument.CursorPosition.Value, restrictToDeclarations: false, CodeCleanupOptions.GetDefaultAsync, CancellationToken.None); + var context = await ChangeSignatureService.GetChangeSignatureContextAsync(InvocationDocument, _testDocument.CursorPosition.Value, restrictToDeclarations: false, CodeActionOptions.DefaultProvider, CancellationToken.None); if (context is ChangeSignatureAnalysisSucceededContext changeSignatureAnalyzedSucceedContext) { return changeSignatureAnalyzedSucceedContext.ParameterConfiguration; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs index 639e0b3bcc336..e1247941c7252 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs @@ -32,11 +32,12 @@ using Roslyn.Utilities; using Xunit; using Xunit.Abstractions; +using Microsoft.CodeAnalysis.Options; -#if CODE_STYLE using System.Diagnostics; using System.IO; -#else + +#if !CODE_STYLE using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions; #endif @@ -47,9 +48,11 @@ public abstract partial class AbstractCodeActionOrUserDiagnosticTest { public sealed class TestParameters { - internal readonly CodeActionOptions codeActionOptions; - internal readonly IdeAnalyzerOptions ideAnalyzerOptions; + /// + /// editorconfig options. + /// internal readonly OptionsCollection options; + internal readonly OptionsCollection globalOptions; internal readonly TestHost testHost; internal readonly string workspaceKind; internal readonly object fixProviderData; @@ -65,8 +68,7 @@ internal TestParameters( ParseOptions parseOptions = null, CompilationOptions compilationOptions = null, OptionsCollection options = null, - CodeActionOptions? codeActionOptions = null, - IdeAnalyzerOptions ideAnalyzerOptions = null, + OptionsCollection globalOptions = null, object fixProviderData = null, int index = 0, CodeActionPriority? priority = null, @@ -79,8 +81,7 @@ internal TestParameters( this.parseOptions = parseOptions; this.compilationOptions = compilationOptions; this.options = options; - this.codeActionOptions = codeActionOptions ?? CodeActionOptions.Default; - this.ideAnalyzerOptions = ideAnalyzerOptions ?? IdeAnalyzerOptions.CodeStyleDefault; + this.globalOptions = globalOptions; this.fixProviderData = fixProviderData; this.index = index; this.priority = priority; @@ -94,34 +95,31 @@ internal TestParameters( public static readonly TestParameters Default = new(parseOptions: null); public TestParameters WithParseOptions(ParseOptions parseOptions) - => new(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithCompilationOptions(CompilationOptions compilationOptions) - => new(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); internal TestParameters WithOptions(OptionsCollection options) - => new(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); - - internal TestParameters WithCodeActionOptions(CodeActionOptions codeActionOptions) - => new(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); - internal TestParameters WithIdeAnalyzerOptions(IdeAnalyzerOptions ideAnalyzerOptions) - => new(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + internal TestParameters WithGlobalOptions(OptionsCollection globalOptions) + => new(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithFixProviderData(object fixProviderData) - => new(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithIndex(int index) - => new(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithRetainNonFixableDiagnostics(bool retainNonFixableDiagnostics) - => new(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithIncludeDiagnosticsOutsideSelection(bool includeDiagnosticsOutsideSelection) - => new(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); public TestParameters WithWorkspaceKind(string workspaceKind) - => new(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); + => new(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, retainNonFixableDiagnostics, includeDiagnosticsOutsideSelection, title, testHost, workspaceKind); } #pragma warning disable IDE0052 // Remove unread private members (unused when CODE_STYLE is set) @@ -176,11 +174,7 @@ protected TestWorkspace CreateWorkspaceFromOptions(string workspaceMarkupOrCode, #endif InitializeWorkspace(workspace, parameters); - // For CodeStyle layer testing, we create an .editorconfig at project root - // to apply the options as workspace options are not available in CodeStyle layer. - // Otherwise, we apply the options directly to the workspace. - -#if CODE_STYLE + // We create an .editorconfig at project root to apply the options. // We need to ensure that our projects/documents are rooted for // execution from CodeStyle layer as we will be adding a rooted .editorconfig to each project // to apply the options. @@ -189,15 +183,19 @@ protected TestWorkspace CreateWorkspaceFromOptions(string workspaceMarkupOrCode, MakeProjectsAndDocumentsRooted(workspace); AddAnalyzerConfigDocumentWithOptions(workspace, parameters.options); } -#else + +#if !CODE_STYLE workspace.ApplyOptions(parameters.options); + + if (parameters.globalOptions != null) + { + workspace.ApplyOptions(parameters.globalOptions); + parameters.globalOptions.SetGlobalOptions(workspace.GlobalOptions); + } #endif - // we need to set global options since the tests are going thru incremental diagnostic analyzer that reads them from there: - workspace.GlobalOptions.SetIdeAnalyzerOptions(GetLanguage(), parameters.ideAnalyzerOptions); return workspace; } -#if CODE_STYLE private static void MakeProjectsAndDocumentsRooted(TestWorkspace workspace) { const string defaultRootFilePath = @"z:\"; @@ -269,7 +267,6 @@ string GenerateAnalyzerConfigText(OptionsCollection options) return textBuilder.ToString(); } } -#endif private static TestParameters WithRegularOptions(TestParameters parameters) => parameters.WithParseOptions(parameters.parseOptions?.WithKind(SourceCodeKind.Regular)); @@ -387,8 +384,7 @@ internal Task TestInRegularAndScriptAsync( CodeActionPriority? priority = null, CompilationOptions compilationOptions = null, OptionsCollection options = null, - CodeActionOptions? codeActionOptions = null, - IdeAnalyzerOptions ideAnalyzerOptions = null, + OptionsCollection globalOptions = null, object fixProviderData = null, ParseOptions parseOptions = null, string title = null, @@ -396,7 +392,7 @@ internal Task TestInRegularAndScriptAsync( { return TestInRegularAndScript1Async( initialMarkup, expectedMarkup, - new TestParameters(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, title: title, testHost: testHost)); + new TestParameters(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, title: title, testHost: testHost)); } internal Task TestInRegularAndScript1Async( @@ -429,8 +425,7 @@ internal Task TestAsync( CompilationOptions compilationOptions = null, int index = 0, OptionsCollection options = null, - CodeActionOptions? codeActionOptions = null, - IdeAnalyzerOptions ideAnalyzerOptions = null, + OptionsCollection globalOptions = null, object fixProviderData = null, CodeActionPriority? priority = null, TestHost testHost = TestHost.InProcess) @@ -438,7 +433,7 @@ internal Task TestAsync( return TestAsync( initialMarkup, expectedMarkup, - new TestParameters(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData, index, priority, testHost: testHost)); + new TestParameters(parseOptions, compilationOptions, options, globalOptions, fixProviderData, index, priority, testHost: testHost)); } private async Task TestAsync( @@ -895,5 +890,72 @@ protected async Task TestAllInRegularAndScriptAsync( await TestActionCountAsync(input, outputs.Length, parameters); } + + protected static void GetDocumentAndSelectSpanOrAnnotatedSpan( + TestWorkspace workspace, + out Document document, + out TextSpan span, + out string annotation) + { + annotation = null; + if (!TryGetDocumentAndSelectSpan(workspace, out document, out span)) + { + document = GetDocumentAndAnnotatedSpan(workspace, out annotation, out span); + } + } + + private static bool TryGetDocumentAndSelectSpan(TestWorkspace workspace, out Document document, out TextSpan span) + { + var hostDocument = workspace.Documents.FirstOrDefault(d => d.SelectedSpans.Any()); + if (hostDocument == null) + { + // If there wasn't a span, see if there was a $$ caret. we'll create an empty span + // there if so. + hostDocument = workspace.Documents.FirstOrDefault(d => d.CursorPosition != null); + if (hostDocument == null) + { + document = null; + span = default; + return false; + } + + span = new TextSpan(hostDocument.CursorPosition.Value, 0); + document = workspace.CurrentSolution.GetDocument(hostDocument.Id); + return true; + } + + span = hostDocument.SelectedSpans.Single(); + document = workspace.CurrentSolution.GetDocument(hostDocument.Id); + return true; + } + + private static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, out string annotation, out TextSpan span) + { + var annotatedDocuments = workspace.Documents.Where(d => d.AnnotatedSpans.Any()); + var hostDocument = annotatedDocuments.Single(); + var annotatedSpan = hostDocument.AnnotatedSpans.Single(); + annotation = annotatedSpan.Key; + span = annotatedSpan.Value.Single(); + return workspace.CurrentSolution.GetDocument(hostDocument.Id); + } + + protected static FixAllScope? GetFixAllScope(string annotation) + { + if (annotation == null) + { + return null; + } + + return annotation switch + { + "FixAllInDocument" => FixAllScope.Document, + "FixAllInProject" => FixAllScope.Project, + "FixAllInSolution" => FixAllScope.Solution, + "FixAllInContainingMember" => FixAllScope.ContainingMember, + "FixAllInContainingType" => FixAllScope.ContainingType, + "FixAllInSelection" => FixAllScope.Custom, + _ => throw new InvalidProgramException("Incorrect FixAll annotation in test"), + }; + } } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs index e6d98f7751676..6c881dc7e2d13 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionTest.cs @@ -5,25 +5,27 @@ #nullable disable using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editor.Implementation.Preview; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PickMembers; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using Xunit; +using FixAllScope = Microsoft.CodeAnalysis.CodeFixes.FixAllScope; namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions { @@ -37,12 +39,49 @@ protected abstract CodeRefactoringProvider CreateCodeRefactoringProvider( { parameters ??= TestParameters.Default; + GetDocumentAndSelectSpanOrAnnotatedSpan(workspace, out var document, out var span, out var annotation); + var refactoring = await GetCodeRefactoringAsync(workspace, parameters); var actions = refactoring == null ? ImmutableArray.Empty : refactoring.CodeActions.Select(n => n.action).AsImmutable(); actions = MassageActions(actions); - return (actions, actions.IsDefaultOrEmpty ? null : actions[parameters.index]); + + var fixAllScope = GetFixAllScope(annotation); + + if (fixAllScope is FixAllScope.ContainingMember or FixAllScope.ContainingType && + document.GetLanguageService() is IFixAllSpanMappingService spanMappingService) + { + var documentsAndSpansToFix = await spanMappingService.GetFixAllSpansAsync( + document, span, fixAllScope.Value, CancellationToken.None).ConfigureAwait(false); + if (documentsAndSpansToFix.IsEmpty) + { + return (ImmutableArray.Empty, null); + } + } + + var actionToInvoke = actions.IsDefaultOrEmpty ? null : actions[parameters.index]; + if (actionToInvoke == null || fixAllScope == null) + return (actions, actionToInvoke); + + var fixAllCodeAction = await GetFixAllFixAsync(actionToInvoke, + refactoring.Provider, document, span, fixAllScope.Value).ConfigureAwait(false); + return (ImmutableArray.Create(fixAllCodeAction), fixAllCodeAction); + } + + private static async Task GetFixAllFixAsync( + CodeAction originalCodeAction, + CodeRefactoringProvider provider, + Document document, + TextSpan selectionSpan, + FixAllScope scope) + { + var fixAllProvider = provider.GetFixAllProvider(); + Assert.NotNull(fixAllProvider); + + var fixAllState = new FixAllState(fixAllProvider, document, selectionSpan, provider, scope, originalCodeAction); + var fixAllContext = new FixAllContext(fixAllState, new ProgressTracker(), CancellationToken.None); + return await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false); } protected override Task> GetDiagnosticsWorkerAsync(TestWorkspace workspace, TestParameters parameters) @@ -50,18 +89,28 @@ protected override Task> GetDiagnosticsWorkerAsync(Te internal async Task GetCodeRefactoringAsync( TestWorkspace workspace, TestParameters parameters) + { + GetDocumentAndSelectSpanOrAnnotatedSpan(workspace, out var document, out var span, out _); + return await GetCodeRefactoringAsync(document, span, workspace, parameters).ConfigureAwait(false); + } + + internal async Task GetCodeRefactoringAsync( + Document document, + TextSpan selectedOrAnnotatedSpan, + TestWorkspace workspace, + TestParameters parameters) { var provider = CreateCodeRefactoringProvider(workspace, parameters); - var documentsWithSelections = workspace.Documents.Where(d => !d.IsLinkFile && d.SelectedSpans.Count == 1); - Debug.Assert(documentsWithSelections.Count() == 1, "One document must have a single span annotation"); - var span = documentsWithSelections.Single().SelectedSpans.Single(); var actions = ArrayBuilder<(CodeAction, TextSpan?)>.GetInstance(); - var document = workspace.CurrentSolution.GetDocument(documentsWithSelections.Single().Id); - var context = new CodeRefactoringContext(document, span, (a, t) => actions.Add((a, t)), _ => parameters.codeActionOptions, CancellationToken.None); - await provider.ComputeRefactoringsAsync(context); - var result = actions.Count > 0 ? new CodeRefactoring(provider, actions.ToImmutable()) : null; + var codeActionOptionsProvider = parameters.globalOptions?.IsEmpty() == false ? + CodeActionOptionsStorage.GetCodeActionOptionsProvider(workspace.GlobalOptions) : + CodeActionOptions.DefaultProvider; + + var context = new CodeRefactoringContext(document, selectedOrAnnotatedSpan, (a, t) => actions.Add((a, t)), codeActionOptionsProvider, CancellationToken.None); + await provider.ComputeRefactoringsAsync(context); + var result = actions.Count > 0 ? new CodeRefactoring(provider, actions.ToImmutable(), FixAllProviderInfo.Create(provider)) : null; actions.Free(); return result; } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs index 0330cb640b1ae..1ec111c9f6834 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs @@ -109,7 +109,7 @@ protected override AnalyzerOptions GetAnalyzerOptions(Project project) => new WorkspaceAnalyzerOptions(base.GetAnalyzerOptions(project), project.Solution, _sharedState.GetIdeAnalyzerOptions(project)); protected override CodeFixContext CreateCodeFixContext(Document document, TextSpan span, ImmutableArray diagnostics, Action> registerCodeFix, CancellationToken cancellationToken) - => new(document, span, diagnostics, registerCodeFix, _ => _sharedState.CodeActionOptions, cancellationToken); + => new(document, span, diagnostics, registerCodeFix, new DelegatingCodeActionOptionsProvider(_ => _sharedState.CodeActionOptions), cancellationToken); protected override FixAllContext CreateFixAllContext( Document? document, @@ -121,7 +121,7 @@ protected override FixAllContext CreateFixAllContext( FixAllContext.DiagnosticProvider fixAllDiagnosticProvider, CancellationToken cancellationToken) => new(new FixAllState( - fixAllProvider: null, + fixAllProvider: NoOpFixAllProvider.Instance, diagnosticSpan: null, document, project, @@ -130,7 +130,7 @@ protected override FixAllContext CreateFixAllContext( codeActionEquivalenceKey, diagnosticIds, fixAllDiagnosticProvider, - _ => _sharedState.CodeActionOptions), + new DelegatingCodeActionOptionsProvider(_ => _sharedState.CodeActionOptions)), new ProgressTracker(), cancellationToken); #endif diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CodeFixVerifierHelper.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CodeFixVerifierHelper.cs index 32b2ecc56dceb..79a2b25270bfe 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CodeFixVerifierHelper.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/CodeFixVerifierHelper.cs @@ -4,8 +4,11 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Options; @@ -119,6 +122,13 @@ public static (SourceText? analyzerConfig, IEnumerable throw new NotImplementedException(); + } +#endif } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs index 5ce7914a7bd14..cebfbdbbc6b3c 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs @@ -158,13 +158,9 @@ internal override async Task> GetDiagnosticsAsync( var (analyzer, fixer) = GetOrCreateDiagnosticProviderAndFixer(workspace, parameters); AddAnalyzerToWorkspace(workspace, analyzer, parameters); - string annotation = null; - if (!TryGetDocumentAndSelectSpan(workspace, out var document, out var span)) - { - document = GetDocumentAndAnnotatedSpan(workspace, out annotation, out span); - } + GetDocumentAndSelectSpanOrAnnotatedSpan(workspace, out var document, out var span, out var annotation); - var testDriver = new TestDiagnosticAnalyzerDriver(workspace, document.Project); + var testDriver = new TestDiagnosticAnalyzerDriver(workspace); var filterSpan = parameters.includeDiagnosticsOutsideSelection ? (TextSpan?)null : span; var diagnostics = (await testDriver.GetAllDiagnosticsAsync(document, filterSpan)).ToImmutableArray(); AssertNoAnalyzerExceptionDiagnostics(diagnostics); @@ -177,7 +173,7 @@ internal override async Task> GetDiagnosticsAsync( var ids = new HashSet(fixer.FixableDiagnosticIds); var dxs = diagnostics.Where(d => ids.Contains(d.Id)).ToList(); var (resultDiagnostics, codeActions, actionToInvoke) = await GetDiagnosticAndFixesAsync( - dxs, fixer, testDriver, document, span, parameters.codeActionOptions, annotation, parameters.index); + dxs, fixer, testDriver, document, span, annotation, parameters.index); // If we are also testing non-fixable diagnostics, // then the result diagnostics need to include all diagnostics, @@ -194,12 +190,12 @@ private protected async Task TestDiagnosticInfoAsync( string initialMarkup, string diagnosticId, DiagnosticSeverity diagnosticSeverity, - IdeAnalyzerOptions ideAnalyzerOptions = null, OptionsCollection options = null, + OptionsCollection globalOptions = null, LocalizableString diagnosticMessage = null) { - await TestDiagnosticInfoAsync(initialMarkup, parseOptions: null, compilationOptions: null, options, ideAnalyzerOptions, diagnosticId, diagnosticSeverity, diagnosticMessage); - await TestDiagnosticInfoAsync(initialMarkup, GetScriptOptions(), compilationOptions: null, options, ideAnalyzerOptions, diagnosticId, diagnosticSeverity, diagnosticMessage); + await TestDiagnosticInfoAsync(initialMarkup, parseOptions: null, compilationOptions: null, options, globalOptions, diagnosticId, diagnosticSeverity, diagnosticMessage); + await TestDiagnosticInfoAsync(initialMarkup, GetScriptOptions(), compilationOptions: null, options, globalOptions, diagnosticId, diagnosticSeverity, diagnosticMessage); } private protected async Task TestDiagnosticInfoAsync( @@ -207,12 +203,12 @@ private protected async Task TestDiagnosticInfoAsync( ParseOptions parseOptions, CompilationOptions compilationOptions, OptionsCollection options, - IdeAnalyzerOptions ideAnalyzerOptions, + OptionsCollection globalOptions, string diagnosticId, DiagnosticSeverity diagnosticSeverity, LocalizableString diagnosticMessage = null) { - var testOptions = new TestParameters(parseOptions, compilationOptions, options: options, ideAnalyzerOptions: ideAnalyzerOptions); + var testOptions = new TestParameters(parseOptions, compilationOptions, options: options, globalOptions: globalOptions); using (var workspace = CreateWorkspaceFromOptions(initialMarkup, testOptions)) { var diagnostics = (await GetDiagnosticsAsync(workspace, testOptions)).ToImmutableArray(); diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs index edad18afa2366..8337e470c019d 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionAllCodeTests.cs @@ -88,7 +88,7 @@ protected async Task TestPragmaOrAttributeAsync( continue; } - var fixes = fixer.GetFixesAsync(document, diagnostic.Location.SourceSpan, SpecializedCollections.SingletonEnumerable(diagnostic), _ => CodeActionOptions.Default, CancellationToken.None).GetAwaiter().GetResult(); + var fixes = fixer.GetFixesAsync(document, diagnostic.Location.SourceSpan, SpecializedCollections.SingletonEnumerable(diagnostic), CodeActionOptions.DefaultProvider, CancellationToken.None).GetAwaiter().GetResult(); if (fixes == null || fixes.Count() <= 0) { continue; diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs index 153893ffa064d..7f748df1f1afd 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractSuppressionDiagnosticTest.cs @@ -83,13 +83,9 @@ internal override async Task> GetDiagnosticsAsync( var (analyzer, fixer) = CreateDiagnosticProviderAndFixer(workspace); AddAnalyzerToWorkspace(workspace, analyzer, parameters); - string annotation = null; - if (!TryGetDocumentAndSelectSpan(workspace, out var document, out var span)) - { - document = GetDocumentAndAnnotatedSpan(workspace, out annotation, out span); - } + GetDocumentAndSelectSpanOrAnnotatedSpan(workspace, out var document, out var span, out var annotation); - var testDriver = new TestDiagnosticAnalyzerDriver(workspace, document.Project, includeSuppressedDiagnostics: IncludeSuppressedDiagnostics); + var testDriver = new TestDiagnosticAnalyzerDriver(workspace, includeSuppressedDiagnostics: IncludeSuppressedDiagnostics); var diagnostics = (await testDriver.GetAllDiagnosticsAsync(document, span)) .Where(d => fixer.IsFixableDiagnostic(d)); @@ -98,7 +94,7 @@ internal override async Task> GetDiagnosticsAsync( var wrapperCodeFixer = new WrapperCodeFixProvider(fixer, filteredDiagnostics.Select(d => d.Id)); return await GetDiagnosticAndFixesAsync( filteredDiagnostics, wrapperCodeFixer, testDriver, document, - span, CodeActionOptions.Default, annotation, parameters.index); + span, annotation, parameters.index); } } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs index dde2727fe3d0c..d0bcdaf488975 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUnncessarySuppressionDiagnosticTest.cs @@ -48,14 +48,10 @@ internal override async Task> GetDiagnosticsAsync( { AddAnalyzersToWorkspace(workspace); - string annotation = null; - if (!TryGetDocumentAndSelectSpan(workspace, out var document, out var span)) - { - document = GetDocumentAndAnnotatedSpan(workspace, out annotation, out span); - } + GetDocumentAndSelectSpanOrAnnotatedSpan(workspace, out var document, out var span, out var annotation); // Include suppressed diagnostics as they are needed by unnecessary suppressions analyzer. - var testDriver = new TestDiagnosticAnalyzerDriver(workspace, document.Project, includeSuppressedDiagnostics: true); + var testDriver = new TestDiagnosticAnalyzerDriver(workspace, includeSuppressedDiagnostics: true); var diagnostics = await testDriver.GetAllDiagnosticsAsync(document, span); // Filter out suppressed diagnostics before invoking code fix. @@ -63,7 +59,7 @@ internal override async Task> GetDiagnosticsAsync( return await GetDiagnosticAndFixesAsync( diagnostics, CodeFixProvider, testDriver, document, - span, CodeActionOptions.Default, annotation, parameters.index); + span, annotation, parameters.index); } } } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs index c145f4f9bcb03..52ebcccb78bb8 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractUserDiagnosticTest.cs @@ -4,10 +4,8 @@ #nullable disable -using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -26,6 +24,7 @@ using Microsoft.CodeAnalysis.Remote.Testing; using Xunit.Abstractions; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics { @@ -115,68 +114,12 @@ protected static Document GetDocumentAndSelectSpan(TestWorkspace workspace, out return workspace.CurrentSolution.GetDocument(hostDocument.Id); } - protected static bool TryGetDocumentAndSelectSpan(TestWorkspace workspace, out Document document, out TextSpan span) - { - var hostDocument = workspace.Documents.FirstOrDefault(d => d.SelectedSpans.Any()); - if (hostDocument == null) - { - // If there wasn't a span, see if there was a $$ caret. we'll create an empty span - // there if so. - hostDocument = workspace.Documents.FirstOrDefault(d => d.CursorPosition != null); - if (hostDocument == null) - { - document = null; - span = default; - return false; - } - - span = new TextSpan(hostDocument.CursorPosition.Value, 0); - document = workspace.CurrentSolution.GetDocument(hostDocument.Id); - return true; - } - - span = hostDocument.SelectedSpans.Single(); - document = workspace.CurrentSolution.GetDocument(hostDocument.Id); - return true; - } - - protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, out string annotation, out TextSpan span) - { - var annotatedDocuments = workspace.Documents.Where(d => d.AnnotatedSpans.Any()); - Debug.Assert(!annotatedDocuments.IsEmpty(), "No annotated span found"); - var hostDocument = annotatedDocuments.Single(); - var annotatedSpan = hostDocument.AnnotatedSpans.Single(); - annotation = annotatedSpan.Key; - span = annotatedSpan.Value.Single(); - return workspace.CurrentSolution.GetDocument(hostDocument.Id); - } - - protected static FixAllScope? GetFixAllScope(string annotation) - { - if (annotation == null) - { - return null; - } - - return annotation switch - { - "FixAllInDocument" => FixAllScope.Document, - "FixAllInProject" => FixAllScope.Project, - "FixAllInSolution" => FixAllScope.Solution, - "FixAllInContainingMember" => FixAllScope.ContainingMember, - "FixAllInContainingType" => FixAllScope.ContainingType, - "FixAllInSelection" => FixAllScope.Custom, - _ => throw new InvalidProgramException("Incorrect FixAll annotation in test"), - }; - } - internal async Task<(ImmutableArray, ImmutableArray, CodeAction actionToInvoke)> GetDiagnosticAndFixesAsync( IEnumerable diagnostics, CodeFixProvider fixer, TestDiagnosticAnalyzerDriver testDriver, Document document, TextSpan span, - CodeActionOptions options, string annotation, int index) { @@ -210,7 +153,7 @@ protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, o diagnostic.Location.SourceSpan, ImmutableArray.Create(diagnostic), (a, d) => fixes.Add(new CodeFix(document.Project, a, d)), - _ => options, + testDriver.FallbackOptions, CancellationToken.None); await fixer.RegisterCodeFixesAsync(context); @@ -234,7 +177,7 @@ protected static Document GetDocumentAndAnnotatedSpan(TestWorkspace workspace, o var fixAllState = GetFixAllState( fixAllProvider, diagnostics, fixer, testDriver, document, - scope.Value, equivalenceKey, _ => options); + scope.Value, equivalenceKey, testDriver.FallbackOptions); var fixAllContext = new FixAllContext(fixAllState, new ProgressTracker(), CancellationToken.None); var fixAllFix = await fixAllProvider.GetFixAsync(fixAllContext); @@ -277,13 +220,12 @@ private protected Task TestActionCountInAllFixesAsync( ParseOptions parseOptions = null, CompilationOptions compilationOptions = null, OptionsCollection options = null, - CodeActionOptions? codeActionOptions = null, - IdeAnalyzerOptions ideAnalyzerOptions = null, + OptionsCollection globalOptions = null, object fixProviderData = null) { return TestActionCountInAllFixesAsync( initialMarkup, - new TestParameters(parseOptions, compilationOptions, options, codeActionOptions, ideAnalyzerOptions, fixProviderData), + new TestParameters(parseOptions, compilationOptions, options, globalOptions, fixProviderData), count); } diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs b/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs index a5ed2485de1a2..b03aaab4afdda 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/MoveToNamespace/AbstractMoveToNamespaceTests.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ChangeNamespace; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; @@ -49,7 +50,7 @@ public async Task TestMoveToNamespaceAsync( var actions = await testState.MoveToNamespaceService.GetCodeActionsAsync( testState.InvocationDocument, testState.TestInvocationDocument.SelectedSpans.Single(), - CodeCleanupOptions.GetDefaultAsync, + CodeActionOptions.DefaultProvider, CancellationToken.None); var operationTasks = actions @@ -90,7 +91,7 @@ public async Task TestMoveToNamespaceAsync( if (!optionCancelled && !string.IsNullOrEmpty(targetNamespace)) { - await TestInRegularAndScriptAsync(markup, expectedMarkup); + await TestInRegularAndScriptAsync(markup, expectedMarkup, options: testParameters.options); } } else diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs b/src/EditorFeatures/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs index 30e3274852617..36fc2c6eb2e45 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/NamingStyles/NamingStylesTestOptionSets.cs @@ -129,7 +129,7 @@ internal OptionsCollection AccessibilitiesArePascalCase(ImmutableArray accessibilities) { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(MethodKind.Ordinary)), accessibilities, @@ -355,7 +355,7 @@ private static NamingStylePreferences MethodNamesArePascalCaseOption(ImmutableAr private static NamingStylePreferences SymbolKindsArePascalCaseOption(ImmutableArray symbolKinds) { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", symbolKinds, accessibilityList: default, @@ -386,7 +386,7 @@ private static NamingStylePreferences SymbolKindsArePascalCaseOption(ImmutableAr private static NamingStylePreferences AccessibilitiesArePascalCaseOption(ImmutableArray accessibilities) { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", symbolKindList: default, accessibilityList: accessibilities, @@ -417,7 +417,7 @@ private static NamingStylePreferences AccessibilitiesArePascalCaseOption(Immutab private static NamingStylePreferences ParameterNamesAreCamelCaseOption() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.Parameter)), accessibilityList: default, @@ -449,7 +449,7 @@ private static NamingStylePreferences ParameterNamesAreCamelCaseOption() private static NamingStylePreferences ParameterNamesAreCamelCaseWithPUnderscorePrefixOption() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name2", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.Parameter)), accessibilityList: default, @@ -481,7 +481,7 @@ private static NamingStylePreferences ParameterNamesAreCamelCaseWithPUnderscoreP private static NamingStylePreferences ParameterNamesAreCamelCaseWithPUnderscorePrefixAndUnderscoreEndSuffixOption() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name2", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.Parameter)), accessibilityList: default, @@ -513,7 +513,7 @@ private static NamingStylePreferences ParameterNamesAreCamelCaseWithPUnderscoreP private static NamingStylePreferences LocalNamesAreCamelCaseOption() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.Local)), accessibilityList: default, @@ -545,7 +545,7 @@ private static NamingStylePreferences LocalNamesAreCamelCaseOption() private static NamingStylePreferences LocalFunctionNamesAreCamelCaseOption() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(MethodKind.LocalFunction)), accessibilityList: default, @@ -577,7 +577,7 @@ private static NamingStylePreferences LocalFunctionNamesAreCamelCaseOption() private static NamingStylePreferences PropertyNamesArePascalCaseOption() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.Property)), accessibilityList: default, @@ -609,7 +609,7 @@ private static NamingStylePreferences PropertyNamesArePascalCaseOption() private static NamingStylePreferences InterfaceNamesStartWithIOption() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(TypeKind.Interface)), accessibilityList: default, @@ -641,7 +641,7 @@ private static NamingStylePreferences InterfaceNamesStartWithIOption() private static NamingStylePreferences TypeParameterNamesStartWithTOption() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.TypeParameter)), accessibilityList: default, @@ -673,7 +673,7 @@ private static NamingStylePreferences TypeParameterNamesStartWithTOption() private static NamingStylePreferences ConstantsAreUpperCaseOption() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create( new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.Field), @@ -707,14 +707,14 @@ private static NamingStylePreferences ConstantsAreUpperCaseOption() private static NamingStylePreferences LocalsAreCamelCaseConstantsAreUpperCaseOption() { var localsSymbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Locals", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.Local)), accessibilityList: default, modifiers: default); var constLocalsSymbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Const Locals", ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.Local)), accessibilityList: default, @@ -761,7 +761,7 @@ private static NamingStylePreferences LocalsAreCamelCaseConstantsAreUpperCaseOpt private static NamingStylePreferences AsyncFunctionNamesEndWithAsyncOption() { var symbolSpecification = new SymbolSpecification( - null, + Guid.NewGuid(), "Name", ImmutableArray.Create( new SymbolSpecification.SymbolKindOrTypeKind(MethodKind.Ordinary), diff --git a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs index b31a5166a4a26..e779264c08114 100644 --- a/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs +++ b/src/EditorFeatures/Test/CodeFixes/CodeFixServiceTests.cs @@ -62,7 +62,7 @@ public async Task TestGetFirstDiagnosticWithFixAsync() var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); var document = project.Documents.Single(); var unused = await fixService.GetMostSevereFixAsync( - document, TextSpan.FromBounds(0, 0), CodeActionRequestPriority.None, _ => CodeActionOptions.Default, CancellationToken.None); + document, TextSpan.FromBounds(0, 0), CodeActionRequestPriority.None, CodeActionOptions.DefaultProvider, CancellationToken.None); var fixer1 = (MockFixer)fixers.Single().Value; var fixer2 = (MockFixer)reference.Fixer!; @@ -89,9 +89,7 @@ public async Task TestGetFixesAsyncWithDuplicateDiagnostics() GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); // Verify that we do not crash when computing fixes. - var options = CodeActionOptions.Default; - - _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); + _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); // Verify that code fix is invoked with both the diagnostics in the context, // i.e. duplicate diagnostics are not silently discarded by the CodeFixService. @@ -117,8 +115,7 @@ public async Task TestGetFixesAsyncHasNoDuplicateConfigurationActions() GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); // Verify registered configuration code actions do not have duplicates. - var options = CodeActionOptions.Default; - var fixCollections = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); + var fixCollections = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); var codeActions = fixCollections.SelectMany(c => c.Fixes.Select(f => f.Action)).ToImmutableArray(); Assert.Equal(7, codeActions.Length); var uniqueTitles = new HashSet(); @@ -148,18 +145,16 @@ public async Task TestGetFixesAsyncForFixableAndNonFixableAnalyzersAsync() using var workspace = tuple.workspace; GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); - var options = CodeActionOptions.Default; - // Verify only analyzerWithFix is executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Normal'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Normal, _ => options, + priority: CodeActionRequestPriority.Normal, CodeActionOptions.DefaultProvider, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(analyzerWithFix.ReceivedCallback); Assert.False(analyzerWithoutFix.ReceivedCallback); // Verify both analyzerWithFix and analyzerWithoutFix are executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Lowest'. _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Lowest, _ => options, + priority: CodeActionRequestPriority.Lowest, CodeActionOptions.DefaultProvider, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(analyzerWithFix.ReceivedCallback); Assert.True(analyzerWithoutFix.ReceivedCallback); @@ -187,10 +182,8 @@ public async Task TestGetFixesAsyncForDocumentDiagnosticAnalyzerAsync() GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager, analyzerReference); // Verify both analyzers are executed when GetFixesAsync is invoked with 'CodeActionRequestPriority.Normal'. - var options = CodeActionOptions.Default; - _ = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), - priority: CodeActionRequestPriority.Normal, _ => options, + priority: CodeActionRequestPriority.Normal, CodeActionOptions.DefaultProvider, addOperationScope: _ => null, cancellationToken: CancellationToken.None); Assert.True(documentDiagnosticAnalyzer.ReceivedCallback); } @@ -274,8 +267,7 @@ private static async Task> GetAddedFixesAsync( var reference = new MockAnalyzerReference(codefix, ImmutableArray.Create(diagnosticAnalyzer)); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); document = project.Documents.Single(); - var options = CodeActionOptions.Default; - var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); + var fixes = await tuple.codeFixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); if (exception) { @@ -300,7 +292,7 @@ private static async Task GetFirstDiagnosticWithFixWithExceptionValidationAsync( GetDocumentAndExtensionManager(tuple.analyzerService, workspace, out var document, out var extensionManager); var unused = await tuple.codeFixService.GetMostSevereFixAsync( - document, TextSpan.FromBounds(0, 0), CodeActionRequestPriority.None, _ => CodeActionOptions.Default, CancellationToken.None); + document, TextSpan.FromBounds(0, 0), CodeActionRequestPriority.None, CodeActionOptions.DefaultProvider, CancellationToken.None); Assert.True(extensionManager.IsDisabled(codefix)); Assert.False(extensionManager.IsIgnored(codefix)); Assert.True(errorReported); @@ -690,9 +682,8 @@ private static async Task> GetNuGetAndVsixCode var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); var document = project.Documents.Single(); - var options = CodeActionOptions.Default; - return await fixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); + return await fixService.GetFixesAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); } private sealed class NuGetCodeFixProvider : AbstractNuGetOrVsixCodeFixProvider diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs index 97219f300c705..28aa4628ac235 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs @@ -45,7 +45,14 @@ internal static async Task TestAddNamespaceAsync( { using var testContext = await TestContext.CreateAsync(initial, expected); var @namespace = CodeGenerationSymbolFactory.CreateNamespaceSymbol(name, imports, members); - testContext.Result = await testContext.Service.AddNamespaceAsync(testContext.Solution, (INamespaceSymbol)testContext.GetDestination(), @namespace, context ?? CodeGenerationContext.Default, CancellationToken.None); + testContext.Result = await testContext.Service.AddNamespaceAsync( + new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()), + (INamespaceSymbol)testContext.GetDestination(), + @namespace, + CancellationToken.None); } internal static async Task TestAddFieldAsync( @@ -73,12 +80,20 @@ internal static async Task TestAddFieldAsync( if (!addToCompilationUnit) { - testContext.Result = await testContext.Service.AddFieldAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), field, context ?? CodeGenerationContext.Default, CancellationToken.None); + testContext.Result = await testContext.Service.AddFieldAsync( + new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()), + (INamedTypeSymbol)testContext.GetDestination(), + field, + CancellationToken.None); } else { - var options = await CodeGenerationOptions.FromDocumentAsync(context ?? CodeGenerationContext.Default, testContext.Document, CancellationToken.None); - var newRoot = testContext.Service.AddField(await testContext.Document.GetSyntaxRootAsync(), field, options, CancellationToken.None); + var options = await testContext.Document.GetCodeGenerationOptionsAsync(testContext.Workspace.GlobalOptions, CancellationToken.None); + var info = options.GetInfo(context ?? CodeGenerationContext.Default, testContext.Document.Project); + var newRoot = testContext.Service.AddField(await testContext.Document.GetSyntaxRootAsync(), field, info, CancellationToken.None); testContext.Result = testContext.Document.WithSyntaxRoot(newRoot); } } @@ -107,7 +122,14 @@ internal static async Task TestAddConstructorAsync( baseConstructorArguments: baseArguments, thisConstructorArguments: thisArguments); - testContext.Result = await testContext.Service.AddMethodAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), ctor, context ?? CodeGenerationContext.Default, CancellationToken.None); + testContext.Result = await testContext.Service.AddMethodAsync( + new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()), + (INamedTypeSymbol)testContext.GetDestination(), + ctor, + CancellationToken.None); } internal static async Task TestAddMethodAsync( @@ -146,7 +168,14 @@ internal static async Task TestAddMethodAsync( parsedStatements, handlesExpressions: handlesExpressions); - testContext.Result = await testContext.Service.AddMethodAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), method, context ?? CodeGenerationContext.Default, CancellationToken.None); + testContext.Result = await testContext.Service.AddMethodAsync( + new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()), + (INamedTypeSymbol)testContext.GetDestination(), + method, + CancellationToken.None); } internal static async Task TestAddOperatorsAsync( @@ -181,7 +210,14 @@ internal static async Task TestAddOperatorsAsync( parameterSymbols, parsedStatements)); - testContext.Result = await testContext.Service.AddMembersAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), methods.ToArray(), context ?? CodeGenerationContext.Default, CancellationToken.None); + testContext.Result = await testContext.Service.AddMembersAsync( + new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()), + (INamedTypeSymbol)testContext.GetDestination(), + methods.ToArray(), + CancellationToken.None); } internal static async Task TestAddUnsupportedOperatorAsync( @@ -210,7 +246,14 @@ internal static async Task TestAddUnsupportedOperatorAsync( ArgumentException exception = null; try { - await testContext.Service.AddMethodAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), method, context ?? CodeGenerationContext.Default, CancellationToken.None); + await testContext.Service.AddMethodAsync( + new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()), + (INamedTypeSymbol)testContext.GetDestination(), + method, + CancellationToken.None); } catch (ArgumentException e) { @@ -250,7 +293,14 @@ internal static async Task TestAddConversionAsync( isImplicit, parsedStatements); - testContext.Result = await testContext.Service.AddMethodAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), method, context ?? CodeGenerationContext.Default, CancellationToken.None); + testContext.Result = await testContext.Service.AddMethodAsync( + new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()), + (INamedTypeSymbol)testContext.GetDestination(), + method, + CancellationToken.None); } internal static async Task TestAddStatementsAsync( @@ -267,8 +317,9 @@ internal static async Task TestAddStatementsAsync( using var testContext = await TestContext.CreateAsync(initial, expected); var parsedStatements = testContext.ParseStatements(statements); var oldSyntax = testContext.GetSelectedSyntax(true); - var options = await CodeGenerationOptions.FromDocumentAsync(context ?? CodeGenerationContext.Default, testContext.Document, CancellationToken.None); - var newSyntax = testContext.Service.AddStatements(oldSyntax, parsedStatements, options, CancellationToken.None); + var options = await testContext.Document.GetCodeGenerationOptionsAsync(testContext.Workspace.GlobalOptions, CancellationToken.None); + var info = options.GetInfo(context ?? CodeGenerationContext.Default, testContext.Document.Project); + var newSyntax = testContext.Service.AddStatements(oldSyntax, parsedStatements, info, CancellationToken.None); testContext.Result = testContext.Document.WithSyntaxRoot((await testContext.Document.GetSyntaxRootAsync()).ReplaceNode(oldSyntax, newSyntax)); } @@ -281,9 +332,10 @@ internal static async Task TestAddParametersAsync( using var testContext = await TestContext.CreateAsync(initial, expected); var parameterSymbols = GetParameterSymbols(parameters, testContext); var oldMemberSyntax = testContext.GetSelectedSyntax(true); - var options = await CodeGenerationOptions.FromDocumentAsync(context ?? CodeGenerationContext.Default, testContext.Document, CancellationToken.None); + var options = await testContext.Document.GetCodeGenerationOptionsAsync(testContext.Workspace.GlobalOptions, CancellationToken.None); + var info = options.GetInfo(context ?? CodeGenerationContext.Default, testContext.Document.Project); - var newMemberSyntax = testContext.Service.AddParameters(oldMemberSyntax, parameterSymbols, options, CancellationToken.None); + var newMemberSyntax = testContext.Service.AddParameters(oldMemberSyntax, parameterSymbols, info, CancellationToken.None); testContext.Result = testContext.Document.WithSyntaxRoot((await testContext.Document.GetSyntaxRootAsync()).ReplaceNode(oldMemberSyntax, newMemberSyntax)); } @@ -310,7 +362,14 @@ internal static async Task TestAddDelegateTypeAsync( typeParameters, parameterSymbols); - testContext.Result = await testContext.Service.AddNamedTypeAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), type, context ?? CodeGenerationContext.Default, CancellationToken.None); + testContext.Result = await testContext.Service.AddNamedTypeAsync( + new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()), + (INamedTypeSymbol)testContext.GetDestination(), + type, + CancellationToken.None); } internal static async Task TestAddEventAsync( @@ -344,7 +403,14 @@ internal static async Task TestAddEventAsync( removeMethod, raiseMethod); - testContext.Result = await testContext.Service.AddEventAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), @event, context ?? CodeGenerationContext.Default, CancellationToken.None); + testContext.Result = await testContext.Service.AddEventAsync( + new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()), + (INamedTypeSymbol)testContext.GetDestination(), + @event, + CancellationToken.None); } internal static async Task TestAddPropertyAsync( @@ -438,7 +504,14 @@ internal static async Task TestAddPropertyAsync( setAccessor, isIndexer); - testContext.Result = await testContext.Service.AddPropertyAsync(testContext.Solution, (INamedTypeSymbol)testContext.GetDestination(), property, context ?? CodeGenerationContext.Default, CancellationToken.None); + testContext.Result = await testContext.Service.AddPropertyAsync( + new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()), + (INamedTypeSymbol)testContext.GetDestination(), + property, + CancellationToken.None); } internal static async Task TestAddNamedTypeAsync( @@ -461,7 +534,14 @@ internal static async Task TestAddNamedTypeAsync( attributes: default, accessibility, modifiers, typeKind, name, typeParameters, baseType, interfaces, specialType, memberSymbols); - testContext.Result = await testContext.Service.AddNamedTypeAsync(testContext.Solution, (INamespaceSymbol)testContext.GetDestination(), type, context ?? CodeGenerationContext.Default, CancellationToken.None); + testContext.Result = await testContext.Service.AddNamedTypeAsync( + new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()), + (INamespaceSymbol)testContext.GetDestination(), + type, + CancellationToken.None); } internal static async Task TestAddAttributeAsync( @@ -474,8 +554,9 @@ internal static async Task TestAddAttributeAsync( var attr = CodeGenerationSymbolFactory.CreateAttributeData(GetTypeSymbol(attributeClass)(testContext.SemanticModel)); var oldNode = testContext.GetDestinationNode(); var codeGenerator = testContext.Document.GetRequiredLanguageService(); - var options = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, testContext.Document, CancellationToken.None); - var newNode = codeGenerator.AddAttributes(oldNode, new[] { attr }, target, options, CancellationToken.None) + var options = await testContext.Document.GetCodeGenerationOptionsAsync(testContext.Workspace.GlobalOptions, CancellationToken.None); + var info = options.GetInfo(CodeGenerationContext.Default, testContext.Document.Project); + var newNode = codeGenerator.AddAttributes(oldNode, new[] { attr }, target, info, CancellationToken.None) .WithAdditionalAnnotations(Formatter.Annotation); testContext.Result = testContext.Document.WithSyntaxRoot(testContext.SemanticModel.SyntaxTree.GetRoot().ReplaceNode(oldNode, newNode)); } @@ -492,8 +573,9 @@ internal static async Task TestRemoveAttributeAsync( var attribute = attributeTarget.GetAttributes().Single(attr => Equals(attr.AttributeClass, attributeType)); var declarationNode = taggedNode.FirstAncestorOrSelf(); var codeGenerator = testContext.Document.GetRequiredLanguageService(); - var options = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, testContext.Document, CancellationToken.None); - var newNode = codeGenerator.RemoveAttribute(declarationNode, attribute, options, CancellationToken.None) + var options = await testContext.Document.GetCodeGenerationOptionsAsync(testContext.Workspace.GlobalOptions, CancellationToken.None); + var info = options.GetInfo(CodeGenerationContext.Default, testContext.Document.Project); + var newNode = codeGenerator.RemoveAttribute(declarationNode, attribute, info, CancellationToken.None) .WithAdditionalAnnotations(Formatter.Annotation); testContext.Result = testContext.Document.WithSyntaxRoot(testContext.SemanticModel.SyntaxTree.GetRoot().ReplaceNode(declarationNode, newNode)); } @@ -513,18 +595,19 @@ internal static async Task TestUpdateDeclarationAsync( var updatedDeclarationNode = declarationNode; var codeGenerator = testContext.Document.GetRequiredLanguageService(); - var options = await CodeGenerationOptions.FromDocumentAsync(new CodeGenerationContext(reuseSyntax: true), testContext.Document, CancellationToken.None); + var options = await testContext.Document.GetCodeGenerationOptionsAsync(testContext.Workspace.GlobalOptions, CancellationToken.None); + var info = options.GetInfo(new CodeGenerationContext(reuseSyntax: true), testContext.Document.Project); if (accessibility.HasValue) { - updatedDeclarationNode = codeGenerator.UpdateDeclarationAccessibility(declarationNode, accessibility.Value, options, CancellationToken.None); + updatedDeclarationNode = codeGenerator.UpdateDeclarationAccessibility(declarationNode, accessibility.Value, info, CancellationToken.None); } else if (modifiers != null) { - updatedDeclarationNode = codeGenerator.UpdateDeclarationModifiers(declarationNode, modifiers, options, CancellationToken.None); + updatedDeclarationNode = codeGenerator.UpdateDeclarationModifiers(declarationNode, modifiers, info, CancellationToken.None); } else if (getType != null) { - updatedDeclarationNode = codeGenerator.UpdateDeclarationType(declarationNode, getType(testContext.SemanticModel), options, CancellationToken.None); + updatedDeclarationNode = codeGenerator.UpdateDeclarationType(declarationNode, getType(testContext.SemanticModel), info, CancellationToken.None); } else if (getNewMembers != null) { @@ -542,7 +625,7 @@ internal static async Task TestUpdateDeclarationAsync( allMembers.AddRange(newMembersToAdd); } - updatedDeclarationNode = codeGenerator.UpdateDeclarationMembers(declarationNode, allMembers, options, CancellationToken.None); + updatedDeclarationNode = codeGenerator.UpdateDeclarationMembers(declarationNode, allMembers, info, CancellationToken.None); } updatedDeclarationNode = updatedDeclarationNode.WithAdditionalAnnotations(Formatter.Annotation); @@ -570,18 +653,21 @@ internal static async Task TestGenerateFromSourceSymbolAsync( .GetDocument(documentId) .GetSemanticModelAsync(); - context ??= CodeGenerationContext.Default; + var solutionContext = new CodeGenerationSolutionContext( + testContext.Solution, + context ?? CodeGenerationContext.Default, + testContext.Workspace.GlobalOptions.CreateProvider()); var symbol = TestContext.GetSelectedSymbol(destSpan, semanticModel); var destination = testContext.GetDestination(); if (destination.IsType) { var members = onlyGenerateMembers ? symbol.GetMembers().ToArray() : new[] { symbol }; - testContext.Result = await testContext.Service.AddMembersAsync(testContext.Solution, (INamedTypeSymbol)destination, members, context, CancellationToken.None); + testContext.Result = await testContext.Service.AddMembersAsync(solutionContext, (INamedTypeSymbol)destination, members, CancellationToken.None); } else { - testContext.Result = await testContext.Service.AddNamespaceOrTypeAsync(testContext.Solution, (INamespaceSymbol)destination, symbol, context, CancellationToken.None); + testContext.Result = await testContext.Service.AddNamespaceOrTypeAsync(solutionContext, (INamespaceSymbol)destination, symbol, CancellationToken.None); } } diff --git a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs index 26631818d7ff2..2fa86a83db93a 100644 --- a/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs +++ b/src/EditorFeatures/Test/CodeRefactorings/CodeRefactoringServiceTest.cs @@ -44,8 +44,7 @@ public async Task TestProjectRefactoringAsync() var reference = new StubAnalyzerReference(); var project = workspace.CurrentSolution.Projects.Single().AddAnalyzerReference(reference); var document = project.Documents.Single(); - var options = CodeActionOptions.Default; - var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); + var refactorings = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); var stubRefactoringAction = refactorings.Single(refactoring => refactoring.CodeActions.FirstOrDefault().action?.Title == nameof(StubRefactoring)); Assert.True(stubRefactoringAction is object); @@ -68,8 +67,7 @@ private static async Task VerifyRefactoringDisabledAsync() var project = workspace.CurrentSolution.Projects.Single(); var document = project.Documents.Single(); var extensionManager = (EditorLayerExtensionManager.ExtensionManager)document.Project.Solution.Workspace.Services.GetRequiredService(); - var options = CodeActionOptions.Default; - var result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), _ => options, CancellationToken.None); + var result = await refactoringService.GetRefactoringsAsync(document, TextSpan.FromBounds(0, 0), CodeActionOptions.DefaultProvider, CancellationToken.None); Assert.True(extensionManager.IsDisabled(codeRefactoring)); Assert.False(extensionManager.IsIgnored(codeRefactoring)); diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs index 6ff5b2914356b..97fdab19127b5 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticAnalyzerServiceTests.cs @@ -1194,12 +1194,11 @@ internal sealed class CancellationTestAnalyzer : DiagnosticAnalyzer new DiagnosticDescriptor(NonCanceledDiagnosticId, "test", "test", "test", DiagnosticSeverity.Warning, isEnabledByDefault: true); private readonly AnalyzerRegisterActionKind _actionKind; - private readonly CancellationTokenSource _cancellationTokenSource; + private readonly CancellationTokenSource _cancellationTokenSource = new(); public CancellationTestAnalyzer(AnalyzerRegisterActionKind actionKind) { _actionKind = actionKind; - _cancellationTokenSource = new CancellationTokenSource(); CanceledCompilations = new ConcurrentSet(); } diff --git a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs index d37a122129bcf..42b5bf0e1a21f 100644 --- a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs @@ -438,6 +438,9 @@ public void CSharp_VerifyIDEDiagnosticSeveritiesAreConfigurable() # IDE0220 dotnet_diagnostic.IDE0220.severity = %value% +# IDE0230 +dotnet_diagnostic.IDE0230.severity = %value% + # IDE1005 dotnet_diagnostic.IDE1005.severity = %value% @@ -1055,6 +1058,9 @@ No editorconfig based code style option # IDE0220, ForEachExplicitCastInSource dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed +# IDE0230, PreferUTF8StringLiterals +csharp_style_prefer_utf8_string_literals = true + # IDE1005, PreferConditionalDelegateCall csharp_style_conditional_delegate_call = true diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index f0c875ccc4e51..d96fd9ff6aa41 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -49,7 +49,7 @@ public sealed partial class EditAndContinueWorkspaceServiceTests : TestBase private const TargetFramework DefaultTargetFramework = TargetFramework.NetStandard20; private Func _mockCompilationOutputsProvider; - private readonly List _telemetryLog; + private readonly List _telemetryLog = new(); private int _telemetryId; private readonly MockManagedEditAndContinueDebuggerService _debuggerService; @@ -57,7 +57,6 @@ public sealed partial class EditAndContinueWorkspaceServiceTests : TestBase public EditAndContinueWorkspaceServiceTests() { _mockCompilationOutputsProvider = _ => new MockCompilationOutputs(Guid.NewGuid()); - _telemetryLog = new List(); _debuggerService = new MockManagedEditAndContinueDebuggerService() { diff --git a/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs b/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs index ab0510ba3ed94..66f2d807f35dc 100644 --- a/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs +++ b/src/EditorFeatures/Test/InheritanceMargin/InheritanceMarginTests.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.VisualBasic; using Roslyn.Utilities; using Xunit; @@ -20,7 +21,7 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.InheritanceMargin [UseExportProvider] public class InheritanceMarginTests { - private const string SearchAreaTag = "SeachTag"; + private const string SearchAreaTag = nameof(SearchAreaTag); #region Helpers @@ -54,6 +55,34 @@ private static Task VerifyInSingleDocumentAsync( return VerifyTestMemberInDocumentAsync(testWorkspace, testHostDocument, memberItems, cancellationToken); } + private static Task VerifyInMultipleDocumentsAsync( + string markup1, + string markup2, + string languageName, + params TestInheritanceMemberItem[] memberItems) + { + var workspaceFile = $@" + + + + + + + + + +"; + + var cancellationToken = CancellationToken.None; + + using var testWorkspace = TestWorkspace.Create( + workspaceFile, + composition: EditorTestCompositions.EditorFeatures); + + var testHostDocument = testWorkspace.Documents[0]; + return VerifyTestMemberInDocumentAsync(testWorkspace, testHostDocument, memberItems, cancellationToken); + } + private static async Task VerifyTestMemberInDocumentAsync( TestWorkspace testWorkspace, TestHostDocument testHostDocument, @@ -73,6 +102,7 @@ private static async Task VerifyTestMemberInDocumentAsync( var actualItems = await service.GetInheritanceMemberItemsAsync( document, searchingSpan, + includeGlobalImports: true, cancellationToken).ConfigureAwait(false); var sortedActualItems = actualItems.OrderBy(item => item.LineNumber).ToImmutableArray(); @@ -94,19 +124,22 @@ private static async Task VerifyInheritanceMemberAsync(TestWorkspace testWorkspa .Select(info => TestInheritanceTargetItem.Create(info, testWorkspace)) .OrderBy(target => target.TargetSymbolName) .ToImmutableArray(); - var sortedActualTargets = actualItem.TargetItems.OrderBy(target => target.DisplayName) - .ToImmutableArray(); + for (var i = 0; i < expectedTargets.Length; i++) - { - await VerifyInheritanceTargetAsync(expectedTargets[i], sortedActualTargets[i]); - } + await VerifyInheritanceTargetAsync(testWorkspace, expectedTargets[i], actualItem.TargetItems[i]); } - private static async Task VerifyInheritanceTargetAsync(TestInheritanceTargetItem expectedTarget, InheritanceTargetItem actualTarget) + private static async Task VerifyInheritanceTargetAsync(Workspace workspace, TestInheritanceTargetItem expectedTarget, InheritanceTargetItem actualTarget) { Assert.Equal(expectedTarget.TargetSymbolName, actualTarget.DisplayName); Assert.Equal(expectedTarget.RelationshipToMember, actualTarget.RelationToMember); + if (expectedTarget.LanguageGlyph != null) + Assert.Equal(expectedTarget.LanguageGlyph, actualTarget.LanguageGlyph); + + if (expectedTarget.ProjectName != null) + Assert.Equal(expectedTarget.ProjectName, actualTarget.ProjectName); + if (expectedTarget.IsInMetadata) { Assert.True(actualTarget.DefinitionItem.Properties.ContainsKey("MetadataSymbolKey")); @@ -119,7 +152,7 @@ private static async Task VerifyInheritanceTargetAsync(TestInheritanceTargetItem Assert.Equal(expectedDocumentSpans.Length, actualDocumentSpans.Length); for (var i = 0; i < actualDocumentSpans.Length; i++) { - var docSpan = await actualDocumentSpans[i].TryRehydrateAsync(CancellationToken.None); + var docSpan = await actualDocumentSpans[i].TryRehydrateAsync(workspace.CurrentSolution, CancellationToken.None); Assert.Equal(expectedDocumentSpans[i].SourceSpan, docSpan.Value.SourceSpan); Assert.Equal(expectedDocumentSpans[i].Document.FilePath, docSpan.Value.Document.FilePath); } @@ -196,16 +229,22 @@ private class TargetInfo public readonly ImmutableArray LocationTags; public readonly InheritanceRelationship Relationship; public readonly bool InMetadata; + public readonly Glyph? LanguageGlyph; + public readonly string? ProjectName; public TargetInfo( string targetSymbolDisplayName, string locationTag, - InheritanceRelationship relationship) + InheritanceRelationship relationship, + Glyph? languageGlyph = null, + string? projectName = null) { TargetSymbolDisplayName = targetSymbolDisplayName; LocationTags = ImmutableArray.Create(locationTag); Relationship = relationship; + LanguageGlyph = languageGlyph; InMetadata = false; + ProjectName = projectName; } public TargetInfo( @@ -236,17 +275,23 @@ private class TestInheritanceTargetItem public readonly InheritanceRelationship RelationshipToMember; public readonly ImmutableArray DocumentSpans; public readonly bool IsInMetadata; + public readonly Glyph? LanguageGlyph; + public readonly string? ProjectName; public TestInheritanceTargetItem( string targetSymbolName, InheritanceRelationship relationshipToMember, - ImmutableArray documentSpans, - bool isInMetadata) + ImmutableArray documentSpans, + bool isInMetadata, + Glyph? languageGlyph, + string? projectName) { TargetSymbolName = targetSymbolName; RelationshipToMember = relationshipToMember; DocumentSpans = documentSpans; IsInMetadata = isInMetadata; + LanguageGlyph = languageGlyph; + ProjectName = projectName; } public static TestInheritanceTargetItem Create( @@ -259,7 +304,9 @@ public static TestInheritanceTargetItem Create( targetInfo.TargetSymbolDisplayName, targetInfo.Relationship, ImmutableArray.Empty, - isInMetadata: true); + isInMetadata: true, + targetInfo.LanguageGlyph, + targetInfo.ProjectName); } else { @@ -287,7 +334,9 @@ public static TestInheritanceTargetItem Create( targetInfo.TargetSymbolDisplayName, targetInfo.Relationship, builder.ToImmutable(), - isInMetadata: false); + isInMetadata: false, + targetInfo.LanguageGlyph, + targetInfo.ProjectName); } } } @@ -1235,6 +1284,79 @@ public partial class {|target3:Bar|} itemOnLine10); } + [Fact] + public Task TestEmptyFileSingleGlobalImportInOtherFile() + { + var markup1 = @""; + var markup2 = @"{|target1:global using System;|}"; + + return VerifyInMultipleDocumentsAsync( + markup1, markup2, LanguageNames.CSharp, + new TestInheritanceMemberItem( + lineNumber: 0, + memberName: string.Format(FeaturesResources.Directives_from_0, "Test2.cs"), + targets: ImmutableArray.Create(new TargetInfo( + targetSymbolDisplayName: "System", + relationship: InheritanceRelationship.InheritedImport, "target1")))); + } + + [Fact] + public Task TestEmptyFileMultipleGlobalImportInOtherFile() + { + var markup1 = @""; + var markup2 = @" +{|target1:global using System;|} +{|target2:global using System.Collections;|}"; + + return VerifyInMultipleDocumentsAsync( + markup1, markup2, LanguageNames.CSharp, + new TestInheritanceMemberItem( + lineNumber: 0, + memberName: string.Format(FeaturesResources.Directives_from_0, "Test2.cs"), + targets: ImmutableArray.Create( + new TargetInfo( + targetSymbolDisplayName: "System", + relationship: InheritanceRelationship.InheritedImport, "target1"), + new TargetInfo( + targetSymbolDisplayName: "System.Collections", + relationship: InheritanceRelationship.InheritedImport, "target2")))); + } + + [Fact] + public Task TestFileWithUsing_SingleGlobalImportInOtherFile() + { + var markup1 = @" +using System.Collections;"; + var markup2 = @"{|target1:global using System;|}"; + + return VerifyInMultipleDocumentsAsync( + markup1, markup2, LanguageNames.CSharp, + new TestInheritanceMemberItem( + lineNumber: 1, + memberName: string.Format(FeaturesResources.Directives_from_0, "Test2.cs"), + targets: ImmutableArray.Create(new TargetInfo( + targetSymbolDisplayName: "System", + relationship: InheritanceRelationship.InheritedImport, "target1")))); + } + + [Fact] + public Task TestIgnoreGlobalImportFromSameFile() + { + var markup1 = @" +global using System.Collections.Generic; +using System.Collections;"; + var markup2 = @"{|target1:global using System;|}"; + + return VerifyInMultipleDocumentsAsync( + markup1, markup2, LanguageNames.CSharp, + new TestInheritanceMemberItem( + lineNumber: 1, + memberName: string.Format(FeaturesResources.Directives_from_0, "Test2.cs"), + targets: ImmutableArray.Create(new TargetInfo( + targetSymbolDisplayName: "System", + relationship: InheritanceRelationship.InheritedImport, "target1")))); + } + #endregion #region TestsForVisualBasic @@ -1396,6 +1518,13 @@ Implements IEnumerable return VerifyInSingleDocumentAsync( markup, LanguageNames.VisualBasic, + new TestInheritanceMemberItem( + lineNumber: 2, + memberName: VBFeaturesResources.Project_level_Imports, + targets: ImmutableArray.Create( + new TargetInfo("System", InheritanceRelationship.InheritedImport), + new TargetInfo("System.Collections.Generic", InheritanceRelationship.InheritedImport), + new TargetInfo("System.Linq", InheritanceRelationship.InheritedImport))), new TestInheritanceMemberItem( lineNumber: 3, memberName: "Class Bar", @@ -1928,6 +2057,14 @@ public interface {|target1:IBar|} void {|target3:Foo|}(); } }"; + var itemForProjectImports = + new TestInheritanceMemberItem( + lineNumber: 2, + memberName: VBFeaturesResources.Project_level_Imports, + targets: ImmutableArray.Create( + new TargetInfo("System", InheritanceRelationship.InheritedImport), + new TargetInfo("System.Collections.Generic", InheritanceRelationship.InheritedImport), + new TargetInfo("System.Linq", InheritanceRelationship.InheritedImport))); var itemForBar44 = new TestInheritanceMemberItem( lineNumber: 4, @@ -1964,8 +2101,132 @@ public interface {|target1:IBar|} return VerifyInDifferentProjectsAsync( (markup1, LanguageNames.VisualBasic), (markup2, LanguageNames.CSharp), - new[] { itemForBar44, itemForFooInMarkup1 }, + new[] { itemForProjectImports, itemForBar44, itemForFooInMarkup1 }, new[] { itemForIBar, itemForFooInMarkup2 }); } + + [Fact] + public Task TestSameNameSymbolInDifferentLanguageProjects() + { + var markup1 = @" + using MyNamespace; + namespace BarNs + { + public class {|target1:Bar|} : IBar + { + } + }"; + + var markup2 = @" + Namespace MyNamespace + Public Interface {|target2:IBar|} + End Interface + + Public Class {|target3:Bar|} + Implements IBar + End Class + End Namespace"; + + var itemForBarInMarkup1 = new TestInheritanceMemberItem( + lineNumber: 5, + memberName: "class Bar", + targets: ImmutableArray.Create(new TargetInfo( + targetSymbolDisplayName: "IBar", + locationTag: "target2", + relationship: InheritanceRelationship.ImplementedInterface))); + + var itemForIBar = new TestInheritanceMemberItem( + lineNumber: 3, + memberName: "Interface IBar", + targets: ImmutableArray.Create( + new TargetInfo( + targetSymbolDisplayName: "Bar", + locationTag: "target1", + relationship: InheritanceRelationship.ImplementingType, + languageGlyph: Glyph.CSharpFile, + projectName: "Assembly1"), + new TargetInfo( + targetSymbolDisplayName: "Bar", + locationTag: "target3", + relationship: InheritanceRelationship.ImplementingType, + languageGlyph: Glyph.BasicFile, + projectName: "Assembly2"))); + + var itemForBarInMarkup2 = new TestInheritanceMemberItem( + lineNumber: 6, + memberName: "Class Bar", + targets: ImmutableArray.Create(new TargetInfo( + targetSymbolDisplayName: "IBar", + locationTag: "target2", + relationship: InheritanceRelationship.ImplementedInterface))); + + return VerifyInDifferentProjectsAsync( + (markup1, LanguageNames.CSharp), + (markup2, LanguageNames.VisualBasic), + new[] { itemForBarInMarkup1 }, + new[] { itemForIBar, itemForBarInMarkup2 }); + } + + [Fact] + public Task TestSameNameSymbolInSameLanguageProjects() + { + var markup1 = @" + using MyNamespace; + namespace BarNs + { + public class {|target1:Bar|} : IBar + { + } + }"; + + var markup2 = @" + namespace MyNamespace { + public interface {|target2:IBar|} + {} + + public class {|target3:Bar|} + : IBar + {} + }"; + + var itemForBarInMarkup1 = new TestInheritanceMemberItem( + lineNumber: 5, + memberName: "class Bar", + targets: ImmutableArray.Create(new TargetInfo( + targetSymbolDisplayName: "IBar", + locationTag: "target2", + relationship: InheritanceRelationship.ImplementedInterface))); + + var itemForIBar = new TestInheritanceMemberItem( + lineNumber: 3, + memberName: "interface IBar", + targets: ImmutableArray.Create( + new TargetInfo( + targetSymbolDisplayName: "Bar", + locationTag: "target1", + relationship: InheritanceRelationship.ImplementingType, + languageGlyph: Glyph.CSharpFile, + projectName: "Assembly1"), + new TargetInfo( + targetSymbolDisplayName: "Bar", + locationTag: "target3", + relationship: InheritanceRelationship.ImplementingType, + languageGlyph: Glyph.CSharpFile, + projectName: "Assembly2"))); + + var itemForBarInMarkup2 = new TestInheritanceMemberItem( + lineNumber: 6, + memberName: "class Bar", + targets: ImmutableArray.Create(new TargetInfo( + targetSymbolDisplayName: "IBar", + locationTag: "target2", + relationship: InheritanceRelationship.ImplementedInterface))); + + return VerifyInDifferentProjectsAsync( + (markup1, LanguageNames.CSharp), + (markup2, LanguageNames.CSharp), + new[] { itemForBarInMarkup1 }, + new[] { itemForIBar, itemForBarInMarkup2 }); + } } } diff --git a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb index bfd0869878f87..e6636df9452ee 100644 --- a/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb +++ b/src/EditorFeatures/Test2/CodeFixes/CodeFixServiceTests.vb @@ -52,7 +52,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference})) Dim project = workspace.CurrentSolution.Projects(0) - Dim options = CodeActionOptions.Default Assert.IsType(Of MockDiagnosticUpdateSourceRegistrationService)(workspace.GetService(Of IDiagnosticUpdateSourceRegistrationService)()) Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) @@ -77,7 +76,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - Function(language) options, + CodeActionOptions.DefaultProvider, CancellationToken.None) Assert.Equal(0, fixes.Count()) @@ -93,7 +92,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - Function(language) options, + CodeActionOptions.DefaultProvider, CancellationToken.None) Assert.Equal(1, fixes.Count()) @@ -103,7 +102,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - Function(language) options, + CodeActionOptions.DefaultProvider, CancellationToken.None) Assert.Equal(0, fixes.Count()) @@ -129,7 +128,6 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences({analyzerReference})) Dim project = workspace.CurrentSolution.Projects(0) - Dim options = CodeActionOptions.Default Assert.IsType(Of MockDiagnosticUpdateSourceRegistrationService)(workspace.GetService(Of IDiagnosticUpdateSourceRegistrationService)()) Dim diagnosticService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.GetService(Of IDiagnosticAnalyzerService)()) @@ -154,7 +152,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests Dim fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - Function(language) options, + CodeActionOptions.DefaultProvider, CancellationToken.None) Assert.Equal(0, fixes.Count()) @@ -170,7 +168,7 @@ Namespace Microsoft.CodeAnalysis.Editor.Implementation.CodeFixes.UnitTests fixes = Await codefixService.GetFixesAsync( document, (Await document.GetSyntaxRootAsync()).FullSpan, - Function(language) options, + CodeActionOptions.DefaultProvider, CancellationToken.None) Assert.Equal(0, fixes.Count()) diff --git a/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb b/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb index e920efd33bb3d..204737337cf56 100644 --- a/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb +++ b/src/EditorFeatures/Test2/Rename/RenameEngineResult.vb @@ -4,6 +4,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeCleanup Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Options @@ -123,7 +124,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename ' features that need to call each part independently and operate on the intermediary values. Dim locations = Renamer.FindRenameLocationsAsync( - solution, symbol, renameOptions, AddressOf CodeCleanupOptions.GetDefaultAsync, CancellationToken.None).GetAwaiter().GetResult() + solution, symbol, renameOptions, CodeActionOptions.DefaultProvider, CancellationToken.None).GetAwaiter().GetResult() Return locations.ResolveConflictsAsync(renameTo, nonConflictSymbols:=Nothing, cancellationToken:=CancellationToken.None).GetAwaiter().GetResult() Else @@ -131,7 +132,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename ' marshaled back. Return Renamer.RenameSymbolAsync( - solution, symbol, renameTo, renameOptions, AddressOf CodeCleanupOptions.GetDefaultAsync, + solution, symbol, renameTo, renameOptions, CodeActionOptions.DefaultProvider, nonConflictSymbols:=Nothing, CancellationToken.None).GetAwaiter().GetResult() End If End Function diff --git a/src/EditorFeatures/Test2/SyncNamespaces/SyncNamespacesServiceTests.vb b/src/EditorFeatures/Test2/SyncNamespaces/SyncNamespacesServiceTests.vb index ec88c170c044a..1fd9ed141433f 100644 --- a/src/EditorFeatures/Test2/SyncNamespaces/SyncNamespacesServiceTests.vb +++ b/src/EditorFeatures/Test2/SyncNamespaces/SyncNamespacesServiceTests.vb @@ -40,7 +40,7 @@ namespace Test.Namespace.App Dim document = project.Documents.Single() Dim syncService = project.GetLanguageService(Of ISyncNamespacesService)() - Dim newSolution = Await syncService.SyncNamespacesAsync(ImmutableArray.Create(project), Function(language) CodeActionOptions.Default, CancellationToken.None) + Dim newSolution = Await syncService.SyncNamespacesAsync(ImmutableArray.Create(project), CodeActionOptions.DefaultProvider, CancellationToken.None) Dim solutionChanges = workspace.CurrentSolution.GetChanges(newSolution) @@ -76,7 +76,7 @@ namespace Test Dim document = project.Documents.Single() Dim syncService = project.GetLanguageService(Of ISyncNamespacesService)() - Dim newSolution = Await syncService.SyncNamespacesAsync(projects, Function(language) CodeActionOptions.Default, CancellationToken.None) + Dim newSolution = Await syncService.SyncNamespacesAsync(projects, CodeActionOptions.DefaultProvider, CancellationToken.None) Dim solutionChanges = workspace.CurrentSolution.GetChanges(newSolution) Dim projectChanges = solutionChanges.GetProjectChanges().Single() @@ -133,7 +133,7 @@ namespace Test2.Namespace.App Dim project = projects(0) Dim syncService = project.GetLanguageService(Of ISyncNamespacesService)() - Dim newSolution = Await syncService.SyncNamespacesAsync(projects, Function(language) CodeActionOptions.Default, CancellationToken.None) + Dim newSolution = Await syncService.SyncNamespacesAsync(projects, CodeActionOptions.DefaultProvider, CancellationToken.None) Dim solutionChanges = workspace.CurrentSolution.GetChanges(newSolution) @@ -187,7 +187,7 @@ namespace Test2.Namespace.App Dim document = project.Documents.Single() Dim syncService = project.GetLanguageService(Of ISyncNamespacesService)() - Dim newSolution = Await syncService.SyncNamespacesAsync(projects, Function(language) CodeActionOptions.Default, CancellationToken.None) + Dim newSolution = Await syncService.SyncNamespacesAsync(projects, CodeActionOptions.DefaultProvider, CancellationToken.None) Dim solutionChanges = workspace.CurrentSolution.GetChanges(newSolution) Dim projectChanges = solutionChanges.GetProjectChanges().Single() @@ -252,7 +252,7 @@ namespace Test2.Namespace Dim document2 = project2.Documents.Single() Dim syncService = project.GetLanguageService(Of ISyncNamespacesService)() - Dim newSolution = Await syncService.SyncNamespacesAsync(projects, Function(language) CodeActionOptions.Default, CancellationToken.None) + Dim newSolution = Await syncService.SyncNamespacesAsync(projects, CodeActionOptions.DefaultProvider, CancellationToken.None) Dim solutionChanges = workspace.CurrentSolution.GetChanges(newSolution) Dim projectChanges = solutionChanges.GetProjectChanges().ToImmutableArray() diff --git a/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs b/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs index 20bf54b2b1d23..26854a7e55c09 100644 --- a/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs +++ b/src/EditorFeatures/TestUtilities/AbstractCommandHandlerTestState.cs @@ -22,6 +22,7 @@ using Roslyn.Test.EditorUtilities; using Roslyn.Test.Utilities; using Xunit; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests { @@ -76,15 +77,18 @@ public AbstractCommandHandlerTestState( } else { - var cursorDocument = Workspace.Documents.First(d => d.CursorPosition.HasValue); + var cursorDocument = Workspace.Documents.First(d => d.CursorPosition.HasValue || d.SelectedSpans.Any(ss => ss.IsEmpty)); _textView = cursorDocument.GetTextView(); _subjectBuffer = cursorDocument.GetTextBuffer(); + var cursorPosition = cursorDocument.CursorPosition ?? cursorDocument.SelectedSpans.First(ss => ss.IsEmpty).Start; + _textView.Caret.MoveTo( + new SnapshotPoint(_subjectBuffer.CurrentSnapshot, cursorPosition)); + if (cursorDocument.AnnotatedSpans.TryGetValue("Selection", out var selectionSpanList)) { var firstSpan = selectionSpanList.First(); var lastSpan = selectionSpanList.Last(); - var cursorPosition = cursorDocument.CursorPosition!.Value; Assert.True(cursorPosition == firstSpan.Start || cursorPosition == firstSpan.End || cursorPosition == lastSpan.Start || cursorPosition == lastSpan.End, @@ -113,8 +117,8 @@ public AbstractCommandHandlerTestState( } _textView.Selection.Select( - new SnapshotSpan(boxSelectionStart, boxSelectionEnd), - isReversed: isReversed); + new SnapshotSpan(boxSelectionStart, boxSelectionEnd), + isReversed: isReversed); } } @@ -295,6 +299,9 @@ public void SendPageUp(Action commandHandler, Action nextHandler) => commandHandler(new PageDownKeyCommandArgs(TextView, SubjectBuffer), nextHandler, TestCommandExecutionContext.Create()); + public void SendCopy(Action commandHandler, Action nextHandler) + => commandHandler(new CopyCommandArgs(TextView, SubjectBuffer), nextHandler, TestCommandExecutionContext.Create()); + public void SendCut(Action commandHandler, Action nextHandler) => commandHandler(new CutCommandArgs(TextView, SubjectBuffer), nextHandler, TestCommandExecutionContext.Create()); diff --git a/src/EditorFeatures/TestUtilities/Async/AsynchronousOperationBlocker.cs b/src/EditorFeatures/TestUtilities/Async/AsynchronousOperationBlocker.cs index ac640ed6957ea..e967ffe00ba91 100644 --- a/src/EditorFeatures/TestUtilities/Async/AsynchronousOperationBlocker.cs +++ b/src/EditorFeatures/TestUtilities/Async/AsynchronousOperationBlocker.cs @@ -13,14 +13,13 @@ namespace Roslyn.Test.Utilities public sealed class AsynchronousOperationBlocker : IDisposable { private readonly ManualResetEvent _waitHandle; - private readonly object _lockObj; + private readonly object _lockObj = new(); private bool _blocking; private bool _disposed; public AsynchronousOperationBlocker() { _waitHandle = new ManualResetEvent(false); - _lockObj = new object(); _blocking = true; } diff --git a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs index 45a2fbeac3e1c..c11adfcd4ee34 100644 --- a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs @@ -127,7 +127,7 @@ private protected abstract Task BaseVerifyWorkerAsync( SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, - List matchingFilters, CompletionItemFlags? flags); + List matchingFilters, CompletionItemFlags? flags, bool skipSpeculation = false); internal Task GetCompletionListAsync( CompletionService service, @@ -241,7 +241,7 @@ private async Task VerifyAsync( SourceCodeKind? sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionModeItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, - List matchingFilters, CompletionItemFlags? flags) + List matchingFilters, CompletionItemFlags? flags, bool skipSpeculation = false) { foreach (var sourceKind in sourceCodeKind.HasValue ? new[] { sourceCodeKind.Value } : new[] { SourceCodeKind.Regular, SourceCodeKind.Script }) { @@ -258,7 +258,8 @@ await VerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionModeItem, displayTextSuffix, displayTextPrefix, - inlineDescription, isComplexTextEdit, matchingFilters, flags).ConfigureAwait(false); + inlineDescription, isComplexTextEdit, matchingFilters, flags, + skipSpeculation: skipSpeculation).ConfigureAwait(false); } } @@ -334,14 +335,16 @@ private protected async Task VerifyItemExistsAsync( SourceCodeKind? sourceCodeKind = null, bool usePreviousCharAsTrigger = false, int? glyph = null, int? matchPriority = null, bool? hasSuggestionModeItem = null, string displayTextSuffix = null, string displayTextPrefix = null, string inlineDescription = null, - bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) + bool? isComplexTextEdit = null, List matchingFilters = null, + CompletionItemFlags? flags = null, bool skipSpeculation = false) { await VerifyAsync(markup, expectedItem, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence: false, glyph: glyph, matchPriority: matchPriority, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, - isComplexTextEdit: isComplexTextEdit, matchingFilters: matchingFilters, flags: flags); + isComplexTextEdit: isComplexTextEdit, matchingFilters: matchingFilters, + flags: flags, skipSpeculation: skipSpeculation); } private protected async Task VerifyItemIsAbsentAsync( @@ -403,7 +406,8 @@ private protected virtual async Task VerifyWorkerAsync( int? glyph, int? matchPriority, bool? hasSuggestionModeItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, - List matchingFilters, CompletionItemFlags? flags) + List matchingFilters, CompletionItemFlags? flags, + bool skipSpeculation = false) { using var workspaceFixture = GetOrCreateWorkspaceFixture(); @@ -417,7 +421,7 @@ await CheckResultsAsync( hasSuggestionModeItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); - if (await CanUseSpeculativeSemanticModelAsync(document1, position)) + if (!skipSpeculation && await CanUseSpeculativeSemanticModelAsync(document1, position)) { var document2 = workspaceFixture.Target.UpdateDocument(code, sourceCodeKind, cleanBeforeUpdate: false); await CheckResultsAsync( @@ -910,7 +914,7 @@ private protected async Task VerifyAtPositionAsync( SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, - bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) + bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null, bool skipSpeculation = false) { code = code.Substring(0, position) + insertText + code.Substring(position); position += insertText.Length; @@ -919,7 +923,7 @@ await BaseVerifyWorkerAsync(code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, skipSpeculation: skipSpeculation); } private protected async Task VerifyAtPositionAsync( @@ -928,13 +932,13 @@ private protected async Task VerifyAtPositionAsync( SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, - List matchingFilters = null, CompletionItemFlags? flags = null) + List matchingFilters = null, CompletionItemFlags? flags = null, bool skipSpeculation = false) { await VerifyAtPositionAsync( code, position, string.Empty, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, - inlineDescription, isComplexTextEdit, matchingFilters, flags); + inlineDescription, isComplexTextEdit, matchingFilters, flags, skipSpeculation: skipSpeculation); } private protected async Task VerifyAtEndOfFileAsync( @@ -967,13 +971,13 @@ private protected async Task VerifyAtPosition_ItemPartiallyWrittenAsync( SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, - List matchingFilters = null, CompletionItemFlags? flags = null) + List matchingFilters = null, CompletionItemFlags? flags = null, bool skipSpeculation = false) { await VerifyAtPositionAsync( code, position, ItemPartiallyWritten(expectedItemOrNull), usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, skipSpeculation: skipSpeculation); } private protected async Task VerifyAtEndOfFileAsync( diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticProviderTestUtilities.cs b/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticProviderTestUtilities.cs index 312be43f46634..b05c52104268f 100644 --- a/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticProviderTestUtilities.cs +++ b/src/EditorFeatures/TestUtilities/Diagnostics/DiagnosticProviderTestUtilities.cs @@ -18,7 +18,7 @@ public static async Task> GetAllDiagnosticsAsync( TextSpan span, bool includeSuppressedDiagnostics = false) { - var testDriver = new TestDiagnosticAnalyzerDriver(workspace, document.Project, includeSuppressedDiagnostics); + var testDriver = new TestDiagnosticAnalyzerDriver(workspace, includeSuppressedDiagnostics); return await testDriver.GetAllDiagnosticsAsync(document, span); } @@ -28,7 +28,7 @@ public static async Task> GetDocumentDiagnosticsAsync( TextSpan span, bool includeSuppressedDiagnostics = false) { - var testDriver = new TestDiagnosticAnalyzerDriver(workspace, document.Project, includeSuppressedDiagnostics); + var testDriver = new TestDiagnosticAnalyzerDriver(workspace, includeSuppressedDiagnostics); return await testDriver.GetDocumentDiagnosticsAsync(document, span); } @@ -37,7 +37,7 @@ public static async Task> GetProjectDiagnosticsAsync( Project project, bool includeSuppressedDiagnostics = false) { - var testDriver = new TestDiagnosticAnalyzerDriver(workspace, project, includeSuppressedDiagnostics); + var testDriver = new TestDiagnosticAnalyzerDriver(workspace, includeSuppressedDiagnostics); return await testDriver.GetProjectDiagnosticsAsync(project); } } diff --git a/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs b/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs index af046dee23461..529c35c176cac 100644 --- a/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs +++ b/src/EditorFeatures/TestUtilities/Diagnostics/TestDiagnosticAnalyzerDriver.cs @@ -18,6 +18,8 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; using Xunit; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.CodeActions; namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics { @@ -26,11 +28,20 @@ public class TestDiagnosticAnalyzerDriver private readonly DiagnosticAnalyzerService _diagnosticAnalyzerService; private readonly bool _includeSuppressedDiagnostics; - public TestDiagnosticAnalyzerDriver(Workspace workspace, Project project, bool includeSuppressedDiagnostics = false) + internal readonly IGlobalOptionService GlobalOptions; + internal readonly CodeActionOptionsProvider FallbackOptions; + + public TestDiagnosticAnalyzerDriver(Workspace workspace, bool includeSuppressedDiagnostics = false) { - Assert.IsType(((IMefHostExportProvider)workspace.Services.HostServices).GetExportedValue()); - _diagnosticAnalyzerService = Assert.IsType(((IMefHostExportProvider)workspace.Services.HostServices).GetExportedValue()); - _diagnosticAnalyzerService.CreateIncrementalAnalyzer(project.Solution.Workspace); + var mefServices = (IMefHostExportProvider)workspace.Services.HostServices; + + Assert.IsType(mefServices.GetExportedValue()); + _diagnosticAnalyzerService = Assert.IsType(mefServices.GetExportedValue()); + + GlobalOptions = mefServices.GetExportedValue(); + FallbackOptions = GlobalOptions.CreateProvider(); + + _diagnosticAnalyzerService.CreateIncrementalAnalyzer(workspace); _includeSuppressedDiagnostics = includeSuppressedDiagnostics; } diff --git a/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs b/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs index c867787212ca7..3ec9a60bec796 100644 --- a/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs +++ b/src/EditorFeatures/TestUtilities/ExtractInterface/ExtractInterfaceTestState.cs @@ -8,7 +8,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.ExtractInterface; @@ -16,6 +18,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests.ExtractInterface { @@ -82,7 +85,7 @@ public Task GetTypeAnalysisResultAsync(TypeD ExtractFromDocument, _testDocument.CursorPosition.Value, typeDiscoveryRule, - CodeCleanupOptions.GetDefaultAsync, + CodeActionOptions.DefaultProvider, CancellationToken.None); } @@ -91,7 +94,7 @@ public Task ExtractViaCommandAsync() return ExtractInterfaceService.ExtractInterfaceAsync( ExtractFromDocument, _testDocument.CursorPosition.Value, - CodeCleanupOptions.GetDefaultAsync, + CodeActionOptions.DefaultProvider, (errorMessage, severity) => { this.ErrorMessage = errorMessage; @@ -105,7 +108,7 @@ public async Task ExtractViaCodeAction() var actions = await ExtractInterfaceService.GetExtractInterfaceCodeActionAsync( ExtractFromDocument, new TextSpan(_testDocument.CursorPosition.Value, 1), - CodeCleanupOptions.GetDefaultAsync, + CodeActionOptions.DefaultProvider, CancellationToken.None); var action = actions.Single(); diff --git a/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs b/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs index 9d1e68be56246..f9aff7552cbe8 100644 --- a/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs +++ b/src/EditorFeatures/TestUtilities/ExtractInterface/TestExtractInterfaceOptions.cs @@ -9,11 +9,14 @@ using System.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Notification; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests.ExtractInterface { @@ -63,7 +66,7 @@ public Task GetExtractInterfaceOptionsAsync( interfaceName: ChosenInterfaceName ?? defaultInterfaceName, fileName: ChosenFileName ?? defaultInterfaceName, location: SameFile ? ExtractInterfaceOptionsResult.ExtractLocation.SameFile : ExtractInterfaceOptionsResult.ExtractLocation.NewFile, - CodeCleanupOptions.GetDefaultAsync); + CodeActionOptions.DefaultProvider); return Task.FromResult(result); } diff --git a/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs b/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs index aba0459795987..c515bbe30786e 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs @@ -6,11 +6,13 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.Implementation.SmartIndent; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Formatting; @@ -173,7 +175,7 @@ private static string ApplyResultAndGetFormattedText(ITextBuffer buffer, IList spans, Dictionary changedOptionSet = null, int? baseIndentation = null) + private protected async Task AssertFormatAsync(string expected, string code, IEnumerable spans, OptionsCollection options = null, int? baseIndentation = null) { using var workspace = CreateWorkspace(code); var hostdoc = workspace.Documents.First(); @@ -196,24 +198,20 @@ protected async Task AssertFormatAsync(string expected, string code, IEnumerable factory.TextSpan = spans?.First() ?? syntaxTree.GetRoot(CancellationToken.None).FullSpan; } - var optionSet = workspace.Options; - if (changedOptionSet != null) - { - foreach (var entry in changedOptionSet) - { - optionSet = optionSet.WithChangedOption(entry.Key, entry.Value); - } - } - var root = await syntaxTree.GetRootAsync(); - var options = SyntaxFormattingOptions.Create(optionSet, workspace.Services, fallbackOptions: null, root.Language); + + var formattingService = document.GetRequiredLanguageService(); + + var formattingOptions = (options != null) ? + formattingService.GetFormattingOptions(options.ToAnalyzerConfigOptions(document.Project.LanguageServices), fallbackOptions: null) : + formattingService.DefaultOptions; document = workspace.CurrentSolution.GetDocument(syntaxTree); var rules = formattingRuleProvider.CreateRule(document, 0).Concat(Formatter.GetDefaultFormattingRules(document)); - AssertFormat(workspace, expected, options, rules, clonedBuffer, root, spans); + AssertFormat(workspace, expected, formattingOptions, rules, clonedBuffer, root, spans); // format with node and transform - AssertFormatWithTransformation(workspace, expected, options, rules, root, spans); + AssertFormatWithTransformation(workspace, expected, formattingOptions, rules, root, spans); } internal void AssertFormatWithTransformation(Workspace workspace, string expected, SyntaxFormattingOptions options, IEnumerable rules, SyntaxNode root, IEnumerable spans) @@ -277,18 +275,10 @@ protected void AssertFormatWithPasteOrReturn(string expectedWithMarker, string c string.Format("Caret positioned incorrectly. Should have been {0}, but was {1}.", expectedPosition, caretPosition)); } - protected async Task AssertFormatWithBaseIndentAsync( - string expected, string markupCode, int baseIndentation, - Dictionary options = null) + private protected async Task AssertFormatWithBaseIndentAsync(string expected, string markupCode, int baseIndentation, OptionsCollection options = null) { TestFileMarkupParser.GetSpans(markupCode, out var code, out ImmutableArray spans); - - await AssertFormatAsync( - expected, - code, - spans, - changedOptionSet: options, - baseIndentation: baseIndentation); + await AssertFormatAsync(expected, code, spans, options, baseIndentation); } /// diff --git a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs index 0d124cc59b065..48d8d36bfb28c 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs @@ -788,7 +788,7 @@ private static TestHostDocument CreateDocument( } var markupAttribute = documentElement.Attribute(MarkupAttributeName); - var isMarkup = markupAttribute == null || (bool)markupAttribute == true; + var isMarkup = markupAttribute == null || (string)markupAttribute == "true" || (string)markupAttribute == "SpansOnly"; string code; int? cursorPosition; @@ -796,7 +796,23 @@ private static TestHostDocument CreateDocument( if (isMarkup) { + // if the caller doesn't want us caring about positions, then replace any $'s with a character unlikely + // to ever show up in the doc naturally. Then, after we convert things, change that character back. We + // do this as a single character so that all the positions of the spans do not change. + if ((string)markupAttribute == "SpansOnly") + markupCode = markupCode.Replace("$", "\uD7FF"); + TestFileMarkupParser.GetPositionAndSpans(markupCode, out code, out cursorPosition, out spans); + + // if we were told SpansOnly then that means that $$ isn't actually a caret (but is something like a raw + // interpolated string delimiter. In that case, if we did see a $$ add it back it at the location we + // found it, and set the cursor back to null as the test will be specifying that location manually + // itself. + if ((string)markupAttribute == "SpansOnly") + { + Contract.ThrowIfTrue(cursorPosition != null); + code = code.Replace("\uD7FF", "$"); + } } else { diff --git a/src/EditorFeatures/Text/Extensions.TextBufferContainer.cs b/src/EditorFeatures/Text/Extensions.TextBufferContainer.cs index 4454c4daa9477..91d7ec2435609 100644 --- a/src/EditorFeatures/Text/Extensions.TextBufferContainer.cs +++ b/src/EditorFeatures/Text/Extensions.TextBufferContainer.cs @@ -37,8 +37,7 @@ private TextBufferContainer(ITextBuffer editorBuffer) /// /// A weak map of all Editor ITextBuffers and their associated SourceTextContainer /// - private static readonly ConditionalWeakTable s_textContainerMap = new ConditionalWeakTable(); - private static readonly ConditionalWeakTable.CreateValueCallback s_createContainerCallback = CreateContainer; + private static readonly ConditionalWeakTable s_textContainerMap = new(); public static TextBufferContainer From(ITextBuffer buffer) { @@ -47,12 +46,9 @@ public static TextBufferContainer From(ITextBuffer buffer) throw new ArgumentNullException(nameof(buffer)); } - return s_textContainerMap.GetValue(buffer, s_createContainerCallback); + return s_textContainerMap.GetValue(buffer, static buffer => new TextBufferContainer(buffer)); } - private static TextBufferContainer CreateContainer(ITextBuffer editorBuffer) - => new TextBufferContainer(editorBuffer); - public ITextBuffer? TryFindEditorTextBuffer() => _weakEditorBuffer.GetTarget(); diff --git a/src/EditorFeatures/VisualBasic/AddImports/VisualBasicAddImportsOnPasteCommandHandler.vb b/src/EditorFeatures/VisualBasic/AddImports/VisualBasicAddImportsOnPasteCommandHandler.vb index 0f67a04f5e839..ad549bc7bbbc2 100644 --- a/src/EditorFeatures/VisualBasic/AddImports/VisualBasicAddImportsOnPasteCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/AddImports/VisualBasicAddImportsOnPasteCommandHandler.vb @@ -6,6 +6,7 @@ Imports System.ComponentModel.Composition Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.Shared.TestHooks Imports Microsoft.VisualStudio.Commanding Imports Microsoft.VisualStudio.Utilities @@ -22,8 +23,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.AddImports Public Sub New(threadingContext As [Shared].Utilities.IThreadingContext, - globalOptions As IGlobalOptionService) - MyBase.New(threadingContext, globalOptions) + globalOptions As IGlobalOptionService, + listenerProvider As IAsynchronousOperationListenerProvider) + MyBase.New(threadingContext, globalOptions, listenerProvider) End Sub Public Overrides ReadOnly Property DisplayName As String = VBEditorResources.Add_Missing_Imports_on_Paste diff --git a/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb b/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb index c4baa2d7f6718..d4fe3b3949c89 100644 --- a/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb +++ b/src/EditorFeatures/VisualBasic/CodeCleanup/VisualBasicCodeCleanupService.vb @@ -24,7 +24,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeCleanup New DiagnosticSet(FeaturesResources.Apply_file_header_preferences, IDEDiagnosticIds.FileHeaderMismatch), New DiagnosticSet(AnalyzersResources.Add_this_or_Me_qualification, - IDEDiagnosticIds.AddQualificationDiagnosticId, IDEDiagnosticIds.RemoveQualificationDiagnosticId), + IDEDiagnosticIds.AddThisOrMeQualificationDiagnosticId, IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId), New DiagnosticSet(FeaturesResources.Apply_language_framework_type_preferences, IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId), New DiagnosticSet(FeaturesResources.Apply_parentheses_preferences, diff --git a/src/EditorFeatures/VisualBasic/CodeGeneration/VisualBasicCodeGenerationOptionsStorage.vb b/src/EditorFeatures/VisualBasic/CodeGeneration/VisualBasicCodeGenerationOptionsStorage.vb new file mode 100644 index 0000000000000..f106b2b29d82a --- /dev/null +++ b/src/EditorFeatures/VisualBasic/CodeGeneration/VisualBasicCodeGenerationOptionsStorage.vb @@ -0,0 +1,33 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System +Imports System.Composition +Imports Microsoft.CodeAnalysis.CodeStyle +Imports Microsoft.CodeAnalysis.VisualBasic.CodeStyle +Imports Microsoft.CodeAnalysis.Editing +Imports Microsoft.CodeAnalysis.Formatting +Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Options +Imports System.Runtime.CompilerServices +Imports Microsoft.CodeAnalysis.CodeGeneration + +Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration + Friend Module VisualBasicCodeGenerationOptionsStorage + + Private NotInheritable Class Service + Implements ICodeGenerationOptionsStorage + + + + Public Sub New() + End Sub + + Public Function GetOptions(globalOptions As IGlobalOptionService) As CodeGenerationOptions Implements ICodeGenerationOptionsStorage.GetOptions + Return VisualBasicCodeGenerationOptions.Default + End Function + End Class + End Module +End Namespace + diff --git a/src/EditorFeatures/VisualBasic/ImplementAbstractClass/ImplementAbstractClassCommandHandler.vb b/src/EditorFeatures/VisualBasic/ImplementAbstractClass/ImplementAbstractClassCommandHandler.vb index b2904e3fca185..758bf97ff7bf8 100644 --- a/src/EditorFeatures/VisualBasic/ImplementAbstractClass/ImplementAbstractClassCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/ImplementAbstractClass/ImplementAbstractClassCommandHandler.vb @@ -33,16 +33,16 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.ImplementAbstractClass Protected Overrides Function TryGetNewDocument( document As Document, - options As ImplementTypeOptions, - TypeSyntax As TypeSyntax, + options As ImplementTypeGenerationOptions, + typeSyntax As TypeSyntax, cancellationToken As CancellationToken ) As Document - If TypeSyntax.Parent.Kind <> SyntaxKind.InheritsStatement Then + If typeSyntax.Parent.Kind <> SyntaxKind.InheritsStatement Then Return Nothing End If - Dim classBlock = TryCast(TypeSyntax.Parent.Parent, ClassBlockSyntax) + Dim classBlock = TryCast(typeSyntax.Parent.Parent, ClassBlockSyntax) If classBlock Is Nothing Then Return Nothing End If diff --git a/src/EditorFeatures/VisualBasic/ImplementInterface/ImplementInterfaceCommandHandler.vb b/src/EditorFeatures/VisualBasic/ImplementInterface/ImplementInterfaceCommandHandler.vb index a93f14150b908..fb5befb1af879 100644 --- a/src/EditorFeatures/VisualBasic/ImplementInterface/ImplementInterfaceCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/ImplementInterface/ImplementInterfaceCommandHandler.vb @@ -33,7 +33,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.ImplementInterface Protected Overrides Function TryGetNewDocument( document As Document, - options As ImplementTypeOptions, + options As ImplementTypeGenerationOptions, typeSyntax As TypeSyntax, cancellationToken As CancellationToken ) As Document diff --git a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb index 4c74f5ba1bb52..b38d38c123c84 100644 --- a/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb +++ b/src/EditorFeatures/VisualBasic/NavigationBar/VisualBasicEditorNavigationBarItemService_CodeGeneration.vb @@ -55,7 +55,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Dim codeGenerationContext = New CodeGenerationContext(contextLocation, generateMethodBodies:=True) - Dim newDocument = Await GetGeneratedDocumentCoreAsync(document, generateCodeItem, codeGenerationContext, cancellationToken).ConfigureAwait(False) + Dim newDocument = Await GetGeneratedDocumentCoreAsync(document, generateCodeItem, codeGenerationContext, globalOptions.CreateProvider(), cancellationToken).ConfigureAwait(False) If newDocument Is Nothing Then Return document End If @@ -82,26 +82,38 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar Return generateCodeItem.Kind <> RoslynNavigationBarItemKind.GenerateFinalizer End Function - Private Shared Function GetGeneratedDocumentCoreAsync(document As Document, generateCodeItem As RoslynNavigationBarItem, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) + Private Shared Function GetGeneratedDocumentCoreAsync( + document As Document, + generateCodeItem As RoslynNavigationBarItem, + codeGenerationContext As CodeGenerationContext, + fallbackOptions As CodeAndImportGenerationOptionsProvider, + cancellationToken As CancellationToken) As Task(Of Document) + Select Case generateCodeItem.Kind Case RoslynNavigationBarItemKind.GenerateDefaultConstructor - Return GenerateDefaultConstructorAsync(document, DirectCast(generateCodeItem, GenerateDefaultConstructor), codeGenerationContext, cancellationToken) + Return GenerateDefaultConstructorAsync(document, DirectCast(generateCodeItem, GenerateDefaultConstructor), codeGenerationContext, fallbackOptions, cancellationToken) Case RoslynNavigationBarItemKind.GenerateEventHandler - Return GenerateEventHandlerAsync(document, DirectCast(generateCodeItem, GenerateEventHandler), codeGenerationContext, cancellationToken) + Return GenerateEventHandlerAsync(document, DirectCast(generateCodeItem, GenerateEventHandler), codeGenerationContext, fallbackOptions, cancellationToken) Case RoslynNavigationBarItemKind.GenerateFinalizer - Return GenerateFinalizerAsync(document, DirectCast(generateCodeItem, GenerateFinalizer), codeGenerationContext, cancellationToken) + Return GenerateFinalizerAsync(document, DirectCast(generateCodeItem, GenerateFinalizer), codeGenerationContext, fallbackOptions, cancellationToken) Case RoslynNavigationBarItemKind.GenerateMethod - Return GenerateMethodAsync(document, DirectCast(generateCodeItem, GenerateMethod), codeGenerationContext, cancellationToken) + Return GenerateMethodAsync(document, DirectCast(generateCodeItem, GenerateMethod), codeGenerationContext, fallbackOptions, cancellationToken) Case Else Throw ExceptionUtilities.UnexpectedValue(generateCodeItem.Kind) End Select End Function - Private Shared Async Function GenerateDefaultConstructorAsync(document As Document, generateCodeItem As GenerateDefaultConstructor, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) + Private Shared Async Function GenerateDefaultConstructorAsync( + document As Document, + generateCodeItem As GenerateDefaultConstructor, + codeGenerationContext As CodeGenerationContext, + fallbackOptions As CodeAndImportGenerationOptionsProvider, + cancellationToken As CancellationToken) As Task(Of Document) + Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, INamedTypeSymbol) @@ -131,14 +143,23 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar statements:=statements.ToImmutableAndFree()) methodSymbol = GeneratedSymbolAnnotation.AddAnnotationToSymbol(methodSymbol) - Return Await CodeGenerator.AddMethodDeclarationAsync(document.Project.Solution, - destinationType, - methodSymbol, - codeGenerationContext, - cancellationToken).ConfigureAwait(False) + Return Await CodeGenerator.AddMethodDeclarationAsync( + New CodeGenerationSolutionContext( + document.Project.Solution, + codeGenerationContext, + fallbackOptions), + destinationType, + methodSymbol, + cancellationToken).ConfigureAwait(False) End Function - Private Shared Async Function GenerateEventHandlerAsync(document As Document, generateCodeItem As GenerateEventHandler, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) + Private Shared Async Function GenerateEventHandlerAsync( + document As Document, + generateCodeItem As GenerateEventHandler, + codeGenerationContext As CodeGenerationContext, + fallbackOptions As CodeAndImportGenerationOptionsProvider, + cancellationToken As CancellationToken) As Task(Of Document) + Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim eventSymbol = TryCast(generateCodeItem.EventSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).GetAnySymbol(), IEventSymbol) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).GetAnySymbol(), INamedTypeSymbol) @@ -179,14 +200,23 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar handlesExpressions:=ImmutableArray.Create(Of SyntaxNode)(handlesSyntax)) methodSymbol = GeneratedSymbolAnnotation.AddAnnotationToSymbol(methodSymbol) - Return Await CodeGenerator.AddMethodDeclarationAsync(document.Project.Solution, - destinationType, - methodSymbol, - codeGenerationContext, - cancellationToken).ConfigureAwait(False) + Return Await CodeGenerator.AddMethodDeclarationAsync( + New CodeGenerationSolutionContext( + document.Project.Solution, + codeGenerationContext, + fallbackOptions), + destinationType, + methodSymbol, + cancellationToken).ConfigureAwait(False) End Function - Private Shared Async Function GenerateFinalizerAsync(document As Document, generateCodeItem As GenerateFinalizer, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) + Private Shared Async Function GenerateFinalizerAsync( + document As Document, + generateCodeItem As GenerateFinalizer, + codeGenerationContext As CodeGenerationContext, + fallbackOptions As CodeAndImportGenerationOptionsProvider, + cancellationToken As CancellationToken) As Task(Of Document) + Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, INamedTypeSymbol) @@ -216,14 +246,23 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar finalizerMethodSymbol = GeneratedSymbolAnnotation.AddAnnotationToSymbol(finalizerMethodSymbol) - Return Await CodeGenerator.AddMethodDeclarationAsync(document.Project.Solution, - destinationType, - finalizerMethodSymbol, - codeGenerationContext, - cancellationToken).ConfigureAwait(False) + Return Await CodeGenerator.AddMethodDeclarationAsync( + New CodeGenerationSolutionContext( + document.Project.Solution, + codeGenerationContext, + fallbackOptions), + destinationType, + finalizerMethodSymbol, + cancellationToken).ConfigureAwait(False) End Function - Private Shared Async Function GenerateMethodAsync(document As Document, generateCodeItem As GenerateMethod, codeGenerationContext As CodeGenerationContext, cancellationToken As CancellationToken) As Task(Of Document) + Private Shared Async Function GenerateMethodAsync( + document As Document, + generateCodeItem As GenerateMethod, + codeGenerationContext As CodeGenerationContext, + fallbackOptions As CodeAndImportGenerationOptionsProvider, + cancellationToken As CancellationToken) As Task(Of Document) + Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim destinationType = TryCast(generateCodeItem.DestinationTypeSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, INamedTypeSymbol) Dim methodToReplicate = TryCast(generateCodeItem.MethodToReplicateSymbolKey.Resolve(compilation, cancellationToken:=cancellationToken).Symbol, IMethodSymbol) @@ -236,11 +275,14 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar CodeGenerationSymbolFactory.CreateMethodSymbol( methodToReplicate.RemoveInaccessibleAttributesAndAttributesOfTypes(destinationType))) - Return Await CodeGenerator.AddMethodDeclarationAsync(document.Project.Solution, - destinationType, - codeGenerationSymbol, - codeGenerationContext, - cancellationToken).ConfigureAwait(False) + Return Await CodeGenerator.AddMethodDeclarationAsync( + New CodeGenerationSolutionContext( + document.Project.Solution, + codeGenerationContext, + fallbackOptions), + destinationType, + codeGenerationSymbol, + cancellationToken).ConfigureAwait(False) End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb b/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb index d29e20e3fa6de..da9fcb1d89f50 100644 --- a/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb +++ b/src/EditorFeatures/VisualBasic/Utilities/CommandHandlers/AbstractImplementAbstractClassOrInterfaceCommandHandler.vb @@ -40,7 +40,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers Protected MustOverride Overloads Function TryGetNewDocument( document As Document, - options As ImplementTypeOptions, + options As ImplementTypeGenerationOptions, typeSyntax As TypeSyntax, cancellationToken As CancellationToken) As Document @@ -164,8 +164,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.Utilities.CommandHandlers Return False End If - Dim options = _globalOptions.GetImplementTypeOptions(document.Project.Language) - Dim newDocument = TryGetNewDocument(document, options, identifier, cancellationToken) + Dim newDocument = TryGetNewDocument(document, _globalOptions.GetImplementTypeGenerationOptions(document.Project.LanguageServices), identifier, cancellationToken) If newDocument Is Nothing Then Return False diff --git a/src/EditorFeatures/VisualBasicTest/CodeActions/Preview/PreviewTests.vb b/src/EditorFeatures/VisualBasicTest/CodeActions/Preview/PreviewTests.vb index 1bed912f62928..0f67c6ccd7858 100644 --- a/src/EditorFeatures/VisualBasicTest/CodeActions/Preview/PreviewTests.vb +++ b/src/EditorFeatures/VisualBasicTest/CodeActions/Preview/PreviewTests.vb @@ -26,12 +26,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings Private Class MyCodeRefactoringProvider : Inherits CodeRefactoringProvider Public NotOverridable Overrides Function ComputeRefactoringsAsync(context As CodeRefactoringContext) As Task - Dim codeAction = New MyCodeAction(context.Document) + Dim codeAction = New TestCodeAction(context.Document) context.RegisterRefactoring(codeAction, context.Span) Return Task.CompletedTask End Function - Private Class MyCodeAction : Inherits CodeAction + Private Class TestCodeAction : Inherits CodeAction Private ReadOnly _oldDocument As Document Public Sub New(oldDocument As Document) diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb index dfa38176747a5..e60b5230e4d03 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb @@ -29,12 +29,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, checkForAbsence As Boolean, glyph As Integer?, matchPriority As Integer?, hasSuggestionItem As Boolean?, displayTextSuffix As String, displayTextPrefix As String, inlineDescription As String, - isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?) As Task + isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?, Optional skipSpeculation As Boolean = False) As Task Return MyBase.VerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, - isComplexTextEdit, matchingFilters, flags) + isComplexTextEdit, matchingFilters, flags, skipSpeculation) End Function Private Protected Overrides Async Function VerifyWorkerAsync( @@ -43,7 +43,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, checkForAbsence As Boolean, glyph As Integer?, matchPriority As Integer?, hasSuggestionItem As Boolean?, displayTextSuffix As String, displayTextPrefix As String, inlineDescription As String, - isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?) As Task + isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?, Optional skipSpeculation As Boolean = False) As Task ' Script/interactive support removed for now. ' TODO: Re-enable these when interactive is back in the product. If sourceCodeKind <> Microsoft.CodeAnalysis.SourceCodeKind.Regular Then @@ -53,7 +53,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Await VerifyAtPositionAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, - isComplexTextEdit, matchingFilters, flags) + isComplexTextEdit, matchingFilters, flags, skipSpeculation) Await VerifyAtEndOfFileAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, @@ -66,7 +66,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Await VerifyAtPosition_ItemPartiallyWrittenAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, - displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters) + displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, skipSpeculation:=skipSpeculation) Await VerifyAtEndOfFile_ItemPartiallyWrittenAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb index b012dc1a2a484..8ff02da37852f 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb @@ -18,7 +18,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, checkForAbsence As Boolean, glyph As Integer?, matchPriority As Integer?, hasSuggestionItem As Boolean?, displayTextSuffix As String, displayTextPrefix As String, inlineDescription As String, - isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?) As Task + isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?, Optional skipSpeculation As Boolean = False) As Task ' Script/interactive support removed for now. ' TODO: Re-enable these when interactive is back in the product. If sourceCodeKind <> SourceCodeKind.Regular Then @@ -29,7 +29,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, - isComplexTextEdit, matchingFilters, flags) + isComplexTextEdit, matchingFilters, flags, skipSpeculation) End Function diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb index 4fba5c0c239d2..36456f3d3fb50 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb @@ -22,8 +22,8 @@ Namespace Tests sourceCodeKind As SourceCodeKind, usePreviousCharAsTrigger As Boolean, checkForAbsence As Boolean, glyph As Integer?, matchPriority As Integer?, hasSuggestionItem As Boolean?, displayTextSuffix As String, displayTextPrefix As String, inlineDescription As String, - isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?) As Task - Await VerifyAtPositionAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags) + isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?, Optional skipSpeculation As Boolean = False) As Task + Await VerifyAtPositionAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags, skipSpeculation) Await VerifyAtEndOfFileAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags) End Function diff --git a/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateJsonStringTests.vb b/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateJsonStringTests.vb index 0a249da5a7e12..7e78efb5ca4a1 100644 --- a/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateJsonStringTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateJsonStringTests.vb @@ -22,8 +22,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EmbeddedLanguages Return (New VisualBasicJsonDiagnosticAnalyzer(), Nothing) End Function - Private Shared Function OptionOn() As IdeAnalyzerOptions - Return New IdeAnalyzerOptions(ReportInvalidJsonPatterns:=True) + Private Function OptionOn() As OptionsCollection + Return [Option](IdeAnalyzerOptionsStorage.ReportInvalidJsonPatterns, True) End Function @@ -35,7 +35,7 @@ class Program dim r = ""[|new|] Json()"" end sub end class", - ideAnalyzerOptions:=OptionOn(), + globalOptions:=OptionOn(), diagnosticId:=AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity:=DiagnosticSeverity.Warning, diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, FeaturesResources.Constructors_not_allowed)) @@ -50,7 +50,7 @@ class Program dim r = ""[|}|]"" end sub end class", - ideAnalyzerOptions:=OptionOn(), + globalOptions:=OptionOn(), diagnosticId:=AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity:=DiagnosticSeverity.Warning, diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, @@ -72,7 +72,7 @@ end class ", - ideAnalyzerOptions:=OptionOn(), + globalOptions:=OptionOn(), diagnosticId:=AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity:=DiagnosticSeverity.Warning, diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, @@ -94,7 +94,7 @@ end class ", - ideAnalyzerOptions:=OptionOn(), + globalOptions:=OptionOn(), diagnosticId:=AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity:=DiagnosticSeverity.Warning, diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, @@ -150,7 +150,7 @@ end class ", - ideAnalyzerOptions:=OptionOn(), + globalOptions:=OptionOn(), diagnosticId:=AbstractJsonDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity:=DiagnosticSeverity.Warning, diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, @@ -176,7 +176,7 @@ end class diagnosticSeverity:=DiagnosticSeverity.Warning, diagnosticMessage:=String.Format(FeaturesResources.JSON_issue_0, FeaturesResources.Comments_not_allowed), - IdeAnalyzerOptions:=OptionOn()) + globalOptions:=OptionOn()) End Function diff --git a/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateRegexStringTests.vb b/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateRegexStringTests.vb index 34af3a58fe9e3..9ec4689ae7379 100644 --- a/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateRegexStringTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EmbeddedLanguages/ValidateRegexStringTests.vb @@ -17,8 +17,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EmbeddedLanguages Return (New VisualBasicRegexDiagnosticAnalyzer(), Nothing) End Function - Private Shared Function OptionOn() As IdeAnalyzerOptions - Return New IdeAnalyzerOptions(ReportInvalidRegexPatterns:=True) + Private Function OptionOn() As OptionsCollection + Return [Option](IdeAnalyzerOptionsStorage.ReportInvalidRegexPatterns, True) End Function @@ -31,7 +31,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EmbeddedLanguages var r = new Regex(""[|)|]"") end sub end class", - ideAnalyzerOptions:=OptionOn(), + globalOptions:=OptionOn(), diagnosticId:=AbstractRegexDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity:=DiagnosticSeverity.Warning, diagnosticMessage:=String.Format(FeaturesResources.Regex_issue_0, FeaturesResources.Too_many_close_parens)) @@ -47,7 +47,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.EmbeddedLanguages var r = new Regex(""""""[|)|]"") end sub end class", - ideAnalyzerOptions:=OptionOn(), + globalOptions:=OptionOn(), diagnosticId:=AbstractRegexDiagnosticAnalyzer.DiagnosticId, diagnosticSeverity:=DiagnosticSeverity.Warning, diagnosticMessage:=String.Format(FeaturesResources.Regex_issue_0, FeaturesResources.Too_many_close_parens)) diff --git a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb index 1971505b8115f..6cbec31d92ab9 100644 --- a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb +++ b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.vb @@ -5,7 +5,10 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.CodeCleanup +Imports Microsoft.CodeAnalysis.CodeGeneration +Imports Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.ExtractMethod @@ -111,7 +114,13 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ExtractMethod Assert.True(selectedCode.ContainsValidContext) ' extract method - Dim extractor = New VisualBasicMethodExtractor(CType(selectedCode, VisualBasicSelectionResult)) + Dim extractGenerationOptions = New ExtractMethodGenerationOptions( + extractOptions, + CodeGenerationOptions.GetDefault(document.Project.LanguageServices), + AddImportPlacementOptions.Default, + Function() NamingStylePreferences.Default) + + Dim extractor = New VisualBasicMethodExtractor(CType(selectedCode, VisualBasicSelectionResult), extractGenerationOptions) Dim result = Await extractor.ExtractMethodAsync(CancellationToken.None) Assert.NotNull(result) Assert.Equal(succeeded, result.Succeeded OrElse result.SucceededWithSuggestion) diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb index 321fb6b901808..15d349032adad 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/CodeCleanUpTests.vb @@ -370,7 +370,7 @@ End Class document, enabledDiagnostics, New ProgressTracker, - Function(language) options, + options.CreateProvider(), CancellationToken.None) Dim actual = Await newDoc.GetTextAsync() diff --git a/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormattingEngineTests.vb b/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormattingEngineTests.vb index 029de3c8778f4..6a690c42f4c6f 100644 --- a/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormattingEngineTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Formatting/VisualBasicFormattingEngineTests.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.Editing +Imports Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions Imports Microsoft.CodeAnalysis.Options Imports Xunit.Abstractions @@ -14,9 +15,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Formatting MyBase.New(output) End Sub - Private Shared Function SeparateImportDirectiveGroups() As Dictionary(Of OptionKey, Object) - Return New Dictionary(Of OptionKey, Object) From { - {New OptionKey(GenerationOptions.SeparateImportDirectiveGroups, LanguageNames.VisualBasic), True} + Private Shared Function SeparateImportDirectiveGroups() As OptionsCollection + Return New OptionsCollection(LanguageNames.VisualBasic) From { + {GenerationOptions.SeparateImportDirectiveGroups, True} } End Function diff --git a/src/EditorFeatures/VisualBasicTest/ImplementAbstractClass/ImplementAbstractClassTests.vb b/src/EditorFeatures/VisualBasicTest/ImplementAbstractClass/ImplementAbstractClassTests.vb index aa48f3d80c513..da69ae88b538a 100644 --- a/src/EditorFeatures/VisualBasicTest/ImplementAbstractClass/ImplementAbstractClassTests.vb +++ b/src/EditorFeatures/VisualBasicTest/ImplementAbstractClass/ImplementAbstractClassTests.vb @@ -632,8 +632,7 @@ Class C Throw New System.NotImplementedException() End Set End Property -End Class", parameters:=New TestParameters(codeActionOptions:=New CodeActionOptions( - ImplementTypeOptions:=New ImplementTypeOptions(PropertyGenerationBehavior:=ImplementTypePropertyGenerationBehavior.PreferAutoProperties)))) +End Class", parameters:=New TestParameters(globalOptions:=[Option](ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties))) End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/ImplementInterface/ImplementInterfaceTests.vb b/src/EditorFeatures/VisualBasicTest/ImplementInterface/ImplementInterfaceTests.vb index 7d29a9b6cfd2f..151aa3b22feb1 100644 --- a/src/EditorFeatures/VisualBasicTest/ImplementInterface/ImplementInterfaceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/ImplementInterface/ImplementInterfaceTests.vb @@ -4648,8 +4648,7 @@ class Class Throw New System.NotImplementedException() End Set End Property -end class", parameters:=New TestParameters(codeActionOptions:=New CodeActionOptions( - implementTypeOptions:=New ImplementTypeOptions(PropertyGenerationBehavior:=ImplementTypePropertyGenerationBehavior.PreferAutoProperties)))) +end class", parameters:=New TestParameters(globalOptions:=[Option](ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties))) End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/InvertConditional/InvertIfTests_FixAll.vb b/src/EditorFeatures/VisualBasicTest/InvertConditional/InvertIfTests_FixAll.vb new file mode 100644 index 0000000000000..f54807cc440d9 --- /dev/null +++ b/src/EditorFeatures/VisualBasicTest/InvertConditional/InvertIfTests_FixAll.vb @@ -0,0 +1,368 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeRefactorings + +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.InvertConditional + + Partial Public Class InvertConditionalTests + Inherits AbstractVisualBasicCodeActionTest + + + Public Async Function InvertConditional_FixAllInDocument() As Task + Await TestInRegularAndScriptAsync( +"Class C + Sub M1(x As Boolean, a As Integer, b As Integer) + Dim c = {|FixAllInDocument:|}If(x, a, b) + End Sub + + Sub M2(x As Boolean, a As Integer, b As Integer) + Dim c = If(x, a, b) + End Sub +End Class + +Class C2 + Sub M3(x As Boolean, a As Integer, b As Integer) + Dim c = If(x, a, b) + End Sub +End Class", +"Class C + Sub M1(x As Boolean, a As Integer, b As Integer) + Dim c = If(Not x, b, a) + End Sub + + Sub M2(x As Boolean, a As Integer, b As Integer) + Dim c = If(Not x, b, a) + End Sub +End Class + +Class C2 + Sub M3(x As Boolean, a As Integer, b As Integer) + Dim c = If(Not x, b, a) + End Sub +End Class") + End Function + + + Public Async Function InvertConditional_FixAllInProject() As Task + Dim input = + + + + + + + + Assembly1 + + + + .ToString() + + Dim expected = + + + + + + + + Assembly1 + + + + .ToString() + + Await TestInRegularAndScriptAsync(input, expected) + End Function + + + Public Async Function InvertConditional_FixAllInSolution() As Task + Dim input = + + + + + + + + Assembly1 + + + + .ToString() + + Dim expected = + + + + + + + + Assembly1 + + + + .ToString() + + Await TestInRegularAndScriptAsync(input, expected) + End Function + + + Public Async Function InvertConditional_FixAllInContainingMember() As Task + Await TestInRegularAndScriptAsync( +"Class C + Sub M1(x As Boolean, a As Integer, b As Integer) + Dim c = {|FixAllInContainingMember:|}If(x, a, b) + Dim c2 = If(x, a, b) + End Sub + + Sub M2(x As Boolean, a As Integer, b As Integer) + Dim c = If(x, a, b) + Dim c2 = If(x, a, b) + End Sub +End Class + +Class C2 + Sub M3(x As Boolean, a As Integer, b As Integer) + Dim c = If(x, a, b) + Dim c2 = If(x, a, b) + End Sub +End Class", +"Class C + Sub M1(x As Boolean, a As Integer, b As Integer) + Dim c = If(Not x, b, a) + Dim c2 = If(Not x, b, a) + End Sub + + Sub M2(x As Boolean, a As Integer, b As Integer) + Dim c = If(x, a, b) + Dim c2 = If(x, a, b) + End Sub +End Class + +Class C2 + Sub M3(x As Boolean, a As Integer, b As Integer) + Dim c = If(x, a, b) + Dim c2 = If(x, a, b) + End Sub +End Class") + End Function + + + Public Async Function InvertConditional_FixAllInContainingType() As Task + Await TestInRegularAndScriptAsync( +"Partial Class C + Sub M1(x As Boolean, a As Integer, b As Integer) + Dim c = {|FixAllInContainingType:|}If(x, a, b) + Dim c2 = If(x, a, b) + End Sub + + Sub M2(x As Boolean, a As Integer, b As Integer) + Dim c = If(x, a, b) + Dim c2 = If(x, a, b) + End Sub +End Class + +Class C2 + Sub M3(x As Boolean, a As Integer, b As Integer) + Dim c = If(x, a, b) + Dim c2 = If(x, a, b) + End Sub +End Class + +Partial Class C + Sub M3(x As Boolean, a As Integer, b As Integer) + Dim c = If(x, a, b) + Dim c2 = If(x, a, b) + End Sub +End Class", +"Partial Class C + Sub M1(x As Boolean, a As Integer, b As Integer) + Dim c = If(Not x, b, a) + Dim c2 = If(Not x, b, a) + End Sub + + Sub M2(x As Boolean, a As Integer, b As Integer) + Dim c = If(Not x, b, a) + Dim c2 = If(Not x, b, a) + End Sub +End Class + +Class C2 + Sub M3(x As Boolean, a As Integer, b As Integer) + Dim c = If(x, a, b) + Dim c2 = If(x, a, b) + End Sub +End Class + +Partial Class C + Sub M3(x As Boolean, a As Integer, b As Integer) + Dim c = If(Not x, b, a) + Dim c2 = If(Not x, b, a) + End Sub +End Class") + End Function + + + Public Async Function InvertConditional_FixAllInContainingType_AcrossFiles() As Task + Dim input = + + + + + + + + Assembly1 + + + + .ToString() + + Dim expected = + + + + + + + + Assembly1 + + + + .ToString() + + Await TestInRegularAndScriptAsync(input, expected) + End Function + End Class +End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/SimplifyThisOrMe/SimplifyThisOrMeTests.vb b/src/EditorFeatures/VisualBasicTest/SimplifyThisOrMe/SimplifyThisOrMeTests.vb index a813775d36df7..ac08e836a6fd3 100644 --- a/src/EditorFeatures/VisualBasicTest/SimplifyThisOrMe/SimplifyThisOrMeTests.vb +++ b/src/EditorFeatures/VisualBasicTest/SimplifyThisOrMe/SimplifyThisOrMeTests.vb @@ -34,7 +34,7 @@ End Module Dim parameters3 As New TestParameters() Using workspace = CreateWorkspaceFromOptions(source.ToString(), parameters3) - Dim diagnostics = (Await GetDiagnosticsAsync(workspace, parameters3)).Where(Function(d) d.Id = IDEDiagnosticIds.RemoveQualificationDiagnosticId) + Dim diagnostics = (Await GetDiagnosticsAsync(workspace, parameters3)).Where(Function(d) d.Id = IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId) Assert.Equal(1, diagnostics.Count) End Using End Function @@ -62,7 +62,7 @@ End Class") Await TestDiagnosticInfoAsync( "Class C : Property SomeProperty As Integer : Sub M() : [|Me|].SomeProperty = 1 : End Sub : End Class", options:=New OptionsCollection(GetLanguage()) From {{CodeStyleOptions2.QualifyPropertyAccess, False, NotificationOption2.Error}}, - diagnosticId:=IDEDiagnosticIds.RemoveQualificationDiagnosticId, + diagnosticId:=IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId, diagnosticSeverity:=DiagnosticSeverity.Error) End Function diff --git a/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb b/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb index 73cebdd9aaa55..b107e27c8a443 100644 --- a/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Wrapping/AbstractParameterWrappingTests.vb @@ -15,32 +15,22 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Wrapping Return FlattenActions(actions) End Function - Private Protected Shared Function GetIndentionColumn(column As Integer) As CodeActionOptions - Return New CodeActionOptions(WrappingColumn:=column) + Private Protected Function GetIndentionColumn(column As Integer) As TestParameters + Return New TestParameters(globalOptions:=[Option](CodeActionOptionsStorage.WrappingColumn, column)) End Function Protected Function TestAllWrappingCasesAsync( input As String, ParamArray outputs As String()) As Task - Return TestAllWrappingCasesAsync(input, options:=CodeActionOptions.Default, outputs) + Return TestAllWrappingCasesAsync(input, parameters:=Nothing, outputs) End Function Private Protected Function TestAllWrappingCasesAsync( input As String, - options As CodeActionOptions, + parameters As TestParameters, ParamArray outputs As String()) As Task - Dim parameters = New TestParameters(codeActionOptions:=options) - Return TestAllInRegularAndScriptAsync(input, parameters, outputs) - End Function - - Private Protected Function TestAllWrappingCasesAsync( - input As String, - options As OptionsCollection, - ParamArray outputs As String()) As Task - - Dim parameters = New TestParameters(options:=options) Return TestAllInRegularAndScriptAsync(input, parameters, outputs) End Function End Class diff --git a/src/EditorFeatures/VisualBasicTest/Wrapping/BinaryExpressionWrappingTests.vb b/src/EditorFeatures/VisualBasicTest/Wrapping/BinaryExpressionWrappingTests.vb index c7c78513f5689..c49f0893b74f4 100644 --- a/src/EditorFeatures/VisualBasicTest/Wrapping/BinaryExpressionWrappingTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Wrapping/BinaryExpressionWrappingTests.vb @@ -15,13 +15,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Wrapping Return New VisualBasicWrappingCodeRefactoringProvider() End Function - Private ReadOnly Property EndOfLine As OptionsCollection = [Option]( - CodeStyleOptions2.OperatorPlacementWhenWrapping, - OperatorPlacementWhenWrappingPreference.EndOfLine) + Private ReadOnly Property EndOfLine As TestParameters = + New TestParameters(options:=[Option](CodeStyleOptions2.OperatorPlacementWhenWrapping, OperatorPlacementWhenWrappingPreference.EndOfLine)) - Private ReadOnly Property BeginningOfLine As OptionsCollection = [Option]( - CodeStyleOptions2.OperatorPlacementWhenWrapping, - OperatorPlacementWhenWrappingPreference.BeginningOfLine) + Private ReadOnly Property BeginningOfLine As TestParameters = + New TestParameters(options:=[Option](CodeStyleOptions2.OperatorPlacementWhenWrapping, OperatorPlacementWhenWrappingPreference.BeginningOfLine)) Public Async Function TestMissingWithSyntaxError() As Task diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs index 5fa077cea832c..5b197c99e8a73 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/EEMethodBinder.cs @@ -63,7 +63,7 @@ internal override void LookupSymbolsInSingleBinder(LookupResult result, string n } } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo info, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo info, LookupOptions options, Binder originalBinder) { throw new NotImplementedException(); } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/PlaceholderLocalBinder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/PlaceholderLocalBinder.cs index d4ed8aaee3406..ada1d59f65b20 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/PlaceholderLocalBinder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/PlaceholderLocalBinder.cs @@ -100,7 +100,7 @@ internal sealed override void LookupSymbolsInSingleBinder( } } - protected sealed override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo info, LookupOptions options, Binder originalBinder) + internal sealed override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo info, LookupOptions options, Binder originalBinder) { throw new NotImplementedException(); } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/WithTypeArgumentsBinder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/WithTypeArgumentsBinder.cs index b81bf38e5353d..b52b6a306014d 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/WithTypeArgumentsBinder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Binders/WithTypeArgumentsBinder.cs @@ -43,7 +43,7 @@ protected override MultiDictionary TypeParameterMap } } - protected override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) + internal override void AddLookupSymbolsInfoInSingleBinder(LookupSymbolsInfo result, LookupOptions options, Binder originalBinder) { if (CanConsiderTypeParameters(options)) { diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb index ce4205b6149a4..1b343dabcdafa 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationContext.vb @@ -789,14 +789,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator End If ' There's no real syntax, so there's no real position. We'll give them separate numbers though. - aliases([alias]) = New AliasAndImportsClausePosition(aliasSymbol, position, ImmutableArray(Of AssemblySymbol).Empty) + aliases([alias]) = New AliasAndImportsClausePosition(aliasSymbol, position, syntaxReference:=Nothing, ImmutableArray(Of AssemblySymbol).Empty) Else If importsBuilder Is Nothing Then importsBuilder = ArrayBuilder(Of NamespaceOrTypeAndImportsClausePosition).GetInstance() End If ' There's no real syntax, so there's no real position. We'll give them separate numbers though. - importsBuilder.Add(New NamespaceOrTypeAndImportsClausePosition(typeSymbol, position, ImmutableArray(Of AssemblySymbol).Empty)) + importsBuilder.Add(New NamespaceOrTypeAndImportsClausePosition(typeSymbol, position, syntaxReference:=Nothing, ImmutableArray(Of AssemblySymbol).Empty)) End If ' Dev12 treats the current namespace the same as any other namespace (see ProcedureContext::LoadImportsAndDefaultNamespaceNormal). @@ -826,7 +826,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator End If ' There's no real syntax, so there's no real position. We'll give them separate numbers though. - importsBuilder.Add(New NamespaceOrTypeAndImportsClausePosition(namespaceOrTypeSymbol, position, ImmutableArray(Of AssemblySymbol).Empty)) + importsBuilder.Add(New NamespaceOrTypeAndImportsClausePosition(namespaceOrTypeSymbol, position, syntaxReference:=Nothing, ImmutableArray(Of AssemblySymbol).Empty)) Else Dim aliasSymbol As New AliasSymbol(importBinder.Compilation, importBinder.ContainingNamespaceOrType, [alias], namespaceOrTypeSymbol, NoLocation.Singleton) @@ -835,7 +835,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator End If ' There's no real syntax, so there's no real position. We'll give them separate numbers though. - aliases([alias]) = New AliasAndImportsClausePosition(aliasSymbol, position, ImmutableArray(Of AssemblySymbol).Empty) + aliases([alias]) = New AliasAndImportsClausePosition(aliasSymbol, position, syntaxReference:=Nothing, ImmutableArray(Of AssemblySymbol).Empty) End If Case ImportTargetKind.NamespaceOrType ' Aliased namespace or type (native PDB only) @@ -858,7 +858,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator End If ' There's no real syntax, so there's no real position. We'll give them separate numbers though. - aliases([alias]) = New AliasAndImportsClausePosition(aliasSymbol, position, ImmutableArray(Of AssemblySymbol).Empty) + aliases([alias]) = New AliasAndImportsClausePosition(aliasSymbol, position, syntaxReference:=Nothing, ImmutableArray(Of AssemblySymbol).Empty) Case ImportTargetKind.XmlNamespace If xmlImports Is Nothing Then @@ -866,7 +866,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator End If ' There's no real syntax, so there's no real position. We'll give them separate numbers though. - xmlImports(importRecord.Alias) = New XmlNamespaceAndImportsClausePosition(importRecord.TargetString, position) + xmlImports(importRecord.Alias) = New XmlNamespaceAndImportsClausePosition(importRecord.TargetString, position, syntaxReference:=Nothing) Case ImportTargetKind.DefaultNamespace ' Processed ahead of time so that it can be incorporated into the compilation before ' constructing the binder chain. diff --git a/src/Features/CSharp/Portable/AssignOutParameters/AbstractAssignOutParametersCodeFixProvider.cs b/src/Features/CSharp/Portable/AssignOutParameters/AbstractAssignOutParametersCodeFixProvider.cs index 7115f93fc94fe..c0f6db0bc86e3 100644 --- a/src/Features/CSharp/Portable/AssignOutParameters/AbstractAssignOutParametersCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/AssignOutParameters/AbstractAssignOutParametersCodeFixProvider.cs @@ -165,13 +165,5 @@ protected static ImmutableArray GenerateAssignmentStatements( return result.ToImmutableAndFree(); } - - protected class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/CSharp/Portable/AssignOutParameters/AssignOutParametersAtStartCodeFixProvider.cs b/src/Features/CSharp/Portable/AssignOutParameters/AssignOutParametersAtStartCodeFixProvider.cs index 94c3e91b87e78..2f78ec398d8c5 100644 --- a/src/Features/CSharp/Portable/AssignOutParameters/AssignOutParametersAtStartCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/AssignOutParameters/AssignOutParametersAtStartCodeFixProvider.cs @@ -9,6 +9,7 @@ using System.Composition; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; @@ -50,7 +51,10 @@ statement.Parent is BlockSyntax block && } context.RegisterCodeFix( - new MyCodeAction(CSharpFeaturesResources.Assign_out_parameters_at_start, GetDocumentUpdater(context)), + CodeAction.Create( + CSharpFeaturesResources.Assign_out_parameters_at_start, + GetDocumentUpdater(context), + nameof(CSharpFeaturesResources.Assign_out_parameters_at_start)), context.Diagnostics); } diff --git a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx index 127cf6526a7fb..88e584a3c32d3 100644 --- a/src/Features/CSharp/Portable/CSharpFeaturesResources.resx +++ b/src/Features/CSharp/Portable/CSharpFeaturesResources.resx @@ -559,8 +559,12 @@ Convert to raw string - - Convert to raw string (no indent) + + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" Apply blank lines between consecutive braces preferences (experimental) @@ -617,4 +621,10 @@ Add 'await' {Locked="await"} "await" is a C# keyword and should not be localized. + + Global 'using' directives + + + Apply UTF-8 string literal preferences + \ No newline at end of file diff --git a/src/Features/CSharp/Portable/CodeFixes/ConditionalExpressionInStringInterpolation/CSharpAddParenthesesAroundConditionalExpressionInInterpolatedStringCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/ConditionalExpressionInStringInterpolation/CSharpAddParenthesesAroundConditionalExpressionInInterpolatedStringCodeFixProvider.cs index 2477f7b27e3ed..a2b23bfbc8af4 100644 --- a/src/Features/CSharp/Portable/CodeFixes/ConditionalExpressionInStringInterpolation/CSharpAddParenthesesAroundConditionalExpressionInInterpolatedStringCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/ConditionalExpressionInStringInterpolation/CSharpAddParenthesesAroundConditionalExpressionInInterpolatedStringCodeFixProvider.cs @@ -43,8 +43,10 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var conditionalExpression = token.GetAncestor(); if (conditionalExpression != null) { - var documentChangeAction = new MyCodeAction( - c => GetChangedDocumentAsync(context.Document, conditionalExpression.SpanStart, c)); + var documentChangeAction = CodeAction.Create( + CSharpFeaturesResources.Add_parentheses_around_conditional_expression_in_interpolated_string, + c => GetChangedDocumentAsync(context.Document, conditionalExpression.SpanStart, c), + nameof(CSharpFeaturesResources.Add_parentheses_around_conditional_expression_in_interpolated_string)); context.RegisterCodeFix(documentChangeAction, diagnostic); } } @@ -122,15 +124,5 @@ private static async Task InsertCloseParenthesisAsync( var newRoot = root.ReplaceNode(parenthesizedExpression, parenthesizedExpressionWithClosingParen); return document.WithSyntaxRoot(newRoot); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(CSharpFeaturesResources.Add_parentheses_around_conditional_expression_in_interpolated_string, - createChangedDocument, - CSharpFeaturesResources.Add_parentheses_around_conditional_expression_in_interpolated_string) - { - } - } } } diff --git a/src/Features/CSharp/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.cs index 5733e097c47af..e78454a629baf 100644 --- a/src/Features/CSharp/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeFixes.GenerateMember; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.GenerateMember.GenerateEnumMember; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -35,10 +36,10 @@ public override ImmutableArray FixableDiagnosticIds get { return ImmutableArray.Create(CS0117); } } - protected override Task> GetCodeActionsAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) + protected override Task> GetCodeActionsAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var service = document.GetLanguageService(); - return service.GenerateEnumMemberAsync(document, node, cancellationToken); + return service.GenerateEnumMemberAsync(document, node, fallbackOptions, cancellationToken); } protected override bool IsCandidate(SyntaxNode node, SyntaxToken token, Diagnostic diagnostic) diff --git a/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateConversionCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateConversionCodeFixProvider.cs index 138f868763ba6..f22c1a9d68609 100644 --- a/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateConversionCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateConversionCodeFixProvider.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeFixes.GenerateMember; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; @@ -58,10 +59,10 @@ node is SimpleNameSyntax || } protected override Task> GetCodeActionsAsync( - Document document, SyntaxNode node, CancellationToken cancellationToken) + Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var service = document.GetRequiredLanguageService(); - return service.GenerateConversionAsync(document, node, cancellationToken); + return service.GenerateConversionAsync(document, node, fallbackOptions, cancellationToken); } } } diff --git a/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateDeconstructMethodCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateDeconstructMethodCodeFixProvider.cs index b48e6c487dc6b..d2aa4d84939a5 100644 --- a/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateDeconstructMethodCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateDeconstructMethodCodeFixProvider.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; @@ -95,7 +96,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) } var service = document.GetLanguageService(); - var codeActions = await service.GenerateDeconstructMethodAsync(document, target, (INamedTypeSymbol)type, cancellationToken).ConfigureAwait(false); + var codeActions = await service.GenerateDeconstructMethodAsync(document, target, (INamedTypeSymbol)type, context.Options, cancellationToken).ConfigureAwait(false); Debug.Assert(!codeActions.IsDefault); context.RegisterFixes(codeActions, context.Diagnostics); diff --git a/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateMethodCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateMethodCodeFixProvider.cs index c0a307f077a85..b0c7106671855 100644 --- a/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateMethodCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/GenerateMethod/GenerateMethodCodeFixProvider.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeFixes.GenerateMember; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember; @@ -54,7 +55,7 @@ internal static class GenerateMethodDiagnosticIds [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.GenerateMethod), Shared] [ExtensionOrder(After = PredefinedCodeFixProviderNames.GenerateEnumMember, Before = PredefinedCodeFixProviderNames.PopulateSwitch)] - internal class GenerateMethodCodeFixProvider : AbstractGenerateMemberCodeFixProvider + internal sealed class GenerateMethodCodeFixProvider : AbstractGenerateMemberCodeFixProvider { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] @@ -90,10 +91,10 @@ node is SimpleNameSyntax || } protected override Task> GetCodeActionsAsync( - Document document, SyntaxNode node, CancellationToken cancellationToken) + Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var service = document.GetRequiredLanguageService(); - return service.GenerateMethodAsync(document, node, cancellationToken); + return service.GenerateMethodAsync(document, node, fallbackOptions, cancellationToken); } } } diff --git a/src/Features/CSharp/Portable/CodeFixes/GenerateType/GenerateTypeCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/GenerateType/GenerateTypeCodeFixProvider.cs index 0ad17420edac7..9121c0a7537cb 100644 --- a/src/Features/CSharp/Portable/CodeFixes/GenerateType/GenerateTypeCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/GenerateType/GenerateTypeCodeFixProvider.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeFixes.GenerateMember; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; @@ -61,10 +62,10 @@ protected override bool IsCandidate(SyntaxNode node, SyntaxToken token, Diagnost => ((ExpressionSyntax)node).GetRightmostName(); protected override Task> GetCodeActionsAsync( - Document document, SyntaxNode node, CancellationToken cancellationToken) + Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var service = document.GetRequiredLanguageService(); - return service.GenerateTypeAsync(document, node, cancellationToken); + return service.GenerateTypeAsync(document, node, fallbackOptions, cancellationToken); } } } diff --git a/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs index d0e16360066bf..5b33e03890ebb 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.CodeGeneration; @@ -59,8 +60,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); context.RegisterRefactoring( - new MyCodeAction( - c => UpdateDocumentAsync(root, document, parentBlock, localFunction, c)), + CodeAction.Create( + CSharpFeaturesResources.Convert_to_method, + c => UpdateDocumentAsync(root, document, parentBlock, localFunction, context.Options, c), + nameof(CSharpFeaturesResources.Convert_to_method)), localFunction.Span); } @@ -69,6 +72,7 @@ private static async Task UpdateDocumentAsync( Document document, BlockSyntax parentBlock, LocalFunctionStatementSyntax localFunction, + CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); @@ -125,8 +129,9 @@ private static async Task UpdateDocumentAsync( typeParameters: typeParameters.ToImmutableArray(), parameters: parameters.AddRange(capturesAsParameters)); - var defaultOptions = await CSharpCodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, document, cancellationToken).ConfigureAwait(false); - var method = MethodGenerator.GenerateMethodDeclaration(methodSymbol, CodeGenerationDestination.Unspecified, defaultOptions, cancellationToken); + var options = await document.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); + var info = (CSharpCodeGenerationContextInfo)options.GetInfo(CodeGenerationContext.Default, document.Project); + var method = MethodGenerator.GenerateMethodDeclaration(methodSymbol, CodeGenerationDestination.Unspecified, info, cancellationToken); var generator = s_generator; var editor = new SyntaxEditor(root, generator); @@ -312,13 +317,5 @@ private static string GenerateUniqueMethodName(ISymbol declaredSymbol) baseName: declaredSymbol.Name, reservedNames: declaredSymbol.ContainingType.GetMembers().Select(m => m.Name)); } - - private sealed class MyCodeAction : CodeActions.CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(CSharpFeaturesResources.Convert_to_method, createChangedDocument, nameof(CSharpFeaturesResources.Convert_to_method)) - { - } - } } } diff --git a/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs index 706522c837a47..7d79b413f7714 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/EnableNullable/EnableNullableCodeRefactoringProvider.cs @@ -59,7 +59,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } context.RegisterRefactoring( - new MyCodeAction((purpose, cancellationToken) => EnableNullableReferenceTypesAsync(document.Project, purpose, cancellationToken))); + new CustomCodeAction((purpose, cancellationToken) => EnableNullableReferenceTypesAsync(document.Project, purpose, cancellationToken))); } private static async Task EnableNullableReferenceTypesAsync(Project project, CodeActionPurpose purpose, CancellationToken cancellationToken) @@ -252,11 +252,11 @@ private enum CodeActionPurpose Apply, } - private sealed class MyCodeAction : CodeAction.SolutionChangeAction + private sealed class CustomCodeAction : CodeAction.SolutionChangeAction { private readonly Func> _createChangedSolution; - public MyCodeAction(Func> createChangedSolution) + public CustomCodeAction(Func> createChangedSolution) : base( CSharpFeaturesResources.Enable_nullable_reference_types_in_project, cancellationToken => createChangedSolution(CodeActionPurpose.Apply, cancellationToken), diff --git a/src/Features/CSharp/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.cs index b29730693a352..ba30e2cacd2ff 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.cs @@ -91,7 +91,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; context.RegisterRefactoring( - new MyCodeAction(c => InlineTemporaryAsync(document, variableDeclarator, c)), + CodeAction.Create( + CSharpFeaturesResources.Inline_temporary_variable, + c => InlineTemporaryAsync(document, variableDeclarator, c), + nameof(CSharpFeaturesResources.Inline_temporary_variable)), variableDeclarator.Span); } @@ -442,13 +445,5 @@ private static bool IsInDeconstructionAssignmentLeft(ExpressionSyntax node) return false; } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(CSharpFeaturesResources.Inline_temporary_variable, createChangedDocument, nameof(CSharpFeaturesResources.Inline_temporary_variable)) - { - } - } } } diff --git a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs index c4fc06cc4234e..e98ef32c730ee 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs @@ -66,9 +66,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } context.RegisterRefactoring( - new MyCodeAction( + CodeAction.Create( Title, - c => UpdateDocumentAsync(document, declaredType, c)), + c => UpdateDocumentAsync(document, declaredType, c), + Title), declaredType.Span); } @@ -130,13 +131,5 @@ private async Task UpdateDocumentAsync(Document document, TypeSyntax t var newRoot = editor.GetChangedRoot(); return document.WithSyntaxRoot(newRoot); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs index 74bae4627819c..3f3a371d406e5 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/UseRecursivePatterns/UseRecursivePatternsCodeRefactoringProvider.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; @@ -59,7 +60,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; context.RegisterRefactoring( - new MyCodeAction( + CodeAction.Create( CSharpFeaturesResources.Use_recursive_patterns, _ => Task.FromResult(document.WithSyntaxRoot(replacementFunc(root))), nameof(CSharpFeaturesResources.Use_recursive_patterns))); @@ -502,13 +503,5 @@ when canConvertToSubpattern(name, arg) && !memberAccess.Expression.IsKind(Syntax } } } - - private sealed class MyCodeAction : CodeActions.CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument, string equivalenceKey) - : base(title, createChangedDocument, equivalenceKey) - { - } - } } } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs index d18b025f07732..49bca936189e5 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs @@ -66,6 +66,14 @@ public override async Task ProvideCompletionsAsync(CompletionContext completionC return; } + // Do not show name suggestions for unbound "async" identifier. + // Most likely user is writing an async method, so name suggestion will just interfere him + if (context.TargetToken.IsKindOrHasMatchingText(SyntaxKind.AsyncKeyword) && + semanticModel.GetSymbolInfo(context.TargetToken).GetAnySymbol() is null) + { + return; + } + var nameInfo = await NameDeclarationInfo.GetDeclarationInfoAsync(document, position, cancellationToken).ConfigureAwait(false); using var _ = ArrayBuilder<(string name, SymbolKind kind)>.GetInstance(out var result); diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs index 8da7c5ef788fa..fdb2f82bd4818 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/PropertySubPatternCompletionProvider.cs @@ -203,7 +203,7 @@ bool IsExtendedPropertyPattern(MemberAccessExpressionSyntax memberAccess, [NotNu memberAccess = (MemberAccessExpressionSyntax)memberAccess.Parent; } - if (memberAccess is { Parent: { Parent: SubpatternSyntax { Parent: PropertyPatternClauseSyntax found } } }) + if (memberAccess is { Parent.Parent: SubpatternSyntax { Parent: PropertyPatternClauseSyntax found } }) { propertyPatternClause = found; return true; diff --git a/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs index c837c80b34065..c495d3b67ff18 100644 --- a/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs @@ -25,7 +25,7 @@ namespace Microsoft.CodeAnalysis.CSharp.ConvertAutoPropertyToFullProperty { [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.ConvertAutoPropertyToFullProperty), Shared] - internal class CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider : AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider + internal class CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider : AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] @@ -46,7 +46,7 @@ internal override async Task GetFieldNameAsync(Document document, IPrope } internal override (SyntaxNode newGetAccessor, SyntaxNode newSetAccessor) GetNewAccessors( - CSharpCodeGenerationPreferences preferences, SyntaxNode property, + CSharpCodeGenerationContextInfo info, SyntaxNode property, string fieldName, SyntaxGenerator generator) { // C# might have trivia with the accessors that needs to be preserved. @@ -55,7 +55,7 @@ internal override (SyntaxNode newGetAccessor, SyntaxNode newSetAccessor) GetNewA var (getAccessor, setAccessor) = GetExistingAccessors(accessorListSyntax); var getAccessorStatement = generator.ReturnStatement(generator.IdentifierName(fieldName)); - var newGetter = GetUpdatedAccessor(preferences, getAccessor, getAccessorStatement); + var newGetter = GetUpdatedAccessor(info, getAccessor, getAccessorStatement); SyntaxNode newSetter = null; if (setAccessor != null) @@ -63,7 +63,7 @@ internal override (SyntaxNode newGetAccessor, SyntaxNode newSetAccessor) GetNewA var setAccessorStatement = generator.ExpressionStatement(generator.AssignmentStatement( generator.IdentifierName(fieldName), generator.IdentifierName("value"))); - newSetter = GetUpdatedAccessor(preferences, setAccessor, setAccessorStatement); + newSetter = GetUpdatedAccessor(info, setAccessor, setAccessorStatement); } return (newGetAccessor: newGetter, newSetAccessor: newSetter); @@ -75,20 +75,20 @@ private static (AccessorDeclarationSyntax getAccessor, AccessorDeclarationSyntax accessorListSyntax.Accessors.FirstOrDefault(a => a.IsKind(SyntaxKind.SetAccessorDeclaration) || a.IsKind(SyntaxKind.InitAccessorDeclaration))); - private static SyntaxNode GetUpdatedAccessor(CSharpCodeGenerationPreferences preferences, + private static SyntaxNode GetUpdatedAccessor(CSharpCodeGenerationContextInfo info, SyntaxNode accessor, SyntaxNode statement) { var newAccessor = AddStatement(accessor, statement); var accessorDeclarationSyntax = (AccessorDeclarationSyntax)newAccessor; - var preference = preferences.PreferExpressionBodiedAccessors; + var preference = info.Options.PreferExpressionBodiedAccessors.Value; if (preference == ExpressionBodyPreference.Never) { return accessorDeclarationSyntax.WithSemicolonToken(default); } if (!accessorDeclarationSyntax.Body.TryConvertToArrowExpressionBody( - accessorDeclarationSyntax.Kind(), preferences.LanguageVersion, preference, + accessorDeclarationSyntax.Kind(), info.LanguageVersion, preference, out var arrowExpression, out _)) { return accessorDeclarationSyntax.WithSemicolonToken(default); @@ -113,11 +113,11 @@ internal static SyntaxNode AddStatement(SyntaxNode accessor, SyntaxNode statemen } internal override SyntaxNode ConvertPropertyToExpressionBodyIfDesired( - CSharpCodeGenerationPreferences preferences, SyntaxNode property) + CSharpCodeGenerationContextInfo info, SyntaxNode property) { var propertyDeclaration = (PropertyDeclarationSyntax)property; - var preference = preferences.PreferExpressionBodiedProperties; + var preference = info.Options.PreferExpressionBodiedProperties.Value; if (preference == ExpressionBodyPreference.Never) { return propertyDeclaration.WithSemicolonToken(default); diff --git a/src/Features/CSharp/Portable/ConvertBetweenRegularAndVerbatimString/AbstractConvertBetweenRegularAndVerbatimStringCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertBetweenRegularAndVerbatimString/AbstractConvertBetweenRegularAndVerbatimStringCodeRefactoringProvider.cs index fae50a6885574..26e6cea3c14ac 100644 --- a/src/Features/CSharp/Portable/ConvertBetweenRegularAndVerbatimString/AbstractConvertBetweenRegularAndVerbatimStringCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertBetweenRegularAndVerbatimString/AbstractConvertBetweenRegularAndVerbatimStringCodeRefactoringProvider.cs @@ -53,20 +53,28 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex return; } + // Note: This is a generally useful feature on strings. But it's not likely to be something + // people want to use a lot. Make low priority so it doesn't interfere with more + // commonly useful refactorings. + if (IsVerbatim(literalExpression)) { // always offer to convert from verbatim string to normal string. - context.RegisterRefactoring(new MyCodeAction( + context.RegisterRefactoring(CodeAction.CreateWithPriority( + CodeActionPriority.Low, CSharpFeaturesResources.Convert_to_regular_string, - c => ConvertToRegularStringAsync(document, literalExpression, c))); + c => ConvertToRegularStringAsync(document, literalExpression, c), + nameof(CSharpFeaturesResources.Convert_to_regular_string))); } else if (ContainsSimpleEscape(charService, subStringTokens)) { // Offer to convert to a verbatim string if the normal string contains simple // escapes that can be directly embedded in the verbatim string. - context.RegisterRefactoring(new MyCodeAction( + context.RegisterRefactoring(CodeAction.CreateWithPriority( + CodeActionPriority.Low, CSharpFeaturesResources.Convert_to_verbatim_string, - c => ConvertToVerbatimStringAsync(document, literalExpression, c))); + c => ConvertToVerbatimStringAsync(document, literalExpression, c), + nameof(CSharpFeaturesResources.Convert_to_verbatim_string))); } } @@ -176,20 +184,5 @@ private static bool ContainsSimpleEscape(VirtualCharSequence chars) return false; } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - /// - /// This is a generally useful feature on strings. But it's not likely to be something - /// people want to use a lot. Make low priority so it doesn't interfere with more - /// commonly useful refactorings. - /// - internal override CodeActionPriority Priority => CodeActionPriority.Low; - - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs b/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs index 10008ce65faee..29d2daf285e83 100644 --- a/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs +++ b/src/Features/CSharp/Portable/ConvertLinq/CSharpConvertLinqQueryToForEachProvider.cs @@ -57,14 +57,13 @@ private sealed class Converter private readonly ISemanticFactsService _semanticFacts; private readonly CancellationToken _cancellationToken; private readonly QueryExpressionSyntax _source; - private readonly List _introducedLocalNames; + private readonly List _introducedLocalNames = new(); public Converter(SemanticModel semanticModel, ISemanticFactsService semanticFacts, QueryExpressionSyntax source, CancellationToken cancellationToken) { _semanticModel = semanticModel; _semanticFacts = semanticFacts; _source = source; - _introducedLocalNames = new List(); _cancellationToken = cancellationToken; } diff --git a/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs index 2acc1e04063e5..3c178f167981c 100644 --- a/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertNamespace/ConvertNamespaceCodeRefactoringProvider.cs @@ -55,7 +55,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(context.Options, cancellationToken).ConfigureAwait(false); - context.RegisterRefactoring(new MyCodeAction( + context.RegisterRefactoring(CodeAction.Create( info.Value.title, c => ConvertAsync(document, namespaceDecl, formattingOptions, c), info.Value.equivalenceKey)); } @@ -72,13 +72,5 @@ private static bool IsValidPosition(BaseNamespaceDeclarationSyntax baseDeclarati throw ExceptionUtilities.UnexpectedValue(baseDeclaration.Kind()); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument, string equivalenceKey) - : base(title, createChangedDocument, equivalenceKey) - { - } - } } } diff --git a/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeRefactoringProvider.cs index 1c496722902cc..b9abd701ffcf9 100644 --- a/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertProgram/ConvertToProgramMainCodeRefactoringProvider.cs @@ -56,18 +56,11 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (!CanOfferUseProgramMain(option, root, compilation, forAnalyzer: false)) return; - context.RegisterRefactoring(new MyCodeAction( - c => ConvertToProgramMainAsync(document, c))); - } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - internal override CodeActionPriority Priority => CodeActionPriority.Low; - - public MyCodeAction(Func> createChangedDocument) - : base(CSharpAnalyzersResources.Convert_to_Program_Main_style_program, createChangedDocument, nameof(ConvertToProgramMainCodeRefactoringProvider)) - { - } + context.RegisterRefactoring(CodeAction.CreateWithPriority( + CodeActionPriority.Low, + CSharpAnalyzersResources.Convert_to_Program_Main_style_program, + c => ConvertToProgramMainAsync(document, c), + nameof(CSharpAnalyzersResources.Convert_to_Program_Main_style_program))); } } } diff --git a/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeFixProvider.cs b/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeFixProvider.cs index 1191dbc1a80e7..ae2f17192632e 100644 --- a/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeFixProvider.cs @@ -52,7 +52,7 @@ protected override async Task FixAllAsync( { var methodDeclaration = (MethodDeclarationSyntax)diagnostics[0].AdditionalLocations[0].FindNode(cancellationToken); - var newDocument = await ConvertToTopLevelStatementsAsync(document, methodDeclaration, CodeCleanupOptions.CreateProvider(fallbackOptions), cancellationToken).ConfigureAwait(false); + var newDocument = await ConvertToTopLevelStatementsAsync(document, methodDeclaration, fallbackOptions, cancellationToken).ConfigureAwait(false); var newRoot = await newDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); editor.ReplaceNode(editor.OriginalRoot, newRoot); diff --git a/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeRefactoringProvider.cs index 843957b96f647..162d37ca62a9b 100644 --- a/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertProgram/ConvertToTopLevelStatementsCodeRefactoringProvider.cs @@ -59,18 +59,11 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - context.RegisterRefactoring(new MyCodeAction( - c => ConvertToTopLevelStatementsAsync(document, methodDeclaration, CodeCleanupOptions.CreateProvider(context.Options), c))); - } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - internal override CodeActionPriority Priority => CodeActionPriority.Low; - - public MyCodeAction(Func> createChangedDocument) - : base(CSharpAnalyzersResources.Convert_to_top_level_statements, createChangedDocument, nameof(ConvertToTopLevelStatementsCodeRefactoringProvider)) - { - } + context.RegisterRefactoring(CodeAction.CreateWithPriority( + CodeActionPriority.Low, + CSharpAnalyzersResources.Convert_to_top_level_statements, + c => ConvertToTopLevelStatementsAsync(document, methodDeclaration, context.Options, c), + nameof(CSharpAnalyzersResources.Convert_to_top_level_statements))); } } } diff --git a/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs index bbc12f32f46b8..cb7f451956a34 100644 --- a/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertToRawString/ConvertRegularStringToRawStringCodeRefactoringProvider.cs @@ -3,12 +3,18 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Immutable; using System.Composition; +using System.Linq; +using System.Reflection.PortableExecutable; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.EmbeddedLanguages.VirtualChars; +using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Indentation; @@ -27,8 +33,8 @@ internal class ConvertRegularStringToRawStringCodeRefactoringProvider : CodeRefa private enum ConvertToRawKind { SingleLine, - MultiLine, MultiLineIndented, + MultiLineWithoutLeadingWhitespace, } [ImportingConstructor] @@ -76,39 +82,71 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (canBeSingleLine) { context.RegisterRefactoring( - new MyCodeAction( + CodeAction.CreateWithPriority( + priority, CSharpFeaturesResources.Convert_to_raw_string, c => UpdateDocumentAsync(document, span, ConvertToRawKind.SingleLine, formattingOptions, c), - nameof(CSharpFeaturesResources.Convert_to_raw_string) + "-" + ConvertToRawKind.SingleLine, - priority), + nameof(CSharpFeaturesResources.Convert_to_raw_string) + "-" + ConvertToRawKind.SingleLine), token.Span); } else { - var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(true); - sourceText.GetLineAndOffset(token.SpanStart, out _, out var lineOffset); - context.RegisterRefactoring( - new MyCodeAction( + CodeAction.CreateWithPriority( + priority, CSharpFeaturesResources.Convert_to_raw_string, c => UpdateDocumentAsync(document, span, ConvertToRawKind.MultiLineIndented, formattingOptions, c), - nameof(CSharpFeaturesResources.Convert_to_raw_string), - priority), + nameof(CSharpFeaturesResources.Convert_to_raw_string)), token.Span); - if (lineOffset > 0) + // Users sometimes write verbatim string literals with a extra starting newline (or indentation) purely + // for aesthetic reasons. For example: + // + // var v = @" + // SELECT column1, column2, ... + // FROM table_name"; + // + // Converting this directly to a raw string will produce: + // + // var v = """ + // + // SELECT column1, column2, ... + // FROM table_name"; + // """ + // + // Check for this and offer instead to generate: + // + // var v = """ + // SELECT column1, column2, ... + // FROM table_name"; + // """ + // + // This changes the contents of the literal, but that can be fine for the domain the user is working in. + // Offer this, but let the user know that this will change runtime semantics. + if (token.IsVerbatimStringLiteral() && + HasLeadingWhitespace(characters) && + CleanupWhitespace(characters).Length > 0) { context.RegisterRefactoring( - new MyCodeAction( - CSharpFeaturesResources.Convert_to_raw_string_no_indent, - c => UpdateDocumentAsync(document, span, ConvertToRawKind.MultiLine, formattingOptions, c), - nameof(CSharpFeaturesResources.Convert_to_raw_string_no_indent), - priority), + CodeAction.CreateWithPriority( + priority, + CSharpFeaturesResources.without_leading_whitespace_may_change_semantics, + c => UpdateDocumentAsync(document, span, ConvertToRawKind.MultiLineWithoutLeadingWhitespace, formattingOptions, c), + nameof(CSharpFeaturesResources.without_leading_whitespace_may_change_semantics)), token.Span); } } } + private static bool HasLeadingWhitespace(VirtualCharSequence characters) + { + var index = 0; + while (index < characters.Length && IsCSharpWhitespace(characters[index])) + index++; + + return index < characters.Length && IsCSharpNewLine(characters[index]); + } + private static async Task UpdateDocumentAsync( Document document, TextSpan span, ConvertToRawKind kind, SyntaxFormattingOptions options, CancellationToken cancellationToken) { @@ -128,20 +166,148 @@ private static SyntaxToken GetReplacementToken( SyntaxFormattingOptions options, CancellationToken cancellationToken) { - return kind switch + var characters = CSharpVirtualCharService.Instance.TryConvertToVirtualChars(token); + Contract.ThrowIfTrue(characters.IsDefaultOrEmpty); + + // If the user asked to remove whitespace then do so now. + if (kind == ConvertToRawKind.MultiLineWithoutLeadingWhitespace) + characters = CleanupWhitespace(characters); + + return kind == ConvertToRawKind.SingleLine + ? ConvertToSingleLineRawString(token, characters) + : ConvertToMultiLineRawIndentedString(document, token, options, characters, cancellationToken); + } + + private static VirtualCharSequence CleanupWhitespace(VirtualCharSequence characters) + { + using var _ = ArrayBuilder.GetInstance(out var lines); + + // First, determine all the lines in the content. + BreakIntoLines(characters, lines); + + // Remove the leading and trailing line if they are all whitespace. + while (lines.Count > 0 && AllWhitespace(lines.First())) + lines.RemoveAt(0); + + while (lines.Count > 0 && AllWhitespace(lines.Last())) + lines.RemoveAt(lines.Count - 1); + + if (lines.Count == 0) + return VirtualCharSequence.Empty; + + // Use the remaining lines to figure out what common whitespace we have. + var commonWhitespacePrefix = ComputeCommonWhitespacePrefix(lines); + + var result = ImmutableSegmentedList.CreateBuilder(); + + foreach (var line in lines) { - ConvertToRawKind.SingleLine => ConvertToSingleLineRawString(token), - ConvertToRawKind.MultiLine => ConvertToMultiLineRawString(token, options.NewLine), - ConvertToRawKind.MultiLineIndented => ConvertToMultiLineRawIndentedString(document, token, options, cancellationToken), - _ => throw ExceptionUtilities.UnexpectedValue(kind), - }; + if (AllWhitespace(line)) + { + // For an all-whitespace line, just add the trailing newlines on the line (if present). + AddRange(result, line.SkipWhile(IsCSharpWhitespace)); + } + else + { + // Normal line. Skip the common whitespace. + AddRange(result, line.Skip(commonWhitespacePrefix)); + } + } + + // Remove all trailing whitespace and newlines from the final string. + while (result.Count > 0 && (IsCSharpNewLine(result[^1]) || IsCSharpWhitespace(result[^1]))) + result.RemoveAt(result.Count - 1); + + return VirtualCharSequence.Create(result.ToImmutable()); } - private static SyntaxToken ConvertToMultiLineRawIndentedString(Document document, SyntaxToken token, SyntaxFormattingOptions formattingOptions, CancellationToken cancellationToken) + private static void AddRange(ImmutableSegmentedList.Builder result, VirtualCharSequence sequence) { - var characters = CSharpVirtualCharService.Instance.TryConvertToVirtualChars(token); - Contract.ThrowIfTrue(characters.IsDefaultOrEmpty); + foreach (var c in sequence) + result.Add(c); + } + + private static int ComputeCommonWhitespacePrefix(ArrayBuilder lines) + { + var commonLeadingWhitespace = GetLeadingWhitespace(lines.First()); + + for (var i = 1; i < lines.Count; i++) + { + if (commonLeadingWhitespace.IsEmpty) + return 0; + + var currentLine = lines[i]; + if (AllWhitespace(currentLine)) + continue; + + var currentLineLeadingWhitespace = GetLeadingWhitespace(currentLine); + commonLeadingWhitespace = ComputeCommonWhitespacePrefix(commonLeadingWhitespace, currentLineLeadingWhitespace); + } + + return commonLeadingWhitespace.Length; + } + + private static VirtualCharSequence ComputeCommonWhitespacePrefix( + VirtualCharSequence leadingWhitespace1, VirtualCharSequence leadingWhitespace2) + { + var length = Math.Min(leadingWhitespace1.Length, leadingWhitespace2.Length); + + var current = 0; + while (current < length && IsCSharpWhitespace(leadingWhitespace1[current]) && leadingWhitespace1[current].Rune == leadingWhitespace2[current].Rune) + current++; + + return leadingWhitespace1.GetSubSequence(TextSpan.FromBounds(0, current)); + } + + private static VirtualCharSequence GetLeadingWhitespace(VirtualCharSequence line) + { + var current = 0; + while (current < line.Length && IsCSharpWhitespace(line[current])) + current++; + + return line.GetSubSequence(TextSpan.FromBounds(0, current)); + } + + private static void BreakIntoLines(VirtualCharSequence characters, ArrayBuilder lines) + { + var index = 0; + + while (index < characters.Length) + lines.Add(GetNextLine(characters, ref index)); + } + private static VirtualCharSequence GetNextLine( + VirtualCharSequence characters, + ref int index) + { + var end = index; + while (end < characters.Length && !IsCSharpNewLine(characters[end])) + end++; + + if (end != characters.Length) + end += IsCarriageReturnNewLine(characters, end) ? 2 : 1; + + var result = characters.GetSubSequence(TextSpan.FromBounds(index, end)); + index = end; + return result; + } + + private static bool AllWhitespace(VirtualCharSequence line) + { + var index = 0; + while (index < line.Length && IsCSharpWhitespace(line[index])) + index++; + + return index == line.Length || IsCSharpNewLine(line[index]); + } + + private static SyntaxToken ConvertToMultiLineRawIndentedString( + Document document, + SyntaxToken token, + SyntaxFormattingOptions formattingOptions, + VirtualCharSequence characters, + CancellationToken cancellationToken) + { // Have to make sure we have a delimiter longer than any quote sequence in the string. var longestQuoteSequence = GetLongestQuoteSequence(characters); var quoteDelimeterCount = Math.Max(3, longestQuoteSequence + 1); @@ -159,7 +325,7 @@ private static SyntaxToken ConvertToMultiLineRawIndentedString(Document document for (int i = 0, n = characters.Length; i < n; i++) { var ch = characters[i]; - if (IsNewLine(ch)) + if (IsCSharpNewLine(ch)) { ch.AppendTo(builder); atStartOfLine = true; @@ -187,39 +353,9 @@ private static SyntaxToken ConvertToMultiLineRawIndentedString(Document document token.TrailingTrivia); } - private static SyntaxToken ConvertToMultiLineRawString(SyntaxToken token, string newLine) + private static SyntaxToken ConvertToSingleLineRawString( + SyntaxToken token, VirtualCharSequence characters) { - var characters = CSharpVirtualCharService.Instance.TryConvertToVirtualChars(token); - Contract.ThrowIfTrue(characters.IsDefaultOrEmpty); - - // Have to make sure we have a delimiter longer than any quote sequence in the string. - var longestQuoteSequence = GetLongestQuoteSequence(characters); - var quoteDelimeterCount = Math.Max(3, longestQuoteSequence + 1); - - using var _ = PooledStringBuilder.GetInstance(out var builder); - - builder.Append('"', quoteDelimeterCount); - builder.Append(newLine); - - foreach (var ch in characters) - ch.AppendTo(builder); - - builder.Append(newLine); - builder.Append('"', quoteDelimeterCount); - - return SyntaxFactory.Token( - token.LeadingTrivia, - SyntaxKind.MultiLineRawStringLiteralToken, - builder.ToString(), - characters.CreateString(), - token.TrailingTrivia); - } - - private static SyntaxToken ConvertToSingleLineRawString(SyntaxToken token) - { - var characters = CSharpVirtualCharService.Instance.TryConvertToVirtualChars(token); - Contract.ThrowIfTrue(characters.IsDefaultOrEmpty); - // Have to make sure we have a delimiter longer than any quote sequence in the string. var longestQuoteSequence = GetLongestQuoteSequence(characters); var quoteDelimeterCount = Math.Max(3, longestQuoteSequence + 1); @@ -240,20 +376,5 @@ private static SyntaxToken ConvertToSingleLineRawString(SyntaxToken token) characters.CreateString(), token.TrailingTrivia); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - internal override CodeActionPriority Priority { get; } - - public MyCodeAction( - string title, - Func> createChangedDocument, - string equivalenceKey, - CodeActionPriority priority) - : base(title, createChangedDocument, equivalenceKey) - { - Priority = priority; - } - } } } diff --git a/src/Features/CSharp/Portable/ConvertToRawString/ConvertToRawStringHelpers.cs b/src/Features/CSharp/Portable/ConvertToRawString/ConvertToRawStringHelpers.cs index fed44e78e66a8..16b8e06ea6488 100644 --- a/src/Features/CSharp/Portable/ConvertToRawString/ConvertToRawStringHelpers.cs +++ b/src/Features/CSharp/Portable/ConvertToRawString/ConvertToRawStringHelpers.cs @@ -4,7 +4,9 @@ using System; using System.Globalization; +using System.Reflection.PortableExecutable; using System.Text; +using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -23,15 +25,25 @@ public static bool CanBeSingleLine(VirtualCharSequence characters) } // a single line raw string cannot contain a newline. - if (characters.Any(static ch => IsNewLine(ch))) + if (characters.Any(static ch => IsCSharpNewLine(ch))) return false; return true; } - public static bool IsNewLine(VirtualChar ch) + public static bool IsCSharpNewLine(VirtualChar ch) => ch.Rune.Utf16SequenceLength == 1 && SyntaxFacts.IsNewLine((char)ch.Value); + public static bool IsCSharpWhitespace(VirtualChar ch) + => ch.Rune.Utf16SequenceLength == 1 && SyntaxFacts.IsWhitespace((char)ch.Value); + + public static bool IsCarriageReturnNewLine(VirtualCharSequence characters, int index) + { + return index + 1 < characters.Length && + characters[index].Rune is { Utf16SequenceLength: 1, Value: '\r' } && + characters[index + 1].Rune is { Utf16SequenceLength: 1, Value: '\n' }; + } + public static bool AllEscapesAreQuotes(VirtualCharSequence sequence) => AllEscapesAre(sequence, static ch => ch.Value == '"'); @@ -80,7 +92,7 @@ public static bool CanConvert(VirtualChar ch) if (ch.Span.Length > 1) { // An escaped newline is fine to convert (to a multi-line raw string). - if (IsNewLine(ch)) + if (IsCSharpNewLine(ch)) return true; // Control/formatting unicode escapes should stay as escapes. The user code will just be enormously diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs index 275d9240590c1..86314de1e9435 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs @@ -54,7 +54,7 @@ protected override ImmutableArray AnalyzeCodeBlock(CodeBlockAnalysis var syntaxTree = semanticModel.SyntaxTree; var options = context.Options.GetCSharpSimplifierOptions(syntaxTree); - var simplifier = new TypeSyntaxSimplifierWalker(this, semanticModel, options, ignoredSpans: null, cancellationToken); + using var simplifier = new TypeSyntaxSimplifierWalker(this, semanticModel, options, ignoredSpans: null, cancellationToken); simplifier.Visit(context.CodeBlock); return simplifier.Diagnostics; } diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs index f0eb6e638b222..bb1fd9307cdd8 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/TypeSyntaxSimplifierWalker.cs @@ -3,22 +3,22 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames { - internal class TypeSyntaxSimplifierWalker : CSharpSyntaxWalker + internal class TypeSyntaxSimplifierWalker : CSharpSyntaxWalker, IDisposable { - private static readonly ImmutableHashSet s_emptyAliasedNames = ImmutableHashSet.Create(StringComparer.Ordinal); - /// /// This set contains the full names of types that have equivalent predefined names in the language. /// @@ -55,7 +55,7 @@ internal class TypeSyntaxSimplifierWalker : CSharpSyntaxWalker /// This is used so we can easily tell if we should try to simplify some identifier to an /// alias when we encounter it. /// - private readonly ImmutableHashSet _aliasedNames; + private readonly PooledHashSet _aliasedNames; public bool HasDiagnostics => _diagnostics?.Count > 0; @@ -82,14 +82,28 @@ public TypeSyntaxSimplifierWalker(CSharpSimplifyTypeNamesDiagnosticAnalyzer anal _cancellationToken = cancellationToken; var root = semanticModel.SyntaxTree.GetRoot(cancellationToken); - _aliasedNames = GetAliasedNames(root as CompilationUnitSyntax); + _aliasedNames = PooledHashSet.GetInstance(); + AddAliasedNames((CompilationUnitSyntax)root); } - private static ImmutableHashSet GetAliasedNames(CompilationUnitSyntax? compilationUnit) + public void Dispose() { - var aliasedNames = s_emptyAliasedNames; - if (compilationUnit is null) - return aliasedNames; + _aliasedNames.Free(); + } + + private void AddAliasedNames(CompilationUnitSyntax compilationUnit) + { + // Using `position: 0` gets all the global aliases defined in other files pulled in here. + var scopes = _semanticModel.GetImportScopes(position: 0, _cancellationToken); + foreach (var scope in scopes) + { + foreach (var alias in scope.Aliases) + { + var name = alias.Target.Name; + if (!string.IsNullOrEmpty(name)) + _aliasedNames.Add(name); + } + } foreach (var usingDirective in compilationUnit.Usings) AddAliasedName(usingDirective); @@ -100,20 +114,16 @@ private static ImmutableHashSet GetAliasedNames(CompilationUnitSyntax? c AddAliasedNames(namespaceDeclaration); } - return aliasedNames; + return; void AddAliasedName(UsingDirectiveSyntax usingDirective) { - if (usingDirective.Alias is object) + if (usingDirective.Alias is not null && + usingDirective.Name.GetRightmostName() is IdentifierNameSyntax identifierName) { - if (usingDirective.Name.GetRightmostName() is IdentifierNameSyntax identifierName) - { - var identifierAlias = identifierName.Identifier.ValueText; - if (!RoslynString.IsNullOrEmpty(identifierAlias)) - { - aliasedNames = aliasedNames.Add(identifierAlias); - } - } + var identifierAlias = identifierName.Identifier.ValueText; + if (!string.IsNullOrEmpty(identifierAlias)) + _aliasedNames.Add(identifierAlias); } } diff --git a/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs b/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs index 4a4c01dda50e4..216508c3c6bb9 100644 --- a/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs +++ b/src/Features/CSharp/Portable/DocumentationComments/CSharpDocumentationCommentSnippetService.cs @@ -151,7 +151,7 @@ private static IEnumerable GetExceptions(SyntaxNode member) var throwExpressionsAndStatements = member.DescendantNodes().Where(n => n.IsKind(SyntaxKind.ThrowExpression, SyntaxKind.ThrowStatement)); var usings = member.GetEnclosingUsingDirectives(); - var hasUsingSystem = usings.Any(u => u.Name is IdentifierNameSyntax { Identifier: { ValueText: nameof(System) } }); + var hasUsingSystem = usings.Any(u => u.Name is IdentifierNameSyntax { Identifier.ValueText: nameof(System) }); using var _ = PooledHashSet.GetInstance(out var seenExceptionTypes); foreach (var throwExpressionOrStatement in throwExpressionsAndStatements) @@ -208,15 +208,15 @@ private static bool IsExceptionCaughtAndNotRethrown(bool hasUsingSystem, TypeSyn return true; if (hasUsingSystem && - catchClause.Declaration.Type is IdentifierNameSyntax { Identifier: { ValueText: nameof(Exception) } }) + catchClause.Declaration.Type is IdentifierNameSyntax { Identifier.ValueText: nameof(Exception) }) { return true; } if (catchClause.Declaration.Type is QualifiedNameSyntax { - Left: IdentifierNameSyntax { Identifier: { ValueText: nameof(System) } }, - Right: IdentifierNameSyntax { Identifier: { ValueText: nameof(Exception) } }, + Left: IdentifierNameSyntax { Identifier.ValueText: nameof(System) }, + Right: IdentifierNameSyntax { Identifier.ValueText: nameof(Exception) }, }) { return true; diff --git a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs index e9aa41afd2c6e..e938950ba9dc4 100644 --- a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs +++ b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs @@ -1159,7 +1159,7 @@ internal override bool IsRecordPrimaryConstructorParameter(SyntaxNode declaratio private static bool IsPropertyDeclarationMatchingPrimaryConstructorParameter(SyntaxNode declaration, INamedTypeSymbol newContainingType) { if (newContainingType.IsRecord && - declaration is PropertyDeclarationSyntax { Identifier: { ValueText: var name } }) + declaration is PropertyDeclarationSyntax { Identifier.ValueText: var name }) { // We need to use symbol information to find the primary constructor, because it could be in another file if the type is partial foreach (var reference in newContainingType.DeclaringSyntaxReferences) @@ -2423,7 +2423,7 @@ internal override void ReportInsertedMemberSymbolRudeEdits(ArrayBuilder RudeEditKind.None, // Inserting a member into an existing generic type is not allowed. - { ContainingType: { Arity: > 0 } } and not INamedTypeSymbol + { ContainingType.Arity: > 0 } and not INamedTypeSymbol => RudeEditKind.InsertIntoGenericType, // Inserting virtual or interface member into an existing type is not allowed. @@ -2443,11 +2443,11 @@ internal override void ReportInsertedMemberSymbolRudeEdits(ArrayBuilder RudeEditKind.InsertOperator, // Inserting a method that explictly implements an interface method into an existing type is not allowed. - IMethodSymbol { ExplicitInterfaceImplementations: { IsEmpty: false } } + IMethodSymbol { ExplicitInterfaceImplementations.IsEmpty: false } => RudeEditKind.InsertMethodWithExplicitInterfaceSpecifier, // TODO: Inserting non-virtual member to an interface (https://github.com/dotnet/roslyn/issues/37128) - { ContainingType: { TypeKind: TypeKind.Interface } } and not INamedTypeSymbol + { ContainingType.TypeKind: TypeKind.Interface } and not INamedTypeSymbol => RudeEditKind.InsertIntoInterface, // Inserting a field into an enum: diff --git a/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs b/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs index 5bbec277915c9..c09694f84980c 100644 --- a/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs +++ b/src/Features/CSharp/Portable/EncapsulateField/CSharpEncapsulateFieldService.cs @@ -34,7 +34,7 @@ public CSharpEncapsulateFieldService() { } - protected override async Task RewriteFieldNameAndAccessibilityAsync(string originalFieldName, bool makePrivate, Document document, SyntaxAnnotation declarationAnnotation, CancellationToken cancellationToken) + protected override async Task RewriteFieldNameAndAccessibilityAsync(string originalFieldName, bool makePrivate, Document document, SyntaxAnnotation declarationAnnotation, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -106,7 +106,14 @@ protected override async Task RewriteFieldNameAndAccessibilityAsync( field.ConstantValue, declarator.Initializer)); - var withField = await codeGenService.AddFieldAsync(document.Project.Solution, field.ContainingType, fieldToAdd, CodeGenerationContext.Default, cancellationToken).ConfigureAwait(false); + var withField = await codeGenService.AddFieldAsync( + new CodeGenerationSolutionContext( + document.Project.Solution, + CodeGenerationContext.Default, + fallbackOptions), + field.ContainingType, + fieldToAdd, + cancellationToken).ConfigureAwait(false); root = await withField.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); declarator = root.GetAnnotatedNodes(tempAnnotation).First(); diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpExtractMethodService.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpExtractMethodService.cs index 35d31d35119cc..9b70f6d5a704c 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpExtractMethodService.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpExtractMethodService.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod { [Export(typeof(IExtractMethodService)), Shared] [ExportLanguageService(typeof(IExtractMethodService), LanguageNames.CSharp)] - internal class CSharpExtractMethodService : AbstractExtractMethodService + internal sealed class CSharpExtractMethodService : AbstractExtractMethodService { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] @@ -23,10 +23,10 @@ public CSharpExtractMethodService() { } - protected override CSharpSelectionValidator CreateSelectionValidator(SemanticDocument document, TextSpan textSpan, bool localFunction, ExtractMethodOptions options) - => new CSharpSelectionValidator(document, textSpan, localFunction, options); + protected override CSharpSelectionValidator CreateSelectionValidator(SemanticDocument document, TextSpan textSpan, ExtractMethodOptions options, bool localFunction) + => new(document, textSpan, options, localFunction); - protected override CSharpMethodExtractor CreateMethodExtractor(CSharpSelectionResult selectionResult, bool localFunction) - => new CSharpMethodExtractor(selectionResult, localFunction); + protected override CSharpMethodExtractor CreateMethodExtractor(CSharpSelectionResult selectionResult, ExtractMethodGenerationOptions options, bool localFunction) + => new(selectionResult, options, localFunction); } } diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.ExpressionCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.ExpressionCodeGenerator.cs index 82edd0fd585d6..ba0d4ab4ae0a5 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.ExpressionCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.ExpressionCodeGenerator.cs @@ -9,11 +9,13 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod @@ -22,15 +24,16 @@ internal partial class CSharpMethodExtractor { private partial class CSharpCodeGenerator { - private class ExpressionCodeGenerator : CSharpCodeGenerator + private sealed class ExpressionCodeGenerator : CSharpCodeGenerator { public ExpressionCodeGenerator( InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzerResult, - OptionSet options, + CSharpCodeGenerationOptions options, + NamingStylePreferencesProvider namingPreferences, bool localFunction) - : base(insertionPoint, selectionResult, analyzerResult, options, localFunction) + : base(insertionPoint, selectionResult, analyzerResult, options, namingPreferences, localFunction) { } diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs index 2b5c555cac181..00be04464a1a0 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.MultipleStatementsCodeGenerator.cs @@ -9,12 +9,14 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod @@ -23,15 +25,16 @@ internal partial class CSharpMethodExtractor { private partial class CSharpCodeGenerator { - public class MultipleStatementsCodeGenerator : CSharpCodeGenerator + public sealed class MultipleStatementsCodeGenerator : CSharpCodeGenerator { public MultipleStatementsCodeGenerator( InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzerResult, - OptionSet options, + CSharpCodeGenerationOptions options, + NamingStylePreferencesProvider namingPreferences, bool localFunction) - : base(insertionPoint, selectionResult, analyzerResult, options, localFunction) + : base(insertionPoint, selectionResult, analyzerResult, options, namingPreferences, localFunction) { } diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.SingleStatementCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.SingleStatementCodeGenerator.cs index f9231f3f8f629..46dc4d01988b1 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.SingleStatementCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.SingleStatementCodeGenerator.cs @@ -8,9 +8,11 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod @@ -19,15 +21,16 @@ internal partial class CSharpMethodExtractor { private partial class CSharpCodeGenerator { - public class SingleStatementCodeGenerator : CSharpCodeGenerator + public sealed class SingleStatementCodeGenerator : CSharpCodeGenerator { public SingleStatementCodeGenerator( InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzerResult, - OptionSet options, + CSharpCodeGenerationOptions options, + NamingStylePreferencesProvider namingPreferences, bool localFunction) - : base(insertionPoint, selectionResult, analyzerResult, options, localFunction) + : base(insertionPoint, selectionResult, analyzerResult, options, namingPreferences, localFunction) { } diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs index 7e161ea9f797c..7b70d87102002 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.LanguageServices; @@ -33,7 +34,7 @@ namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod { internal partial class CSharpMethodExtractor { - private abstract partial class CSharpCodeGenerator : CodeGenerator + private abstract partial class CSharpCodeGenerator : CodeGenerator { private readonly SyntaxToken _methodName; @@ -44,11 +45,12 @@ public static Task GenerateAsync( InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzerResult, - OptionSet options, + CSharpCodeGenerationOptions options, + NamingStylePreferencesProvider namingPreferences, bool localFunction, CancellationToken cancellationToken) { - var codeGenerator = Create(insertionPoint, selectionResult, analyzerResult, options, localFunction); + var codeGenerator = Create(insertionPoint, selectionResult, analyzerResult, options, namingPreferences, localFunction); return codeGenerator.GenerateAsync(cancellationToken); } @@ -56,22 +58,23 @@ private static CSharpCodeGenerator Create( InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzerResult, - OptionSet options, + CSharpCodeGenerationOptions options, + NamingStylePreferencesProvider namingPreferences, bool localFunction) { if (ExpressionCodeGenerator.IsExtractMethodOnExpression(selectionResult)) { - return new ExpressionCodeGenerator(insertionPoint, selectionResult, analyzerResult, options, localFunction); + return new ExpressionCodeGenerator(insertionPoint, selectionResult, analyzerResult, options, namingPreferences, localFunction); } if (SingleStatementCodeGenerator.IsExtractMethodOnSingleStatement(selectionResult)) { - return new SingleStatementCodeGenerator(insertionPoint, selectionResult, analyzerResult, options, localFunction); + return new SingleStatementCodeGenerator(insertionPoint, selectionResult, analyzerResult, options, namingPreferences, localFunction); } if (MultipleStatementsCodeGenerator.IsExtractMethodOnMultipleStatements(selectionResult)) { - return new MultipleStatementsCodeGenerator(insertionPoint, selectionResult, analyzerResult, options, localFunction); + return new MultipleStatementsCodeGenerator(insertionPoint, selectionResult, analyzerResult, options, namingPreferences, localFunction); } throw ExceptionUtilities.UnexpectedValue(selectionResult); @@ -81,9 +84,10 @@ protected CSharpCodeGenerator( InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzerResult, - OptionSet options, + CSharpCodeGenerationOptions options, + NamingStylePreferencesProvider namingPreferences, bool localFunction) - : base(insertionPoint, selectionResult, analyzerResult, options, localFunction) + : base(insertionPoint, selectionResult, analyzerResult, options, namingPreferences, localFunction) { Contract.ThrowIfFalse(SemanticDocument == selectionResult.SemanticDocument); @@ -92,9 +96,7 @@ protected CSharpCodeGenerator( } private CSharpSelectionResult CSharpSelectionResult - { - get { return (CSharpSelectionResult)SelectionResult; } - } + => (CSharpSelectionResult)SelectionResult; protected override SyntaxNode GetPreviousMember(SemanticDocument document) { @@ -232,7 +234,7 @@ private DeclarationModifiers CreateMethodModifiers() // Static local functions are only supported in C# 8.0 and later var languageVersion = SemanticDocument.SyntaxTree.Options.LanguageVersion(); - if (LocalFunction && (!Options.GetOption(CSharpCodeStyleOptions.PreferStaticLocalFunction).Value || languageVersion < LanguageVersion.CSharp8)) + if (LocalFunction && (!Options.PreferStaticLocalFunction.Value || languageVersion < LanguageVersion.CSharp8)) { isStatic = false; } @@ -850,7 +852,7 @@ protected string GenerateMethodNameFromUserPreference() } // For local functions, pascal case and camel case should be the most common and therefore we only consider those cases. - var namingPreferences = Options.GetOption(NamingStyleOptions.NamingPreferences, LanguageNames.CSharp); + var namingPreferences = NamingPreferences(SemanticDocument.Document.Project.LanguageServices); var localFunctionPreferences = namingPreferences.SymbolSpecifications.Where(symbol => symbol.AppliesTo(new SymbolKindOrTypeKind(MethodKind.LocalFunction), CreateMethodModifiers(), null)); var namingRules = namingPreferences.Rules.NamingRules; diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs index 7cbe224815408..8e5e92b8072c0 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.cs @@ -10,6 +10,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.Formatting; @@ -23,8 +25,8 @@ namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod { internal partial class CSharpMethodExtractor : MethodExtractor { - public CSharpMethodExtractor(CSharpSelectionResult result, bool localFunction) - : base(result, localFunction) + public CSharpMethodExtractor(CSharpSelectionResult result, ExtractMethodGenerationOptions options, bool localFunction) + : base(result, options, localFunction) { } @@ -100,8 +102,8 @@ protected override async Task ExpandAsync(SelectionResult sele return await selection.SemanticDocument.WithSyntaxRootAsync(selection.SemanticDocument.Root.ReplaceNode(lastExpression, newExpression), cancellationToken).ConfigureAwait(false); } - protected override Task GenerateCodeAsync(InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzeResult, OptionSet options, CancellationToken cancellationToken) - => CSharpCodeGenerator.GenerateAsync(insertionPoint, selectionResult, analyzeResult, options, LocalFunction, cancellationToken); + protected override Task GenerateCodeAsync(InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzeResult, CodeGenerationOptions options, NamingStylePreferencesProvider namingPreferences, CancellationToken cancellationToken) + => CSharpCodeGenerator.GenerateAsync(insertionPoint, selectionResult, analyzeResult, (CSharpCodeGenerationOptions)options, namingPreferences, LocalFunction, cancellationToken); protected override ImmutableArray GetCustomFormattingRules(Document document) => ImmutableArray.Create(new FormattingRule()); diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionValidator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionValidator.cs index e31dfc8200a70..ec6be81a5d107 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionValidator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpSelectionValidator.cs @@ -29,8 +29,8 @@ internal partial class CSharpSelectionValidator : SelectionValidator public CSharpSelectionValidator( SemanticDocument document, TextSpan textSpan, - bool localFunction, - ExtractMethodOptions options) + ExtractMethodOptions options, + bool localFunction) : base(document, textSpan, options) { _localFunction = localFunction; diff --git a/src/Features/CSharp/Portable/FullyQualify/CSharpFullyQualifyCodeFixProvider.cs b/src/Features/CSharp/Portable/FullyQualify/CSharpFullyQualifyCodeFixProvider.cs index 12c90de00ed4e..5e47883c0cd09 100644 --- a/src/Features/CSharp/Portable/FullyQualify/CSharpFullyQualifyCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/FullyQualify/CSharpFullyQualifyCodeFixProvider.cs @@ -99,7 +99,7 @@ protected override async Task ReplaceNodeAsync(SyntaxNode node, stri // CS0138 that would result from the former. Don't do this for using aliases though as `static` and using // aliases cannot be combined. if (resultingSymbolIsType && - node.Parent is UsingDirectiveSyntax { Alias: null, StaticKeyword: { RawKind: 0 } } usingDirective) + node.Parent is UsingDirectiveSyntax { Alias: null, StaticKeyword.RawKind: 0 } usingDirective) { var newUsingDirective = usingDirective .WithStaticKeyword(SyntaxFactory.Token(SyntaxKind.StaticKeyword)) diff --git a/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs b/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs index 7cb6623d96142..67c6a9eee7b74 100644 --- a/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeFixes.GenerateMember; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; @@ -64,10 +65,10 @@ public GenerateConstructorCodeFixProvider() public override ImmutableArray FixableDiagnosticIds => GenerateConstructorDiagnosticIds.AllDiagnosticIds; protected override Task> GetCodeActionsAsync( - Document document, SyntaxNode node, CancellationToken cancellationToken) + Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var service = document.GetLanguageService(); - return service.GenerateConstructorAsync(document, node, cancellationToken); + return service.GenerateConstructorAsync(document, node, fallbackOptions, cancellationToken); } protected override bool IsCandidate(SyntaxNode node, SyntaxToken token, Diagnostic diagnostic) diff --git a/src/Features/CSharp/Portable/GenerateVariable/CSharpGenerateVariableCodeFixProvider.cs b/src/Features/CSharp/Portable/GenerateVariable/CSharpGenerateVariableCodeFixProvider.cs index 490630737699b..6224e5c056cd8 100644 --- a/src/Features/CSharp/Portable/GenerateVariable/CSharpGenerateVariableCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/GenerateVariable/CSharpGenerateVariableCodeFixProvider.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeFixes.GenerateMember; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.GenerateMember.GenerateVariable; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -58,10 +59,10 @@ protected override SyntaxNode GetTargetNode(SyntaxNode node) } protected override Task> GetCodeActionsAsync( - Document document, SyntaxNode node, CancellationToken cancellationToken) + Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var service = document.GetLanguageService(); - return service.GenerateVariableAsync(document, node, cancellationToken); + return service.GenerateVariableAsync(document, node, fallbackOptions, cancellationToken); } } } diff --git a/src/Features/CSharp/Portable/ImplementInterface/AbstractChangeImplementionCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ImplementInterface/AbstractChangeImplementionCodeRefactoringProvider.cs index 8ec4133700b49..73c895ade88a6 100644 --- a/src/Features/CSharp/Portable/ImplementInterface/AbstractChangeImplementionCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ImplementInterface/AbstractChangeImplementionCodeRefactoringProvider.cs @@ -71,9 +71,11 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex // like: "System.IEnumerable.GetEnumerator" directlyImplementedMembers.AddRange(member, member.ExplicitOrImplicitInterfaceImplementations()); - var codeAction = new MyCodeAction( - string.Format(Implement_0, member.ExplicitOrImplicitInterfaceImplementations().First().Name), - c => ChangeImplementationAsync(project, directlyImplementedMembers, c)); + var firstImplName = member.ExplicitOrImplicitInterfaceImplementations().First().Name; + var codeAction = CodeAction.Create( + string.Format(Implement_0, firstImplName), + c => ChangeImplementationAsync(project, directlyImplementedMembers, c), + nameof(Implement_0) + firstImplName); var containingType = member.ContainingType; var interfaceTypes = directlyImplementedMembers.SelectMany(kvp => kvp.Value).Select( @@ -102,16 +104,18 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex if (offerForSameInterface) { var interfaceNames = interfaceTypes.Select(i => i.ToDisplayString(NameAndTypeParametersFormat)); - nestedActions.Add(new MyCodeAction( + nestedActions.Add(CodeAction.Create( string.Format(Implement_0, string.Join(", ", interfaceNames)), - c => ChangeImplementationAsync(project, implementedMembersFromSameInterfaces, c))); + c => ChangeImplementationAsync(project, implementedMembersFromSameInterfaces, c), + nameof(Implement_0) + string.Join(", ", interfaceNames))); } if (offerForAllInterfaces) { - nestedActions.Add(new MyCodeAction( + nestedActions.Add(CodeAction.Create( Implement_all_interfaces, - c => ChangeImplementationAsync(project, implementedMembersFromAllInterfaces, c))); + c => ChangeImplementationAsync(project, implementedMembersFromAllInterfaces, c), + nameof(Implement_all_interfaces))); } context.RegisterRefactoring(CodeAction.CodeActionWithNestedActions.Create( @@ -246,13 +250,5 @@ await UpdateReferencesAsync( return solutionEditor.GetChangedSolution(); } - - private class MyCodeAction : CodeAction.SolutionChangeAction - { - public MyCodeAction(string title, Func> createChangedSolution) - : base(title, createChangedSolution, title) - { - } - } } } diff --git a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs index 1362d6a7fe76f..faa2a1877ed92 100644 --- a/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ImplementInterface; @@ -50,11 +51,11 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) } var service = document.GetRequiredLanguageService(); - var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var actions = token.Parent.GetAncestorsOrThis() .Where(_interfaceName) - .Select(n => service.GetCodeActions(document, context.Options(document.Project.LanguageServices).ImplementTypeOptions, model, n, cancellationToken)) + .Select(n => service.GetCodeActions(document, context.Options.GetImplementTypeGenerationOptions(document.Project.LanguageServices), model, n, cancellationToken)) .FirstOrDefault(a => !a.IsEmpty); if (actions.IsDefaultOrEmpty) diff --git a/src/EditorFeatures/CSharp/InheritanceMargin/CSharpInheritanceMarginService.cs b/src/Features/CSharp/Portable/InheritanceMargin/CSharpInheritanceMarginService.cs similarity index 95% rename from src/EditorFeatures/CSharp/InheritanceMargin/CSharpInheritanceMarginService.cs rename to src/Features/CSharp/Portable/InheritanceMargin/CSharpInheritanceMarginService.cs index c1b8330890e7a..be3cd9326a105 100644 --- a/src/EditorFeatures/CSharp/InheritanceMargin/CSharpInheritanceMarginService.cs +++ b/src/Features/CSharp/Portable/InheritanceMargin/CSharpInheritanceMarginService.cs @@ -7,14 +7,13 @@ using System.Collections.Immutable; using System.Composition; using System.Linq; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.InheritanceMargin; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.CSharp.InheritanceMargin +namespace Microsoft.CodeAnalysis.CSharp.InheritanceMargin { [ExportLanguageService(typeof(IInheritanceMarginService), LanguageNames.CSharp), Shared] internal class CSharpInheritanceMarginService : AbstractInheritanceMarginService @@ -25,6 +24,8 @@ public CSharpInheritanceMarginService() { } + protected override string GlobalImportsTitle => CSharpFeaturesResources.Global_using_directives; + protected override ImmutableArray GetMembers(IEnumerable nodesToSearch) { var typeDeclarationNodes = nodesToSearch.OfType(); diff --git a/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs b/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs index 9f88bf8b4ecd5..8456ce3f2449e 100644 --- a/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs +++ b/src/Features/CSharp/Portable/InlineHints/CSharpInlineTypeHintsService.cs @@ -5,13 +5,11 @@ using System; using System.Composition; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.InlineHints; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -38,7 +36,7 @@ public CSharpInlineTypeHintsService(IGlobalOptionService globalOptions) { if (forImplicitVariableTypes || displayAllOverride) { - if (node is VariableDeclarationSyntax { Type: { IsVar: true } } variableDeclaration && + if (node is VariableDeclarationSyntax { Type.IsVar: true } variableDeclaration && variableDeclaration.Variables.Count == 1 && !variableDeclaration.Variables[0].Identifier.IsMissing) { @@ -47,7 +45,7 @@ public CSharpInlineTypeHintsService(IGlobalOptionService globalOptions) return CreateTypeHint(type, displayAllOverride, forImplicitVariableTypes, variableDeclaration.Type, variableDeclaration.Variables[0].Identifier); } - if (node is DeclarationExpressionSyntax { Type: { IsVar: true } } declarationExpression) + if (node is DeclarationExpressionSyntax { Type.IsVar: true } declarationExpression) { var type = semanticModel.GetTypeInfo(declarationExpression.Type, cancellationToken).Type; if (IsValidType(type)) @@ -64,7 +62,7 @@ public CSharpInlineTypeHintsService(IGlobalOptionService globalOptions) : new(type, new TextSpan(variableDesignation.Identifier.SpanStart, 0), textChange: null, trailingSpace: true); } } - else if (node is ForEachStatementSyntax { Type: { IsVar: true } } forEachStatement) + else if (node is ForEachStatementSyntax { Type.IsVar: true } forEachStatement) { var info = semanticModel.GetForEachStatementInfo(forEachStatement); var type = info.ElementType; diff --git a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs index 4c637bbff1f57..1225af3e4aa6e 100644 --- a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs +++ b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeFixHelper.cs @@ -25,11 +25,12 @@ public static async Task MakeLocalFunctionStaticAsync( Document document, LocalFunctionStatementSyntax localFunction, ImmutableArray captures, + CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var root = (await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false))!; var syntaxEditor = new SyntaxEditor(root, document.Project.Solution.Workspace.Services); - await MakeLocalFunctionStaticAsync(document, localFunction, captures, syntaxEditor, cancellationToken).ConfigureAwait(false); + await MakeLocalFunctionStaticAsync(document, localFunction, captures, syntaxEditor, fallbackOptions, cancellationToken).ConfigureAwait(false); return document.WithSyntaxRoot(syntaxEditor.GetChangedRoot()); } @@ -38,6 +39,7 @@ public static async Task MakeLocalFunctionStaticAsync( LocalFunctionStatementSyntax localFunction, ImmutableArray captures, SyntaxEditor syntaxEditor, + CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var root = (await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false))!; @@ -139,7 +141,8 @@ public static async Task MakeLocalFunctionStaticAsync( } var codeGenerator = document.GetRequiredLanguageService(); - var options = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, document, cancellationToken).ConfigureAwait(false); + var options = await document.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); + var info = options.GetInfo(CodeGenerationContext.Default, document.Project); // Updates the local function declaration with variables passed in as parameters syntaxEditor.ReplaceNode( @@ -149,7 +152,7 @@ public static async Task MakeLocalFunctionStaticAsync( var localFunctionWithNewParameters = codeGenerator.AddParameters( node, parameterAndCapturedSymbols.SelectAsArray(p => p.symbol), - options, + info, cancellationToken); if (shouldWarn) diff --git a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs index 78b3e3ea78719..cf12ebdceab60 100644 --- a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/MakeLocalFunctionStaticCodeRefactoringProvider.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -50,7 +51,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte { context.RegisterRefactoring(CodeAction.Create( CSharpAnalyzersResources.Make_local_function_static, - c => MakeLocalFunctionStaticCodeFixHelper.MakeLocalFunctionStaticAsync(document, localFunction, captures, c), + c => MakeLocalFunctionStaticCodeFixHelper.MakeLocalFunctionStaticAsync(document, localFunction, captures, context.Options, c), nameof(CSharpAnalyzersResources.Make_local_function_static))); } } diff --git a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs index fc62b82dda908..383eb62592c2a 100644 --- a/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/MakeLocalFunctionStatic/PassInCapturedVariablesAsArgumentsCodeFixProvider.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; @@ -42,7 +43,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) context.RegisterCodeFix( CodeAction.Create( CSharpCodeFixesResources.Pass_in_captured_variables_as_arguments, - c => MakeLocalFunctionStaticCodeFixHelper.MakeLocalFunctionStaticAsync(document, localFunction, captures, c), + c => MakeLocalFunctionStaticCodeFixHelper.MakeLocalFunctionStaticAsync(document, localFunction, captures, context.Options, c), nameof(CSharpCodeFixesResources.Pass_in_captured_variables_as_arguments)), diagnostic); @@ -60,6 +61,7 @@ protected override Task FixAllAsync(Document document, ImmutableArray FixCodeAsync(document, structDeclaration, c)), + CodeAction.Create( + CSharpFeaturesResources.Make_ref_struct, + c => FixCodeAsync(document, structDeclaration, c), + nameof(CSharpFeaturesResources.Make_ref_struct)), context.Diagnostics); } } @@ -89,15 +92,5 @@ private static StructDeclarationSyntax FindContainingStruct(SyntaxNode root, Tex // so find only the first parent declaration return member.GetAncestor() as StructDeclarationSyntax; } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(CSharpFeaturesResources.Make_ref_struct, - createChangedDocument, - CSharpFeaturesResources.Make_ref_struct) - { - } - } } } diff --git a/src/Features/CSharp/Portable/RemoveUnusedLocalFunction/CSharpRemoveUnusedLocalFunctionCodeFixProvider.cs b/src/Features/CSharp/Portable/RemoveUnusedLocalFunction/CSharpRemoveUnusedLocalFunctionCodeFixProvider.cs index 000bda31cd5f1..c22b3b2671e2f 100644 --- a/src/Features/CSharp/Portable/RemoveUnusedLocalFunction/CSharpRemoveUnusedLocalFunctionCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/RemoveUnusedLocalFunction/CSharpRemoveUnusedLocalFunctionCodeFixProvider.cs @@ -38,7 +38,12 @@ public sealed override ImmutableArray FixableDiagnosticIds public override Task RegisterCodeFixesAsync(CodeFixContext context) { - context.RegisterCodeFix(new MyCodeAction(GetDocumentUpdater(context)), context.Diagnostics); + context.RegisterCodeFix( + CodeAction.Create( + CSharpFeaturesResources.Remove_unused_function, + GetDocumentUpdater(context), + nameof(CSharpFeaturesResources.Remove_unused_function)), + context.Diagnostics); return Task.CompletedTask; } @@ -61,13 +66,5 @@ protected override Task FixAllAsync(Document document, ImmutableArray> createChangedDocument) - : base(CSharpFeaturesResources.Remove_unused_function, createChangedDocument, CSharpFeaturesResources.Remove_unused_function) - { - } - } } } diff --git a/src/Features/CSharp/Portable/ReplaceDefaultLiteral/CSharpReplaceDefaultLiteralCodeFixProvider.cs b/src/Features/CSharp/Portable/ReplaceDefaultLiteral/CSharpReplaceDefaultLiteralCodeFixProvider.cs index f69765df6e698..0ff3bac61b93a 100644 --- a/src/Features/CSharp/Portable/ReplaceDefaultLiteral/CSharpReplaceDefaultLiteralCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/ReplaceDefaultLiteral/CSharpReplaceDefaultLiteralCodeFixProvider.cs @@ -59,9 +59,10 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) if (newExpression != null) { context.RegisterCodeFix( - new MyCodeAction( + CodeAction.Create( + string.Format(CSharpFeaturesResources.Use_0, displayText), c => ReplaceAsync(context.Document, context.Span, newExpression, c), - displayText), + nameof(CSharpFeaturesResources.Use_0)), context.Diagnostics); } } @@ -148,13 +149,5 @@ private static bool IsZero(object o) return false; } } - - private sealed class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument, string literal) - : base(string.Format(CSharpFeaturesResources.Use_0, literal), createChangedDocument, CSharpFeaturesResources.Use_0) - { - } - } } } diff --git a/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs index 9a8c32a78477c..b8aaf6a03e895 100644 --- a/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs @@ -74,8 +74,11 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - context.RegisterRefactoring(new MyCodeAction( - c => ReverseForStatementAsync(document, forStatement, c))); + context.RegisterRefactoring( + CodeAction.Create( + CSharpFeaturesResources.Reverse_for_statement, + c => ReverseForStatementAsync(document, forStatement, c), + nameof(CSharpFeaturesResources.Reverse_for_statement))); } } @@ -392,13 +395,5 @@ private static ExpressionSyntax InvertAfter(ExpressionSyntax after) var newOpToken = SyntaxFactory.Token(newKind).WithTriviaFrom(opToken); return after.ReplaceToken(opToken, newOpToken); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(CSharpFeaturesResources.Reverse_for_statement, createChangedDocument, nameof(CSharpFeaturesResources.Reverse_for_statement)) - { - } - } } } diff --git a/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeCodeFixProvider.cs b/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeCodeFixProvider.cs index 6a11854b24733..8dcc45dcbbe70 100644 --- a/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeCodeFixProvider.cs @@ -2,8 +2,6 @@ // 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.Collections.Generic; using System.Composition; using System.Diagnostics.CodeAnalysis; @@ -33,13 +31,13 @@ protected override SyntaxNode Rewrite(SyntaxNode root, ISet memberAccessNodes; + private readonly ISet _memberAccessNodes; public Rewriter(ISet memberAccessNodes) - => this.memberAccessNodes = memberAccessNodes; + => _memberAccessNodes = memberAccessNodes; - public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) - => memberAccessNodes.Contains(node) + public override SyntaxNode? VisitMemberAccessExpression(MemberAccessExpressionSyntax node) + => _memberAccessNodes.Contains(node) ? node.GetNameWithTriviaMoved() : base.VisitMemberAccessExpression(node); } diff --git a/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs index 61355bddd70fc..202d25fcea7d7 100644 --- a/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/SimplifyThisOrMe/CSharpSimplifyThisOrMeDiagnosticAnalyzer.cs @@ -2,16 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Threading; using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.CSharp.Simplification; using Microsoft.CodeAnalysis.CSharp.Simplification.Simplifiers; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.LanguageServices; -using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Simplification.Simplifiers; using Microsoft.CodeAnalysis.SimplifyThisOrMe; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.SimplifyThisOrMe { @@ -24,17 +22,12 @@ internal sealed class CSharpSimplifyThisOrMeDiagnosticAnalyzer MemberAccessExpressionSyntax, CSharpSimplifierOptions> { - protected override ISyntaxFacts GetSyntaxFacts() - => CSharpSyntaxFacts.Instance; + protected override ISyntaxKinds SyntaxKinds => CSharpSyntaxKinds.Instance; protected override CSharpSimplifierOptions GetSimplifierOptions(AnalyzerOptions options, SyntaxTree syntaxTree) => options.GetCSharpSimplifierOptions(syntaxTree); - protected override bool CanSimplifyTypeNameExpression( - SemanticModel model, MemberAccessExpressionSyntax node, CSharpSimplifierOptions options, - out TextSpan issueSpan, CancellationToken cancellationToken) - { - return ExpressionSimplifier.Instance.TrySimplify(node, model, options, out _, out issueSpan, cancellationToken); - } + protected override AbstractMemberAccessExpressionSimplifier Simplifier + => MemberAccessExpressionSimplifier.Instance; } } diff --git a/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs b/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs index 5a68a42614dbb..920ecb64e4b36 100644 --- a/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs @@ -40,9 +40,6 @@ protected override string GetTitle(string diagnosticId, string nodeText) case IDEDiagnosticIds.SimplifyMemberAccessDiagnosticId: return string.Format(CSharpFeaturesResources.Simplify_member_access_0, nodeText); - case IDEDiagnosticIds.RemoveQualificationDiagnosticId: - return CSharpFeaturesResources.Remove_this_qualification; - default: throw ExceptionUtilities.UnexpectedValue(diagnosticId); } diff --git a/src/Features/CSharp/Portable/UseExplicitTypeForConst/UseExplicitTypeForConstCodeFixProvider.cs b/src/Features/CSharp/Portable/UseExplicitTypeForConst/UseExplicitTypeForConstCodeFixProvider.cs index 5bd37b9bada53..da6e2459a1dc6 100644 --- a/src/Features/CSharp/Portable/UseExplicitTypeForConst/UseExplicitTypeForConstCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/UseExplicitTypeForConst/UseExplicitTypeForConstCodeFixProvider.cs @@ -53,7 +53,10 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) } context.RegisterCodeFix( - new MyCodeAction(c => FixAsync(context.Document, context.Span, type, c)), + CodeAction.Create( + CSharpAnalyzersResources.Use_explicit_type_instead_of_var, + c => FixAsync(context.Document, context.Span, type, c), + nameof(CSharpAnalyzersResources.Use_explicit_type_instead_of_var)), context.Diagnostics); } } @@ -67,15 +70,5 @@ private static async Task FixAsync( var newRoot = root.ReplaceNode(variableDeclaration.Type, type.GenerateTypeSyntax(allowVar: false)); return document.WithSyntaxRoot(newRoot); } - - private sealed class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(CSharpAnalyzersResources.Use_explicit_type_instead_of_var, - createChangedDocument, - nameof(CSharpAnalyzersResources.Use_explicit_type_instead_of_var)) - { - } - } } } diff --git a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs index 7c18d147aada6..1cc8e801fa3b0 100644 --- a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs @@ -97,23 +97,28 @@ private static bool TryComputeRefactoring( var succeeded = false; if (helper.CanOfferUseExpressionBody(optionSet, declaration, forAnalyzer: false)) { - context.RegisterRefactoring(new MyCodeAction( - helper.UseExpressionBodyTitle.ToString(), - c => UpdateDocumentAsync( - document, root, declaration, helper, - useExpressionBody: true, cancellationToken: c)), + var title = helper.UseExpressionBodyTitle.ToString(); + context.RegisterRefactoring( + CodeAction.Create( + title, + c => UpdateDocumentAsync( + document, root, declaration, helper, + useExpressionBody: true, cancellationToken: c), + title), declaration.Span); succeeded = true; } if (helper.CanOfferUseBlockBody(optionSet, declaration, forAnalyzer: false, out _, out _)) { + var title = helper.UseBlockBodyTitle.ToString(); context.RegisterRefactoring( - new MyCodeAction( - helper.UseBlockBodyTitle.ToString(), + CodeAction.Create( + title, c => UpdateDocumentAsync( document, root, declaration, helper, - useExpressionBody: false, cancellationToken: c)), + useExpressionBody: false, cancellationToken: c), + title), declaration.Span); succeeded = true; } @@ -150,13 +155,5 @@ private static async Task UpdateDocumentAsync( var newRoot = root.ReplaceNode(parent, updatedParent); return document.WithSyntaxRoot(newRoot); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider.cs index 0357333fdb241..8dc2edf4352dc 100644 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider.cs @@ -214,14 +214,6 @@ private static bool CreateReturnStatementForExpression( return true; } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } // Stub classes needed only for exporting purposes. diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Fixing.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Fixing.cs index 3fb7b6c768d0c..9f451b3cb3d49 100644 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Fixing.cs +++ b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Fixing.cs @@ -20,9 +20,11 @@ internal partial class UseExpressionBodyForLambdaCodeStyleProvider { protected override Task> ComputeCodeActionsAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { - var codeAction = new MyCodeAction( - diagnostic.GetMessage(), - c => FixWithSyntaxEditorAsync(document, diagnostic, c)); + var title = diagnostic.GetMessage(); + var codeAction = CodeAction.Create( + title, + c => FixWithSyntaxEditorAsync(document, diagnostic, c), + title); return Task.FromResult(ImmutableArray.Create(codeAction)); } diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Refactoring.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Refactoring.cs index a394bfb30fe7b..d398f5c9cbe12 100644 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Refactoring.cs +++ b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeStyleProvider_Refactoring.cs @@ -109,19 +109,23 @@ private static async Task> ComputeRefactoringsAsync( using var resultDisposer = ArrayBuilder.GetInstance(out var result); if (CanOfferUseExpressionBody(option, lambdaNode, root.GetLanguageVersion())) { - result.Add(new MyCodeAction( - UseExpressionBodyTitle.ToString(), + var title = UseExpressionBodyTitle.ToString(); + result.Add(CodeAction.Create( + title, c => UpdateDocumentAsync( - document, root, lambdaNode, c))); + document, root, lambdaNode, c), + title)); } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (CanOfferUseBlockBody(semanticModel, option, lambdaNode, cancellationToken)) { - result.Add(new MyCodeAction( - UseBlockBodyTitle.ToString(), + var title = UseBlockBodyTitle.ToString(); + result.Add(CodeAction.Create( + title, c => UpdateDocumentAsync( - document, root, lambdaNode, c))); + document, root, lambdaNode, c), + title)); } return result.ToImmutable(); diff --git a/src/Features/CSharp/Portable/UseNamedArguments/CSharpUseNamedArgumentsCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseNamedArguments/CSharpUseNamedArgumentsCodeRefactoringProvider.cs index 6f65b384fd1f9..09dd11dc69a2b 100644 --- a/src/Features/CSharp/Portable/UseNamedArguments/CSharpUseNamedArgumentsCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseNamedArguments/CSharpUseNamedArgumentsCodeRefactoringProvider.cs @@ -41,7 +41,7 @@ protected override bool IsImplicitIndexOrRangeIndexer(ImmutableArray FixableDiagnosticIds public override Task RegisterCodeFixesAsync(CodeFixContext context) { - context.RegisterCodeFix(new MyCodeAction(GetDocumentUpdater(context)), context.Diagnostics); + context.RegisterCodeFix( + CodeAction.CreateWithPriority( + CodeActionPriority.Low, + CSharpAnalyzersResources.Use_pattern_matching, + GetDocumentUpdater(context), + nameof(CSharpAnalyzersResources.Use_pattern_matching)), + context.Diagnostics); return Task.CompletedTask; } @@ -62,15 +68,5 @@ protected override async Task FixAllAsync( var updatedRoot = updatedSemanticModel.SyntaxTree.GetRoot(cancellationToken); editor.ReplaceNode(editor.OriginalRoot, updatedRoot); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(CSharpAnalyzersResources.Use_pattern_matching, createChangedDocument, nameof(CSharpIsAndCastCheckWithoutNameCodeFixProvider)) - { - } - - internal override CodeActionPriority Priority => CodeActionPriority.Low; - } } } diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf index cbcc3428f3b8e..c8d18056a4fdc 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf @@ -117,6 +117,11 @@ Použít předvolby příkazu using + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences Použít předvolby var @@ -157,11 +162,6 @@ Převést na nezpracovaný řetězec - - Convert to raw string (no indent) - Převést na nezpracovaný řetězec (bez odsazení) - - Convert to regular string Převést na běžný řetězec @@ -187,6 +187,11 @@ Povolit v projektu typy odkazů s možnou hodnotou null + + Global 'using' directives + Global 'using' directives + + Inline temporary variable Dočasná vložená proměnná @@ -757,6 +762,14 @@ Zavést příkaz using {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement příkaz yield break diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf index ea96e7612aa1f..c73a8149745f5 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf @@ -117,6 +117,11 @@ Verwendunganweisungseinstellungen anwenden + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences „var“-Einstellungen anwenden @@ -157,11 +162,6 @@ In Rohzeichenfolge konvertieren - - Convert to raw string (no indent) - In rohe Zeichenfolge konvertieren (kein Einzug) - - Convert to regular string In reguläre Zeichenfolge konvertieren @@ -187,6 +187,11 @@ Nullwerte zulassende Verweistypen im Projekt aktivieren + + Global 'using' directives + Global 'using' directives + + Inline temporary variable Inline temporär variabel @@ -757,6 +762,14 @@ "using"-Anweisung einführen {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement yield break-Anweisung diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf index 0b123e5965722..5c465cf487a68 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf @@ -117,6 +117,11 @@ Aplicar preferencias de instrucción using + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences Aplicar preferencias \"var\" @@ -157,11 +162,6 @@ Convertir en cadena sin formato - - Convert to raw string (no indent) - Convertir en cadena sin formato (sin sangría) - - Convert to regular string Convertir en cadena regular @@ -187,6 +187,11 @@ Habilitar tipos de referencia que aceptan valores NULL en el proyecto + + Global 'using' directives + Global 'using' directives + + Inline temporary variable Variable temporal en línea @@ -757,6 +762,14 @@ Introducir la instrucción "using" {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement instrucción yield break diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf index 9fd60db52ff3f..c9d360a5ea75a 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf @@ -117,6 +117,11 @@ Appliquer les préférences d’instruction using + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences Appliquer les préférences 'var' @@ -157,11 +162,6 @@ Convertir en chaîne brute - - Convert to raw string (no indent) - Convertir en chaîne brute (pas de retrait) - - Convert to regular string Convertir en chaîne classique @@ -187,6 +187,11 @@ Activer les types de référence nullables dans le projet + + Global 'using' directives + Global 'using' directives + + Inline temporary variable Variable temporaire inline @@ -757,6 +762,14 @@ Introduire l’instruction 'using' {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement instruction yield break diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf index cb74844536edc..87555e7660a2b 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf @@ -117,6 +117,11 @@ Applica preferenze dell'istruzione using + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences Applica preferenze 'var' @@ -157,11 +162,6 @@ Converti in stringa non elaborata - - Convert to raw string (no indent) - Converti in stringa non elaborata (nessun rientro) - - Convert to regular string Converti in stringa normale @@ -187,6 +187,11 @@ Abilita tipi riferimento nullable nel progetto + + Global 'using' directives + Global 'using' directives + + Inline temporary variable Variabile temporanea inline @@ -757,6 +762,14 @@ Introduci l'istruzione 'using' {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement istruzione yield break diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf index b2cf7b62b6f26..a4f93c1ea1bcf 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf @@ -117,6 +117,11 @@ using ステートメントの基本設定を適用する + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences 'var' の基本設定を適用する: @@ -157,11 +162,6 @@ 生文字列に変換する - - Convert to raw string (no indent) - 生文字列に変換 (インデントなし) - - Convert to regular string 正規文字列に変換する @@ -187,6 +187,11 @@ プロジェクトで null 許容参照型を有効にする + + Global 'using' directives + Global 'using' directives + + Inline temporary variable インラインの一時変数 @@ -757,6 +762,14 @@ 'using' ステートメントを導入します {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement yield break ステートメント diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf index 640ce1c05e363..df2d82a06750b 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf @@ -117,6 +117,11 @@ Using 문 적용 기본 설정 + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences 'var' 적용 기본 설정 @@ -157,11 +162,6 @@ 원시 문자열로 변환 - - Convert to raw string (no indent) - 원시 문자열로 변환(한 수준 내리기 안 함) - - Convert to regular string 일반 문자열로 변환 @@ -187,6 +187,11 @@ 프로젝트에서 null 허용 참조 형식 사용 + + Global 'using' directives + Global 'using' directives + + Inline temporary variable 인라인 임시 변수 @@ -757,6 +762,14 @@ 'using' 문 지정 {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement yield break 문 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf index 2a746d93ea58a..bb9bde014fa93 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf @@ -117,6 +117,11 @@ Zastosuj preferencje instrukcji użycia + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences Zastosuj preferencje „var” @@ -157,11 +162,6 @@ Konwertuj na nieprzetworzony ciąg - - Convert to raw string (no indent) - Konwertuj na nieprzetworzony ciąg (bez wcięcia) - - Convert to regular string Konwertuj na zwykły ciąg @@ -187,6 +187,11 @@ Włącz typy referencyjne dopuszczające wartości null w projekcie + + Global 'using' directives + Global 'using' directives + + Inline temporary variable Wstawiona zmienna tymczasowa @@ -757,6 +762,14 @@ Wprowadź instrukcję „using” {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement instrukcja yield break diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf index ca4e409449607..1f808fc338950 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf @@ -117,6 +117,11 @@ Aplicar preferências de uso de instrução + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences Aplicar preferências de “var”: @@ -157,11 +162,6 @@ Converter em cadeia de caracteres bruta - - Convert to raw string (no indent) - Converter em cadeia de caracteres bruta (sem recuo) - - Convert to regular string Converter para cadeia de caracteres regular @@ -187,6 +187,11 @@ Habilitar os tipos de referência anuláveis no projeto + + Global 'using' directives + Global 'using' directives + + Inline temporary variable Variável temporária embutida @@ -757,6 +762,14 @@ Introduzir a instrução 'using' {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement instrução yield break diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf index 87823c1ce20f7..4bd0a6e90ef2c 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf @@ -117,6 +117,11 @@ Применить настройки для оператора using + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences Применить настройки для \"var\" @@ -157,11 +162,6 @@ Преобразовать в необработанную строку - - Convert to raw string (no indent) - Преобразовать в необработанную строку (без отступа) - - Convert to regular string Преобразовать в обычную строку @@ -187,6 +187,11 @@ Включить типы ссылок, допускающие значение NULL, в проекте + + Global 'using' directives + Global 'using' directives + + Inline temporary variable Встроенная временная переменная @@ -757,6 +762,14 @@ Добавить инструкцию 'using' {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement оператор yield break diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf index 095f338b07c6f..62774cb90841a 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf @@ -117,6 +117,11 @@ Using deyimi tercihlerini uygula + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences 'var' tercihlerini uygula @@ -157,11 +162,6 @@ Ham dizeye dönüştür - - Convert to raw string (no indent) - Ham dizeye dönüştür (girinti yok) - - Convert to regular string Normal dizeye dönüştür @@ -187,6 +187,11 @@ Projedeki null atanabilir başvuru türlerini etkinleştir + + Global 'using' directives + Global 'using' directives + + Inline temporary variable Satır içi geçici değişken @@ -757,6 +762,14 @@ 'using' deyimi ekle {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement yield break deyimi diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf index 5fdefd2c93d4a..5bdb196ca488e 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf @@ -117,6 +117,11 @@ 使用语句首选项应用 + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences 应用 \"var\" 首选项 @@ -157,11 +162,6 @@ 转换为原始字符串 - - Convert to raw string (no indent) - 转换为原始字符串(无缩进) - - Convert to regular string 转换为正则字符串 @@ -187,6 +187,11 @@ 在项目中启用可为 null 的引用类型 + + Global 'using' directives + Global 'using' directives + + Inline temporary variable 内联临时变量 @@ -757,6 +762,14 @@ 引入 'using' 语句 {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement yield break 语句 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf index d8864333348bf..f7305f3c56e8d 100644 --- a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf +++ b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf @@ -117,6 +117,11 @@ 套用 Using 陳述式喜好設定 + + Apply UTF-8 string literal preferences + Apply UTF-8 string literal preferences + + Apply 'var' preferences 套用 'var' 喜好設定 @@ -157,11 +162,6 @@ 轉換成原始字串 - - Convert to raw string (no indent) - 轉換成原始字串 (無縮排) - - Convert to regular string 轉換為一般字串 @@ -187,6 +187,11 @@ 在專案中啟用可為 Null 的參考類型 + + Global 'using' directives + Global 'using' directives + + Inline temporary variable 內嵌暫存變數 @@ -757,6 +762,14 @@ 引進 'using’ 陳述式 {Locked="using"} "using" is a C# keyword and should not be localized. + + ... without leading whitespace (may change semantics) + ... without leading whitespace (may change semantics) + This clause is a follow up to the "Convert to raw string" loc string. + The intent is that the user sees "Convert to raw string" as an option to select, + and that is then followed with this clause. This is so we don't have a huge string + saying "Convert to raw string without leading whitespace (may change semantics)" + yield break statement yield break 陳述式 diff --git a/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs b/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs index 0ce53cfa86f30..bb4a326124f06 100644 --- a/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddAnonymousTypeMemberName/AbstractAddAnonymousTypeMemberNameCodeFixProvider.cs @@ -42,7 +42,12 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } - context.RegisterCodeFix(new MyCodeAction(GetDocumentUpdater(context)), context.Diagnostics); + context.RegisterCodeFix( + CodeAction.Create( + FeaturesResources.Add_member_name, + GetDocumentUpdater(context), + nameof(FeaturesResources.Add_member_name)), + context.Diagnostics); } private async Task GetMemberDeclaratorAsync( @@ -129,13 +134,5 @@ private async Task FixOneAsync( return WithName(currentDeclarator, nameToken); }); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Add_member_name, createChangedDocument, nameof(FeaturesResources.Add_member_name)) - { - } - } } } diff --git a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs index 7fbb15e834188..156832a8177f0 100644 --- a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs +++ b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.AddConstructorParametersCodeAction.cs @@ -22,6 +22,7 @@ internal partial class AddConstructorParametersFromMembersCodeRefactoringProvide private class AddConstructorParametersCodeAction : CodeAction { private readonly Document _document; + private readonly CodeGenerationContextInfo _info; private readonly ConstructorCandidate _constructorCandidate; private readonly ISymbol _containingType; private readonly ImmutableArray _missingParameters; @@ -35,19 +36,21 @@ private class AddConstructorParametersCodeAction : CodeAction public AddConstructorParametersCodeAction( Document document, + CodeGenerationContextInfo info, ConstructorCandidate constructorCandidate, ISymbol containingType, ImmutableArray missingParameters, bool useSubMenuName) { _document = document; + _info = info; _constructorCandidate = constructorCandidate; _containingType = containingType; _missingParameters = missingParameters; _useSubMenuName = useSubMenuName; } - protected override async Task GetChangedSolutionAsync(CancellationToken cancellationToken) + protected override Task GetChangedSolutionAsync(CancellationToken cancellationToken) { var services = _document.Project.Solution.Workspace.Services; var declarationService = _document.GetRequiredLanguageService(); @@ -55,11 +58,10 @@ public AddConstructorParametersCodeAction( _constructorCandidate.Constructor).Select(r => r.GetSyntax(cancellationToken)).First(); var codeGenerator = _document.GetRequiredLanguageService(); - var options = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, _document, cancellationToken).ConfigureAwait(false); var newConstructor = constructor; - newConstructor = codeGenerator.AddParameters(newConstructor, _missingParameters, options, cancellationToken); - newConstructor = codeGenerator.AddStatements(newConstructor, CreateAssignStatements(_constructorCandidate), options, cancellationToken) + newConstructor = codeGenerator.AddParameters(newConstructor, _missingParameters, _info, cancellationToken); + newConstructor = codeGenerator.AddStatements(newConstructor, CreateAssignStatements(_constructorCandidate), _info, cancellationToken) .WithAdditionalAnnotations(Formatter.Annotation); var syntaxTree = constructor.SyntaxTree; @@ -69,7 +71,7 @@ public AddConstructorParametersCodeAction( var constructorDocument = _document.Project.GetDocument(syntaxTree); Contract.ThrowIfNull(constructorDocument); - return constructorDocument.WithSyntaxRoot(newRoot).Project.Solution; + return Task.FromResult(constructorDocument.WithSyntaxRoot(newRoot).Project.Solution); } private IEnumerable CreateAssignStatements(ConstructorCandidate constructorCandidate) diff --git a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs index c90a3914b9812..0d22a883f31d8 100644 --- a/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddConstructorParametersFromMembers/AddConstructorParametersFromMembersCodeRefactoringProvider.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; @@ -43,7 +44,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var result = await AddConstructorParametersFromMembersAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + var result = await AddConstructorParametersFromMembersAsync(document, textSpan, context.Options, cancellationToken).ConfigureAwait(false); if (result == null) { return; @@ -53,7 +54,8 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte context.RegisterRefactorings(actions); } - private static async Task AddConstructorParametersFromMembersAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken) + private static async Task AddConstructorParametersFromMembersAsync( + Document document, TextSpan textSpan, CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateFromMembers_AddConstructorParametersFromMembers, cancellationToken)) { @@ -68,7 +70,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var state = await State.GenerateAsync(info.SelectedMembers, document, cancellationToken).ConfigureAwait(false); if (state?.ConstructorCandidates != null && !state.ConstructorCandidates.IsEmpty) { - return CreateCodeActions(document, state); + var codeGenOptions = await document.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); + var contextInfo = codeGenOptions.GetInfo(CodeGenerationContext.Default, document.Project); + + return CreateCodeActions(document, contextInfo, state); } } @@ -108,7 +113,7 @@ private static ImmutableArray GetGroupedActions(AddConstructorParame return actions.ToImmutable(); } - private static AddConstructorParameterResult CreateCodeActions(Document document, State state) + private static AddConstructorParameterResult CreateCodeActions(Document document, CodeGenerationContextInfo info, State state) { using var _0 = ArrayBuilder.GetInstance(out var requiredParametersActions); using var _1 = ArrayBuilder.GetInstance(out var optionalParametersActions); @@ -121,6 +126,7 @@ private static AddConstructorParameterResult CreateCodeActions(Document document { requiredParametersActions.Add(new AddConstructorParametersCodeAction( document, + info, constructorCandidate, containingType, constructorCandidate.MissingParameters, @@ -129,6 +135,7 @@ private static AddConstructorParameterResult CreateCodeActions(Document document optionalParametersActions.Add(GetOptionalContructorParametersCodeAction( document, + info, constructorCandidate, containingType, useSubMenuName: useSubMenu)); @@ -140,7 +147,7 @@ private static AddConstructorParameterResult CreateCodeActions(Document document static bool CanHaveRequiredParameters(ImmutableArray parameters) => parameters.Length == 0 || !parameters.Last().IsOptional; - static AddConstructorParametersCodeAction GetOptionalContructorParametersCodeAction(Document document, ConstructorCandidate constructorCandidate, INamedTypeSymbol containingType, bool useSubMenuName) + static AddConstructorParametersCodeAction GetOptionalContructorParametersCodeAction(Document document, CodeGenerationContextInfo info, ConstructorCandidate constructorCandidate, INamedTypeSymbol containingType, bool useSubMenuName) { var missingOptionalParameters = constructorCandidate.MissingParameters.SelectAsArray( p => CodeGenerationSymbolFactory.CreateParameterSymbol( @@ -153,13 +160,14 @@ static AddConstructorParametersCodeAction GetOptionalContructorParametersCodeAct hasDefaultValue: true)); return new AddConstructorParametersCodeAction( - document, constructorCandidate, containingType, missingOptionalParameters, useSubMenuName); + document, info, constructorCandidate, containingType, missingOptionalParameters, useSubMenuName); } } - public async Task> ComputeIntentAsync(Document priorDocument, TextSpan priorSelection, Document currentDocument, IntentDataProvider intentDataProvider, CancellationToken cancellationToken) + public async Task> ComputeIntentAsync( + Document priorDocument, TextSpan priorSelection, Document currentDocument, IntentDataProvider intentDataProvider, CancellationToken cancellationToken) { - var addConstructorParametersResult = await AddConstructorParametersFromMembersAsync(priorDocument, priorSelection, cancellationToken).ConfigureAwait(false); + var addConstructorParametersResult = await AddConstructorParametersFromMembersAsync(priorDocument, priorSelection, intentDataProvider.FallbackOptions, cancellationToken).ConfigureAwait(false); if (addConstructorParametersResult == null) { return ImmutableArray.Empty; diff --git a/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs index 261c20b40f164..e1b5b97caebf4 100644 --- a/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddDebuggerDisplay/AbstractAddDebuggerDisplayCodeRefactoringProvider.cs @@ -56,9 +56,11 @@ await GetRelevantTypeFromHeaderAsync(context).ConfigureAwait(false) ?? if (HasDebuggerDisplayAttribute(typeSymbol, compilation)) return; - context.RegisterRefactoring(new MyCodeAction( + context.RegisterRefactoring(CodeAction.CreateWithPriority( priority, - c => ApplyAsync(document, type, debuggerAttributeTypeSymbol, c))); + FeaturesResources.Add_DebuggerDisplay_attribute, + c => ApplyAsync(document, type, debuggerAttributeTypeSymbol, c), + nameof(FeaturesResources.Add_DebuggerDisplay_attribute))); } private static async Task<(TTypeDeclarationSyntax type, CodeActionPriority priority)?> GetRelevantTypeFromHeaderAsync(CodeRefactoringContext context) @@ -95,10 +97,10 @@ await GetRelevantTypeFromHeaderAsync(context).ConfigureAwait(false) ?? } private static bool IsToStringMethod(IMethodSymbol methodSymbol) - => methodSymbol is { Name: nameof(ToString), Arity: 0, Parameters: { IsEmpty: true } }; + => methodSymbol is { Name: nameof(ToString), Arity: 0, Parameters.IsEmpty: true }; private static bool IsDebuggerDisplayMethod(IMethodSymbol methodSymbol) - => methodSymbol is { Name: DebuggerDisplayMethodName, Arity: 0, Parameters: { IsEmpty: true } }; + => methodSymbol is { Name: DebuggerDisplayMethodName, Arity: 0, Parameters.IsEmpty: true }; private static bool IsClassOrStruct(ITypeSymbol typeSymbol) => typeSymbol.TypeKind is TypeKind.Class or TypeKind.Struct; @@ -174,16 +176,5 @@ private async Task ApplyAsync(Document document, TTypeDeclarationSynta return document.WithSyntaxRoot(editor.GetChangedRoot()); } - - private sealed class MyCodeAction : CodeAction.DocumentChangeAction - { - internal override CodeActionPriority Priority { get; } - - public MyCodeAction(CodeActionPriority priority, Func> createChangedDocument) - : base(FeaturesResources.Add_DebuggerDisplay_attribute, createChangedDocument, nameof(FeaturesResources.Add_DebuggerDisplay_attribute)) - { - Priority = priority; - } - } } } diff --git a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs index 5744c0ab94899..abea0ab575aea 100644 --- a/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/AddFileBanner/AbstractAddFileBannerCodeRefactoringProvider.cs @@ -82,7 +82,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (siblingBanner.Length > 0 && !siblingDocument.IsGeneratedCode(cancellationToken)) { context.RegisterRefactoring( - new MyCodeAction(_ => AddBannerAsync(document, root, siblingDocument, siblingBanner)), + CodeAction.Create( + CodeFixesResources.Add_file_header, + _ => AddBannerAsync(document, root, siblingDocument, siblingBanner), + nameof(CodeFixesResources.Add_file_header)), new Text.TextSpan(position, length: 0)); return; } @@ -148,13 +151,5 @@ private async Task> TryGetBannerAsync( var token = syntaxFacts.ParseToken(text.ToString()); return bannerService.GetFileBanner(token); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(CodeFixesResources.Add_file_header, createChangedDocument, nameof(CodeFixesResources.Add_file_header)) - { - } - } } } diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs index c8567d70b4fc3..50387d3554821 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -56,7 +56,8 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var addImportService = document.GetRequiredLanguageService(); var services = document.Project.Solution.Workspace.Services; - var searchOptions = context.Options(document.Project.LanguageServices).SearchOptions; + var codeActionOptions = context.Options.GetOptions(document.Project.LanguageServices); + var searchOptions = codeActionOptions.SearchOptions; var symbolSearchService = _symbolSearchService ?? services.GetRequiredService(); @@ -77,7 +78,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var addImportOptions = new AddImportOptions( searchOptions, cleanupOptions, - context.Options(document.Project.LanguageServices).HideAdvancedMembers); + codeActionOptions.HideAdvancedMembers); var fixesForDiagnostic = await addImportService.GetFixesForDiagnosticsAsync( document, span, diagnostics, MaxResults, symbolSearchService, addImportOptions, packageSources, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs index a4c40808d2e81..4884081c4131e 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs @@ -26,9 +26,6 @@ private class ParentInstallPackageCodeAction : CodeAction.CodeActionWithNestedAc { public override ImmutableArray Tags => WellKnownTagArrays.NuGet; - // Adding a nuget reference is lower priority than other fixes.. - internal override CodeActionPriority Priority => CodeActionPriority.Low; - /// /// Even though we have child actions, we mark ourselves as explicitly non-inlinable. /// We want to the experience of having the top level item the user has to see and @@ -41,7 +38,8 @@ public ParentInstallPackageCodeAction( IPackageInstallerService installerService) : base(string.Format(FeaturesResources.Install_package_0, fixData.PackageName), CreateNestedActions(document, fixData, installerService), - isInlinable: false) + isInlinable: false, + priority: CodeActionPriority.Low) // Adding a nuget reference is lower priority than other fixes.. { Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.PackageSymbol); } diff --git a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs index 9e543e09569ad..25151d245702f 100644 --- a/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddPackage/AbstractAddPackageCodeFixProvider.cs @@ -52,7 +52,7 @@ protected async Task> GetAddPackagesCodeActionsAsync( var codeActions = ArrayBuilder.GetInstance(); if (symbolSearchService != null && installerService != null && - context.Options(document.Project.LanguageServices).SearchOptions.SearchNuGetPackages && + context.Options.GetOptions(document.Project.LanguageServices).SearchOptions.SearchNuGetPackages && installerService.IsEnabled(document.Project.Id)) { var packageSources = PackageSourceHelper.GetPackageSources(installerService.TryGetPackageSources()); diff --git a/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs b/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs index f1cb798cc20ef..aaaf7caa5a9fc 100644 --- a/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs @@ -247,9 +247,10 @@ ImmutableArray NestByOverload() { // We create the mandatory data.CreateChangedSolutionNonCascading fix first. var title = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, data.Method, includeParameters: true); - CodeAction codeAction = new MyCodeAction( - title: title, - data.CreateChangedSolutionNonCascading); + var codeAction = CodeAction.Create( + title, + data.CreateChangedSolutionNonCascading, + equivalenceKey: title); if (data.CreateChangedSolutionCascading != null) { // We have two fixes to offer. We nest the two fixes in an inlinable CodeAction @@ -261,9 +262,10 @@ ImmutableArray NestByOverload() title: titleForNesting, ImmutableArray.Create( codeAction, - new MyCodeAction( - title: titleCascading, - data.CreateChangedSolutionCascading)), + CodeAction.Create( + titleCascading, + data.CreateChangedSolutionCascading, + equivalenceKey: titleCascading)), isInlinable: true); } @@ -281,7 +283,7 @@ ImmutableArray NestByCascading() var nonCascadingActions = codeFixData.SelectAsArray(data => { var title = GetCodeFixTitle(FeaturesResources.Add_to_0, data.Method, includeParameters: true); - return (CodeAction)new MyCodeAction(title: title, data.CreateChangedSolutionNonCascading); + return CodeAction.Create(title, data.CreateChangedSolutionNonCascading, equivalenceKey: title); }); var cascadingActions = codeFixData.SelectAsArray( @@ -289,7 +291,7 @@ ImmutableArray NestByCascading() data => { var title = GetCodeFixTitle(FeaturesResources.Add_to_0, data.Method, includeParameters: true); - return (CodeAction)new MyCodeAction(title: title, data.CreateChangedSolutionCascading!); + return CodeAction.Create(title, data.CreateChangedSolutionCascading!, equivalenceKey: title); }); var aMethod = codeFixData.First().Method; // We need to term the MethodGroup and need an arbitrary IMethodSymbol to do so. @@ -561,13 +563,5 @@ private static bool TypeInfoMatchesType( return false; } - - private class MyCodeAction : CodeAction.SolutionChangeAction - { - public MyCodeAction(string title, Func> createChangedSolution) - : base(title, createChangedSolution, title) - { - } - } } } diff --git a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureCodeRefactoringProvider.cs b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureCodeRefactoringProvider.cs index 3994d97e04813..18e50f30ef69e 100644 --- a/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureCodeRefactoringProvider.cs @@ -29,7 +29,7 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex if (span.IsEmpty) { var service = document.GetLanguageService(); - var actions = await service.GetChangeSignatureCodeActionAsync(document, span, CodeCleanupOptions.CreateProvider(context.Options), cancellationToken).ConfigureAwait(false); + var actions = await service.GetChangeSignatureCodeActionAsync(document, span, context.Options, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); } } diff --git a/src/Features/Core/Portable/CodeFixes/AbstractConfigurationActionWithNestedActions.cs b/src/Features/Core/Portable/CodeFixes/AbstractConfigurationActionWithNestedActions.cs index 8054d3d34a351..b30a81e31f055 100644 --- a/src/Features/Core/Portable/CodeFixes/AbstractConfigurationActionWithNestedActions.cs +++ b/src/Features/Core/Portable/CodeFixes/AbstractConfigurationActionWithNestedActions.cs @@ -17,13 +17,11 @@ namespace Microsoft.CodeAnalysis.CodeFixes internal abstract class AbstractConfigurationActionWithNestedActions : CodeAction.CodeActionWithNestedActions { protected AbstractConfigurationActionWithNestedActions(ImmutableArray nestedActions, string title) - : base(title, nestedActions, isInlinable: false) + : base(title, nestedActions, isInlinable: false, + priority: CodeActionPriority.Lowest) // Put configurations/suppressions at the end of everything. { } - // Put configurations/suppressions at the end of everything. - internal override CodeActionPriority Priority => CodeActionPriority.Lowest; - /// /// Additional priority associated with all configuration and suppression code actions. /// This allows special code actions such as Bulk configuration to to be at the end of diff --git a/src/Features/Core/Portable/CodeFixes/Async/AbstractConvertToAsyncCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Async/AbstractConvertToAsyncCodeFixProvider.cs index 580708ca66e13..df81ee16c7bdb 100644 --- a/src/Features/Core/Portable/CodeFixes/Async/AbstractConvertToAsyncCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Async/AbstractConvertToAsyncCodeFixProvider.cs @@ -69,17 +69,11 @@ private async Task GetCodeActionAsync( var syntaxTree = result.Item1; var newRoot = result.Item2; var otherDocument = document.Project.Solution.GetDocument(syntaxTree); - return new MyCodeAction( - await GetDescriptionAsync(diagnostic, node, semanticModel, cancellationToken).ConfigureAwait(false), - token => Task.FromResult(otherDocument.WithSyntaxRoot(newRoot))); - } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } + var title = await GetDescriptionAsync(diagnostic, node, semanticModel, cancellationToken).ConfigureAwait(false); + return CodeAction.Create( + title, + token => Task.FromResult(otherDocument.WithSyntaxRoot(newRoot)), + title); } } } diff --git a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/AbstractFixAllCodeFixCodeAction.cs b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/AbstractFixAllCodeFixCodeAction.cs new file mode 100644 index 0000000000000..8d80b2381919c --- /dev/null +++ b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/AbstractFixAllCodeFixCodeAction.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; +using Microsoft.CodeAnalysis.Shared.Utilities; + +namespace Microsoft.CodeAnalysis.CodeFixes +{ + /// + /// Fix all code action for a code action registered by a . + /// + internal abstract class AbstractFixAllCodeFixCodeAction : AbstractFixAllCodeAction + { + private static readonly HashSet s_predefinedCodeFixProviderNames = GetPredefinedCodeFixProviderNames(); + + protected AbstractFixAllCodeFixCodeAction( + IFixAllState fixAllState, bool showPreviewChangesDialog) + : base(fixAllState, showPreviewChangesDialog) + { + } + + protected override IFixAllContext CreateFixAllContext(IFixAllState fixAllState, IProgressTracker progressTracker, CancellationToken cancellationToken) + => new FixAllContext((FixAllState)fixAllState, progressTracker, cancellationToken); + + protected override bool IsInternalProvider(IFixAllState fixAllState) + { + var exportAttributes = fixAllState.Provider.GetType().GetTypeInfo().GetCustomAttributes(typeof(ExportCodeFixProviderAttribute), false); + if (exportAttributes?.Any() == true) + { + var exportAttribute = (ExportCodeFixProviderAttribute)exportAttributes.First(); + return !string.IsNullOrEmpty(exportAttribute.Name) + && s_predefinedCodeFixProviderNames.Contains(exportAttribute.Name); + } + + return false; + } + + private static HashSet GetPredefinedCodeFixProviderNames() + { + var names = new HashSet(); + + var fields = typeof(PredefinedCodeFixProviderNames).GetTypeInfo().DeclaredFields; + foreach (var field in fields) + { + if (field.IsStatic) + { + names.Add((string)field.GetValue(null)!); + } + } + + return names; + } + } +} diff --git a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs index f3fa02d75dcde..d7814cb94117a 100644 --- a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixMultipleCodeAction.cs @@ -4,15 +4,17 @@ #nullable disable +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; + namespace Microsoft.CodeAnalysis.CodeFixes { - internal partial class FixMultipleCodeAction : FixSomeCodeAction + internal partial class FixMultipleCodeAction : AbstractFixAllCodeFixCodeAction { private readonly string _title; private readonly string _computingFixWaitDialogMessage; - internal FixMultipleCodeAction( - FixAllState fixAllState, + public FixMultipleCodeAction( + IFixAllState fixAllState, string title, string computingFixWaitDialogMessage) : base(fixAllState, showPreviewChangesDialog: false) diff --git a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixSomeCodeAction.cs b/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixSomeCodeAction.cs deleted file mode 100644 index 66c4af66d2bd9..0000000000000 --- a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/FixSomeCodeAction.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// 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.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Shared.Utilities; - -namespace Microsoft.CodeAnalysis.CodeFixes -{ - internal abstract class FixSomeCodeAction : CodeAction - { - private static readonly HashSet s_predefinedCodeFixProviderNames = GetPredefinedCodeFixProviderNames(); - - internal readonly FixAllState FixAllState; - private bool _showPreviewChangesDialog; - - internal FixSomeCodeAction( - FixAllState fixAllState, bool showPreviewChangesDialog) - { - FixAllState = fixAllState; - _showPreviewChangesDialog = showPreviewChangesDialog; - } - - protected override async Task> ComputeOperationsAsync(CancellationToken cancellationToken) - => await ComputeOperationsAsync(new ProgressTracker(), cancellationToken).ConfigureAwait(false); - - internal override Task> ComputeOperationsAsync( - IProgressTracker progressTracker, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - FixAllLogger.LogState(FixAllState, IsInternalCodeFixProvider(FixAllState.CodeFixProvider)); - - var service = FixAllState.Project.Solution.Workspace.Services.GetService(); - - var fixAllContext = new FixAllContext(FixAllState, progressTracker, cancellationToken); - if (progressTracker != null) - progressTracker.Description = FixAllContextHelper.GetDefaultFixAllTitle(fixAllContext); - - return service.GetFixAllOperationsAsync(fixAllContext, _showPreviewChangesDialog); - } - - internal sealed override Task GetChangedSolutionAsync( - IProgressTracker progressTracker, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - FixAllLogger.LogState(FixAllState, IsInternalCodeFixProvider(FixAllState.CodeFixProvider)); - - var service = FixAllState.Project.Solution.Workspace.Services.GetService(); - - var fixAllContext = new FixAllContext(FixAllState, progressTracker, cancellationToken); - if (progressTracker != null) - progressTracker.Description = FixAllContextHelper.GetDefaultFixAllTitle(fixAllContext); - - return service.GetFixAllChangedSolutionAsync(fixAllContext); - } - - private static bool IsInternalCodeFixProvider(CodeFixProvider fixer) - { - var exportAttributes = fixer.GetType().GetTypeInfo().GetCustomAttributes(typeof(ExportCodeFixProviderAttribute), false); - if (exportAttributes?.Any() == true) - { - var exportAttribute = (ExportCodeFixProviderAttribute)exportAttributes.First(); - return s_predefinedCodeFixProviderNames.Contains(exportAttribute.Name); - } - - return false; - } - - private static HashSet GetPredefinedCodeFixProviderNames() - { - var names = new HashSet(); - - var fields = typeof(PredefinedCodeFixProviderNames).GetTypeInfo().DeclaredFields; - foreach (var field in fields) - { - if (field.IsStatic) - { - names.Add((string)field.GetValue(null)); - } - } - - return names; - } - - internal TestAccessor GetTestAccessor() - => new(this); - - internal readonly struct TestAccessor - { - private readonly FixSomeCodeAction _fixSomeCodeAction; - - internal TestAccessor(FixSomeCodeAction fixSomeCodeAction) - => _fixSomeCodeAction = fixSomeCodeAction; - - /// - /// Gets a reference to , which can be read or written by test code. - /// - public ref bool ShowPreviewChangesDialog - => ref _fixSomeCodeAction._showPreviewChangesDialog; - } - } -} diff --git a/src/Features/Core/Portable/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs index 83c378af27d1a..37532bfb73285 100644 --- a/src/Features/Core/Portable/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/GenerateMember/AbstractGenerateMemberCodeFixProvider.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -23,7 +24,7 @@ internal abstract class AbstractGenerateMemberCodeFixProvider : CodeFixProvider return null; } - protected abstract Task> GetCodeActionsAsync(Document document, SyntaxNode node, CancellationToken cancellationToken); + protected abstract Task> GetCodeActionsAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken); protected abstract bool IsCandidate(SyntaxNode node, SyntaxToken token, Diagnostic diagnostic); public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) @@ -43,7 +44,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var names = GetTargetNodes(syntaxFacts, root, context.Span, diagnostic); foreach (var name in names) { - var codeActions = await GetCodeActionsAsync(context.Document, name, context.CancellationToken).ConfigureAwait(false); + var codeActions = await GetCodeActionsAsync(context.Document, name, context.Options, context.CancellationToken).ConfigureAwait(false); if (codeActions.IsDefaultOrEmpty) { continue; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionBatchFixAllProvider.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionBatchFixAllProvider.cs index 22e76e7b5813f..2084246815783 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionBatchFixAllProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionBatchFixAllProvider.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Collections; @@ -50,7 +51,7 @@ protected AbstractSuppressionBatchFixAllProvider() { } if (documentsAndDiagnosticsToFixMap?.Any() == true) { var progressTracker = fixAllContext.GetProgressTracker(); - progressTracker.Description = FixAllContextHelper.GetDefaultFixAllTitle(fixAllContext); + progressTracker.Description = fixAllContext.GetDefaultFixAllTitle(); var fixAllState = fixAllContext.State; FixAllLogger.LogDiagnosticsStats(fixAllState.CorrelationId, documentsAndDiagnosticsToFixMap); @@ -150,7 +151,7 @@ protected virtual async Task AddDocumentFixesAsync( // TODO: Wrap call to ComputeFixesAsync() below in IExtensionManager.PerformFunctionAsync() so that // a buggy extension that throws can't bring down the host? - return fixAllState.CodeFixProvider.RegisterCodeFixesAsync(context) ?? Task.CompletedTask; + return fixAllState.Provider.RegisterCodeFixesAsync(context) ?? Task.CompletedTask; }, cancellationToken)); } @@ -249,7 +250,7 @@ protected virtual Task AddProjectFixesAsync( } public virtual string GetFixAllTitle(FixAllState fixAllState) - => FixAllContextHelper.GetDefaultFixAllTitle(fixAllState.Scope, fixAllState.DiagnosticIds, fixAllState.Document, fixAllState.Project); + => FixAllHelper.GetDefaultFixAllTitle(fixAllState.Scope, title: fixAllState.DiagnosticIds.First(), fixAllState.Document!, fixAllState.Project); public virtual async Task TryMergeFixesAsync( Solution oldSolution, diff --git a/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllCodeAction.cs b/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllCodeAction.cs new file mode 100644 index 0000000000000..a38945733651b --- /dev/null +++ b/src/Features/Core/Portable/CodeFixesAndRefactorings/AbstractFixAllCodeAction.cs @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Roslyn.Utilities; +using FixAllScope = Microsoft.CodeAnalysis.CodeFixes.FixAllScope; + +namespace Microsoft.CodeAnalysis.CodeFixesAndRefactorings +{ + /// + /// Fix all code action for a code action registered by + /// a or a . + /// + internal abstract class AbstractFixAllCodeAction : CodeAction + { + private bool _showPreviewChangesDialog; + + public IFixAllState FixAllState { get; } + + protected AbstractFixAllCodeAction( + IFixAllState fixAllState, bool showPreviewChangesDialog) + { + FixAllState = fixAllState; + _showPreviewChangesDialog = showPreviewChangesDialog; + } + + /// + /// Determine if the is an internal first-party provider or not. + /// + protected abstract bool IsInternalProvider(IFixAllState fixAllState); + + /// + /// Creates a new with the given parameters. + /// + protected abstract IFixAllContext CreateFixAllContext(IFixAllState fixAllState, IProgressTracker progressTracker, CancellationToken cancellationToken); + + public override string Title + => this.FixAllState.Scope switch + { + FixAllScope.Document => FeaturesResources.Document, + FixAllScope.Project => FeaturesResources.Project, + FixAllScope.Solution => FeaturesResources.Solution, + FixAllScope.ContainingMember => FeaturesResources.Containing_Member, + FixAllScope.ContainingType => FeaturesResources.Containing_Type, + _ => throw ExceptionUtilities.UnexpectedValue(this.FixAllState.Scope), + }; + + internal override string Message => FeaturesResources.Computing_fix_all_occurrences_code_fix; + + protected sealed override async Task> ComputeOperationsAsync(CancellationToken cancellationToken) + => await ComputeOperationsAsync(new ProgressTracker(), cancellationToken).ConfigureAwait(false); + + internal sealed override Task> ComputeOperationsAsync( + IProgressTracker progressTracker, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + FixAllLogger.LogState(FixAllState, IsInternalProvider(FixAllState)); + + var service = FixAllState.Project.Solution.Workspace.Services.GetRequiredService(); + + var fixAllContext = CreateFixAllContext(FixAllState, progressTracker, cancellationToken); + progressTracker.Description = fixAllContext.GetDefaultFixAllTitle(); + + return service.GetFixAllOperationsAsync(fixAllContext, _showPreviewChangesDialog); + } + + internal sealed override Task GetChangedSolutionAsync( + IProgressTracker progressTracker, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + FixAllLogger.LogState(FixAllState, IsInternalProvider(FixAllState)); + + var service = FixAllState.Project.Solution.Workspace.Services.GetRequiredService(); + + var fixAllContext = CreateFixAllContext(FixAllState, progressTracker, cancellationToken); + progressTracker.Description = fixAllContext.GetDefaultFixAllTitle(); + + return service.GetFixAllChangedSolutionAsync(fixAllContext); + } + + // internal for testing purposes. + internal TestAccessor GetTestAccessor() + => new(this); + + // internal for testing purposes. + internal readonly struct TestAccessor + { + private readonly AbstractFixAllCodeAction _fixAllCodeAction; + + internal TestAccessor(AbstractFixAllCodeAction fixAllCodeAction) + => _fixAllCodeAction = fixAllCodeAction; + + /// + /// Gets a reference to , which can be read or written by test code. + /// + public ref bool ShowPreviewChangesDialog + => ref _fixAllCodeAction._showPreviewChangesDialog; + } + } +} diff --git a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/IFixAllGetFixesService.cs b/src/Features/Core/Portable/CodeFixesAndRefactorings/IFixAllGetFixesService.cs similarity index 80% rename from src/Features/Core/Portable/CodeFixes/FixAllOccurrences/IFixAllGetFixesService.cs rename to src/Features/Core/Portable/CodeFixesAndRefactorings/IFixAllGetFixesService.cs index 8e5c98c878c5b..1f73730297125 100644 --- a/src/Features/Core/Portable/CodeFixes/FixAllOccurrences/IFixAllGetFixesService.cs +++ b/src/Features/Core/Portable/CodeFixesAndRefactorings/IFixAllGetFixesService.cs @@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Host; -namespace Microsoft.CodeAnalysis.CodeFixes +namespace Microsoft.CodeAnalysis.CodeFixesAndRefactorings { internal interface IFixAllGetFixesService : IWorkspaceService { @@ -17,11 +17,11 @@ internal interface IFixAllGetFixesService : IWorkspaceService /// Computes the fix all occurrences code fix, brings up the preview changes dialog for the fix and /// returns the code action operations corresponding to the fix. /// - Task> GetFixAllOperationsAsync(FixAllContext fixAllContext, bool showPreviewChangesDialog); + Task> GetFixAllOperationsAsync(IFixAllContext fixAllContext, bool showPreviewChangesDialog); /// /// Computes the fix all occurrences code fix and returns the changed solution. /// - Task GetFixAllChangedSolutionAsync(FixAllContext fixAllContext); + Task GetFixAllChangedSolutionAsync(IFixAllContext fixAllContext); } } diff --git a/src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs index a7c7c87ae31f5..6e9620343eaaf 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddAwait/AbstractAddAwaitCodeRefactoringProvider.cs @@ -48,16 +48,20 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex var expression = expressions[i]; if (IsValidAwaitableExpression(model, syntaxFacts, expression, cancellationToken)) { + var title = GetTitle(); context.RegisterRefactoring( - new MyCodeAction( - GetTitle(), - c => AddAwaitAsync(document, expression, withConfigureAwait: false, c)), + CodeAction.Create( + title, + c => AddAwaitAsync(document, expression, withConfigureAwait: false, c), + title), expression.Span); + var titleWithConfigureAwait = GetTitleWithConfigureAwait(); context.RegisterRefactoring( - new MyCodeAction( - GetTitleWithConfigureAwait(), - c => AddAwaitAsync(document, expression, withConfigureAwait: true, c)), + CodeAction.Create( + titleWithConfigureAwait, + c => AddAwaitAsync(document, expression, withConfigureAwait: true, c), + titleWithConfigureAwait), expression.Span); } } @@ -109,13 +113,5 @@ private static Task AddAwaitAsync( return document.ReplaceNodeAsync(expression, awaitExpression, cancellationToken); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs index d9acc7242f7c0..59e2c084904e8 100644 --- a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsRefactoringProvider.cs @@ -7,6 +7,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Formatting; @@ -39,7 +40,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var cleanupOptions = await document.GetCodeCleanupOptionsAsync(context.Options, cancellationToken).ConfigureAwait(false); var options = new AddMissingImportsOptions( cleanupOptions, - context.Options(document.Project.LanguageServices).HideAdvancedMembers); + context.Options.GetOptions(document.Project.LanguageServices).HideAdvancedMembers); var analysis = await addMissingImportsService.AnalyzeAsync(document, textSpan, options, cancellationToken).ConfigureAwait(false); if (!analysis.CanAddMissingImports) @@ -47,9 +48,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var addImportsCodeAction = new AddMissingImportsCodeAction( + var addImportsCodeAction = CodeAction.Create( CodeActionTitle, - cancellationToken => AddMissingImportsAsync(document, addMissingImportsService, analysis, options.CleanupOptions.FormattingOptions, cancellationToken)); + cancellationToken => AddMissingImportsAsync(document, addMissingImportsService, analysis, options.CleanupOptions.FormattingOptions, cancellationToken), + CodeActionTitle); context.RegisterRefactoring(addImportsCodeAction, textSpan); } @@ -59,13 +61,5 @@ private static async Task AddMissingImportsAsync(Document document, IA var modifiedDocument = await addMissingImportsService.AddMissingImportsAsync(document, analysis, formattingOptions, cancellationToken).ConfigureAwait(false); return modifiedDocument.Project.Solution; } - - private class AddMissingImportsCodeAction : CodeActions.CodeAction.SolutionChangeAction - { - public AddMissingImportsCodeAction(string title, Func> createChangedSolution) - : base(title, createChangedSolution, title) - { - } - } } } diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoring.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoring.cs index e675d46fcdd45..3938a5780a37d 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoring.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoring.cs @@ -2,11 +2,10 @@ // 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.Collections.Immutable; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CodeRefactorings @@ -27,10 +26,16 @@ internal class CodeRefactoring /// public ImmutableArray<(CodeAction action, TextSpan? applicableToSpan)> CodeActions { get; } - public CodeRefactoring(CodeRefactoringProvider provider, ImmutableArray<(CodeAction, TextSpan?)> actions) + public FixAllProviderInfo? FixAllProviderInfo { get; } + + public CodeRefactoring( + CodeRefactoringProvider provider, + ImmutableArray<(CodeAction, TextSpan?)> actions, + FixAllProviderInfo? fixAllProviderInfo) { Provider = provider; CodeActions = actions.NullToEmpty(); + FixAllProviderInfo = fixAllProviderInfo; if (CodeActions.IsEmpty) { diff --git a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs index fd5b54aa4c790..c4c076031f14e 100644 --- a/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/CodeRefactoringService.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Extensions; using Microsoft.CodeAnalysis.Host.Mef; @@ -28,11 +29,8 @@ internal sealed class CodeRefactoringService : ICodeRefactoringService { private readonly Lazy>>> _lazyLanguageToProvidersMap; private readonly Lazy> _lazyRefactoringToMetadataMap; - private readonly ConditionalWeakTable, StrongBox>> _projectRefactoringsMap = new(); - private readonly ConditionalWeakTable _analyzerReferenceToRefactoringsMap = new(); - private readonly ConditionalWeakTable.CreateValueCallback _createProjectCodeRefactoringsProvider - = new(r => new ProjectCodeRefactoringProvider(r)); + private ImmutableDictionary _fixAllProviderMap = ImmutableDictionary.Empty; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -132,7 +130,8 @@ public async Task> GetRefactoringsAsync( using (addOperationScope(providerName)) using (RoslynEventSource.LogInformationalBlock(FunctionId.Refactoring_CodeRefactoringService_GetRefactoringsAsync, providerName, cancellationToken)) { - return GetRefactoringFromProviderAsync(document, state, provider, providerMetadata, extensionManager, options, cancellationToken); + return GetRefactoringFromProviderAsync(document, state, provider, providerMetadata, + extensionManager, options, cancellationToken); } }, cancellationToken)); @@ -143,7 +142,7 @@ public async Task> GetRefactoringsAsync( } } - private static async Task GetRefactoringFromProviderAsync( + private async Task GetRefactoringFromProviderAsync( Document document, TextSpan state, CodeRefactoringProvider provider, @@ -183,11 +182,14 @@ public async Task> GetRefactoringsAsync( var task = provider.ComputeRefactoringsAsync(context) ?? Task.CompletedTask; await task.ConfigureAwait(false); - var result = actions.Count > 0 - ? new CodeRefactoring(provider, actions.ToImmutable()) - : null; + if (actions.Count == 0) + { + return null; + } - return result; + var fixAllProviderInfo = extensionManager.PerformFunction( + provider, () => ImmutableInterlocked.GetOrAdd(ref _fixAllProviderMap, provider, FixAllProviderInfo.Create), defaultValue: null); + return new CodeRefactoring(provider, actions.ToImmutable(), fixAllProviderInfo); } catch (OperationCanceledException) { @@ -203,49 +205,18 @@ public async Task> GetRefactoringsAsync( return null; } - private ImmutableArray GetProjectRefactorings(Project project) + private static ImmutableArray GetProjectRefactorings(Project project) { // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict refactorings in Interactive if (project.Solution.Workspace.Kind == WorkspaceKind.Interactive) - { return ImmutableArray.Empty; - } - - if (_projectRefactoringsMap.TryGetValue(project.AnalyzerReferences, out var refactorings)) - { - return refactorings.Value; - } - - return GetProjectRefactoringsSlow(project); - // Local functions - ImmutableArray GetProjectRefactoringsSlow(Project project) - { - return _projectRefactoringsMap.GetValue(project.AnalyzerReferences, pId => new StrongBox>(ComputeProjectRefactorings(project))).Value; - } - - ImmutableArray ComputeProjectRefactorings(Project project) - { - using var _ = ArrayBuilder.GetInstance(out var builder); - foreach (var reference in project.AnalyzerReferences) - { - var projectCodeRefactoringProvider = _analyzerReferenceToRefactoringsMap.GetValue(reference, _createProjectCodeRefactoringsProvider); - foreach (var refactoring in projectCodeRefactoringProvider.GetExtensions(project.Language)) - builder.Add(refactoring); - } - - return builder.ToImmutable(); - } + return ProjectCodeRefactoringProvider.GetExtensions(project); } private class ProjectCodeRefactoringProvider - : AbstractProjectExtensionProvider + : AbstractProjectExtensionProvider { - public ProjectCodeRefactoringProvider(AnalyzerReference reference) - : base(reference) - { - } - protected override bool SupportsLanguage(ExportCodeRefactoringProviderAttribute exportAttribute, string language) { return exportAttribute.Languages == null diff --git a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs index d0e83a3ca20f7..33c78be068002 100644 --- a/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/ExtractMethod/AbstractExtractMethodCodeRefactoringProvider.cs @@ -57,7 +57,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var extractOptions = context.Options(document.Project.LanguageServices).ExtractMethodOptions; + var extractOptions = await document.GetExtractMethodGenerationOptionsAsync(context.Options, cancellationToken).ConfigureAwait(false); var cleanupOptions = await document.GetCodeCleanupOptionsAsync(context.Options, cancellationToken).ConfigureAwait(false); var actions = await GetCodeActionsAsync(document, textSpan, extractOptions, cleanupOptions, cancellationToken).ConfigureAwait(false); @@ -67,7 +67,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte private static async Task> GetCodeActionsAsync( Document document, TextSpan textSpan, - ExtractMethodOptions extractOptions, + ExtractMethodGenerationOptions extractOptions, CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken) { @@ -81,7 +81,7 @@ private static async Task> GetCodeActionsAsync( return actions.ToImmutable(); } - private static async Task ExtractMethodAsync(Document document, TextSpan textSpan, ExtractMethodOptions extractOptions, CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken) + private static async Task ExtractMethodAsync(Document document, TextSpan textSpan, ExtractMethodGenerationOptions extractOptions, CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken) { var result = await ExtractMethodService.ExtractMethodAsync( document, @@ -95,7 +95,7 @@ private static async Task ExtractMethodAsync(Document document, Text if (!result.Succeeded && !result.SucceededWithSuggestion) return null; - return new MyCodeAction( + return CodeAction.Create( FeaturesResources.Extract_method, async c => { @@ -105,7 +105,7 @@ private static async Task ExtractMethodAsync(Document document, Text nameof(FeaturesResources.Extract_method)); } - private static async Task ExtractLocalFunctionAsync(Document document, TextSpan textSpan, ExtractMethodOptions extractOptions, CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken) + private static async Task ExtractLocalFunctionAsync(Document document, TextSpan textSpan, ExtractMethodGenerationOptions extractOptions, CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken) { var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetLanguageService(); @@ -124,7 +124,7 @@ private static async Task ExtractLocalFunctionAsync(Document documen if (localFunctionResult.Succeeded || localFunctionResult.SucceededWithSuggestion) { - var codeAction = new MyCodeAction( + var codeAction = CodeAction.Create( FeaturesResources.Extract_local_function, async c => { @@ -148,13 +148,5 @@ private static async Task AddRenameAnnotationAsync(Document document, return document.WithSyntaxRoot(finalRoot); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument, string equivalenceKey) - : base(title, createChangedDocument, equivalenceKey) - { - } - } } } diff --git a/src/Features/Core/Portable/CodeRefactorings/FixAllOccurences/FixAllCodeRefactoringCodeAction.cs b/src/Features/Core/Portable/CodeRefactorings/FixAllOccurences/FixAllCodeRefactoringCodeAction.cs new file mode 100644 index 0000000000000..2a4f6eb7bea90 --- /dev/null +++ b/src/Features/Core/Portable/CodeRefactorings/FixAllOccurences/FixAllCodeRefactoringCodeAction.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; +using Microsoft.CodeAnalysis.Shared.Utilities; + +namespace Microsoft.CodeAnalysis.CodeRefactorings +{ + /// + /// Fix all code action for a code action registered by a . + /// + internal sealed class FixAllCodeRefactoringCodeAction : AbstractFixAllCodeAction + { + public FixAllCodeRefactoringCodeAction(IFixAllState fixAllState) + : base(fixAllState, showPreviewChangesDialog: true) + { + } + + protected override IFixAllContext CreateFixAllContext(IFixAllState fixAllState, IProgressTracker progressTracker, CancellationToken cancellationToken) + => new FixAllContext((FixAllState)fixAllState, progressTracker, cancellationToken); + + protected override bool IsInternalProvider(IFixAllState fixAllState) + => true; // FixAll for refactorings is currently only supported for internal code refactoring providers. + } +} diff --git a/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs index 59aa82f79d0e1..39d8c1f24fedc 100644 --- a/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/MoveType/MoveTypeCodeRefactoringProvider.cs @@ -7,6 +7,7 @@ using System.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -37,7 +38,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } var service = document.GetLanguageService(); - var actions = await service.GetRefactoringAsync(document, textSpan, SyntaxFormattingOptions.CreateProvider(context.Options), cancellationToken).ConfigureAwait(false); + var actions = await service.GetRefactoringAsync(document, textSpan, context.Options, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); } } diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs index 305af88573752..4123d170d3ec5 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.ChangeNamespace; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -70,11 +71,13 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var service = document.GetRequiredLanguageService(); - var solutionChangeAction = new ChangeNamespaceCodeAction( - state.TargetNamespace.Length == 0 - ? FeaturesResources.Change_to_global_namespace - : string.Format(FeaturesResources.Change_namespace_to_0, state.TargetNamespace), - token => service.ChangeNamespaceAsync(document, state.Container, state.TargetNamespace, CodeCleanupOptions.CreateProvider(context.Options), token)); + var title = state.TargetNamespace.Length == 0 + ? FeaturesResources.Change_to_global_namespace + : string.Format(FeaturesResources.Change_namespace_to_0, state.TargetNamespace); + var solutionChangeAction = CodeAction.Create( + title, + token => service.ChangeNamespaceAsync(document, state.Container, state.TargetNamespace, context.Options, token), + title); context.RegisterRefactoring(solutionChangeAction, textSpan); } @@ -93,13 +96,5 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte protected abstract Task TryGetApplicableInvocationNodeAsync(Document document, TextSpan span, CancellationToken cancellationToken); protected abstract string EscapeIdentifier(string identifier); - - private class ChangeNamespaceCodeAction : SolutionChangeAction - { - public ChangeNamespaceCodeAction(string title, Func> createChangedSolution) - : base(title, createChangedSolution, title) - { - } - } } } diff --git a/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.Fixing.cs b/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.Fixing.cs index e18e2724afafe..631ee701b3225 100644 --- a/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.Fixing.cs +++ b/src/Features/Core/Portable/CodeStyle/AbstractCodeStyleProvider.Fixing.cs @@ -33,11 +33,10 @@ private async Task RegisterCodeFixesAsync(CodeFixContext context) public abstract class CodeFixProvider : SyntaxEditorBasedCodeFixProvider { - public readonly TCodeStyleProvider _codeStyleProvider; + public readonly TCodeStyleProvider _codeStyleProvider = new(); protected CodeFixProvider() { - _codeStyleProvider = new TCodeStyleProvider(); FixableDiagnosticIds = ImmutableArray.Create(_codeStyleProvider._descriptorId); } diff --git a/src/Features/Core/Portable/Common/AbstractProjectExtensionProvider.cs b/src/Features/Core/Portable/Common/AbstractProjectExtensionProvider.cs new file mode 100644 index 0000000000000..627c767262460 --- /dev/null +++ b/src/Features/Core/Portable/Common/AbstractProjectExtensionProvider.cs @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis +{ + internal abstract class AbstractProjectExtensionProvider + where TProvider : AbstractProjectExtensionProvider, new() + where TExportAttribute : Attribute + where TExtension : class + { + // Following CWTs are used to cache completion providers from projects' references, + // so we can avoid the slow path unless there's any change to the references. + private static readonly ConditionalWeakTable, StrongBox>> s_referencesToExtensionsMap = new(); + private static readonly ConditionalWeakTable s_referenceToProviderMap = new(); + + private AnalyzerReference Reference { get; init; } = null!; + private ImmutableDictionary> _extensionsPerLanguage = ImmutableDictionary>.Empty; + + protected abstract bool SupportsLanguage(TExportAttribute exportAttribute, string language); + protected abstract bool TryGetExtensionsFromReference(AnalyzerReference reference, out ImmutableArray extensions); + + public static ImmutableArray GetExtensions(Project? project) + { + if (project is null) + return ImmutableArray.Empty; + + if (s_referencesToExtensionsMap.TryGetValue(project.AnalyzerReferences, out var providers)) + return providers.Value; + + return GetExtensionsSlow(project); + + ImmutableArray GetExtensionsSlow(Project project) + => s_referencesToExtensionsMap.GetValue(project.AnalyzerReferences, _ => new(ComputeExtensions(project))).Value; + + ImmutableArray ComputeExtensions(Project project) + { + using var _ = ArrayBuilder.GetInstance(out var builder); + foreach (var reference in project.AnalyzerReferences) + { + var provider = s_referenceToProviderMap.GetValue( + reference, static reference => new TProvider() { Reference = reference }); + foreach (var extension in provider.GetExtensions(project.Language)) + builder.Add(extension); + } + + return builder.ToImmutable(); + } + } + + private ImmutableArray GetExtensions(string language) + => ImmutableInterlocked.GetOrAdd(ref _extensionsPerLanguage, language, (language, provider) => provider.CreateExtensions(language), this); + + private ImmutableArray CreateExtensions(string language) + { + // check whether the analyzer reference knows how to return extensions directly. + if (TryGetExtensionsFromReference(this.Reference, out var extensions)) + return extensions; + + // otherwise, see whether we can pick it up from reference itself + if (this.Reference is not AnalyzerFileReference analyzerFileReference) + return ImmutableArray.Empty; + + using var _ = ArrayBuilder.GetInstance(out var builder); + + try + { + var analyzerAssembly = analyzerFileReference.GetAssembly(); + var typeInfos = analyzerAssembly.DefinedTypes; + + foreach (var typeInfo in typeInfos) + { + if (typeInfo.IsSubclassOf(typeof(TExtension))) + { + try + { + var attribute = typeInfo.GetCustomAttribute(); + if (attribute is not null && SupportsLanguage(attribute, language)) + { + builder.AddIfNotNull((TExtension?)Activator.CreateInstance(typeInfo.AsType())); + } + } + catch + { + } + } + } + } + catch + { + // REVIEW: is the below message right? + // NOTE: We could report "unable to load analyzer" exception here but it should have been already reported by DiagnosticService. + } + + return builder.ToImmutable(); + } + } +} diff --git a/src/Features/Core/Portable/Common/AbstractProjectExtensionProvider`2.cs b/src/Features/Core/Portable/Common/AbstractProjectExtensionProvider`2.cs deleted file mode 100644 index a3418e6ed2053..0000000000000 --- a/src/Features/Core/Portable/Common/AbstractProjectExtensionProvider`2.cs +++ /dev/null @@ -1,84 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// 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.Collections.Immutable; -using System.Reflection; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.PooledObjects; - -namespace Microsoft.CodeAnalysis -{ - internal abstract class AbstractProjectExtensionProvider - where TExportAttribute : Attribute - { - private readonly AnalyzerReference _reference; - private ImmutableDictionary> _extensionsPerLanguage; - - public AbstractProjectExtensionProvider(AnalyzerReference reference) - { - _reference = reference; - _extensionsPerLanguage = ImmutableDictionary>.Empty; - } - - protected abstract bool SupportsLanguage(TExportAttribute exportAttribute, string language); - - protected abstract bool TryGetExtensionsFromReference(AnalyzerReference reference, out ImmutableArray extensions); - - public ImmutableArray GetExtensions(string language) - { - return ImmutableInterlocked.GetOrAdd(ref _extensionsPerLanguage, language, (language, provider) => provider.CreateExtensions(language), this); - } - - private ImmutableArray CreateExtensions(string language) - { - // check whether the analyzer reference knows how to return extensions directly. - if (TryGetExtensionsFromReference(_reference, out var extensions)) - { - return extensions; - } - - // otherwise, see whether we can pick it up from reference itself - if (_reference is not AnalyzerFileReference analyzerFileReference) - { - return ImmutableArray.Empty; - } - - using var _ = ArrayBuilder.GetInstance(out var builder); - - try - { - var analyzerAssembly = analyzerFileReference.GetAssembly(); - var typeInfos = analyzerAssembly.DefinedTypes; - - foreach (var typeInfo in typeInfos) - { - if (typeInfo.IsSubclassOf(typeof(TExtension))) - { - try - { - var attribute = typeInfo.GetCustomAttribute(); - if (attribute is object && SupportsLanguage(attribute, language)) - { - builder.Add((TExtension)Activator.CreateInstance(typeInfo.AsType())); - } - } - catch - { - } - } - } - } - catch - { - // REVIEW: is the below message right? - // NOTE: We could report "unable to load analyzer" exception here but it should have been already reported by DiagnosticService. - } - - return builder.ToImmutable(); - } - } -} diff --git a/src/Features/Core/Portable/Completion/CompletionContext.cs b/src/Features/Core/Portable/Completion/CompletionContext.cs index c7f64e56717a0..64705e6744826 100644 --- a/src/Features/Core/Portable/Completion/CompletionContext.cs +++ b/src/Features/Core/Portable/Completion/CompletionContext.cs @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.Completion /// public sealed class CompletionContext { - private readonly List _items; + private readonly List _items = new(); private CompletionItem? _suggestionModeItem; private bool _isExclusive; @@ -141,7 +141,6 @@ internal CompletionContext( Trigger = trigger; CompletionOptions = options; CancellationToken = cancellationToken; - _items = new List(); #pragma warning disable RS0030 // Do not used banned APIs Options = OptionValueSet.Empty; diff --git a/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.ProviderManager.cs b/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.ProviderManager.cs index 2fe6bf7ef83d4..bc428492d56e4 100644 --- a/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.ProviderManager.cs +++ b/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.ProviderManager.cs @@ -27,14 +27,6 @@ private sealed class ProviderManager : IEqualityComparer _nameToProvider = new(); private readonly Dictionary, ImmutableArray> _rolesToProviders; - // Following CWTs are used to cache completion providers from projects' references, - // so we can avoid the slow path unless there's any change to the references. - private readonly ConditionalWeakTable, StrongBox>> _projectCompletionProvidersMap = new(); - private readonly ConditionalWeakTable _analyzerReferenceToCompletionProvidersMap = new(); - - private readonly ConditionalWeakTable.CreateValueCallback _createProjectCompletionProvidersProvider - = new(r => new ProjectCompletionProvider(r)); - private readonly Func, ImmutableArray> _createRoleProviders; private readonly Func _getProviderByName; @@ -116,46 +108,15 @@ public ConcatImmutableArray GetFilteredProviders( return allCompletionProviders.ConcatFast(projectCompletionProviders); } - private ImmutableArray GetProjectCompletionProviders(Project? project) + public static ImmutableArray GetProjectCompletionProviders(Project? project) { - if (project is null) - { - return ImmutableArray.Empty; - } - - if (project is null || project.Solution.Workspace.Kind == WorkspaceKind.Interactive) + if (project?.Solution.Workspace.Kind == WorkspaceKind.Interactive) { // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict completions in Interactive return ImmutableArray.Empty; } - if (_projectCompletionProvidersMap.TryGetValue(project.AnalyzerReferences, out var completionProviders)) - { - return completionProviders.Value; - } - - return GetProjectCompletionProvidersSlow(project); - - // Local functions - ImmutableArray GetProjectCompletionProvidersSlow(Project project) - { - return _projectCompletionProvidersMap.GetValue(project.AnalyzerReferences, pId => new(ComputeProjectCompletionProviders(project))).Value; - } - - ImmutableArray ComputeProjectCompletionProviders(Project project) - { - using var _ = ArrayBuilder.GetInstance(out var builder); - foreach (var reference in project.AnalyzerReferences) - { - var projectCompletionProvider = _analyzerReferenceToCompletionProvidersMap.GetValue(reference, _createProjectCompletionProvidersProvider); - foreach (var completionProvider in projectCompletionProvider.GetExtensions(project.Language)) - { - builder.Add(completionProvider); - } - } - - return builder.ToImmutable(); - } + return ProjectCompletionProvider.GetExtensions(project); } private ImmutableArray FilterProviders( @@ -254,13 +215,8 @@ int IEqualityComparer>.GetHashCode([DisallowNull] Immut } private sealed class ProjectCompletionProvider - : AbstractProjectExtensionProvider + : AbstractProjectExtensionProvider { - public ProjectCompletionProvider(AnalyzerReference reference) - : base(reference) - { - } - protected override bool SupportsLanguage(ExportCompletionProviderAttribute exportAttribute, string language) { return exportAttribute.Language == null diff --git a/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs b/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs index a943c021ace2c..227add0b836d3 100644 --- a/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs +++ b/src/Features/Core/Portable/Completion/CompletionServiceWithProviders.cs @@ -62,6 +62,9 @@ protected virtual ImmutableArray GetBuiltInProviders() internal IEnumerable> GetImportedProviders() => _providerManager.GetImportedProviders(); + internal static ImmutableArray GetProjectCompletionProviders(Project? project) + => ProviderManager.GetProjectCompletionProviders(project); + protected ImmutableArray GetProviders(ImmutableHashSet? roles) => _providerManager.GetProviders(roles); diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs index e04543f5b9346..dbc458f414f01 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractMemberInsertingCompletionProvider.cs @@ -6,6 +6,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; @@ -35,7 +37,7 @@ public AbstractMemberInsertingCompletionProvider() public override async Task GetChangeAsync(Document document, CompletionItem item, char? commitKey = null, CancellationToken cancellationToken = default) { // TODO: pass fallback options: https://github.com/dotnet/roslyn/issues/60786 - var fallbackOptions = new CodeCleanupOptionsProvider(CodeCleanupOptions.GetDefaultAsync); + var fallbackOptions = CodeActionOptions.DefaultProvider; var newDocument = await DetermineNewDocumentAsync(document, item, fallbackOptions, cancellationToken).ConfigureAwait(false); var newText = await newDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); @@ -67,7 +69,11 @@ public override async Task GetChangeAsync(Document document, C return CompletionChange.Create(change, changesArray, newPosition, includesCommitCharacter: true); } - private async Task DetermineNewDocumentAsync(Document document, CompletionItem completionItem, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken) + private async Task DetermineNewDocumentAsync( + Document document, + CompletionItem completionItem, + CleanCodeGenerationOptionsProvider fallbackOptions, + CancellationToken cancellationToken) { var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); @@ -80,7 +86,7 @@ private async Task DetermineNewDocumentAsync(Document document, Comple var annotatedRoot = tree.GetRoot(cancellationToken).ReplaceToken(token, token.WithAdditionalAnnotations(_otherAnnotation)); document = document.WithSyntaxRoot(annotatedRoot); - var memberContainingDocument = await GenerateMemberAndUsingsAsync(document, completionItem, line, cancellationToken).ConfigureAwait(false); + var memberContainingDocument = await GenerateMemberAndUsingsAsync(document, completionItem, line, fallbackOptions, cancellationToken).ConfigureAwait(false); if (memberContainingDocument == null) { // Generating the new document failed because we somehow couldn't resolve @@ -111,6 +117,7 @@ private async Task DetermineNewDocumentAsync(Document document, Comple Document document, CompletionItem completionItem, TextLine line, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var codeGenService = document.GetRequiredLanguageService(); @@ -131,8 +138,11 @@ private async Task DetermineNewDocumentAsync(Document document, Comple } // CodeGenerationOptions containing before and after - var context = new CodeGenerationContext( - contextLocation: semanticModel.SyntaxTree.GetLocation(TextSpan.FromBounds(line.Start, line.Start))); + var context = new CodeGenerationSolutionContext( + document.Project.Solution, + new CodeGenerationContext( + contextLocation: semanticModel.SyntaxTree.GetLocation(TextSpan.FromBounds(line.Start, line.Start))), + fallbackOptions); var generatedMember = await GenerateMemberAsync(overriddenMember, containingType, document, completionItem, cancellationToken).ConfigureAwait(false); generatedMember = _annotation.AddAnnotationToSymbol(generatedMember); @@ -140,15 +150,15 @@ private async Task DetermineNewDocumentAsync(Document document, Comple Document? memberContainingDocument = null; if (generatedMember.Kind == SymbolKind.Method) { - memberContainingDocument = await codeGenService.AddMethodAsync(document.Project.Solution, containingType, (IMethodSymbol)generatedMember, context, cancellationToken).ConfigureAwait(false); + memberContainingDocument = await codeGenService.AddMethodAsync(context, containingType, (IMethodSymbol)generatedMember, cancellationToken).ConfigureAwait(false); } else if (generatedMember.Kind == SymbolKind.Property) { - memberContainingDocument = await codeGenService.AddPropertyAsync(document.Project.Solution, containingType, (IPropertySymbol)generatedMember, context, cancellationToken).ConfigureAwait(false); + memberContainingDocument = await codeGenService.AddPropertyAsync(context, containingType, (IPropertySymbol)generatedMember, cancellationToken).ConfigureAwait(false); } else if (generatedMember.Kind == SymbolKind.Event) { - memberContainingDocument = await codeGenService.AddEventAsync(document.Project.Solution, containingType, (IEventSymbol)generatedMember, context, cancellationToken).ConfigureAwait(false); + memberContainingDocument = await codeGenService.AddEventAsync(context, containingType, (IEventSymbol)generatedMember, cancellationToken).ConfigureAwait(false); } return memberContainingDocument; diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs index 985597a4819ae..3ca05a73c7984 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.SymbolComputer.cs @@ -31,7 +31,7 @@ private class SymbolComputer // This dictionary is used as cache among all projects and PE references. // The key is the receiver type as in the extension method declaration (symbol retrived from originating compilation). // The value indicates if we can reduce an extension method with this receiver type given receiver type. - private readonly ConcurrentDictionary _checkedReceiverTypes; + private readonly ConcurrentDictionary _checkedReceiverTypes = new(); public SymbolComputer( Document document, @@ -49,7 +49,6 @@ public SymbolComputer( var receiverTypeNames = GetReceiverTypeNames(receiverTypeSymbol); _receiverTypeNames = AddComplexTypes(receiverTypeNames); _cacheService = GetCacheService(document.Project); - _checkedReceiverTypes = new ConcurrentDictionary(); } public static async Task CreateAsync( diff --git a/src/Features/Core/Portable/ConflictMarkerResolution/AbstractConflictMarkerCodeFixProvider.cs b/src/Features/Core/Portable/ConflictMarkerResolution/AbstractConflictMarkerCodeFixProvider.cs index bcbbdbfee6a5c..cb645fd163608 100644 --- a/src/Features/Core/Portable/ConflictMarkerResolution/AbstractConflictMarkerCodeFixProvider.cs +++ b/src/Features/Core/Portable/ConflictMarkerResolution/AbstractConflictMarkerCodeFixProvider.cs @@ -212,17 +212,17 @@ private static void RegisterCodeFixes( var endPos = endLine.Start; context.RegisterCodeFix( - new MyCodeAction(takeTopText, + CodeAction.Create(takeTopText, c => TakeTopAsync(document, startPos, equalsPos, endPos, c), TakeTopEquivalenceKey), context.Diagnostics); context.RegisterCodeFix( - new MyCodeAction(takeBottomText, + CodeAction.Create(takeBottomText, c => TakeBottomAsync(document, startPos, equalsPos, endPos, c), TakeBottomEquivalenceKey), context.Diagnostics); context.RegisterCodeFix( - new MyCodeAction(FeaturesResources.Take_both, + CodeAction.Create(FeaturesResources.Take_both, c => TakeBothAsync(document, startPos, equalsPos, endPos, c), TakeBothEquivalenceKey), context.Diagnostics); @@ -357,13 +357,5 @@ TakeBottomEquivalenceKey or public override FixAllProvider GetFixAllProvider() => FixAllProvider.Create(async (context, document, diagnostics) => await this.FixAllAsync(document, diagnostics, context.CodeActionEquivalenceKey, context.CancellationToken).ConfigureAwait(false)); - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument, string equivalenceKey) - : base(title, createChangedDocument, equivalenceKey) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs index 94a1822ea3e89..420a64550ab7c 100644 --- a/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAnonymousType/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; @@ -61,19 +62,23 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var syntaxFacts = document.GetRequiredLanguageService(); if (syntaxFacts.SupportsRecord(anonymousObject.SyntaxTree.Options)) { - context.RegisterRefactoring(new MyCodeAction( - FeaturesResources.Convert_to_record, - c => ConvertAsync(document, textSpan, isRecord: true, c)), + context.RegisterRefactoring( + CodeAction.Create( + FeaturesResources.Convert_to_record, + c => ConvertAsync(document, textSpan, context.Options, isRecord: true, c), + nameof(FeaturesResources.Convert_to_record)), anonymousObject.Span); } - context.RegisterRefactoring(new MyCodeAction( + context.RegisterRefactoring( + CodeAction.Create( FeaturesResources.Convert_to_class, - c => ConvertAsync(document, textSpan, isRecord: false, c)), + c => ConvertAsync(document, textSpan, context.Options, isRecord: false, c), + nameof(FeaturesResources.Convert_to_class)), anonymousObject.Span); } - private async Task ConvertAsync(Document document, TextSpan span, bool isRecord, CancellationToken cancellationToken) + private async Task ConvertAsync(Document document, TextSpan span, CodeActionOptionsProvider fallbackOptions, bool isRecord, CancellationToken cancellationToken) { var (anonymousObject, anonymousType) = await TryGetAnonymousObjectAsync(document, span, cancellationToken).ConfigureAwait(false); @@ -126,16 +131,15 @@ await ReplaceMatchingAnonymousTypesAsync( sortMembers: false, autoInsertionLocation: false); - // fallback options: https://github.com/dotnet/roslyn/issues/60794 - var codeGenOptions = await CodeGenerationOptions.FromDocumentAsync(context, document, cancellationToken).ConfigureAwait(false); - var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var codeGenOptions = await document.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); + var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); var codeGenService = document.GetRequiredLanguageService(); // Then, actually insert the new class in the appropriate container. var container = anonymousObject.GetAncestor() ?? root; editor.ReplaceNode(container, (currentContainer, _) => - codeGenService.AddNamedType(currentContainer, namedTypeSymbol, codeGenOptions, cancellationToken)); + codeGenService.AddNamedType(currentContainer, namedTypeSymbol, codeGenOptions.GetInfo(context, document.Project), cancellationToken)); var updatedDocument = document.WithSyntaxRoot(editor.GetChangedRoot()); @@ -400,13 +404,5 @@ private static IMethodSymbol CreateClassConstructor( return constructor; } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs index 8e626eb88a81d..e62b1a4ff2da6 100644 --- a/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAutoPropertyToFullProperty/AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; @@ -16,17 +17,17 @@ namespace Microsoft.CodeAnalysis.ConvertAutoPropertyToFullProperty { - internal abstract class AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider : CodeRefactoringProvider + internal abstract class AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider : CodeRefactoringProvider where TPropertyDeclarationNode : SyntaxNode where TTypeDeclarationNode : SyntaxNode - where TCodeGenerationPreferences : CodeGenerationPreferences + where TCodeGenerationContextInfo : CodeGenerationContextInfo { internal abstract Task GetFieldNameAsync(Document document, IPropertySymbol propertySymbol, CancellationToken cancellationToken); internal abstract (SyntaxNode newGetAccessor, SyntaxNode newSetAccessor) GetNewAccessors( - TCodeGenerationPreferences preferences, SyntaxNode property, string fieldName, SyntaxGenerator generator); + TCodeGenerationContextInfo info, SyntaxNode property, string fieldName, SyntaxGenerator generator); internal abstract SyntaxNode GetPropertyWithoutInitializer(SyntaxNode property); internal abstract SyntaxNode GetInitializerValue(SyntaxNode property); - internal abstract SyntaxNode ConvertPropertyToExpressionBodyIfDesired(TCodeGenerationPreferences preferences, SyntaxNode fullProperty); + internal abstract SyntaxNode ConvertPropertyToExpressionBodyIfDesired(TCodeGenerationContextInfo info, SyntaxNode fullProperty); internal abstract SyntaxNode GetTypeBlock(SyntaxNode syntaxNode); public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) @@ -53,8 +54,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } context.RegisterRefactoring( - new ConvertAutoPropertyToFullPropertyCodeAction( - c => ExpandToFullPropertyAsync(document, property, propertySymbol, root, c)), + CodeAction.Create( + FeaturesResources.Convert_to_full_property, + c => ExpandToFullPropertyAsync(document, property, propertySymbol, root, context.Options, c), + nameof(FeaturesResources.Convert_to_full_property)), property.Span); } @@ -81,6 +84,7 @@ private async Task ExpandToFullPropertyAsync( SyntaxNode property, IPropertySymbol propertySymbol, SyntaxNode root, + CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { Contract.ThrowIfNull(document.DocumentState.ParseOptions); @@ -89,12 +93,13 @@ private async Task ExpandToFullPropertyAsync( var codeGenerator = document.GetRequiredLanguageService(); var services = document.Project.Solution.Workspace.Services; - var preferences = (TCodeGenerationPreferences)await CodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var options = await document.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); + var info = (TCodeGenerationContextInfo)options.GetInfo(CodeGenerationContext.Default, document.Project); // Create full property. If the auto property had an initial value // we need to remove it and later add it to the backing field var fieldName = await GetFieldNameAsync(document, propertySymbol, cancellationToken).ConfigureAwait(false); - var (newGetAccessor, newSetAccessor) = GetNewAccessors(preferences, property, fieldName, generator); + var (newGetAccessor, newSetAccessor) = GetNewAccessors(info, property, fieldName, generator); var fullProperty = generator .WithAccessorDeclarations( GetPropertyWithoutInitializer(property), @@ -102,7 +107,7 @@ private async Task ExpandToFullPropertyAsync( ? new SyntaxNode[] { newGetAccessor } : new SyntaxNode[] { newGetAccessor, newSetAccessor }) .WithLeadingTrivia(property.GetLeadingTrivia()); - fullProperty = ConvertPropertyToExpressionBodyIfDesired(preferences, fullProperty); + fullProperty = ConvertPropertyToExpressionBodyIfDesired(info, fullProperty); var editor = new SyntaxEditor(root, services); editor.ReplaceNode(property, fullProperty.WithAdditionalAnnotations(Formatter.Annotation)); @@ -113,7 +118,6 @@ private async Task ExpandToFullPropertyAsync( propertySymbol.Type, fieldName, initializer: GetInitializerValue(property)); - var codeGenOptions = preferences.GetOptions(CodeGenerationContext.Default); var typeDeclaration = propertySymbol.ContainingType.DeclaringSyntaxReferences; foreach (var td in typeDeclaration) { @@ -121,7 +125,7 @@ private async Task ExpandToFullPropertyAsync( if (property.Ancestors().Contains(block)) { editor.ReplaceNode(block, (currentTypeDecl, _) - => codeGenerator.AddField(currentTypeDecl, newField, codeGenOptions, cancellationToken) + => codeGenerator.AddField(currentTypeDecl, newField, info, cancellationToken) .WithAdditionalAnnotations(Formatter.Annotation)); } } @@ -129,13 +133,5 @@ private async Task ExpandToFullPropertyAsync( var newRoot = editor.GetChangedRoot(); return document.WithSyntaxRoot(newRoot); } - - private class ConvertAutoPropertyToFullPropertyCodeAction : CodeAction.DocumentChangeAction - { - public ConvertAutoPropertyToFullPropertyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Convert_to_full_property, createChangedDocument, nameof(FeaturesResources.Convert_to_full_property)) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertCast/AbstractConvertCastCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertCast/AbstractConvertCastCodeRefactoringProvider.cs index 1b54800fb112a..98179415633bb 100644 --- a/src/Features/Core/Portable/ConvertCast/AbstractConvertCastCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertCast/AbstractConvertCastCodeRefactoringProvider.cs @@ -50,10 +50,12 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex var type = semanticModel.GetTypeInfo(typeNode, cancellationToken).Type; if (type is { TypeKind: not TypeKind.Error, IsReferenceType: true }) { + var title = GetTitle(); context.RegisterRefactoring( - new MyCodeAction( - GetTitle(), - c => ConvertAsync(document, from, cancellationToken)), + CodeAction.Create( + title, + c => ConvertAsync(document, from, cancellationToken), + title), from.Span); } } @@ -67,13 +69,5 @@ protected async Task ConvertAsync( var newRoot = root.ReplaceNode(from, ConvertExpression(from)); return document.WithSyntaxRoot(newRoot); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs index fc9cde67e6c2a..53ce1b98fb5d7 100644 --- a/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertForEachToFor/AbstractConvertForEachToForCodeRefactoringProvider.cs @@ -76,9 +76,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } context.RegisterRefactoring( - new ForEachToForCodeAction( + CodeAction.Create( Title, - c => ConvertForeachToForAsync(document, foreachInfo, c)), + c => ConvertForeachToForAsync(document, foreachInfo, c), + Title), foreachStatement.Span); } @@ -459,14 +460,5 @@ public ForEachInfo( public bool RequireCollectionStatement { get; } public TForEachStatement ForEachStatement { get; } } - - private class ForEachToForCodeAction : CodeAction.DocumentChangeAction - { - public ForEachToForCodeAction( - string title, - Func> createChangedDocument) : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertForToForEach/AbstractConvertForToForEachCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertForToForEach/AbstractConvertForToForEachCodeRefactoringProvider.cs index 79b78d79d3c06..84360293befc9 100644 --- a/src/Features/Core/Portable/ConvertForToForEach/AbstractConvertForToForEachCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertForToForEach/AbstractConvertForToForEachCodeRefactoringProvider.cs @@ -146,11 +146,14 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } // Looks good. We can convert this. + var title = GetTitle(); context.RegisterRefactoring( - new MyCodeAction(GetTitle(), + CodeAction.Create( + title, c => ConvertForToForEachAsync( document, forStatement, iterationVariable, collectionExpression, - containingType, collectionType.Type, iterationType, c)), + containingType, collectionType.Type, iterationType, c), + title), forStatement.Span); return; @@ -494,13 +497,5 @@ private static bool IsViableIndexer(IPropertySymbol property) => property.IsIndexer && property.Parameters.Length == 1 && property.Parameters[0].Type?.SpecialType == SpecialType.System_Int32; - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs index 56b6cbd0b2c75..13f9da40d2ee7 100644 --- a/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertIfToSwitch/AbstractConvertIfToSwitchCodeRefactoringProvider.cs @@ -78,7 +78,8 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex } context.RegisterRefactoring( - new MyCodeAction(GetTitle(forSwitchExpression: false), + CodeAction.Create( + GetTitle(forSwitchExpression: false), c => UpdateDocumentAsync(document, target, ifStatement, sections, analyzer.Features, convertToSwitchExpression: false, c), "SwitchStatement"), ifStatement.Span); @@ -87,7 +88,8 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex CanConvertToSwitchExpression(analyzer.Supports(Feature.OrPattern), sections)) { context.RegisterRefactoring( - new MyCodeAction(GetTitle(forSwitchExpression: true), + CodeAction.Create( + GetTitle(forSwitchExpression: true), c => UpdateDocumentAsync(document, target, ifStatement, sections, analyzer.Features, convertToSwitchExpression: true, c), "SwitchExpression"), ifStatement.Span); @@ -150,13 +152,5 @@ static bool CanConvertSectionForSwitchExpression(bool supportsOrPattern, Analyze return supportsOrPattern && section.Labels.All(label => label.Guards.IsDefaultOrEmpty); } } - - private sealed class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument, string equivalenceKey) - : base(title, createChangedDocument, equivalenceKey) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertLinq/AbstractConvertLinqQueryToForEachProvider.cs b/src/Features/Core/Portable/ConvertLinq/AbstractConvertLinqQueryToForEachProvider.cs index 65e19fa3c2312..4f7868ccc3cd2 100644 --- a/src/Features/Core/Portable/ConvertLinq/AbstractConvertLinqQueryToForEachProvider.cs +++ b/src/Features/Core/Portable/ConvertLinq/AbstractConvertLinqQueryToForEachProvider.cs @@ -45,9 +45,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (TryConvert(queryExpression, semanticModel, semanticFacts, cancellationToken, out var documentUpdateInfo)) { context.RegisterRefactoring( - new MyCodeAction( + CodeAction.Create( Title, - c => Task.FromResult(document.WithSyntaxRoot(documentUpdateInfo.UpdateRoot(root)))), + c => Task.FromResult(document.WithSyntaxRoot(documentUpdateInfo.UpdateRoot(root))), + Title), queryExpression.Span); } } @@ -88,13 +89,5 @@ public SyntaxNode UpdateRoot(SyntaxNode root) } } } - - protected sealed class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs b/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs index a670cc0e6be90..f065ae79e523c 100644 --- a/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs +++ b/src/Features/Core/Portable/ConvertLinq/ConvertForEachToLinqQuery/AbstractConvertForEachToLinqQueryProvider.cs @@ -113,9 +113,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // select n1 + n2 // context.RegisterRefactoring( - new ForEachToLinqQueryCodeAction( + CodeAction.Create( FeaturesResources.Convert_to_linq, - c => ApplyConversionAsync(queryConverter, document, convertToQuery: true, c)), + c => ApplyConversionAsync(queryConverter, document, convertToQuery: true, c), + nameof(FeaturesResources.Convert_to_linq)), forEachStatement.Span); // Offer refactoring to convert foreach to LINQ invocation expression. For example: @@ -135,9 +136,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (TryBuildConverter(forEachStatement, semanticModel, convertLocalDeclarations: false, cancellationToken, out var linqConverter)) { context.RegisterRefactoring( - new ForEachToLinqQueryCodeAction( + CodeAction.Create( FeaturesResources.Convert_to_linq_call_form, - c => ApplyConversionAsync(linqConverter, document, convertToQuery: false, c)), + c => ApplyConversionAsync(linqConverter, document, convertToQuery: false, c), + nameof(FeaturesResources.Convert_to_linq_call_form)), forEachStatement.Span); } } @@ -183,13 +185,5 @@ private bool TryBuildConverter( converter = null; return false; } - - private class ForEachToLinqQueryCodeAction : CodeAction.DocumentChangeAction - { - public ForEachToLinqQueryCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertNumericLiteral/AbstractConvertNumericLiteralCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertNumericLiteral/AbstractConvertNumericLiteralCodeRefactoringProvider.cs index e23aaa5ef077e..7b0e927686e1c 100644 --- a/src/Features/Core/Portable/ConvertNumericLiteral/AbstractConvertNumericLiteralCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertNumericLiteral/AbstractConvertNumericLiteralCodeRefactoringProvider.cs @@ -105,7 +105,7 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex void RegisterRefactoringWithResult(string text, string title) { context.RegisterRefactoring( - new MyCodeAction(title, c => ReplaceTokenAsync(document, root, numericToken, value, text, suffix)), + CodeAction.Create(title, c => ReplaceTokenAsync(document, root, numericToken, value, text, suffix), title), numericToken.Span); } } @@ -168,12 +168,5 @@ private static bool IsIntegral(SpecialType specialType) } private enum NumericKind { Unknown, Decimal, Binary, Hexadecimal } - - private sealed class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertConcatenationToInterpolatedStringRefactoringProvider.cs b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertConcatenationToInterpolatedStringRefactoringProvider.cs index f716c84f7ddee..03165d2a219d1 100644 --- a/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertConcatenationToInterpolatedStringRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertConcatenationToInterpolatedStringRefactoringProvider.cs @@ -106,8 +106,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var interpolatedString = CreateInterpolatedString(document, isVerbatimStringLiteral, pieces); context.RegisterRefactoring( - new MyCodeAction( - _ => UpdateDocumentAsync(document, root, top, interpolatedString)), + CodeAction.Create( + FeaturesResources.Convert_to_interpolated_string, + _ => UpdateDocumentAsync(document, root, top, interpolatedString), + nameof(FeaturesResources.Convert_to_interpolated_string)), top.Span); } @@ -250,13 +252,5 @@ private static bool IsStringConcat( (method.MetadataName == WellKnownMemberNames.AdditionOperatorName || method.MetadataName == WellKnownMemberNames.ConcatenateOperatorName); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Convert_to_interpolated_string, createChangedDocument, nameof(FeaturesResources.Convert_to_interpolated_string)) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs index 14cb10e4ae3fe..bc0867ad5a4b2 100644 --- a/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertToInterpolatedString/AbstractConvertPlaceholderToInterpolatedStringRefactoringProvider.cs @@ -89,8 +89,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var shouldReplaceInvocation = stringInvocationMethods.Contains(invocationSymbol); context.RegisterRefactoring( - new ConvertToInterpolatedStringCodeAction( - c => CreateInterpolatedStringAsync(invocationSyntax, document, syntaxFactsService, shouldReplaceInvocation, c)), + CodeAction.Create( + FeaturesResources.Convert_to_interpolated_string, + c => CreateInterpolatedStringAsync(invocationSyntax, document, syntaxFactsService, shouldReplaceInvocation, c), + nameof(FeaturesResources.Convert_to_interpolated_string)), invocationSyntax.Span); // Local Functions @@ -350,14 +352,6 @@ private static bool IsArgumentListNotPassingArrayToParams( return true; } - private class ConvertToInterpolatedStringCodeAction : CodeAction.DocumentChangeAction - { - public ConvertToInterpolatedStringCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Convert_to_interpolated_string, createChangedDocument, nameof(FeaturesResources.Convert_to_interpolated_string)) - { - } - } - private static class StringFormatArguments { public const string FormatArgumentName = "format"; diff --git a/src/Features/Core/Portable/ConvertToInterpolatedString/ConvertRegularStringToInterpolatedStringRefactoringProvider.cs b/src/Features/Core/Portable/ConvertToInterpolatedString/ConvertRegularStringToInterpolatedStringRefactoringProvider.cs index d90e74f4cd538..94c9847d25dae 100644 --- a/src/Features/Core/Portable/ConvertToInterpolatedString/ConvertRegularStringToInterpolatedStringRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertToInterpolatedString/ConvertRegularStringToInterpolatedStringRefactoringProvider.cs @@ -73,7 +73,11 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } context.RegisterRefactoring( - new MyCodeAction(_ => UpdateDocumentAsync(document, root, token)), + CodeAction.CreateWithPriority( + CodeActionPriority.Low, + FeaturesResources.Convert_to_interpolated_string, + _ => UpdateDocumentAsync(document, root, token), + nameof(FeaturesResources.Convert_to_interpolated_string)), literalExpression.Span); } @@ -109,15 +113,5 @@ private static Task UpdateDocumentAsync(Document document, SyntaxNode literalExpression, CreateInterpolatedString(document, literalExpression, syntaxFacts.IsVerbatimStringLiteral(token))))); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - internal override CodeActionPriority Priority => CodeActionPriority.Low; - - public MyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Convert_to_interpolated_string, createChangedDocument, nameof(FeaturesResources.Convert_to_interpolated_string)) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs index 0c52371a02d84..19b4bec1073bf 100644 --- a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; @@ -86,12 +87,11 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte .ToImmutableArray(); var syntaxTree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var fallbackOptions = CodeCleanupOptions.CreateProvider(context.Options); var syntaxFacts = document.GetRequiredLanguageService(); if (syntaxFacts.SupportsRecordStruct(syntaxTree.Options)) { - var recordChildActions = CreateChildActions(document, textSpan, tupleExprOrTypeNode, fields, capturedTypeParameters, fallbackOptions, isRecord: true); + var recordChildActions = CreateChildActions(document, textSpan, tupleExprOrTypeNode, fields, capturedTypeParameters, context.Options, isRecord: true); if (recordChildActions.Length > 0) { context.RegisterRefactoring( @@ -103,7 +103,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } } - var childActions = CreateChildActions(document, textSpan, tupleExprOrTypeNode, fields, capturedTypeParameters, fallbackOptions, isRecord: false); + var childActions = CreateChildActions(document, textSpan, tupleExprOrTypeNode, fields, capturedTypeParameters, context.Options, isRecord: false); if (childActions.Length > 0) { context.RegisterRefactoring( @@ -122,7 +122,7 @@ ImmutableArray CreateChildActions( SyntaxNode tupleExprOrTypeNode, ImmutableArray fields, ImmutableArray capturedTypeParameters, - CodeCleanupOptionsProvider fallbackOptions, + CleanCodeGenerationOptionsProvider fallbackOptions, bool isRecord) { using var scopes = TemporaryArray.Empty; @@ -169,8 +169,8 @@ ImmutableArray CreateChildActions( return tupleExprOrTypeNode.FirstAncestorOrSelf((node, syntaxFacts) => syntaxFacts.IsMethodLevelMember(node), syntaxFacts); } - private CodeAction CreateAction(Document document, TextSpan span, Scope scope, CodeCleanupOptionsProvider fallbackOptions, bool isRecord) - => new MyCodeAction(GetTitle(scope), c => ConvertToStructAsync(document, span, scope, fallbackOptions, isRecord, c), scope.ToString()); + private CodeAction CreateAction(Document document, TextSpan span, Scope scope, CleanCodeGenerationOptionsProvider fallbackOptions, bool isRecord) + => CodeAction.Create(GetTitle(scope), c => ConvertToStructAsync(document, span, scope, fallbackOptions, isRecord, c), scope.ToString()); private static string GetTitle(Scope scope) => scope switch @@ -205,7 +205,7 @@ await document.TryGetRelevantNodeAsync(span, cancellationToken } public async Task ConvertToStructAsync( - Document document, TextSpan span, Scope scope, CodeCleanupOptionsProvider fallbackOptions, bool isRecord, CancellationToken cancellationToken) + Document document, TextSpan span, Scope scope, CleanCodeGenerationOptionsProvider fallbackOptions, bool isRecord, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -218,7 +218,7 @@ public async Task ConvertToStructAsync( var result = await client.TryInvokeAsync( solution, (service, solutionInfo, callbackId, cancellationToken) => service.ConvertToStructAsync(solutionInfo, callbackId, document.Id, span, scope, isRecord, cancellationToken), - callbackTarget: new RemoteOptionsProvider(solution.Workspace.Services, fallbackOptions.Invoke), + callbackTarget: new RemoteOptionsProvider(solution.Workspace.Services, fallbackOptions), cancellationToken).ConfigureAwait(false); if (!result.HasValue) @@ -252,7 +252,7 @@ private static async Task AddRenameTokenAsync( } private async Task ConvertToStructInCurrentProcessAsync( - Document document, TextSpan span, Scope scope, CodeCleanupOptionsProvider fallbackOptions, bool isRecord, CancellationToken cancellationToken) + Document document, TextSpan span, Scope scope, CleanCodeGenerationOptionsProvider fallbackOptions, bool isRecord, CancellationToken cancellationToken) { var (tupleExprOrTypeNode, tupleType) = await TryGetTupleInfoAsync( document, span, cancellationToken).ConfigureAwait(false); @@ -305,7 +305,7 @@ await ReplaceExpressionAndTypesInScopeAsync( await GenerateStructIntoContainingNamespaceAsync( document, tupleExprOrTypeNode, namedTypeSymbol, - documentToEditorMap, cancellationToken).ConfigureAwait(false); + documentToEditorMap, fallbackOptions, cancellationToken).ConfigureAwait(false); var updatedSolution = await ApplyChangesAsync( document, documentToEditorMap, fallbackOptions, cancellationToken).ConfigureAwait(false); @@ -543,7 +543,8 @@ private static ImmutableArray GetDocumentsToUpdateForContainin private static async Task GenerateStructIntoContainingNamespaceAsync( Document document, SyntaxNode tupleExprOrTypeNode, INamedTypeSymbol namedTypeSymbol, - Dictionary documentToEditorMap, CancellationToken cancellationToken) + Dictionary documentToEditorMap, + CleanCodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -565,11 +566,12 @@ private static async Task GenerateStructIntoContainingNamespaceAsync( sortMembers: false, autoInsertionLocation: false); - var options = await CodeGenerationOptions.FromDocumentAsync(context, document, cancellationToken).ConfigureAwait(false); + var options = await document.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); + var info = options.GetInfo(context, document.Project); // Then, actually insert the new class in the appropriate container. editor.ReplaceNode(container, (currentContainer, _) => - codeGenService.AddNamedType(currentContainer, namedTypeSymbol, options, cancellationToken)); + codeGenService.AddNamedType(currentContainer, namedTypeSymbol, info, cancellationToken)); } private static async Task ApplyChangesAsync( @@ -939,16 +941,5 @@ private static IMethodSymbol CreateConstructor( return constructor; } - - private class MyCodeAction : CodeAction.SolutionChangeAction - { - public MyCodeAction( - string title, - Func> createChangedSolution, - string equivalenceKey) - : base(title, createChangedSolution, equivalenceKey) - { - } - } } } diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/IConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/IConvertTupleToStructCodeRefactoringProvider.cs index 44fd95e5cc1d3..9b1b77056b8d3 100644 --- a/src/Features/Core/Portable/ConvertTupleToStruct/IConvertTupleToStructCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertTupleToStruct/IConvertTupleToStructCodeRefactoringProvider.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; @@ -14,6 +15,6 @@ namespace Microsoft.CodeAnalysis.ConvertTupleToStruct internal interface IConvertTupleToStructCodeRefactoringProvider : ILanguageService { Task ConvertToStructAsync( - Document document, TextSpan span, Scope scope, CodeCleanupOptionsProvider fallbackOptions, bool isRecord, CancellationToken cancellationToken); + Document document, TextSpan span, Scope scope, CleanCodeGenerationOptionsProvider fallbackOptions, bool isRecord, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringService.cs b/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringService.cs index 7339e72bfc018..8176de886a957 100644 --- a/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringService.cs +++ b/src/Features/Core/Portable/ConvertTupleToStruct/IRemoteConvertTupleToStructCodeRefactoringService.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Remote; @@ -21,7 +22,7 @@ internal interface IRemoteConvertTupleToStructCodeRefactoringService // TODO https://github.com/microsoft/vs-streamjsonrpc/issues/789 internal interface ICallback // : IRemoteOptionsCallback { - ValueTask GetOptionsAsync(RemoteServiceCallbackId callbackId, string language, CancellationToken cancellationToken); + ValueTask GetOptionsAsync(RemoteServiceCallbackId callbackId, string language, CancellationToken cancellationToken); } ValueTask ConvertToStructAsync( @@ -43,8 +44,8 @@ public RemoteConvertTupleToStructCodeRefactoringServiceCallbackDispatcher() { } - public ValueTask GetOptionsAsync(RemoteServiceCallbackId callbackId, string language, CancellationToken cancellationToken) - => ((RemoteOptionsProvider)GetCallback(callbackId)).GetOptionsAsync(language, cancellationToken); + public ValueTask GetOptionsAsync(RemoteServiceCallbackId callbackId, string language, CancellationToken cancellationToken) + => ((RemoteOptionsProvider)GetCallback(callbackId)).GetOptionsAsync(language, cancellationToken); } [DataContract] diff --git a/src/Features/Core/Portable/DocumentIdSpan.cs b/src/Features/Core/Portable/DocumentIdSpan.cs index ec3b578c5cb82..b6a55cca76806 100644 --- a/src/Features/Core/Portable/DocumentIdSpan.cs +++ b/src/Features/Core/Portable/DocumentIdSpan.cs @@ -2,6 +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. +using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Text; @@ -13,24 +14,27 @@ namespace Microsoft.CodeAnalysis /// pointing at a particular location in a but do not want to root a potentially /// very stale snapshot that may keep around a lot of memory in a host. /// + [DataContract] internal readonly struct DocumentIdSpan { - private readonly Workspace _workspace; - private readonly DocumentId _documentId; + [DataMember(Order = 0)] + public readonly DocumentId DocumentId; + [DataMember(Order = 1)] public readonly TextSpan SourceSpan; - public DocumentIdSpan(DocumentSpan documentSpan) + public DocumentIdSpan(DocumentId documentId, TextSpan sourceSpan) { - _workspace = documentSpan.Document.Project.Solution.Workspace; - _documentId = documentSpan.Document.Id; - SourceSpan = documentSpan.SourceSpan; + DocumentId = documentId; + SourceSpan = sourceSpan; } - public async Task TryRehydrateAsync(CancellationToken cancellationToken) + public static implicit operator DocumentIdSpan(DocumentSpan documentSpan) + => new(documentSpan.Document.Id, documentSpan.SourceSpan); + + public async Task TryRehydrateAsync(Solution solution, CancellationToken cancellationToken) { - var solution = _workspace.CurrentSolution; - var document = await solution.GetDocumentAsync(_documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); - return document == null ? null : new DocumentSpan(document, SourceSpan); + var document = await solution.GetDocumentAsync(this.DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + return document == null ? null : new DocumentSpan(document, this.SourceSpan); } } } diff --git a/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractAddDocCommentNodesCodeFixProvider.cs b/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractAddDocCommentNodesCodeFixProvider.cs index 856b2964af1ae..14dbe2b659d2c 100644 --- a/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractAddDocCommentNodesCodeFixProvider.cs +++ b/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractAddDocCommentNodesCodeFixProvider.cs @@ -34,8 +34,10 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) if (parentMethod != null && TryGetDocCommentNode(parentMethod.GetLeadingTrivia()) != null) { context.RegisterCodeFix( - new MyCodeAction( - c => AddParamTagAsync(context.Document, context.Span, c)), + CodeAction.Create( + FeaturesResources.Add_missing_param_nodes, + c => AddParamTagAsync(context.Document, context.Span, c), + nameof(FeaturesResources.Add_missing_param_nodes)), context.Diagnostics); } } @@ -174,13 +176,5 @@ protected TXmlElementSyntax GetParamNodeForParamName( return null; } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Add_missing_param_nodes, createChangedDocument, nameof(FeaturesResources.Add_missing_param_nodes)) - { - } - } } } diff --git a/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractRemoveDocCommentNodeCodeFixProvider.cs b/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractRemoveDocCommentNodeCodeFixProvider.cs index a399ddc35d411..987606df58241 100644 --- a/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractRemoveDocCommentNodeCodeFixProvider.cs +++ b/src/Features/Core/Portable/DocumentationComments/CodeFixes/AbstractRemoveDocCommentNodeCodeFixProvider.cs @@ -39,8 +39,10 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) if (GetParamNode(root, context.Span) != null) { context.RegisterCodeFix( - new MyCodeAction( - c => RemoveDuplicateParamTagAsync(context.Document, context.Span, c)), + CodeAction.Create( + FeaturesResources.Remove_tag, + c => RemoveDuplicateParamTagAsync(context.Document, context.Span, c), + nameof(FeaturesResources.Remove_tag)), context.Diagnostics); } } @@ -122,13 +124,5 @@ private bool ShouldRemovePreviousSibling(List paramNodeSiblings, int return false; } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Remove_tag, createChangedDocument, nameof(FeaturesResources.Remove_tag)) - { - } - } } } diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index 2e3887c75ab27..8e52dbfcb62a4 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -3258,7 +3258,7 @@ private static bool IsReloadable(INamedTypeSymbol type) { // We assume that the attribute System.Runtime.CompilerServices.CreateNewOnMetadataUpdateAttribute, if it exists, is well formed. // If not an error will be reported during EnC delta emit. - if (attributeData.AttributeClass is { Name: CreateNewOnMetadataUpdateAttributeName, ContainingNamespace: { Name: "CompilerServices", ContainingNamespace: { Name: "Runtime", ContainingNamespace: { Name: "System" } } } }) + if (attributeData.AttributeClass is { Name: CreateNewOnMetadataUpdateAttributeName, ContainingNamespace: { Name: "CompilerServices", ContainingNamespace: { Name: "Runtime", ContainingNamespace.Name: "System" } } }) { return true; } diff --git a/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs b/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs index 84ff8f6cb6351..a8daeb77d4413 100644 --- a/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs +++ b/src/Features/Core/Portable/EditAndContinue/CommittedSolution.cs @@ -86,7 +86,7 @@ internal enum DocumentState /// Once a document state is or /// it will never change. /// - private readonly Dictionary _documentState; + private readonly Dictionary _documentState = new(); private readonly object _guard = new(); @@ -94,7 +94,6 @@ public CommittedSolution(DebuggingSession debuggingSession, Solution solution, I { _solution = solution; _debuggingSession = debuggingSession; - _documentState = new Dictionary(); _documentState.AddRange(initialDocumentStates); } diff --git a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDetectionCodeFixProvider.cs b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDetectionCodeFixProvider.cs index e7c51e05883b1..68d0decb53588 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDetectionCodeFixProvider.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDetectionCodeFixProvider.cs @@ -35,7 +35,12 @@ public override ImmutableArray FixableDiagnosticIds public override Task RegisterCodeFixesAsync(CodeFixContext context) { - context.RegisterCodeFix(new MyCodeAction(GetDocumentUpdater(context)), context.Diagnostics); + context.RegisterCodeFix( + CodeAction.Create( + FeaturesResources.Enable_all_JSON_editor_features, + GetDocumentUpdater(context), + nameof(FeaturesResources.Enable_all_JSON_editor_features)), + context.Diagnostics); return Task.CompletedTask; } @@ -60,13 +65,5 @@ protected override Task FixAllAsync( return Task.CompletedTask; } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Enable_all_JSON_editor_features, createChangedDocument, nameof(FeaturesResources.Enable_all_JSON_editor_features)) - { - } - } } } diff --git a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/EmbeddedCompletionContext.cs b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/EmbeddedCompletionContext.cs index 36c8508cba6b9..bca3e49ef6e5d 100644 --- a/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/EmbeddedCompletionContext.cs +++ b/src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/EmbeddedCompletionContext.cs @@ -17,13 +17,13 @@ private readonly struct EmbeddedCompletionContext { private readonly RegexEmbeddedLanguage _language; private readonly CompletionContext _context; - private readonly HashSet _names; + private readonly HashSet _names = new(); public readonly RegexTree Tree; public readonly SyntaxToken StringToken; public readonly int Position; public readonly CompletionTrigger Trigger; - public readonly List Items; + public readonly List Items = new(); public EmbeddedCompletionContext( RegexEmbeddedLanguage language, @@ -33,12 +33,10 @@ public EmbeddedCompletionContext( { _language = language; _context = context; - _names = new HashSet(); Tree = tree; StringToken = stringToken; Position = _context.Position; Trigger = _context.Trigger; - Items = new List(); } public void AddIfMissing( diff --git a/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs b/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs index 0821d0e696768..eb9f6c39f1fc7 100644 --- a/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs +++ b/src/Features/Core/Portable/EncapsulateField/AbstractEncapsulateFieldService.cs @@ -30,10 +30,10 @@ namespace Microsoft.CodeAnalysis.EncapsulateField { internal abstract partial class AbstractEncapsulateFieldService : ILanguageService { - protected abstract Task RewriteFieldNameAndAccessibilityAsync(string originalFieldName, bool makePrivate, Document document, SyntaxAnnotation declarationAnnotation, CancellationToken cancellationToken); + protected abstract Task RewriteFieldNameAndAccessibilityAsync(string originalFieldName, bool makePrivate, Document document, SyntaxAnnotation declarationAnnotation, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken); protected abstract Task> GetFieldsAsync(Document document, TextSpan span, CancellationToken cancellationToken); - public async Task EncapsulateFieldsInSpanAsync(Document document, TextSpan span, CodeCleanupOptionsProvider fallbackOptions, bool useDefaultBehavior, CancellationToken cancellationToken) + public async Task EncapsulateFieldsInSpanAsync(Document document, TextSpan span, CleanCodeGenerationOptionsProvider fallbackOptions, bool useDefaultBehavior, CancellationToken cancellationToken) { var fields = await GetFieldsAsync(document, span, cancellationToken).ConfigureAwait(false); if (fields.IsDefaultOrEmpty) @@ -46,7 +46,7 @@ public async Task EncapsulateFieldsInSpanAsync(Document c => EncapsulateFieldsAsync(document, fields, fallbackOptions, useDefaultBehavior, c)); } - public async Task> GetEncapsulateFieldCodeActionsAsync(Document document, TextSpan span, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken) + public async Task> GetEncapsulateFieldCodeActionsAsync(Document document, TextSpan span, CleanCodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var fields = await GetFieldsAsync(document, span, cancellationToken).ConfigureAwait(false); if (fields.IsDefaultOrEmpty) @@ -72,32 +72,36 @@ public async Task> GetEncapsulateFieldCodeActionsAsyn return builder.ToImmutable(); } - private ImmutableArray EncapsulateAllFields(Document document, ImmutableArray fields, CodeCleanupOptionsProvider fallbackOptions) + private ImmutableArray EncapsulateAllFields(Document document, ImmutableArray fields, CleanCodeGenerationOptionsProvider fallbackOptions) { - return ImmutableArray.Create( - new MyCodeAction( + return ImmutableArray.Create( + CodeAction.Create( FeaturesResources.Encapsulate_fields_and_use_property, - c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: true, c)), - new MyCodeAction( + c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: true, c), + nameof(FeaturesResources.Encapsulate_fields_and_use_property)), + CodeAction.Create( FeaturesResources.Encapsulate_fields_but_still_use_field, - c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: false, c))); + c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: false, c), + nameof(FeaturesResources.Encapsulate_fields_but_still_use_field))); } - private ImmutableArray EncapsulateOneField(Document document, IFieldSymbol field, CodeCleanupOptionsProvider fallbackOptions) + private ImmutableArray EncapsulateOneField(Document document, IFieldSymbol field, CleanCodeGenerationOptionsProvider fallbackOptions) { var fields = ImmutableArray.Create(field); - return ImmutableArray.Create( - new MyCodeAction( + return ImmutableArray.Create( + CodeAction.Create( string.Format(FeaturesResources.Encapsulate_field_colon_0_and_use_property, field.Name), - c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: true, c)), - new MyCodeAction( + c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: true, c), + nameof(FeaturesResources.Encapsulate_field_colon_0_and_use_property) + "_" + field.Name), + CodeAction.Create( string.Format(FeaturesResources.Encapsulate_field_colon_0_but_still_use_field, field.Name), - c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: false, c))); + c => EncapsulateFieldsAsync(document, fields, fallbackOptions, updateReferences: false, c), + nameof(FeaturesResources.Encapsulate_field_colon_0_but_still_use_field) + "_" + field.Name)); } public async Task EncapsulateFieldsAsync( Document document, ImmutableArray fields, - CodeCleanupOptionsProvider fallbackOptions, + CleanCodeGenerationOptionsProvider fallbackOptions, bool updateReferences, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -113,7 +117,7 @@ public async Task EncapsulateFieldsAsync( var result = await client.TryInvokeAsync)>>( solution, (service, solutionInfo, callbackId, cancellationToken) => service.EncapsulateFieldsAsync(solutionInfo, callbackId, document.Id, fieldSymbolKeys, updateReferences, cancellationToken), - callbackTarget: new RemoteOptionsProvider(solution.Workspace.Services, fallbackOptions.Invoke), + callbackTarget: new RemoteOptionsProvider(solution.Workspace.Services, fallbackOptions), cancellationToken).ConfigureAwait(false); if (!result.HasValue) @@ -130,7 +134,7 @@ public async Task EncapsulateFieldsAsync( document, fields, fallbackOptions, updateReferences, cancellationToken).ConfigureAwait(false); } - private async Task EncapsulateFieldsInCurrentProcessAsync(Document document, ImmutableArray fields, CodeCleanupOptionsProvider fallbackOptions, bool updateReferences, CancellationToken cancellationToken) + private async Task EncapsulateFieldsInCurrentProcessAsync(Document document, ImmutableArray fields, CleanCodeGenerationOptionsProvider fallbackOptions, bool updateReferences, CancellationToken cancellationToken) { Contract.ThrowIfTrue(fields.Length == 0); @@ -160,7 +164,7 @@ private async Task EncapsulateFieldAsync( Document document, IFieldSymbol field, bool updateReferences, - CodeCleanupOptionsProvider fallbackOptions, + CleanCodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var originalField = field; @@ -205,7 +209,7 @@ private async Task EncapsulateFieldAsync( document = solutionNeedingProperty.GetDocument(document.Id); var markFieldPrivate = field.DeclaredAccessibility != Accessibility.Private; - var rewrittenFieldDeclaration = await RewriteFieldNameAndAccessibilityAsync(finalFieldName, markFieldPrivate, document, declarationAnnotation, cancellationToken).ConfigureAwait(false); + var rewrittenFieldDeclaration = await RewriteFieldNameAndAccessibilityAsync(finalFieldName, markFieldPrivate, document, declarationAnnotation, fallbackOptions, cancellationToken).ConfigureAwait(false); var formattingOptions = await document.GetSyntaxFormattingOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); @@ -216,7 +220,7 @@ private async Task EncapsulateFieldAsync( { var linkedDocument = solution.GetDocument(linkedDocumentId); var linkedDocumentFormattingOptions = await linkedDocument.GetSyntaxFormattingOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); - var updatedLinkedRoot = await RewriteFieldNameAndAccessibilityAsync(finalFieldName, markFieldPrivate, linkedDocument, declarationAnnotation, cancellationToken).ConfigureAwait(false); + var updatedLinkedRoot = await RewriteFieldNameAndAccessibilityAsync(finalFieldName, markFieldPrivate, linkedDocument, declarationAnnotation, fallbackOptions, cancellationToken).ConfigureAwait(false); var updatedLinkedDocument = await Formatter.FormatAsync(linkedDocument.WithSyntaxRoot(updatedLinkedRoot), Formatter.Annotation, linkedDocumentFormattingOptions, cancellationToken).ConfigureAwait(false); solution = updatedLinkedDocument.Project.Solution; } @@ -240,10 +244,13 @@ private async Task EncapsulateFieldAsync( var simplifierOptions = await document.GetSimplifierOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); - var solutionWithProperty = await AddPropertyAsync( - document, document.Project.Solution, field, generatedProperty, formattingOptions, simplifierOptions, cancellationToken).ConfigureAwait(false); + var documentWithProperty = await AddPropertyAsync( + document, document.Project.Solution, field, generatedProperty, fallbackOptions, cancellationToken).ConfigureAwait(false); + + documentWithProperty = await Formatter.FormatAsync(documentWithProperty, Formatter.Annotation, formattingOptions, cancellationToken).ConfigureAwait(false); + documentWithProperty = await Simplifier.ReduceAsync(documentWithProperty, simplifierOptions, cancellationToken).ConfigureAwait(false); - return solutionWithProperty; + return documentWithProperty.Project.Solution; } private async Task UpdateReferencesAsync( @@ -330,30 +337,27 @@ private ISet GetConstructorLocations(INamedTypeSymbol containingType) internal abstract IEnumerable GetConstructorNodes(INamedTypeSymbol containingType); - protected static async Task AddPropertyAsync( + protected static async Task AddPropertyAsync( Document document, Solution destinationSolution, IFieldSymbol field, IPropertySymbol property, - SyntaxFormattingOptions formattingOptions, - SimplifierOptions simplifierOptions, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var codeGenerationService = document.GetLanguageService(); var fieldDeclaration = field.DeclaringSyntaxReferences.First(); - var context = new CodeGenerationContext( - contextLocation: fieldDeclaration.SyntaxTree.GetLocation(fieldDeclaration.Span)); + var context = new CodeGenerationSolutionContext( + destinationSolution, + new CodeGenerationContext( + contextLocation: fieldDeclaration.SyntaxTree.GetLocation(fieldDeclaration.Span)), + fallbackOptions); var destination = field.ContainingType; - var updatedDocument = await codeGenerationService.AddPropertyAsync( - destinationSolution, destination, property, context, cancellationToken).ConfigureAwait(false); - - updatedDocument = await Formatter.FormatAsync(updatedDocument, Formatter.Annotation, formattingOptions, cancellationToken).ConfigureAwait(false); - updatedDocument = await Simplifier.ReduceAsync(updatedDocument, simplifierOptions, cancellationToken).ConfigureAwait(false); - - return updatedDocument.Project.Solution; + return await codeGenerationService.AddPropertyAsync( + context, destination, property, cancellationToken).ConfigureAwait(false); } protected static IPropertySymbol GenerateProperty( @@ -459,13 +463,5 @@ protected static string GeneratePropertyName(string fieldName) } private static readonly CultureInfo EnUSCultureInfo = new("en-US"); - - private class MyCodeAction : CodeAction.SolutionChangeAction - { - public MyCodeAction(string title, Func> createChangedSolution) - : base(title, createChangedSolution, title) - { - } - } } } diff --git a/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs index b0a9c66ad3f5f..cde605a2b37a4 100644 --- a/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs +++ b/src/Features/Core/Portable/EncapsulateField/EncapsulateFieldRefactoringProvider.cs @@ -2,12 +2,10 @@ // 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.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -15,7 +13,7 @@ namespace Microsoft.CodeAnalysis.EncapsulateField { [ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeRefactoringProviderNames.EncapsulateField), Shared] - internal class EncapsulateFieldRefactoringProvider : CodeRefactoringProvider + internal sealed class EncapsulateFieldRefactoringProvider : CodeRefactoringProvider { [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] @@ -26,9 +24,9 @@ public EncapsulateFieldRefactoringProvider() public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, textSpan, cancellationToken) = context; - var service = document.GetLanguageService(); + var service = document.GetRequiredLanguageService(); - var actions = await service.GetEncapsulateFieldCodeActionsAsync(document, textSpan, CodeCleanupOptions.CreateProvider(context.Options), cancellationToken).ConfigureAwait(false); + var actions = await service.GetEncapsulateFieldCodeActionsAsync(document, textSpan, context.Options, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); } } diff --git a/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs b/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs index 626539f710eaf..395aae8130d5d 100644 --- a/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs +++ b/src/Features/Core/Portable/EncapsulateField/IRemoteEncapsulateFieldService.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Text; @@ -19,9 +20,9 @@ namespace Microsoft.CodeAnalysis.EncapsulateField internal interface IRemoteEncapsulateFieldService { // TODO https://github.com/microsoft/vs-streamjsonrpc/issues/789 - internal interface ICallback // : IRemoteOptionsCallback + internal interface ICallback // : IRemoteOptionsCallback { - ValueTask GetOptionsAsync(RemoteServiceCallbackId callbackId, string language, CancellationToken cancellationToken); + ValueTask GetOptionsAsync(RemoteServiceCallbackId callbackId, string language, CancellationToken cancellationToken); } ValueTask)>> EncapsulateFieldsAsync( @@ -42,7 +43,7 @@ public RemoteConvertTupleToStructCodeRefactoringServiceCallbackDispatcher() { } - public ValueTask GetOptionsAsync(RemoteServiceCallbackId callbackId, string language, CancellationToken cancellationToken) - => ((RemoteOptionsProvider)GetCallback(callbackId)).GetOptionsAsync(language, cancellationToken); + public ValueTask GetOptionsAsync(RemoteServiceCallbackId callbackId, string language, CancellationToken cancellationToken) + => ((RemoteOptionsProvider)GetCallback(callbackId)).GetOptionsAsync(language, cancellationToken); } } diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptFormattingService.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptFormattingService.cs index 7f9bd49be721d..460c4a047c053 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptFormattingService.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptFormattingService.cs @@ -25,12 +25,12 @@ internal sealed class VSTypeScriptFormattingService : IFormattingService public VSTypeScriptFormattingService([Import(AllowDefault = true)] IVSTypeScriptFormattingServiceImplementation impl) => _impl = impl ?? throw new ArgumentNullException(nameof(impl)); - public Task FormatAsync(Document document, IEnumerable? spans, SyntaxFormattingOptions options, CancellationToken cancellationToken) + public Task FormatAsync(Document document, IEnumerable? spans, LineFormattingOptions lineFormattingOptions, SyntaxFormattingOptions? syntaxFormattingOptions, CancellationToken cancellationToken) { var tsOptions = new VSTypeScriptIndentationOptions( - UseSpaces: !options.UseTabs, - TabSize: options.TabSize, - IndentSize: options.IndentationSize); + UseSpaces: !lineFormattingOptions.UseTabs, + TabSize: lineFormattingOptions.TabSize, + IndentSize: lineFormattingOptions.IndentationSize); return _impl.FormatAsync(document, spans, tsOptions, cancellationToken); } diff --git a/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs b/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs index 1bd152adc8b4c..664e0a23b7d05 100644 --- a/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs +++ b/src/Features/Core/Portable/ExtractClass/AbstractExtractClassRefactoringProvider.cs @@ -4,6 +4,7 @@ using System; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.PullMemberUp; @@ -87,7 +88,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var syntaxFacts = document.GetRequiredLanguageService(); var containingTypeDeclarationNode = selectedMemberNode.FirstAncestorOrSelf(syntaxFacts.IsTypeDeclaration); - return new ExtractClassWithDialogCodeAction(document, span, optionsService, containingType, containingTypeDeclarationNode!, selectedMember); + return new ExtractClassWithDialogCodeAction(document, span, optionsService, containingType, containingTypeDeclarationNode!, context.Options, selectedMember); } private async Task TryGetClassActionAsync(CodeRefactoringContext context, IExtractClassOptionsService optionsService) @@ -108,7 +109,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return null; } - return new ExtractClassWithDialogCodeAction(document, span, optionsService, originalType, selectedClassNode); + return new ExtractClassWithDialogCodeAction(document, span, optionsService, originalType, selectedClassNode, context.Options); } } } diff --git a/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs b/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs index 4b914a7c02529..4575d5e4c78d4 100644 --- a/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/ExtractClass/ExtractClassWithDialogCodeAction.cs @@ -28,6 +28,7 @@ internal class ExtractClassWithDialogCodeAction : CodeActionWithOptions private readonly ISymbol? _selectedMember; private readonly INamedTypeSymbol _selectedType; private readonly SyntaxNode _selectedTypeDeclarationNode; + private readonly CleanCodeGenerationOptionsProvider _fallbackOptions; private readonly IExtractClassOptionsService _service; public TextSpan Span { get; } @@ -39,12 +40,14 @@ public ExtractClassWithDialogCodeAction( IExtractClassOptionsService service, INamedTypeSymbol selectedType, SyntaxNode selectedTypeDeclarationNode, + CleanCodeGenerationOptionsProvider fallbackOptions, ISymbol? selectedMember = null) { _document = document; _service = service; _selectedType = selectedType; _selectedTypeDeclarationNode = selectedTypeDeclarationNode; + _fallbackOptions = fallbackOptions; _selectedMember = selectedMember; Span = span; } @@ -92,6 +95,7 @@ protected override async Task> ComputeOperation symbolMapping.AnnotatedSolution.GetRequiredDocument(_document.Id), newType, symbolMapping, + _fallbackOptions, cancellationToken).ConfigureAwait(false) : await ExtractTypeHelpers.AddTypeToNewFileAsync( symbolMapping.AnnotatedSolution, @@ -101,6 +105,7 @@ protected override async Task> ComputeOperation _document.Folders, newType, _document, + _fallbackOptions, cancellationToken).ConfigureAwait(false); // Update the original type to have the new base @@ -205,7 +210,7 @@ private async Task PullMembersUpAsync( var pullMemberUpOptions = PullMembersUpOptionsBuilder.BuildPullMembersUpOptions(newType, pullMembersBuilder.ToImmutable()); var updatedOriginalDocument = solution.GetRequiredDocument(_document.Id); - return await MembersPuller.PullMembersUpAsync(updatedOriginalDocument, pullMemberUpOptions, cancellationToken).ConfigureAwait(false); + return await MembersPuller.PullMembersUpAsync(updatedOriginalDocument, pullMemberUpOptions, _fallbackOptions, cancellationToken).ConfigureAwait(false); } private static async Task GetNewTypeSymbolAsync(Document document, SyntaxAnnotation typeAnnotation, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs index 90e4ba8a7ff3d..d81aee62cc072 100644 --- a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs +++ b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs @@ -60,7 +60,7 @@ public async Task> GetExtractInterfac public async Task ExtractInterfaceAsync( Document documentWithTypeToExtractFrom, int position, - CodeCleanupOptionsProvider fallbackOptions, + CleanCodeGenerationOptionsProvider fallbackOptions, Action errorHandler, CancellationToken cancellationToken) { @@ -113,7 +113,7 @@ public async Task AnalyzeTypeAtPositionAsync return new ExtractInterfaceTypeAnalysisResult(document, typeNode, typeToExtractFrom, extractableMembers, fallbackOptions); } - public async Task ExtractInterfaceFromAnalyzedTypeAsync(ExtractInterfaceTypeAnalysisResult refactoringResult, CodeCleanupOptionsProvider fallbackOptions, CancellationToken cancellationToken) + public async Task ExtractInterfaceFromAnalyzedTypeAsync(ExtractInterfaceTypeAnalysisResult refactoringResult, CleanCodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var containingNamespaceDisplay = refactoringResult.TypeToExtractFrom.ContainingNamespace.IsGlobalNamespace ? string.Empty @@ -194,6 +194,7 @@ private async Task ExtractInterfaceToNewFileAsync( refactoringResult.DocumentToExtractFrom.Folders, extractedInterfaceSymbol, refactoringResult.DocumentToExtractFrom, + extractInterfaceOptions.FallbackOptions, cancellationToken).ConfigureAwait(false); var completedUnformattedSolution = await GetSolutionWithOriginalTypeUpdatedAsync( @@ -235,6 +236,7 @@ private async Task ExtractInterfaceToSameFileAsync( document, extractedInterfaceSymbol, symbolMapping, + extractInterfaceOptions.FallbackOptions, cancellationToken).ConfigureAwait(false); var unformattedSolution = documentWithInterface.Project.Solution; diff --git a/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeRefactoringProvider.cs b/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeRefactoringProvider.cs index 27ab17a628de9..7085d76700de0 100644 --- a/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceCodeRefactoringProvider.cs @@ -28,7 +28,7 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex { var (document, textSpan, cancellationToken) = context; var service = document.GetLanguageService(); - var actions = await service.GetExtractInterfaceCodeActionAsync(document, textSpan, CodeCleanupOptions.CreateProvider(context.Options), cancellationToken).ConfigureAwait(false); + var actions = await service.GetExtractInterfaceCodeActionAsync(document, textSpan, context.Options, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); } } diff --git a/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceOptionsResult.cs b/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceOptionsResult.cs index b3f4a6f1dc712..b9c2442e0a7a1 100644 --- a/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceOptionsResult.cs +++ b/src/Features/Core/Portable/ExtractInterface/ExtractInterfaceOptionsResult.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; namespace Microsoft.CodeAnalysis.ExtractInterface { @@ -24,9 +25,9 @@ public enum ExtractLocation public string InterfaceName { get; } public string FileName { get; } public ExtractLocation Location { get; } - public CodeCleanupOptionsProvider FallbackOptions { get; } + public CleanCodeGenerationOptionsProvider FallbackOptions { get; } - public ExtractInterfaceOptionsResult(bool isCancelled, ImmutableArray includedMembers, string interfaceName, string fileName, ExtractLocation location, CodeCleanupOptionsProvider fallbackOptions) + public ExtractInterfaceOptionsResult(bool isCancelled, ImmutableArray includedMembers, string interfaceName, string fileName, ExtractLocation location, CleanCodeGenerationOptionsProvider fallbackOptions) { IsCancelled = isCancelled; IncludedMembers = includedMembers; diff --git a/src/Features/Core/Portable/ExtractMethod/AbstractExtractMethodService.cs b/src/Features/Core/Portable/ExtractMethod/AbstractExtractMethodService.cs index ac7d1adbe3f2e..01f8de1c5f379 100644 --- a/src/Features/Core/Portable/ExtractMethod/AbstractExtractMethodService.cs +++ b/src/Features/Core/Portable/ExtractMethod/AbstractExtractMethodService.cs @@ -14,19 +14,19 @@ internal abstract class AbstractExtractMethodService ExtractMethodAsync( Document document, TextSpan textSpan, bool localFunction, - ExtractMethodOptions options, + ExtractMethodGenerationOptions options, CancellationToken cancellationToken) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); - var validator = CreateSelectionValidator(semanticDocument, textSpan, localFunction, options); + var validator = CreateSelectionValidator(semanticDocument, textSpan, options.ExtractOptions, localFunction); var selectionResult = await validator.GetValidSelectionAsync(cancellationToken).ConfigureAwait(false); if (!selectionResult.ContainsValidContext) @@ -37,7 +37,7 @@ public async Task ExtractMethodAsync( cancellationToken.ThrowIfCancellationRequested(); // extract method - var extractor = CreateMethodExtractor((TResult)selectionResult, localFunction); + var extractor = CreateMethodExtractor((TResult)selectionResult, options, localFunction); return await extractor.ExtractMethodAsync(cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/ExtractMethod/ExtractMethodService.cs b/src/Features/Core/Portable/ExtractMethod/ExtractMethodService.cs index 3f42c691933ab..a5e87f89fe562 100644 --- a/src/Features/Core/Portable/ExtractMethod/ExtractMethodService.cs +++ b/src/Features/Core/Portable/ExtractMethod/ExtractMethodService.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.ExtractMethod { internal static class ExtractMethodService { - public static Task ExtractMethodAsync(Document document, TextSpan textSpan, bool localFunction, ExtractMethodOptions options, CancellationToken cancellationToken) + public static Task ExtractMethodAsync(Document document, TextSpan textSpan, bool localFunction, ExtractMethodGenerationOptions options, CancellationToken cancellationToken) => document.GetRequiredLanguageService().ExtractMethodAsync(document, textSpan, localFunction, options, cancellationToken); } } diff --git a/src/Features/Core/Portable/ExtractMethod/IExtractMethodService.cs b/src/Features/Core/Portable/ExtractMethod/IExtractMethodService.cs index 354dbf6a4ff9b..fc8aa761de1cd 100644 --- a/src/Features/Core/Portable/ExtractMethod/IExtractMethodService.cs +++ b/src/Features/Core/Portable/ExtractMethod/IExtractMethodService.cs @@ -12,6 +12,6 @@ namespace Microsoft.CodeAnalysis.ExtractMethod { internal interface IExtractMethodService : ILanguageService { - Task ExtractMethodAsync(Document document, TextSpan textSpan, bool localFunction, ExtractMethodOptions options, CancellationToken cancellationToken); + Task ExtractMethodAsync(Document document, TextSpan textSpan, bool localFunction, ExtractMethodGenerationOptions options, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.SymbolMapBuilder.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.SymbolMapBuilder.cs index f938f85142781..ad7e030216acb 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.SymbolMapBuilder.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.Analyzer.SymbolMapBuilder.cs @@ -22,7 +22,7 @@ private class SymbolMapBuilder : SyntaxWalker private readonly SemanticModel _semanticModel; private readonly ISyntaxFactsService _service; private readonly TextSpan _span; - private readonly Dictionary> _symbolMap; + private readonly Dictionary> _symbolMap = new(); private readonly CancellationToken _cancellationToken; public static Dictionary> Build( @@ -52,7 +52,6 @@ private SymbolMapBuilder( _semanticModel = semanticModel; _service = service; _span = span; - _symbolMap = new Dictionary>(); _cancellationToken = cancellationToken; } diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs index e72b1b051f167..3bca31182a429 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.CodeGenerator.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; @@ -22,10 +23,11 @@ namespace Microsoft.CodeAnalysis.ExtractMethod { internal abstract partial class MethodExtractor { - protected abstract partial class CodeGenerator + protected abstract partial class CodeGenerator where TStatement : SyntaxNode where TExpression : SyntaxNode where TNodeUnderContainer : SyntaxNode + where TCodeGenerationOptions : CodeGenerationOptions { protected readonly SyntaxAnnotation MethodNameAnnotation; protected readonly SyntaxAnnotation MethodDefinitionAnnotation; @@ -36,10 +38,11 @@ protected abstract partial class CodeGenerator GenerateAsync(CancellationToken cancellationTok OperationStatus.NoValidLocationToInsertMethodCall, callSiteDocument, cancellationToken).ConfigureAwait(false); } - var options = codeGenerationService.GetOptions( - destination.SyntaxTree.Options, - Options, + var info = Options.GetInfo( new CodeGenerationContext( generateDefaultAccessibility: false, - generateMethodBodies: true)); + generateMethodBodies: true), + callSiteDocument.Project); - var localMethod = codeGenerationService.CreateMethodDeclaration(result.Data, CodeGenerationDestination.Unspecified, options, cancellationToken); - newContainer = codeGenerationService.AddStatements(destination, new[] { localMethod }, options, cancellationToken); + var localMethod = codeGenerationService.CreateMethodDeclaration(result.Data, CodeGenerationDestination.Unspecified, info, cancellationToken); + newContainer = codeGenerationService.AddStatements(destination, new[] { localMethod }, info, cancellationToken); } else { @@ -122,15 +125,14 @@ public async Task GenerateAsync(CancellationToken cancellationTok // it is possible in a script file case where there is no previous member. in that case, insert new text into top level script destination = previousMemberNode.Parent ?? previousMemberNode; - var options = codeGenerationService.GetOptions( - destination.SyntaxTree.Options, - Options, + var info = Options.GetInfo( new CodeGenerationContext( afterThisLocation: previousMemberNode.GetLocation(), generateDefaultAccessibility: true, - generateMethodBodies: true)); + generateMethodBodies: true), + callSiteDocument.Project); - newContainer = codeGenerationService.AddMethod(destination, result.Data, options, cancellationToken); + newContainer = codeGenerationService.AddMethod(destination, result.Data, info, cancellationToken); } var newSyntaxRoot = newCallSiteRoot.ReplaceNode(destination, newContainer); diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableSymbol.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableSymbol.cs index 5d308ab405643..d6480217c9ce4 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableSymbol.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.VariableSymbol.cs @@ -181,7 +181,7 @@ public override string Name protected class LocalVariableSymbol : VariableSymbol, IComparable> where T : SyntaxNode { - private readonly SyntaxAnnotation _annotation; + private readonly SyntaxAnnotation _annotation = new(); private readonly ILocalSymbol _localSymbol; private readonly HashSet _nonNoisySet; @@ -191,7 +191,6 @@ public LocalVariableSymbol(Compilation compilation, ILocalSymbol localSymbol, IT Contract.ThrowIfNull(localSymbol); Contract.ThrowIfNull(nonNoisySet); - _annotation = new SyntaxAnnotation(); _localSymbol = localSymbol; _nonNoisySet = nonNoisySet; } diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs index 598f8f428cbb3..a8af7a1cd81c5 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.cs @@ -10,9 +10,12 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting.Rules; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExtractMethod @@ -20,12 +23,17 @@ namespace Microsoft.CodeAnalysis.ExtractMethod internal abstract partial class MethodExtractor { protected readonly SelectionResult OriginalSelectionResult; + protected readonly ExtractMethodGenerationOptions Options; protected readonly bool LocalFunction; - public MethodExtractor(SelectionResult selectionResult, bool localFunction) + public MethodExtractor( + SelectionResult selectionResult, + ExtractMethodGenerationOptions options, + bool localFunction) { Contract.ThrowIfNull(selectionResult); OriginalSelectionResult = selectionResult; + Options = options; LocalFunction = localFunction; } @@ -34,7 +42,7 @@ public MethodExtractor(SelectionResult selectionResult, bool localFunction) protected abstract Task PreserveTriviaAsync(SelectionResult selectionResult, CancellationToken cancellationToken); protected abstract Task ExpandAsync(SelectionResult selection, CancellationToken cancellationToken); - protected abstract Task GenerateCodeAsync(InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzeResult, OptionSet options, CancellationToken cancellationToken); + protected abstract Task GenerateCodeAsync(InsertionPoint insertionPoint, SelectionResult selectionResult, AnalyzerResult analyzeResult, CodeGenerationOptions options, NamingStylePreferencesProvider namingPreferences, CancellationToken cancellationToken); protected abstract SyntaxToken GetMethodNameAtInvocation(IEnumerable methodNames); protected abstract ImmutableArray GetCustomFormattingRules(Document document); @@ -63,13 +71,13 @@ public async Task ExtractMethodAsync(CancellationToken canc cancellationToken.ThrowIfCancellationRequested(); var expandedDocument = await ExpandAsync(OriginalSelectionResult.With(triviaResult.SemanticDocument), cancellationToken).ConfigureAwait(false); - var options = await analyzeResult.SemanticDocument.Document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var generatedCode = await GenerateCodeAsync( insertionPoint.With(expandedDocument), OriginalSelectionResult.With(expandedDocument), analyzeResult.With(expandedDocument), - options, + Options.CodeGenerationOptions, + Options.NamingPreferences, cancellationToken).ConfigureAwait(false); var applied = await triviaResult.ApplyAsync(generatedCode, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/FeaturesResources.resx b/src/Features/Core/Portable/FeaturesResources.resx index f136dc94ae276..12d576bdf9d5d 100644 --- a/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/Features/Core/Portable/FeaturesResources.resx @@ -3129,4 +3129,7 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Sort Imports or usings + + Directives from '{0}' + \ No newline at end of file diff --git a/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs b/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs index 102bcb8d15477..a4b2332102095 100644 --- a/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs +++ b/src/Features/Core/Portable/FindUsages/DefinitionItem.DefaultDefinitionItem.cs @@ -60,9 +60,6 @@ public DefaultDefinitionItem( return await SourceSpans[0].GetNavigableLocationAsync(cancellationToken).ConfigureAwait(false); } - public DetachedDefinitionItem Detach() - => new(Tags, DisplayParts, NameDisplayParts, OriginationParts, SourceSpans, Properties, DisplayableProperties, DisplayIfNoReferences); - private async ValueTask<(Project? project, ISymbol? symbol)> TryResolveSymbolInCurrentSolutionAsync(Workspace workspace, string symbolKey, CancellationToken cancellationToken) { if (!Properties.TryGetValue(MetadataSymbolOriginatingProjectIdGuid, out var projectIdGuid) || diff --git a/src/Features/Core/Portable/FindUsages/DefinitionItem.DetachedDefinitionItem.cs b/src/Features/Core/Portable/FindUsages/DefinitionItem.DetachedDefinitionItem.cs index d1138a27c4b71..2fe4cd287abac 100644 --- a/src/Features/Core/Portable/FindUsages/DefinitionItem.DetachedDefinitionItem.cs +++ b/src/Features/Core/Portable/FindUsages/DefinitionItem.DetachedDefinitionItem.cs @@ -3,63 +3,70 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Shared.Collections; +using static Microsoft.CodeAnalysis.FindUsages.DefinitionItem; namespace Microsoft.CodeAnalysis.FindUsages { - internal partial class DefinitionItem + [DataContract] + internal readonly struct DetachedDefinitionItem { - internal readonly struct DetachedDefinitionItem - { - public readonly ImmutableArray Tags; - public readonly ImmutableDictionary Properties; - public readonly ImmutableDictionary DisplayableProperties; - public readonly ImmutableArray NameDisplayParts; - public readonly ImmutableArray DisplayParts; - public readonly ImmutableArray OriginationParts; - public readonly bool DisplayIfNoReferences; - - public readonly ImmutableArray SourceSpans; + [DataMember(Order = 0)] + public readonly ImmutableArray Tags; + [DataMember(Order = 1)] + public readonly ImmutableArray DisplayParts; + [DataMember(Order = 2)] + public readonly ImmutableArray NameDisplayParts; + [DataMember(Order = 3)] + public readonly ImmutableArray OriginationParts; + [DataMember(Order = 4)] + public readonly ImmutableArray SourceSpans; + [DataMember(Order = 5)] + public readonly ImmutableDictionary Properties; + [DataMember(Order = 6)] + public readonly ImmutableDictionary DisplayableProperties; + [DataMember(Order = 7)] + public readonly bool DisplayIfNoReferences; - public DetachedDefinitionItem( - ImmutableArray tags, - ImmutableArray displayParts, - ImmutableArray nameDisplayParts, - ImmutableArray originationParts, - ImmutableArray sourceSpans, - ImmutableDictionary properties, - ImmutableDictionary displayableProperties, - bool displayIfNoReferences) - { - Tags = tags; - DisplayParts = displayParts; - NameDisplayParts = nameDisplayParts; - OriginationParts = originationParts; - Properties = properties; - DisplayableProperties = displayableProperties; - DisplayIfNoReferences = displayIfNoReferences; - SourceSpans = sourceSpans.SelectAsArray(ss => new DocumentIdSpan(ss)); - } + public DetachedDefinitionItem( + ImmutableArray tags, + ImmutableArray displayParts, + ImmutableArray nameDisplayParts, + ImmutableArray originationParts, + ImmutableArray sourceSpans, + ImmutableDictionary properties, + ImmutableDictionary displayableProperties, + bool displayIfNoReferences) + { + Tags = tags; + DisplayParts = displayParts; + NameDisplayParts = nameDisplayParts; + OriginationParts = originationParts; + Properties = properties; + DisplayableProperties = displayableProperties; + DisplayIfNoReferences = displayIfNoReferences; + SourceSpans = sourceSpans; + } - public async Task TryRehydrateAsync(CancellationToken cancellationToken) + public async Task TryRehydrateAsync(Solution solution, CancellationToken cancellationToken) + { + using var converted = TemporaryArray.Empty; + foreach (var ss in SourceSpans) { - using var converted = TemporaryArray.Empty; - foreach (var ss in SourceSpans) - { - var documentSpan = await ss.TryRehydrateAsync(cancellationToken).ConfigureAwait(false); - if (documentSpan == null) - return null; + var documentSpan = await ss.TryRehydrateAsync(solution, cancellationToken).ConfigureAwait(false); + if (documentSpan == null) + return null; - converted.Add(documentSpan.Value); - } - - return new DefaultDefinitionItem( - Tags, DisplayParts, NameDisplayParts, OriginationParts, - converted.ToImmutableAndClear(), - Properties, DisplayableProperties, DisplayIfNoReferences); + converted.Add(documentSpan.Value); } + + return new DefaultDefinitionItem( + Tags, DisplayParts, NameDisplayParts, OriginationParts, + converted.ToImmutableAndClear(), + Properties, DisplayableProperties, DisplayIfNoReferences); } } } diff --git a/src/Features/Core/Portable/FindUsages/DefinitionItem.cs b/src/Features/Core/Portable/FindUsages/DefinitionItem.cs index 33513bbe185c1..6220d7184762c 100644 --- a/src/Features/Core/Portable/FindUsages/DefinitionItem.cs +++ b/src/Features/Core/Portable/FindUsages/DefinitionItem.cs @@ -321,5 +321,8 @@ internal static ImmutableArray GetOriginationParts(ISymbol symbol) return ImmutableArray.Empty; } + + public DetachedDefinitionItem Detach() + => new(Tags, DisplayParts, NameDisplayParts, OriginationParts, SourceSpans.SelectAsArray(ss => (DocumentIdSpan)ss), Properties, DisplayableProperties, DisplayIfNoReferences); } } diff --git a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs index 0d9a624da1027..9ea67da24c29a 100644 --- a/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs +++ b/src/Features/Core/Portable/FullyQualify/AbstractFullyQualifyCodeFixProvider.cs @@ -63,7 +63,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } - var hideAdvancedMembers = context.Options(document.Project.LanguageServices).HideAdvancedMembers; + var hideAdvancedMembers = context.Options.GetOptions(document.Project.LanguageServices).HideAdvancedMembers; var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var matchingTypes = await GetMatchingTypesAsync(document, semanticModel, node, hideAdvancedMembers, cancellationToken).ConfigureAwait(false); @@ -122,9 +122,11 @@ private IEnumerable CreateActions( memberName = name; } - var codeAction = new MyCodeAction( - $"{containerName}.{memberName}", - c => ProcessNodeAsync(document, node, containerName, symbolResult.OriginalSymbol, c)); + var title = $"{containerName}.{memberName}"; + var codeAction = CodeAction.Create( + title, + c => ProcessNodeAsync(document, node, containerName, symbolResult.OriginalSymbol, c), + title); yield return codeAction; } @@ -335,14 +337,6 @@ private static IEnumerable FilterAndSort(IEnumerable .Where(n => n.Symbol is INamedTypeSymbol || !((INamespaceSymbol)n.Symbol).IsGlobalNamespace) .Order(); - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, equivalenceKey: title) - { - } - } - private class GroupingCodeAction : CodeAction.CodeActionWithNestedActions { public GroupingCodeAction(string title, ImmutableArray nestedActions) diff --git a/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs index 90ccc457d8363..4a6f1f5ea846a 100644 --- a/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateComparisonOperators/GenerateComparisonOperatorsCodeRefactoringProvider.cs @@ -94,9 +94,9 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (missingComparableTypes.Count == 1) { var missingType = missingComparableTypes[0]; - context.RegisterRefactoring(new MyCodeAction( + context.RegisterRefactoring(CodeAction.Create( FeaturesResources.Generate_comparison_operators, - c => GenerateComparisonOperatorsAsync(document, typeDeclaration, missingType, c), + c => GenerateComparisonOperatorsAsync(document, typeDeclaration, missingType, context.Options, c), nameof(FeaturesResources.Generate_comparison_operators))); return; } @@ -107,9 +107,9 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte { var typeArg = missingType.TypeArguments[0]; var displayString = typeArg.ToMinimalDisplayString(semanticModel, textSpan.Start); - nestedActions.Add(new MyCodeAction( + nestedActions.Add(CodeAction.Create( string.Format(FeaturesResources.Generate_for_0, displayString), - c => GenerateComparisonOperatorsAsync(document, typeDeclaration, missingType, c), + c => GenerateComparisonOperatorsAsync(document, typeDeclaration, missingType, context.Options, c), nameof(FeaturesResources.Generate_for_0) + "_" + displayString)); } @@ -134,6 +134,7 @@ private static async Task GenerateComparisonOperatorsAsync( Document document, SyntaxNode typeDeclaration, INamedTypeSymbol comparableType, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); @@ -148,9 +149,12 @@ private static async Task GenerateComparisonOperatorsAsync( generator, semanticModel.Compilation, containingType, comparableType, GenerateLeftExpression(generator, comparableType, compareMethod)); - var context = new CodeGenerationContext(contextLocation: typeDeclaration.GetLocation()); + var solutionContext = new CodeGenerationSolutionContext( + document.Project.Solution, + new CodeGenerationContext(contextLocation: typeDeclaration.GetLocation()), + fallbackOptions); - return await codeGenService.AddMembersAsync(document.Project.Solution, containingType, operators, context, cancellationToken).ConfigureAwait(false); + return await codeGenService.AddMembersAsync(solutionContext, containingType, operators, cancellationToken).ConfigureAwait(false); } private static SyntaxNode GenerateLeftExpression( @@ -260,13 +264,5 @@ private static string GetOperatorName(CodeGenerationOperatorKind kind) CodeGenerationOperatorKind.GreaterThanOrEqual => WellKnownMemberNames.GreaterThanOrEqualOperatorName, _ => throw ExceptionUtilities.Unreachable, }; - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument, string equivalenceKey) - : base(title, createChangedDocument, equivalenceKey) - { - } - } } } diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs index 5d0d112594166..27887169d59d8 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.ConstructorDelegatingCodeAction.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; @@ -23,17 +24,20 @@ private class ConstructorDelegatingCodeAction : CodeAction private readonly Document _document; private readonly State _state; private readonly bool _addNullChecks; + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; public ConstructorDelegatingCodeAction( AbstractGenerateConstructorFromMembersCodeRefactoringProvider service, Document document, State state, - bool addNullChecks) + bool addNullChecks, + CodeAndImportGenerationOptionsProvider fallbackOptions) { _service = service; _document = document; _state = state; _addNullChecks = addNullChecks; + _fallbackOptions = fallbackOptions; } protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) @@ -88,7 +92,12 @@ protected override async Task GetChangedDocumentAsync(CancellationToke var statements = nullCheckStatements.ToImmutable().Concat(assignStatements.ToImmutable()); var result = await codeGenerationService.AddMethodAsync( - _document.Project.Solution, + new CodeGenerationSolutionContext( + _document.Project.Solution, + new CodeGenerationContext( + contextLocation: syntaxTree.GetLocation(_state.TextSpan), + afterThisLocation: afterThisLocation), + _fallbackOptions), _state.ContainingType, CodeGenerationSymbolFactory.CreateConstructorSymbol( attributes: default, @@ -98,9 +107,6 @@ protected override async Task GetChangedDocumentAsync(CancellationToke parameters: _state.Parameters, statements: statements, thisConstructorArguments: thisConstructorArguments), - new CodeGenerationContext( - contextLocation: syntaxTree.GetLocation(_state.TextSpan), - afterThisLocation: afterThisLocation), cancellationToken: cancellationToken).ConfigureAwait(false); return await AddNavigationAnnotationAsync(result, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs index 06c1fee0d2391..38240d68d50bc 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.FieldDelegatingCodeAction.cs @@ -15,23 +15,26 @@ namespace Microsoft.CodeAnalysis.GenerateConstructorFromMembers { internal abstract partial class AbstractGenerateConstructorFromMembersCodeRefactoringProvider { - private class FieldDelegatingCodeAction : CodeAction + private sealed class FieldDelegatingCodeAction : CodeAction { private readonly AbstractGenerateConstructorFromMembersCodeRefactoringProvider _service; private readonly Document _document; private readonly State _state; private readonly bool _addNullChecks; + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; public FieldDelegatingCodeAction( AbstractGenerateConstructorFromMembersCodeRefactoringProvider service, Document document, State state, - bool addNullChecks) + bool addNullChecks, + CodeAndImportGenerationOptionsProvider fallbackOptions) { _service = service; _document = document; _state = state; _addNullChecks = addNullChecks; + _fallbackOptions = fallbackOptions; } protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) @@ -75,12 +78,14 @@ protected override async Task GetChangedDocumentAsync(CancellationToke : null; var result = await CodeGenerator.AddMemberDeclarationsAsync( - _document.Project.Solution, + new CodeGenerationSolutionContext( + _document.Project.Solution, + new CodeGenerationContext( + contextLocation: syntaxTree.GetLocation(_state.TextSpan), + afterThisLocation: afterThisLocation), + _fallbackOptions), _state.ContainingType, members, - new CodeGenerationContext( - contextLocation: syntaxTree.GetLocation(_state.TextSpan), - afterThisLocation: afterThisLocation), cancellationToken).ConfigureAwait(false); return await AddNavigationAnnotationAsync(result, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs index 083df03f866aa..b5fc10b9f221e 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.GenerateConstructorWithDialogCodeAction.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.GenerateFromMembers; using Microsoft.CodeAnalysis.PickMembers; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -25,7 +26,7 @@ private class GenerateConstructorWithDialogCodeAction : CodeActionWithOptions private readonly Accessibility? _desiredAccessibility; private readonly AbstractGenerateConstructorFromMembersCodeRefactoringProvider _service; private readonly TextSpan _textSpan; - + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; private bool? _addNullCheckOptionValue; internal ImmutableArray ViableMembers { get; } @@ -35,11 +36,13 @@ private class GenerateConstructorWithDialogCodeAction : CodeActionWithOptions public GenerateConstructorWithDialogCodeAction( AbstractGenerateConstructorFromMembersCodeRefactoringProvider service, - Document document, TextSpan textSpan, + Document document, + TextSpan textSpan, INamedTypeSymbol containingType, Accessibility? desiredAccessibility, ImmutableArray viableMembers, - ImmutableArray pickMembersOptions) + ImmutableArray pickMembersOptions, + CodeAndImportGenerationOptionsProvider fallbackOptions) { _service = service; _document = document; @@ -48,6 +51,7 @@ public GenerateConstructorWithDialogCodeAction( _desiredAccessibility = desiredAccessibility; ViableMembers = viableMembers; PickMembersOptions = pickMembersOptions; + _fallbackOptions = fallbackOptions; } public override object GetOptions(CancellationToken cancellationToken) @@ -95,7 +99,7 @@ protected override async Task> ComputeOperation { if (state.MatchingConstructor.IsImplicitlyDeclared) { - var codeAction = new FieldDelegatingCodeAction(_service, _document, state, addNullChecks); + var codeAction = new FieldDelegatingCodeAction(_service, _document, state, addNullChecks, _fallbackOptions); return await codeAction.GetOperationsAsync(cancellationToken).ConfigureAwait(false); } @@ -109,8 +113,8 @@ protected override async Task> ComputeOperation else { var codeAction = state.DelegatedConstructor != null - ? new ConstructorDelegatingCodeAction(_service, _document, state, addNullChecks) - : (CodeAction)new FieldDelegatingCodeAction(_service, _document, state, addNullChecks); + ? new ConstructorDelegatingCodeAction(_service, _document, state, addNullChecks, _fallbackOptions) + : (CodeAction)new FieldDelegatingCodeAction(_service, _document, state, addNullChecks, _fallbackOptions); return await codeAction.GetOperationsAsync(cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs index cc2676406ce59..d2233dee59288 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs @@ -61,7 +61,8 @@ public override Task ComputeRefactoringsAsync(CodeRefactoringContext context) { return ComputeRefactoringsAsync(context.Document, context.Span, (action, applicableToSpan) => context.RegisterRefactoring(action, applicableToSpan), - (actions) => context.RegisterRefactorings(actions), desiredAccessibility: null, context.CancellationToken); + (actions) => context.RegisterRefactorings(actions), desiredAccessibility: null, + context.Options, context.CancellationToken); } public async Task> ComputeIntentAsync(Document priorDocument, TextSpan priorSelection, Document currentDocument, IntentDataProvider intentDataProvider, CancellationToken cancellationToken) @@ -75,6 +76,7 @@ await ComputeRefactoringsAsync( (singleAction, applicableToSpan) => actions.Add(singleAction), (multipleActions) => actions.AddRange(multipleActions), desiredAccessibility: accessibility, + intentDataProvider.FallbackOptions, cancellationToken).ConfigureAwait(false); if (actions.IsEmpty()) @@ -137,6 +139,7 @@ private async Task ComputeRefactoringsAsync( Action registerSingleAction, Action> registerMultipleActions, Accessibility? desiredAccessibility, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) @@ -145,7 +148,7 @@ private async Task ComputeRefactoringsAsync( } var actions = await GenerateConstructorFromMembersAsync( - document, textSpan, addNullChecks: false, desiredAccessibility, cancellationToken: cancellationToken).ConfigureAwait(false); + document, textSpan, addNullChecks: false, desiredAccessibility, fallbackOptions, cancellationToken).ConfigureAwait(false); if (!actions.IsDefault) { registerMultipleActions(actions); @@ -153,7 +156,7 @@ private async Task ComputeRefactoringsAsync( if (actions.IsDefaultOrEmpty && textSpan.IsEmpty) { - var nonSelectionAction = await HandleNonSelectionAsync(document, textSpan, desiredAccessibility, cancellationToken).ConfigureAwait(false); + var nonSelectionAction = await HandleNonSelectionAsync(document, textSpan, desiredAccessibility, fallbackOptions, cancellationToken).ConfigureAwait(false); if (nonSelectionAction != null) { registerSingleAction(nonSelectionAction.Value.CodeAction, nonSelectionAction.Value.ApplicableToSpan); @@ -165,6 +168,7 @@ private async Task ComputeRefactoringsAsync( Document document, TextSpan textSpan, Accessibility? desiredAccessibility, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var helpers = document.GetRequiredLanguageService(); @@ -228,11 +232,11 @@ private async Task ComputeRefactoringsAsync( return (new GenerateConstructorWithDialogCodeAction( this, document, textSpan, containingType, desiredAccessibility, viableMembers, - pickMemberOptions.ToImmutable()), typeDeclaration.Span); + pickMemberOptions.ToImmutable(), fallbackOptions), typeDeclaration.Span); } public async Task> GenerateConstructorFromMembersAsync( - Document document, TextSpan textSpan, bool addNullChecks, Accessibility? desiredAccessibility, CancellationToken cancellationToken) + Document document, TextSpan textSpan, bool addNullChecks, Accessibility? desiredAccessibility, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateFromMembers_GenerateConstructorFromMembers, cancellationToken)) { @@ -242,7 +246,7 @@ public async Task> GenerateConstructorFromMembersAsyn var state = await State.TryGenerateAsync(this, document, textSpan, info.ContainingType, desiredAccessibility, info.SelectedMembers, cancellationToken).ConfigureAwait(false); if (state != null && state.MatchingConstructor == null) { - return GetCodeActions(document, state, addNullChecks); + return GetCodeActions(document, state, addNullChecks, fallbackOptions); } } @@ -250,13 +254,13 @@ public async Task> GenerateConstructorFromMembersAsyn } } - private ImmutableArray GetCodeActions(Document document, State state, bool addNullChecks) + private ImmutableArray GetCodeActions(Document document, State state, bool addNullChecks, CodeAndImportGenerationOptionsProvider fallbackOptions) { using var _ = ArrayBuilder.GetInstance(out var result); - result.Add(new FieldDelegatingCodeAction(this, document, state, addNullChecks)); + result.Add(new FieldDelegatingCodeAction(this, document, state, addNullChecks, fallbackOptions)); if (state.DelegatedConstructor != null) - result.Add(new ConstructorDelegatingCodeAction(this, document, state, addNullChecks)); + result.Add(new ConstructorDelegatingCodeAction(this, document, state, addNullChecks, fallbackOptions)); return result.ToImmutable(); } diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs index 7fcb341ee1666..0bcd11a55e2ad 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorCodeFixProvider.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -36,7 +37,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var service = document.GetRequiredLanguageService(); var actions = await service.GenerateDefaultConstructorsAsync( - document, new TextSpan(typeName.Value.Span.Start, 0), forRefactoring: false, cancellationToken).ConfigureAwait(false); + document, new TextSpan(typeName.Value.Span.Start, 0), context.Options, forRefactoring: false, cancellationToken).ConfigureAwait(false); context.RegisterFixes(actions, diagnostic); } } diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs index 123ee3c1c7e19..0d9e535d89865 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.AbstractCodeAction.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; @@ -22,17 +23,20 @@ private abstract class AbstractCodeAction : CodeAction private readonly Document _document; private readonly State _state; private readonly string _title; + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; protected AbstractCodeAction( Document document, State state, IList constructors, - string title) + string title, + CodeAndImportGenerationOptionsProvider fallbackOptions) { _document = document; _state = state; _constructors = constructors; _title = title; + _fallbackOptions = fallbackOptions; } public override string Title => _title; @@ -41,10 +45,12 @@ protected override async Task GetChangedDocumentAsync(CancellationToke { Contract.ThrowIfNull(_state.ClassType); var result = await CodeGenerator.AddMemberDeclarationsAsync( - _document.Project.Solution, + new CodeGenerationSolutionContext( + _document.Project.Solution, + CodeGenerationContext.Default, + _fallbackOptions), _state.ClassType, _constructors.Select(CreateConstructorDefinition), - CodeGenerationContext.Default, cancellationToken).ConfigureAwait(false); return result; diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs index efacd88dc6444..2901934c5f339 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeAction.cs @@ -3,19 +3,22 @@ // See the LICENSE file in the project root for more information. using System.Linq; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.GenerateDefaultConstructors { internal abstract partial class AbstractGenerateDefaultConstructorsService { - private class GenerateDefaultConstructorCodeAction : AbstractCodeAction + private sealed class GenerateDefaultConstructorCodeAction : AbstractCodeAction { public GenerateDefaultConstructorCodeAction( Document document, State state, - IMethodSymbol constructor) - : base(document, state, new[] { constructor }, GetDisplayText(state, constructor)) + IMethodSymbol constructor, + CodeAndImportGenerationOptionsProvider fallbackOptions) + : base(document, state, new[] { constructor }, GetDisplayText(state, constructor), fallbackOptions) { } diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs index c298c029b74ec..f61e052388464 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.CodeActionAll.cs @@ -3,18 +3,21 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; namespace Microsoft.CodeAnalysis.GenerateDefaultConstructors { internal abstract partial class AbstractGenerateDefaultConstructorsService { - private class CodeActionAll : AbstractCodeAction + private sealed class CodeActionAll : AbstractCodeAction { public CodeActionAll( Document document, State state, - IList constructors) - : base(document, state, constructors, FeaturesResources.Generate_all) + IList constructors, + CodeAndImportGenerationOptionsProvider fallbackOptions) + : base(document, state, constructors, FeaturesResources.Generate_all, fallbackOptions) { } } diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs index 8f0c8866382ea..3fa526a9edfc6 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/AbstractGenerateDefaultConstructorsService.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; @@ -27,6 +28,7 @@ protected abstract bool TryInitializeState( public async Task> GenerateDefaultConstructorsAsync( Document document, TextSpan textSpan, + CodeAndImportGenerationOptionsProvider fallbackOptions, bool forRefactoring, CancellationToken cancellationToken) { @@ -41,10 +43,10 @@ public async Task> GenerateDefaultConstructorsAsync( if (state != null) { foreach (var constructor in state.UnimplementedConstructors) - result.Add(new GenerateDefaultConstructorCodeAction(document, state, constructor)); + result.Add(new GenerateDefaultConstructorCodeAction(document, state, constructor, fallbackOptions)); if (state.UnimplementedConstructors.Length > 1) - result.Add(new CodeActionAll(document, state, state.UnimplementedConstructors)); + result.Add(new CodeActionAll(document, state, state.UnimplementedConstructors, fallbackOptions)); } } diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs index 219cb103aeebe..df8236e8c94b6 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/GenerateDefaultConstructorsCodeRefactoringProvider.cs @@ -5,6 +5,7 @@ using System.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -46,7 +47,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var service = document.GetRequiredLanguageService(); var actions = await service.GenerateDefaultConstructorsAsync( - document, textSpan, forRefactoring: true, cancellationToken).ConfigureAwait(false); + document, textSpan, context.Options, forRefactoring: true, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); } } diff --git a/src/Features/Core/Portable/GenerateDefaultConstructors/IGenerateDefaultConstructorsService.cs b/src/Features/Core/Portable/GenerateDefaultConstructors/IGenerateDefaultConstructorsService.cs index 5303bb9b9033e..b74ebf50ef1ef 100644 --- a/src/Features/Core/Portable/GenerateDefaultConstructors/IGenerateDefaultConstructorsService.cs +++ b/src/Features/Core/Portable/GenerateDefaultConstructors/IGenerateDefaultConstructorsService.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; @@ -14,6 +15,6 @@ namespace Microsoft.CodeAnalysis.GenerateDefaultConstructors internal interface IGenerateDefaultConstructorsService : ILanguageService { Task> GenerateDefaultConstructorsAsync( - Document document, TextSpan textSpan, bool forRefactoring, CancellationToken cancellationToken); + Document document, TextSpan textSpan, CodeAndImportGenerationOptionsProvider fallbackOptions, bool forRefactoring, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs index 3fb4db438a361..4562c81084fcb 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeAction.cs @@ -34,12 +34,14 @@ private partial class GenerateEqualsAndGetHashCodeAction : CodeAction private readonly SyntaxNode _typeDeclaration; private readonly INamedTypeSymbol _containingType; private readonly ImmutableArray _selectedMembers; + private readonly CleanCodeGenerationOptionsProvider _fallbackOptions; public GenerateEqualsAndGetHashCodeAction( Document document, SyntaxNode typeDeclaration, INamedTypeSymbol containingType, ImmutableArray selectedMembers, + CleanCodeGenerationOptionsProvider fallbackOptions, bool generateEquals, bool generateGetHashCode, bool implementIEquatable, @@ -49,6 +51,7 @@ public GenerateEqualsAndGetHashCodeAction( _typeDeclaration = typeDeclaration; _containingType = containingType; _selectedMembers = selectedMembers; + _fallbackOptions = fallbackOptions; _generateEquals = generateEquals; _generateGetHashCode = generateGetHashCode; _implementIEquatable = implementIEquatable; @@ -85,11 +88,11 @@ protected override async Task GetChangedDocumentAsync(CancellationToke var codeGenerator = _document.GetRequiredLanguageService(); - // fallback options: https://github.com/dotnet/roslyn/issues/60794 - var codeGenOptions = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, _document, cancellationToken).ConfigureAwait(false); - var formattingOptions = await _document.GetSyntaxFormattingOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var codeGenOptions = await _document.GetCodeGenerationOptionsAsync(_fallbackOptions, cancellationToken).ConfigureAwait(false); + var formattingOptions = await _document.GetSyntaxFormattingOptionsAsync(_fallbackOptions, cancellationToken).ConfigureAwait(false); - var newTypeDeclaration = codeGenerator.AddMembers(_typeDeclaration, methods, codeGenOptions, cancellationToken); + var info = codeGenOptions.GetInfo(CodeGenerationContext.Default, _document.Project); + var newTypeDeclaration = codeGenerator.AddMembers(_typeDeclaration, methods, info, cancellationToken); if (constructedTypeToImplement is object) { diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs index 3dc0d28273dbd..04b50bc7ec963 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.GenerateFromMembers; using Microsoft.CodeAnalysis.Host.Mef; @@ -58,16 +59,18 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var actions = await GenerateEqualsAndGetHashCodeFromMembersAsync(document, textSpan, cancellationToken).ConfigureAwait(false); + var actions = await GenerateEqualsAndGetHashCodeFromMembersAsync(document, textSpan, context.Options, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); if (actions.IsDefaultOrEmpty && textSpan.IsEmpty) { - await HandleNonSelectionAsync(context).ConfigureAwait(false); + await HandleNonSelectionAsync(context, context.Options).ConfigureAwait(false); } } - private async Task HandleNonSelectionAsync(CodeRefactoringContext context) + private async Task HandleNonSelectionAsync( + CodeRefactoringContext context, + CleanCodeGenerationOptionsProvider fallbackOptions) { var (document, textSpan, cancellationToken) = context; @@ -110,7 +113,7 @@ private async Task HandleNonSelectionAsync(CodeRefactoringContext context) containingType, out var hasEquals, out var hasGetHashCode); var actions = await CreateActionsAsync( - document, typeDeclaration, containingType, viableMembers, + document, typeDeclaration, containingType, viableMembers, fallbackOptions, hasEquals, hasGetHashCode, withDialog: true, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions, textSpan); @@ -165,6 +168,7 @@ private static void GetExistingMemberInfo(INamedTypeSymbol containingType, out b public async Task> GenerateEqualsAndGetHashCodeFromMembersAsync( Document document, TextSpan textSpan, + CleanCodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateFromMembers_GenerateEqualsAndGetHashCode, cancellationToken)) @@ -184,7 +188,7 @@ public async Task> GenerateEqualsAndGetHashCodeFromMe RoslynDebug.AssertNotNull(typeDeclaration); return await CreateActionsAsync( - document, typeDeclaration, info.ContainingType, info.SelectedMembers, + document, typeDeclaration, info.ContainingType, info.SelectedMembers, fallbackOptions, hasEquals, hasGetHashCode, withDialog: false, cancellationToken).ConfigureAwait(false); } } @@ -195,6 +199,7 @@ public async Task> GenerateEqualsAndGetHashCodeFromMe private async Task> CreateActionsAsync( Document document, SyntaxNode typeDeclaration, INamedTypeSymbol containingType, ImmutableArray selectedMembers, + CleanCodeGenerationOptionsProvider fallbackOptions, bool hasEquals, bool hasGetHashCode, bool withDialog, CancellationToken cancellationToken) { using var _ = ArrayBuilder>.GetInstance(out var tasks); @@ -209,22 +214,22 @@ private async Task> CreateActionsAsync( // the user would need to bother just generating that member without also // generating 'Equals' as well. tasks.Add(CreateCodeActionAsync( - document, typeDeclaration, containingType, selectedMembers, + document, typeDeclaration, containingType, selectedMembers, fallbackOptions, generateEquals: true, generateGetHashCode: false, withDialog, cancellationToken)); tasks.Add(CreateCodeActionAsync( - document, typeDeclaration, containingType, selectedMembers, + document, typeDeclaration, containingType, selectedMembers, fallbackOptions, generateEquals: true, generateGetHashCode: true, withDialog, cancellationToken)); } else if (!hasEquals) { tasks.Add(CreateCodeActionAsync( - document, typeDeclaration, containingType, selectedMembers, + document, typeDeclaration, containingType, selectedMembers, fallbackOptions, generateEquals: true, generateGetHashCode: false, withDialog, cancellationToken)); } else if (!hasGetHashCode) { tasks.Add(CreateCodeActionAsync( - document, typeDeclaration, containingType, selectedMembers, + document, typeDeclaration, containingType, selectedMembers, fallbackOptions, generateEquals: false, generateGetHashCode: true, withDialog, cancellationToken)); } @@ -234,15 +239,17 @@ private async Task> CreateActionsAsync( private Task CreateCodeActionAsync( Document document, SyntaxNode typeDeclaration, INamedTypeSymbol containingType, ImmutableArray members, + CleanCodeGenerationOptionsProvider fallbackOptions, bool generateEquals, bool generateGetHashCode, bool withDialog, CancellationToken cancellationToken) { return withDialog - ? CreateCodeActionWithDialogAsync(document, typeDeclaration, containingType, members, generateEquals, generateGetHashCode, cancellationToken) - : CreateCodeActionWithoutDialogAsync(document, typeDeclaration, containingType, members, generateEquals, generateGetHashCode, cancellationToken); + ? CreateCodeActionWithDialogAsync(document, typeDeclaration, containingType, members, fallbackOptions, generateEquals, generateGetHashCode, cancellationToken) + : CreateCodeActionWithoutDialogAsync(document, typeDeclaration, containingType, members, fallbackOptions, generateEquals, generateGetHashCode, cancellationToken); } private async Task CreateCodeActionWithDialogAsync( Document document, SyntaxNode typeDeclaration, INamedTypeSymbol containingType, ImmutableArray members, + CleanCodeGenerationOptionsProvider fallbackOptions, bool generateEquals, bool generateGetHashCode, CancellationToken cancellationToken) { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); @@ -274,12 +281,12 @@ private async Task CreateCodeActionWithDialogAsync( } return new GenerateEqualsAndGetHashCodeWithDialogCodeAction( - this, document, typeDeclaration, containingType, members, - pickMembersOptions.ToImmutable(), generateEquals, generateGetHashCode); + this, document, typeDeclaration, containingType, members, pickMembersOptions.ToImmutable(), fallbackOptions, generateEquals, generateGetHashCode); } private static async Task CreateCodeActionWithoutDialogAsync( Document document, SyntaxNode typeDeclaration, INamedTypeSymbol containingType, ImmutableArray members, + CleanCodeGenerationOptionsProvider fallbackOptions, bool generateEquals, bool generateGetHashCode, CancellationToken cancellationToken) { var implementIEquatable = false; @@ -295,7 +302,7 @@ private static async Task CreateCodeActionWithoutDialogAsync( } return new GenerateEqualsAndGetHashCodeAction( - document, typeDeclaration, containingType, members, + document, typeDeclaration, containingType, members, fallbackOptions, generateEquals, generateGetHashCode, implementIEquatable, generateOperators); } } diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs index 7d92171afff6c..679fb5d5da50c 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/GenerateEqualsAndHashWithDialogCodeAction.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.PickMembers; using Roslyn.Utilities; @@ -25,7 +26,7 @@ private class GenerateEqualsAndGetHashCodeWithDialogCodeAction : CodeActionWithO private readonly INamedTypeSymbol _containingType; private readonly ImmutableArray _viableMembers; private readonly ImmutableArray _pickMembersOptions; - + private readonly CleanCodeGenerationOptionsProvider _fallbackOptions; private bool? _implementIEqutableOptionValue; private bool? _generateOperatorsOptionValue; @@ -36,6 +37,7 @@ public GenerateEqualsAndGetHashCodeWithDialogCodeAction( INamedTypeSymbol containingType, ImmutableArray viableMembers, ImmutableArray pickMembersOptions, + CleanCodeGenerationOptionsProvider fallbackOptions, bool generateEquals = false, bool generateGetHashCode = false) { @@ -45,6 +47,7 @@ public GenerateEqualsAndGetHashCodeWithDialogCodeAction( _containingType = containingType; _viableMembers = viableMembers; _pickMembersOptions = pickMembersOptions; + _fallbackOptions = fallbackOptions; _generateEquals = generateEquals; _generateGetHashCode = generateGetHashCode; } @@ -69,7 +72,6 @@ protected override async Task> ComputeOperation // If we presented the user any options, then persist whatever values // the user chose. That way we'll keep that as the default for the // next time the user opens the dialog. - var workspace = _document.Project.Solution.Workspace; var implementIEqutableOption = result.Options.FirstOrDefault(o => o.Id == ImplementIEquatableId); if (implementIEqutableOption != null) { @@ -86,7 +88,7 @@ protected override async Task> ComputeOperation var generatorOperators = (generateOperatorsOption?.Value ?? false); var action = new GenerateEqualsAndGetHashCodeAction( - _document, _typeDeclaration, _containingType, result.Members, + _document, _typeDeclaration, _containingType, result.Members, _fallbackOptions, _generateEquals, _generateGetHashCode, implementIEquatable, generatorOperators); return await action.GetOperationsAsync(cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs index a1cbb3323486d..b9e2eed7ec695 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.State.cs @@ -29,6 +29,7 @@ protected internal class State { private readonly TService _service; private readonly SemanticDocument _document; + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; private readonly NamingRule _fieldNamingRule; private readonly NamingRule _propertyNamingRule; @@ -54,7 +55,7 @@ protected internal class State public ImmutableDictionary ParameterToNewPropertyMap { get; private set; } public bool IsContainedInUnsafeType { get; private set; } - private State(TService service, SemanticDocument document, NamingRule fieldNamingRule, NamingRule propertyNamingRule, NamingRule parameterNamingRule) + private State(TService service, SemanticDocument document, NamingRule fieldNamingRule, NamingRule propertyNamingRule, NamingRule parameterNamingRule, CodeAndImportGenerationOptionsProvider fallbackOptions) { _service = service; _document = document; @@ -64,19 +65,21 @@ private State(TService service, SemanticDocument document, NamingRule fieldNamin ParameterToNewFieldMap = ImmutableDictionary.Empty; ParameterToNewPropertyMap = ImmutableDictionary.Empty; + _fallbackOptions = fallbackOptions; } public static async Task GenerateAsync( TService service, SemanticDocument document, SyntaxNode node, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var fieldNamingRule = await document.Document.GetApplicableNamingRuleAsync(SymbolKind.Field, Accessibility.Private, cancellationToken).ConfigureAwait(false); var propertyNamingRule = await document.Document.GetApplicableNamingRuleAsync(SymbolKind.Property, Accessibility.Public, cancellationToken).ConfigureAwait(false); var parameterNamingRule = await document.Document.GetApplicableNamingRuleAsync(SymbolKind.Parameter, Accessibility.NotApplicable, cancellationToken).ConfigureAwait(false); - var state = new State(service, document, fieldNamingRule, propertyNamingRule, parameterNamingRule); + var state = new State(service, document, fieldNamingRule, propertyNamingRule, parameterNamingRule, fallbackOptions); if (!await state.TryInitializeAsync(node, cancellationToken).ConfigureAwait(false)) { return null; @@ -594,11 +597,15 @@ public async Task GetChangedDocumentAsync( baseConstructorArguments: isThis ? default : delegatingArguments, thisConstructorArguments: isThis ? delegatingArguments : default); - return await provider.GetRequiredService().AddMembersAsync( + var context = new CodeGenerationSolutionContext( document.Project.Solution, + new CodeGenerationContext(Token.GetLocation()), + _fallbackOptions); + + return await provider.GetRequiredService().AddMembersAsync( + context, TypeToGenerateIn, members.Concat(constructor), - new CodeGenerationContext(Token.GetLocation()), cancellationToken).ConfigureAwait(false); } @@ -639,7 +646,10 @@ private async Task GenerateMemberDelegatingConstructorAsync( ImmutableDictionary.Empty; return await provider.GetRequiredService().AddMembersAsync( - document.Project.Solution, + new CodeGenerationSolutionContext( + document.Project.Solution, + new CodeGenerationContext(Token.GetLocation()), + _fallbackOptions), TypeToGenerateIn, provider.GetRequiredService().CreateMemberDelegatingConstructor( semanticModel, @@ -653,7 +663,6 @@ private async Task GenerateMemberDelegatingConstructorAsync( preferThrowExpression: false, generateProperties: withProperties, IsContainedInUnsafeType), - new CodeGenerationContext(Token.GetLocation()), cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs index 1d58ae04b7ca0..be789d885a33e 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/AbstractGenerateConstructorService.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServices; @@ -75,13 +76,13 @@ protected bool WillCauseConstructorCycle(State state, SemanticDocument document, return true; } - public async Task> GenerateConstructorAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) + public async Task> GenerateConstructorAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateConstructor, cancellationToken)) { var semanticDocument = await SemanticDocument.CreateAsync(document, cancellationToken).ConfigureAwait(false); - var state = await State.GenerateAsync((TService)this, semanticDocument, node, cancellationToken).ConfigureAwait(false); + var state = await State.GenerateAsync((TService)this, semanticDocument, node, fallbackOptions, cancellationToken).ConfigureAwait(false); if (state != null) { Contract.ThrowIfNull(state.TypeToGenerateIn); @@ -91,23 +92,26 @@ public async Task> GenerateConstructorAsync(Document // If we have any fields we'd like to generate, offer a code action to do that. if (state.ParameterToNewFieldMap.Count > 0) { - result.Add(new MyCodeAction( + result.Add(CodeAction.Create( string.Format(FeaturesResources.Generate_constructor_in_0_with_fields, state.TypeToGenerateIn.Name), - c => state.GetChangedDocumentAsync(document, withFields: true, withProperties: false, c))); + c => state.GetChangedDocumentAsync(document, withFields: true, withProperties: false, c), + nameof(FeaturesResources.Generate_constructor_in_0_with_fields) + "_" + state.TypeToGenerateIn.Name)); } // Same with a version that generates properties instead. if (state.ParameterToNewPropertyMap.Count > 0) { - result.Add(new MyCodeAction( + result.Add(CodeAction.Create( string.Format(FeaturesResources.Generate_constructor_in_0_with_properties, state.TypeToGenerateIn.Name), - c => state.GetChangedDocumentAsync(document, withFields: false, withProperties: true, c))); + c => state.GetChangedDocumentAsync(document, withFields: false, withProperties: true, c), + nameof(FeaturesResources.Generate_constructor_in_0_with_properties) + "_" + state.TypeToGenerateIn.Name)); } // Always offer to just generate the constructor and nothing else. - result.Add(new MyCodeAction( + result.Add(CodeAction.Create( string.Format(FeaturesResources.Generate_constructor_in_0, state.TypeToGenerateIn.Name), - c => state.GetChangedDocumentAsync(document, withFields: false, withProperties: false, c))); + c => state.GetChangedDocumentAsync(document, withFields: false, withProperties: false, c), + nameof(FeaturesResources.Generate_constructor_in_0) + "_" + state.TypeToGenerateIn.Name)); return result.ToImmutable(); } @@ -182,13 +186,5 @@ private ImmutableArray GenerateParameterNames( .Select((name, index) => new ParameterName(name, isFixed[index], parameterNamingRule)) .Skip(reservedNames.Count).ToImmutableArray(); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/IGenerateConstructorService.cs b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/IGenerateConstructorService.cs index 195870f7ba76b..2bfce5ba82f66 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateConstructor/IGenerateConstructorService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateConstructor/IGenerateConstructorService.cs @@ -6,12 +6,13 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor { internal interface IGenerateConstructorService : ILanguageService { - Task> GenerateConstructorAsync(Document document, SyntaxNode node, CancellationToken cancellationToken); + Task> GenerateConstructorAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs index 4e3ccd73d7e22..a6fc19ef38e01 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.CodeAction.cs @@ -19,13 +19,16 @@ private partial class GenerateEnumMemberCodeAction : CodeAction { private readonly Document _document; private readonly State _state; + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; public GenerateEnumMemberCodeAction( Document document, - State state) + State state, + CodeAndImportGenerationOptionsProvider fallbackOptions) { _document = document; _state = state; + _fallbackOptions = fallbackOptions; } protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) @@ -39,7 +42,11 @@ protected override async Task GetChangedDocumentAsync(CancellationToke : null; var result = await codeGenerator.AddFieldAsync( - _document.Project.Solution, + new CodeGenerationSolutionContext( + _document.Project.Solution, + new CodeGenerationContext( + contextLocation: _state.IdentifierToken.GetLocation()), + _fallbackOptions), _state.TypeToGenerateIn, CodeGenerationSymbolFactory.CreateFieldSymbol( attributes: default, @@ -49,9 +56,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke name: _state.IdentifierToken.ValueText, hasConstantValue: value != null, constantValue: value), - new CodeGenerationContext(contextLocation: _state.IdentifierToken.GetLocation()), - cancellationToken) - .ConfigureAwait(false); + cancellationToken).ConfigureAwait(false); return result; } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.cs b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.cs index 482b841e61c6c..fbf67e0bcf613 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/AbstractGenerateEnumMemberService.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Internal.Log; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateEnumMember @@ -25,7 +26,7 @@ protected AbstractGenerateEnumMemberService() protected abstract bool IsIdentifierNameGeneration(SyntaxNode node); protected abstract bool TryInitializeIdentifierNameState(SemanticDocument document, TSimpleNameSyntax identifierName, CancellationToken cancellationToken, out SyntaxToken identifierToken, out TExpressionSyntax simpleNameOrMemberAccessExpression); - public async Task> GenerateEnumMemberAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) + public async Task> GenerateEnumMemberAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateEnumMember, cancellationToken)) { @@ -36,11 +37,8 @@ public async Task> GenerateEnumMemberAsync(Document d return ImmutableArray.Empty; } - return GetActions(document, state); + return ImmutableArray.Create(new GenerateEnumMemberCodeAction(document, state, fallbackOptions)); } } - - private static ImmutableArray GetActions(Document document, State state) - => ImmutableArray.Create(new GenerateEnumMemberCodeAction(document, state)); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/IGenerateEnumMemberService.cs b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/IGenerateEnumMemberService.cs index 4dc419b89a952..919b199399997 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/IGenerateEnumMemberService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateEnumMember/IGenerateEnumMemberService.cs @@ -2,18 +2,17 @@ // 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.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateEnumMember { internal interface IGenerateEnumMemberService : ILanguageService { - Task> GenerateEnumMemberAsync(Document document, SyntaxNode node, CancellationToken cancellationToken); + Task> GenerateEnumMemberAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateConversionService.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateConversionService.cs index 9332f04dafa56..3458d3cc5028b 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateConversionService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateConversionService.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Internal.Log; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember @@ -28,6 +29,7 @@ internal abstract partial class AbstractGenerateConversionService> GenerateConversionAsync( Document document, SyntaxNode node, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateMethod, cancellationToken)) @@ -39,7 +41,7 @@ public async Task> GenerateConversionAsync( return ImmutableArray.Empty; } - return await GetActionsAsync(document, state, cancellationToken).ConfigureAwait(false); + return await GetActionsAsync(document, state, fallbackOptions, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.cs index 300ea897b0907..ff6929934eac0 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.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.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Internal.Log; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember @@ -24,6 +23,7 @@ public async Task> GenerateDeconstructMethodAsync( Document document, SyntaxNode leftSide, INamedTypeSymbol typeToGenerateIn, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateMethod, cancellationToken)) @@ -33,7 +33,7 @@ public async Task> GenerateDeconstructMethodAsync( var state = await State.GenerateDeconstructMethodStateAsync( (TService)this, semanticDocument, leftSide, typeToGenerateIn, cancellationToken).ConfigureAwait(false); - return state != null ? await GetActionsAsync(document, state, cancellationToken).ConfigureAwait(false) : ImmutableArray.Empty; + return state != null ? await GetActionsAsync(document, state, fallbackOptions, cancellationToken).ConfigureAwait(false) : ImmutableArray.Empty; } } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.cs index b1e2b4204b505..8cfbbfcdeb3d4 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServices; @@ -29,6 +30,7 @@ internal abstract partial class AbstractGenerateMethodService> GenerateMethodAsync( Document document, SyntaxNode node, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateMethod, cancellationToken)) @@ -40,7 +42,7 @@ public async Task> GenerateMethodAsync( return ImmutableArray.Empty; } - return await GetActionsAsync(document, state, cancellationToken).ConfigureAwait(false); + return await GetActionsAsync(document, state, fallbackOptions, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs index ac2cc6d29a833..532abe2662021 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.CodeAction.cs @@ -23,17 +23,20 @@ private partial class GenerateParameterizedMemberCodeAction : CodeAction private readonly bool _isAbstract; private readonly bool _generateProperty; private readonly string _equivalenceKey; + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; public GenerateParameterizedMemberCodeAction( TService service, Document document, State state, + CodeAndImportGenerationOptionsProvider fallbackOptions, bool isAbstract, bool generateProperty) { _service = service; _document = document; _state = state; + _fallbackOptions = fallbackOptions; _isAbstract = isAbstract; _generateProperty = generateProperty; _equivalenceKey = Title; @@ -71,14 +74,15 @@ protected override async Task GetChangedDocumentAsync(CancellationToke var property = await _state.SignatureInfo.GeneratePropertyAsync(syntaxFactory, _isAbstract, _state.IsWrittenTo, cancellationToken).ConfigureAwait(false); var result = await CodeGenerator.AddPropertyDeclarationAsync( - _document.Project.Solution, + new CodeGenerationSolutionContext( + _document.Project.Solution, + new CodeGenerationContext( + afterThisLocation: _state.IdentifierToken.GetLocation(), + generateMethodBodies: _state.TypeToGenerateIn.TypeKind != TypeKind.Interface), + _fallbackOptions), _state.TypeToGenerateIn, property, - new CodeGenerationContext( - afterThisLocation: _state.IdentifierToken.GetLocation(), - generateMethodBodies: _state.TypeToGenerateIn.TypeKind != TypeKind.Interface), - cancellationToken) - .ConfigureAwait(false); + cancellationToken).ConfigureAwait(false); return result; } @@ -87,12 +91,14 @@ protected override async Task GetChangedDocumentAsync(CancellationToke var method = await _state.SignatureInfo.GenerateMethodAsync(syntaxFactory, _isAbstract, cancellationToken).ConfigureAwait(false); var result = await CodeGenerator.AddMethodDeclarationAsync( - _document.Project.Solution, + new CodeGenerationSolutionContext( + _document.Project.Solution, + new CodeGenerationContext( + afterThisLocation: _state.Location, + generateMethodBodies: _state.TypeToGenerateIn.TypeKind != TypeKind.Interface), + _fallbackOptions), _state.TypeToGenerateIn, method, - new CodeGenerationContext( - afterThisLocation: _state.Location, - generateMethodBodies: _state.TypeToGenerateIn.TypeKind != TypeKind.Interface), cancellationToken) .ConfigureAwait(false); diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs index 894bdb375b490..1a6cf83fce85d 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.PooledObjects; @@ -38,10 +39,10 @@ protected virtual string GetImplicitConversionDisplayText(State state) protected virtual string GetExplicitConversionDisplayText(State state) => string.Empty; - protected async ValueTask> GetActionsAsync(Document document, State state, CancellationToken cancellationToken) + protected async ValueTask> GetActionsAsync(Document document, State state, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using var _ = ArrayBuilder.GetInstance(out var result); - result.Add(new GenerateParameterizedMemberCodeAction((TService)this, document, state, isAbstract: false, generateProperty: false)); + result.Add(new GenerateParameterizedMemberCodeAction((TService)this, document, state, fallbackOptions, isAbstract: false, generateProperty: false)); // If we're trying to generate an instance method into an abstract class (but not a // static class or an interface), then offer to generate it abstractly. @@ -51,7 +52,7 @@ protected async ValueTask> GetActionsAsync(Document d !state.IsStatic; if (canGenerateAbstractly) - result.Add(new GenerateParameterizedMemberCodeAction((TService)this, document, state, isAbstract: true, generateProperty: false)); + result.Add(new GenerateParameterizedMemberCodeAction((TService)this, document, state, fallbackOptions, isAbstract: true, generateProperty: false)); var semanticFacts = document.Project.Solution.Workspace.Services.GetLanguageServices(state.TypeToGenerateIn.Language).GetService(); @@ -63,10 +64,10 @@ protected async ValueTask> GetActionsAsync(Document d if (typeParameters.Length == 0 && returnType.SpecialType != SpecialType.System_Void) { - result.Add(new GenerateParameterizedMemberCodeAction((TService)this, document, state, isAbstract: false, generateProperty: true)); + result.Add(new GenerateParameterizedMemberCodeAction((TService)this, document, state, fallbackOptions, isAbstract: false, generateProperty: true)); if (canGenerateAbstractly) - result.Add(new GenerateParameterizedMemberCodeAction((TService)this, document, state, isAbstract: true, generateProperty: true)); + result.Add(new GenerateParameterizedMemberCodeAction((TService)this, document, state, fallbackOptions, isAbstract: true, generateProperty: true)); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateConversionService.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateConversionService.cs index f394535417267..7d3af99c16c0f 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateConversionService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateConversionService.cs @@ -2,18 +2,17 @@ // 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.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember { internal interface IGenerateConversionService : ILanguageService { - Task> GenerateConversionAsync(Document document, SyntaxNode node, CancellationToken cancellationToken); + Task> GenerateConversionAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateDeconstructMemberService.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateDeconstructMemberService.cs index c3e09ca8f5b2f..c6a773b46203b 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateDeconstructMemberService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateDeconstructMemberService.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.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember @@ -15,6 +14,6 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember internal interface IGenerateDeconstructMemberService : ILanguageService { Task> GenerateDeconstructMethodAsync( - Document document, SyntaxNode targetVariables, INamedTypeSymbol typeToGenerateIn, CancellationToken cancellationToken); + Document document, SyntaxNode targetVariables, INamedTypeSymbol typeToGenerateIn, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateParameterizedMemberService.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateParameterizedMemberService.cs index 0e34aa794b173..e7f800411c238 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateParameterizedMemberService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/IGenerateParameterizedMemberService.cs @@ -2,18 +2,17 @@ // 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.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember { internal interface IGenerateParameterizedMemberService : ILanguageService { - Task> GenerateMethodAsync(Document document, SyntaxNode node, CancellationToken cancellationToken); + Task> GenerateMethodAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs index 33c69286f2c4f..968550f4387f5 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.CodeAction.cs @@ -28,6 +28,7 @@ private partial class GenerateVariableCodeAction : CodeAction private readonly RefKind _refKind; private readonly SemanticDocument _semanticDocument; private readonly string _equivalenceKey; + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; public GenerateVariableCodeAction( SemanticDocument document, @@ -35,7 +36,8 @@ public GenerateVariableCodeAction( bool generateProperty, bool isReadonly, bool isConstant, - RefKind refKind) + RefKind refKind, + CodeAndImportGenerationOptionsProvider fallbackOptions) { _semanticDocument = document; _state = state; @@ -44,18 +46,21 @@ public GenerateVariableCodeAction( _isConstant = isConstant; _refKind = refKind; _equivalenceKey = Title; + _fallbackOptions = fallbackOptions; } protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) { - var solution = _semanticDocument.Project.Solution; var generateUnsafe = _state.TypeMemberType.RequiresUnsafeModifier() && !_state.IsContainedInUnsafeType; - var context = new CodeGenerationContext( - afterThisLocation: _state.AfterThisLocation, - beforeThisLocation: _state.BeforeThisLocation, - contextLocation: _state.IdentifierToken.GetLocation()); + var context = new CodeGenerationSolutionContext( + _semanticDocument.Project.Solution, + new CodeGenerationContext( + afterThisLocation: _state.AfterThisLocation, + beforeThisLocation: _state.BeforeThisLocation, + contextLocation: _state.IdentifierToken.GetLocation()), + _fallbackOptions); if (_generateProperty) { @@ -78,7 +83,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke setMethod: setAccessor); return await CodeGenerator.AddPropertyDeclarationAsync( - solution, _state.TypeToGenerateIn, propertySymbol, context, cancellationToken).ConfigureAwait(false); + context, _state.TypeToGenerateIn, propertySymbol, cancellationToken).ConfigureAwait(false); } else { @@ -92,7 +97,7 @@ protected override async Task GetChangedDocumentAsync(CancellationToke name: _state.IdentifierToken.ValueText); return await CodeGenerator.AddFieldDeclarationAsync( - solution, _state.TypeToGenerateIn, fieldSymbol, context, cancellationToken).ConfigureAwait(false); + context, _state.TypeToGenerateIn, fieldSymbol, cancellationToken).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs index b6ebbe03a1fed..8763d769a9bc0 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.GenerateLocalCodeAction.cs @@ -18,17 +18,19 @@ namespace Microsoft.CodeAnalysis.GenerateMember.GenerateVariable { internal partial class AbstractGenerateVariableService { - private class GenerateLocalCodeAction : CodeAction + private sealed class GenerateLocalCodeAction : CodeAction { private readonly TService _service; private readonly Document _document; private readonly State _state; + private readonly CodeGenerationOptionsProvider _fallbackOptions; - public GenerateLocalCodeAction(TService service, Document document, State state) + public GenerateLocalCodeAction(TService service, Document document, State state, CodeGenerationOptionsProvider fallbackOptions) { _service = service; _document = document; _state = state; + _fallbackOptions = fallbackOptions; } public override string Title @@ -54,7 +56,6 @@ protected override async Task GetChangedDocumentAsync(CancellationToke private async Task GetNewRootAsync(CancellationToken cancellationToken) { var semanticModel = await _document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var preferences = await CodeGenerationPreferences.FromDocumentAsync(_document, cancellationToken).ConfigureAwait(false); if (_service.TryConvertToLocalDeclaration(_state.LocalType, _state.IdentifierToken, semanticModel, cancellationToken, out var newRoot)) { @@ -73,13 +74,17 @@ private async Task GetNewRootAsync(CancellationToken cancellationTok var codeGenService = _document.GetLanguageService(); var root = _state.IdentifierToken.GetAncestors().Last(); - var options = preferences.GetOptions( - new CodeGenerationContext(beforeThisLocation: _state.IdentifierToken.GetLocation())); + var options = await _document.GetCodeGenerationOptionsAsync(_fallbackOptions, cancellationToken).ConfigureAwait(false); + + var info = options.GetInfo( + new CodeGenerationContext( + beforeThisLocation: _state.IdentifierToken.GetLocation()), + _document.Project); return codeGenService.AddStatements( root, SpecializedCollections.SingletonEnumerable(localStatement), - options, + info, cancellationToken: cancellationToken); } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.cs b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.cs index 25eea99b90011..e91748bacbc38 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateVariable/AbstractGenerateVariableService.cs @@ -39,6 +39,7 @@ protected AbstractGenerateVariableService() public async Task> GenerateVariableAsync( Document document, SyntaxNode node, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateMember_GenerateVariable, cancellationToken)) @@ -62,26 +63,27 @@ public async Task> GenerateVariableAsync( var name = state.IdentifierToken.ValueText; if (char.IsUpper(name.ToCharArray().FirstOrDefault())) { - await AddPropertyCodeActionsAsync(actions, semanticDocument, state, cancellationToken).ConfigureAwait(false); - AddFieldCodeActions(actions, semanticDocument, state); + await AddPropertyCodeActionsAsync(actions, semanticDocument, state, fallbackOptions, cancellationToken).ConfigureAwait(false); + AddFieldCodeActions(actions, semanticDocument, state, fallbackOptions); } else { - AddFieldCodeActions(actions, semanticDocument, state); - await AddPropertyCodeActionsAsync(actions, semanticDocument, state, cancellationToken).ConfigureAwait(false); + AddFieldCodeActions(actions, semanticDocument, state, fallbackOptions); + await AddPropertyCodeActionsAsync(actions, semanticDocument, state, fallbackOptions, cancellationToken).ConfigureAwait(false); } } - await AddLocalCodeActionsAsync(actions, document, state, cancellationToken).ConfigureAwait(false); + await AddLocalCodeActionsAsync(actions, document, state, fallbackOptions, cancellationToken).ConfigureAwait(false); await AddParameterCodeActionsAsync(actions, document, state, cancellationToken).ConfigureAwait(false); if (actions.Count > 1) { // Wrap the generate variable actions into a single top level suggestion // so as to not clutter the list. - return ImmutableArray.Create(new MyCodeAction( + return ImmutableArray.Create(CodeAction.Create( string.Format(FeaturesResources.Generate_variable_0, state.IdentifierToken.ValueText), - actions.ToImmutable())); + actions.ToImmutable(), + isInlinable: true)); } return actions.ToImmutable(); @@ -92,7 +94,7 @@ protected virtual bool ContainingTypesOrSelfHasUnsafeKeyword(INamedTypeSymbol co => false; private static async Task AddPropertyCodeActionsAsync( - ArrayBuilder result, SemanticDocument document, State state, CancellationToken cancellationToken) + ArrayBuilder result, SemanticDocument document, State state, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { if (state.IsInOutContext) return; @@ -114,10 +116,10 @@ private static async Task AddPropertyCodeActionsAsync( if (isOnlyReadAndIsInInterface || state.IsInConstructor) { result.Add(new GenerateVariableCodeAction( - document, state, generateProperty: true, isReadonly: true, isConstant: false, refKind: GetRefKindFromContext(state))); + document, state, generateProperty: true, isReadonly: true, isConstant: false, refKind: GetRefKindFromContext(state), fallbackOptions)); } - GenerateWritableProperty(result, document, state); + GenerateWritableProperty(result, document, state, fallbackOptions); } private static async Task NameIsHighlyUnlikelyToWarrantSymbolAsync( @@ -135,27 +137,27 @@ private static async Task NameIsHighlyUnlikelyToWarrantSymbolAsync( return false; } - private static void GenerateWritableProperty(ArrayBuilder result, SemanticDocument document, State state) + private static void GenerateWritableProperty(ArrayBuilder result, SemanticDocument document, State state, CodeAndImportGenerationOptionsProvider fallbackOptions) { result.Add(new GenerateVariableCodeAction( document, state, generateProperty: true, isReadonly: false, isConstant: false, - refKind: GetRefKindFromContext(state))); + refKind: GetRefKindFromContext(state), fallbackOptions)); } - private static void AddFieldCodeActions(ArrayBuilder result, SemanticDocument document, State state) + private static void AddFieldCodeActions(ArrayBuilder result, SemanticDocument document, State state, CodeAndImportGenerationOptionsProvider fallbackOptions) { if (state.TypeToGenerateIn.TypeKind != TypeKind.Interface) { if (state.IsConstant) { result.Add(new GenerateVariableCodeAction( - document, state, generateProperty: false, isReadonly: false, isConstant: true, refKind: RefKind.None)); + document, state, generateProperty: false, isReadonly: false, isConstant: true, refKind: RefKind.None, fallbackOptions)); } else { if (!state.OfferReadOnlyFieldFirst) { - GenerateWriteableField(result, document, state); + GenerateWriteableField(result, document, state, fallbackOptions); } // If we haven't written to the field, or we're in the constructor for the type @@ -163,25 +165,25 @@ private static void AddFieldCodeActions(ArrayBuilder result, Semanti if (!state.IsWrittenTo || state.IsInConstructor) { result.Add(new GenerateVariableCodeAction( - document, state, generateProperty: false, isReadonly: true, isConstant: false, refKind: RefKind.None)); + document, state, generateProperty: false, isReadonly: true, isConstant: false, refKind: RefKind.None, fallbackOptions)); } if (state.OfferReadOnlyFieldFirst) { - GenerateWriteableField(result, document, state); + GenerateWriteableField(result, document, state, fallbackOptions); } } } } - private static void GenerateWriteableField(ArrayBuilder result, SemanticDocument document, State state) + private static void GenerateWriteableField(ArrayBuilder result, SemanticDocument document, State state, CodeAndImportGenerationOptionsProvider fallbackOptions) { result.Add(new GenerateVariableCodeAction( - document, state, generateProperty: false, isReadonly: false, isConstant: false, refKind: RefKind.None)); + document, state, generateProperty: false, isReadonly: false, isConstant: false, refKind: RefKind.None, fallbackOptions)); } private async Task AddLocalCodeActionsAsync( - ArrayBuilder result, Document document, State state, CancellationToken cancellationToken) + ArrayBuilder result, Document document, State state, CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { if (state.CanGenerateLocal()) { @@ -192,7 +194,7 @@ private async Task AddLocalCodeActionsAsync( return; } - result.Add(new GenerateLocalCodeAction((TService)this, document, state)); + result.Add(new GenerateLocalCodeAction((TService)this, document, state, fallbackOptions)); } } @@ -230,13 +232,5 @@ private static RefKind GetRefKindFromContext(State state) return RefKind.None; } } - - private class MyCodeAction : CodeAction.CodeActionWithNestedActions - { - public MyCodeAction(string title, ImmutableArray nestedActions) - : base(title, nestedActions, isInlinable: true) - { - } - } } } diff --git a/src/Features/Core/Portable/GenerateMember/GenerateVariable/IGenerateVariableService.cs b/src/Features/Core/Portable/GenerateMember/GenerateVariable/IGenerateVariableService.cs index 2eaa6c3422033..e362d4f0638ee 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateVariable/IGenerateVariableService.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateVariable/IGenerateVariableService.cs @@ -8,12 +8,13 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateMember.GenerateVariable { internal interface IGenerateVariableService : ILanguageService { - Task> GenerateVariableAsync(Document document, SyntaxNode node, CancellationToken cancellationToken); + Task> GenerateVariableAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs index 229b9a2b37987..50dccb8e7320f 100644 --- a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesCodeRefactoringProvider.cs @@ -6,6 +6,7 @@ using System.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServices; @@ -59,7 +60,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte context.RegisterRefactoring( new GenerateOverridesWithDialogCodeAction( - this, document, textSpan, containingType, overridableMembers), + this, document, textSpan, containingType, overridableMembers, context.Options), typeDeclaration.Span); } } diff --git a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs index 69278befe05f7..fdff7c0ff852d 100644 --- a/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/GenerateOverrides/GenerateOverridesWithDialogCodeAction.cs @@ -30,19 +30,22 @@ private sealed class GenerateOverridesWithDialogCodeAction : CodeActionWithOptio private readonly INamedTypeSymbol _containingType; private readonly ImmutableArray _viableMembers; private readonly TextSpan _textSpan; + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; public GenerateOverridesWithDialogCodeAction( GenerateOverridesCodeRefactoringProvider service, Document document, TextSpan textSpan, INamedTypeSymbol containingType, - ImmutableArray viableMembers) + ImmutableArray viableMembers, + CodeAndImportGenerationOptionsProvider fallbackOptions) { _service = service; _document = document; _containingType = containingType; _viableMembers = viableMembers; _textSpan = textSpan; + _fallbackOptions = fallbackOptions; } public override string Title => FeaturesResources.Generate_overrides; @@ -81,12 +84,14 @@ protected override async Task> ComputeOperation var members = await Task.WhenAll(memberTasks).ConfigureAwait(false); var newDocument = await CodeGenerator.AddMemberDeclarationsAsync( - _document.Project.Solution, + new CodeGenerationSolutionContext( + _document.Project.Solution, + new CodeGenerationContext( + afterThisLocation: afterThisLocation, + contextLocation: syntaxTree.GetLocation(_textSpan)), + _fallbackOptions), _containingType, members, - new CodeGenerationContext( - afterThisLocation: afterThisLocation, - contextLocation: syntaxTree.GetLocation(_textSpan)), cancellationToken).ConfigureAwait(false); return new CodeActionOperation[] diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs index 87631934c4683..0f1c9ae0bffc3 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.CodeAction.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.ProjectManagement; @@ -24,17 +25,20 @@ private class GenerateTypeCodeAction : CodeAction private readonly Document _document; private readonly State _state; private readonly string _equivalenceKey; + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; public GenerateTypeCodeAction( TService service, Document document, State state, + CodeAndImportGenerationOptionsProvider fallbackOptions, bool intoNamespace, bool inNewFile) { _service = service; _document = document; _state = state; + _fallbackOptions = fallbackOptions; _intoNamespace = intoNamespace; _inNewFile = inNewFile; _equivalenceKey = Title; @@ -63,7 +67,7 @@ protected override async Task> ComputeOperation { var semanticDocument = await SemanticDocument.CreateAsync(_document, cancellationToken).ConfigureAwait(false); - var editor = new Editor(_service, semanticDocument, _state, _intoNamespace, _inNewFile, cancellationToken: cancellationToken); + var editor = new Editor(_service, semanticDocument, _state, _fallbackOptions, _intoNamespace, _inNewFile, cancellationToken); return await editor.GetOperationsAsync().ConfigureAwait(false); } @@ -76,17 +80,19 @@ public override string Title public override string EquivalenceKey => _equivalenceKey; } - private class GenerateTypeCodeActionWithOption : CodeActionWithOptions + private sealed class GenerateTypeCodeActionWithOption : CodeActionWithOptions { private readonly TService _service; private readonly Document _document; private readonly State _state; + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; - internal GenerateTypeCodeActionWithOption(TService service, Document document, State state) + internal GenerateTypeCodeActionWithOption(TService service, Document document, State state, CodeAndImportGenerationOptionsProvider fallbackOptions) { _service = service; _document = document; _state = state; + _fallbackOptions = fallbackOptions; } public override string Title => FeaturesResources.Generate_new_type; @@ -173,7 +179,7 @@ protected override async Task> ComputeOperation if (options is GenerateTypeOptionsResult generateTypeOptions && !generateTypeOptions.IsCancelled) { var semanticDocument = await SemanticDocument.CreateAsync(_document, cancellationToken).ConfigureAwait(false); - var editor = new Editor(_service, semanticDocument, _state, true, generateTypeOptions, cancellationToken); + var editor = new Editor(_service, semanticDocument, _state, _fallbackOptions, fromDialog: true, generateTypeOptions, cancellationToken); operations = await editor.GetOperationsAsync().ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs index bc15ec314a604..acc61e80518f8 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.Editor.cs @@ -41,11 +41,13 @@ private partial class Editor private readonly bool _fromDialog; private readonly GenerateTypeOptionsResult _generateTypeOptionsResult; private readonly CancellationToken _cancellationToken; + private readonly CodeAndImportGenerationOptionsProvider _fallbackOptions; public Editor( TService service, SemanticDocument document, State state, + CodeAndImportGenerationOptionsProvider fallbackOptions, bool intoNamespace, bool inNewFile, CancellationToken cancellationToken) @@ -53,6 +55,7 @@ public Editor( _service = service; _semanticDocument = document; _state = state; + _fallbackOptions = fallbackOptions; _intoNamespace = intoNamespace; _inNewFile = inNewFile; _cancellationToken = cancellationToken; @@ -62,6 +65,7 @@ public Editor( TService service, SemanticDocument document, State state, + CodeAndImportGenerationOptionsProvider fallbackOptions, bool fromDialog, GenerateTypeOptionsResult generateTypeOptionsResult, CancellationToken cancellationToken) @@ -72,6 +76,7 @@ public Editor( _service = service; _semanticDocument = document; _state = state; + _fallbackOptions = fallbackOptions; _fromDialog = fromDialog; _generateTypeOptionsResult = generateTypeOptionsResult; _cancellationToken = cancellationToken; @@ -292,10 +297,12 @@ private async Task> GetGenerateInNewFileOperati // namespace in the new file. This will properly generate the code, and add any // additional niceties like imports/usings. var codeGenResult = await CodeGenerator.AddNamespaceOrTypeDeclarationAsync( - newSolution, + new CodeGenerationSolutionContext( + newSolution, + new CodeGenerationContext(newSemanticModel.SyntaxTree.GetLocation(new TextSpan())), + _fallbackOptions), enclosingNamespace, rootNamespaceOrType, - new CodeGenerationContext(newSemanticModel.SyntaxTree.GetLocation(new TextSpan())), _cancellationToken).ConfigureAwait(false); // containers is determined to be @@ -387,10 +394,12 @@ private async Task> GetGenerateIntoContainingNa var solution = _semanticDocument.Project.Solution; var codeGenResult = await CodeGenerator.AddNamedTypeDeclarationAsync( - solution, + new CodeGenerationSolutionContext( + solution, + new CodeGenerationContext(afterThisLocation: _semanticDocument.SyntaxTree.GetLocation(_state.SimpleName.Span)), + _fallbackOptions), enclosingNamespace, namedType, - new CodeGenerationContext(afterThisLocation: _semanticDocument.SyntaxTree.GetLocation(_state.SimpleName.Span)), _cancellationToken).ConfigureAwait(false); return new CodeActionOperation[] { new ApplyChangesOperation(codeGenResult.Project.Solution) }; @@ -432,10 +441,12 @@ private async Task> GetGenerateIntoExistingDocu var solution = _semanticDocument.Project.Solution; var codeGenResult = await CodeGenerator.AddNamespaceOrTypeDeclarationAsync( - solution, + new CodeGenerationSolutionContext( + solution, + new CodeGenerationContext(afterThisLocation: enclosingNamespaceGeneratedTypeToAddAndLocation.Item3), + _fallbackOptions), enclosingNamespaceGeneratedTypeToAddAndLocation.Item1, enclosingNamespaceGeneratedTypeToAddAndLocation.Item2, - new CodeGenerationContext(afterThisLocation: enclosingNamespaceGeneratedTypeToAddAndLocation.Item3), _cancellationToken).ConfigureAwait(false); var newRoot = await codeGenResult.GetSyntaxRootAsync(_cancellationToken).ConfigureAwait(false); var updatedSolution = solution.WithDocumentSyntaxRoot(generateTypeOptionsResult.ExistingDocument.Id, newRoot, PreservationMode.PreserveIdentity); @@ -546,10 +557,12 @@ private async Task> GetGenerateIntoTypeOperatio { var solution = _semanticDocument.Project.Solution; var codeGenResult = await CodeGenerator.AddNamedTypeDeclarationAsync( - solution, + new CodeGenerationSolutionContext( + solution, + new CodeGenerationContext(contextLocation: _state.SimpleName.GetLocation()), + _fallbackOptions), _state.TypeToGenerateInOpt, namedType, - new CodeGenerationContext(contextLocation: _state.SimpleName.GetLocation()), _cancellationToken) .ConfigureAwait(false); diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs index 896e92300c1de..5a31f253b0136 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.cs @@ -69,6 +69,7 @@ protected AbstractGenerateTypeService() public async Task> GenerateTypeAsync( Document document, SyntaxNode node, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_GenerateType, cancellationToken)) @@ -78,13 +79,15 @@ public async Task> GenerateTypeAsync( var state = await State.GenerateAsync((TService)this, semanticDocument, node, cancellationToken).ConfigureAwait(false); if (state != null) { - var actions = GetActions(semanticDocument, node, state, cancellationToken); + var actions = GetActions(semanticDocument, node, state, fallbackOptions, cancellationToken); if (actions.Length > 1) { // Wrap the generate type actions into a single top level suggestion // so as to not clutter the list. - return ImmutableArray.Create(new MyCodeAction( - string.Format(FeaturesResources.Generate_type_0, state.Name), actions.AsImmutable())); + return ImmutableArray.Create(CodeAction.Create( + string.Format(FeaturesResources.Generate_type_0, state.Name), + actions.AsImmutable(), + isInlinable: true)); } else { @@ -100,6 +103,7 @@ private ImmutableArray GetActions( SemanticDocument document, SyntaxNode node, State state, + CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { using var _ = ArrayBuilder.GetInstance(out var result); @@ -111,7 +115,7 @@ private ImmutableArray GetActions( if (workspace == null || workspace.CanApplyChange(ApplyChangesKind.AddDocument)) { generateNewTypeInDialog = true; - result.Add(new GenerateTypeCodeAction((TService)this, document.Document, state, intoNamespace: true, inNewFile: true)); + result.Add(new GenerateTypeCodeAction((TService)this, document.Document, state, fallbackOptions, intoNamespace: true, inNewFile: true)); } // If they just are generating "Goo" then we want to offer to generate it into the @@ -124,15 +128,15 @@ private ImmutableArray GetActions( if ((isSimpleName || generateIntoContaining) && CanGenerateIntoContainingNamespace(document, node, cancellationToken)) { - result.Add(new GenerateTypeCodeAction((TService)this, document.Document, state, intoNamespace: true, inNewFile: false)); + result.Add(new GenerateTypeCodeAction((TService)this, document.Document, state, fallbackOptions, intoNamespace: true, inNewFile: false)); } } if (state.TypeToGenerateInOpt != null) - result.Add(new GenerateTypeCodeAction((TService)this, document.Document, state, intoNamespace: false, inNewFile: false)); + result.Add(new GenerateTypeCodeAction((TService)this, document.Document, state, fallbackOptions, intoNamespace: false, inNewFile: false)); if (generateNewTypeInDialog) - result.Add(new GenerateTypeCodeActionWithOption((TService)this, document.Document, state)); + result.Add(new GenerateTypeCodeActionWithOption((TService)this, document.Document, state, fallbackOptions)); return result.ToImmutable(); } @@ -296,13 +300,5 @@ protected static bool GeneratedTypesMustBePublic(Project project) return false; } - - private class MyCodeAction : CodeAction.CodeActionWithNestedActions - { - public MyCodeAction(string title, ImmutableArray nestedActions) - : base(title, nestedActions, isInlinable: true) - { - } - } } } diff --git a/src/Features/Core/Portable/GenerateType/IGenerateTypeService.cs b/src/Features/Core/Portable/GenerateType/IGenerateTypeService.cs index 0d36cd258a29e..9deb8e1089d37 100644 --- a/src/Features/Core/Portable/GenerateType/IGenerateTypeService.cs +++ b/src/Features/Core/Portable/GenerateType/IGenerateTypeService.cs @@ -2,19 +2,18 @@ // 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.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.GenerateType { internal interface IGenerateTypeService : ILanguageService { - Task> GenerateTypeAsync(Document document, SyntaxNode node, CancellationToken cancellationToken); + Task> GenerateTypeAsync(Document document, SyntaxNode node, CodeAndImportGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken); Task<(INamespaceSymbol, INamespaceOrTypeSymbol, Location)> GetOrGenerateEnclosingNamespaceSymbolAsync(INamedTypeSymbol namedTypeSymbol, string[] containers, Document selectedDocument, SyntaxNode selectedDocumentRoot, CancellationToken cancellationToken); string GetRootNamespace(CompilationOptions options); } diff --git a/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs b/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs index 47e275514e026..5bd2c638e25d9 100644 --- a/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs +++ b/src/Features/Core/Portable/ImplementAbstractClass/AbstractImplementAbstractClassCodeFixProvider.cs @@ -42,7 +42,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; var data = await ImplementAbstractClassData.TryGetDataAsync( - document, classNode, GetClassIdentifier(classNode), context.Options(document.Project.LanguageServices).ImplementTypeOptions, cancellationToken).ConfigureAwait(false); + document, classNode, GetClassIdentifier(classNode), context.Options.GetImplementTypeGenerationOptions(document.Project.LanguageServices), cancellationToken).ConfigureAwait(false); if (data == null) return; diff --git a/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs b/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs index b6f3e094d41e3..16f75ef9ad787 100644 --- a/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs +++ b/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs @@ -24,7 +24,7 @@ namespace Microsoft.CodeAnalysis.ImplementAbstractClass internal sealed class ImplementAbstractClassData { private readonly Document _document; - private readonly ImplementTypeOptions _options; + private readonly ImplementTypeGenerationOptions _options; private readonly SyntaxNode _classNode; private readonly SyntaxToken _classIdentifier; private readonly ImmutableArray<(INamedTypeSymbol type, ImmutableArray members)> _unimplementedMembers; @@ -33,7 +33,7 @@ internal sealed class ImplementAbstractClassData public readonly INamedTypeSymbol AbstractClassType; public ImplementAbstractClassData( - Document document, ImplementTypeOptions options, SyntaxNode classNode, SyntaxToken classIdentifier, + Document document, ImplementTypeGenerationOptions options, SyntaxNode classNode, SyntaxToken classIdentifier, INamedTypeSymbol classType, INamedTypeSymbol abstractClassType, ImmutableArray<(INamedTypeSymbol type, ImmutableArray members)> unimplementedMembers) { @@ -47,7 +47,7 @@ public ImplementAbstractClassData( } public static async Task TryGetDataAsync( - Document document, SyntaxNode classNode, SyntaxToken classIdentifier, ImplementTypeOptions options, CancellationToken cancellationToken) + Document document, SyntaxNode classNode, SyntaxToken classIdentifier, ImplementTypeGenerationOptions options, CancellationToken cancellationToken) { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (semanticModel.GetDeclaredSymbol(classNode, cancellationToken) is not INamedTypeSymbol classType) @@ -77,7 +77,7 @@ public ImplementAbstractClassData( } public static async Task TryImplementAbstractClassAsync( - Document document, SyntaxNode classNode, SyntaxToken classIdentifier, ImplementTypeOptions options, CancellationToken cancellationToken) + Document document, SyntaxNode classNode, SyntaxToken classIdentifier, ImplementTypeGenerationOptions options, CancellationToken cancellationToken) { var data = await TryGetDataAsync(document, classNode, classIdentifier, options, cancellationToken).ConfigureAwait(false); if (data == null) @@ -90,8 +90,8 @@ public async Task ImplementAbstractClassAsync( ISymbol? throughMember, bool? canDelegateAllMembers, CancellationToken cancellationToken) { var compilation = await _document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - var memberDefinitions = GenerateMembers(compilation, throughMember, _options.PropertyGenerationBehavior, cancellationToken); - var groupMembers = _options.InsertionBehavior == ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind; + var memberDefinitions = GenerateMembers(compilation, throughMember, _options.ImplementTypeOptions.PropertyGenerationBehavior, cancellationToken); + var groupMembers = _options.ImplementTypeOptions.InsertionBehavior == ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind; // If we're implementing through one of our members, but we can't delegate all members // through it, then give an error message on the class decl letting the user know. @@ -111,12 +111,12 @@ public async Task ImplementAbstractClassAsync( sortMembers: groupMembers); var codeGenerator = _document.GetRequiredLanguageService(); - var options = await CodeGenerationOptions.FromDocumentAsync(context, _document, cancellationToken).ConfigureAwait(false); + var codeGenOptions = await _document.GetCodeGenerationOptionsAsync(_options.FallbackOptions, cancellationToken).ConfigureAwait(false); var updatedClassNode = codeGenerator.AddMembers( classNodeToAddMembersTo, memberDefinitions, - options, + codeGenOptions.GetInfo(context, _document.Project), cancellationToken); var root = await _document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs index 4e73cbbb3ea53..41532d55d3f2e 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs +++ b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.CodeAction.cs @@ -32,7 +32,7 @@ internal partial class ImplementInterfaceCodeAction : CodeAction private readonly bool _onlyRemaining; protected readonly ISymbol ThroughMember; protected readonly Document Document; - protected readonly ImplementTypeOptions Options; + protected readonly ImplementTypeGenerationOptions Options; protected readonly State State; protected readonly AbstractImplementInterfaceService Service; private readonly string _equivalenceKey; @@ -40,7 +40,7 @@ internal partial class ImplementInterfaceCodeAction : CodeAction internal ImplementInterfaceCodeAction( AbstractImplementInterfaceService service, Document document, - ImplementTypeOptions options, + ImplementTypeGenerationOptions options, State state, bool explicitly, bool abstractly, @@ -49,8 +49,8 @@ internal ImplementInterfaceCodeAction( { Service = service; Document = document; - Options = options; State = state; + Options = options; Abstractly = abstractly; _onlyRemaining = onlyRemaining; Explicitly = explicitly; @@ -61,7 +61,7 @@ internal ImplementInterfaceCodeAction( public static ImplementInterfaceCodeAction CreateImplementAbstractlyCodeAction( AbstractImplementInterfaceService service, Document document, - ImplementTypeOptions options, + ImplementTypeGenerationOptions options, State state) { return new ImplementInterfaceCodeAction(service, document, options, state, explicitly: false, abstractly: true, onlyRemaining: true, throughMember: null); @@ -70,7 +70,7 @@ public static ImplementInterfaceCodeAction CreateImplementAbstractlyCodeAction( public static ImplementInterfaceCodeAction CreateImplementCodeAction( AbstractImplementInterfaceService service, Document document, - ImplementTypeOptions options, + ImplementTypeGenerationOptions options, State state) { return new ImplementInterfaceCodeAction(service, document, options, state, explicitly: false, abstractly: false, onlyRemaining: true, throughMember: null); @@ -79,7 +79,7 @@ public static ImplementInterfaceCodeAction CreateImplementCodeAction( public static ImplementInterfaceCodeAction CreateImplementExplicitlyCodeAction( AbstractImplementInterfaceService service, Document document, - ImplementTypeOptions options, + ImplementTypeGenerationOptions options, State state) { return new ImplementInterfaceCodeAction(service, document, options, state, explicitly: true, abstractly: false, onlyRemaining: false, throughMember: null); @@ -88,7 +88,7 @@ public static ImplementInterfaceCodeAction CreateImplementExplicitlyCodeAction( public static ImplementInterfaceCodeAction CreateImplementThroughMemberCodeAction( AbstractImplementInterfaceService service, Document document, - ImplementTypeOptions options, + ImplementTypeGenerationOptions options, State state, ISymbol throughMember) { @@ -98,7 +98,7 @@ public static ImplementInterfaceCodeAction CreateImplementThroughMemberCodeActio public static ImplementInterfaceCodeAction CreateImplementRemainingExplicitlyCodeAction( AbstractImplementInterfaceService service, Document document, - ImplementTypeOptions options, + ImplementTypeGenerationOptions options, State state) { return new ImplementInterfaceCodeAction(service, document, options, state, explicitly: true, abstractly: false, onlyRemaining: true, throughMember: null); @@ -199,22 +199,24 @@ protected async Task GetUpdatedDocumentAsync( var isComImport = unimplementedMembers.Any(t => t.type.IsComImport); var memberDefinitions = GenerateMembers( - compilation, unimplementedMembers, Options.PropertyGenerationBehavior); + compilation, unimplementedMembers, Options.ImplementTypeOptions.PropertyGenerationBehavior); // Only group the members in the destination if the user wants that *and* // it's not a ComImport interface. Member ordering in ComImport interfaces // matters, so we don't want to much with them. var groupMembers = !isComImport && - Options.InsertionBehavior == ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind; + Options.ImplementTypeOptions.InsertionBehavior == ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind; return await CodeGenerator.AddMemberDeclarationsAsync( - result.Project.Solution, - classOrStructType, + new CodeGenerationSolutionContext( + result.Project.Solution, + new CodeGenerationContext( + contextLocation: classOrStructDecl.GetLocation(), + autoInsertionLocation: groupMembers, + sortMembers: groupMembers), + Options.FallbackOptions), + classOrStructType, memberDefinitions.Concat(extraMembers), - new CodeGenerationContext( - contextLocation: classOrStructDecl.GetLocation(), - autoInsertionLocation: groupMembers, - sortMembers: groupMembers), cancellationToken).ConfigureAwait(false); } diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs index 860c90e995a1b..17f2f09c5e0cc 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs +++ b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.DisposePatternCodeAction.cs @@ -84,12 +84,12 @@ private static bool ShouldImplementDisposePattern(State state, bool explicitly) return state.ClassOrStructType.FindImplementationForInterfaceMember(disposeMethod) == null; } - private class ImplementInterfaceWithDisposePatternCodeAction : ImplementInterfaceCodeAction + private sealed class ImplementInterfaceWithDisposePatternCodeAction : ImplementInterfaceCodeAction { public ImplementInterfaceWithDisposePatternCodeAction( AbstractImplementInterfaceService service, Document document, - ImplementTypeOptions options, + ImplementTypeGenerationOptions options, State state, bool explicitly, bool abstractly, @@ -100,7 +100,7 @@ public ImplementInterfaceWithDisposePatternCodeAction( public static ImplementInterfaceWithDisposePatternCodeAction CreateImplementWithDisposePatternCodeAction( AbstractImplementInterfaceService service, Document document, - ImplementTypeOptions options, + ImplementTypeGenerationOptions options, State state) { return new ImplementInterfaceWithDisposePatternCodeAction(service, document, options, state, explicitly: false, abstractly: false, throughMember: null); @@ -109,7 +109,7 @@ public static ImplementInterfaceWithDisposePatternCodeAction CreateImplementWith public static ImplementInterfaceWithDisposePatternCodeAction CreateImplementExplicitlyWithDisposePatternCodeAction( AbstractImplementInterfaceService service, Document document, - ImplementTypeOptions options, + ImplementTypeGenerationOptions options, State state) { return new ImplementInterfaceWithDisposePatternCodeAction(service, document, options, state, explicitly: true, abstractly: false, throughMember: null); @@ -158,12 +158,12 @@ public override async Task GetUpdatedDocumentAsync( sortMembers: false, autoInsertionLocation: false); - var codeGenerationOptions = await CodeGenerationOptions.FromDocumentAsync(context, document, cancellationToken).ConfigureAwait(false); + var options = await document.GetCodeGenerationOptionsAsync(Options.FallbackOptions, cancellationToken).ConfigureAwait(false); var typeDeclarationWithAllMembers = codeGenerator.AddMembers( typeDeclarationWithCoreMembers, disposableMethods, - codeGenerationOptions, + options.GetInfo(context, document.Project), cancellationToken); var docWithAllMembers = docWithCoreMembers.WithSyntaxRoot( diff --git a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.cs b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.cs index 0e2e1a871a7fe..0e36ab9be8275 100644 --- a/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.cs +++ b/src/Features/Core/Portable/ImplementInterface/AbstractImplementInterfaceService.cs @@ -36,7 +36,7 @@ protected AbstractImplementInterfaceService() protected abstract SyntaxNode AddCommentInsideIfStatement(SyntaxNode ifDisposingStatement, SyntaxTriviaList trivia); protected abstract SyntaxNode CreateFinalizer(SyntaxGenerator generator, INamedTypeSymbol classType, string disposeMethodDisplayString); - public async Task ImplementInterfaceAsync(Document document, ImplementTypeOptions options, SyntaxNode node, CancellationToken cancellationToken) + public async Task ImplementInterfaceAsync(Document document, ImplementTypeGenerationOptions options, SyntaxNode node, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.Refactoring_ImplementInterface, cancellationToken)) { @@ -57,13 +57,13 @@ public async Task ImplementInterfaceAsync(Document document, Implement } } - public ImmutableArray GetCodeActions(Document document, ImplementTypeOptions options, SemanticModel model, SyntaxNode node, CancellationToken cancellationToken) + public ImmutableArray GetCodeActions(Document document, ImplementTypeGenerationOptions options, SemanticModel model, SyntaxNode node, CancellationToken cancellationToken) { var state = State.Generate(this, document, model, node, cancellationToken); return GetActions(document, options, state).ToImmutableArray(); } - private IEnumerable GetActions(Document document, ImplementTypeOptions options, State state) + private IEnumerable GetActions(Document document, ImplementTypeGenerationOptions options, State state) { if (state == null) { diff --git a/src/Features/Core/Portable/ImplementInterface/IImplementInterfaceService.cs b/src/Features/Core/Portable/ImplementInterface/IImplementInterfaceService.cs index 6d572fbbcfd53..ba074a7f396d9 100644 --- a/src/Features/Core/Portable/ImplementInterface/IImplementInterfaceService.cs +++ b/src/Features/Core/Portable/ImplementInterface/IImplementInterfaceService.cs @@ -2,8 +2,6 @@ // 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.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -15,7 +13,7 @@ namespace Microsoft.CodeAnalysis.ImplementInterface { internal interface IImplementInterfaceService : ILanguageService { - Task ImplementInterfaceAsync(Document document, ImplementTypeOptions options, SyntaxNode node, CancellationToken cancellationToken); - ImmutableArray GetCodeActions(Document document, ImplementTypeOptions options, SemanticModel model, SyntaxNode node, CancellationToken cancellationToken); + Task ImplementInterfaceAsync(Document document, ImplementTypeGenerationOptions options, SyntaxNode node, CancellationToken cancellationToken); + ImmutableArray GetCodeActions(Document document, ImplementTypeGenerationOptions options, SemanticModel model, SyntaxNode node, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService.cs b/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService.cs new file mode 100644 index 0000000000000..bd60097b714b4 --- /dev/null +++ b/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService.cs @@ -0,0 +1,126 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.FindUsages; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.SymbolMapping; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.InheritanceMargin +{ + using SymbolKeyAndLineNumberArray = ImmutableArray<(SymbolKey, int lineNumber)>; + + internal abstract partial class AbstractInheritanceMarginService : IInheritanceMarginService + { + /// + /// Given the syntax nodes to search, + /// get all the method, event, property and type declaration syntax nodes. + /// + protected abstract ImmutableArray GetMembers(IEnumerable nodesToSearch); + + /// + /// Get the token that represents declaration node. + /// e.g. Identifier for method/property/event and this keyword for indexer. + /// + protected abstract SyntaxToken GetDeclarationToken(SyntaxNode declarationNode); + + protected abstract string GlobalImportsTitle { get; } + + public async ValueTask> GetInheritanceMemberItemsAsync( + Document document, + TextSpan spanToSearch, + bool includeGlobalImports, + CancellationToken cancellationToken) + { + var (remappedProject, symbolKeyAndLineNumbers) = await GetMemberSymbolKeysAsync(document, spanToSearch, cancellationToken).ConfigureAwait(false); + + // if we didn't remap the symbol to another project (e.g. remapping from a metadata-as-source symbol back to + // the originating project), then we're in teh same project and we should try to get global import + // information to display. + if (remappedProject != document.Project) + includeGlobalImports = false; + + if (!includeGlobalImports && symbolKeyAndLineNumbers.IsEmpty) + return ImmutableArray.Empty; + + return await GetInheritanceMemberItemAsync( + remappedProject, + documentForGlobalImports: includeGlobalImports ? document : null, + spanToSearch, + symbolKeyAndLineNumbers, + cancellationToken).ConfigureAwait(false); + } + + private async ValueTask<(Project remapped, SymbolKeyAndLineNumberArray symbolKeyAndLineNumbers)> GetMemberSymbolKeysAsync( + Document document, + TextSpan spanToSearch, + CancellationToken cancellationToken) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var allDeclarationNodes = GetMembers(root.DescendantNodes(spanToSearch)); + if (!allDeclarationNodes.IsEmpty) + { + var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + + var mappingService = document.Project.Solution.Workspace.Services.GetRequiredService(); + using var _ = ArrayBuilder<(SymbolKey symbolKey, int lineNumber)>.GetInstance(out var builder); + + Project? project = null; + + foreach (var memberDeclarationNode in allDeclarationNodes) + { + var member = semanticModel.GetDeclaredSymbol(memberDeclarationNode, cancellationToken); + if (member == null || !CanHaveInheritanceTarget(member)) + continue; + + // Use mapping service to find correct solution & symbol. (e.g. metadata symbol) + var mappingResult = await mappingService.MapSymbolAsync(document, member, cancellationToken).ConfigureAwait(false); + if (mappingResult == null) + continue; + + // All the symbols here are declared in the same document, they should belong to the same project. + // So here it is enough to get the project once. + project ??= mappingResult.Project; + builder.Add((mappingResult.Symbol.GetSymbolKey(cancellationToken), sourceText.Lines.GetLineFromPosition(GetDeclarationToken(memberDeclarationNode).SpanStart).LineNumber)); + } + + if (project != null) + return (project, builder.ToImmutable()); + } + + return (document.Project, SymbolKeyAndLineNumberArray.Empty); + } + + private static bool CanHaveInheritanceTarget(ISymbol symbol) + { + if (symbol is INamedTypeSymbol namedType) + { + return !symbol.IsStatic && namedType.TypeKind is TypeKind.Interface or TypeKind.Class or TypeKind.Struct; + } + + if (symbol is IEventSymbol or IPropertySymbol + or IMethodSymbol + { + MethodKind: MethodKind.Ordinary or MethodKind.ExplicitInterfaceImplementation or MethodKind.UserDefinedOperator or MethodKind.Conversion + }) + { + return true; + } + + return false; + } + } +} diff --git a/src/Features/Core/Portable/InheritanceMargin/InheritanceMarginServiceHelpers.cs b/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService_Helpers.cs similarity index 69% rename from src/Features/Core/Portable/InheritanceMargin/InheritanceMarginServiceHelpers.cs rename to src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService_Helpers.cs index fa720ed555fe8..5135e9b778db3 100644 --- a/src/Features/Core/Portable/InheritanceMargin/InheritanceMarginServiceHelpers.cs +++ b/src/Features/Core/Portable/InheritanceMargin/AbstractInheritanceMarginService_Helpers.cs @@ -2,44 +2,50 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Immutable; using System.Diagnostics; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindSymbols.FindReferences; using Microsoft.CodeAnalysis.FindUsages; -using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.InheritanceMargin { - internal static class InheritanceMarginServiceHelper + internal abstract partial class AbstractInheritanceMarginService { private static readonly SymbolDisplayFormat s_displayFormat = new( - globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.OmittedAsContaining, - typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes, - genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, - memberOptions: - SymbolDisplayMemberOptions.IncludeContainingType | - SymbolDisplayMemberOptions.IncludeExplicitInterface, - propertyStyle: SymbolDisplayPropertyStyle.NameOnly, - miscellaneousOptions: - SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers | - SymbolDisplayMiscellaneousOptions.UseSpecialTypes | - SymbolDisplayMiscellaneousOptions.UseErrorTypeSymbolName | - SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier); - - public static async ValueTask> GetInheritanceMemberItemAsync( - Solution solution, - ProjectId projectId, + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.OmittedAsContaining, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes, + genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters, + memberOptions: + SymbolDisplayMemberOptions.IncludeContainingType | + SymbolDisplayMemberOptions.IncludeExplicitInterface, + propertyStyle: SymbolDisplayPropertyStyle.NameOnly, + miscellaneousOptions: + SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers | + SymbolDisplayMiscellaneousOptions.UseSpecialTypes | + SymbolDisplayMiscellaneousOptions.UseErrorTypeSymbolName | + SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier); + + public async ValueTask> GetInheritanceMemberItemAsync( + Project project, + Document? documentForGlobalImports, + TextSpan spanToSearch, ImmutableArray<(SymbolKey symbolKey, int lineNumber)> symbolKeyAndLineNumbers, CancellationToken cancellationToken) { + var solution = project.Solution; var remoteClient = await RemoteHostClient.TryGetClientAsync(solution.Workspace.Services, cancellationToken).ConfigureAwait(false); if (remoteClient != null) { @@ -47,34 +53,44 @@ public static async ValueTask> // when a set of symbols is passed to remote process, those without inheritance targets would not be returned. // To match the returned inheritance targets to the line number, we need set an 'Id' when calling the remote process, // however, given the line number is just an int, setting up an int 'Id' for an int is quite useless, so just passed it to the remote process. - var result = await remoteClient.TryInvokeAsync>( + var result = await remoteClient.TryInvokeAsync>( solution, - (remoteInheritanceMarginService, solutionInfo, cancellationToken) => - remoteInheritanceMarginService.GetInheritanceMarginItemsAsync(solutionInfo, projectId, symbolKeyAndLineNumbers, cancellationToken), + (service, solutionInfo, cancellationToken) => + service.GetInheritanceMarginItemsAsync( + solutionInfo, project.Id, documentForGlobalImports?.Id, spanToSearch, symbolKeyAndLineNumbers, cancellationToken), cancellationToken).ConfigureAwait(false); if (!result.HasValue) { - return ImmutableArray.Empty; + return ImmutableArray.Empty; } return result.Value; } else { - return await GetInheritanceMemberItemInProcAsync(solution, projectId, symbolKeyAndLineNumbers, cancellationToken).ConfigureAwait(false); + return await GetInheritanceMemberItemInProcessAsync( + project, documentForGlobalImports, spanToSearch, symbolKeyAndLineNumbers, cancellationToken).ConfigureAwait(false); } } - private static async ValueTask> GetInheritanceMemberItemInProcAsync( - Solution solution, - ProjectId projectId, + private async ValueTask> GetInheritanceMemberItemInProcessAsync( + Project project, + Document? documentForGlobalImports, + TextSpan spanToSearch, ImmutableArray<(SymbolKey symbolKey, int lineNumber)> symbolKeyAndLineNumbers, CancellationToken cancellationToken) { - var project = solution.GetRequiredProject(projectId); + var solution = project.Solution; var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); - using var _ = ArrayBuilder.GetInstance(out var builder); + using var _ = ArrayBuilder.GetInstance(out var builder); + + if (documentForGlobalImports != null) + { + await AddInheritedGlobalImportsAsync( + documentForGlobalImports, spanToSearch, builder, cancellationToken).ConfigureAwait(false); + } + foreach (var (symbolKey, lineNumber) in symbolKeyAndLineNumbers) { var symbol = symbolKey.Resolve(compilation, cancellationToken: cancellationToken).Symbol; @@ -93,11 +109,122 @@ private static async ValueTask return builder.ToImmutable(); } + private async Task AddInheritedGlobalImportsAsync( + Document document, + TextSpan spanToSearch, + ArrayBuilder items, + CancellationToken cancellationToken) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + var syntaxFacts = document.GetRequiredLanguageService(); + var imports = syntaxFacts.GetImportsOfCompilationUnit(root); + + // Place the imports item on the start of the first import in the file. Or, if there is no import, then on + // the first line. + var spanStart = imports.Count > 0 ? imports[0].SpanStart : 0; + + // if that location doesn't intersect with the lines of interest, immediately bail out. + if (!spanToSearch.IntersectsWith(spanStart)) + return; + + var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); + var scopes = semanticModel.GetImportScopes(root.FullSpan.End, cancellationToken); + + // If we have global imports they would only be in the last scope in the scopes array. All other scopes + // correspond to inner scopes for either the compilation unit or namespace. + var lastScope = scopes.LastOrDefault(); + if (lastScope == null) + return; + + // Pull in any project level imports, or imports from other files (e.g. global usings). + var syntaxTree = semanticModel.SyntaxTree; + var nonLocalImports = lastScope.Imports + .WhereAsArray(i => i.DeclaringSyntaxReference?.SyntaxTree != syntaxTree) + .Sort((i1, i2) => + { + return (i1.DeclaringSyntaxReference, i2.DeclaringSyntaxReference) switch + { + // Both are project level imports. Sort by name of symbol imported. + (null, null) => i1.NamespaceOrType.ToDisplayString().CompareTo(i2.NamespaceOrType.ToDisplayString()), + // project level imports come first. + (null, not null) => -1, + (not null, null) => 1, + // both are from different files. Sort by file path first, then location in file if same file path. + ({ SyntaxTree: var syntaxTree1, Span: var span1 }, { SyntaxTree: var syntaxTree2, Span: var span2 }) + => syntaxTree1.FilePath != syntaxTree2.FilePath + ? StringComparer.OrdinalIgnoreCase.Compare(syntaxTree1.FilePath, syntaxTree2.FilePath) + : span1.CompareTo(span2), + }; + }); + + if (nonLocalImports.Length == 0) + return; + + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var lineNumber = text.Lines.GetLineFromPosition(spanStart).LineNumber; + + var projectState = document.Project.State; + var projectName = projectState.NameAndFlavor.name ?? projectState.Name; + var languageGlyph = document.Project.Language switch + { + LanguageNames.CSharp => Glyph.CSharpFile, + LanguageNames.VisualBasic => Glyph.BasicFile, + _ => throw ExceptionUtilities.UnexpectedValue(document.Project.Language), + }; + + foreach (var group in nonLocalImports.GroupBy(i => i.DeclaringSyntaxReference?.SyntaxTree)) + { + var groupSyntaxTree = group.Key; + if (groupSyntaxTree is null) + { + using var _ = ArrayBuilder.GetInstance(out var targetItems); + + foreach (var import in group) + { + var item = DefinitionItem.CreateNonNavigableItem(ImmutableArray.Empty, ImmutableArray.Empty); + targetItems.Add(new InheritanceTargetItem( + InheritanceRelationship.InheritedImport, item.Detach(), Glyph.None, languageGlyph, + import.NamespaceOrType.ToDisplayString(), projectName)); + } + + items.Add(new InheritanceMarginItem( + lineNumber, this.GlobalImportsTitle, ImmutableArray.Create(new TaggedText(TextTags.Text, this.GlobalImportsTitle)), + Glyph.Namespace, targetItems.ToImmutable())); + } + else + { + var destinationDocument = document.Project.Solution.GetDocument(groupSyntaxTree); + if (destinationDocument is null) + continue; + + using var _ = ArrayBuilder.GetInstance(out var targetItems); + + foreach (var import in group) + { + var item = DefinitionItem.Create( + ImmutableArray.Empty, ImmutableArray.Empty, + new DocumentSpan(destinationDocument, import.DeclaringSyntaxReference!.Span)); + targetItems.Add(new InheritanceTargetItem( + InheritanceRelationship.InheritedImport, item.Detach(), Glyph.None, languageGlyph, + import.NamespaceOrType.ToDisplayString(), projectName)); + } + + var filePath = groupSyntaxTree.FilePath; + var fileName = filePath == null ? null : IOUtilities.PerformIO(() => Path.GetFileName(filePath)) ?? filePath; + var taggedText = new TaggedText(TextTags.Text, string.Format(FeaturesResources.Directives_from_0, fileName)); + + items.Add(new InheritanceMarginItem( + lineNumber, this.GlobalImportsTitle, ImmutableArray.Create(taggedText), Glyph.Namespace, targetItems.ToImmutable())); + } + } + } + private static async ValueTask AddInheritanceMemberItemsForNamedTypeAsync( Solution solution, INamedTypeSymbol memberSymbol, int lineNumber, - ArrayBuilder builder, + ArrayBuilder builder, CancellationToken cancellationToken) { // Get all base types. @@ -157,7 +284,7 @@ private static async ValueTask AddInheritanceMemberItemsForMembersAsync( Solution solution, ISymbol memberSymbol, int lineNumber, - ArrayBuilder builder, + ArrayBuilder builder, CancellationToken cancellationToken) { if (memberSymbol.ContainingSymbol.IsInterfaceType()) @@ -210,7 +337,7 @@ private static async ValueTask AddInheritanceMemberItemsForMembersAsync( } } - private static async ValueTask CreateInheritanceMemberItemForInterfaceAsync( + private static async ValueTask CreateInheritanceMemberItemForInterfaceAsync( Solution solution, INamedTypeSymbol interfaceSymbol, int lineNumber, @@ -239,14 +366,15 @@ private static async ValueTask CreateInherita cancellationToken), cancellationToken) .ConfigureAwait(false); - return new SerializableInheritanceMarginItem( + return InheritanceMarginItem.CreateOrdered( lineNumber, + topLevelDisplayText: null, FindUsagesHelpers.GetDisplayParts(interfaceSymbol), interfaceSymbol.GetGlyph(), baseSymbolItems.Concat(derivedTypeItems)); } - private static async ValueTask CreateInheritanceMemberItemForInterfaceMemberAsync( + private static async ValueTask CreateInheritanceMemberItemForInterfaceMemberAsync( Solution solution, ISymbol memberSymbol, int lineNumber, @@ -263,14 +391,15 @@ private static async ValueTask CreateInherita InheritanceRelationship.ImplementingMember, cancellationToken), cancellationToken).ConfigureAwait(false); - return new SerializableInheritanceMarginItem( + return InheritanceMarginItem.CreateOrdered( lineNumber, + topLevelDisplayText: null, FindUsagesHelpers.GetDisplayParts(memberSymbol), memberSymbol.GetGlyph(), implementedMemberItems); } - private static async ValueTask CreateInheritanceItemForClassAndStructureAsync( + private static async ValueTask CreateInheritanceItemForClassAndStructureAsync( Solution solution, INamedTypeSymbol memberSymbol, int lineNumber, @@ -300,14 +429,15 @@ private static async ValueTask CreateInherita cancellationToken), cancellationToken) .ConfigureAwait(false); - return new SerializableInheritanceMarginItem( + return InheritanceMarginItem.CreateOrdered( lineNumber, + topLevelDisplayText: null, FindUsagesHelpers.GetDisplayParts(memberSymbol), memberSymbol.GetGlyph(), baseSymbolItems.Concat(derivedTypeItems)); } - private static async ValueTask CreateInheritanceMemberItemForClassOrStructMemberAsync( + private static async ValueTask CreateInheritanceMemberItemForClassOrStructMemberAsync( Solution solution, ISymbol memberSymbol, int lineNumber, @@ -346,14 +476,15 @@ private static async ValueTask CreateInherita InheritanceRelationship.OverridingMember, cancellationToken), cancellationToken).ConfigureAwait(false); - return new SerializableInheritanceMarginItem( + return InheritanceMarginItem.CreateOrdered( lineNumber, + topLevelDisplayText: null, FindUsagesHelpers.GetDisplayParts(memberSymbol), memberSymbol.GetGlyph(), implementedMemberItems.Concat(overridenMemberItems).Concat(overridingMemberItems)); } - private static async ValueTask CreateInheritanceItemAsync( + private static async ValueTask CreateInheritanceItemAsync( Solution solution, ISymbol targetSymbol, InheritanceRelationship inheritanceRelationship, @@ -367,12 +498,24 @@ private static async ValueTask CreateInherita var displayName = targetSymbol.ToDisplayString(s_displayFormat); - return new SerializableInheritanceTargetItem( + var projectState = definition.SourceSpans.Length > 0 + ? definition.SourceSpans[0].Document.Project.State + : null; + + var languageGlyph = targetSymbol.Language switch + { + LanguageNames.CSharp => Glyph.CSharpFile, + LanguageNames.VisualBasic => Glyph.BasicFile, + _ => throw ExceptionUtilities.UnexpectedValue(targetSymbol.Language), + }; + + return new InheritanceTargetItem( inheritanceRelationship, - // Id is used by FAR service for caching, it is not used in inheritance margin - SerializableDefinitionItem.Dehydrate(id: 0, definition), + definition.Detach(), targetSymbol.GetGlyph(), - displayName); + languageGlyph, + displayName, + projectState?.NameAndFlavor.name ?? projectState?.Name); } private static ImmutableArray GetImplementedSymbolsForTypeMember( diff --git a/src/EditorFeatures/Core/InheritanceMargin/IInheritanceMarginService.cs b/src/Features/Core/Portable/InheritanceMargin/IInheritanceMarginService.cs similarity index 95% rename from src/EditorFeatures/Core/InheritanceMargin/IInheritanceMarginService.cs rename to src/Features/Core/Portable/InheritanceMargin/IInheritanceMarginService.cs index 123b71ecf7aad..ee97a994fb97e 100644 --- a/src/EditorFeatures/Core/InheritanceMargin/IInheritanceMarginService.cs +++ b/src/Features/Core/Portable/InheritanceMargin/IInheritanceMarginService.cs @@ -18,6 +18,7 @@ internal interface IInheritanceMarginService : ILanguageService ValueTask> GetInheritanceMemberItemsAsync( Document document, TextSpan spanToSearch, + bool includeGlobalImports, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/InheritanceMargin/IRemoteInheritanceMarginService.cs b/src/Features/Core/Portable/InheritanceMargin/IRemoteInheritanceMarginService.cs index 64ecea4ec1348..794439cabe0e9 100644 --- a/src/Features/Core/Portable/InheritanceMargin/IRemoteInheritanceMarginService.cs +++ b/src/Features/Core/Portable/InheritanceMargin/IRemoteInheritanceMarginService.cs @@ -6,14 +6,17 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Remote; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.InheritanceMargin { internal interface IRemoteInheritanceMarginService { - ValueTask> GetInheritanceMarginItemsAsync( + ValueTask> GetInheritanceMarginItemsAsync( Checksum solutionChecksum, ProjectId projectId, + DocumentId? documentIdForGlobalImports, + TextSpan spanToSearch, ImmutableArray<(SymbolKey symbolKey, int lineNumber)> symbolKeyAndLineNumbers, CancellationToken cancellationToken); } diff --git a/src/EditorFeatures/Core/InheritanceMargin/InheritanceMarginItem.cs b/src/Features/Core/Portable/InheritanceMargin/InheritanceMarginItem.cs similarity index 52% rename from src/EditorFeatures/Core/InheritanceMargin/InheritanceMarginItem.cs rename to src/Features/Core/Portable/InheritanceMargin/InheritanceMarginItem.cs index a2eda3d3ff472..0bc5f0b4f0561 100644 --- a/src/EditorFeatures/Core/InheritanceMargin/InheritanceMarginItem.cs +++ b/src/Features/Core/Portable/InheritanceMargin/InheritanceMarginItem.cs @@ -3,53 +3,72 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Linq; +using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; namespace Microsoft.CodeAnalysis.InheritanceMargin { + [DataContract] internal readonly struct InheritanceMarginItem { /// /// Line number used to show the margin for the member. /// + [DataMember(Order = 0)] public readonly int LineNumber; + /// + /// Special display text to show when showing the 'hover' tip for a margin item. Used to override the default + /// text we show that says "'X' is inherited". Used currently for showing information about top-level-imports. + /// + [DataMember(Order = 1)] + public readonly string? TopLevelDisplayText; + /// /// Display texts for this member. /// + [DataMember(Order = 2)] public readonly ImmutableArray DisplayTexts; /// /// Member's glyph. /// + [DataMember(Order = 3)] public readonly Glyph Glyph; /// /// An array of the implementing/implemented/overriding/overridden targets for this member. /// + [DataMember(Order = 4)] public readonly ImmutableArray TargetItems; public InheritanceMarginItem( int lineNumber, + string? topLevelDisplayText, ImmutableArray displayTexts, Glyph glyph, ImmutableArray targetItems) { LineNumber = lineNumber; + TopLevelDisplayText = topLevelDisplayText; DisplayTexts = displayTexts; Glyph = glyph; TargetItems = targetItems; } - public static async ValueTask ConvertAsync( - Solution solution, - SerializableInheritanceMarginItem serializableItem, - CancellationToken cancellationToken) + public static InheritanceMarginItem CreateOrdered( + int lineNumber, + string? topLevelDisplayText, + ImmutableArray displayTexts, + Glyph glyph, + ImmutableArray targetItems) { - var targetItems = await serializableItem.TargetItems.SelectAsArrayAsync( - (item, _) => InheritanceTargetItem.ConvertAsync(solution, item, cancellationToken), cancellationToken).ConfigureAwait(false); - return new InheritanceMarginItem(serializableItem.LineNumber, serializableItem.DisplayTexts, serializableItem.Glyph, targetItems); + return new(lineNumber, topLevelDisplayText, displayTexts, glyph, Order(targetItems)); } + + public static ImmutableArray Order(ImmutableArray targetItems) + => targetItems.OrderBy(t => t.DisplayName).ThenByDescending(t => t.LanguageGlyph).ThenBy(t => t.ProjectName ?? "").ToImmutableArray(); } } diff --git a/src/Features/Core/Portable/InheritanceMargin/InheritanceRelationship.cs b/src/Features/Core/Portable/InheritanceMargin/InheritanceRelationship.cs index 7715f132eb745..b339c0d9a18b5 100644 --- a/src/Features/Core/Portable/InheritanceMargin/InheritanceRelationship.cs +++ b/src/Features/Core/Portable/InheritanceMargin/InheritanceRelationship.cs @@ -20,46 +20,51 @@ internal enum InheritanceRelationship /// /// Implented interfaces for class or struct. Shown as I↑ /// - ImplementedInterface = 1, + ImplementedInterface = 1 << 0, /// /// Base type for class or struct. Shown as O↑ /// - BaseType = 2, + BaseType = 1 << 1, /// /// Derived type for class or struct. Shown as O↓ /// - DerivedType = 4, + DerivedType = 1 << 2, /// /// Inherited interface for interface. Shown as I↑ /// - InheritedInterface = 8, + InheritedInterface = 1 << 3, /// /// Implementing class, struct and interface for interface. Shown as I↓ /// - ImplementingType = 16, + ImplementingType = 1 << 4, /// /// Implemented member for member in class or structure. Shown as I↑ /// - ImplementedMember = 32, + ImplementedMember = 1 << 5, /// /// Overridden member for member in class or structure. Shown as O↑ /// - OverriddenMember = 64, + OverriddenMember = 1 << 6, /// /// Overrrding member for member in class or structure. Shown as O↓ /// - OverridingMember = 128, + OverridingMember = 1 << 7, /// /// Implmenting member for member in interface. Shown as I↓ /// - ImplementingMember = 256 + ImplementingMember = 1 << 8, + + /// + /// An import directive inherited from the global scope. + /// + InheritedImport = 1 << 9, } } diff --git a/src/EditorFeatures/Core/InheritanceMargin/InheritanceTargetItem.cs b/src/Features/Core/Portable/InheritanceMargin/InheritanceTargetItem.cs similarity index 58% rename from src/EditorFeatures/Core/InheritanceMargin/InheritanceTargetItem.cs rename to src/Features/Core/Portable/InheritanceMargin/InheritanceTargetItem.cs index cb85e9bdec277..55e7032f71400 100644 --- a/src/EditorFeatures/Core/InheritanceMargin/InheritanceTargetItem.cs +++ b/src/Features/Core/Portable/InheritanceMargin/InheritanceTargetItem.cs @@ -2,6 +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. +using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindUsages; @@ -11,54 +12,60 @@ namespace Microsoft.CodeAnalysis.InheritanceMargin /// /// Information used to decided the margin image and responsible for performing navigations /// + [DataContract] internal readonly struct InheritanceTargetItem { /// /// Indicate the inheritance relationship between the target and member. /// + [DataMember(Order = 0)] public readonly InheritanceRelationship RelationToMember; /// /// DefinitionItem used to display the additional information and performs navigation. /// - public readonly DefinitionItem.DetachedDefinitionItem DefinitionItem; + [DataMember(Order = 1)] + public readonly DetachedDefinitionItem DefinitionItem; /// /// The glyph for this target. /// + [DataMember(Order = 2)] public readonly Glyph Glyph; + /// + /// The glyph for source language. Used to disambiguate results when multiple targets have the same name. + /// + [DataMember(Order = 3)] + public readonly Glyph LanguageGlyph; + /// /// The display name used in margin. /// + [DataMember(Order = 4)] public readonly string DisplayName; + /// + /// Name of the project the symbol is defined in (if known). Used to disambiguate results when multiple targets + /// have the same name and same language. + /// + [DataMember(Order = 5)] + public readonly string? ProjectName; + public InheritanceTargetItem( InheritanceRelationship relationToMember, - DefinitionItem.DetachedDefinitionItem definitionItem, + DetachedDefinitionItem definitionItem, Glyph glyph, - string displayName) + Glyph languageGlyph, + string displayName, + string? projectName) { RelationToMember = relationToMember; DefinitionItem = definitionItem; Glyph = glyph; + LanguageGlyph = languageGlyph; DisplayName = displayName; - } - - public static async ValueTask ConvertAsync( - Solution solution, - SerializableInheritanceTargetItem serializableItem, - CancellationToken cancellationToken) - { - var definitionItem = await serializableItem.DefinitionItem.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false); - - // detach this item so that it doesn't hold onto a full solution snapshot in other documents that - // are not getting updated. - return new InheritanceTargetItem( - serializableItem.RelationToMember, - definitionItem.Detach(), - serializableItem.Glyph, - serializableItem.DisplayName); + ProjectName = projectName; } } } diff --git a/src/Features/Core/Portable/InheritanceMargin/SerializableInheritanceMarginItem.cs b/src/Features/Core/Portable/InheritanceMargin/SerializableInheritanceMarginItem.cs deleted file mode 100644 index 7f4f1645e05e3..0000000000000 --- a/src/Features/Core/Portable/InheritanceMargin/SerializableInheritanceMarginItem.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Immutable; -using System.Runtime.Serialization; - -namespace Microsoft.CodeAnalysis.InheritanceMargin -{ - [DataContract] - internal readonly struct SerializableInheritanceMarginItem - { - [DataMember(Order = 0)] - public readonly int LineNumber; - - [DataMember(Order = 1)] - public readonly ImmutableArray DisplayTexts; - - [DataMember(Order = 2)] - public readonly Glyph Glyph; - - [DataMember(Order = 3)] - public readonly ImmutableArray TargetItems; - - public SerializableInheritanceMarginItem(int lineNumber, ImmutableArray displayTexts, Glyph glyph, ImmutableArray targetItems) - { - LineNumber = lineNumber; - DisplayTexts = displayTexts; - Glyph = glyph; - TargetItems = targetItems; - } - } -} diff --git a/src/Features/Core/Portable/InheritanceMargin/SerializableInheritanceTargetItem.cs b/src/Features/Core/Portable/InheritanceMargin/SerializableInheritanceTargetItem.cs deleted file mode 100644 index 28d17c78c9ffa..0000000000000 --- a/src/Features/Core/Portable/InheritanceMargin/SerializableInheritanceTargetItem.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.Serialization; -using Microsoft.CodeAnalysis.FindUsages; - -namespace Microsoft.CodeAnalysis.InheritanceMargin -{ - [DataContract] - internal readonly struct SerializableInheritanceTargetItem - { - [DataMember(Order = 0)] - public readonly InheritanceRelationship RelationToMember; - - [DataMember(Order = 1)] - public readonly SerializableDefinitionItem DefinitionItem; - - [DataMember(Order = 2)] - public readonly Glyph Glyph; - - [DataMember(Order = 3)] - public readonly string DisplayName; - - public SerializableInheritanceTargetItem( - InheritanceRelationship relationToMember, - SerializableDefinitionItem definitionItem, - Glyph glyph, - string displayName) - { - RelationToMember = relationToMember; - DefinitionItem = definitionItem; - Glyph = glyph; - DisplayName = displayName; - } - } -} diff --git a/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs b/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs index 01ef17c1bd039..286e2d0584a47 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractAddParameterCheckCodeRefactoringProvider.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Operations; @@ -69,7 +70,7 @@ protected override async Task> GetRefactoringsForAllP return ImmutableArray.Empty; // Great. The list has parameters that need null checks. Offer to add null checks for all. - return ImmutableArray.Create(new MyCodeAction( + return ImmutableArray.Create(CodeAction.Create( FeaturesResources.Add_null_checks_for_all_parameters, c => UpdateDocumentForRefactoringAsync(document, blockStatementOpt, listOfParametersOrdinals, parameterSpan, c), nameof(FeaturesResources.Add_null_checks_for_all_parameters))); @@ -82,6 +83,7 @@ protected override async Task> GetRefactoringsForSing SyntaxNode funcOrRecord, IMethodSymbol methodSymbol, IBlockOperation? blockStatementOpt, + CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); @@ -92,7 +94,7 @@ protected override async Task> GetRefactoringsForSing // Great. There was no null check. Offer to add one. using var result = TemporaryArray.Empty; - result.Add(new MyCodeAction( + result.Add(CodeAction.Create( FeaturesResources.Add_null_check, c => AddNullCheckAsync(document, parameterSyntax, parameter, funcOrRecord, methodSymbol, blockStatementOpt, c), nameof(FeaturesResources.Add_null_check))); @@ -102,12 +104,12 @@ protected override async Task> GetRefactoringsForSing // to place the checks. if (parameter.Type.SpecialType == SpecialType.System_String && !IsRecordDeclaration(funcOrRecord)) { - result.Add(new MyCodeAction( + result.Add(CodeAction.Create( FeaturesResources.Add_string_IsNullOrEmpty_check, c => AddStringCheckAsync(document, parameter, funcOrRecord, methodSymbol, blockStatementOpt, nameof(string.IsNullOrEmpty), c), nameof(FeaturesResources.Add_string_IsNullOrEmpty_check))); - result.Add(new MyCodeAction( + result.Add(CodeAction.Create( FeaturesResources.Add_string_IsNullOrWhiteSpace_check, c => AddStringCheckAsync(document, parameter, funcOrRecord, methodSymbol, blockStatementOpt, nameof(string.IsNullOrWhiteSpace), c), nameof(FeaturesResources.Add_string_IsNullOrWhiteSpace_check))); diff --git a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs index 877209aba34b9..9ea3c91ffca48 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs @@ -60,6 +60,7 @@ protected override async Task> GetRefactoringsForSing SyntaxNode constructorDeclaration, IMethodSymbol method, IBlockOperation? blockStatementOpt, + CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { // Only supported for constructor parameters. @@ -92,12 +93,12 @@ protected override async Task> GetRefactoringsForSing { return HandleExistingFieldOrProperty( document, parameter, constructorDeclaration, - blockStatementOpt, fieldOrProperty); + blockStatementOpt, fieldOrProperty, fallbackOptions); } return await HandleNoExistingFieldOrPropertyAsync( document, parameter, constructorDeclaration, - method, blockStatementOpt, rules, cancellationToken).ConfigureAwait(false); + method, blockStatementOpt, rules, fallbackOptions, cancellationToken).ConfigureAwait(false); } private async Task> HandleNoExistingFieldOrPropertyAsync( @@ -107,6 +108,7 @@ private async Task> HandleNoExistingFieldOrPropertyAs IMethodSymbol method, IBlockOperation? blockStatementOpt, ImmutableArray rules, + CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { // Didn't find a field/prop that this parameter could be assigned to. @@ -116,7 +118,7 @@ private async Task> HandleNoExistingFieldOrPropertyAs var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var (fieldAction, propertyAction) = AddSpecificParameterInitializationActions( - document, parameter, constructorDeclaration, blockStatementOpt, rules, options); + document, parameter, constructorDeclaration, blockStatementOpt, rules, options, fallbackOptions); // Check if the surrounding parameters are assigned to another field in this class. If so, offer to // make this parameter into a field as well. Otherwise, default to generating a property @@ -133,7 +135,7 @@ private async Task> HandleNoExistingFieldOrPropertyAs } var (allFieldsAction, allPropertiesAction) = AddAllParameterInitializationActions( - document, constructorDeclaration, method, blockStatementOpt, rules, options); + document, constructorDeclaration, method, blockStatementOpt, rules, options, fallbackOptions); if (allFieldsAction != null && allPropertiesAction != null) { @@ -158,7 +160,8 @@ private async Task> HandleNoExistingFieldOrPropertyAs IMethodSymbol method, IBlockOperation? blockStatementOpt, ImmutableArray rules, - DocumentOptionSet options) + DocumentOptionSet options, + CodeGenerationOptionsProvider fallbackOptions) { if (blockStatementOpt == null) return default; @@ -171,14 +174,16 @@ private async Task> HandleNoExistingFieldOrPropertyAs var fields = parameters.SelectAsArray(p => (ISymbol)CreateField(p, options, rules)); var properties = parameters.SelectAsArray(p => (ISymbol)CreateProperty(p, options, rules)); - var allFieldsAction = new MyCodeAction( + var allFieldsAction = CodeAction.Create( FeaturesResources.Create_and_assign_remaining_as_fields, c => AddAllSymbolInitializationsAsync( - document, constructorDeclaration, blockStatementOpt, parameters, fields, c)); - var allPropertiesAction = new MyCodeAction( + document, constructorDeclaration, blockStatementOpt, parameters, fields, fallbackOptions, c), + nameof(FeaturesResources.Create_and_assign_remaining_as_fields)); + var allPropertiesAction = CodeAction.Create( FeaturesResources.Create_and_assign_remaining_as_properties, c => AddAllSymbolInitializationsAsync( - document, constructorDeclaration, blockStatementOpt, parameters, properties, c)); + document, constructorDeclaration, blockStatementOpt, parameters, properties, fallbackOptions, c), + nameof(FeaturesResources.Create_and_assign_remaining_as_properties)); return (allFieldsAction, allPropertiesAction); } @@ -189,16 +194,19 @@ private async Task> HandleNoExistingFieldOrPropertyAs SyntaxNode constructorDeclaration, IBlockOperation? blockStatementOpt, ImmutableArray rules, - DocumentOptionSet options) + DocumentOptionSet options, + CodeGenerationOptionsProvider fallbackOptions) { var field = CreateField(parameter, options, rules); var property = CreateProperty(parameter, options, rules); - var fieldAction = new MyCodeAction( + var fieldAction = CodeAction.Create( string.Format(FeaturesResources.Create_and_assign_field_0, field.Name), - c => AddSingleSymbolInitializationAsync(document, constructorDeclaration, blockStatementOpt, parameter, field, c)); - var propertyAction = new MyCodeAction( + c => AddSingleSymbolInitializationAsync(document, constructorDeclaration, blockStatementOpt, parameter, field, fallbackOptions, c), + nameof(FeaturesResources.Create_and_assign_field_0) + "_" + field.Name); + var propertyAction = CodeAction.Create( string.Format(FeaturesResources.Create_and_assign_property_0, property.Name), - c => AddSingleSymbolInitializationAsync(document, constructorDeclaration, blockStatementOpt, parameter, property, c)); + c => AddSingleSymbolInitializationAsync(document, constructorDeclaration, blockStatementOpt, parameter, property, fallbackOptions, c), + nameof(FeaturesResources.Create_and_assign_property_0) + "_" + property.Name); return (fieldAction, propertyAction); } @@ -226,7 +234,8 @@ private static ImmutableArray GetParametersWithoutAssociatedMe return result.ToImmutable(); } - private ImmutableArray HandleExistingFieldOrProperty(Document document, IParameterSymbol parameter, SyntaxNode functionDeclaration, IBlockOperation? blockStatementOpt, ISymbol fieldOrProperty) + private ImmutableArray HandleExistingFieldOrProperty( + Document document, IParameterSymbol parameter, SyntaxNode functionDeclaration, IBlockOperation? blockStatementOpt, ISymbol fieldOrProperty, CodeGenerationOptionsProvider fallbackOptions) { // Found a field/property that this parameter should be assigned to. // Just offer the simple assignment to it. @@ -237,10 +246,11 @@ private ImmutableArray HandleExistingFieldOrProperty(Document docume var title = string.Format(resource, fieldOrProperty.Name); - return ImmutableArray.Create(new MyCodeAction( + return ImmutableArray.Create(CodeAction.Create( title, c => AddSingleSymbolInitializationAsync( - document, functionDeclaration, blockStatementOpt, parameter, fieldOrProperty, c))); + document, functionDeclaration, blockStatementOpt, parameter, fieldOrProperty, fallbackOptions, c), + title)); } private static ISymbol? TryFindSiblingFieldOrProperty(IParameterSymbol parameter, IBlockOperation? blockStatementOpt) @@ -359,6 +369,7 @@ private async Task AddAllSymbolInitializationsAsync( IBlockOperation? blockStatementOpt, ImmutableArray parameters, ImmutableArray fieldsOrProperties, + CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { Debug.Assert(parameters.Length >= 2); @@ -409,6 +420,7 @@ private async Task AddAllSymbolInitializationsAsync( currentBlockStatementOpt, currentParameter, fieldOrProperty, + fallbackOptions, cancellationToken).ConfigureAwait(false); } @@ -421,13 +433,14 @@ private async Task AddSingleSymbolInitializationAsync( IBlockOperation? blockStatementOpt, IParameterSymbol parameter, ISymbol fieldOrProperty, + CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var services = document.Project.Solution.Workspace.Services; var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, services); var generator = editor.Generator; - var preferences = await CodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var options = await document.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); var codeGenerator = document.GetRequiredLanguageService(); if (fieldOrProperty.ContainingType == null) @@ -454,14 +467,14 @@ private async Task AddSingleSymbolInitializationAsync( { return codeGenerator.AddProperty( currentTypeDecl, property, - preferences.GetOptions(GetAddContext(parameter, blockStatementOpt, typeDeclaration, cancellationToken)), + options.GetInfo(GetAddContext(parameter, blockStatementOpt, typeDeclaration, cancellationToken), document.Project), cancellationToken); } else if (fieldOrProperty is IFieldSymbol field) { return codeGenerator.AddField( currentTypeDecl, field, - preferences.GetOptions(GetAddContext(parameter, blockStatementOpt, typeDeclaration, cancellationToken)), + options.GetInfo(GetAddContext(parameter, blockStatementOpt, typeDeclaration, cancellationToken), document.Project), cancellationToken); } else diff --git a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs index afb66666f0c42..d61ca08e6813c 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeParameterCodeRefactoringProvider.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageServices; @@ -66,6 +67,7 @@ protected abstract Task> GetRefactoringsForSinglePara SyntaxNode functionDeclaration, IMethodSymbol methodSymbol, IBlockOperation? blockStatementOpt, + CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken); protected abstract void InsertStatement( @@ -122,7 +124,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte // Ok. Looks like the selected parameter could be refactored. Defer to subclass to // actually determine if there are any viable refactorings here. var refactorings = await GetRefactoringsForSingleParameterAsync( - document, selectedParameter, parameter, funcOrRecord, methodSymbol, blockStatementOpt, cancellationToken).ConfigureAwait(false); + document, selectedParameter, parameter, funcOrRecord, methodSymbol, blockStatementOpt, context.Options, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(refactorings, context.Span); } @@ -272,13 +274,5 @@ protected static bool IsFieldOrPropertyReference( fieldOrProperty = null; return false; } - - protected class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument, string? equivalenceKey = null) - : base(title, createChangedDocument, equivalenceKey) - { - } - } } } diff --git a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs index 3db807b76b50a..436286776be60 100644 --- a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs +++ b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.InlineContext.cs @@ -386,11 +386,11 @@ private static ImmutableDictionary ComputeRenameTable( private class LocalVariableDeclarationVisitor : OperationWalker { private readonly CancellationToken _cancellationToken; - private readonly HashSet _allSymbols; + private readonly HashSet _allSymbols = new(); + private LocalVariableDeclarationVisitor(CancellationToken cancellationToken) { _cancellationToken = cancellationToken; - _allSymbols = new HashSet(); } public static ImmutableHashSet GetAllSymbols( diff --git a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.cs b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.cs index fd1cf6cf010ff..05013fd119e96 100644 --- a/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.cs +++ b/src/Features/Core/Portable/InlineMethod/AbstractInlineMethodRefactoringProvider.cs @@ -253,7 +253,7 @@ private ImmutableArray GenerateCodeActions(Document document, IInvocationOperation invocationOperation) { var calleeMethodName = calleeMethodSymbol.ToNameDisplayString(); - var codeActionRemovesCallee = new MySolutionChangeAction( + var codeActionRemovesCallee = CodeAction.Create( string.Format(FeaturesResources.Inline_0, calleeMethodName), cancellationToken => InlineMethodAsync( @@ -265,9 +265,10 @@ private ImmutableArray GenerateCodeActions(Document document, callerMethodNode, inlineExpression, invocationOperation, - removeCalleeDeclarationNode: true, cancellationToken: cancellationToken)); + removeCalleeDeclarationNode: true, cancellationToken: cancellationToken), + nameof(FeaturesResources.Inline_0) + "_" + calleeMethodName); - var codeActionKeepsCallee = new MySolutionChangeAction( + var codeActionKeepsCallee = CodeAction.Create( string.Format(FeaturesResources.Inline_and_keep_0, calleeMethodName), cancellationToken => InlineMethodAsync( @@ -279,7 +280,8 @@ private ImmutableArray GenerateCodeActions(Document document, callerMethodNode, inlineExpression, invocationOperation, - removeCalleeDeclarationNode: false, cancellationToken: cancellationToken)); + removeCalleeDeclarationNode: false, cancellationToken: cancellationToken), + nameof(FeaturesResources.Inline_and_keep_0) + "_" + calleeMethodName); return ImmutableArray.Create(codeActionRemovesCallee, codeActionKeepsCallee); } @@ -589,15 +591,5 @@ private async Task GetChangedCallerAsync(Document document, return null; } - - private class MySolutionChangeAction : CodeAction.SolutionChangeAction - { - public MySolutionChangeAction( - string title, - Func> createChangedSolution) - : base(title, createChangedSolution, title) - { - } - } } } diff --git a/src/Features/Core/Portable/Intents/IntentDataProvider.cs b/src/Features/Core/Portable/Intents/IntentDataProvider.cs index bead3ee4be1f3..64cb421654ad4 100644 --- a/src/Features/Core/Portable/Intents/IntentDataProvider.cs +++ b/src/Features/Core/Portable/Intents/IntentDataProvider.cs @@ -5,11 +5,13 @@ using System; using System.Text.Json; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.ErrorReporting; namespace Microsoft.CodeAnalysis.Features.Intents { - internal class IntentDataProvider + internal sealed class IntentDataProvider { private static readonly Lazy s_serializerOptions = new Lazy(() => { @@ -21,11 +23,16 @@ internal class IntentDataProvider return serializerOptions; }); + public readonly CodeAndImportGenerationOptionsProvider FallbackOptions; + private readonly string? _serializedIntentData; - public IntentDataProvider(string? serializedIntentData) + public IntentDataProvider( + string? serializedIntentData, + CodeAndImportGenerationOptionsProvider fallbackOptions) { _serializedIntentData = serializedIntentData; + FallbackOptions = fallbackOptions; } public T? GetIntentData() where T : class diff --git a/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs b/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs index b775d534cdbbb..6bd43c8fdc30c 100644 --- a/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/IntroduceUsingStatement/AbstractIntroduceUsingStatementCodeRefactoringProvider.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.LanguageServices; @@ -41,9 +42,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte if (declarationSyntax != null) { context.RegisterRefactoring( - new MyCodeAction( + CodeAction.Create( CodeActionTitle, - cancellationToken => IntroduceUsingStatementAsync(document, declarationSyntax, cancellationToken)), + cancellationToken => IntroduceUsingStatementAsync(document, declarationSyntax, cancellationToken), + CodeActionTitle), declarationSyntax.Span); } } @@ -311,13 +313,5 @@ private static void AddReferencedLocalVariables( AddReferencedLocalVariables(referencedVariables, childNode, localVariables, semanticModel, syntaxFactsService, cancellationToken); } } - - private sealed class MyCodeAction : DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs index b3d4dd35fc439..49b032e9aa5a8 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterDocumentRewriter.cs @@ -31,14 +31,17 @@ private class IntroduceParameterDocumentRewriter private readonly IMethodSymbol _methodSymbol; private readonly SyntaxNode _containerMethod; private readonly IntroduceParameterCodeActionKind _actionKind; + private readonly CodeGenerationOptionsProvider _fallbackOptions; private readonly bool _allOccurrences; - public IntroduceParameterDocumentRewriter(AbstractIntroduceParameterService service, + public IntroduceParameterDocumentRewriter( + AbstractIntroduceParameterService service, Document originalDocument, TExpressionSyntax expression, IMethodSymbol methodSymbol, SyntaxNode containingMethod, IntroduceParameterCodeActionKind selectedCodeAction, + CodeGenerationOptionsProvider fallbackOptions, bool allOccurrences) { _service = service; @@ -51,6 +54,7 @@ public IntroduceParameterDocumentRewriter(AbstractIntroduceParameterService RewriteDocumentAsync(Compilation compilation, Document document, List invocations, CancellationToken cancellationToken) @@ -449,13 +453,14 @@ private async Task CreateMethodDeclarationAsync(SyntaxNode newStatem string? newMethodIdentifier, ITypeSymbol? typeSymbol, bool isTrampoline, CancellationToken cancellationToken) { var codeGenerationService = _originalDocument.GetRequiredLanguageService(); - var codeGenOptions = await CodeGenerationOptions.FromDocumentAsync(CodeGenerationContext.Default, _originalDocument, cancellationToken).ConfigureAwait(false); + var codeGenOptions = await _originalDocument.GetCodeGenerationOptionsAsync(_fallbackOptions, cancellationToken).ConfigureAwait(false); + var info = codeGenOptions.GetInfo(CodeGenerationContext.Default, _originalDocument.Project); var newMethod = isTrampoline ? CodeGenerationSymbolFactory.CreateMethodSymbol(_methodSymbol, name: newMethodIdentifier, parameters: validParameters, statements: ImmutableArray.Create(newStatement), returnType: typeSymbol) : CodeGenerationSymbolFactory.CreateMethodSymbol(_methodSymbol, statements: ImmutableArray.Create(newStatement), containingType: _methodSymbol.ContainingType); - var newMethodDeclaration = codeGenerationService.CreateMethodDeclaration(newMethod, CodeGenerationDestination.Unspecified, codeGenOptions, cancellationToken); + var newMethodDeclaration = codeGenerationService.CreateMethodDeclaration(newMethod, CodeGenerationDestination.Unspecified, info, cancellationToken); Contract.ThrowIfNull(newMethodDeclaration); return newMethodDeclaration; } diff --git a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs index d90a39faee03d..2ad593c5b1b09 100644 --- a/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs +++ b/src/Features/Core/Portable/IntroduceVariable/AbstractIntroduceParameterService.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; @@ -116,7 +117,7 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex return; } - var actions = await GetActionsAsync(document, expression, methodSymbol, containingMethod, cancellationToken).ConfigureAwait(false); + var actions = await GetActionsAsync(document, expression, methodSymbol, containingMethod, context.Options, cancellationToken).ConfigureAwait(false); if (actions is null) { @@ -146,7 +147,7 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex /// is a constructor. /// private async Task<(ImmutableArray actions, ImmutableArray actionsAllOccurrences)?> GetActionsAsync(Document document, - TExpressionSyntax expression, IMethodSymbol methodSymbol, SyntaxNode containingMethod, + TExpressionSyntax expression, IMethodSymbol methodSymbol, SyntaxNode containingMethod, CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var (shouldDisplay, containsClassExpression) = await ShouldExpressionDisplayCodeActionAsync( @@ -185,10 +186,12 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex return (actionsBuilder.ToImmutableAndClear(), actionsBuilderAllOccurrences.ToImmutableAndClear()); // Local function to create a code action with more ease - MyCodeAction CreateNewCodeAction(string actionName, bool allOccurrences, IntroduceParameterCodeActionKind selectedCodeAction) + CodeAction CreateNewCodeAction(string actionName, bool allOccurrences, IntroduceParameterCodeActionKind selectedCodeAction) { - return new MyCodeAction(actionName, c => IntroduceParameterAsync( - document, expression, methodSymbol, containingMethod, allOccurrences, selectedCodeAction, c)); + return CodeAction.Create( + actionName, + c => IntroduceParameterAsync(document, expression, methodSymbol, containingMethod, allOccurrences, selectedCodeAction, fallbackOptions, c), + actionName); } } @@ -243,13 +246,13 @@ MyCodeAction CreateNewCodeAction(string actionName, bool allOccurrences, Introdu /// private async Task IntroduceParameterAsync(Document originalDocument, TExpressionSyntax expression, IMethodSymbol methodSymbol, SyntaxNode containingMethod, bool allOccurrences, IntroduceParameterCodeActionKind selectedCodeAction, - CancellationToken cancellationToken) + CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var methodCallSites = await FindCallSitesAsync(originalDocument, methodSymbol, cancellationToken).ConfigureAwait(false); var modifiedSolution = originalDocument.Project.Solution; var rewriter = new IntroduceParameterDocumentRewriter(this, originalDocument, - expression, methodSymbol, containingMethod, selectedCodeAction, allOccurrences); + expression, methodSymbol, containingMethod, selectedCodeAction, fallbackOptions, allOccurrences); foreach (var (project, projectCallSites) in methodCallSites.GroupBy(kvp => kvp.Key.Project)) { @@ -318,14 +321,6 @@ await SymbolFinder.FindReferencesAsync( return methodCallSites; } - private class MyCodeAction : SolutionChangeAction - { - public MyCodeAction(string title, Func> createChangedSolution) - : base(title, createChangedSolution, title) - { - } - } - private enum IntroduceParameterCodeActionKind { Refactor, diff --git a/src/Features/Core/Portable/IntroduceVariable/IntroduceLocalForExpressionCodeRefactoringProvider.cs b/src/Features/Core/Portable/IntroduceVariable/IntroduceLocalForExpressionCodeRefactoringProvider.cs index b7724a4a7adf8..d2c221535baf8 100644 --- a/src/Features/Core/Portable/IntroduceVariable/IntroduceLocalForExpressionCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/IntroduceVariable/IntroduceLocalForExpressionCodeRefactoringProvider.cs @@ -53,9 +53,10 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex var nodeString = singleLineExpression.ToString(); context.RegisterRefactoring( - new MyCodeAction( + CodeAction.Create( string.Format(FeaturesResources.Introduce_local_for_0, nodeString), - c => IntroduceLocalAsync(document, expressionStatement, c)), + c => IntroduceLocalAsync(document, expressionStatement, c), + nameof(FeaturesResources.Introduce_local_for_0) + "_" + nodeString), expressionStatement.Span); } @@ -107,13 +108,5 @@ protected static async Task GenerateUniqueNameAsync( .WithAdditionalAnnotations(RenameAnnotation.Create()); return uniqueName; } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/IntroduceVariable/IntroduceVariableCodeRefactoringProvider.cs b/src/Features/Core/Portable/IntroduceVariable/IntroduceVariableCodeRefactoringProvider.cs index 17a2f266c62ee..0a567e53a1313 100644 --- a/src/Features/Core/Portable/IntroduceVariable/IntroduceVariableCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/IntroduceVariable/IntroduceVariableCodeRefactoringProvider.cs @@ -7,6 +7,7 @@ using System.Composition; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs b/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs index 59da6609cc87e..f076a466a50dc 100644 --- a/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InvertConditional/AbstractInvertConditionalCodeRefactoringProvider.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Immutable; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -10,16 +12,17 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.InvertConditional { internal abstract class AbstractInvertConditionalCodeRefactoringProvider - : CodeRefactoringProvider + : SyntaxEditorBasedCodeRefactoringProvider where TConditionalExpressionSyntax : SyntaxNode { protected abstract bool ShouldOffer(TConditionalExpressionSyntax conditional); + protected override ImmutableArray SupportedFixAllScopes => AllFixAllScopes; + public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, span, cancellationToken) = context; @@ -30,8 +33,11 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - context.RegisterRefactoring(new MyCodeAction( - c => InvertConditionalAsync(document, span, c)), + context.RegisterRefactoring( + CodeAction.Create( + FeaturesResources.Invert_conditional, + c => InvertConditionalAsync(document, conditional, c), + nameof(FeaturesResources.Invert_conditional)), conditional.Span); } @@ -39,12 +45,37 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte Document document, TextSpan span, CancellationToken cancellationToken) => await document.TryGetRelevantNodeAsync(span, cancellationToken).ConfigureAwait(false); - private static async Task InvertConditionalAsync( - Document document, TextSpan span, CancellationToken cancellationToken) + protected override async Task FixAllAsync(Document document, ImmutableArray fixAllSpans, SyntaxEditor editor, CancellationToken cancellationToken) { - var conditional = await FindConditionalAsync(document, span, cancellationToken).ConfigureAwait(false); - Contract.ThrowIfNull(conditional); + var originalRoot = editor.OriginalRoot; + + // Get all conditional nodes in the given fixAllSpans. + var conditionals = originalRoot.DescendantNodes().OfType() + .Where(node => fixAllSpans.Any(fixAllSpan => fixAllSpan.IntersectsWith(node.Span))); + + // We're going to be continually editing this tree. Track all the nodes we + // care about so we can find them across each edit. + document = document.WithSyntaxRoot(originalRoot.TrackNodes(conditionals)); + + // Process the conditional expressions in reverse so the nested conditionals are processed before the outer ones. + foreach (var originalConditional in conditionals.Reverse()) + { + // Only process conditionals fully within fixAllSpan + if (!fixAllSpans.Any(fixAllSpan => fixAllSpan.Contains(originalConditional.Span))) + continue; + + var currentRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var currentConditional = currentRoot.GetCurrentNodes(originalConditional).Single(); + document = await InvertConditionalAsync(document, currentConditional, cancellationToken).ConfigureAwait(false); + } + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + editor.ReplaceNode(originalRoot, root); + } + + private static async Task InvertConditionalAsync( + Document document, TConditionalExpressionSyntax conditional, CancellationToken cancellationToken) + { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); @@ -59,13 +90,5 @@ private static async Task InvertConditionalAsync( return document.WithSyntaxRoot(editor.GetChangedRoot()); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Invert_conditional, createChangedDocument, nameof(FeaturesResources.Invert_conditional)) - { - } - } } } diff --git a/src/Features/Core/Portable/InvertIf/AbstractInvertIfCodeRefactoringProvider.cs b/src/Features/Core/Portable/InvertIf/AbstractInvertIfCodeRefactoringProvider.cs index 4b8f208629a32..c1a316d806e61 100644 --- a/src/Features/Core/Portable/InvertIf/AbstractInvertIfCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InvertIf/AbstractInvertIfCodeRefactoringProvider.cs @@ -52,9 +52,12 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex return; } + var title = GetTitle(); context.RegisterRefactoring( - new MyCodeAction(GetTitle(), - c => InvertIfAsync(document, ifNode, c)), + CodeAction.Create( + title, + c => InvertIfAsync(document, ifNode, c), + title), ifNode.Span); } @@ -590,13 +593,5 @@ private SyntaxNode GetRootWithInvertIfStatement( throw ExceptionUtilities.UnexpectedValue(invertIfStyle); } } - - private sealed class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/InvertLogical/AbstractInvertLogicalCodeRefactoringProvider.cs b/src/Features/Core/Portable/InvertLogical/AbstractInvertLogicalCodeRefactoringProvider.cs index 895a7c5c1b6db..32127658f5ccd 100644 --- a/src/Features/Core/Portable/InvertLogical/AbstractInvertLogicalCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/InvertLogical/AbstractInvertLogicalCodeRefactoringProvider.cs @@ -71,10 +71,12 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } } + var title = GetTitle(syntaxKinds, expression.RawKind); context.RegisterRefactoring( - new MyCodeAction( - GetTitle(syntaxKinds, expression.RawKind), - c => InvertLogicalAsync(document, expression, c)), + CodeAction.Create( + title, + c => InvertLogicalAsync(document, expression, c), + title), expression.Span); } @@ -144,13 +146,5 @@ private static int InvertedKind(ISyntaxKindsService syntaxKinds, int binaryExprK => binaryExprKind == syntaxKinds.LogicalAndExpression ? syntaxKinds.LogicalOrExpression : syntaxKinds.LogicalAndExpression; - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs index 4e70c8f267af3..1784c37a94cd3 100644 --- a/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs +++ b/src/Features/Core/Portable/MakeMethodAsynchronous/AbstractMakeMethodAsynchronousCodeFixProvider.cs @@ -60,18 +60,24 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) var isEntryPoint = symbol != null && symbol.IsStatic && IsLikelyEntryPointName(symbol.Name, context.Document); // Offer to convert to a Task return type. + var taskTitle = GetMakeAsyncTaskFunctionResource(); context.RegisterCodeFix( - new MyCodeAction(GetMakeAsyncTaskFunctionResource(), c => FixNodeAsync( - context.Document, diagnostic, keepVoid: false, isEntryPoint, cancellationToken: c)), + CodeAction.Create( + taskTitle, + c => FixNodeAsync(context.Document, diagnostic, keepVoid: false, isEntryPoint, cancellationToken: c), + taskTitle), context.Diagnostics); // If it's a void returning method (and not an entry point), also offer to keep the void return type var isOrdinaryOrLocalFunction = symbol.IsOrdinaryMethodOrLocalFunction(); if (isOrdinaryOrLocalFunction && symbol.ReturnsVoid && !isEntryPoint) { + var asyncVoidTitle = GetMakeAsyncVoidFunctionResource(); context.RegisterCodeFix( - new MyCodeAction(GetMakeAsyncVoidFunctionResource(), c => FixNodeAsync( - context.Document, diagnostic, keepVoid: true, isEntryPoint: false, cancellationToken: c)), + CodeAction.Create( + asyncVoidTitle, + c => FixNodeAsync(context.Document, diagnostic, keepVoid: true, isEntryPoint: false, cancellationToken: c), + asyncVoidTitle), context.Diagnostics); } } @@ -229,13 +235,5 @@ protected static bool IsTaskLike(ITypeSymbol returnType, KnownTypes knownTypes) return false; } - - private class MyCodeAction : CodeAction.SolutionChangeAction - { - public MyCodeAction(string title, Func> createChangedSolution) - : base(title, createChangedSolution, equivalenceKey: title) - { - } - } } } diff --git a/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs b/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs index 2719460e484ad..674f90dbdd260 100644 --- a/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs +++ b/src/Features/Core/Portable/MakeMethodSynchronous/AbstractMakeMethodSynchronousCodeFixProvider.cs @@ -25,8 +25,6 @@ namespace Microsoft.CodeAnalysis.MakeMethodSynchronous { internal abstract class AbstractMakeMethodSynchronousCodeFixProvider : CodeFixProvider { - public static readonly string EquivalenceKey = FeaturesResources.Make_method_synchronous; - protected abstract bool IsAsyncSupportingFunctionSyntax(SyntaxNode node); protected abstract SyntaxNode RemoveAsyncTokenAndFixReturnType(IMethodSymbol methodSymbolOpt, SyntaxNode node, KnownTypes knownTypes); @@ -35,7 +33,10 @@ internal abstract class AbstractMakeMethodSynchronousCodeFixProvider : CodeFixPr public override Task RegisterCodeFixesAsync(CodeFixContext context) { context.RegisterCodeFix( - new MyCodeAction(c => FixNodeAsync(context.Document, context.Diagnostics.First(), c)), + CodeAction.Create( + FeaturesResources.Make_method_synchronous, + c => FixNodeAsync(context.Document, context.Diagnostics.First(), c), + nameof(FeaturesResources.Make_method_synchronous)), context.Diagnostics); return Task.CompletedTask; } @@ -250,13 +251,5 @@ private static void RemoveAwaitFromCallerIfPresent( } } } - - private class MyCodeAction : CodeAction.SolutionChangeAction - { - public MyCodeAction(Func> createChangedSolution) - : base(FeaturesResources.Make_method_synchronous, createChangedSolution, AbstractMakeMethodSynchronousCodeFixProvider.EquivalenceKey) - { - } - } } } diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs index c82d7633d3d7e..59d7a4a7fee9b 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.DocumentationComments; @@ -27,7 +28,7 @@ public async Task AddSourceToAsync( Document document, Compilation symbolCompilation, ISymbol symbol, - CodeCleanupOptions cleanupOptions, + CleanCodeGenerationOptions options, CancellationToken cancellationToken) { if (document == null) @@ -39,19 +40,21 @@ public async Task AddSourceToAsync( var rootNamespace = newSemanticModel.GetEnclosingNamespace(position: 0, cancellationToken); Contract.ThrowIfNull(rootNamespace); - var context = new CodeGenerationContext( - contextLocation: newSemanticModel.SyntaxTree.GetLocation(new TextSpan()), - generateMethodBodies: false, - generateDocumentationComments: true, - mergeAttributes: false, - autoInsertionLocation: false); + var context = new CodeGenerationSolutionContext( + document.Project.Solution, + new CodeGenerationContext( + contextLocation: newSemanticModel.SyntaxTree.GetLocation(new TextSpan()), + generateMethodBodies: false, + generateDocumentationComments: true, + mergeAttributes: false, + autoInsertionLocation: false), + new CodeAndImportGenerationOptions(options.GenerationOptions, options.CleanupOptions.AddImportOptions).CreateProvider()); // Add the interface of the symbol to the top of the root namespace document = await CodeGenerator.AddNamespaceOrTypeDeclarationAsync( - document.Project.Solution, + context, rootNamespace, CreateCodeGenerationSymbol(document, symbol), - context, cancellationToken).ConfigureAwait(false); document = await AddNullableRegionsAsync(document, cancellationToken).ConfigureAwait(false); @@ -65,12 +68,12 @@ public async Task AddSourceToAsync( var formattedDoc = await Formatter.FormatAsync( docWithAssemblyInfo, SpecializedCollections.SingletonEnumerable(node.FullSpan), - cleanupOptions.FormattingOptions, + options.CleanupOptions.FormattingOptions, GetFormattingRules(docWithAssemblyInfo), cancellationToken).ConfigureAwait(false); var reducers = GetReducers(); - return await Simplifier.ReduceAsync(formattedDoc, reducers, cleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); + return await Simplifier.ReduceAsync(formattedDoc, reducers, options.CleanupOptions.SimplifierOptions, cancellationToken).ConfigureAwait(false); } protected abstract Task AddNullableRegionsAsync(Document document, CancellationToken cancellationToken); diff --git a/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs b/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs index 345db808457d6..281db54655942 100644 --- a/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs +++ b/src/Features/Core/Portable/MetadataAsSource/DecompilationMetadataAsSourceFileProvider.cs @@ -91,7 +91,7 @@ public DecompilationMetadataAsSourceFileProvider() if (decompiledSourceService != null) { - temporaryDocument = await decompiledSourceService.AddSourceToAsync(temporaryDocument, compilation, symbol, refInfo.metadataReference, refInfo.assemblyLocation, options.CleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); + temporaryDocument = await decompiledSourceService.AddSourceToAsync(temporaryDocument, compilation, symbol, refInfo.metadataReference, refInfo.assemblyLocation, options.GenerationOptions.CleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); } else { @@ -107,7 +107,7 @@ public DecompilationMetadataAsSourceFileProvider() if (!useDecompiler) { var sourceFromMetadataService = temporaryDocument.Project.LanguageServices.GetRequiredService(); - temporaryDocument = await sourceFromMetadataService.AddSourceToAsync(temporaryDocument, compilation, symbol, options.CleanupOptions, cancellationToken).ConfigureAwait(false); + temporaryDocument = await sourceFromMetadataService.AddSourceToAsync(temporaryDocument, compilation, symbol, options.GenerationOptions, cancellationToken).ConfigureAwait(false); } // We have the content, so write it out to disk diff --git a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceService.cs b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceService.cs index 95edfc9fd9626..f41b070608b85 100644 --- a/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/IMetadataAsSourceService.cs @@ -2,11 +2,10 @@ // 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.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Simplification; @@ -23,8 +22,9 @@ internal interface IMetadataAsSourceService : ILanguageService /// The document to generate source into /// The in which is resolved. /// The symbol to generate source for + /// Options to use to generate and format the code. /// To cancel document operations /// The updated document - Task AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, CodeCleanupOptions cleanupOptions, CancellationToken cancellationToken = default); + Task AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, CleanCodeGenerationOptions options, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs index 8eb5e0578d265..f26073e5a4e5a 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceOptions.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; namespace Microsoft.CodeAnalysis.MetadataAsSource; @@ -10,16 +11,16 @@ namespace Microsoft.CodeAnalysis.MetadataAsSource; /// /// Options for metadata as source navigation /// -/// Options to use to prettify the generated document. +/// Options to use to prettify the generated document. /// to disallow decompiling code, which may /// result in signagures only being returned if there is no other non-decompilation option available /// Whether navigation should try to use the default Microsoft and /// Nuget symbol servers regardless of debugger settings internal readonly record struct MetadataAsSourceOptions( - CodeCleanupOptions CleanupOptions, + CleanCodeGenerationOptions GenerationOptions, bool NavigateToDecompiledSources = true, bool AlwaysUseDefaultSymbolServers = true) { public static MetadataAsSourceOptions GetDefault(HostLanguageServices languageServices) - => new(CleanupOptions: CodeCleanupOptions.GetDefault(languageServices)); + => new(GenerationOptions: CleanCodeGenerationOptions.GetDefault(languageServices)); } diff --git a/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.cs b/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.cs index 58f64598b9903..d11500464c0f8 100644 --- a/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceCodeRefactoringProvider.cs @@ -43,7 +43,11 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } context.RegisterRefactoring( - new MyCodeAction(c => MoveDeclarationNearReferenceAsync(document, declaration, c)), + CodeAction.CreateWithPriority( + CodeActionPriority.Low, + FeaturesResources.Move_declaration_near_reference, + c => MoveDeclarationNearReferenceAsync(document, declaration, c), + nameof(FeaturesResources.Move_declaration_near_reference)), declaration.Span); } @@ -53,15 +57,5 @@ private static async Task MoveDeclarationNearReferenceAsync( var service = document.GetRequiredLanguageService(); return await service.MoveDeclarationNearReferenceAsync(document, statement, cancellationToken).ConfigureAwait(false); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Move_declaration_near_reference, createChangedDocument, nameof(FeaturesResources.Move_declaration_near_reference)) - { - } - - internal override CodeActionPriority Priority => CodeActionPriority.Low; - } } } diff --git a/src/Features/Core/Portable/MoveStaticMembers/AbstractMoveStaticMembersRefactoringProvider.cs b/src/Features/Core/Portable/MoveStaticMembers/AbstractMoveStaticMembersRefactoringProvider.cs index 36305366bc243..d08745b5f997f 100644 --- a/src/Features/Core/Portable/MoveStaticMembers/AbstractMoveStaticMembersRefactoringProvider.cs +++ b/src/Features/Core/Portable/MoveStaticMembers/AbstractMoveStaticMembersRefactoringProvider.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.PullMemberUp; @@ -54,7 +55,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var syntaxFacts = document.GetRequiredLanguageService(); - var action = new MoveStaticMembersWithDialogCodeAction(document, span, service, selectedType, selectedMember: selectedMembers[0]); + var action = new MoveStaticMembersWithDialogCodeAction(document, span, service, selectedType, context.Options, selectedMember: selectedMembers[0]); context.RegisterRefactoring(action, selectedMembers[0].DeclaringSyntaxReferences[0].Span); } diff --git a/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs b/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs index f61c8ac6955dd..f3dc5a851c09e 100644 --- a/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/MoveStaticMembers/MoveStaticMembersWithDialogCodeAction.cs @@ -28,6 +28,7 @@ internal class MoveStaticMembersWithDialogCodeAction : CodeActionWithOptions private readonly ISymbol? _selectedMember; private readonly INamedTypeSymbol _selectedType; private readonly IMoveStaticMembersOptionsService _service; + private readonly CleanCodeGenerationOptionsProvider _fallbackOptions; public TextSpan Span { get; } public override string Title => FeaturesResources.Move_static_members_to_another_type; @@ -37,11 +38,13 @@ public MoveStaticMembersWithDialogCodeAction( TextSpan span, IMoveStaticMembersOptionsService service, INamedTypeSymbol selectedType, + CleanCodeGenerationOptionsProvider fallbackOptions, ISymbol? selectedMember = null) { _document = document; _service = service; _selectedType = selectedType; + _fallbackOptions = fallbackOptions; _selectedMember = selectedMember; Span = span; } @@ -95,6 +98,7 @@ protected override async Task> ComputeOperation _document.Folders, newType, _document, + _fallbackOptions, cancellationToken).ConfigureAwait(false); // get back type declaration in the newly created file @@ -118,7 +122,7 @@ protected override async Task> ComputeOperation .SelectAsArray(node => (semanticModel.GetDeclaredSymbol(node, cancellationToken), false)); var pullMembersUpOptions = PullMembersUpOptionsBuilder.BuildPullMembersUpOptions(newType, members); - var movedSolution = await MembersPuller.PullMembersUpAsync(sourceDoc, pullMembersUpOptions, cancellationToken).ConfigureAwait(false); + var movedSolution = await MembersPuller.PullMembersUpAsync(sourceDoc, pullMembersUpOptions, _fallbackOptions, cancellationToken).ConfigureAwait(false); return new CodeActionOperation[] { new ApplyChangesOperation(movedSolution) }; } diff --git a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs index fa2ecd65eb1de..94a2974f22c40 100644 --- a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs +++ b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceService.cs @@ -257,7 +257,7 @@ private static async Task MoveTypeToNamespaceAsync( document, moveSpan, MoveTypeOperationKind.MoveTypeNamespaceScope, - SyntaxFormattingOptions.CreateProvider(fallbackOptions), + fallbackOptions, cancellationToken).ConfigureAwait(false); var modifiedDocument = modifiedSolution.GetDocument(document.Id); diff --git a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs index 8eccb7250373a..c80a639e53d8d 100644 --- a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs +++ b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceCodeActionProvider.cs @@ -29,7 +29,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte { var (document, textSpan, cancellationToken) = context; var moveToNamespaceService = document.GetLanguageService(); - var actions = await moveToNamespaceService.GetCodeActionsAsync(document, textSpan, CodeCleanupOptions.CreateProvider(context.Options), cancellationToken).ConfigureAwait(false); + var actions = await moveToNamespaceService.GetCodeActionsAsync(document, textSpan, context.Options, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); } } diff --git a/src/Features/Core/Portable/NameTupleElement/AbstractNameTupleElementCodeRefactoringProvider.cs b/src/Features/Core/Portable/NameTupleElement/AbstractNameTupleElementCodeRefactoringProvider.cs index 1392b09d085fc..24502132948b0 100644 --- a/src/Features/Core/Portable/NameTupleElement/AbstractNameTupleElementCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/NameTupleElement/AbstractNameTupleElementCodeRefactoringProvider.cs @@ -31,9 +31,10 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } context.RegisterRefactoring( - new MyCodeAction( + CodeAction.Create( string.Format(FeaturesResources.Add_tuple_element_name_0, elementName), - c => AddNamedElementAsync(document, span, cancellationToken)), + c => AddNamedElementAsync(document, span, cancellationToken), + nameof(FeaturesResources.Add_tuple_element_name_0) + "_" + elementName), argument.Span); } @@ -87,13 +88,5 @@ private async Task AddNamedElementAsync(Document document, TextSpan sp var newRoot = root.ReplaceNode(argument, newArgument); return document.WithSyntaxRoot(newRoot); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/PdbSourceDocument/PdbFileLocatorService.cs b/src/Features/Core/Portable/PdbSourceDocument/PdbFileLocatorService.cs index 2c3c2f4c0cec3..0ab491b6372ad 100644 --- a/src/Features/Core/Portable/PdbSourceDocument/PdbFileLocatorService.cs +++ b/src/Features/Core/Portable/PdbSourceDocument/PdbFileLocatorService.cs @@ -35,7 +35,7 @@ public PdbFileLocatorService( public async Task GetDocumentDebugInfoReaderAsync(string dllPath, bool useDefaultSymbolServers, TelemetryMessage telemetry, CancellationToken cancellationToken) { - var dllStream = IOUtilities.PerformIO(() => File.OpenRead(dllPath)); + var dllStream = IOUtilities.PerformIO(() => ReadFileIfExists(dllPath)); if (dllStream is null) return null; @@ -45,7 +45,7 @@ public PdbFileLocatorService( try { // Try to load the pdb file from disk, or embedded - if (peReader.TryOpenAssociatedPortablePdb(dllPath, pdbPath => File.OpenRead(pdbPath), out var pdbReaderProvider, out var pdbFilePath)) + if (peReader.TryOpenAssociatedPortablePdb(dllPath, ReadFileIfExists, out var pdbReaderProvider, out var pdbFilePath)) { Contract.ThrowIfNull(pdbReaderProvider); @@ -126,6 +126,14 @@ public PdbFileLocatorService( } return result; + + static FileStream? ReadFileIfExists(string fileName) + { + if (File.Exists(fileName)) + return File.OpenRead(fileName); + + return null; + } } } } diff --git a/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentLoaderService.cs b/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentLoaderService.cs index 41ffad4b39984..8101b2ff5aed2 100644 --- a/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentLoaderService.cs +++ b/src/Features/Core/Portable/PdbSourceDocument/PdbSourceDocumentLoaderService.cs @@ -26,13 +26,13 @@ internal sealed class PdbSourceDocumentLoaderService : IPdbSourceDocumentLoaderS /// Lazy import ISourceLinkService because it can cause debugger /// binaries to be eagerly loaded even if they are never used. /// - private readonly Lazy _sourceLinkService; + private readonly Lazy? _sourceLinkService; private readonly IPdbSourceDocumentLogger? _logger; [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code")] public PdbSourceDocumentLoaderService( - [Import(AllowDefault = true)] Lazy sourceLinkService, + [Import(AllowDefault = true)] Lazy? sourceLinkService, [Import(AllowDefault = true)] IPdbSourceDocumentLogger? logger) { _sourceLinkService = sourceLinkService; @@ -128,7 +128,7 @@ public PdbSourceDocumentLoaderService( private async Task TryGetSourceLinkFileAsync(SourceDocument sourceDocument, Encoding encoding, TelemetryMessage telemetry, bool useExtendedTimeout, CancellationToken cancellationToken) { - if (sourceDocument.SourceLinkUrl is null || _sourceLinkService.Value is null) + if (sourceDocument.SourceLinkUrl is null || _sourceLinkService is null) return null; var timeout = useExtendedTimeout ? ExtendedSourceLinkTimeout : SourceLinkTimeout; diff --git a/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs index f5c769bc05864..425e87bc6d67d 100644 --- a/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs +++ b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs @@ -36,7 +36,12 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) var diagnostic = context.Diagnostics[0]; if (diagnostic.Properties.ContainsKey(PreferFrameworkTypeConstants.PreferFrameworkType)) { - context.RegisterCodeFix(new PreferFrameworkTypeCodeAction(GetDocumentUpdater(context)), context.Diagnostics); + context.RegisterCodeFix( + CodeAction.Create( + FeaturesResources.Use_framework_type, + GetDocumentUpdater(context), + nameof(FeaturesResources.Use_framework_type)), + context.Diagnostics); } return Task.CompletedTask; @@ -64,14 +69,5 @@ protected override async Task FixAllAsync( protected override bool IncludeDiagnosticDuringFixAll(Diagnostic diagnostic) => diagnostic.Properties.ContainsKey(PreferFrameworkTypeConstants.PreferFrameworkType); - - private class PreferFrameworkTypeCodeAction : CodeAction.DocumentChangeAction - { - public PreferFrameworkTypeCodeAction( - Func> createChangedDocument) - : base(FeaturesResources.Use_framework_type, createChangedDocument, FeaturesResources.Use_framework_type) - { - } - } } } diff --git a/src/Features/Core/Portable/PullMemberUp/AbstractPullMemberUpRefactoringProvider.cs b/src/Features/Core/Portable/PullMemberUp/AbstractPullMemberUpRefactoringProvider.cs index 54d7cd31d9ad3..39580abc1b7b5 100644 --- a/src/Features/Core/Portable/PullMemberUp/AbstractPullMemberUpRefactoringProvider.cs +++ b/src/Features/Core/Portable/PullMemberUp/AbstractPullMemberUpRefactoringProvider.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings.PullMemberUp.Dialog; using Microsoft.CodeAnalysis.PullMemberUp; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -65,8 +66,8 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte return; } - var allActions = allDestinations.Select(destination => MembersPuller.TryComputeCodeAction(document, selectedMember, destination)) - .WhereNotNull().Concat(new PullMemberUpWithDialogCodeAction(document, selectedMember, _service)) + var allActions = allDestinations.Select(destination => MembersPuller.TryComputeCodeAction(document, selectedMember, destination, context.Options)) + .WhereNotNull().Concat(new PullMemberUpWithDialogCodeAction(document, selectedMember, _service, context.Options)) .ToImmutableArray(); var nestedCodeAction = CodeActionWithNestedActions.Create( diff --git a/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.cs b/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.cs index b689df0bbe71c..11e8506369501 100644 --- a/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.cs +++ b/src/Features/Core/Portable/PullMemberUp/Dialog/PullMemberUpWithDialogCodeAction.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.CodeRefactorings.PullMemberUp.Dialog; using Microsoft.CodeAnalysis.PullMemberUp; using Roslyn.Utilities; @@ -14,7 +15,7 @@ namespace Microsoft.CodeAnalysis.CodeRefactorings.PullMemberUp { internal abstract partial class AbstractPullMemberUpRefactoringProvider { - private class PullMemberUpWithDialogCodeAction : CodeActionWithOptions + private sealed class PullMemberUpWithDialogCodeAction : CodeActionWithOptions { /// /// Member which user initially selects. It will be selected initially when the dialog pops up. @@ -22,17 +23,20 @@ private class PullMemberUpWithDialogCodeAction : CodeActionWithOptions private readonly ISymbol _selectedMember; private readonly Document _document; private readonly IPullMemberUpOptionsService _service; + private readonly CleanCodeGenerationOptionsProvider _fallbackOptions; public override string Title => FeaturesResources.Pull_members_up_to_base_type; public PullMemberUpWithDialogCodeAction( Document document, ISymbol selectedMember, - IPullMemberUpOptionsService service) + IPullMemberUpOptionsService service, + CleanCodeGenerationOptionsProvider fallbackOptions) { _document = document; _selectedMember = selectedMember; _service = service; + _fallbackOptions = fallbackOptions; } public override object GetOptions(CancellationToken cancellationToken) @@ -44,7 +48,7 @@ protected override async Task> ComputeOperation { if (options is PullMembersUpOptions pullMemberUpOptions) { - var changedSolution = await MembersPuller.PullMembersUpAsync(_document, pullMemberUpOptions, cancellationToken).ConfigureAwait(false); + var changedSolution = await MembersPuller.PullMembersUpAsync(_document, pullMemberUpOptions, _fallbackOptions, cancellationToken).ConfigureAwait(false); return new[] { new ApplyChangesOperation(changedSolution) }; } else diff --git a/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs b/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs index 3b871508ed55d..90218a305cf40 100644 --- a/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs +++ b/src/Features/Core/Portable/PullMemberUp/MembersPuller.cs @@ -37,7 +37,8 @@ internal static class MembersPuller public static CodeAction TryComputeCodeAction( Document document, ISymbol selectedMember, - INamedTypeSymbol destination) + INamedTypeSymbol destination, + CleanCodeGenerationOptionsProvider fallbackOptions) { var result = PullMembersUpOptionsBuilder.BuildPullMembersUpOptions(destination, ImmutableArray.Create((member: selectedMember, makeAbstract: false))); if (result.PullUpOperationNeedsToDoExtraChanges || @@ -49,20 +50,21 @@ public static CodeAction TryComputeCodeAction( var title = string.Format(FeaturesResources.Pull_0_up_to_1, selectedMember.Name, result.Destination.Name); return SolutionChangeAction.Create( title, - cancellationToken => PullMembersUpAsync(document, result, cancellationToken), + cancellationToken => PullMembersUpAsync(document, result, fallbackOptions, cancellationToken), title); } public static Task PullMembersUpAsync( Document document, PullMembersUpOptions pullMembersUpOptions, + CleanCodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { return pullMembersUpOptions.Destination.TypeKind switch { - TypeKind.Interface => PullMembersIntoInterfaceAsync(document, pullMembersUpOptions, document.Project.Solution, cancellationToken), + TypeKind.Interface => PullMembersIntoInterfaceAsync(document, pullMembersUpOptions, fallbackOptions, cancellationToken), // We can treat VB modules as a static class - TypeKind.Class or TypeKind.Module => PullMembersIntoClassAsync(document, pullMembersUpOptions, document.Project.Solution, cancellationToken), + TypeKind.Class or TypeKind.Module => PullMembersIntoClassAsync(document, pullMembersUpOptions, fallbackOptions, cancellationToken), _ => throw ExceptionUtilities.UnexpectedValue(pullMembersUpOptions.Destination), }; } @@ -88,16 +90,16 @@ private static IMethodSymbol MakePublicAccessor(IMethodSymbol getterOrSetter) private static async Task PullMembersIntoInterfaceAsync( Document document, PullMembersUpOptions pullMemberUpOptions, - Solution solution, + CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { + var solution = document.Project.Solution; var solutionEditor = new SolutionEditor(solution); var codeGenerationService = document.Project.LanguageServices.GetRequiredService(); var destinationSyntaxNode = await codeGenerationService.FindMostRelevantNameSpaceOrTypeDeclarationAsync( - solution, pullMemberUpOptions.Destination, CodeGenerationContext.Default, cancellationToken).ConfigureAwait(false); + solution, pullMemberUpOptions.Destination, location: null, cancellationToken).ConfigureAwait(false); var symbolToDeclarationsMap = await InitializeSymbolToDeclarationsMapAsync(pullMemberUpOptions, cancellationToken).ConfigureAwait(false); - var symbolsToPullUp = pullMemberUpOptions.MemberAnalysisResults. - SelectAsArray(analysisResult => GetSymbolsToPullUp(analysisResult)); + var symbolsToPullUp = pullMemberUpOptions.MemberAnalysisResults.SelectAsArray(GetSymbolsToPullUp); var destinationEditor = await solutionEditor.GetDocumentEditorAsync( solution.GetDocumentId(destinationSyntaxNode.SyntaxTree), @@ -108,8 +110,9 @@ private static async Task PullMembersIntoInterfaceAsync( generateMethodBodies: false, generateMembers: false); - var codeGenerationOptions = await CodeGenerationOptions.FromDocumentAsync(context, destinationEditor.OriginalDocument, cancellationToken).ConfigureAwait(false); - var destinationWithMembersAdded = codeGenerationService.AddMembers(destinationSyntaxNode, symbolsToPullUp, codeGenerationOptions, cancellationToken); + var options = await destinationEditor.OriginalDocument.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); + var info = options.GetInfo(context, document.Project); + var destinationWithMembersAdded = codeGenerationService.AddMembers(destinationSyntaxNode, symbolsToPullUp, info, cancellationToken); destinationEditor.ReplaceNode(destinationSyntaxNode, (syntaxNode, generator) => destinationWithMembersAdded); @@ -135,7 +138,7 @@ private static async Task PullMembersIntoInterfaceAsync( ChangeMemberToPublicAndNonStatic( codeGenerationService, originalMemberEditor, declaration, analysisResult.Member, - codeGenerationOptions, cancellationToken); + info, cancellationToken); } } } @@ -195,7 +198,7 @@ private static void ChangeMemberToPublicAndNonStatic( DocumentEditor editor, SyntaxNode memberDeclaration, ISymbol member, - CodeGenerationOptions options, + CodeGenerationContextInfo info, CancellationToken cancellationToken) { var modifiers = DeclarationModifiers.From(member).WithIsStatic(false); @@ -208,7 +211,7 @@ private static void ChangeMemberToPublicAndNonStatic( eventSymbol, memberDeclaration, modifiers, - options, + info, cancellationToken); } else @@ -224,7 +227,7 @@ private static void ChangeEventToPublicAndNonStatic( IEventSymbol eventSymbol, SyntaxNode eventDeclaration, DeclarationModifiers modifiers, - CodeGenerationOptions options, + CodeGenerationContextInfo info, CancellationToken cancellationToken) { var declaration = editor.Generator.GetDeclaration(eventDeclaration); @@ -246,8 +249,12 @@ private static void ChangeEventToPublicAndNonStatic( accessibility: Accessibility.Public, modifiers: modifiers); - var eventGenerationOptions = options.WithContext(new CodeGenerationContext(generateMethodBodies: false)); - var publicAndNonStaticSyntax = codeGenerationService.CreateEventDeclaration(publicAndNonStaticSymbol, CodeGenerationDestination.ClassType, eventGenerationOptions, cancellationToken); + var eventGenerationInfo = info.WithContext(new CodeGenerationContext( + null, + null, + generateMethodBodies: false)); + + var publicAndNonStaticSyntax = codeGenerationService.CreateEventDeclaration(publicAndNonStaticSymbol, CodeGenerationDestination.ClassType, eventGenerationInfo, cancellationToken); // Insert a new declaration and remove the original declaration editor.InsertAfter(declaration, publicAndNonStaticSyntax); editor.RemoveNode(eventDeclaration); @@ -263,14 +270,15 @@ private static void ChangeEventToPublicAndNonStatic( private static async Task PullMembersIntoClassAsync( Document document, PullMembersUpOptions result, - Solution solution, + CleanCodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { + var solution = document.Project.Solution; var solutionEditor = new SolutionEditor(solution); var codeGenerationService = document.Project.LanguageServices.GetRequiredService(); var destinationSyntaxNode = await codeGenerationService.FindMostRelevantNameSpaceOrTypeDeclarationAsync( - solution, result.Destination, CodeGenerationContext.Default, cancellationToken).ConfigureAwait(false); + solution, result.Destination, location: null, cancellationToken).ConfigureAwait(false); var destinationEditor = await solutionEditor.GetDocumentEditorAsync( solution.GetDocumentId(destinationSyntaxNode.SyntaxTree), @@ -293,14 +301,15 @@ private static async Task PullMembersIntoClassAsync( } }); - var context = new CodeGenerationContext(reuseSyntax: true, generateMethodBodies: false); + var context = new CodeGenerationContext( + reuseSyntax: true, + generateMethodBodies: false); + + var options = await destinationEditor.OriginalDocument.GetCleanCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); - // TODO: fallback options: https://github.com/dotnet/roslyn/issues/60794 - var codeGenOptions = await CodeGenerationOptions.FromDocumentAsync(context, destinationEditor.OriginalDocument, cancellationToken).ConfigureAwait(false); - var formattingOptions = await destinationEditor.OriginalDocument.GetSyntaxFormattingOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); - var importsPlacementOptions = await destinationEditor.OriginalDocument.GetAddImportPlacementOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var info = options.GenerationOptions.GetInfo(context, destinationEditor.OriginalDocument.Project); - var newDestination = codeGenerationService.AddMembers(destinationSyntaxNode, pullUpMembersSymbols, codeGenOptions, cancellationToken); + var newDestination = codeGenerationService.AddMembers(destinationSyntaxNode, pullUpMembersSymbols, info, cancellationToken); using var _ = PooledHashSet.GetInstance(out var sourceImports); var syntaxFacts = destinationEditor.OriginalDocument.GetRequiredLanguageService(); @@ -369,18 +378,18 @@ private static async Task PullMembersIntoClassAsync( node.GetCurrentNode(newDestination), sourceImports, generator, - importsPlacementOptions, + options.CleanupOptions.AddImportOptions, cancellationToken)); var removeImportsService = destinationEditor.OriginalDocument.GetRequiredLanguageService(); var destinationDocument = await removeImportsService.RemoveUnnecessaryImportsAsync( destinationEditor.GetChangedDocument(), node => node.HasAnnotation(s_annotation), - formattingOptions, + options.CleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); // Format whitespace trivia within the import statements we pull up - destinationDocument = await Formatter.FormatAsync(destinationDocument, s_annotation, formattingOptions, cancellationToken).ConfigureAwait(false); + destinationDocument = await Formatter.FormatAsync(destinationDocument, s_annotation, options.CleanupOptions.FormattingOptions, cancellationToken).ConfigureAwait(false); var destinationRoot = AddLeadingTriviaBeforeFirstMember( await destinationDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false), diff --git a/src/Features/Core/Portable/RemoveAsyncModifier/AbstractRemoveAsyncModifierCodeFixProvider.cs b/src/Features/Core/Portable/RemoveAsyncModifier/AbstractRemoveAsyncModifierCodeFixProvider.cs index 7fe36ff307677..529c5846e65c0 100644 --- a/src/Features/Core/Portable/RemoveAsyncModifier/AbstractRemoveAsyncModifierCodeFixProvider.cs +++ b/src/Features/Core/Portable/RemoveAsyncModifier/AbstractRemoveAsyncModifierCodeFixProvider.cs @@ -51,7 +51,12 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) if (ShouldOfferFix(methodSymbol.ReturnType, knownTypes)) { - context.RegisterCodeFix(new MyCodeAction(GetDocumentUpdater(context)), context.Diagnostics); + context.RegisterCodeFix( + CodeAction.Create( + FeaturesResources.Remove_async_modifier, + GetDocumentUpdater(context), + nameof(FeaturesResources.Remove_async_modifier)), + context.Diagnostics); } } @@ -246,13 +251,5 @@ static SyntaxNode QualifiedNameToMemberAccess(int qualifiedNameSyntaxKind, int m return expression; } } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Remove_async_modifier, createChangedDocument, FeaturesResources.Remove_async_modifier) - { - } - } } } diff --git a/src/Features/Core/Portable/RemoveUnusedVariable/AbstractRemoveUnusedVariableCodeFixProvider.cs b/src/Features/Core/Portable/RemoveUnusedVariable/AbstractRemoveUnusedVariableCodeFixProvider.cs index a7edd569713e0..a2435223bf191 100644 --- a/src/Features/Core/Portable/RemoveUnusedVariable/AbstractRemoveUnusedVariableCodeFixProvider.cs +++ b/src/Features/Core/Portable/RemoveUnusedVariable/AbstractRemoveUnusedVariableCodeFixProvider.cs @@ -47,7 +47,14 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var blockFacts = document.GetRequiredLanguageService(); if (ShouldOfferFixForLocalDeclaration(blockFacts, node)) - context.RegisterCodeFix(new MyCodeAction(GetDocumentUpdater(context)), diagnostic); + { + context.RegisterCodeFix( + CodeAction.Create( + FeaturesResources.Remove_unused_variable, + GetDocumentUpdater(context), + nameof(FeaturesResources.Remove_unused_variable)), + diagnostic); + } } protected override async Task FixAllAsync(Document document, ImmutableArray diagnostics, SyntaxEditor syntaxEditor, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) @@ -194,13 +201,5 @@ private void MergeNodesToRemove(HashSet nodesToRemove) } } } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Remove_unused_variable, createChangedDocument, FeaturesResources.Remove_unused_variable) - { - } - } } } diff --git a/src/Features/Core/Portable/ReplaceDocCommentTextWithTag/AbstractReplaceDocCommentTextWithTagCodeRefactoringProvider.cs b/src/Features/Core/Portable/ReplaceDocCommentTextWithTag/AbstractReplaceDocCommentTextWithTagCodeRefactoringProvider.cs index 76b8728c79add..22d25acc9a9c1 100644 --- a/src/Features/Core/Portable/ReplaceDocCommentTextWithTag/AbstractReplaceDocCommentTextWithTagCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ReplaceDocCommentTextWithTag/AbstractReplaceDocCommentTextWithTagCodeRefactoringProvider.cs @@ -156,9 +156,10 @@ private static void RegisterRefactoring( CodeRefactoringContext context, TextSpan expandedSpan, string replacement) { context.RegisterRefactoring( - new MyCodeAction( + CodeAction.Create( string.Format(FeaturesResources.Use_0, replacement), - c => ReplaceTextAsync(context.Document, expandedSpan, replacement, c)), + c => ReplaceTextAsync(context.Document, expandedSpan, replacement, c), + nameof(FeaturesResources.Use_0) + "_" + replacement), expandedSpan); } @@ -234,13 +235,5 @@ private static bool ShouldExpandSpanBackwardOneCharacter( return false; } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs b/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs index 8ef9f76dd1c26..5524959b6dad8 100644 --- a/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs @@ -72,7 +72,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var nameChanged = hasGetPrefix; // Looks good! - context.RegisterRefactoring(new ReplaceMethodWithPropertyCodeAction( + context.RegisterRefactoring(CodeAction.Create( string.Format(FeaturesResources.Replace_0_with_property, methodName), c => ReplaceMethodsWithPropertyAsync(document, propertyName, nameChanged, methodSymbol, setMethod: null, cancellationToken: c), methodName), @@ -85,7 +85,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var setMethod = FindSetMethod(methodSymbol); if (setMethod != null) { - context.RegisterRefactoring(new ReplaceMethodWithPropertyCodeAction( + context.RegisterRefactoring(CodeAction.Create( string.Format(FeaturesResources.Replace_0_and_1_with_property, methodName, setMethod.Name), c => ReplaceMethodsWithPropertyAsync(document, propertyName, nameChanged, methodSymbol, setMethod, cancellationToken: c), methodName + "-get/set"), @@ -491,13 +491,5 @@ public bool Equals([AllowNull] ReferenceLocation x, [AllowNull] ReferenceLocatio public int GetHashCode([DisallowNull] ReferenceLocation obj) => obj.Location.SourceSpan.GetHashCode(); - - private class ReplaceMethodWithPropertyCodeAction : CodeAction.SolutionChangeAction - { - public ReplaceMethodWithPropertyCodeAction(string title, Func> createChangedSolution, string equivalenceKey) - : base(title, createChangedSolution, equivalenceKey) - { - } - } } } diff --git a/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs b/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs index 85179d5c155d0..033f941ead4e3 100644 --- a/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs @@ -65,7 +65,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte : FeaturesResources.Replace_0_with_methods; context.RegisterRefactoring( - new ReplacePropertyWithMethodsCodeAction( + CodeAction.Create( string.Format(resourceString, propertyName), c => ReplacePropertyWithMethodsAsync(document, propertySymbol, c), propertyName), @@ -435,13 +435,5 @@ public bool Equals((IPropertySymbol property, ReferenceLocation location) x, (IP public int GetHashCode((IPropertySymbol property, ReferenceLocation location) obj) => obj.location.Location.SourceSpan.GetHashCode(); - - private class ReplacePropertyWithMethodsCodeAction : CodeAction.SolutionChangeAction - { - public ReplacePropertyWithMethodsCodeAction(string title, Func> createChangedSolution, string equivalenceKey) - : base(title, createChangedSolution, equivalenceKey) - { - } - } } } diff --git a/src/Features/Core/Portable/Shared/Utilities/CompilationAvailableEventSource.cs b/src/Features/Core/Portable/Shared/Utilities/CompilationAvailableEventSource.cs new file mode 100644 index 0000000000000..6e2597870d664 --- /dev/null +++ b/src/Features/Core/Portable/Shared/Utilities/CompilationAvailableEventSource.cs @@ -0,0 +1,101 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Remote; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Tagging; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Shared.Utilities +{ + /// + /// Helper type that can be used to ask for a to be produced in our OOP server for a + /// particular , asking for a callback to be executed when that has happened. Each time this + /// is asked for for a particular project, any existing outstanding work to produce a for + /// a prior will be cancelled. + /// + internal class CompilationAvailableEventSource : IDisposable + { + private readonly IAsynchronousOperationListener _asyncListener; + + /// + /// Cancellation tokens controlling background computation of the compilation. + /// + private readonly ReferenceCountedDisposable _cancellationSeries = new(new CancellationSeries()); + + public CompilationAvailableEventSource( + IAsynchronousOperationListener asyncListener) + { + _asyncListener = asyncListener; + } + + public void Dispose() + => _cancellationSeries.Dispose(); + + /// + /// Request that the compilation for be made available in our OOP server, calling back on + /// once that happens. Subsequence calls to this method will cancel + /// any outstanding requests in flight. + /// + public void EnsureCompilationAvailability(Project project, Action onCompilationAvailable) + { + if (project == null) + return; + + if (!project.SupportsCompilation) + return; + + using var cancellationSeries = _cancellationSeries.TryAddReference(); + if (cancellationSeries is null) + { + // Already in the process of disposing this instance + return; + } + + // Cancel any existing tasks that are computing the compilation and spawn a new one to compute + // it and notify any listening clients. + var cancellationToken = cancellationSeries.Target.CreateNext(); + + var token = _asyncListener.BeginAsyncOperation(nameof(EnsureCompilationAvailability)); + var task = Task.Run(async () => + { + // Support cancellation without throwing. + // + // We choose a long delay here so that we can avoid this work as long as the user is continually making + // changes to their code. During that time, features that use this are already kicking off fast work + // with frozen-partial semantics and we'd like that to not have to contend with more expensive work + // kicked off in OOP to compute full compilations. + await _asyncListener.Delay(DelayTimeSpan.NonFocus, cancellationToken).NoThrowAwaitableInternal(captureContext: false); + if (cancellationToken.IsCancellationRequested) + return; + + var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false); + if (client != null) + { + var result = await client.TryInvokeAsync( + project, + (service, solutionInfo, cancellationToken) => service.ComputeCompilationAsync(solutionInfo, project.Id, cancellationToken), + cancellationToken).ConfigureAwait(false); + + if (!result) + return; + } + else + { + // if we can't get the client, just compute the compilation locally and fire the event once we have it. + await CompilationAvailableHelpers.ComputeCompilationInCurrentProcessAsync(project, cancellationToken).ConfigureAwait(false); + } + + // now that we know we have an full compilation, let the caller know so it can do whatever it needs in + // response. + onCompilationAvailable(); + }, cancellationToken); + task.CompletesAsyncOperation(token); + } + } +} diff --git a/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs b/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs index 84d7ddde080cd..3d32897ca3a3c 100644 --- a/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs +++ b/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs @@ -26,17 +26,18 @@ namespace Microsoft.CodeAnalysis.Shared.Utilities { internal static class ExtractTypeHelpers { - public static async Task<(Document containingDocument, SyntaxAnnotation typeAnnotation)> AddTypeToExistingFileAsync(Document document, INamedTypeSymbol newType, AnnotatedSymbolMapping symbolMapping, CancellationToken cancellationToken) + public static async Task<(Document containingDocument, SyntaxAnnotation typeAnnotation)> AddTypeToExistingFileAsync(Document document, INamedTypeSymbol newType, AnnotatedSymbolMapping symbolMapping, CodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var originalRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var typeDeclaration = originalRoot.GetAnnotatedNodes(symbolMapping.TypeNodeAnnotation).Single(); var editor = new SyntaxEditor(originalRoot, symbolMapping.AnnotatedSolution.Workspace.Services); var context = new CodeGenerationContext(generateMethodBodies: true); - var options = await CodeGenerationOptions.FromDocumentAsync(context, document, cancellationToken).ConfigureAwait(false); + var options = await document.GetCodeGenerationOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); + var info = options.GetInfo(context, document.Project); var codeGenService = document.GetRequiredLanguageService(); - var newTypeNode = codeGenService.CreateNamedTypeDeclaration(newType, CodeGenerationDestination.Unspecified, options, cancellationToken) + var newTypeNode = codeGenService.CreateNamedTypeDeclaration(newType, CodeGenerationDestination.Unspecified, info, cancellationToken) .WithAdditionalAnnotations(SimplificationHelpers.SimplifyModuleNameAnnotation); var typeAnnotation = new SyntaxAnnotation(); @@ -56,6 +57,7 @@ internal static class ExtractTypeHelpers IEnumerable folders, INamedTypeSymbol newSymbol, Document hintDocument, + CleanCodeGenerationOptionsProvider fallbackOptions, CancellationToken cancellationToken) { var newDocumentId = DocumentId.CreateNewId(projectId, debugName: fileName); @@ -82,14 +84,15 @@ internal static class ExtractTypeHelpers var namespaceParts = namespaceWithoutRoot.Split('.').Where(s => !string.IsNullOrEmpty(s)); var newTypeDocument = await CodeGenerator.AddNamespaceOrTypeDeclarationAsync( - newDocument.Project.Solution, + new CodeGenerationSolutionContext( + newDocument.Project.Solution, + context, + fallbackOptions), newSemanticModel.GetEnclosingNamespace(0, cancellationToken), newSymbol.GenerateRootNamespaceOrType(namespaceParts.ToArray()), - context, cancellationToken).ConfigureAwait(false); - // TODO: fallback options: https://github.com/dotnet/roslyn/issues/60794 - var newCleanupOptions = await newTypeDocument.GetCodeCleanupOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); + var newCleanupOptions = await newTypeDocument.GetCodeCleanupOptionsAsync(fallbackOptions, cancellationToken).ConfigureAwait(false); var formattingService = newTypeDocument.GetLanguageService(); if (formattingService is not null) diff --git a/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeCodeFixProvider.cs b/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeCodeFixProvider.cs index 6387bf504d00b..f9d482283912a 100644 --- a/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeCodeFixProvider.cs +++ b/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeCodeFixProvider.cs @@ -2,8 +2,6 @@ // 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.Collections.Generic; using System.Collections.Immutable; @@ -20,35 +18,33 @@ namespace Microsoft.CodeAnalysis.SimplifyThisOrMe { - internal abstract partial class AbstractSimplifyThisOrMeCodeFixProvider< - TMemberAccessExpressionSyntax> + internal abstract partial class AbstractSimplifyThisOrMeCodeFixProvider : SyntaxEditorBasedCodeFixProvider where TMemberAccessExpressionSyntax : SyntaxNode { - protected AbstractSimplifyThisOrMeCodeFixProvider() - { - } - protected abstract string GetTitle(); + protected abstract SyntaxNode Rewrite(SyntaxNode root, ISet memberAccessNodes); public sealed override ImmutableArray FixableDiagnosticIds { get; } = - ImmutableArray.Create(IDEDiagnosticIds.RemoveQualificationDiagnosticId); + ImmutableArray.Create(IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId); public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { - context.RegisterCodeFix(new MyCodeAction( - GetTitle(), - GetDocumentUpdater(context), - IDEDiagnosticIds.RemoveQualificationDiagnosticId), context.Diagnostics); + context.RegisterCodeFix( + CodeAction.Create( + GetTitle(), + GetDocumentUpdater(context), + IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId), + context.Diagnostics); return Task.CompletedTask; } - protected override async Task FixAllAsync( + protected sealed override async Task FixAllAsync( Document document, ImmutableArray diagnostics, SyntaxEditor editor, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken) { - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetLanguageService(); @@ -58,16 +54,5 @@ protected override async Task FixAllAsync( var newRoot = Rewrite(root, memberAccessNodes); editor.ReplaceNode(root, newRoot); } - - protected abstract SyntaxNode Rewrite(SyntaxNode root, ISet memberAccessNodes); - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction( - string title, Func> createChangedDocument, string equivalenceKey) - : base(title, createChangedDocument, equivalenceKey) - { - } - } } } diff --git a/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs b/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs index 74d29d3be55fd..3903a1a4217f0 100644 --- a/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/SimplifyThisOrMe/AbstractSimplifyThisOrMeDiagnosticAnalyzer.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.QualifyMemberAccess; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Simplification.Simplifiers; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.SimplifyThisOrMe @@ -28,85 +29,56 @@ internal abstract class AbstractSimplifyThisOrMeDiagnosticAnalyzer< where TMemberAccessExpressionSyntax : TExpressionSyntax where TSimplifierOptions : SimplifierOptions { - private readonly ImmutableArray _kindsOfInterest; - protected AbstractSimplifyThisOrMeDiagnosticAnalyzer() - : base(IDEDiagnosticIds.RemoveQualificationDiagnosticId, + : base(IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId, EnforceOnBuildValues.RemoveQualification, ImmutableHashSet.Create(CodeStyleOptions2.QualifyFieldAccess, CodeStyleOptions2.QualifyPropertyAccess, CodeStyleOptions2.QualifyMethodAccess, CodeStyleOptions2.QualifyEventAccess), new LocalizableResourceString(nameof(FeaturesResources.Remove_qualification), FeaturesResources.ResourceManager, typeof(FeaturesResources)), new LocalizableResourceString(nameof(WorkspacesResources.Name_can_be_simplified), WorkspacesResources.ResourceManager, typeof(WorkspacesResources)), isUnnecessary: true) { - var syntaxKinds = GetSyntaxFacts().SyntaxKinds; - _kindsOfInterest = ImmutableArray.Create( - syntaxKinds.Convert(syntaxKinds.ThisExpression)); } - protected abstract ISyntaxFacts GetSyntaxFacts(); + protected abstract ISyntaxKinds SyntaxKinds { get; } + protected abstract TSimplifierOptions GetSimplifierOptions(AnalyzerOptions options, SyntaxTree syntaxTree); - protected abstract bool CanSimplifyTypeNameExpression( - SemanticModel model, TMemberAccessExpressionSyntax memberAccess, TSimplifierOptions options, out TextSpan issueSpan, CancellationToken cancellationToken); + protected abstract AbstractMemberAccessExpressionSimplifier Simplifier { get; } - public override DiagnosticAnalyzerCategory GetAnalyzerCategory() + public sealed override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; - protected override void InitializeWorker(AnalysisContext context) - => context.RegisterSyntaxNodeAction(AnalyzeNode, _kindsOfInterest); - - protected abstract TSimplifierOptions GetSimplifierOptions(AnalyzerOptions options, SyntaxTree syntaxTree); + protected sealed override void InitializeWorker(AnalysisContext context) + => context.RegisterSyntaxNodeAction(AnalyzeNode, this.SyntaxKinds.Convert(this.SyntaxKinds.ThisExpression)); private void AnalyzeNode(SyntaxNodeAnalysisContext context) { var cancellationToken = context.CancellationToken; - var node = (TThisExpressionSyntax)context.Node; + var node = context.Node; + var semanticModel = context.SemanticModel; - if (node.Parent is not TMemberAccessExpressionSyntax expr) - { + if (node.Parent is not TMemberAccessExpressionSyntax memberAccessExpression) return; - } var syntaxTree = node.SyntaxTree; - var simplifierOptions = GetSimplifierOptions(context.Options, syntaxTree); - var model = context.SemanticModel; - if (!CanSimplifyTypeNameExpression( - model, expr, simplifierOptions, out var issueSpan, cancellationToken)) - { - return; - } - - if (model.SyntaxTree.OverlapsHiddenPosition(issueSpan, cancellationToken)) - { - return; - } - - var symbolInfo = model.GetSymbolInfo(expr, cancellationToken); - if (symbolInfo.Symbol == null) + if (!this.Simplifier.ShouldSimplifyThisMemberAccessExpression( + memberAccessExpression, semanticModel, simplifierOptions, out var thisExpression, out var severity, cancellationToken)) { return; } - var optionValue = simplifierOptions.QualifyMemberAccess(symbolInfo.Symbol.Kind); - if (optionValue == null) - { - return; - } - - var severity = optionValue.Notification.Severity; var builder = ImmutableDictionary.CreateBuilder(); // used so we can provide a link in the preview to the options page. This value is // hard-coded there to be the one that will go to the code-style page. builder["OptionName"] = nameof(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration); - builder["OptionLanguage"] = model.Language; - - var diagnostic = DiagnosticHelper.Create( - Descriptor, syntaxTree.GetLocation(issueSpan), severity, - ImmutableArray.Create(expr.GetLocation()), builder.ToImmutable()); + builder["OptionLanguage"] = semanticModel.Language; - context.ReportDiagnostic(diagnostic); + context.ReportDiagnostic(DiagnosticHelper.Create( + Descriptor, thisExpression.GetLocation(), severity, + ImmutableArray.Create(memberAccessExpression.GetLocation()), + builder.ToImmutable())); } } } diff --git a/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs b/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs index 3cf4e92da0378..4b11dab8d3a37 100644 --- a/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs +++ b/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs @@ -90,10 +90,12 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var syntaxFacts = document.GetLanguageService(); var title = GetTitle(diagnosticId, syntaxFacts.ConvertToSingleLine(node).ToString()); - context.RegisterCodeFix(new MyCodeAction( - title, - GetDocumentUpdater(context), - diagnosticId), context.Diagnostics); + context.RegisterCodeFix( + CodeAction.Create( + title, + GetDocumentUpdater(context), + diagnosticId), + context.Diagnostics); } protected override async Task FixAllAsync( @@ -131,14 +133,5 @@ private bool CanSimplifyTypeNameExpression(SemanticModel model, SyntaxNode node, return issueSpan.Equals(span); } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction( - string title, Func> createChangedDocument, string equivalenceKey) - : base(title, createChangedDocument, equivalenceKey) - { - } - } } } diff --git a/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerRegistrationService.cs b/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerRegistrationService.cs index 852981b0f8aaf..b5def68057044 100644 --- a/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerRegistrationService.cs +++ b/src/Features/Core/Portable/SolutionCrawler/SolutionCrawlerRegistrationService.cs @@ -22,8 +22,8 @@ internal partial class SolutionCrawlerRegistrationService : ISolutionCrawlerRegi { private const string Default = "*"; - private readonly object _gate; - private readonly SolutionCrawlerProgressReporter _progressReporter; + private readonly object _gate = new(); + private readonly SolutionCrawlerProgressReporter _progressReporter = new(); private readonly IAsynchronousOperationListener _listener; private readonly Dictionary _documentWorkCoordinatorMap; @@ -36,15 +36,11 @@ public SolutionCrawlerRegistrationService( [ImportMany] IEnumerable> analyzerProviders, IAsynchronousOperationListenerProvider listenerProvider) { - _gate = new object(); - _analyzerProviders = analyzerProviders.GroupBy(kv => kv.Metadata.Name).ToImmutableDictionary(g => g.Key, g => g.ToImmutableArray()); AssertAnalyzerProviders(_analyzerProviders); _documentWorkCoordinatorMap = new Dictionary(ReferenceEqualityComparer.Instance); _listener = listenerProvider.GetListener(FeatureAttribute.SolutionCrawler); - - _progressReporter = new SolutionCrawlerProgressReporter(); } public void Register(Workspace workspace) diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.AbstractPriorityProcessor.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.AbstractPriorityProcessor.cs index 2fe11a9e28083..edacf3d41d69e 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.AbstractPriorityProcessor.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.AbstractPriorityProcessor.cs @@ -22,7 +22,7 @@ private abstract class AbstractPriorityProcessor : GlobalOperationAwareIdleProce { protected readonly IncrementalAnalyzerProcessor Processor; - private readonly object _gate; + private readonly object _gate = new(); private Lazy> _lazyAnalyzers; public AbstractPriorityProcessor( @@ -34,7 +34,6 @@ public AbstractPriorityProcessor( CancellationToken shutdownToken) : base(listener, globalOperationNotificationService, backOffTimeSpan, shutdownToken) { - _gate = new object(); _lazyAnalyzers = lazyAnalyzers; Processor = processor; diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.AsyncWorkItemQueue.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.AsyncWorkItemQueue.cs index 0facf62e7783f..2126979f4ae36 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.AsyncWorkItemQueue.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.AsyncWorkItemQueue.cs @@ -20,7 +20,7 @@ internal partial class WorkCoordinator private abstract class AsyncWorkItemQueue : IDisposable where TKey : class { - private readonly object _gate; + private readonly object _gate = new(); private readonly SemaphoreSlim _semaphore; private bool _disposed; @@ -28,13 +28,11 @@ private abstract class AsyncWorkItemQueue : IDisposable private readonly SolutionCrawlerProgressReporter _progressReporter; // map containing cancellation source for the item given out. - private readonly Dictionary _cancellationMap; + private readonly Dictionary _cancellationMap = new(); public AsyncWorkItemQueue(SolutionCrawlerProgressReporter progressReporter, Workspace workspace) { - _gate = new object(); _semaphore = new SemaphoreSlim(initialCount: 0); - _cancellationMap = new Dictionary(); _workspace = workspace; _progressReporter = progressReporter; diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs index 45007cb7f9161..747d0dc739c83 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs @@ -24,7 +24,7 @@ private sealed class HighPriorityProcessor : IdleProcessor { private readonly IncrementalAnalyzerProcessor _processor; private readonly AsyncDocumentWorkItemQueue _workItemQueue; - private readonly object _gate; + private readonly object _gate = new(); private Lazy> _lazyAnalyzers; @@ -41,7 +41,6 @@ public HighPriorityProcessor( { _processor = processor; _lazyAnalyzers = lazyAnalyzers; - _gate = new object(); _running = Task.CompletedTask; _workItemQueue = new AsyncDocumentWorkItemQueue(processor._registration.ProgressReporter, processor._registration.Workspace); diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs index 039f8edb801d0..f4a317aceaad5 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.IncrementalAnalyzerProcessor.cs @@ -42,7 +42,7 @@ private partial class IncrementalAnalyzerProcessor // NOTE: IDiagnosticAnalyzerService can be null in test environment. private readonly Lazy _lazyDiagnosticAnalyzerService; - private LogAggregator _logAggregator; + private LogAggregator _logAggregator = new(); public IncrementalAnalyzerProcessor( IAsynchronousOperationListener listener, @@ -54,8 +54,6 @@ public IncrementalAnalyzerProcessor( TimeSpan lowBackOffTimeSpan, CancellationToken shutdownToken) { - _logAggregator = new LogAggregator(); - _listener = listener; _registration = registration; _cacheService = registration.Workspace.Services.GetService(); @@ -396,11 +394,10 @@ public void Dispose() { } private class AnalyzersGetter { private readonly List> _analyzerProviders; - private readonly Dictionary> _analyzerMap; + private readonly Dictionary> _analyzerMap = new(); public AnalyzersGetter(IEnumerable> analyzerProviders) { - _analyzerMap = new Dictionary>(); _analyzerProviders = analyzerProviders.ToList(); } diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.SemanticChangeProcessor.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.SemanticChangeProcessor.cs index fbb00afed9732..11a2db60b861a 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.SemanticChangeProcessor.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.SemanticChangeProcessor.cs @@ -34,8 +34,8 @@ private sealed class SemanticChangeProcessor : IdleProcessor private readonly Registration _registration; private readonly ProjectProcessor _processor; - private readonly NonReentrantLock _workGate; - private readonly Dictionary _pendingWork; + private readonly NonReentrantLock _workGate = new(); + private readonly Dictionary _pendingWork = new(); public SemanticChangeProcessor( IAsynchronousOperationListener listener, @@ -52,9 +52,6 @@ public SemanticChangeProcessor( _processor = new ProjectProcessor(listener, registration, documentWorkerProcessor, projectBackOffTimeSpan, cancellationToken); - _workGate = new NonReentrantLock(); - _pendingWork = new Dictionary(); - Start(); // Register a clean-up task to ensure pending work items are flushed from the queue if they will @@ -338,8 +335,8 @@ private class ProjectProcessor : IdleProcessor private readonly Registration _registration; private readonly IncrementalAnalyzerProcessor _processor; - private readonly NonReentrantLock _workGate; - private readonly Dictionary _pendingWork; + private readonly NonReentrantLock _workGate = new(); + private readonly Dictionary _pendingWork = new(); public ProjectProcessor( IAsynchronousOperationListener listener, @@ -354,9 +351,6 @@ public ProjectProcessor( _gate = new SemaphoreSlim(initialCount: 0); - _workGate = new NonReentrantLock(); - _pendingWork = new Dictionary(); - Start(); // Register a clean-up task to ensure pending work items are flushed from the queue if they will diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs index 16bc6a736a3a4..29282ec15323b 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs @@ -22,15 +22,15 @@ internal partial class SolutionCrawlerRegistrationService internal sealed partial class WorkCoordinator { private readonly Registration _registration; - private readonly object _gate; + private readonly object _gate = new(); - private readonly LogAggregator _logAggregator; + private readonly LogAggregator _logAggregator = new(); private readonly IAsynchronousOperationListener _listener; private readonly IOptionService _optionService; private readonly IDocumentTrackingService _documentTrackingService; private readonly IWorkspaceConfigurationService? _workspaceConfigurationService; - private readonly CancellationTokenSource _shutdownNotificationSource; + private readonly CancellationTokenSource _shutdownNotificationSource = new(); private readonly CancellationToken _shutdownToken; private readonly TaskQueue _eventProcessingQueue; @@ -44,10 +44,7 @@ public WorkCoordinator( bool initializeLazily, Registration registration) { - _logAggregator = new LogAggregator(); - _registration = registration; - _gate = new object(); _listener = listener; _optionService = _registration.Workspace.Services.GetRequiredService(); @@ -55,7 +52,6 @@ public WorkCoordinator( _workspaceConfigurationService = _registration.Workspace.Services.GetService(); // event and worker queues - _shutdownNotificationSource = new CancellationTokenSource(); _shutdownToken = _shutdownNotificationSource.Token; _eventProcessingQueue = new TaskQueue(listener, TaskScheduler.Default); diff --git a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs index fb8cf487ab84c..940efa745addf 100644 --- a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs +++ b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs @@ -118,7 +118,7 @@ private async Task CreateSpellCheckCodeIssueAsync( // - We believe spell-check should only compare what you have typed to what symbol would be offered here. var options = CompletionOptions.Default with { - HideAdvancedMembers = context.Options(document.Project.LanguageServices).HideAdvancedMembers, + HideAdvancedMembers = context.Options.GetOptions(document.Project.LanguageServices).HideAdvancedMembers, SnippetsBehavior = SnippetsRule.NeverInclude, ShowItemsFromUnimportedNamespaces = false, TargetTypedCompletionFilter = false, @@ -187,8 +187,13 @@ private async Task CheckItemsAsync( { // Wrap the spell checking actions into a single top level suggestion // so as to not clutter the list. - context.RegisterCodeFix(new MyCodeAction( - string.Format(FeaturesResources.Fix_typo_0, nameText), codeActions), context.Diagnostics); + context.RegisterCodeFix( + CodeAction.CreateWithPriority( + CodeActionPriority.Low, + string.Format(FeaturesResources.Fix_typo_0, nameText), + codeActions, + isInlinable: true), + context.Diagnostics); } else { @@ -209,9 +214,10 @@ private static async Task GetInsertionTextAsync(Document document, Compl : text; } - private SpellCheckCodeAction CreateCodeAction(SyntaxToken nameToken, string oldName, string newName, Document document) + private CodeAction CreateCodeAction(SyntaxToken nameToken, string oldName, string newName, Document document) { - return new SpellCheckCodeAction( + return CodeAction.CreateWithPriority( + CodeActionPriority.Low, string.Format(FeaturesResources.Change_0_to_1, oldName, newName), c => UpdateAsync(document, nameToken, newName, c), equivalenceKey: newName); @@ -224,25 +230,5 @@ private async Task UpdateAsync(Document document, SyntaxToken nameToke return document.WithSyntaxRoot(newRoot); } - - private class SpellCheckCodeAction : CodeAction.DocumentChangeAction - { - internal override CodeActionPriority Priority => CodeActionPriority.Low; - - public SpellCheckCodeAction(string title, Func> createChangedDocument, string equivalenceKey) - : base(title, createChangedDocument, equivalenceKey) - { - } - } - - private class MyCodeAction : CodeAction.CodeActionWithNestedActions - { - internal override CodeActionPriority Priority => CodeActionPriority.Low; - - public MyCodeAction(string title, ImmutableArray nestedActions) - : base(title, nestedActions, isInlinable: true) - { - } - } } } diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractMergeConsecutiveIfStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractMergeConsecutiveIfStatementsCodeRefactoringProvider.cs index 3d8631d648ae7..eb4449bc361fd 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractMergeConsecutiveIfStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractMergeConsecutiveIfStatementsCodeRefactoringProvider.cs @@ -48,7 +48,8 @@ internal abstract class AbstractMergeConsecutiveIfStatementsCodeRefactoringProvi protected sealed override CodeAction CreateCodeAction(Func> createChangedDocument, MergeDirection direction, string ifKeywordText) { var resourceText = direction == MergeDirection.Up ? FeaturesResources.Merge_with_previous_0_statement : FeaturesResources.Merge_with_next_0_statement; - return new MyCodeAction(string.Format(resourceText, ifKeywordText), createChangedDocument); + var title = string.Format(resourceText, ifKeywordText); + return CodeAction.Create(title, createChangedDocument, title); } protected sealed override Task CanBeMergedUpAsync( @@ -255,13 +256,5 @@ private static bool ContainEquivalentStatements( statements = statements1; return statements1.SequenceEqual(statements2, syntaxFacts.AreEquivalent); } - - private sealed class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs index c3c27ccde0435..6c776a5f716f0 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/Consecutive/AbstractSplitIntoConsecutiveIfStatementsCodeRefactoringProvider.cs @@ -46,7 +46,10 @@ protected sealed override int GetLogicalExpressionKind(ISyntaxKindsService synta => syntaxKinds.LogicalOrExpression; protected sealed override CodeAction CreateCodeAction(Func> createChangedDocument, string ifKeywordText) - => new MyCodeAction(string.Format(FeaturesResources.Split_into_consecutive_0_statements, ifKeywordText), createChangedDocument); + => CodeAction.Create( + string.Format(FeaturesResources.Split_into_consecutive_0_statements, ifKeywordText), + createChangedDocument, + nameof(FeaturesResources.Split_into_consecutive_0_statements) + "_" + ifKeywordText); protected sealed override async Task GetChangedRootAsync( Document document, @@ -151,13 +154,5 @@ private static async Task CanBeSeparateStatementsAsync( return !controlFlow.EndPointIsReachable; } } - - private sealed class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractMergeNestedIfStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractMergeNestedIfStatementsCodeRefactoringProvider.cs index 6532a17def714..d1cba7d22384c 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractMergeNestedIfStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractMergeNestedIfStatementsCodeRefactoringProvider.cs @@ -36,7 +36,8 @@ internal abstract class AbstractMergeNestedIfStatementsCodeRefactoringProvider protected sealed override CodeAction CreateCodeAction(Func> createChangedDocument, MergeDirection direction, string ifKeywordText) { var resourceText = direction == MergeDirection.Up ? FeaturesResources.Merge_with_outer_0_statement : FeaturesResources.Merge_with_nested_0_statement; - return new MyCodeAction(string.Format(resourceText, ifKeywordText), createChangedDocument); + var title = string.Format(resourceText, ifKeywordText); + return CodeAction.Create(title, createChangedDocument, title); } protected sealed override Task CanBeMergedUpAsync( @@ -257,13 +258,5 @@ private static bool IsElseIfOrElseClauseEquivalent( return statements1.SequenceEqual(statements2, syntaxFacts.AreEquivalent); } - - private sealed class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractSplitIntoNestedIfStatementsCodeRefactoringProvider.cs b/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractSplitIntoNestedIfStatementsCodeRefactoringProvider.cs index f7b3c45295fae..c3cdd5403913c 100644 --- a/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractSplitIntoNestedIfStatementsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/SplitOrMergeIfStatements/Nested/AbstractSplitIntoNestedIfStatementsCodeRefactoringProvider.cs @@ -32,7 +32,10 @@ protected sealed override int GetLogicalExpressionKind(ISyntaxKindsService synta => syntaxKinds.LogicalAndExpression; protected sealed override CodeAction CreateCodeAction(Func> createChangedDocument, string ifKeywordText) - => new MyCodeAction(string.Format(FeaturesResources.Split_into_nested_0_statements, ifKeywordText), createChangedDocument); + => CodeAction.Create( + string.Format(FeaturesResources.Split_into_nested_0_statements, ifKeywordText), + createChangedDocument, + nameof(FeaturesResources.Split_into_nested_0_statements) + "_" + ifKeywordText); protected sealed override Task GetChangedRootAsync( Document document, @@ -53,13 +56,5 @@ protected sealed override Task GetChangedRootAsync( return Task.FromResult( root.ReplaceNode(ifOrElseIf, outerIfOrElseIf.WithAdditionalAnnotations(Formatter.Annotation))); } - - private sealed class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesSevice.cs b/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesSevice.cs index 8c416119c0c31..cc1c99b8e1998 100644 --- a/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesSevice.cs +++ b/src/Features/Core/Portable/SyncNamespaces/AbstractSyncNamespacesSevice.cs @@ -117,7 +117,7 @@ private static async Task GetFixAllContextAsync( return new FixAllContext( new FixAllState( - fixAllProvider: null, + fixAllProvider: NoOpFixAllProvider.Instance, diagnosticSpan: firstDiagnostic.Location.SourceSpan, document, document.Project, diff --git a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs index 26d4a961bee1f..ef47debfc221f 100644 --- a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs +++ b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs @@ -87,10 +87,9 @@ private async Task ProcessResultAsync(CodeFixContext context, Diagnost var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); var renameOptions = new SymbolRenameOptions(); - var fallbackOptions = CodeCleanupOptions.CreateProvider(context.Options); var fieldLocations = await Renamer.FindRenameLocationsAsync( - solution, fieldSymbol, renameOptions, fallbackOptions, cancellationToken).ConfigureAwait(false); + solution, fieldSymbol, renameOptions, context.Options, cancellationToken).ConfigureAwait(false); // First, create the updated property we want to replace the old property with var isWrittenToOutsideOfConstructor = IsWrittenToOutsideOfConstructorOrProperty(fieldSymbol, fieldLocations, property, cancellationToken); @@ -212,7 +211,7 @@ private async Task ProcessResultAsync(CodeFixContext context, Diagnost editor.RemoveNode(nodeToRemove, syntaxRemoveOptions); var newRoot = editor.GetChangedRoot(); - newRoot = await FormatAsync(newRoot, fieldDocument, fallbackOptions, cancellationToken).ConfigureAwait(false); + newRoot = await FormatAsync(newRoot, fieldDocument, context.Options, cancellationToken).ConfigureAwait(false); return solution.WithDocumentSyntaxRoot(fieldDocument.Id, newRoot); } @@ -226,8 +225,8 @@ private async Task ProcessResultAsync(CodeFixContext context, Diagnost Contract.ThrowIfNull(newFieldTreeRoot); var newPropertyTreeRoot = propertyTreeRoot.ReplaceNode(property, updatedProperty); - newFieldTreeRoot = await FormatAsync(newFieldTreeRoot, fieldDocument, fallbackOptions, cancellationToken).ConfigureAwait(false); - newPropertyTreeRoot = await FormatAsync(newPropertyTreeRoot, propertyDocument, fallbackOptions, cancellationToken).ConfigureAwait(false); + newFieldTreeRoot = await FormatAsync(newFieldTreeRoot, fieldDocument, context.Options, cancellationToken).ConfigureAwait(false); + newPropertyTreeRoot = await FormatAsync(newPropertyTreeRoot, propertyDocument, context.Options, cancellationToken).ConfigureAwait(false); var updatedSolution = solution.WithDocumentSyntaxRoot(fieldDocument.Id, newFieldTreeRoot); updatedSolution = updatedSolution.WithDocumentSyntaxRoot(propertyDocument.Id, newPropertyTreeRoot); diff --git a/src/Features/Core/Portable/UseNamedArguments/AbstractUseNamedArgumentsCodeRefactoringProvider.cs b/src/Features/Core/Portable/UseNamedArguments/AbstractUseNamedArgumentsCodeRefactoringProvider.cs index 3a8125dc5b72e..f93d8848a66a4 100644 --- a/src/Features/Core/Portable/UseNamedArguments/AbstractUseNamedArgumentsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/UseNamedArguments/AbstractUseNamedArgumentsCodeRefactoringProvider.cs @@ -111,23 +111,26 @@ public async Task ComputeRefactoringsAsync( potentialArgumentsToName > 1) { context.RegisterRefactoring( - new MyCodeAction( + CodeAction.Create( string.Format(FeaturesResources.Add_argument_name_0, argumentName), - c => AddNamedArgumentsAsync(root, document, argument, parameters, argumentIndex, includingTrailingArguments: false)), + c => AddNamedArgumentsAsync(root, document, argument, parameters, argumentIndex, includingTrailingArguments: false), + nameof(FeaturesResources.Add_argument_name_0) + "_" + argumentName), argument.Span); context.RegisterRefactoring( - new MyCodeAction( + CodeAction.Create( string.Format(FeaturesResources.Add_argument_name_0_including_trailing_arguments, argumentName), - c => AddNamedArgumentsAsync(root, document, argument, parameters, argumentIndex, includingTrailingArguments: true)), + c => AddNamedArgumentsAsync(root, document, argument, parameters, argumentIndex, includingTrailingArguments: true), + nameof(FeaturesResources.Add_argument_name_0_including_trailing_arguments) + "_" + argumentName), argument.Span); } else { context.RegisterRefactoring( - new MyCodeAction( + CodeAction.Create( string.Format(FeaturesResources.Add_argument_name_0, argumentName), - c => AddNamedArgumentsAsync(root, document, argument, parameters, argumentIndex, includingTrailingArguments: true)), + c => AddNamedArgumentsAsync(root, document, argument, parameters, argumentIndex, includingTrailingArguments: true), + nameof(FeaturesResources.Add_argument_name_0) + "_" + argumentName), argument.Span); } } @@ -211,13 +214,5 @@ public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContex await _attributeArgumentAnalyzer.ComputeRefactoringsAsync(context, root).ConfigureAwait(false); } } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(string title, Func> createChangedDocument) - : base(title, createChangedDocument, title) - { - } - } } } diff --git a/src/Features/Core/Portable/Workspace/BackgroundCompiler.cs b/src/Features/Core/Portable/Workspace/BackgroundCompiler.cs index ece31756865a6..e701cce0ea6f5 100644 --- a/src/Features/Core/Portable/Workspace/BackgroundCompiler.cs +++ b/src/Features/Core/Portable/Workspace/BackgroundCompiler.cs @@ -23,7 +23,7 @@ internal sealed class BackgroundCompiler : IDisposable private Compilation?[]? _mostRecentCompilations; private readonly object _buildGate = new(); - private CancellationTokenSource _cancellationSource; + private CancellationTokenSource _cancellationSource = new(); public BackgroundCompiler(Workspace workspace) { @@ -33,7 +33,6 @@ public BackgroundCompiler(Workspace workspace) var listenerProvider = workspace.Services.GetRequiredService(); _taskQueue = new TaskQueue(listenerProvider.GetListener(), TaskScheduler.Default); - _cancellationSource = new CancellationTokenSource(); _workspace.WorkspaceChanged += OnWorkspaceChanged; _workspace.DocumentOpened += OnDocumentOpened; _workspace.DocumentClosed += OnDocumentClosed; diff --git a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs index d54d2493c0e7c..883445ffdd276 100644 --- a/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/Wrapping/AbstractWrappingCodeRefactoringProvider.cs @@ -45,7 +45,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var token = root.FindToken(position); var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); - var options = GetWrappingOptions(configOptions, context.Options(document.Project.LanguageServices)); + var options = GetWrappingOptions(configOptions, context.Options.GetOptions(document.Project.LanguageServices)); foreach (var node in token.GetRequiredParent().AncestorsAndSelf()) { diff --git a/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs b/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs index caed7435cddc7..ac98a1eb9a44e 100644 --- a/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs +++ b/src/Features/Core/Portable/Wrapping/WrapItemsAction.cs @@ -39,10 +39,8 @@ internal class WrapItemsAction : DocumentChangeAction // // This value is only relevant if this code action is the only one in its group, // and it ends up getting inlined as a top-level-action that is offered. - internal override CodeActionPriority Priority => CodeActionPriority.Low; - public WrapItemsAction(string title, string parentTitle, Func> createChangedDocument) - : base(title, createChangedDocument, title) + : base(title, createChangedDocument, title, CodeActionPriority.Low) { ParentTitle = parentTitle; SortTitle = parentTitle + "_" + title; diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index 78e954e20b071..b236cbc35f805 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -615,6 +615,11 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Odstranění zachycené proměnné {0} vyžaduje restartování aplikace. + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method Neměňte tento kód. Kód pro vyčištění vložte do metody {0}. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index fe1f11c6beb78..bbd9fd75fcd15 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -615,6 +615,11 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Das Löschen der erfassten Variable „{0}“ erfordert einen Neustart der Anwendung. + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "{0}" ein. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index 6b5c97aa33c04..e2feb760ae980 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -615,6 +615,11 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Para eliminar la variable capturada "{0}" se requiere reiniciar la aplicación. + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method No cambie este código. Coloque el código de limpieza en el método "{0}". diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index 4556d6cba01e2..7c1a84da5f7f1 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -615,6 +615,11 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai La suppression de la variable capturée « {0} » requiert le redémarrage de l’application. + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method Ne changez pas ce code. Placez le code de nettoyage dans la méthode '{0}' diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index d7eac79e7a648..55cad3071dc20 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -615,6 +615,11 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Se si elimina la variabile catturata '{0}', è necessario riavviare l'applicazione. + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method Non modificare questo codice. Inserire il codice di pulizia nel metodo '{0}' diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index 86c5f48fe1753..61657a853bc33 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -615,6 +615,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma キャプチャした変数 '{0}' を削除するには、アプリケーションを再起動する必要があります。 + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method このコードを変更しないでください。クリーンアップ コードを '{0}' メソッドに記述します diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index 01aa69bc51093..be8a0dd17da50 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -615,6 +615,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 캡처된 변수 '{0}'을(를) 삭제하려면 응용 프로그램을 다시 시작해야 합니다. + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method 이 코드를 변경하지 마세요. '{0}' 메서드에 정리 코드를 입력합니다. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index eb0509769f713..bd6f1249248e2 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -615,6 +615,11 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Usuwanie przechwyconej zmiennej "{0}" wymaga ponownego uruchomienia aplikacji. + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method Nie zmieniaj tego kodu. Umieść kod czyszczący w metodzie „{0}”. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index 3a0ae27d7c213..b4c48a0936f70 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -615,6 +615,11 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Excluir a variável capturada '{0}' requer a reinicialização do aplicativo. + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method Não altere este código. Coloque o código de limpeza no método '{0}' diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index 83cbfe2baa2ed..37d16622c8633 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -615,6 +615,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Для удаления зафиксированной переменной "{0}" требуется перезапустить приложение. + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method Не изменяйте этот код. Разместите код очистки в методе "{0}". diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index 3ad61a57a831a..556c1600e8048 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -615,6 +615,11 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Yakalanan '{0}' değişkenini silmek, uygulamanın yeniden başlatılmasını gerektirir. + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method Bu kodu değiştirmeyin. Temizleme kodunu '{0}' metodunun içine yerleştirin. diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index b658f2a1d7aac..528e191e5356c 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -615,6 +615,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 删除捕获的变量“{0}”需要重新启动应用程序。 + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method 不要更改此代码。请将清理代码放入“{0}”方法中 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index 5d4ff36d0bcc3..d2cb7daaf433f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -615,6 +615,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 刪除擷取到的變數 '{0}' 需要重新啟動應用程式。 + + Directives from '{0}' + Directives from '{0}' + + Do not change this code. Put cleanup code in '{0}' method 請勿變更此程式碼。請將清除程式碼放入 '{0}' 方法 diff --git a/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs b/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs index 411121020fdd4..00bbd0827567a 100644 --- a/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs +++ b/src/Features/LanguageServer/Protocol/Features/CodeCleanup/AbstractCodeCleanupService.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.RemoveUnnecessaryImports; diff --git a/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.ProjectCodeFixProvider.cs b/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.ProjectCodeFixProvider.cs index 1717a1d65a564..feffd3529350b 100644 --- a/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.ProjectCodeFixProvider.cs +++ b/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.ProjectCodeFixProvider.cs @@ -2,8 +2,6 @@ // 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.Collections.Immutable; using System.Linq; @@ -14,13 +12,8 @@ namespace Microsoft.CodeAnalysis.CodeFixes internal partial class CodeFixService { private class ProjectCodeFixProvider - : AbstractProjectExtensionProvider + : AbstractProjectExtensionProvider { - public ProjectCodeFixProvider(AnalyzerReference reference) - : base(reference) - { - } - protected override bool SupportsLanguage(ExportCodeFixProviderAttribute exportAttribute, string language) { return exportAttribute.Languages == null diff --git a/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs b/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs index 4184fe688da2e..5ae2e35a6ab31 100644 --- a/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs +++ b/src/Features/LanguageServer/Protocol/Features/CodeFixes/CodeFixService.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes.Suppression; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.ErrorLogger; using Microsoft.CodeAnalysis.ErrorReporting; @@ -43,8 +44,6 @@ internal partial class CodeFixService : ICodeFixService private readonly ConditionalWeakTable, ImmutableDictionary>> _projectFixersMap = new(); // Shared by project fixers and workspace fixers. - private readonly ConditionalWeakTable _analyzerReferenceToFixersMap = new(); - private readonly ConditionalWeakTable.CreateValueCallback _createProjectCodeFixProvider = r => new ProjectCodeFixProvider(r); private readonly ImmutableDictionary>> _configurationProvidersMap; private readonly ImmutableArray> _errorLoggers; @@ -657,7 +656,7 @@ await diagnosticsWithSameSpan.OrderByDescending(d => d.Severity) var codeFixProvider = (fixer as CodeFixProvider) ?? new WrapperCodeFixProvider((IConfigurationFixProvider)fixer, diagnostics.Select(d => d.Id)); fixAllState = new FixAllState( - fixAllProviderInfo.FixAllProvider, + (FixAllProvider)fixAllProviderInfo.FixAllProvider, fixesSpan, document, document.Project, @@ -850,19 +849,16 @@ private ImmutableDictionary> Compu var extensionManager = project.Solution.Workspace.Services.GetService(); using var _ = PooledDictionary>.GetInstance(out var builder); - foreach (var reference in project.AnalyzerReferences) + var codeFixProviders = ProjectCodeFixProvider.GetExtensions(project); + foreach (var fixer in codeFixProviders) { - var projectCodeFixerProvider = _analyzerReferenceToFixersMap.GetValue(reference, _createProjectCodeFixProvider); - foreach (var fixer in projectCodeFixerProvider.GetExtensions(project.Language)) + var fixableIds = this.GetFixableDiagnosticIds(fixer, extensionManager); + foreach (var id in fixableIds) { - var fixableIds = this.GetFixableDiagnosticIds(fixer, extensionManager); - foreach (var id in fixableIds) - { - if (string.IsNullOrWhiteSpace(id)) - continue; + if (string.IsNullOrWhiteSpace(id)) + continue; - builder.MultiAdd(id, fixer); - } + builder.MultiAdd(id, fixer); } } diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DefaultDiagnosticAnalyzerService.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DefaultDiagnosticAnalyzerService.cs index a4ad7569e739b..c364510ff71df 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DefaultDiagnosticAnalyzerService.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DefaultDiagnosticAnalyzerService.cs @@ -23,7 +23,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics [ExportIncrementalAnalyzerProvider(WellKnownSolutionCrawlerAnalyzers.Diagnostic, workspaceKinds: null)] internal partial class DefaultDiagnosticAnalyzerService : IIncrementalAnalyzerProvider, IDiagnosticUpdateSource { - private readonly DiagnosticAnalyzerInfoCache _analyzerInfoCache; + private readonly DiagnosticAnalyzerInfoCache _analyzerInfoCache = new(); private readonly IGlobalOptionService _globalOptions; [ImportingConstructor] @@ -33,7 +33,6 @@ public DefaultDiagnosticAnalyzerService( IGlobalOptionService globalOptions) { _globalOptions = globalOptions; - _analyzerInfoCache = new DiagnosticAnalyzerInfoCache(); registrationService.Register(this); _globalOptions = globalOptions; } diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs index 96c74151a96d3..d4e9a1b32e100 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticAnalyzerService.cs @@ -28,7 +28,7 @@ internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService private const string DiagnosticsUpdatedEventName = "DiagnosticsUpdated"; // use eventMap and taskQueue to serialize events - private readonly EventMap _eventMap; + private readonly EventMap _eventMap = new(); private readonly TaskQueue _eventQueue; public DiagnosticAnalyzerInfoCache AnalyzerInfoCache { get; private set; } @@ -36,7 +36,7 @@ internal partial class DiagnosticAnalyzerService : IDiagnosticAnalyzerService public IAsynchronousOperationListener Listener { get; } public IGlobalOptionService GlobalOptions { get; } - private readonly ConditionalWeakTable _map; + private readonly ConditionalWeakTable _map = new(); private readonly ConditionalWeakTable.CreateValueCallback _createIncrementalAnalyzer; [ImportingConstructor] @@ -50,9 +50,7 @@ public DiagnosticAnalyzerService( Listener = listenerProvider.GetListener(FeatureAttribute.DiagnosticService); GlobalOptions = globalOptions; - _map = new ConditionalWeakTable(); _createIncrementalAnalyzer = CreateIncrementalAnalyzerCallback; - _eventMap = new EventMap(); _eventQueue = new TaskQueue(Listener, TaskScheduler.Default); diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticService.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticService.cs index 5eb371103ef1c..24990cd9c93f9 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticService.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/DiagnosticService.cs @@ -26,11 +26,11 @@ internal partial class DiagnosticService : IDiagnosticService { private const string DiagnosticsUpdatedEventName = "DiagnosticsUpdated"; - private readonly EventMap _eventMap; + private readonly EventMap _eventMap = new(); private readonly TaskQueue _eventQueue; - private readonly object _gate; - private readonly Dictionary>> _map; + private readonly object _gate = new(); + private readonly Dictionary>> _map = new(); private readonly EventListenerTracker _eventListenerTracker; @@ -53,13 +53,8 @@ public DiagnosticService( _updateSources = ImmutableHashSet.Empty; // queue to serialize events. - _eventMap = new EventMap(); - _eventQueue = new TaskQueue(listenerProvider.GetListener(FeatureAttribute.DiagnosticService), TaskScheduler.Default); - _gate = new object(); - _map = new Dictionary>>(); - _eventListenerTracker = new EventListenerTracker(eventListeners, WellKnownEventListeners.DiagnosticService); } diff --git a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs index 7a0b5b5880394..883be923a04be 100644 --- a/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs +++ b/src/Features/LanguageServer/Protocol/Features/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.cs @@ -29,11 +29,11 @@ namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2 internal partial class DiagnosticIncrementalAnalyzer : IIncrementalAnalyzer { private readonly int _correlationId; - private readonly DiagnosticAnalyzerTelemetry _telemetry; + private readonly DiagnosticAnalyzerTelemetry _telemetry = new(); private readonly StateManager _stateManager; private readonly InProcOrRemoteHostAnalyzerRunner _diagnosticAnalyzerRunner; private readonly IDocumentTrackingService _documentTrackingService; - private ConditionalWeakTable _projectCompilationsWithAnalyzers; + private ConditionalWeakTable _projectCompilationsWithAnalyzers = new(); internal DiagnosticAnalyzerService AnalyzerService { get; } internal Workspace Workspace { get; } @@ -56,10 +56,8 @@ public DiagnosticIncrementalAnalyzer( _stateManager = new StateManager(workspace, analyzerInfoCache); _stateManager.ProjectAnalyzerReferenceChanged += OnProjectAnalyzerReferenceChanged; - _telemetry = new DiagnosticAnalyzerTelemetry(); _diagnosticAnalyzerRunner = new InProcOrRemoteHostAnalyzerRunner(analyzerInfoCache, analyzerService.Listener); - _projectCompilationsWithAnalyzers = new ConditionalWeakTable(); } internal IGlobalOptionService GlobalOptions => AnalyzerService.GlobalOptions; diff --git a/src/EditorFeatures/Core/CodeActions/CodeActionOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs similarity index 59% rename from src/EditorFeatures/Core/CodeActions/CodeActionOptionsStorage.cs rename to src/Features/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs index bbe647be1ef11..d54ef3d3a0ac3 100644 --- a/src/EditorFeatures/Core/CodeActions/CodeActionOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CodeActionOptionsStorage.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.Formatting; @@ -17,6 +18,9 @@ namespace Microsoft.CodeAnalysis.CodeActions { internal static class CodeActionOptionsStorage { + public static readonly PerLanguageOption2 WrappingColumn = + new("FormattingOptions", "WrappingColumn", CodeActionOptions.DefaultWrappingColumn); + internal static CodeActionOptions GetCodeActionOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) => GetCodeActionOptions(globalOptions, languageServices, isBlocking: false); @@ -29,19 +33,32 @@ private static CodeActionOptions GetCodeActionOptions(this IGlobalOptionService ImplementTypeOptions: globalOptions.GetImplementTypeOptions(languageServices.Language), ExtractMethodOptions: globalOptions.GetExtractMethodOptions(languageServices.Language), CleanupOptions: globalOptions.GetCodeCleanupOptions(languageServices), + CodeGenerationOptions: globalOptions.GetCodeGenerationOptions(languageServices), HideAdvancedMembers: globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, languageServices.Language), - IsBlocking: isBlocking); + IsBlocking: isBlocking, + WrappingColumn: globalOptions.GetOption(WrappingColumn, languageServices.Language)); internal static CodeActionOptionsProvider GetCodeActionOptionsProvider(this IGlobalOptionService globalOptions) - { - var cache = ImmutableDictionary.Empty; - return languageService => ImmutableInterlocked.GetOrAdd(ref cache, languageService.Language, (_, options) => GetCodeActionOptions(options, languageService), globalOptions); - } + => new CachingCodeActionsOptionsProvider(globalOptions, isBlocking: false); internal static CodeActionOptionsProvider GetBlockingCodeActionOptionsProvider(this IGlobalOptionService globalOptions) + => new CachingCodeActionsOptionsProvider(globalOptions, isBlocking: true); + + private sealed class CachingCodeActionsOptionsProvider : AbstractCodeActionOptionsProvider { - var cache = ImmutableDictionary.Empty; - return languageService => ImmutableInterlocked.GetOrAdd(ref cache, languageService.Language, (language, options) => GetBlockingCodeActionOptions(options, languageService), globalOptions); + private readonly IGlobalOptionService _globalOptions; + private readonly bool _isBlocking; + + private ImmutableDictionary _cache = ImmutableDictionary.Empty; + + public CachingCodeActionsOptionsProvider(IGlobalOptionService globalOptions, bool isBlocking) + { + _globalOptions = globalOptions; + _isBlocking = isBlocking; + } + + public override CodeActionOptions GetOptions(HostLanguageServices languageService) + => ImmutableInterlocked.GetOrAdd(ref _cache, languageService.Language, (language, options) => GetCodeActionOptions(options, languageService, _isBlocking), _globalOptions); } } } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CodeCleanupOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CodeCleanupOptionsStorage.cs index 7a6f77be755e5..1e61d699b09d7 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/CodeCleanupOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/CodeCleanupOptionsStorage.cs @@ -23,7 +23,4 @@ public static CodeCleanupOptions GetCodeCleanupOptions(this IGlobalOptionService FormattingOptions: globalOptions.GetSyntaxFormattingOptions(languageServices), SimplifierOptions: globalOptions.GetSimplifierOptions(languageServices), AddImportOptions: AddImportPlacementOptions.Default); - - public static CodeCleanupOptionsProvider GetCodeCleanupOptionsProvider(this IGlobalOptionService globalOptions) - => new((language, cancellationToken) => ValueTaskFactory.FromResult(globalOptions.GetCodeCleanupOptions(language))); } diff --git a/src/Features/LanguageServer/Protocol/Features/Options/CodeGenerationOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/CodeGenerationOptionsStorage.cs new file mode 100644 index 0000000000000..cd38b5748a05f --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Features/Options/CodeGenerationOptionsStorage.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CodeGeneration; + +internal interface ICodeGenerationOptionsStorage : ILanguageService +{ + CodeGenerationOptions GetOptions(IGlobalOptionService globalOptions); +} + +internal static class CodeGenerationOptionsStorage +{ + public static ValueTask GetCodeGenerationOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) + => document.GetCodeGenerationOptionsAsync(globalOptions.GetCodeGenerationOptions(document.Project.LanguageServices), cancellationToken); + + public static ValueTask GetCleanCodeGenerationOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) + => document.GetCleanCodeGenerationOptionsAsync(globalOptions.GetCleanCodeGenerationOptions(document.Project.LanguageServices), cancellationToken); + + public static CodeGenerationOptions GetCodeGenerationOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + => languageServices.GetRequiredService().GetOptions(globalOptions); + + public static CodeAndImportGenerationOptions GetCodeAndImportGenerationOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + => new(globalOptions.GetCodeGenerationOptions(languageServices), globalOptions.GetAddImportPlacementOptions(languageServices)); + + public static CleanCodeGenerationOptions GetCleanCodeGenerationOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + => new(globalOptions.GetCodeGenerationOptions(languageServices), globalOptions.GetCodeCleanupOptions(languageServices)); +} diff --git a/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs index fa7f762a27208..ee6de6c55232f 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/ExtractMethodOptionsStorage.cs @@ -2,6 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.ExtractMethod; @@ -12,6 +18,15 @@ public static ExtractMethodOptions GetExtractMethodOptions(this IGlobalOptionSer => new( DontPutOutOrRefOnStruct: globalOptions.GetOption(DontPutOutOrRefOnStruct, language)); + public static ExtractMethodGenerationOptions GetExtractMethodGenerationOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + => new(globalOptions.GetExtractMethodOptions(languageServices.Language), + globalOptions.GetCodeGenerationOptions(languageServices), + globalOptions.GetAddImportPlacementOptions(languageServices), + globalOptions.GetNamingStylePreferencesProvider()); + + public static ValueTask GetExtractMethodGenerationOptionsAsync(this Document document, IGlobalOptionService globalOptions, CancellationToken cancellationToken) + => document.GetExtractMethodGenerationOptionsAsync(globalOptions.GetExtractMethodGenerationOptions(document.Project.LanguageServices), cancellationToken); + public static readonly PerLanguageOption2 DontPutOutOrRefOnStruct = new( "ExtractMethodOptions", "DontPutOutOrRefOnStruct", ExtractMethodOptions.Default.DontPutOutOrRefOnStruct, storageLocation: new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.Don't Put Out Or Ref On Strcut")); // NOTE: the spelling error is what we've shipped and thus should not change diff --git a/src/Features/LanguageServer/Protocol/Features/Options/GlobalCodeActionOptionsProvider.cs b/src/Features/LanguageServer/Protocol/Features/Options/GlobalCodeActionOptionsProvider.cs new file mode 100644 index 0000000000000..7668c0f593478 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Features/Options/GlobalCodeActionOptionsProvider.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImport; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Simplification; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Options; + +internal static class CodeActionOptionsStorage +{ + public static Provider CreateProvider(this IGlobalOptionService globalOptions) + => new(globalOptions); + + // TODO: we can implement providers directly on IGlobalOptionService once it moves to LSP layer + public sealed class Provider : + SyntaxFormattingOptionsProvider, + SimplifierOptionsProvider, + AddImportPlacementOptionsProvider, + CodeCleanupOptionsProvider, + CodeGenerationOptionsProvider, + CleanCodeGenerationOptionsProvider, + CodeAndImportGenerationOptionsProvider, + CodeActionOptionsProvider + { + private readonly IGlobalOptionService _globalOptions; + + public Provider(IGlobalOptionService globalOptions) + => _globalOptions = globalOptions; + + CodeActionOptions CodeActionOptionsProvider.GetOptions(HostLanguageServices languageService) + => _globalOptions.GetCodeActionOptions(languageService); + + ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(_globalOptions.GetSyntaxFormattingOptions(languageServices)); + + ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(_globalOptions.GetSimplifierOptions(languageServices)); + + ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(_globalOptions.GetAddImportPlacementOptions(languageServices)); + + ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(_globalOptions.GetCodeCleanupOptions(languageServices)); + + ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(_globalOptions.GetCodeGenerationOptions(languageServices)); + + ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(_globalOptions.GetCleanCodeGenerationOptions(languageServices)); + + ValueTask OptionsProvider.GetOptionsAsync(HostLanguageServices languageServices, CancellationToken cancellationToken) + => ValueTaskFactory.FromResult(_globalOptions.GetCodeAndImportGenerationOptions(languageServices)); + } +} diff --git a/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs index fd67734d0531f..fa82def580046 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/IdeAnalyzerOptionsStorage.cs @@ -31,18 +31,6 @@ public static IdeAnalyzerOptions GetIdeAnalyzerOptions(this IGlobalOptionService CleanupOptions: supportsCleanupOptions ? globalOptions.GetCodeCleanupOptions(languageServices) : null); } - // for testing only - internal static void SetIdeAnalyzerOptions(this IGlobalOptionService globalOptions, string language, IdeAnalyzerOptions options) - { - globalOptions.SetGlobalOption(new OptionKey((IOption)CrashOnAnalyzerException), options.CrashOnAnalyzerException); - globalOptions.SetGlobalOption(new OptionKey((IOption)FadeOutUnusedImports, language), options.FadeOutUnusedImports); - globalOptions.SetGlobalOption(new OptionKey((IOption)FadeOutUnreachableCode, language), options.FadeOutUnreachableCode); - globalOptions.SetGlobalOption(new OptionKey((IOption)ReportInvalidPlaceholdersInStringDotFormatCalls, language), options.ReportInvalidPlaceholdersInStringDotFormatCalls); - globalOptions.SetGlobalOption(new OptionKey((IOption)ReportInvalidRegexPatterns, language), options.ReportInvalidRegexPatterns); - globalOptions.SetGlobalOption(new OptionKey((IOption)ReportInvalidJsonPatterns, language), options.ReportInvalidJsonPatterns); - globalOptions.SetGlobalOption(new OptionKey((IOption)DetectAndOfferEditorFeaturesForProbableJsonStrings, language), options.DetectAndOfferEditorFeaturesForProbableJsonStrings); - } - public static readonly Option2 CrashOnAnalyzerException = new( "InternalDiagnosticsOptions", "CrashOnAnalyzerException", IdeAnalyzerOptions.DefaultCrashOnAnalyzerException, storageLocation: new LocalUserProfileStorageLocation(@"Roslyn\Internal\Diagnostics\CrashOnAnalyzerException")); diff --git a/src/EditorFeatures/Core/ImplementType/ImplementTypeOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs similarity index 80% rename from src/EditorFeatures/Core/ImplementType/ImplementTypeOptionsStorage.cs rename to src/Features/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs index 139acd773f8a2..688a5fd575d3a 100644 --- a/src/EditorFeatures/Core/ImplementType/ImplementTypeOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/ImplementTypeOptionsStorage.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.ImplementType @@ -13,6 +15,10 @@ public static ImplementTypeOptions GetImplementTypeOptions(this IGlobalOptionSer InsertionBehavior: globalOptions.GetOption(InsertionBehavior, language), PropertyGenerationBehavior: globalOptions.GetOption(PropertyGenerationBehavior, language)); + public static ImplementTypeGenerationOptions GetImplementTypeGenerationOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) + => new(globalOptions.GetImplementTypeOptions(languageServices.Language), + globalOptions.CreateProvider()); + private const string FeatureName = "ImplementTypeOptions"; public static readonly PerLanguageOption2 InsertionBehavior = diff --git a/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs index d432f368d0a83..67f138f249f17 100644 --- a/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs +++ b/src/Features/LanguageServer/Protocol/Features/Options/MetadataAsSourceOptionsStorage.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Simplification; @@ -13,7 +14,7 @@ internal static class MetadataAsSourceOptionsStorage { public static MetadataAsSourceOptions GetMetadataAsSourceOptions(this IGlobalOptionService globalOptions, HostLanguageServices languageServices) => new( - CleanupOptions: globalOptions.GetCodeCleanupOptions(languageServices), + GenerationOptions: globalOptions.GetCleanCodeGenerationOptions(languageServices), NavigateToDecompiledSources: globalOptions.GetOption(NavigateToDecompiledSources), AlwaysUseDefaultSymbolServers: globalOptions.GetOption(AlwaysUseDefaultSymbolServers)); diff --git a/src/Features/LanguageServer/Protocol/Features/Options/NamingStylePreferencesStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/NamingStylePreferencesStorage.cs new file mode 100644 index 0000000000000..965865012f8b5 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Features/Options/NamingStylePreferencesStorage.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Simplification; + +namespace Microsoft.CodeAnalysis.CodeStyle; + +internal static class NamingStyleOptionsStorage +{ + public static NamingStylePreferences GetNamingStylePreferences(this IGlobalOptionService globalOptions, string language) + => globalOptions.GetOption(NamingStyleOptions.NamingPreferences, language); + + public static NamingStylePreferencesProvider GetNamingStylePreferencesProvider(this IGlobalOptionService globalOptions) + => languageServices => globalOptions.GetNamingStylePreferences(languageServices.Language); +} diff --git a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchOptionsStorage.cs b/src/Features/LanguageServer/Protocol/Features/Options/SymbolSearchOptionsStorage.cs similarity index 100% rename from src/EditorFeatures/Core/SymbolSearch/SymbolSearchOptionsStorage.cs rename to src/Features/LanguageServer/Protocol/Features/Options/SymbolSearchOptionsStorage.cs diff --git a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/IFixAllSuggestedAction.cs b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/IFixAllCodeFixSuggestedAction.cs similarity index 71% rename from src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/IFixAllSuggestedAction.cs rename to src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/IFixAllCodeFixSuggestedAction.cs index 27c3f2d3a2466..3ec606a4a29b5 100644 --- a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/IFixAllSuggestedAction.cs +++ b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/IFixAllCodeFixSuggestedAction.cs @@ -3,20 +3,20 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; namespace Microsoft.CodeAnalysis.UnifiedSuggestions.UnifiedSuggestedActions { /// /// Common interface used by both local Roslyn and LSP to implement - /// their specific versions of FixAllSuggestedAction. + /// their specific versions of FixAllCodeFixSuggestedAction. /// - internal interface IFixAllSuggestedAction + internal interface IFixAllCodeFixSuggestedAction { Diagnostic Diagnostic { get; } CodeAction OriginalCodeAction { get; } - FixAllState? FixAllState { get; } + IFixAllState FixAllState { get; } } } diff --git a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/IFixAllCodeRefactoringSuggestedAction.cs b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/IFixAllCodeRefactoringSuggestedAction.cs new file mode 100644 index 0000000000000..1767d7858bfb4 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/IFixAllCodeRefactoringSuggestedAction.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; + +namespace Microsoft.CodeAnalysis.UnifiedSuggestions.UnifiedSuggestedActions +{ + /// + /// Common interface used by both local Roslyn and LSP to implement + /// their specific versions of FixAllCodeRefactoringSuggestedAction. + /// + internal interface IFixAllCodeRefactoringSuggestedAction + { + CodeAction OriginalCodeAction { get; } + + IFixAllState FixAllState { get; } + } +} diff --git a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedCodeRefactoringSuggestedAction.cs b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedCodeRefactoringSuggestedAction.cs index c553d3efbf2de..0510063053db6 100644 --- a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedCodeRefactoringSuggestedAction.cs +++ b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedCodeRefactoringSuggestedAction.cs @@ -16,14 +16,18 @@ internal class UnifiedCodeRefactoringSuggestedAction : UnifiedSuggestedAction, I { public CodeRefactoringProvider CodeRefactoringProvider { get; } + public UnifiedSuggestedActionSet? FixAllFlavors { get; } + public UnifiedCodeRefactoringSuggestedAction( Workspace workspace, CodeAction codeAction, CodeActionPriority codeActionPriority, - CodeRefactoringProvider codeRefactoringProvider) + CodeRefactoringProvider codeRefactoringProvider, + UnifiedSuggestedActionSet? fixAllFlavors) : base(workspace, codeAction, codeActionPriority) { CodeRefactoringProvider = codeRefactoringProvider; + FixAllFlavors = fixAllFlavors; } } } diff --git a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedFixAllSuggestedAction.cs b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedFixAllCodeFixSuggestedAction.cs similarity index 68% rename from src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedFixAllSuggestedAction.cs rename to src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedFixAllCodeFixSuggestedAction.cs index cee1754022f77..3d6fc0a911d31 100644 --- a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedFixAllSuggestedAction.cs +++ b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedFixAllCodeFixSuggestedAction.cs @@ -4,25 +4,26 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.UnifiedSuggestions.UnifiedSuggestedActions; namespace Microsoft.CodeAnalysis.UnifiedSuggestions { /// - /// Similar to FixAllSuggestedAction, but in a location that can be used by + /// Similar to FixAllCodeFixSuggestedAction, but in a location that can be used by /// both local Roslyn and LSP. /// - internal class UnifiedFixAllSuggestedAction : UnifiedSuggestedAction, IFixAllSuggestedAction + internal class UnifiedFixAllCodeFixSuggestedAction : UnifiedSuggestedAction, IFixAllCodeFixSuggestedAction { public Diagnostic Diagnostic { get; } - public FixAllState? FixAllState { get; } + public IFixAllState FixAllState { get; } - public UnifiedFixAllSuggestedAction( + public UnifiedFixAllCodeFixSuggestedAction( Workspace workspace, CodeAction codeAction, CodeActionPriority codeActionPriority, - FixAllState? fixAllState, + IFixAllState fixAllState, Diagnostic diagnostic) : base(workspace, codeAction, codeActionPriority) { diff --git a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedFixAllCodeRefactoringSuggestedAction.cs b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedFixAllCodeRefactoringSuggestedAction.cs new file mode 100644 index 0000000000000..11f6993cb7301 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActions/UnifiedFixAllCodeRefactoringSuggestedAction.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.UnifiedSuggestions.UnifiedSuggestedActions; + +namespace Microsoft.CodeAnalysis.UnifiedSuggestions +{ + /// + /// Similar to FixAllCodeRefactoringSuggestedAction, but in a location that can be used by + /// both local Roslyn and LSP. + /// + internal class UnifiedFixAllCodeRefactoringSuggestedAction : UnifiedSuggestedAction, IFixAllCodeRefactoringSuggestedAction + { + public IFixAllState FixAllState { get; } + + public UnifiedFixAllCodeRefactoringSuggestedAction( + Workspace workspace, + CodeAction codeAction, + CodeActionPriority codeActionPriority, + IFixAllState fixAllState) + : base(workspace, codeAction, codeActionPriority) + { + FixAllState = fixAllState; + } + } +} diff --git a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index 488b5a9656ebe..141a25762da1c 100644 --- a/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/Features/LanguageServer/Protocol/Features/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeFixesAndRefactorings; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -137,7 +138,7 @@ async Task GetUnifiedSuggestedActionAsync(CodeAction ac { if (action.NestedCodeActions.Length > 0) { - _ = ArrayBuilder.GetInstance(action.NestedCodeActions.Length, out var unifiedNestedActions); + using var _ = ArrayBuilder.GetInstance(action.NestedCodeActions.Length, out var unifiedNestedActions); foreach (var nestedAction in action.NestedCodeActions) { var unifiedNestedAction = await GetUnifiedSuggestedActionAsync(nestedAction, fix).ConfigureAwait(false); @@ -197,7 +198,7 @@ static CodeFixGroupKey GetGroupKey(CodeFix fix) private static async Task GetUnifiedFixAllSuggestedActionSetAsync( CodeAction action, int actionCount, - FixAllState fixAllState, + IFixAllState fixAllState, ImmutableArray supportedScopes, Diagnostic firstDiagnostic, Workspace workspace, @@ -234,7 +235,7 @@ static CodeFixGroupKey GetGroupKey(CodeFix fix) } var fixAllStateForScope = fixAllState.With(scope: scope, codeActionEquivalenceKey: action.EquivalenceKey); - var fixAllSuggestedAction = new UnifiedFixAllSuggestedAction( + var fixAllSuggestedAction = new UnifiedFixAllCodeFixSuggestedAction( workspace, action, action.Priority, fixAllStateForScope, firstDiagnostic); fixAllSuggestedActions.Add(fixAllSuggestedAction); @@ -427,8 +428,14 @@ public static async Task> GetFilterAnd var filteredRefactorings = FilterOnAnyThread(refactorings, selection, filterOutsideSelection); - return filteredRefactorings.SelectAsArray( - r => OrganizeRefactorings(workspace, r)); + using var _ = ArrayBuilder.GetInstance(filteredRefactorings.Length, out var orderedRefactorings); + foreach (var refactoring in filteredRefactorings) + { + var orderedRefactoring = await OrganizeRefactoringsAsync(workspace, document, selection, refactoring, cancellationToken).ConfigureAwait(false); + orderedRefactorings.Add(orderedRefactoring); + } + + return orderedRefactorings.ToImmutable(); } private static ImmutableArray FilterOnAnyThread( @@ -447,7 +454,7 @@ private static ImmutableArray FilterOnAnyThread( ? null : actions.Length == refactoring.CodeActions.Length ? refactoring - : new CodeRefactoring(refactoring.Provider, actions); + : new CodeRefactoring(refactoring.Provider, actions, refactoring.FixAllProviderInfo); bool IsActionAndSpanApplicable((CodeAction action, TextSpan? applicableSpan) actionAndSpan) { @@ -474,34 +481,19 @@ bool IsActionAndSpanApplicable((CodeAction action, TextSpan? applicableSpan) act /// and should show up after fixes but before /// suppression fixes in the light bulb menu. /// - private static UnifiedSuggestedActionSet OrganizeRefactorings(Workspace workspace, CodeRefactoring refactoring) + private static async Task OrganizeRefactoringsAsync( + Workspace workspace, + Document document, + TextSpan selection, + CodeRefactoring refactoring, + CancellationToken cancellationToken) { - using var refactoringSuggestedActionsDisposer = ArrayBuilder.GetInstance(out var refactoringSuggestedActions); + using var _ = ArrayBuilder.GetInstance(out var refactoringSuggestedActions); - foreach (var codeAction in refactoring.CodeActions) + foreach (var (action, applicableToSpan) in refactoring.CodeActions) { - if (codeAction.action.NestedCodeActions.Length > 0) - { - var nestedActions = codeAction.action.NestedCodeActions.SelectAsArray( - na => (IUnifiedSuggestedAction)new UnifiedCodeRefactoringSuggestedAction(workspace, na, na.Priority, refactoring.Provider)); - - var set = new UnifiedSuggestedActionSet( - categoryName: null, - actions: nestedActions, - title: null, - priority: GetUnifiedSuggestedActionSetPriority(codeAction.action.Priority), - applicableToSpan: codeAction.applicableToSpan); - - refactoringSuggestedActions.Add( - new UnifiedSuggestedActionWithNestedActions( - workspace, codeAction.action, codeAction.action.Priority, refactoring.Provider, ImmutableArray.Create(set))); - } - else - { - refactoringSuggestedActions.Add( - new UnifiedCodeRefactoringSuggestedAction( - workspace, codeAction.action, codeAction.action.Priority, refactoring.Provider)); - } + var unifiedActionSet = await GetUnifiedSuggestedActionSetAsync(action, applicableToSpan, selection, cancellationToken).ConfigureAwait(false); + refactoringSuggestedActions.Add(unifiedActionSet); } var actions = refactoringSuggestedActions.ToImmutable(); @@ -519,6 +511,96 @@ private static UnifiedSuggestedActionSet OrganizeRefactorings(Workspace workspac title: null, priority: GetUnifiedSuggestedActionSetPriority(actions.Max(a => a.CodeActionPriority)), applicableToSpan: refactoring.CodeActions.FirstOrDefault().applicableToSpan); + + // Local functions + async Task GetUnifiedSuggestedActionSetAsync(CodeAction codeAction, TextSpan? applicableToSpan, TextSpan selection, CancellationToken cancellationToken) + { + if (codeAction.NestedCodeActions.Length > 0) + { + using var _1 = ArrayBuilder.GetInstance(codeAction.NestedCodeActions.Length, out var nestedActions); + foreach (var nestedAction in codeAction.NestedCodeActions) + { + var unifiedAction = await GetUnifiedSuggestedActionSetAsync(nestedAction, applicableToSpan, selection, cancellationToken).ConfigureAwait(false); + nestedActions.Add(unifiedAction); + } + + var set = new UnifiedSuggestedActionSet( + categoryName: null, + actions: nestedActions.ToImmutable(), + title: null, + priority: GetUnifiedSuggestedActionSetPriority(codeAction.Priority), + applicableToSpan: applicableToSpan); + + return new UnifiedSuggestedActionWithNestedActions( + workspace, codeAction, codeAction.Priority, refactoring.Provider, ImmutableArray.Create(set)); + } + else + { + var fixAllSuggestedActionSet = await GetUnifiedFixAllSuggestedActionSetAsync(codeAction, + refactoring.CodeActions.Length, document, selection, refactoring.Provider, + refactoring.FixAllProviderInfo, workspace, cancellationToken).ConfigureAwait(false); + + return new UnifiedCodeRefactoringSuggestedAction( + workspace, codeAction, codeAction.Priority, refactoring.Provider, fixAllSuggestedActionSet); + } + } + } + + // If the provided fix all context is non-null and the context's code action Id matches + // the given code action's Id, returns the set of fix all occurrences actions associated + // with the code action. + private static async Task GetUnifiedFixAllSuggestedActionSetAsync( + CodeAction action, + int actionCount, + Document document, + TextSpan selection, + CodeRefactoringProvider provider, + FixAllProviderInfo? fixAllProviderInfo, + Workspace workspace, + CancellationToken cancellationToken) + { + if (fixAllProviderInfo == null) + { + return null; + } + + // If the provider registered more than one code action, but provided a null equivalence key + // we have no way to distinguish between which registered actions to apply or ignore for FixAll. + // So, we just bail out for this case. + if (actionCount > 1 && action.EquivalenceKey == null) + { + return null; + } + + using var fixAllSuggestedActionsDisposer = ArrayBuilder.GetInstance(out var fixAllSuggestedActions); + foreach (var scope in fixAllProviderInfo.SupportedScopes) + { + var fixAllState = new CodeRefactorings.FixAllState( + (CodeRefactorings.FixAllProvider)fixAllProviderInfo.FixAllProvider, + document, selection, provider, scope, action); + + if (scope is FixAllScope.ContainingMember or FixAllScope.ContainingType) + { + // Skip showing ContainingMember and ContainingType FixAll scopes if the language + // does not implement 'IFixAllSpanMappingService' langauge service or + // we have no mapped FixAll spans to fix. + var documentsAndSpans = await fixAllState.GetFixAllSpansAsync(cancellationToken).ConfigureAwait(false); + if (documentsAndSpans.IsEmpty) + continue; + } + + var fixAllSuggestedAction = new UnifiedFixAllCodeRefactoringSuggestedAction( + workspace, action, action.Priority, fixAllState); + + fixAllSuggestedActions.Add(fixAllSuggestedAction); + } + + return new UnifiedSuggestedActionSet( + categoryName: null, + actions: fixAllSuggestedActions.ToImmutable(), + title: CodeFixesResources.Fix_all_occurrences_in, + priority: UnifiedSuggestedActionSetPriority.Lowest, + applicableToSpan: null); } private static UnifiedSuggestedActionSetPriority GetUnifiedSuggestedActionSetPriority(CodeActionPriority key) diff --git a/src/Features/LanguageServer/Protocol/Handler/RequestContext.cs b/src/Features/LanguageServer/Protocol/Handler/RequestContext.cs index a62a542f0dccd..f183774e0f004 100644 --- a/src/Features/LanguageServer/Protocol/Handler/RequestContext.cs +++ b/src/Features/LanguageServer/Protocol/Handler/RequestContext.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Immutable; +using System.Threading; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -59,6 +60,10 @@ internal readonly struct RequestContext public readonly IGlobalOptionService GlobalOptions; + public readonly LspWorkspaceManager LspWorkspaceManager; + public readonly ILanguageServerNotificationManager NotificationManager; + public readonly CancellationToken QueueCancellationToken; + /// /// Tracing object that can be used to log information about the status of requests. /// @@ -73,7 +78,10 @@ public RequestContext( IDocumentChangeTracker documentChangeTracker, ImmutableDictionary trackedDocuments, ImmutableArray supportedLanguages, - IGlobalOptionService globalOptions) + IGlobalOptionService globalOptions, + LspWorkspaceManager lspWorkspaceManager, + ILanguageServerNotificationManager notificationManager, + CancellationToken queueCancellationToken) { Document = document; Solution = solution; @@ -84,6 +92,9 @@ public RequestContext( _documentChangeTracker = documentChangeTracker; _logger = logger; _trackedDocuments = trackedDocuments; + LspWorkspaceManager = lspWorkspaceManager; + NotificationManager = notificationManager; + QueueCancellationToken = queueCancellationToken; } public static RequestContext? Create( @@ -93,9 +104,11 @@ public RequestContext( ILspLogger logger, ClientCapabilities clientCapabilities, LspWorkspaceManager lspWorkspaceManager, + ILanguageServerNotificationManager notificationManager, IDocumentChangeTracker documentChangeTracker, ImmutableArray supportedLanguages, - IGlobalOptionService globalOptions) + IGlobalOptionService globalOptions, + CancellationToken queueCancellationToken) { // Retrieve the current LSP tracked text as of this request. // This is safe as all creation of request contexts cannot happen concurrently. @@ -107,7 +120,10 @@ public RequestContext( // so they're not accidentally operating on stale solution state. if (!requiresLSPSolution) { - return new RequestContext(solution: null, logger, clientCapabilities, serverKind, document: null, documentChangeTracker, trackedDocuments, supportedLanguages, globalOptions); + return new RequestContext( + solution: null, logger, clientCapabilities, serverKind, document: null, + documentChangeTracker, trackedDocuments, supportedLanguages, globalOptions, + lspWorkspaceManager, notificationManager, queueCancellationToken); } // Go through each registered workspace, find the solution that contains the document that @@ -140,7 +156,10 @@ public RequestContext( documentChangeTracker, trackedDocuments, supportedLanguages, - globalOptions); + globalOptions, + lspWorkspaceManager, + notificationManager, + queueCancellationToken); return context; } diff --git a/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.QueueItem.cs b/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.QueueItem.cs index 0ec8109ecb26c..756af21c38e94 100644 --- a/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.QueueItem.cs +++ b/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.QueueItem.cs @@ -58,7 +58,7 @@ private class QueueItem : IQueueItem /// A task completion source representing the result of this queue item's work. /// This is the task that the client is waiting on. /// - private readonly TaskCompletionSource _completionSource; + private readonly TaskCompletionSource _completionSource = new(); public bool RequiresLSPSolution { get; } @@ -87,7 +87,6 @@ public QueueItem( RequestTelemetryLogger telemetryLogger, CancellationToken cancellationToken) { - _completionSource = new TaskCompletionSource(); // Set the tcs state to cancelled if the token gets cancelled outside of our callback (for example the server shutting down). cancellationToken.Register(() => _completionSource.TrySetCanceled(cancellationToken)); diff --git a/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs b/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs index 555e139c9d68b..64500d08e003f 100644 --- a/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs +++ b/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs @@ -58,12 +58,13 @@ internal partial class RequestExecutionQueue /// representing the queue's cancellation token and the individual request cancellation token. /// private readonly AsyncQueue<(IQueueItem queueItem, CancellationToken cancellationToken)> _queue = new(); - private readonly CancellationTokenSource _cancelSource = new CancellationTokenSource(); + private readonly CancellationTokenSource _cancelSource = new(); private readonly RequestTelemetryLogger _requestTelemetryLogger; private readonly IGlobalOptionService _globalOptions; private readonly ILspLogger _logger; private readonly LspWorkspaceManager _lspWorkspaceManager; + private readonly ILanguageServerNotificationManager _notificationManager; /// /// For test purposes only. @@ -89,7 +90,8 @@ public RequestExecutionQueue( ImmutableArray supportedLanguages, WellKnownLspServerKinds serverKind, RequestTelemetryLogger requestTelemetryLogger, - LspWorkspaceManager lspWorkspaceManager) + LspWorkspaceManager lspWorkspaceManager, + ILanguageServerNotificationManager notificationManager) { _logger = logger; _globalOptions = globalOptions; @@ -97,6 +99,7 @@ public RequestExecutionQueue( _serverKind = serverKind; _requestTelemetryLogger = requestTelemetryLogger; _lspWorkspaceManager = lspWorkspaceManager; + _notificationManager = notificationManager; // Start the queue processing _queueProcessingTask = ProcessQueueAsync(); @@ -267,9 +270,11 @@ private void OnRequestServerShutdown(string message) _logger, queueItem.ClientCapabilities, _lspWorkspaceManager, + _notificationManager, trackerToUse, _supportedLanguages, - _globalOptions); + _globalOptions, + queueCancellationToken: this.CancellationToken); } } } diff --git a/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/RoslynSemanticTokens.cs b/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/RoslynSemanticTokens.cs deleted file mode 100644 index 44a391d4c8459..0000000000000 --- a/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/RoslynSemanticTokens.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable enable - -using System.Runtime.Serialization; -using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens -{ - internal sealed class RoslynSemanticTokens : LSP.SemanticTokens - { - /// - /// True if the token set is complete, meaning it's generated using a full semantic - /// model rather than a frozen one. - /// - /// - /// Certain clients such as Razor need to know whether we're returning partial - /// (i.e. possibly inaccurate) results. This may occur if the full compilation - /// is not yet available. - /// - [DataMember(Name = "isFinalized")] - public bool IsFinalized { get; set; } - } -} diff --git a/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs b/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs index d0f5b1b8f6046..cd5c0f0e192f3 100644 --- a/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs +++ b/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensHelpers.cs @@ -145,11 +145,6 @@ internal static async Task ComputeSemanticTokensDataAsync( // can pass in a range if they wish. var textSpan = range is null ? root.FullSpan : ProtocolConversions.RangeToTextSpan(range, text); - // If the full compilation is not yet available, we'll try getting a partial one. It may contain inaccurate - // results but will speed up how quickly we can respond to the client's request. - document = document.WithFrozenPartialSemantics(cancellationToken); - options = options with { ForceFrozenPartialSemanticsForCrossProcessOperations = true }; - var classifiedSpans = await GetClassifiedSpansForDocumentAsync( document, textSpan, options, includeSyntacticClassifications, cancellationToken).ConfigureAwait(false); diff --git a/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRangeHandler.cs b/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRangeHandler.cs index eb8b9a554c1fd..55bf81fe95324 100644 --- a/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRangeHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRangeHandler.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Composition; +using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification; @@ -12,6 +14,8 @@ using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.VisualStudio.LanguageServer.Protocol; using Roslyn.Utilities; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; @@ -23,22 +27,57 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens /// [ExportRoslynLanguagesLspRequestHandlerProvider(typeof(SemanticTokensRangeHandler)), Shared] [Method(Methods.TextDocumentSemanticTokensRangeName)] - internal class SemanticTokensRangeHandler : AbstractStatelessRequestHandler + internal class SemanticTokensRangeHandler : AbstractStatelessRequestHandler, IDisposable { private readonly IGlobalOptionService _globalOptions; - - // Lock to guard _projectToCompilation dictionary - private readonly object _lock = new(); - private readonly Dictionary> _projectIdToCompilation = new(); + private readonly IAsynchronousOperationListener _asyncListener; public override bool MutatesSolutionState => false; public override bool RequiresLSPSolution => true; + #region Semantic Tokens Refresh state + + /// + /// Lock over the mutable state that follows. + /// + private readonly object _gate = new(); + + /// + /// Mapping from project id to the workqueue for producing the corresponding compilation for it on the OOP server. + /// + private readonly Dictionary _projectIdToEventSource = new(); + + /// + /// Mapping from project id to the project-cone-checksum for it we were at when the project for it had its + /// compilation produced on the oop server. + /// + private readonly Dictionary _projectIdToLastComputedChecksum = new(); + + // initialized when first request comes in. + + /// + /// Initially null. Set to true/false when first initialized. The other following fields will be set if this + /// is true. + /// + private bool? _supportsRefresh; + + private LspWorkspaceManager? _lspWorkspaceManager; + + /// + /// Debouncing queue so that we don't attempt to issue a semantic tokens refresh notification too often. + /// + private AsyncBatchingWorkQueue? _semanticTokenRefreshQueue; + + #endregion + [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public SemanticTokensRangeHandler(IGlobalOptionService globalOptions) + public SemanticTokensRangeHandler( + IGlobalOptionService globalOptions, + IAsynchronousOperationListenerProvider asynchronousOperationListenerProvider) { _globalOptions = globalOptions; + _asyncListener = asynchronousOperationListenerProvider.GetListener(FeatureAttribute.Classification); } public override LSP.TextDocumentIdentifier? GetTextDocumentIdentifier(LSP.SemanticTokensRangeParams request) @@ -47,73 +86,152 @@ public SemanticTokensRangeHandler(IGlobalOptionService globalOptions) return request.TextDocument; } + public void Dispose() + { + ImmutableArray eventSources; + lock (_gate) + { + eventSources = _projectIdToEventSource.Values.ToImmutableArray(); + _projectIdToEventSource.Clear(); + + if (_lspWorkspaceManager != null) + _lspWorkspaceManager.LspSolutionChanged -= OnLspSolutionChanged; + } + + foreach (var eventSource in eventSources) + eventSource.Dispose(); + } + + /// + /// Returns true/false if refresh is supported for semantic tokens. + /// + private bool InitializeIfFirstRequest(RequestContext context) + { + lock (_gate) + { + if (_supportsRefresh == null) + { + _supportsRefresh = context.ClientCapabilities.Workspace?.SemanticTokens?.RefreshSupport is true; + + if (_supportsRefresh.Value) + { + // Only send a refresh notification to the client every 0.5s (if needed) in order to avoid + // sending too many notifications at once. This ensures we batch up workspace notifications, + // but also means we send soon enough after a compilation-computation to not make the user wait + // an enormous amount of time. + _semanticTokenRefreshQueue = new AsyncBatchingWorkQueue( + delay: TimeSpan.FromMilliseconds(500), + processBatchAsync: c => context.NotificationManager.SendNotificationAsync(Methods.WorkspaceSemanticTokensRefreshName, c), + asyncListener: _asyncListener, + context.QueueCancellationToken); + + _lspWorkspaceManager = context.LspWorkspaceManager; + _lspWorkspaceManager.LspSolutionChanged += OnLspSolutionChanged; + } + } + + return _supportsRefresh.Value; + } + } + + private void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e) + => EnqueueSemanticTokenRefreshNotification(); + + private void EnqueueSemanticTokenRefreshNotification() + { + // We should only get here if refresh was enabled, which only happens in a codepath that ensured the queue + // was instantiated. + Contract.ThrowIfNull(_semanticTokenRefreshQueue); + _semanticTokenRefreshQueue.AddWork(); + } + public override async Task HandleRequestAsync( - LSP.SemanticTokensRangeParams request, + SemanticTokensRangeParams request, RequestContext context, CancellationToken cancellationToken) { + // If this is the first time getting a request, initialize our state with information about the + // server/manager we're owned by. + var supportsRefresh = InitializeIfFirstRequest(context); + Contract.ThrowIfNull(request.TextDocument, "TextDocument is null."); Contract.ThrowIfNull(context.Document, "Document is null."); - var project = context.Document.Project; - var options = _globalOptions.GetClassificationOptions(project.Language); - - // Razor uses isFinalized to determine whether to cache tokens. We should be able to - // remove it altogether once Roslyn implements workspace/semanticTokens/refresh: - // https://github.com/dotnet/roslyn/issues/60441 - var isFinalized = !context.Document.IsRazorDocument() || - await IsDataFinalizedAsync(project, cancellationToken).ConfigureAwait(false); + // If the full compilation is not yet available, we'll try getting a partial one. It may contain inaccurate + // results but will speed up how quickly we can respond to the client's request. + var document = context.Document.WithFrozenPartialSemantics(cancellationToken); + var project = document.Project; + var options = _globalOptions.GetClassificationOptions(project.Language) with { ForceFrozenPartialSemanticsForCrossProcessOperations = true }; // The results from the range handler should not be cached since we don't want to cache // partial token results. In addition, a range request is only ever called with a whole // document request, so caching range results is unnecessary since the whole document // handler will cache the results anyway. var tokensData = await SemanticTokensHelpers.ComputeSemanticTokensDataAsync( - context.Document, + document, SemanticTokensHelpers.TokenTypeToIndex, request.Range, options, includeSyntacticClassifications: context.Document.IsRazorDocument(), cancellationToken).ConfigureAwait(false); - return new RoslynSemanticTokens { Data = tokensData, IsFinalized = isFinalized }; + // The above call to get semantic tokens may be inaccurate (because we use frozen partial semantics). Kick + // off a request to ensure that the OOP side gets a fully up to compilation for this project. Once it does + // we can optionally choose to notify our caller to do a refresh if we computed a compilation for a new + // solution snapshot. + if (supportsRefresh) + await TryEnqueueRefreshComputationAsync(project, cancellationToken).ConfigureAwait(false); + + return new LSP.SemanticTokens { Data = tokensData }; } - private async Task IsDataFinalizedAsync(Project project, CancellationToken cancellationToken) + private async Task TryEnqueueRefreshComputationAsync(Project project, CancellationToken cancellationToken) { - // We use a combination of IsFullyLoaded + the completed project compilation as the metric - // for isFinalized. It may not be completely accurate but this is only a a temporary fix until - // workspace/semanticTokens/refresh is implemented. - lock (_lock) + // Determine the checksum for this project cone. Note: this should be fast in practice because this is + // the same project-cone-checksum we used to even call into OOp above when we computed semantic tokens. + var projectChecksum = await project.Solution.State.GetChecksumAsync(project.Id, cancellationToken).ConfigureAwait(false); + + lock (_gate) { - if (_projectIdToCompilation.TryGetValue(project.Id, out var compilationTask) && compilationTask.IsCompleted) - { - // We don't want to hang on to the compilation since this can be very expensive, - // but we do want to mark the compilation as being successfully retrieved. - if (compilationTask.Result is not null) - { - _projectIdToCompilation[project.Id] = Task.FromResult(null); - } + // If this checksum is the same as the last computed result, no need to continue, we would not produce a + // different compilation. + if (ChecksumIsUnchanged_NoLock(project, projectChecksum)) + return; - return true; + if (!_projectIdToEventSource.TryGetValue(project.Id, out var eventSource)) + { + eventSource = new CompilationAvailableEventSource(_asyncListener); + _projectIdToEventSource.Add(project.Id, eventSource); } - } - var workspaceStatusService = project.Solution.Workspace.Services.GetRequiredService(); - var isFullyLoaded = await workspaceStatusService.IsFullyLoadedAsync(cancellationToken).ConfigureAwait(false); + eventSource.EnsureCompilationAvailability(project, () => OnCompilationAvailable(project, projectChecksum)); + } + } - lock (_lock) + private void OnCompilationAvailable(Project project, Checksum projectChecksum) + { + lock (_gate) { - if (isFullyLoaded && !_projectIdToCompilation.ContainsKey(project.Id)) - { - // If the project's compilation isn't yet available, kick off a task in the background to - // hopefully make it available faster since we'll need it later to compute tokens. - var newCompilationTask = project.GetCompilationAsync(cancellationToken); - _projectIdToCompilation.Add(project.Id, newCompilationTask); - } + // Paranoia: It's technically possible (though unlikely) for two calls to compute the compilation for + // the same project to come back and call into this. This is because the + // CompilationAvailableEventSource uses cooperative cancellation to cancel the in-flight request before + // issuing the new one. There is no requirement though that the inflight request actually stop (or run + // to completion) prior to the next request running and completing. In practice this should not happen + // as cancellation is checked fairly regularly. However, if it does, check and do not bother to issue a + // refresh in this case. + if (ChecksumIsUnchanged_NoLock(project, projectChecksum)) + return; + + // keep track of this checksum. That way we don't get into a loop where we send a refresh notification, + // then we get called back into, causing us to compute the compilation, causing us to send the refresh + // notification, etc. etc. + _projectIdToLastComputedChecksum[project.Id] = projectChecksum; } - return false; + EnqueueSemanticTokenRefreshNotification(); } + + private bool ChecksumIsUnchanged_NoLock(Project project, Checksum projectChecksum) + => _projectIdToLastComputedChecksum.TryGetValue(project.Id, out var lastChecksum) && lastChecksum == projectChecksum; } } diff --git a/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshListener.cs b/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshListener.cs deleted file mode 100644 index 6d30982ce77a8..0000000000000 --- a/src/Features/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshListener.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.VisualStudio.LanguageServer.Protocol; -using Newtonsoft.Json.Linq; -using Roslyn.Utilities; -using StreamJsonRpc; - -namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens -{ - /// - /// Sends a notification from server->client indicating something has changed in the LSP workspace. - /// The client will then send a request to the server for refreshed tokens. - /// - internal class SemanticTokensRefreshListener - { - private readonly LspWorkspaceManager _lspWorkspaceManager; - private readonly ILanguageServerNotificationManager _languageServerNotificationManager; - private readonly AsyncBatchingWorkQueue _workQueue; - - public SemanticTokensRefreshListener( - LspWorkspaceManager lspWorkspaceManager, - ILanguageServerNotificationManager languageServerNotificationManager, - IAsynchronousOperationListener listener, - CancellationToken cancellationToken) - { - _lspWorkspaceManager = lspWorkspaceManager; - _languageServerNotificationManager = languageServerNotificationManager; - _lspWorkspaceManager.LspSolutionChanged += OnLspWorkspaceChanged; - - // Only send a refresh notification to the client every 2s (if needed) - // in order to avoid sending too many notifications at once. - _workQueue = new AsyncBatchingWorkQueue( - delay: TimeSpan.FromMilliseconds(2000), - processBatchAsync: SendSemanticTokensNotificationAsync, - asyncListener: listener, - cancellationToken); - } - - private void OnLspWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e) => _workQueue.AddWork(); - - // TO-DO: Replace hardcoded string with const once LSP side is merged. - public ValueTask SendSemanticTokensNotificationAsync(CancellationToken cancellationToken) - => _languageServerNotificationManager.SendNotificationAsync(Methods.WorkspaceSemanticTokensRefreshName, cancellationToken); - - public void Dispose() - { - _lspWorkspaceManager.LspSolutionChanged -= OnLspWorkspaceChanged; - } - } -} diff --git a/src/Features/LanguageServer/Protocol/LanguageServerTarget.cs b/src/Features/LanguageServer/Protocol/LanguageServerTarget.cs index fc8363bc43475..ff2b5fa7fd0d3 100644 --- a/src/Features/LanguageServer/Protocol/LanguageServerTarget.cs +++ b/src/Features/LanguageServer/Protocol/LanguageServerTarget.cs @@ -36,9 +36,6 @@ internal class LanguageServerTarget : ILanguageServerTarget // Set on first LSP initialize request. private ClientCapabilities? _clientCapabilities; - // Set on initialized. - private SemanticTokensRefreshListener? _semanticTokensRefreshListener; - // Fields used during shutdown. private bool _shuttingDown; private Task? _errorShutdownTask; @@ -82,7 +79,8 @@ internal LanguageServerTarget( supportedLanguages, serverKind, _requestTelemetryLogger, - _lspWorkspaceManager); + _lspWorkspaceManager, + _notificationManager); _queue.RequestServerShutdown += RequestExecutionQueue_Errored; var entryPointMethod = typeof(DelegatingEntryPoint).GetMethod(nameof(DelegatingEntryPoint.EntryPointAsync)); @@ -162,12 +160,6 @@ public Task InitializeAsync(InitializeParams initializeParams, public virtual Task InitializedAsync(CancellationToken cancellationToken) { Contract.ThrowIfNull(_clientCapabilities); - if (_clientCapabilities.Workspace is not null && _clientCapabilities.Workspace.SemanticTokens.RefreshSupport) - { - _semanticTokensRefreshListener = new SemanticTokensRefreshListener( - _lspWorkspaceManager, _notificationManager, _listener, cancellationToken); - } - return Task.CompletedTask; } @@ -255,7 +247,6 @@ private void ShutdownRequestQueue() // won't cause any problems calling it again _queue.Shutdown(); - _semanticTokensRefreshListener?.Dispose(); _requestTelemetryLogger.Dispose(); _lspWorkspaceManager.Dispose(); } diff --git a/src/Features/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs index e76778c1fa6af..61b3ffbd42605 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs @@ -21,7 +21,7 @@ public abstract class AbstractSemanticTokensTests : AbstractLanguageServerProtoc { private protected static async Task RunGetSemanticTokensRangeAsync(TestLspServer testLspServer, LSP.Location caret, LSP.Range range) { - var result = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentSemanticTokensRangeName, + var result = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentSemanticTokensRangeName, CreateSemanticTokensRangeParams(caret, range), CancellationToken.None); Contract.ThrowIfNull(result); return result; diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEndConstruct/GenerateEndConstructCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEndConstruct/GenerateEndConstructCodeFixProvider.vb index 6ce7418cb3269..b3560b6cf596a 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEndConstruct/GenerateEndConstructCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEndConstruct/GenerateEndConstructCodeFixProvider.vb @@ -82,9 +82,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEndConstruct If endStatement.Parent.Kind = SyntaxKind.PropertyBlock Then context.RegisterCodeFix( - New MyCodeAction( + CodeAction.Create( VBFeaturesResources.Insert_the_missing_End_Property_statement, - Function(c) GeneratePropertyEndConstructAsync(context.Document, DirectCast(endStatement.Parent, PropertyBlockSyntax), c)), + Function(c) GeneratePropertyEndConstructAsync(context.Document, DirectCast(endStatement.Parent, PropertyBlockSyntax), c), + NameOf(VBFeaturesResources.Insert_the_missing_End_Property_statement)), context.Diagnostics) Return End If @@ -92,18 +93,21 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEndConstruct If endStatement.Kind = SyntaxKind.EndGetStatement OrElse endStatement.Kind = SyntaxKind.EndSetStatement Then If endStatement?.Parent?.Parent.Kind = SyntaxKind.PropertyBlock Then context.RegisterCodeFix( - New MyCodeAction( + CodeAction.Create( VBFeaturesResources.Insert_the_missing_End_Property_statement, - Function(c) GeneratePropertyEndConstructAsync(context.Document, DirectCast(endStatement.Parent.Parent, PropertyBlockSyntax), c)), + Function(c) GeneratePropertyEndConstructAsync(context.Document, DirectCast(endStatement.Parent.Parent, PropertyBlockSyntax), c), + NameOf(VBFeaturesResources.Insert_the_missing_End_Property_statement)), context.Diagnostics) Return End If End If + Dim title = GetDescription(endStatement) context.RegisterCodeFix( - New MyCodeAction( - GetDescription(endStatement), - Function(c) GenerateEndConstructAsync(context.Document, endStatement, c)), + CodeAction.Create( + title, + Function(c) GenerateEndConstructAsync(context.Document, endStatement, c), + title), context.Diagnostics) End Function @@ -254,13 +258,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEndConstruct Return updatedDocument End Function - - Private Class MyCodeAction - Inherits CodeAction.DocumentChangeAction - - Public Sub New(title As String, createChangedDocument As Func(Of CancellationToken, Task(Of Document))) - MyBase.New(title, createChangedDocument, title) - End Sub - End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.vb index 0f448c7efc67c..98cfb2c72bd98 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEnumMember/GenerateEnumMemberCodeFixProvider.vb @@ -9,6 +9,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.CodeFixes.GenerateMember +Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.GenerateMember.GenerateEnumMember Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -31,9 +32,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEnumMember End Get End Property - Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) + Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, fallbackOptions As CodeAndImportGenerationOptionsProvider, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) Dim service = document.GetLanguageService(Of IGenerateEnumMemberService)() - Return service.GenerateEnumMemberAsync(document, node, cancellationToken) + Return service.GenerateEnumMemberAsync(document, node, fallbackOptions, cancellationToken) End Function Protected Overrides Function IsCandidate(node As SyntaxNode, token As SyntaxToken, diagnostic As Diagnostic) As Boolean diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.CodeAction.vb b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.CodeAction.vb index b6ac043fa5026..be371df651dd6 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.CodeAction.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.CodeAction.vb @@ -15,15 +15,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent Private ReadOnly _targetSymbol As INamedTypeSymbol Private ReadOnly _generatedEvent As IEventSymbol Private ReadOnly _codeGenService As ICodeGenerationService + Private ReadOnly _fallbackOptions As CodeAndImportGenerationOptionsProvider Public Sub New(solution As Solution, targetSymbol As INamedTypeSymbol, generatedEvent As IEventSymbol, - codeGenService As ICodeGenerationService) + codeGenService As ICodeGenerationService, + fallbackOptions As CodeAndImportGenerationOptionsProvider) _solution = solution _targetSymbol = targetSymbol _generatedEvent = generatedEvent _codeGenService = codeGenService + _fallbackOptions = fallbackOptions End Sub Public Overrides ReadOnly Property Title As String @@ -34,8 +37,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent Protected Overrides Function GetChangedDocumentAsync(cancellationToken As CancellationToken) As Task(Of Document) Return _codeGenService.AddEventAsync( - _solution, _targetSymbol, _generatedEvent, - CodeGenerationContext.Default, cancellationToken) + New CodeGenerationSolutionContext( + _solution, + CodeGenerationContext.Default, + _fallbackOptions), + _targetSymbol, + _generatedEvent, + cancellationToken) End Function End Class End Class diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb index a0837df596ca2..25e61ae3edfa1 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb @@ -53,17 +53,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent For Each node In token.GetAncestors(Of SyntaxNode).Where(Function(c) c.Span.IntersectsWith(context.Span) AndAlso IsCandidate(c)) Dim qualifiedName = TryCast(node, QualifiedNameSyntax) If qualifiedName IsNot Nothing Then - result = Await GenerateEventFromImplementsAsync(context.Document, qualifiedName, context.CancellationToken).ConfigureAwait(False) + result = Await GenerateEventFromImplementsAsync(context.Document, qualifiedName, context.Options, context.CancellationToken).ConfigureAwait(False) End If Dim handlesClauseItem = TryCast(node, HandlesClauseItemSyntax) If handlesClauseItem IsNot Nothing Then - result = Await GenerateEventFromHandlesAsync(context.Document, handlesClauseItem, context.CancellationToken).ConfigureAwait(False) + result = Await GenerateEventFromHandlesAsync(context.Document, handlesClauseItem, context.Options, context.CancellationToken).ConfigureAwait(False) End If Dim handlerStatement = TryCast(node, AddRemoveHandlerStatementSyntax) If handlerStatement IsNot Nothing Then - result = Await GenerateEventFromAddRemoveHandlerAsync(context.Document, handlerStatement, context.CancellationToken).ConfigureAwait(False) + result = Await GenerateEventFromAddRemoveHandlerAsync(context.Document, handlerStatement, context.Options, context.CancellationToken).ConfigureAwait(False) End If If result IsNot Nothing Then @@ -73,7 +73,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent Next End Function - Private Shared Async Function GenerateEventFromAddRemoveHandlerAsync(document As Document, handlerStatement As AddRemoveHandlerStatementSyntax, cancellationToken As CancellationToken) As Task(Of CodeAction) + Private Shared Async Function GenerateEventFromAddRemoveHandlerAsync(document As Document, handlerStatement As AddRemoveHandlerStatementSyntax, fallbackOptions As CodeAndImportGenerationOptionsProvider, cancellationToken As CancellationToken) As Task(Of CodeAction) Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) Dim handlerExpression = GetHandlerExpression(handlerStatement) @@ -113,10 +113,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent Return Nothing End If - Return Await GenerateCodeActionAsync(document, semanticModel, delegateSymbol, actualEventName, targetType, cancellationToken).ConfigureAwait(False) + Return Await GenerateCodeActionAsync(document, semanticModel, delegateSymbol, actualEventName, targetType, fallbackOptions, cancellationToken).ConfigureAwait(False) End Function - Private Shared Async Function GenerateCodeActionAsync(document As Document, semanticModel As SemanticModel, delegateSymbol As IMethodSymbol, actualEventName As String, targetType As INamedTypeSymbol, cancellationToken As CancellationToken) As Task(Of CodeAction) + Private Shared Async Function GenerateCodeActionAsync( + document As Document, + semanticModel As SemanticModel, + delegateSymbol As IMethodSymbol, + actualEventName As String, + targetType As INamedTypeSymbol, + fallbackOptions As CodeAndImportGenerationOptionsProvider, + cancellationToken As CancellationToken) As Task(Of CodeAction) + Dim codeGenService = document.Project.Solution.Workspace.Services.GetLanguageServices(targetType.Language).GetService(Of ICodeGenerationService) Dim syntaxFactService = document.Project.Solution.Workspace.Services.GetLanguageServices(targetType.Language).GetService(Of ISyntaxFactsService) @@ -147,7 +155,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent ' instead of an 'As' clause. delegateType.AssociatedSymbol = generatedEvent - Return New GenerateEventCodeAction(document.Project.Solution, targetType, generatedEvent, codeGenService) + Return New GenerateEventCodeAction(document.Project.Solution, targetType, generatedEvent, codeGenService, fallbackOptions) End Function Private Shared Function GetHandlerExpression(handlerStatement As AddRemoveHandlerStatementSyntax) As ExpressionSyntax @@ -231,7 +239,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent Return TypeOf node Is HandlesClauseItemSyntax OrElse TypeOf node Is QualifiedNameSyntax OrElse TypeOf node Is AddRemoveHandlerStatementSyntax End Function - Private Shared Async Function GenerateEventFromImplementsAsync(document As Document, node As QualifiedNameSyntax, cancellationToken As CancellationToken) As Task(Of CodeAction) + Private Shared Async Function GenerateEventFromImplementsAsync(document As Document, node As QualifiedNameSyntax, fallbackOptions As CodeAndImportGenerationOptionsProvider, cancellationToken As CancellationToken) As Task(Of CodeAction) If node.Right.IsMissing Then Return Nothing End If @@ -296,15 +304,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent ' instead of an 'As' clause. eventHandlerType.AssociatedSymbol = generatedEvent - Return New GenerateEventCodeAction(document.Project.Solution, targetType, generatedEvent, codeGenService) + Return New GenerateEventCodeAction(document.Project.Solution, targetType, generatedEvent, codeGenService, fallbackOptions) Else ' Event with no parameters. Dim generatedMember = CodeGenerationSymbolFactory.CreateEventSymbol(boundEvent, name:=actualEventName) - Return New GenerateEventCodeAction(document.Project.Solution, targetType, generatedMember, codeGenService) + Return New GenerateEventCodeAction(document.Project.Solution, targetType, generatedMember, codeGenService, fallbackOptions) End If End Function - Private Shared Async Function GenerateEventFromHandlesAsync(document As Document, handlesClauseItem As HandlesClauseItemSyntax, cancellationToken As CancellationToken) As Task(Of CodeAction) + Private Shared Async Function GenerateEventFromHandlesAsync(document As Document, handlesClauseItem As HandlesClauseItemSyntax, fallbackOptions As CodeAndImportGenerationOptionsProvider, cancellationToken As CancellationToken) As Task(Of CodeAction) If handlesClauseItem.IsMissing OrElse handlesClauseItem.EventContainer.IsMissing OrElse handlesClauseItem.EventMember.IsMissing Then Return Nothing End If @@ -396,8 +404,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent delegateType.AssociatedSymbol = generatedEvent Return New GenerateEventCodeAction( - document.Project.Solution, originalTargetType, generatedEvent, - codeGenService) + document.Project.Solution, originalTargetType, generatedEvent, codeGenService, fallbackOptions) End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateConversionCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateConversionCodeFixProvider.vb index 2bb303b8b94e9..76f5fb193d21e 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateConversionCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateConversionCodeFixProvider.vb @@ -9,6 +9,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.CodeFixes.GenerateMember +Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -31,9 +32,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateMethod End Get End Property - Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) + Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, fallbackOptions As CodeAndImportGenerationOptionsProvider, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) Dim service = document.GetLanguageService(Of IGenerateConversionService)() - Return service.GenerateConversionAsync(document, node, cancellationToken) + Return service.GenerateConversionAsync(document, node, fallbackOptions, cancellationToken) End Function Protected Overrides Function IsCandidate(node As SyntaxNode, token As SyntaxToken, diagnostic As Diagnostic) As Boolean diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateParameterizedMemberCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateParameterizedMemberCodeFixProvider.vb index 595186755b84b..22ca8aef89b7d 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateParameterizedMemberCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/GenerateParameterizedMember/GenerateParameterizedMemberCodeFixProvider.vb @@ -9,6 +9,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.CodeFixes.GenerateMember +Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.GenerateMember.GenerateParameterizedMember Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -50,9 +51,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateMethod End Get End Property - Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) + Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, fallbackOptions As CodeAndImportGenerationOptionsProvider, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) Dim service = document.GetLanguageService(Of IGenerateParameterizedMemberService)() - Return service.GenerateMethodAsync(document, node, cancellationToken) + Return service.GenerateMethodAsync(document, node, fallbackOptions, cancellationToken) End Function Protected Overrides Function IsCandidate(node As SyntaxNode, token As SyntaxToken, diagnostic As Diagnostic) As Boolean diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateType/GenerateTypeCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/GenerateType/GenerateTypeCodeFixProvider.vb index a71c85b53e08a..3dcf7f51329f7 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateType/GenerateTypeCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/GenerateType/GenerateTypeCodeFixProvider.vb @@ -9,6 +9,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.CodeFixes.GenerateMember +Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.GenerateType Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -39,9 +40,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateType End Get End Property - Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) + Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, fallbackOptions As CodeAndImportGenerationOptionsProvider, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) Dim service = document.GetLanguageService(Of IGenerateTypeService)() - Return service.GenerateTypeAsync(document, node, cancellationToken) + Return service.GenerateTypeAsync(document, node, fallbackOptions, cancellationToken) End Function Protected Overrides Function IsCandidate(node As SyntaxNode, token As SyntaxToken, diagnostic As Diagnostic) As Boolean diff --git a/src/Features/VisualBasic/Portable/CodeFixes/IncorrectFunctionReturnType/IncorrectFunctionReturnTypeCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/IncorrectFunctionReturnType/IncorrectFunctionReturnTypeCodeFixProvider.vb index 65154b371977c..aaefe83490467 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/IncorrectFunctionReturnType/IncorrectFunctionReturnTypeCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/IncorrectFunctionReturnType/IncorrectFunctionReturnTypeCodeFixProvider.vb @@ -80,18 +80,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.IncorrectFunctionReturnTy Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) Dim newRoot = root.ReplaceNode(node, rewrittenNode) Dim newDocument = document.WithSyntaxRoot(newRoot) - Return {New MyCodeAction(newDocument)} + Return {CodeAction.Create( + VBFeaturesResources.Fix_Incorrect_Function_Return_Type, + Function(c) Task.FromResult(newDocument), + NameOf(VBFeaturesResources.Fix_Incorrect_Function_Return_Type))} End If Return SpecializedCollections.EmptyEnumerable(Of CodeAction)() End Function - - Private Class MyCodeAction - Inherits CodeAction.DocumentChangeAction - - Public Sub New(newDocument As Document) - MyBase.New(VBFeaturesResources.Fix_Incorrect_Function_Return_Type, Function(c) Task.FromResult(newDocument), NameOf(VBFeaturesResources.Fix_Incorrect_Function_Return_Type)) - End Sub - End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/CodeFixes/OverloadBase/OverloadBaseCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/OverloadBase/OverloadBaseCodeFixProvider.vb index 898dc577db506..99cdd9589a84b 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/OverloadBase/OverloadBaseCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/OverloadBase/OverloadBaseCodeFixProvider.vb @@ -4,6 +4,7 @@ Imports System.Collections.Immutable Imports System.Composition +Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef @@ -45,9 +46,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.OverloadBase End If If diagnostic.Descriptor.Id = BC40003 Then - context.RegisterCodeFix(New AddKeywordAction(context.Document, token.Parent, VBFeaturesResources.Add_Overloads, SyntaxKind.OverloadsKeyword, SyntaxFormattingOptions.CreateProvider(context.Options)), context.Diagnostics) + context.RegisterCodeFix(New AddKeywordAction(context.Document, token.Parent, VBFeaturesResources.Add_Overloads, SyntaxKind.OverloadsKeyword, context.Options), context.Diagnostics) ElseIf diagnostic.Descriptor.Id = BC40004 Then - context.RegisterCodeFix(New AddKeywordAction(context.Document, token.Parent, VBFeaturesResources.Add_Shadows, SyntaxKind.ShadowsKeyword, SyntaxFormattingOptions.CreateProvider(context.Options)), context.Diagnostics) + context.RegisterCodeFix(New AddKeywordAction(context.Document, token.Parent, VBFeaturesResources.Add_Shadows, SyntaxKind.ShadowsKeyword, context.Options), context.Diagnostics) End If End Function End Class diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb index 7317a24165387..a3043da8e5451 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/VisualBasicInlineTemporaryCodeRefactoringProvider.vb @@ -60,7 +60,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary End If context.RegisterRefactoring( - New MyCodeAction(Function(c) InlineTemporaryAsync(document, modifiedIdentifier, c)), variableDeclarator.Span) + CodeAction.Create( + VBFeaturesResources.Inline_temporary_variable, + Function(c) InlineTemporaryAsync(document, modifiedIdentifier, c), + NameOf(VBFeaturesResources.Inline_temporary_variable)), + variableDeclarator.Span) End Function Private Shared Function HasConflict( @@ -465,13 +469,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary Return Await inlinedDocument.ReplaceNodesAsync(replacementNodesWithChangedSemantics.Keys, conflictAnnotationAdder, cancellationToken).ConfigureAwait(False) End Function - - Private Class MyCodeAction - Inherits CodeAction.DocumentChangeAction - - Public Sub New(createChangedDocument As Func(Of CancellationToken, Task(Of Document))) - MyBase.New(VBFeaturesResources.Inline_temporary_variable, createChangedDocument, NameOf(VBFeaturesResources.Inline_temporary_variable)) - End Sub - End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/ConvertAutoPropertyToFullProperty/VisualBasicConvertAutoPropertyToFullProperty.vb b/src/Features/VisualBasic/Portable/ConvertAutoPropertyToFullProperty/VisualBasicConvertAutoPropertyToFullProperty.vb index ae22a97584cee..313a6aa6a82d1 100644 --- a/src/Features/VisualBasic/Portable/ConvertAutoPropertyToFullProperty/VisualBasicConvertAutoPropertyToFullProperty.vb +++ b/src/Features/VisualBasic/Portable/ConvertAutoPropertyToFullProperty/VisualBasicConvertAutoPropertyToFullProperty.vb @@ -16,7 +16,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertAutoPropertyToFullProperty Friend Class VisualBasicConvertAutoPropertyToFullPropertyCodeRefactoringProvider - Inherits AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider(Of PropertyStatementSyntax, TypeBlockSyntax, VisualBasicCodeGenerationPreferences) + Inherits AbstractConvertAutoPropertyToFullPropertyCodeRefactoringProvider(Of PropertyStatementSyntax, TypeBlockSyntax, VisualBasicCodeGenerationContextInfo) Private Const Underscore As String = "_" @@ -34,9 +34,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertAutoPropertyToFullProperty Return Task.FromResult(Underscore + propertySymbol.Name) End Function - Friend Overrides Function GetNewAccessors(preferences As VisualBasicCodeGenerationPreferences, propertyNode As SyntaxNode, - fieldName As String, generator As SyntaxGenerator) _ - As (newGetAccessor As SyntaxNode, newSetAccessor As SyntaxNode) + Friend Overrides Function GetNewAccessors( + info As VisualBasicCodeGenerationContextInfo, + propertyNode As SyntaxNode, + fieldName As String, + generator As SyntaxGenerator) As (newGetAccessor As SyntaxNode, newSetAccessor As SyntaxNode) Dim returnStatement = New SyntaxList(Of StatementSyntax)(DirectCast(generator.ReturnStatement( generator.IdentifierName(fieldName)), StatementSyntax)) @@ -80,7 +82,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertAutoPropertyToFullProperty Return DirectCast(propertyNode, PropertyStatementSyntax).Initializer?.Value End Function - Friend Overrides Function ConvertPropertyToExpressionBodyIfDesired(preferences As VisualBasicCodeGenerationPreferences, propertyNode As SyntaxNode) As SyntaxNode + Friend Overrides Function ConvertPropertyToExpressionBodyIfDesired(info As VisualBasicCodeGenerationContextInfo, propertyNode As SyntaxNode) As SyntaxNode Return propertyNode End Function diff --git a/src/Features/VisualBasic/Portable/EncapsulateField/VisualBasicEncapsulateFieldService.vb b/src/Features/VisualBasic/Portable/EncapsulateField/VisualBasicEncapsulateFieldService.vb index c090fa61cfc31..d34283af4824e 100644 --- a/src/Features/VisualBasic/Portable/EncapsulateField/VisualBasicEncapsulateFieldService.vb +++ b/src/Features/VisualBasic/Portable/EncapsulateField/VisualBasicEncapsulateFieldService.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports System.Composition Imports System.Threading +Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.EncapsulateField Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef @@ -21,11 +22,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EncapsulateField Public Sub New() End Sub - Protected Overrides Async Function RewriteFieldNameAndAccessibilityAsync(originalFieldName As String, - makePrivate As Boolean, - document As Document, - declarationAnnotation As SyntaxAnnotation, - cancellationToken As CancellationToken) As Task(Of SyntaxNode) + Protected Overrides Async Function RewriteFieldNameAndAccessibilityAsync( + originalFieldName As String, + makePrivate As Boolean, + document As Document, + declarationAnnotation As SyntaxAnnotation, + fallbackOptions As CodeAndImportGenerationOptionsProvider, + cancellationToken As CancellationToken) As Task(Of SyntaxNode) Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicExtractMethodService.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicExtractMethodService.vb index f8418af28345e..81b853e7223cd 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicExtractMethodService.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicExtractMethodService.vb @@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.Text Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod - Friend Class VisualBasicExtractMethodService + Friend NotInheritable Class VisualBasicExtractMethodService Inherits AbstractExtractMethodService(Of VisualBasicSelectionValidator, VisualBasicMethodExtractor, VisualBasicSelectionResult) @@ -20,13 +20,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod Protected Overrides Function CreateSelectionValidator(document As SemanticDocument, textSpan As TextSpan, - localFunction As Boolean, - options As ExtractMethodOptions) As VisualBasicSelectionValidator + options As ExtractMethodOptions, + localFunction As Boolean) As VisualBasicSelectionValidator Return New VisualBasicSelectionValidator(document, textSpan, options) End Function - Protected Overrides Function CreateMethodExtractor(selectionResult As VisualBasicSelectionResult, localFunction As Boolean) As VisualBasicMethodExtractor - Return New VisualBasicMethodExtractor(selectionResult) + Protected Overrides Function CreateMethodExtractor(selectionResult As VisualBasicSelectionResult, options As ExtractMethodGenerationOptions, localFunction As Boolean) As VisualBasicMethodExtractor + Return New VisualBasicMethodExtractor(selectionResult, options) End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb index f66afae74afef..2f47b5dd6822a 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb @@ -13,11 +13,13 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.Simplification Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration +Imports Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod Partial Friend Class VisualBasicMethodExtractor Partial Private MustInherit Class VisualBasicCodeGenerator - Inherits CodeGenerator(Of StatementSyntax, ExpressionSyntax, StatementSyntax) + Inherits CodeGenerator(Of StatementSyntax, ExpressionSyntax, StatementSyntax, VisualBasicCodeGenerationOptions) Private ReadOnly _methodName As SyntaxToken @@ -44,7 +46,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod End Function Protected Sub New(insertionPoint As InsertionPoint, selectionResult As SelectionResult, analyzerResult As AnalyzerResult) - MyBase.New(insertionPoint, selectionResult, analyzerResult, OptionValueSet.Empty) + MyBase.New(insertionPoint, selectionResult, analyzerResult, VisualBasicCodeGenerationOptions.Default, Function(language) NamingStylePreferences.Default, localFunction:=False) Contract.ThrowIfFalse(Me.SemanticDocument Is selectionResult.SemanticDocument) Me._methodName = CreateMethodName().WithAdditionalAnnotations(MethodNameAnnotation) diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb index 5407bc1808d14..7dbde2a0b8fc0 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.ExtractMethod Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Formatting.Rules @@ -17,8 +18,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod Partial Friend Class VisualBasicMethodExtractor Inherits MethodExtractor - Public Sub New(result As VisualBasicSelectionResult) - MyBase.New(result, localFunction:=False) + Public Sub New(result As VisualBasicSelectionResult, options As ExtractMethodGenerationOptions) + MyBase.New(result, options, localFunction:=False) End Sub Protected Overrides Function AnalyzeAsync(selectionResult As SelectionResult, localFunction As Boolean, cancellationToken As CancellationToken) As Task(Of AnalyzerResult) @@ -67,7 +68,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod Return Await selection.SemanticDocument.WithSyntaxRootAsync(selection.SemanticDocument.Root.ReplaceNode(lastExpression, newStatement), cancellationToken).ConfigureAwait(False) End Function - Protected Overrides Function GenerateCodeAsync(insertionPoint As InsertionPoint, selectionResult As SelectionResult, analyzeResult As AnalyzerResult, options As OptionSet, cancellationToken As CancellationToken) As Task(Of GeneratedCode) + Protected Overrides Function GenerateCodeAsync(insertionPoint As InsertionPoint, selectionResult As SelectionResult, analyzeResult As AnalyzerResult, options As CodeGenerationOptions, namingPreferences As NamingStylePreferencesProvider, cancellationToken As CancellationToken) As Task(Of GeneratedCode) Return VisualBasicCodeGenerator.GenerateResultAsync(insertionPoint, selectionResult, analyzeResult, cancellationToken) End Function diff --git a/src/Features/VisualBasic/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.vb b/src/Features/VisualBasic/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.vb index ce32658b465ec..fe4a611523c25 100644 --- a/src/Features/VisualBasic/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/GenerateConstructor/GenerateConstructorCodeFixProvider.vb @@ -9,6 +9,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.CodeFixes.GenerateMember +Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.GenerateMember.GenerateConstructor Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -48,9 +49,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateConstructor End Get End Property - Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) + Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, fallbackOptions As CodeAndImportGenerationOptionsProvider, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) Dim service = document.GetLanguageService(Of IGenerateConstructorService)() - Return service.GenerateConstructorAsync(document, node, cancellationToken) + Return service.GenerateConstructorAsync(document, node, fallbackOptions, cancellationToken) End Function Protected Overrides Function GetTargetNode(node As SyntaxNode) As SyntaxNode diff --git a/src/Features/VisualBasic/Portable/GenerateVariable/VisualBasicGenerateVariableCodeFixProvider.vb b/src/Features/VisualBasic/Portable/GenerateVariable/VisualBasicGenerateVariableCodeFixProvider.vb index 5f6e5d830768a..703bbf4972f5e 100644 --- a/src/Features/VisualBasic/Portable/GenerateVariable/VisualBasicGenerateVariableCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/GenerateVariable/VisualBasicGenerateVariableCodeFixProvider.vb @@ -9,6 +9,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.CodeFixes.GenerateMember +Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.GenerateMember.GenerateVariable Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -34,9 +35,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateVariable End Get End Property - Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) + Protected Overrides Function GetCodeActionsAsync(document As Document, node As SyntaxNode, fallbackOptions As CodeAndImportGenerationOptionsProvider, cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of CodeAction)) Dim service = document.GetLanguageService(Of IGenerateVariableService)() - Return service.GenerateVariableAsync(document, node, cancellationToken) + Return service.GenerateVariableAsync(document, node, fallbackOptions, cancellationToken) End Function Protected Overrides Function IsCandidate(node As SyntaxNode, token As SyntaxToken, diagnostic As Diagnostic) As Boolean diff --git a/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb b/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb index 2103001078cf6..fb2e2e22bcc78 100644 --- a/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb @@ -5,6 +5,7 @@ Imports System.Collections.Immutable Imports System.Composition Imports System.Diagnostics.CodeAnalysis +Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.ImplementInterface Imports Microsoft.CodeAnalysis.ImplementType @@ -61,7 +62,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ImplementInterface Dim service = document.GetLanguageService(Of IImplementInterfaceService)() Dim actions = service.GetCodeActions( document, - context.Options(document.Project.LanguageServices).ImplementTypeOptions, + context.Options.GetImplementTypeGenerationOptions(document.Project.LanguageServices), Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False), typeNode, cancellationToken) diff --git a/src/EditorFeatures/VisualBasic/InheritanceMargin/VisualBasicInheritanceMarginService.vb b/src/Features/VisualBasic/Portable/InheritanceMargin/VisualBasicInheritanceMarginService.vb similarity index 94% rename from src/EditorFeatures/VisualBasic/InheritanceMargin/VisualBasicInheritanceMarginService.vb rename to src/Features/VisualBasic/Portable/InheritanceMargin/VisualBasicInheritanceMarginService.vb index 39eb6d82cfd05..006670e618174 100644 --- a/src/EditorFeatures/VisualBasic/InheritanceMargin/VisualBasicInheritanceMarginService.vb +++ b/src/Features/VisualBasic/Portable/InheritanceMargin/VisualBasicInheritanceMarginService.vb @@ -7,9 +7,10 @@ Imports System.Composition Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.InheritanceMargin Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.InheritanceMarginService +Namespace Microsoft.CodeAnalysis.VisualBasic.InheritanceMarginService Friend Class VisualBasicInheritanceMarginService @@ -20,6 +21,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.InheritanceMarginService Public Sub New() End Sub + Protected Overrides ReadOnly Property GlobalImportsTitle As String = VBFeaturesResources.Project_level_Imports + Protected Overrides Function GetMembers(nodesToSearch As IEnumerable(Of SyntaxNode)) As ImmutableArray(Of SyntaxNode) Dim typeBlockNodes = nodesToSearch.OfType(Of TypeBlockSyntax) diff --git a/src/Features/VisualBasic/Portable/RemoveSharedFromModuleMembers/VisualBasicRemoveSharedFromModuleMembersCodeFixProvider.vb b/src/Features/VisualBasic/Portable/RemoveSharedFromModuleMembers/VisualBasicRemoveSharedFromModuleMembersCodeFixProvider.vb index 0ee93c6e31214..826fe2f44ecfa 100644 --- a/src/Features/VisualBasic/Portable/RemoveSharedFromModuleMembers/VisualBasicRemoveSharedFromModuleMembersCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/RemoveSharedFromModuleMembers/VisualBasicRemoveSharedFromModuleMembersCodeFixProvider.vb @@ -48,7 +48,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveSharedFromModuleMembers Continue For End If - context.RegisterCodeFix(New MyCodeAction(GetDocumentUpdater(context, diagnostic)), diagnostic) + context.RegisterCodeFix( + CodeAction.Create( + VBFeaturesResources.Remove_shared_keyword_from_module_member, + GetDocumentUpdater(context, diagnostic), + NameOf(VBFeaturesResources.Remove_shared_keyword_from_module_member)), + diagnostic) Next Return Task.CompletedTask @@ -68,13 +73,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveSharedFromModuleMembers Dim generator = SyntaxGenerator.GetGenerator(document) Return generator.WithModifiers(node, generator.GetModifiers(node).WithIsStatic(False)) End Function - - Private Class MyCodeAction - Inherits CodeAction.DocumentChangeAction - - Public Sub New(createChangedDocument As Func(Of CancellationToken, Task(Of Document))) - MyBase.New(VBFeaturesResources.Remove_shared_keyword_from_module_member, createChangedDocument, VBFeaturesResources.Remove_shared_keyword_from_module_member) - End Sub - End Class End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb index bd7e94245a4a0..e6e5b72ba40a3 100644 --- a/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/SimplifyThisOrMe/VisualBasicSimplifyThisOrMeDiagnosticAnalyzer.vb @@ -2,15 +2,13 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Threading Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.LanguageServices -Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.Simplification.Simplifiers Imports Microsoft.CodeAnalysis.SimplifyThisOrMe -Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices -Imports Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Imports Microsoft.CodeAnalysis.VisualBasic.Simplification +Imports Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.SimplifyThisOrMe @@ -23,21 +21,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SimplifyThisOrMe MemberAccessExpressionSyntax, VisualBasicSimplifierOptions) - Protected Overrides Function GetSyntaxFacts() As ISyntaxFacts - Return VisualBasicSyntaxFacts.Instance - End Function + Protected Overrides ReadOnly Property SyntaxKinds As ISyntaxKinds = VisualBasicSyntaxKinds.Instance Protected Overrides Function GetSimplifierOptions(options As AnalyzerOptions, syntaxTree As SyntaxTree) As VisualBasicSimplifierOptions Return options.GetVisualBasicSimplifierOptions(syntaxTree) End Function - Protected Overrides Function CanSimplifyTypeNameExpression( - model As SemanticModel, memberAccess As MemberAccessExpressionSyntax, - options As VisualBasicSimplifierOptions, ByRef issueSpan As TextSpan, - cancellationToken As CancellationToken) As Boolean - - Dim replacementSyntax As ExpressionSyntax = Nothing - Return ExpressionSimplifier.Instance.TrySimplify(memberAccess, model, options, replacementSyntax, issueSpan, cancellationToken) - End Function + Protected Overrides ReadOnly Property Simplifier As AbstractMemberAccessExpressionSimplifier(Of ExpressionSyntax, MemberAccessExpressionSyntax, MeExpressionSyntax) = MemberAccessExpressionSimplifier.Instance End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx index a21c8e43da239..13e7583883c6c 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx @@ -1224,4 +1224,7 @@ Sub(<parameterList>) <statement> Apply object creation preferences + + Project level 'Imports' + \ No newline at end of file diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf index 316b2defb1266..664c7323973b4 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf @@ -102,6 +102,11 @@ Uspořádat direktivy Import {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member Odebrat klíčové slovo Shared ze členu modulu diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf index 716f78f85b5e0..ea9abc914d2b9 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf @@ -102,6 +102,11 @@ Import-Direktiven organisieren {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member Schlüsselwort "Shared" aus Modulmember entfernen diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf index 70d79c51597ea..35899dff6e36d 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf @@ -102,6 +102,11 @@ Organizar Importaciones {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member Quitar la palabra clave "Shared" del miembro del módulo diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf index da98fe02304c7..8e8b9cb4d1e50 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf @@ -102,6 +102,11 @@ Organiser les Imports {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member Supprimer le mot clé 'Shared' du membre de module diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf index e160fd1ff50f6..dfda93b167cde 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf @@ -102,6 +102,11 @@ Organizza direttive Import {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member Rimuovi la parola chiave 'Shared' dal membro Module diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf index 98d741b8e696e..a9bfab95f83be 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf @@ -102,6 +102,11 @@ Import の整理 {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member モジュール メンバーから 'Shared' キーワードを削除 diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf index b470122d0aac2..3647ac925243c 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf @@ -102,6 +102,11 @@ Import 구성 {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member 모듈 멤버에서 'Shared' 키워드 제거 diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf index 8409c340f921e..63b10eb2b15a4 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf @@ -102,6 +102,11 @@ Organizuj dyrektywy Import {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member Usuń słowo kluczowe "Shared" ze składowej modułu diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf index ba9361d789944..7c65a89eaf059 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf @@ -102,6 +102,11 @@ Organizar as Imports {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member Remover a palavra-chave 'Shared' do membro do Módulo diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf index 65c86c72794ed..24e77e2deedc3 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf @@ -102,6 +102,11 @@ Организовать импорты (Import) {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member Удалить ключевое слово "Shared" из элемента модуля diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf index f5ee94035173e..cddcec6e9a262 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf @@ -102,6 +102,11 @@ Import'ları Düzenle {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member Modül üyesinden 'Shared' anahtar sözcüğünü kaldır diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf index 2c9367e2fc00f..903bf13e46877 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf @@ -102,6 +102,11 @@ 整理 Import {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member 从模块成员中删除 "Shared" 关键字 diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf index e67dcd10e2978..539819f1bed02 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf @@ -102,6 +102,11 @@ 整理 Import {Locked="Import"} + + Project level 'Imports' + Project level 'Imports' + + Remove 'Shared' keyword from Module member 從模組成員移除 'Shared' 關鍵字 diff --git a/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs b/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs index 8e3e5dbf477db..5b1062e6e0339 100644 --- a/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs +++ b/src/Tools/ExternalAccess/OmniSharp/CodeActions/OmniSharpCodeFixContextFactory.cs @@ -8,7 +8,6 @@ using System.Threading; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Text; @@ -23,15 +22,15 @@ public static CodeFixContext CreateCodeFixContext( Action> registerCodeFix, OmniSharpCodeActionOptions options, CancellationToken cancellationToken) - => new(document, span, diagnostics, registerCodeFix, _ => options.GetCodeActionOptions(), cancellationToken); + => new(document, span, diagnostics, registerCodeFix, new DelegatingCodeActionOptionsProvider(_ => options.GetCodeActionOptions()), cancellationToken); - public static CodeRefactoringContext CreateCodeRefactoringContext( + public static CodeAnalysis.CodeRefactorings.CodeRefactoringContext CreateCodeRefactoringContext( Document document, TextSpan span, Action registerRefactoring, OmniSharpCodeActionOptions options, CancellationToken cancellationToken) - => new(document, span, registerRefactoring, _ => options.GetCodeActionOptions(), cancellationToken); + => new(document, span, registerRefactoring, new DelegatingCodeActionOptionsProvider(_ => options.GetCodeActionOptions()), cancellationToken); public static FixAllContext CreateFixAllContext( Document? document, @@ -45,7 +44,7 @@ public static FixAllContext CreateFixAllContext( Func optionsProvider, CancellationToken cancellationToken) => new(new FixAllState( - fixAllProvider: null, + fixAllProvider: NoOpFixAllProvider.Instance, diagnosticSpan, document, project, @@ -54,7 +53,7 @@ public static FixAllContext CreateFixAllContext( codeActionEquivalenceKey, diagnosticIds, fixAllDiagnosticProvider, - languageServices => optionsProvider(languageServices.Language).GetCodeActionOptions()), + new DelegatingCodeActionOptionsProvider(languageServices => optionsProvider(languageServices.Language).GetCodeActionOptions())), new ProgressTracker(), cancellationToken); } } diff --git a/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs b/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs index 135df8fdfdf08..fd1f6d040febc 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Internal/ExtractInterface/OmniSharpExtractInterfaceOptionsService.cs @@ -8,13 +8,16 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.ExtractInterface; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Options; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Internal.ExtractInterface { @@ -49,7 +52,7 @@ public async Task GetExtractInterfaceOptionsAsync result.InterfaceName, result.FileName, (ExtractInterfaceOptionsResult.ExtractLocation)result.Location, - CodeCleanupOptions.GetDefaultAsync); + CodeActionOptions.DefaultProvider); } } } diff --git a/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs b/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs index 63365f545eee2..ef2dd3729bffc 100644 --- a/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs +++ b/src/Tools/ExternalAccess/OmniSharp/MetadataAsSource/OmniSharpMetadataAsSourceService.cs @@ -6,11 +6,13 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.Formatting; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.MetadataAsSource; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.MetadataAsSource { @@ -32,7 +34,12 @@ public static async Task AddSourceToAsync(Document document, Compilati var service = document.GetRequiredLanguageService(); var cleanupOptions = await document.GetCodeCleanupOptionsAsync(fallbackOptions: null, cancellationToken).ConfigureAwait(false); - return await service.AddSourceToAsync(document, symbolCompilation, symbol, cleanupOptions, cancellationToken).ConfigureAwait(false); + + var options = new CleanCodeGenerationOptions( + GenerationOptions: CodeGenerationOptions.GetDefault(document.Project.LanguageServices), + CleanupOptions: cleanupOptions); + + return await service.AddSourceToAsync(document, symbolCompilation, symbol, options, cancellationToken).ConfigureAwait(false); } /// @@ -49,7 +56,12 @@ public static async Task AddSourceToAsync(Document document, Compilati public static Task AddSourceToAsync(Document document, Compilation symbolCompilation, ISymbol symbol, OmniSharpSyntaxFormattingOptionsWrapper formattingOptions, CancellationToken cancellationToken) { var service = document.GetRequiredLanguageService(); - return service.AddSourceToAsync(document, symbolCompilation, symbol, formattingOptions.CleanupOptions, cancellationToken); + + var options = new CleanCodeGenerationOptions( + GenerationOptions: CodeGenerationOptions.GetDefault(document.Project.LanguageServices), + CleanupOptions: formattingOptions.CleanupOptions); + + return service.AddSourceToAsync(document, symbolCompilation, symbol, options, cancellationToken); } } } diff --git a/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs b/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs index c637779ca897a..0dfe4d8ed0082 100644 --- a/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs +++ b/src/Tools/ExternalAccess/OmniSharp/Rename/OmniSharpRenamer.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Rename; @@ -23,7 +24,7 @@ public static async Task RenameSymbolAsync( ImmutableHashSet? nonConflictSymbols, CancellationToken cancellationToken) { - var resolution = await Renamer.RenameSymbolAsync(solution, symbol, newName, options.ToRenameOptions(), CodeCleanupOptions.GetDefaultAsync, nonConflictSymbols, cancellationToken).ConfigureAwait(false); + var resolution = await Renamer.RenameSymbolAsync(solution, symbol, newName, options.ToRenameOptions(), CodeActionOptions.DefaultProvider, nonConflictSymbols, cancellationToken).ConfigureAwait(false); return new RenameResult(resolution.NewSolution, resolution.ErrorMessage); } } diff --git a/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs b/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs index ef2b8773a02a0..bc71064d6c697 100644 --- a/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs +++ b/src/Tools/ExternalAccess/Razor/RazorCSharpFormattingInteractionService.cs @@ -49,7 +49,7 @@ public static async Task> GetFormattingChangesAsync( var globalOptions = document.Project.Solution.Workspace.Services.GetRequiredService().GlobalOptions; var indentationOptions = new IndentationOptions( - SyntaxFormattingOptions.Create(documentOptions, services, globalOptions.GetSyntaxFormattingOptions(document.Project.LanguageServices), document.Project.Language), + SyntaxFormattingOptions.Create(documentOptions, globalOptions.GetSyntaxFormattingOptions(document.Project.LanguageServices), document.Project.LanguageServices), globalOptions.GetAutoFormattingOptions(document.Project.Language)); return await formattingService.GetFormattingChangesOnTypedCharacterAsync(document, position, indentationOptions, cancellationToken).ConfigureAwait(false); diff --git a/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs b/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs index aff73c5aa9c12..b4c3d224223ff 100644 --- a/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs +++ b/src/Tools/ExternalAccess/Razor/RazorGlobalOptions.cs @@ -8,6 +8,9 @@ using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Formatting; using System.Linq; +using System.Collections.Immutable; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor { @@ -17,19 +20,49 @@ internal sealed class RazorGlobalOptions private readonly IGlobalOptionService _globalOptions; [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be marked with 'ObsoleteAttribute'", Justification = "Used in test code")] public RazorGlobalOptions(IGlobalOptionService globalOptions) { _globalOptions = globalOptions; } + public RazorAutoFormattingOptions GetAutoFormattingOptions() + => new(_globalOptions.GetAutoFormattingOptions(LanguageNames.CSharp)); + +#pragma warning disable IDE0060 // Remove unused parameter /// - /// For testing purposes. + /// For testing purposes only. Razor does not use MEF composition for host services so we need to return a mock. /// public static RazorGlobalOptions GetGlobalOptions(Workspace workspace) - => ((IMefHostExportProvider)workspace.Services.HostServices).GetExports().Single().Value; + => new(new TestGlobalOptionService()); +#pragma warning restore - public RazorAutoFormattingOptions GetAutoFormattingOptions() - => new(_globalOptions.GetAutoFormattingOptions(LanguageNames.CSharp)); + private sealed class TestGlobalOptionService : IGlobalOptionService + { +#pragma warning disable CS0067 // Remove unused event + public event EventHandler? OptionChanged; +#pragma warning restore + + public T GetOption(PerLanguageOption2 option, string? languageName) + => default!; + + public T GetOption(Option option) + => throw new NotImplementedException(); + + public T GetOption(Option2 option) => throw new NotImplementedException(); + public T GetOption(PerLanguageOption option, string? languageName) => throw new NotImplementedException(); + public object? GetOption(OptionKey optionKey) => throw new NotImplementedException(); + public ImmutableArray GetOptions(ImmutableArray optionKeys) => throw new NotImplementedException(); + public IEnumerable GetRegisteredOptions() => throw new NotImplementedException(); + public ImmutableHashSet GetRegisteredSerializableOptions(ImmutableHashSet languages) => throw new NotImplementedException(); + public SerializableOptionSet GetSerializableOptionsSnapshot(ImmutableHashSet languages, IOptionService optionService) => throw new NotImplementedException(); + public void RefreshOption(OptionKey optionKey, object? newValue) => throw new NotImplementedException(); + public void RegisterWorkspace(Workspace workspace) => throw new NotImplementedException(); + public void SetGlobalOption(OptionKey optionKey, object? value) => throw new NotImplementedException(); + public void SetGlobalOptions(ImmutableArray optionKeys, ImmutableArray values) => throw new NotImplementedException(); + public void SetOptions(OptionSet optionSet) => throw new NotImplementedException(); + public bool TryMapEditorConfigKeyToOption(string key, string? language, [NotNullWhen(true)] out IEditorConfigStorageLocation2? storageLocation, out OptionKey optionKey) => throw new NotImplementedException(); + public void UnregisterWorkspace(Workspace workspace) => throw new NotImplementedException(); + } } } diff --git a/src/Tools/IdeBenchmarks/InheritanceMargin/BenchmarksHelpers.cs b/src/Tools/IdeBenchmarks/InheritanceMargin/BenchmarksHelpers.cs index 08338c2b2cd98..09c7d6ea3f793 100644 --- a/src/Tools/IdeBenchmarks/InheritanceMargin/BenchmarksHelpers.cs +++ b/src/Tools/IdeBenchmarks/InheritanceMargin/BenchmarksHelpers.cs @@ -26,7 +26,8 @@ public static async Task> GenerateInherita foreach (var document in project.Documents) { var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var items = await languageService.GetInheritanceMemberItemsAsync(document, root.Span, cancellationToken).ConfigureAwait(false); + var items = await languageService.GetInheritanceMemberItemsAsync( + document, root.Span, includeGlobalImports: true, cancellationToken).ConfigureAwait(false); builder.AddRange(items); } } diff --git a/src/Tools/Source/RunTests/ProcessTestExecutor.cs b/src/Tools/Source/RunTests/ProcessTestExecutor.cs index 0b98c98aee261..193d707d14228 100644 --- a/src/Tools/Source/RunTests/ProcessTestExecutor.cs +++ b/src/Tools/Source/RunTests/ProcessTestExecutor.cs @@ -25,7 +25,7 @@ internal ProcessTestExecutor(TestExecutionOptions options) Options = options; } - public string GetCommandLineArguments(AssemblyInfo assemblyInfo, bool useSingleQuotes) + public string GetCommandLineArguments(AssemblyInfo assemblyInfo, bool useSingleQuotes, bool isHelix) { // http://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html // Single quotes are needed in bash to avoid the need to escape characters such as backtick (`) which are found in metadata names. @@ -87,11 +87,16 @@ void MaybeAddSeparator(char separator = '|') builder.Append(" --blame-crash"); } - // The 25 minute timeout accounts for the fact that VSIX deployment and/or experimental hive reset and + // The 25 minute timeout in integration tests accounts for the fact that VSIX deployment and/or experimental hive reset and // configuration can take significant time (seems to vary from ~10 seconds to ~15 minutes), and the blame // functionality cannot separate this configuration overhead from the first test which will eventually run. // https://github.com/dotnet/roslyn/issues/59851 - builder.Append(" --blame-hang-dump-type full --blame-hang-timeout 25minutes"); + // + // Helix timeout is 15 minutes as helix jobs fully timeout in 30minutes. So in order to capture dumps we need the timeout + // to be 2x shorter than the expected test run time (15min) in case only the last test hangs. + var timeout = isHelix ? "15minutes" : "25minutes"; + + builder.Append($" --blame-hang-dump-type full --blame-hang-timeout {timeout}"); return builder.ToString(); } @@ -125,7 +130,7 @@ private async Task RunTestAsyncInternal(AssemblyInfo assemblyInfo, b { try { - var commandLineArguments = GetCommandLineArguments(assemblyInfo, useSingleQuotes: false); + var commandLineArguments = GetCommandLineArguments(assemblyInfo, useSingleQuotes: false, isHelix: false); var resultsFilePath = GetResultsFilePath(assemblyInfo); var resultsDir = Path.GetDirectoryName(resultsFilePath); var htmlResultsFilePath = Options.IncludeHtml ? GetResultsFilePath(assemblyInfo, "html") : null; diff --git a/src/Tools/Source/RunTests/TestRunner.cs b/src/Tools/Source/RunTests/TestRunner.cs index eb2df388bb9a2..8bf1a7dd09c97 100644 --- a/src/Tools/Source/RunTests/TestRunner.cs +++ b/src/Tools/Source/RunTests/TestRunner.cs @@ -155,7 +155,7 @@ string makeHelixWorkItemProject(AssemblyInfo assemblyInfo) // figure out solutions for issues such as creating file paths in the correct format for the target machine. var isUnix = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var commandLineArguments = _testExecutor.GetCommandLineArguments(assemblyInfo, useSingleQuotes: isUnix); + var commandLineArguments = _testExecutor.GetCommandLineArguments(assemblyInfo, useSingleQuotes: isUnix, isHelix: true); commandLineArguments = SecurityElement.Escape(commandLineArguments); var setEnvironmentVariable = isUnix ? "export" : "set"; diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs index e9314d4df9fd5..ced9c909852e4 100644 --- a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs @@ -156,6 +156,7 @@ private IEnumerable GetExpressionCodeStyleOptions(AnalyzerConf yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferRangeOperator, description: ServicesVSResources.Prefer_range_operator, editorConfigOptions, visualStudioOptions, updaterService, FileName); yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent, description: CSharpVSResources.Prefer_implicit_object_creation_when_type_is_apparent, editorConfigOptions, visualStudioOptions, updaterService, FileName); yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferTupleSwap, description: ServicesVSResources.Prefer_tuple_swap, editorConfigOptions, visualStudioOptions, updaterService, FileName); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferUTF8StringLiterals, description: ServicesVSResources.Prefer_UTF8_string_literals, editorConfigOptions, visualStudioOptions, updaterService, FileName); } private IEnumerable GetPatternMatchingCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml index a8f8a799d42b0..17ab4678d54c7 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml @@ -56,6 +56,7 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Skip_analyzers_for_implicitly_triggered_builds}" /> + @@ -67,6 +68,7 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Navigate_asynchronously_exerimental}" /> + @@ -87,6 +89,7 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Add_missing_using_directives_on_paste}" /> + @@ -94,6 +97,7 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Compute_Quick_Actions_asynchronously_experimental}" /> + @@ -103,6 +107,7 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_EnableHighlightKeywords}" /> + @@ -120,6 +125,7 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Collapse_regions_when_collapsing_to_definitions}" /> + @@ -129,6 +135,7 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Fade_out_unreachable_code}" /> + @@ -138,8 +145,8 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Show_guides_for_code_level_constructs}" /> - - + + - + + diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs index ac8cbb4d3ec8d..d96556a3a5a14 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs @@ -49,6 +49,7 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon InitializeComponent(); + // Analysis BindToOption(Run_background_code_analysis_for, SolutionCrawlerOptionsStorage.BackgroundAnalysisScopeOption, LanguageNames.CSharp); BindToOption(DisplayDiagnosticsInline, InlineDiagnosticsOptions.EnableInlineDiagnostics, LanguageNames.CSharp); BindToOption(at_the_end_of_the_line_of_code, InlineDiagnosticsOptions.Location, InlineDiagnosticsLocations.PlacedAtEndOfCode, LanguageNames.CSharp); @@ -69,6 +70,7 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon BindToOption(Always_use_default_symbol_servers_for_navigation, MetadataAsSourceOptionsStorage.AlwaysUseDefaultSymbolServers); BindToOption(Navigate_asynchronously_exerimental, FeatureOnOffOptions.NavigateAsynchronously); + // Using Directives BindToOption(PlaceSystemNamespaceFirst, GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp); BindToOption(SeparateImportGroups, GenerationOptions.SeparateImportDirectiveGroups, LanguageNames.CSharp); BindToOption(SuggestForTypesInReferenceAssemblies, SymbolSearchOptionsStorage.SearchReferenceAssemblies, LanguageNames.CSharp); @@ -81,39 +83,44 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon return false; }); - BindToOption(Split_string_literals_on_enter, SplitStringLiteralOptions.Enabled, LanguageNames.CSharp); + // Quick Actions + BindToOption(ComputeQuickActionsAsynchronouslyExperimental, SuggestionsOptions.Asynchronous, () => + { + // If the option has not been set by the user, check if the option is disabled from experimentation. + return !optionStore.GetOption(SuggestionsOptions.AsynchronousQuickActionsDisableFeatureFlag); + }); + + // Highlighting + BindToOption(EnableHighlightReferences, FeatureOnOffOptions.ReferenceHighlighting, LanguageNames.CSharp); + BindToOption(EnableHighlightKeywords, FeatureOnOffOptions.KeywordHighlighting, LanguageNames.CSharp); + // Outlining BindToOption(EnterOutliningMode, FeatureOnOffOptions.Outlining, LanguageNames.CSharp); + BindToOption(DisplayLineSeparators, FeatureOnOffOptions.LineSeparator, LanguageNames.CSharp); BindToOption(Show_outlining_for_declaration_level_constructs, BlockStructureOptionsStorage.ShowOutliningForDeclarationLevelConstructs, LanguageNames.CSharp); BindToOption(Show_outlining_for_code_level_constructs, BlockStructureOptionsStorage.ShowOutliningForCodeLevelConstructs, LanguageNames.CSharp); BindToOption(Show_outlining_for_comments_and_preprocessor_regions, BlockStructureOptionsStorage.ShowOutliningForCommentsAndPreprocessorRegions, LanguageNames.CSharp); BindToOption(Collapse_regions_when_collapsing_to_definitions, BlockStructureOptionsStorage.CollapseRegionsWhenCollapsingToDefinitions, LanguageNames.CSharp); + // Fading BindToOption(Fade_out_unused_usings, IdeAnalyzerOptionsStorage.FadeOutUnusedImports, LanguageNames.CSharp); BindToOption(Fade_out_unreachable_code, IdeAnalyzerOptionsStorage.FadeOutUnreachableCode, LanguageNames.CSharp); + // Block Structure Guides BindToOption(Show_guides_for_declaration_level_constructs, BlockStructureOptionsStorage.ShowBlockStructureGuidesForDeclarationLevelConstructs, LanguageNames.CSharp); BindToOption(Show_guides_for_code_level_constructs, BlockStructureOptionsStorage.ShowBlockStructureGuidesForCodeLevelConstructs, LanguageNames.CSharp); + // Comments BindToOption(GenerateXmlDocCommentsForTripleSlash, DocumentationCommentOptionsStorage.AutoXmlDocCommentGeneration, LanguageNames.CSharp); BindToOption(InsertSlashSlashAtTheStartOfNewLinesWhenWritingSingleLineComments, SplitStringLiteralOptions.Enabled, LanguageNames.CSharp); BindToOption(InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments, FeatureOnOffOptions.AutoInsertBlockCommentStartString, LanguageNames.CSharp); + // Editor Help BindToOption(ShowRemarksInQuickInfo, QuickInfoOptionsStorage.ShowRemarksInQuickInfo, LanguageNames.CSharp); - BindToOption(DisplayLineSeparators, FeatureOnOffOptions.LineSeparator, LanguageNames.CSharp); - - // Quick Actions - BindToOption(ComputeQuickActionsAsynchronouslyExperimental, SuggestionsOptions.Asynchronous, () => - { - // If the option has not been set by the user, check if the option is disabled from experimentation. - return !optionStore.GetOption(SuggestionsOptions.AsynchronousQuickActionsDisableFeatureFlag); - }); - - // Highlighting - BindToOption(EnableHighlightReferences, FeatureOnOffOptions.ReferenceHighlighting, LanguageNames.CSharp); - BindToOption(EnableHighlightKeywords, FeatureOnOffOptions.KeywordHighlighting, LanguageNames.CSharp); - BindToOption(RenameTrackingPreview, FeatureOnOffOptions.RenameTrackingPreview, LanguageNames.CSharp); + BindToOption(Split_string_literals_on_enter, SplitStringLiteralOptions.Enabled, LanguageNames.CSharp); + BindToOption(Fix_text_pasted_into_string_literals_experimental, FeatureOnOffOptions.AutomaticallyFixStringContentsOnPaste, LanguageNames.CSharp); + BindToOption(Report_invalid_placeholders_in_string_dot_format_calls, IdeAnalyzerOptionsStorage.ReportInvalidPlaceholdersInStringDotFormatCalls, LanguageNames.CSharp); BindToOption(Underline_reassigned_variables, ClassificationOptionsStorage.ClassifyReassignedVariables, LanguageNames.CSharp); BindToOption(Enable_all_features_in_opened_files_from_source_generators, WorkspaceConfigurationOptionsStorage.EnableOpeningSourceGeneratedFilesInWorkspace, () => { @@ -122,27 +129,30 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon return optionStore.GetOption(WorkspaceConfigurationOptionsStorage.EnableOpeningSourceGeneratedFilesInWorkspaceFeatureFlag); }); - BindToOption(DontPutOutOrRefOnStruct, ExtractMethodOptionsStorage.DontPutOutOrRefOnStruct, LanguageNames.CSharp); - - BindToOption(with_other_members_of_the_same_kind, ImplementTypeOptionsStorage.InsertionBehavior, ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind, LanguageNames.CSharp); - BindToOption(at_the_end, ImplementTypeOptionsStorage.InsertionBehavior, ImplementTypeInsertionBehavior.AtTheEnd, LanguageNames.CSharp); - - BindToOption(prefer_throwing_properties, ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferThrowingProperties, LanguageNames.CSharp); - BindToOption(prefer_auto_properties, ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties, LanguageNames.CSharp); - - BindToOption(Report_invalid_placeholders_in_string_dot_format_calls, IdeAnalyzerOptionsStorage.ReportInvalidPlaceholdersInStringDotFormatCalls, LanguageNames.CSharp); - + // Regular Expressions BindToOption(Colorize_regular_expressions, ClassificationOptionsStorage.ColorizeRegexPatterns, LanguageNames.CSharp); BindToOption(Report_invalid_regular_expressions, IdeAnalyzerOptionsStorage.ReportInvalidRegexPatterns, LanguageNames.CSharp); BindToOption(Highlight_related_regular_expression_components_under_cursor, HighlightingOptionsStorage.HighlightRelatedRegexComponentsUnderCursor, LanguageNames.CSharp); BindToOption(Show_completion_list, CompletionOptionsStorage.ProvideRegexCompletions, LanguageNames.CSharp); + // Json BindToOption(Colorize_JSON_strings, ClassificationOptionsStorage.ColorizeJsonPatterns, LanguageNames.CSharp); BindToOption(Report_invalid_JSON_strings, IdeAnalyzerOptionsStorage.ReportInvalidJsonPatterns, LanguageNames.CSharp); BindToOption(Highlight_related_JSON_components_under_cursor, HighlightingOptionsStorage.HighlightRelatedJsonComponentsUnderCursor, LanguageNames.CSharp); + // Classifications BindToOption(Editor_color_scheme, ColorSchemeOptions.ColorScheme); + // Extract Method + BindToOption(DontPutOutOrRefOnStruct, ExtractMethodOptionsStorage.DontPutOutOrRefOnStruct, LanguageNames.CSharp); + + // Implement Interface or Abstract Class + BindToOption(with_other_members_of_the_same_kind, ImplementTypeOptionsStorage.InsertionBehavior, ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind, LanguageNames.CSharp); + BindToOption(at_the_end, ImplementTypeOptionsStorage.InsertionBehavior, ImplementTypeInsertionBehavior.AtTheEnd, LanguageNames.CSharp); + BindToOption(prefer_throwing_properties, ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferThrowingProperties, LanguageNames.CSharp); + BindToOption(prefer_auto_properties, ImplementTypeOptionsStorage.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties, LanguageNames.CSharp); + + // Inline Hints BindToOption(DisplayAllHintsWhilePressingAltF1, InlineHintsViewOptions.DisplayAllHintsWhilePressingAltF1); BindToOption(ColorHints, InlineHintsViewOptions.ColorHints, LanguageNames.CSharp); @@ -160,10 +170,13 @@ public AdvancedOptionPageControl(OptionStore optionStore, IComponentModel compon BindToOption(ShowHintsForLambdaParameterTypes, InlineHintsOptionsStorage.ForLambdaParameterTypes, LanguageNames.CSharp); BindToOption(ShowHintsForImplicitObjectCreation, InlineHintsOptionsStorage.ForImplicitObjectCreation, LanguageNames.CSharp); + // Inheritance Margin // Leave the null converter here to make sure if the option value is get from the storage (if it is null), the feature will be enabled BindToOption(ShowInheritanceMargin, FeatureOnOffOptions.ShowInheritanceMargin, LanguageNames.CSharp, () => true); BindToOption(InheritanceMarginCombinedWithIndicatorMargin, FeatureOnOffOptions.InheritanceMarginCombinedWithIndicatorMargin); + BindToOption(IncludeGlobalImports, FeatureOnOffOptions.InheritanceMarginIncludeGlobalImports, LanguageNames.CSharp); + // Stack Trace Explorer BindToOption(AutomaticallyOpenStackTraceExplorer, StackTraceExplorerOptionsMetadata.OpenOnFocus); } diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs index 44728fb010263..44ff496df7c0d 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs @@ -309,6 +309,9 @@ public static string Show_inheritance_margin public static string Combine_inheritance_margin_with_indicator_margin => ServicesVSResources.Combine_inheritance_margin_with_indicator_margin; + public static string Include_global_imports + => ServicesVSResources.Include_global_imports; + public static string Option_JSON_strings => ServicesVSResources.JSON_strings; @@ -327,6 +330,9 @@ public static string Stack_Trace_Explorer public static string Option_Automatically_open_stack_trace_explorer_on_focus => ServicesVSResources.Automatically_open_stack_trace_explorer_on_focus; + public static string Option_Fix_text_pasted_into_string_literals_experimental + => ServicesVSResources.Fix_text_pasted_into_string_literals_experimental; + public static string Option_Go_To_Definition => ServicesVSResources.Go_To_Definition; diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.OnOff.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.OnOff.cs index bc30e8ca2c8ae..9727581bb4179 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.OnOff.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.OnOff.cs @@ -15,6 +15,12 @@ public int AutoInsertAsteriskForNewLinesOfBlockComments set { SetBooleanOption(FeatureOnOffOptions.AutoInsertBlockCommentStartString, value); } } + public int AutomaticallyFixStringContentsOnPaste + { + get { return GetBooleanOption(FeatureOnOffOptions.AutomaticallyFixStringContentsOnPaste); } + set { SetBooleanOption(FeatureOnOffOptions.AutomaticallyFixStringContentsOnPaste, value); } + } + public int DisplayLineSeparators { get { return GetBooleanOption(FeatureOnOffOptions.LineSeparator); } diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Style.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Style.cs index e5ec830ed808e..cd267e9b60cf8 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Style.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject/AutomationObject.Style.cs @@ -381,6 +381,12 @@ public string Style_PreferTupleSwap set { SetXmlOption(CSharpCodeStyleOptions.PreferTupleSwap, value); } } + public string Style_PreferUTF8StringLiterals + { + get { return GetXmlOption(CSharpCodeStyleOptions.PreferUTF8StringLiterals); } + set { SetXmlOption(CSharpCodeStyleOptions.PreferUTF8StringLiterals, value); } + } + public string Style_PreferredUsingDirectivePlacement { get { return GetXmlOption(CSharpCodeStyleOptions.PreferredUsingDirectivePlacement); } diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs index 5cffab73b13d5..86806ef13f103 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs @@ -1157,6 +1157,21 @@ void M2(string[] args) //] }} }} +"; + + private static readonly string s_preferUTF8StringLiterals = $@" +using System; + +//[ +class WebResponse +{{ + // {ServicesVSResources.Prefer_colon} + private readonly byte[] header = ""Hello""u8; + + // {ServicesVSResources.Over_colon} + private readonly byte[] header = new byte[] {{ 72, 101, 108, 108, 111 }}; +}} +//] "; private static readonly string s_preferIsNullOverReferenceEquals = $@" @@ -2177,6 +2192,7 @@ internal StyleViewModel(OptionStore optionStore, IServiceProvider serviceProvide CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferRangeOperator, ServicesVSResources.Prefer_range_operator, s_preferRangeOperator, s_preferRangeOperator, this, optionStore, expressionPreferencesGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferTupleSwap, ServicesVSResources.Prefer_tuple_swap, s_preferTupleSwap, s_preferTupleSwap, this, optionStore, expressionPreferencesGroupTitle)); + CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferUTF8StringLiterals, ServicesVSResources.Prefer_UTF8_string_literals, s_preferUTF8StringLiterals, s_preferUTF8StringLiterals, this, optionStore, expressionPreferencesGroupTitle)); AddExpressionBodyOptions(optionStore, expressionPreferencesGroupTitle); AddUnusedValueOptions(optionStore, expressionPreferencesGroupTitle); diff --git a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs index 40b653d0f2d93..30ff5045dd35f 100644 --- a/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs +++ b/src/VisualStudio/Core/Def/CodeCleanup/AbstractCodeCleanUpFixer.cs @@ -353,7 +353,7 @@ private static async Task FixDocumentAsync( new OrganizeUsingsSet(isRemoveUnusedUsingsEnabled, isSortUsingsEnabled)); return await codeCleanupService.CleanupAsync( - document, enabledDiagnostics, progressTracker, _ => ideOptions, cancellationToken).ConfigureAwait(false); + document, enabledDiagnostics, progressTracker, ideOptions.CreateProvider(), cancellationToken).ConfigureAwait(false); } } } diff --git a/src/VisualStudio/Core/Def/CodeCleanup/CommonCodeCleanUpFixerDiagnosticIds.cs b/src/VisualStudio/Core/Def/CodeCleanup/CommonCodeCleanUpFixerDiagnosticIds.cs index 94a8ee91a4d4a..4e5fdf2c41488 100644 --- a/src/VisualStudio/Core/Def/CodeCleanup/CommonCodeCleanUpFixerDiagnosticIds.cs +++ b/src/VisualStudio/Core/Def/CodeCleanup/CommonCodeCleanUpFixerDiagnosticIds.cs @@ -13,20 +13,20 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.CodeCleanup internal static class CommonCodeCleanUpFixerDiagnosticIds { [Export] - [FixId(IDEDiagnosticIds.AddQualificationDiagnosticId)] - [Name(IDEDiagnosticIds.AddQualificationDiagnosticId)] + [FixId(IDEDiagnosticIds.AddThisOrMeQualificationDiagnosticId)] + [Name(IDEDiagnosticIds.AddThisOrMeQualificationDiagnosticId)] [Order(After = IDEDiagnosticIds.UseObjectInitializerDiagnosticId)] [ConfigurationKey("unused")] - [HelpLink($"https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/{IDEDiagnosticIds.AddQualificationDiagnosticId}")] + [HelpLink($"https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/{IDEDiagnosticIds.AddThisOrMeQualificationDiagnosticId}")] [LocalizedName(typeof(AnalyzersResources), nameof(AnalyzersResources.Add_this_or_Me_qualification))] public static readonly FixIdDefinition? AddQualificationDiagnosticId; [Export] - [FixId(IDEDiagnosticIds.RemoveQualificationDiagnosticId)] - [Name(IDEDiagnosticIds.RemoveQualificationDiagnosticId)] + [FixId(IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId)] + [Name(IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId)] [Order(After = IDEDiagnosticIds.UseObjectInitializerDiagnosticId)] [ConfigurationKey("unused")] - [HelpLink($"https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/{IDEDiagnosticIds.RemoveQualificationDiagnosticId}")] + [HelpLink($"https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/{IDEDiagnosticIds.RemoveThisOrMeQualificationDiagnosticId}")] [LocalizedName(typeof(AnalyzersResources), nameof(AnalyzersResources.Add_this_or_Me_qualification))] public static readonly FixIdDefinition? RemoveQualificationDiagnosticId; @@ -51,7 +51,7 @@ internal static class CommonCodeCleanUpFixerDiagnosticIds [Export] [FixId(IDEDiagnosticIds.MakeFieldReadonlyDiagnosticId)] [Name(IDEDiagnosticIds.MakeFieldReadonlyDiagnosticId)] - [Order(After = IDEDiagnosticIds.AddQualificationDiagnosticId)] + [Order(After = IDEDiagnosticIds.AddThisOrMeQualificationDiagnosticId)] [ConfigurationKey("unused")] [HelpLink($"https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/{IDEDiagnosticIds.MakeFieldReadonlyDiagnosticId}")] [LocalizedName(typeof(AnalyzersResources), nameof(AnalyzersResources.Make_field_readonly))] diff --git a/src/VisualStudio/Core/Def/Extensions/VisualStudioWorkspaceImplExtensions.cs b/src/VisualStudio/Core/Def/Extensions/VisualStudioWorkspaceImplExtensions.cs index c7def514d3d74..11c7a02ef0203 100644 --- a/src/VisualStudio/Core/Def/Extensions/VisualStudioWorkspaceImplExtensions.cs +++ b/src/VisualStudio/Core/Def/Extensions/VisualStudioWorkspaceImplExtensions.cs @@ -19,15 +19,11 @@ internal static class VisualStudioWorkspaceImplExtensions // We're mucking around creating native objects. They need to live around as long as the // hierarchy we're getting them for. To do this, we attach them to the hierarchy with a // conditional weak table. - private static readonly ConditionalWeakTable> s_hierarchyToItemIdToImageHandle = - new(); - - private static readonly ConditionalWeakTable>.CreateValueCallback s_createValue = - _ => new Dictionary(); + private static readonly ConditionalWeakTable> s_hierarchyToItemIdToImageHandle = new(); private static bool TryGetImageListAndIndex(this IVsHierarchy hierarchy, IVsImageService2 imageService, uint itemId, out IntPtr imageList, out ushort index) { - var itemIdToImageHandle = s_hierarchyToItemIdToImageHandle.GetValue(hierarchy, s_createValue); + var itemIdToImageHandle = s_hierarchyToItemIdToImageHandle.GetValue(hierarchy, static _ => new Dictionary()); // Get the actual image moniker that the vs hierarchy is using to in solution explorer. var imageMoniker = imageService.GetImageMonikerForHierarchyItem(hierarchy, itemId, (int)__VSHIERARCHYIMAGEASPECT.HIA_Icon); diff --git a/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs b/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs index 433a6180a85fd..3d6520619859d 100644 --- a/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs +++ b/src/VisualStudio/Core/Def/ExtractInterface/VisualStudioExtractInterfaceOptionsService.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeCleanup; +using Microsoft.CodeAnalysis.CodeGeneration; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ExtractInterface; using Microsoft.CodeAnalysis.Host.Mef; @@ -77,7 +78,7 @@ public async Task GetExtractInterfaceOptionsAsync interfaceName: viewModel.DestinationViewModel.TypeName.Trim(), fileName: viewModel.DestinationViewModel.FileName.Trim(), location: GetLocation(viewModel.DestinationViewModel.Destination), - _globalOptions.GetCodeCleanupOptionsProvider()); + _globalOptions.CreateProvider()); } else { diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginHelpers.cs b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginHelpers.cs index 54317e85fdfcc..95421a5e3cc68 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginHelpers.cs +++ b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginHelpers.cs @@ -6,7 +6,9 @@ using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Wpf; using Microsoft.CodeAnalysis.InheritanceMargin; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.LanguageServices.Implementation.InheritanceMargin.MarginGlyph; @@ -16,6 +18,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.InheritanceMarg { internal static class InheritanceMarginHelpers { + private static readonly ObjectPool> s_pool = new(() => new()); + private static readonly ImmutableArray s_relationships_Shown_As_I_Up_Arrow = ImmutableArray.Create( InheritanceRelationship.ImplementedInterface, @@ -88,15 +92,36 @@ public static ImageMoniker GetMoniker(InheritanceRelationship inheritanceRelatio return KnownMonikers.Overridden; } + if (inheritanceRelationship.HasFlag(InheritanceRelationship.InheritedImport)) + return KnownMonikers.NamespaceShortcut; + // The relationship is None. Don't know what image should be shown, throws throw ExceptionUtilities.UnexpectedValue(inheritanceRelationship); } - public static ImmutableArray CreateMenuItemViewModelsForSingleMember(ImmutableArray targets) - => targets.OrderBy(target => target.DisplayName) - .GroupBy(target => target.RelationToMember) - .SelectMany(grouping => CreateMenuItemsWithHeader(grouping.Key, grouping)) - .ToImmutableArray(); + public static ImmutableArray CreateModelsForMarginItem(InheritanceMarginItem item) + { + var nameToTargets = s_pool.Allocate(); + try + { + // Create a mapping from display name to all targets with that name. This will allow us to determine if + // there may be multiple results with the same name, so we can disambiguate them with additional + // information later on when we create the items. + var targets = item.TargetItems; + foreach (var target in targets) + nameToTargets.Add(target.DisplayName, target); + + return item.TargetItems + .GroupBy(t => t.RelationToMember) + .SelectMany(g => CreateMenuItemsWithHeader(item, g.Key, g, nameToTargets)) + .ToImmutableArray(); + } + finally + { + nameToTargets.Clear(); + s_pool.Free(nameToTargets); + } + } /// /// Create the view models for the inheritance targets of multiple members @@ -116,14 +141,19 @@ public static ImmutableArray CreateMenuItemViewModelsForMulti // For multiple members, check if all the targets have the same inheritance relationship. // If so, then don't add the header, because it is already indicated by the margin. // Otherwise, add the Header. - return members.SelectAsArray(MemberMenuItemViewModel.CreateWithHeaderInTargets).CastArray(); + return members.SelectAsArray(m => new MemberMenuItemViewModel( + m.DisplayTexts.JoinText(), + m.Glyph.GetImageMoniker(), + CreateModelsForMarginItem(m))).CastArray(); } public static ImmutableArray CreateMenuItemsWithHeader( + InheritanceMarginItem item, InheritanceRelationship relationship, - IEnumerable targets) + IEnumerable targets, + MultiDictionary nameToTargets) { - using var _ = CodeAnalysis.PooledObjects.ArrayBuilder.GetInstance(out var builder); + using var _ = ArrayBuilder.GetInstance(out var builder); var displayContent = relationship switch { InheritanceRelationship.ImplementedInterface => ServicesVSResources.Implemented_interfaces, @@ -135,14 +165,34 @@ public static ImmutableArray CreateMenuItemsWithHeader( InheritanceRelationship.OverriddenMember => ServicesVSResources.Overridden_members, InheritanceRelationship.OverridingMember => ServicesVSResources.Overriding_members, InheritanceRelationship.ImplementingMember => ServicesVSResources.Implementing_members, + InheritanceRelationship.InheritedImport => item.DisplayTexts.JoinText(), _ => throw ExceptionUtilities.UnexpectedValue(relationship) }; - var headerViewModel = new HeaderMenuItemViewModel(displayContent, GetMoniker(relationship), displayContent); - builder.Add(headerViewModel); - foreach (var targetItem in targets) + builder.Add(new HeaderMenuItemViewModel(displayContent, GetMoniker(relationship))); + foreach (var target in targets) { - builder.Add(TargetMenuItemViewModel.Create(targetItem)); + var targetsWithSameName = nameToTargets[target.DisplayName]; + if (targetsWithSameName.Count >= 2) + { + // Two or more items with the same name. Try to disambiguate them based on their languages if + // they're all distinct, or their project name if they're not. + var distinctLanguageCount = targetsWithSameName.Select(t => t.LanguageGlyph).Distinct().Count(); + if (distinctLanguageCount == targetsWithSameName.Count) + { + builder.Add(DisambiguousTargetMenuItemViewModel.CreateWithSourceLanguageGlyph(target)); + continue; + } + + if (target.ProjectName != null) + { + builder.Add(TargetMenuItemViewModel.Create( + target, string.Format(ServicesVSResources._0_1, target.DisplayName, target.ProjectName))); + continue; + } + } + + builder.Add(TargetMenuItemViewModel.Create(target, target.DisplayName)); } return builder.ToImmutable(); diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTag.cs b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTag.cs index 3636b6baf7fb5..77dd95d1c7a48 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTag.cs +++ b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTag.cs @@ -2,10 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; +using System.Collections; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.InheritanceMargin; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.Text.Editor; using Roslyn.Utilities; @@ -41,27 +45,17 @@ public InheritanceMarginTag(Workspace workspace, int lineNumber, ImmutableArray< Workspace = workspace; LineNumber = lineNumber; MembersOnLine = membersOnLine; - // The common case, one line has one member, avoid to use select & aggregate - if (membersOnLine.Length == 1) - { - var member = membersOnLine[0]; - var targets = member.TargetItems; - var relationship = targets[0].RelationToMember; - foreach (var target in targets.Skip(1)) - { - relationship |= target.RelationToMember; - } - Moniker = InheritanceMarginHelpers.GetMoniker(relationship); - } - else - { - // Multiple members on same line. - var aggregateRelationship = membersOnLine - .SelectMany(member => member.TargetItems.Select(target => target.RelationToMember)) - .Aggregate((r1, r2) => r1 | r2); - Moniker = InheritanceMarginHelpers.GetMoniker(aggregateRelationship); - } + // The common case is that one line has one member. + using var _ = ArrayBuilder.GetInstance(out var allItems); + foreach (var marginItem in membersOnLine) + allItems.AddRange(marginItem.TargetItems); + + var relationship = allItems[0].RelationToMember; + for (var i = 1; i < allItems.Count; i++) + relationship |= allItems[i].RelationToMember; + + Moniker = InheritanceMarginHelpers.GetMoniker(relationship); } } } diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTaggerProvider.cs b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTaggerProvider.cs index b7b2271a9d86f..6ebdb575302b0 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTaggerProvider.cs +++ b/src/VisualStudio/Core/Def/InheritanceMargin/InheritanceMarginTaggerProvider.cs @@ -93,37 +93,33 @@ protected override async Task ProduceTagsAsync( { var document = spanToTag.Document; if (document == null) - { return; - } + + var inheritanceMarginInfoService = document.GetLanguageService(); + if (inheritanceMarginInfoService == null) + return; if (GlobalOptions.GetOption(FeatureOnOffOptions.ShowInheritanceMargin, document.Project.Language) == false) - { return; - } + + var includeGlobalImports = GlobalOptions.GetOption(FeatureOnOffOptions.InheritanceMarginIncludeGlobalImports, document.Project.Language); // Use FrozenSemantics Version of document to get the semantics ready, therefore we could have faster // response. (Since the full load might take a long time) // We also subscribe to CompilationAvailableTaggerEventSource, so this will finally reach the correct state. document = document.WithFrozenPartialSemantics(cancellationToken); - var inheritanceMarginInfoService = document.GetLanguageService(); - if (inheritanceMarginInfoService == null) - { - return; - } var spanToSearch = spanToTag.SnapshotSpan.Span.ToTextSpan(); var stopwatch = SharedStopwatch.StartNew(); var inheritanceMemberItems = await inheritanceMarginInfoService.GetInheritanceMemberItemsAsync( document, spanToSearch, + includeGlobalImports, cancellationToken).ConfigureAwait(false); var elapsed = stopwatch.Elapsed; if (inheritanceMemberItems.IsEmpty) - { return; - } InheritanceMarginLogger.LogGenerateBackgroundInheritanceInfo(elapsed); @@ -131,8 +127,7 @@ protected override async Task ProduceTagsAsync( // For example: // interface IBar { void Foo1(); void Foo2(); } // class Bar : IBar { void Foo1() { } void Foo2() { } } - var lineToMembers = inheritanceMemberItems - .GroupBy(item => item.LineNumber); + var lineToMembers = inheritanceMemberItems.GroupBy(item => item.LineNumber); var snapshot = spanToTag.SnapshotSpan.Snapshot; diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/DisambiguousTargetMenuItemViewModel.cs b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/DisambiguousTargetMenuItemViewModel.cs new file mode 100644 index 0000000000000..f623e1f1c5c1a --- /dev/null +++ b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/DisambiguousTargetMenuItemViewModel.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Wpf; +using Microsoft.CodeAnalysis.FindUsages; +using Microsoft.CodeAnalysis.InheritanceMargin; +using Microsoft.VisualStudio.Imaging.Interop; +using Microsoft.VisualStudio.LanguageServices.Implementation.InheritanceMargin.MarginGlyph; +using Roslyn.Utilities; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.InheritanceMargin.MarginGlyph +{ + /// + /// The View Model would be used when there are multiple targets with same name in the group. + /// It contains an addtional image moniker represents the source language in the UI. + /// + internal class DisambiguousTargetMenuItemViewModel : TargetMenuItemViewModel + { + /// + /// Icon represets the source language of this target. + /// + public ImageMoniker LanguageMoniker { get; } + + // Internal for testing purpose + internal DisambiguousTargetMenuItemViewModel( + string displayContent, + ImageMoniker imageMoniker, + DetachedDefinitionItem definitionItem, + ImageMoniker languageMoniker) : base(displayContent, imageMoniker, definitionItem) + { + LanguageMoniker = languageMoniker; + } + + public static DisambiguousTargetMenuItemViewModel CreateWithSourceLanguageGlyph( + InheritanceTargetItem target) + { + return new( + target.DisplayName, + target.Glyph.GetImageMoniker(), + target.DefinitionItem, + target.LanguageGlyph.GetImageMoniker()); + } + } +} diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/HeaderMenuItemViewModel.cs b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/HeaderMenuItemViewModel.cs index 7b97f8e3bfffe..e5e2009e2e667 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/HeaderMenuItemViewModel.cs +++ b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/HeaderMenuItemViewModel.cs @@ -14,8 +14,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.InheritanceMarg /// internal class HeaderMenuItemViewModel : MenuItemViewModel { - public HeaderMenuItemViewModel(string displayContent, ImageMoniker imageMoniker, string automationName) - : base(displayContent, imageMoniker, automationName) + public HeaderMenuItemViewModel(string displayContent, ImageMoniker imageMoniker) + : base(displayContent, imageMoniker) { } } diff --git a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml index 4e5c1510dda34..b0612a63355b7 100644 --- a/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml +++ b/src/VisualStudio/Core/Def/InheritanceMargin/MarginGlyph/InheritanceMarginContextMenu.xaml @@ -22,7 +22,6 @@ - @@ -35,7 +34,7 @@ - + @@ -75,6 +74,62 @@ + + +