diff --git a/Compilers.sln b/Compilers.sln index c03b89de1d83f..d047ebb257b2c 100644 --- a/Compilers.sln +++ b/Compilers.sln @@ -168,7 +168,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeStyleConfigFileGenerato EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CodeAnalysis.Collections", "src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.shproj", "{E919DD77-34F8-4F57-8058-4D3FF4C2B241}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rebuild", "src\Compilers\Core\Rebuild\Rebuild.csproj", "{321F9FED-AACC-42CB-93E5-541D79E099E8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Rebuild", "src\Compilers\Core\Rebuild\Microsoft.CodeAnalysis.Rebuild.csproj", "{321F9FED-AACC-42CB-93E5-541D79E099E8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Rebuild.UnitTests", "src\Compilers\Core\RebuildTest\Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj", "{FDBFBB64-5980-41C2-9E3E-FB8E2F700A5C}" EndProject diff --git a/Compilers.slnf b/Compilers.slnf index f03772c2261d0..b1ac6a6a8ad6f 100644 --- a/Compilers.slnf +++ b/Compilers.slnf @@ -31,7 +31,7 @@ "src\\Compilers\\Core\\MSBuildTask\\Microsoft.Build.Tasks.CodeAnalysis.csproj", "src\\Compilers\\Core\\Portable\\Microsoft.CodeAnalysis.csproj", "src\\Compilers\\Core\\RebuildTest\\Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj", - "src\\Compilers\\Core\\Rebuild\\Rebuild.csproj", + "src\\Compilers\\Core\\Rebuild\\Microsoft.CodeAnalysis.Rebuild.csproj", "src\\Compilers\\Extension\\Roslyn.Compilers.Extension.csproj", "src\\Compilers\\Server\\VBCSCompilerTests\\VBCSCompiler.UnitTests.csproj", "src\\Compilers\\Server\\VBCSCompiler\\VBCSCompiler.csproj", diff --git a/Roslyn.sln b/Roslyn.sln index db3fb77dc8658..303f630b773cb 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -483,7 +483,7 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CodeAnalysis.Coll EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Collections.Package", "src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.Package.csproj", "{0C2E1633-1462-4712-88F4-A0C945BAD3A8}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rebuild", "src\Compilers\Core\Rebuild\Rebuild.csproj", "{B7D29559-4360-434A-B9B9-2C0612287999}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Rebuild", "src\Compilers\Core\Rebuild\Microsoft.CodeAnalysis.Rebuild.csproj", "{B7D29559-4360-434A-B9B9-2C0612287999}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Rebuild.UnitTests", "src\Compilers\Core\RebuildTest\Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj", "{21B49277-E55A-45EF-8818-744BCD6CB732}" EndProject diff --git a/azure-pipelines-official.yml b/azure-pipelines-official.yml index b1bf1d64f9570..79d14e429b0cb 100644 --- a/azure-pipelines-official.yml +++ b/azure-pipelines-official.yml @@ -48,11 +48,11 @@ stages: - job: OfficialBuild displayName: Official Build timeoutInMinutes: 360 - # Conditionally set build pool so we can share this YAML when building with different pipeline (devdiv vs dnceng) - pool: + # Conditionally set build pool so we can share this YAML when building with different pipeline (devdiv vs dnceng) + pool: ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: name: VSEngSS-MicroBuild2017 - demands: + demands: - msbuild - visualstudio - DotNetFramework @@ -60,7 +60,7 @@ stages: name: NetCoreInternal-Pool queue: BuildPool.Windows.10.Amd64.VS2019.Pre - steps: + steps: # Make sure our two pipelines generate builds with distinct build numbers to avoid confliction. # i.e. DevDiv builds will have even rev# whereas dnceng builds will be odd. - task: PowerShell@2 @@ -82,7 +82,7 @@ stages: type: 'Build' tags: 'OfficialBuild' condition: and(succeeded(), endsWith(variables['SourceBranchName'], '-vs-deps'), eq(variables['PRNumber'], 'default')) - + - task: tagBuildOrRelease@0 displayName: Tag PR validation build inputs: @@ -152,13 +152,13 @@ stages: displayName: Build inputs: filePath: eng/build.ps1 - arguments: -ci + arguments: -ci -restore -build -pack -sign -publish - -binaryLog + -binaryLog -configuration $(BuildConfiguration) -officialBuildId $(Build.BuildNumber) -officialSkipTests $(SkipTests) @@ -249,7 +249,7 @@ stages: # Publish insertion packages to CoreXT store. - task: NuGetCommand@2 - displayName: Publish CoreXT Packages + displayName: Publish CoreXT Packages inputs: command: push packagesToPush: '$(Build.SourcesDirectory)\artifacts\VSSetup\$(BuildConfiguration)\DevDivPackages\**\*.nupkg' @@ -270,7 +270,7 @@ stages: ArtifactName: 'VSSetup' condition: succeeded() - # Publish our NuPkgs as an artifact. The name of this artifact must be PackageArtifacts as the + # Publish our NuPkgs as an artifact. The name of this artifact must be PackageArtifacts as the # arcade templates depend on the name. - task: PublishBuildArtifacts@1 displayName: Publish Artifact Packages @@ -295,7 +295,7 @@ stages: - template: /eng/common/templates/job/publish-build-assets.yml parameters: publishUsingPipelines: true - dependsOn: + dependsOn: - OfficialBuild ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}: queue: @@ -304,7 +304,7 @@ stages: pool: vmImage: vs2017-win2016 -# We need to skip post-build stages for PR validation build, but it can only be identified by +# We need to skip post-build stages for PR validation build, but it can only be identified by # the runtime variable 'PRNumber', thus this dummy stage. Also the dummy job is required # otherwise AzDO would just repeat jobs from previous stage. - stage: SetValidateDependency @@ -324,8 +324,8 @@ stages: # https://github.com/dotnet/arcade/issues/2871 is resolved. enableSymbolValidation: false enableSourceLinkValidation: false - # It's important that post-build stages are depends on 'SetValidateDependency' stage instead of 'build', - # since we don't want to publish validation build. + # It's important that post-build stages are depends on 'SetValidateDependency' stage instead of 'build', + # since we don't want to publish validation build. validateDependsOn: - SetValidateDependency dependsOn: diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md index 53e399e2dd4c0..579fd1e764325 100644 --- a/docs/Language Feature Status.md +++ b/docs/Language Feature Status.md @@ -12,9 +12,11 @@ efforts behind them. | ------- | ------ | ----- | ---------- | -------- | --------- | | [Record structs](https://github.com/dotnet/csharplang/issues/4334) | [record-structs](https://github.com/dotnet/roslyn/tree/features/record-structs) | [In Progress](https://github.com/dotnet/roslyn/issues/51199) | [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs), [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv) | | [Global Using Directive](https://github.com/dotnet/csharplang/issues/3428) | [GlobalUsingDirective](https://github.com/dotnet/roslyn/tree/features/GlobalUsingDirective) | [In Progress](https://github.com/dotnet/roslyn/issues/51307) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [cston](https://github.com/cston) | [AlekseyTs](https://github.com/AlekseyTs) | +| [Static Abstract Members In Interfaces](https://github.com/dotnet/csharplang/issues/4436) | [StaticAbstractMembersInInterfaces](https://github.com/dotnet/roslyn/tree/features/StaticAbstractMembersInInterfaces) | [In Progress](https://github.com/dotnet/roslyn/issues/52221) | [AlekseyTs](https://github.com/AlekseyTs) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [MadsTorgersen](https://github.com/MadsTorgersen) | | [File-scoped namespace](https://github.com/dotnet/csharplang/issues/137) | [FileScopedNamespaces](https://github.com/dotnet/roslyn/tree/features/FileScopedNamespaces) | In Progress | [chsienki](https://github.com/chsienki) | [cston](https://github.com/cston), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | | [Interpolated string improvements](https://github.com/dotnet/csharplang/issues/4487) | [interpolated-string](https://github.com/dotnet/roslyn/tree/features/interpolated-string) | [In Progress](https://github.com/dotnet/roslyn/issues/51499) | [333fred](https://github.com/333fred) | [AlekseyTs](https://github.com/AlekseyTs), [chsienki](https://github.com/chsienki) | [jaredpar](https://github.com/jaredpar) | -| [Parameterless struct constructors](https://github.com/dotnet/csharplang/issues/99) | TBD | In Progress | [cston](https://github.com/cston) | [jcouv](https://github.com/jcouv), [333fred](https://github.com/333fred) | [jcouv](https://github.com/jouv) | +| [Parameterless struct constructors](https://github.com/dotnet/csharplang/issues/99) | [struct-ctors](https://github.com/dotnet/roslyn/tree/features/struct-ctors) | [In Progress](https://github.com/dotnet/roslyn/issues/51698) | [cston](https://github.com/cston) | [jcouv](https://github.com/jcouv), [333fred](https://github.com/333fred) | [jcouv](https://github.com/jouv) | +| [Lambda improvements](https://github.com/dotnet/csharplang/blob/main/proposals/lambda-improvements.md) | [lambdas](https://github.com/dotnet/roslyn/tree/features/lambdas) | [In Progress](https://github.com/dotnet/roslyn/issues/52192) | [cston](https://github.com/cston) | [333fred](https://github.com/333fred), [jcouv](https://github.com/jcouv) | [jaredpar](https://github.com/jaredpar) | | [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) | | [Improved Definite Assignment](https://github.com/dotnet/csharplang/issues/4465) | [improved-definite-assignment](https://github.com/dotnet/roslyn/tree/features/improved-definite-assignment) | [In Progress](https://github.com/dotnet/roslyn/issues/51463) | [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv) | [jaredpar](https://github.com/jaredpar) | | [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) | diff --git a/docs/compilers/Deterministic Inputs.md b/docs/compilers/Deterministic Inputs.md index 2d7c1bf336432..c865ff6ffad0f 100644 --- a/docs/compilers/Deterministic Inputs.md +++ b/docs/compilers/Deterministic Inputs.md @@ -1,13 +1,12 @@ Deterministic Inputs ==================== -We are aiming to make the compilers ultimately deterministic (https://github.com/dotnet/roslyn/issues/372). What that means is that the "same inputs" will cause the compilers to produce the "same outputs". +The C# and VB compilers are fully deterministic when the `/deterministic` option is specified (this is the default in the .NET SDK). This means that the "same inputs" will cause the compilers to produce the "same outputs" byte for byte. The following are considered inputs to the compiler for the purpose of determinism: -- The sequence of command-line parameters -- The contents of the compiler's `.rsp` response file. -- The precise version of the compiler used, and its referenced assemblies +- The sequence of command-line parameters (order is important) +- The precise version of the compiler used and the files included in its deployment: reference assemblies, rsp, etc ... - Current full directory path (you can reduce this to a relative path; see https://github.com/dotnet/roslyn/issues/949) - (Binary) contents of all files explicitly passed to the compiler, directly or indirectly, including - source files @@ -17,15 +16,17 @@ The following are considered inputs to the compiler for the purpose of determini - the strong name key file - `@` response files - Analyzers + - Generators - Rulesets - - "additional files" that may be used by analyzers -- The current culture (for the language in which diagnostics and exception messages are produced). + - "additional files" that may be used by analyzers and generators +- The current culture if `/preferreduilang` is not specified (for the language in which diagnostics and exception messages are produced). - The current OS code page if `/codepage` is not specified and any of the input source files do not have BOM and are not UTF-8 encoded. - The existence, non-existence, and contents of files on the compiler's search paths (specified, e.g. by `/lib` or `/recurse`) - The CLR platform on which the compiler is run: - The result of `double` arithmetic performed for constant-folding may use excess precision on some platforms. - The compiler uses Unicode tables provided by the platform. - The version of the zlib library that the CLR uses to implement compression (when `/embed` or `/debug:embedded` is used). -- The value of `%LIBPATH%`, as it can affect analyzer dependency loading. +- The value of `%LIBPATH%`, as it can affect reference discovery if not fully qualified and how the runtime handles analyzer / generator dependency loading. +- The full path of source files although `/pathmap` can be used to normalize this between compiles of the same code in different root directories. At the moment the compiler also depends on the time of day and random numbers for GUIDs, so it is not deterministic unless you specify `/deterministic`. diff --git a/docs/wiki/Manual-Testing.md b/docs/wiki/Manual-Testing.md index 260f92311e664..05ab1927ecd8f 100644 --- a/docs/wiki/Manual-Testing.md +++ b/docs/wiki/Manual-Testing.md @@ -66,7 +66,7 @@ When doing a test pass, copy this page and consider using these status indicator | **Typing** | :fast_forward: **General Typing**
- Type and paste new constructs
- Nothing interferes with verbatim typing | | | | | | :mag: :fast_forward: **Completion**
- Typing new keyword/construct names
- Dotting off of new constructs
- Matching part of the identifier is highlighted (including word prefix matches) [Visual Studio 2015 Update 1]
- Target type preselection [Visual Studio 2017]
IntelliSense filtering [Visual Studio 2017] | | | | | | :fast_forward: **Formatting**
- Spacing in and around new constructs
- Spacing options
- Format Document command
`Tools > Options` settings should be respected | | | | -| | :fast_forward: **Automatic Brace Completion** (*C# only*)
- Auto-insert close brace
- Shift+Enter commit of IntelliSense and any pending brace completion sessions (Known issue: https://github.com/dotnet/roslyn/issues/18065) | | | N/A | +| | :fast_forward: **Automatic Brace Completion** (*C# only*)
- Auto-insert close brace
- Shift+Enter commit of IntelliSense and any pending brace completion sessions (Currently C# only: https://github.com/dotnet/roslyn/issues/18065) | | | N/A | | | :fast_forward: **Indentation**
- Typing `Enter` in an unfinished statement indents the next line | | | | | **Navigating** | :mag: :fast_forward: **Go To Definition**
- F12 from callsites to definition
- Ctrl+click [Visual Studio 2017 version 15.4] | | | | | | :fast_forward: **Go To Implementation**
- Ctrl+F12 to jump from virtual members to their implementations
- Jump from inheritable types to their implementations | | | N/A | diff --git a/eng/Versions.props b/eng/Versions.props index da6f91a9cf921..9c5fe36c3dbf7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -8,7 +8,7 @@ 3 10 0 - 2 + 3 $(MajorVersion).$(MinorVersion).$(PatchVersion) - + @@ -1440,7 +1440,7 @@ - + - + @@ -1964,7 +1964,7 @@ - + @@ -2130,7 +2130,7 @@ - + @@ -2146,7 +2146,7 @@ - + diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 502d910ed047f..8116475713893 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2360,7 +2360,7 @@ internal void ReportUnusedImports(SyntaxTree? filterTree, BindingDiagnosticBag d else if (info.Kind == SyntaxKind.ExternAliasDirective) { // Record targets of used extern aliases - var node = info.Tree.GetRoot().FindToken(info.Span.Start, findInsideTrivia: false). + var node = info.Tree.GetRoot(cancellationToken).FindToken(info.Span.Start, findInsideTrivia: false). Parent!.FirstAncestorOrSelf(); if (node is object && GetExternAliasTarget(node.Identifier.ValueText, out NamespaceSymbol target)) diff --git a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs index 86faca93ca01f..61f0a48e49946 100644 --- a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs @@ -1260,7 +1260,7 @@ private SynthesizedRecordConstructor TryGetSynthesizedRecordConstructor(RecordDe NamedTypeSymbol recordType = GetDeclaredType(node); var symbol = recordType.GetMembersUnordered().OfType().SingleOrDefault(); - if (symbol?.GetSyntax() != node) + if (symbol?.SyntaxRef.SyntaxTree != node.SyntaxTree || symbol.GetSyntax() != node) { return null; } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/CSharpDataFlowAnalysis.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/CSharpDataFlowAnalysis.cs index 96f70fd620a3d..bf24860d0dfba 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/CSharpDataFlowAnalysis.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/CSharpDataFlowAnalysis.cs @@ -371,7 +371,7 @@ private HashSet UnassignedVariableAddressOfSyntaxes } /// - /// Returns true iff analysis was successful. Analysis can fail if the region does not properly span a single expression, + /// Returns true if and only if analysis was successful. Analysis can fail if the region does not properly span a single expression, /// a single statement, or a contiguous series of statements within the enclosing block. /// public sealed override bool Succeeded diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/ControlFlowAnalysis.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/ControlFlowAnalysis.cs index 226af335a1d09..a467bdf6efbc9 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/ControlFlowAnalysis.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/ControlFlowAnalysis.cs @@ -133,7 +133,7 @@ public override ImmutableArray ReturnStatements } /// - /// Returns true iff analysis was successful. Analysis can fail if the region does not properly span a single expression, + /// Returns true if and only if analysis was successful. Analysis can fail if the region does not properly span a single expression, /// a single statement, or a contiguous series of statements within the enclosing block. /// public sealed override bool Succeeded diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs index 09d63db09f1d6..d7da9cca73740 100644 --- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs @@ -509,7 +509,7 @@ public BoundAwaitableValuePlaceholder(SyntaxNode syntax, uint valEscape, TypeSym } - public new TypeSymbol? Type => base.Type!; + public new TypeSymbol? Type => base.Type; public uint ValEscape { get; } [DebuggerStepThrough] @@ -853,7 +853,7 @@ public BoundNamespaceExpression(SyntaxNode syntax, NamespaceSymbol namespaceSymb } - public new TypeSymbol Type => base.Type!; + public new TypeSymbol? Type => base.Type; public NamespaceSymbol NamespaceSymbol { get; } @@ -1018,7 +1018,7 @@ public BoundUnconvertedAddressOfOperator(SyntaxNode syntax, BoundMethodGroup ope public BoundMethodGroup Operand { get; } - public new TypeSymbol? Type => base.Type!; + public new TypeSymbol? Type => base.Type; [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitUnconvertedAddressOfOperator(this); @@ -2325,7 +2325,7 @@ public BoundDefaultLiteral(SyntaxNode syntax) } - public new TypeSymbol? Type => base.Type!; + public new TypeSymbol? Type => base.Type; [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitDefaultLiteral(this); @@ -2613,7 +2613,7 @@ public BoundArgListOperator(SyntaxNode syntax, ImmutableArray a } - public new TypeSymbol? Type => base.Type!; + public new TypeSymbol? Type => base.Type; public ImmutableArray Arguments { get; } @@ -4047,7 +4047,7 @@ public BoundBaseReference(SyntaxNode syntax, TypeSymbol? type) } - public new TypeSymbol? Type => base.Type!; + public new TypeSymbol? Type => base.Type; [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitBaseReference(this); @@ -5204,7 +5204,7 @@ protected BoundMethodOrPropertyGroup(BoundKind kind, SyntaxNode syntax, BoundExp } - public new TypeSymbol Type => base.Type!; + public new TypeSymbol? Type => base.Type; public BoundExpression? ReceiverOpt { get; } @@ -5821,7 +5821,7 @@ public BoundUnconvertedObjectCreationExpression(SyntaxNode syntax, ImmutableArra } - public new TypeSymbol? Type => base.Type!; + public new TypeSymbol? Type => base.Type; public ImmutableArray Arguments { get; } @@ -5940,7 +5940,7 @@ public BoundTupleLiteral(SyntaxNode syntax, ImmutableArray argu } - public new TypeSymbol? Type => base.Type!; + public new TypeSymbol? Type => base.Type; [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitTupleLiteral(this); @@ -6563,7 +6563,7 @@ public BoundArrayInitialization(SyntaxNode syntax, ImmutableArray base.Type!; + public new TypeSymbol? Type => base.Type; public ImmutableArray Initializers { get; } [DebuggerStepThrough] @@ -6992,7 +6992,7 @@ public BoundLambda(SyntaxNode syntax, UnboundLambda unboundLambda, LambdaSymbol public LambdaSymbol Symbol { get; } - public new TypeSymbol? Type => base.Type!; + public new TypeSymbol? Type => base.Type; public BoundBlock Body { get; } @@ -7037,7 +7037,7 @@ public UnboundLambda(SyntaxNode syntax, UnboundLambdaState data, Boolean withDep } - public new TypeSymbol Type => base.Type!; + public new TypeSymbol? Type => base.Type; public UnboundLambdaState Data { get; } @@ -7717,7 +7717,7 @@ public BoundDiscardExpression(SyntaxNode syntax, TypeSymbol? type) } - public new TypeSymbol? Type => base.Type!; + public new TypeSymbol? Type => base.Type; [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitDiscardExpression(this); @@ -7774,7 +7774,7 @@ protected VariablePendingInference(BoundKind kind, SyntaxNode syntax, Symbol var } - public new TypeSymbol Type => base.Type!; + public new TypeSymbol? Type => base.Type; public Symbol VariableSymbol { get; } @@ -7844,7 +7844,7 @@ public OutDeconstructVarPendingInference(SyntaxNode syntax) } - public new TypeSymbol Type => base.Type!; + public new TypeSymbol? Type => base.Type; [DebuggerStepThrough] public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitOutDeconstructVarPendingInference(this); @@ -7937,7 +7937,7 @@ public BoundExpressionWithNullability(SyntaxNode syntax, BoundExpression express public BoundExpression Expression { get; } - public new TypeSymbol? Type => base.Type!; + public new TypeSymbol? Type => base.Type; public NullableAnnotation NullableAnnotation { get; } [DebuggerStepThrough] diff --git a/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj b/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj index b952c21041c66..ae5c7ac879933 100644 --- a/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj +++ b/src/Compilers/CSharp/Portable/Microsoft.CodeAnalysis.CSharp.csproj @@ -62,6 +62,7 @@ + diff --git a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs index 00cd1b4219ae4..7ffdfa34258ac 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs @@ -131,7 +131,7 @@ internal bool IsMarshalAsObject /// Returns true if the parameter is semantically optional. /// /// - /// True iff the parameter has a default argument syntax, + /// True if and only if the parameter has a default argument syntax, /// or the parameter is not a params-array and Optional metadata flag is set. /// public bool IsOptional diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs index a223121680f94..95c8b305768ac 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs @@ -116,7 +116,11 @@ private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, MethodKind if (methodKind == MethodKind.StaticConstructor) { - if ((mods & DeclarationModifiers.AccessibilityMask) != 0) + // Don't report ERR_StaticConstructorWithAccessModifiers if the ctor symbol name doesn't match the containing type name. + // This avoids extra unnecessary errors. + // There will already be a diagnostic saying Method must have a return type. + if ((mods & DeclarationModifiers.AccessibilityMask) != 0 && + ContainingType.Name == ((ConstructorDeclarationSyntax)this.SyntaxNode).Identifier.ValueText) { diagnostics.Add(ErrorCode.ERR_StaticConstructorWithAccessModifiers, location, this); mods = mods & ~DeclarationModifiers.AccessibilityMask; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs index c4bbe7916d425..a0e05f31f5354 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs @@ -60,7 +60,11 @@ protected sealed override void MethodChecks(BindingDiagnosticBag diagnostics) _lazyReturnType = TypeWithAnnotations.Create(bodyBinder.GetSpecialType(SpecialType.System_Void, diagnostics, syntax)); var location = this.Locations[0]; - if (MethodKind == MethodKind.StaticConstructor && (_lazyParameters.Length != 0)) + // Don't report ERR_StaticConstParam if the ctor symbol name doesn't match the containing type name. + // This avoids extra unnecessary errors. + // There will already be a diagnostic saying Method must have a return type. + if (MethodKind == MethodKind.StaticConstructor && (_lazyParameters.Length != 0) && + ContainingType.Name == ((ConstructorDeclarationSyntax)this.SyntaxNode).Identifier.ValueText) { diagnostics.Add(ErrorCode.ERR_StaticConstParam, location, this); } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs index 46b26c57c47ef..d35c1fff5ff08 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs @@ -434,6 +434,11 @@ private static bool NeedsSeparator(SyntaxToken token, SyntaxToken next) } } + if (token.IsKind(SyntaxKind.GreaterThanToken) && token.Parent.IsKind(SyntaxKind.FunctionPointerParameterList)) + { + return true; + } + if (token.IsKind(SyntaxKind.CommaToken) && !next.IsKind(SyntaxKind.CommaToken) && !token.Parent.IsKind(SyntaxKind.EnumDeclaration)) @@ -456,7 +461,8 @@ private static bool NeedsSeparator(SyntaxToken token, SyntaxToken next) if (token.IsKind(SyntaxKind.ColonToken)) { - return !token.Parent.IsKind(SyntaxKind.InterpolationFormatClause); + return !token.Parent.IsKind(SyntaxKind.InterpolationFormatClause) && + !token.Parent.IsKind(SyntaxKind.XmlPrefix); } if (next.IsKind(SyntaxKind.ColonToken)) @@ -485,9 +491,108 @@ private static bool NeedsSeparator(SyntaxToken token, SyntaxToken next) return true; } - if (token.IsKind(SyntaxKind.EqualsToken) || next.IsKind(SyntaxKind.EqualsToken)) + if (token.IsKind(SyntaxKind.EqualsToken)) { - return true; + return !token.Parent.IsKind(SyntaxKind.XmlTextAttribute); + } + + if (next.IsKind(SyntaxKind.EqualsToken)) + { + return !next.Parent.IsKind(SyntaxKind.XmlTextAttribute); + } + + // Rules for function pointer below are taken from: + // https://github.com/dotnet/roslyn/blob/1cca63b5d8ea170f8d8e88e1574aa3ebe354c23b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs#L321-L413 + if (token.Parent.IsKind(SyntaxKind.FunctionPointerType)) + { + // No spacing between delegate and * + if (next.IsKind(SyntaxKind.AsteriskToken) && token.IsKind(SyntaxKind.DelegateKeyword)) + { + return false; + } + + // Force a space between * and the calling convention + if (token.IsKind(SyntaxKind.AsteriskToken) && next.Parent.IsKind(SyntaxKind.FunctionPointerCallingConvention)) + { + switch (next.Kind()) + { + case SyntaxKind.IdentifierToken: + case SyntaxKind.ManagedKeyword: + case SyntaxKind.UnmanagedKeyword: + return true; + } + } + } + + if (next.Parent.IsKind(SyntaxKind.FunctionPointerParameterList) && next.IsKind(SyntaxKind.LessThanToken)) + { + switch (token.Kind()) + { + // No spacing between the * and < tokens if there is no calling convention + case SyntaxKind.AsteriskToken: + // No spacing between the calling convention and opening angle bracket of function pointer types: + // delegate* managed< + case SyntaxKind.ManagedKeyword: + case SyntaxKind.UnmanagedKeyword: + // No spacing between the calling convention specifier and the opening angle + // delegate* unmanaged[Cdecl]< + case SyntaxKind.CloseBracketToken when token.Parent.IsKind(SyntaxKind.FunctionPointerUnmanagedCallingConventionList): + return false; + } + } + + // No space between unmanaged and the [ + // delegate* unmanaged[ + if (token.Parent.IsKind(SyntaxKind.FunctionPointerCallingConvention) && next.Parent.IsKind(SyntaxKind.FunctionPointerUnmanagedCallingConventionList) && + next.IsKind(SyntaxKind.OpenBracketToken)) + { + return false; + } + + // Function pointer calling convention adjustments + if (next.Parent.IsKind(SyntaxKind.FunctionPointerUnmanagedCallingConventionList) && token.Parent.IsKind(SyntaxKind.FunctionPointerUnmanagedCallingConventionList)) + { + if (next.IsKind(SyntaxKind.IdentifierToken)) + { + if (token.IsKind(SyntaxKind.OpenBracketToken)) + { + return false; + } + // Space after the , + // unmanaged[Cdecl, Thiscall + else if (token.IsKind(SyntaxKind.CommaToken)) + { + return true; + } + } + + // No space between identifier and comma + // unmanaged[Cdecl, + if (next.IsKind(SyntaxKind.CommaToken)) + { + return false; + } + + // No space before the ] + // unmanaged[Cdecl] + if (next.IsKind(SyntaxKind.CloseBracketToken)) + { + return false; + } + } + + // No space after the < in function pointer parameter lists + // delegate* in function pointer parameter lists + // delegate* + if (next.IsKind(SyntaxKind.GreaterThanToken) && next.Parent.IsKind(SyntaxKind.FunctionPointerParameterList)) + { + return false; } if (token.IsKind(SyntaxKind.EqualsGreaterThanToken) || next.IsKind(SyntaxKind.EqualsGreaterThanToken)) @@ -501,6 +606,19 @@ private static bool NeedsSeparator(SyntaxToken token, SyntaxToken next) return true; } + // No space before an asterisk that's part of a PointerTypeSyntax. + if (next.IsKind(SyntaxKind.AsteriskToken) && next.Parent is PointerTypeSyntax) + { + return false; + } + + // The last asterisk of a pointer declaration should be followed by a space. + if (token.IsKind(SyntaxKind.AsteriskToken) && token.Parent is PointerTypeSyntax && + (next.IsKind(SyntaxKind.IdentifierToken) || next.Parent.IsKind(SyntaxKind.IndexerDeclaration))) + { + return true; + } + if (IsKeyword(token.Kind())) { if (!next.IsKind(SyntaxKind.ColonToken) && diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs index ce8631fc49ca7..82781686a4f44 100644 --- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs +++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs @@ -688,7 +688,7 @@ public void Win32ResourceArguments() var parsedArgs = DefaultParse(args, WorkingDirectory); var compilation = CreateCompilation(new SyntaxTree[0]); IEnumerable errors; - CSharpCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, out errors); + CSharpCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, out errors); Assert.Equal(1, errors.Count()); Assert.Equal((int)ErrorCode.ERR_CantOpenWin32Manifest, errors.First().Code); Assert.Equal(2, errors.First().Arguments.Count()); @@ -700,7 +700,7 @@ public void Win32ResourceArguments() parsedArgs = DefaultParse(args, WorkingDirectory); - CSharpCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, out errors); + CSharpCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, out errors); Assert.Equal(1, errors.Count()); Assert.Equal((int)ErrorCode.ERR_CantOpenIcon, errors.First().Code); Assert.Equal(2, errors.First().Arguments.Count()); @@ -711,7 +711,7 @@ public void Win32ResourceArguments() }; parsedArgs = DefaultParse(args, WorkingDirectory); - CSharpCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, out errors); + CSharpCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, out errors); Assert.Equal(1, errors.Count()); Assert.Equal((int)ErrorCode.ERR_CantOpenWin32Res, errors.First().Code); Assert.Equal(2, errors.First().Arguments.Count()); @@ -722,7 +722,7 @@ public void Win32ResourceArguments() }; parsedArgs = DefaultParse(args, WorkingDirectory); - CSharpCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, out errors); + CSharpCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, out errors); Assert.Equal(1, errors.Count()); Assert.Equal((int)ErrorCode.ERR_CantOpenWin32Res, errors.First().Code); Assert.Equal(2, errors.First().Arguments.Count()); @@ -733,7 +733,7 @@ public void Win32ResourceArguments() }; parsedArgs = DefaultParse(args, WorkingDirectory); - CSharpCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, out errors); + CSharpCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, out errors); Assert.Equal(1, errors.Count()); Assert.Equal((int)ErrorCode.ERR_CantOpenIcon, errors.First().Code); Assert.Equal(2, errors.First().Arguments.Count()); @@ -744,7 +744,7 @@ public void Win32ResourceArguments() }; parsedArgs = DefaultParse(args, WorkingDirectory); - CSharpCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, out errors); + CSharpCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, out errors); Assert.Equal(1, errors.Count()); Assert.Equal((int)ErrorCode.ERR_CantOpenWin32Manifest, errors.First().Code); Assert.Equal(2, errors.First().Arguments.Count()); @@ -813,7 +813,7 @@ public void Win32IconContainsGarbage() var compilation = CreateCompilation(new SyntaxTree[0]); IEnumerable errors; - CSharpCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, out errors); + CSharpCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, out errors); Assert.Equal(1, errors.Count()); Assert.Equal((int)ErrorCode.ERR_ErrorBuildingWin32Resources, errors.First().Code); Assert.Equal(1, errors.First().Arguments.Count()); @@ -1808,35 +1808,6 @@ public void LangVersion_ListLangVersions() } } - - [Fact] - public void OptimizationLevelAdded_Canary() - { - // When OptimizationLevel is changed, this test will break. This list must be checked: - // - update OptimizationLevelFacts.ToPdbSerializedString - // - update tests that call this method - // - update docs\features\compilation-from-portable-pdb.md - // NOTE: release is duplicated because the return value for release is the same regardless of the debugPlusMode bool - AssertEx.SetEqual(new[] { "release", "release", "debug", "debug-plus" }, - Enum.GetValues(typeof(OptimizationLevel)).Cast().SelectMany(l => new[] { l.ToPdbSerializedString(false), l.ToPdbSerializedString(true) })); - } - - [Theory, - InlineData("release", true, OptimizationLevel.Release, false), - InlineData("debug", true, OptimizationLevel.Debug, false), - InlineData("debug-plus", true, OptimizationLevel.Debug, true), - InlineData("other", false, OptimizationLevel.Debug, false), - InlineData(null, false, OptimizationLevel.Debug, false)] - public void OptimizationLevel_ParsePdbSerializedString(string input, bool success, OptimizationLevel expected, bool expectedDebugPlusMode) - { - Assert.Equal(success, OptimizationLevelFacts.TryParsePdbSerializedString(input, out var optimization, out var debugPlusMode)); - Assert.Equal(expected, optimization); - Assert.Equal(expectedDebugPlusMode, debugPlusMode); - - // The canary check is a reminder that this test needs to be updated when an optimization level is added - OptimizationLevelAdded_Canary(); - } - [Fact] [WorkItem(546961, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546961")] public void Define() @@ -8698,7 +8669,7 @@ public void IOFailure_DisposeOutputFile() var srcPath = MakeTrivialExe(Temp.CreateDirectory().Path); var exePath = Path.Combine(Path.GetDirectoryName(srcPath), "test.exe"); var csc = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/nologo", "/preferreduilang:en", $"/out:{exePath}", srcPath }); - csc.FileOpen = (file, mode, access, share) => + csc.FileSystem = TestableFileSystem.CreateForStandard(openFileFunc: (file, mode, access, share) => { if (file == exePath) { @@ -8707,7 +8678,7 @@ public void IOFailure_DisposeOutputFile() } return File.Open(file, mode, access, share); - }; + }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); Assert.Equal(1, csc.Run(outWriter)); @@ -8721,7 +8692,7 @@ public void IOFailure_DisposePdbFile() var exePath = Path.Combine(Path.GetDirectoryName(srcPath), "test.exe"); var pdbPath = Path.ChangeExtension(exePath, "pdb"); var csc = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/nologo", "/preferreduilang:en", "/debug", $"/out:{exePath}", srcPath }); - csc.FileOpen = (file, mode, access, share) => + csc.FileSystem = TestableFileSystem.CreateForStandard(openFileFunc: (file, mode, access, share) => { if (file == pdbPath) { @@ -8730,7 +8701,7 @@ public void IOFailure_DisposePdbFile() } return File.Open(file, mode, access, share); - }; + }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); Assert.Equal(1, csc.Run(outWriter)); @@ -8743,7 +8714,7 @@ public void IOFailure_DisposeXmlFile() var srcPath = MakeTrivialExe(Temp.CreateDirectory().Path); var xmlPath = Path.Combine(Path.GetDirectoryName(srcPath), "test.xml"); var csc = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/nologo", "/preferreduilang:en", $"/doc:{xmlPath}", srcPath }); - csc.FileOpen = (file, mode, access, share) => + csc.FileSystem = TestableFileSystem.CreateForStandard(openFileFunc: (file, mode, access, share) => { if (file == xmlPath) { @@ -8752,7 +8723,7 @@ public void IOFailure_DisposeXmlFile() } return File.Open(file, mode, access, share); - }; + }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); Assert.Equal(1, csc.Run(outWriter)); @@ -8767,7 +8738,7 @@ public void IOFailure_DisposeSourceLinkFile(string format) var srcPath = MakeTrivialExe(Temp.CreateDirectory().Path); var sourceLinkPath = Path.Combine(Path.GetDirectoryName(srcPath), "test.json"); var csc = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/nologo", "/preferreduilang:en", "/debug:" + format, $"/sourcelink:{sourceLinkPath}", srcPath }); - csc.FileOpen = (file, mode, access, share) => + csc.FileSystem = TestableFileSystem.CreateForStandard(openFileFunc: (file, mode, access, share) => { if (file == sourceLinkPath) { @@ -8782,7 +8753,7 @@ public void IOFailure_DisposeSourceLinkFile(string format) } return File.Open(file, mode, access, share); - }; + }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); Assert.Equal(1, csc.Run(outWriter)); @@ -8795,7 +8766,7 @@ public void IOFailure_OpenOutputFile() string sourcePath = MakeTrivialExe(); string exePath = Path.Combine(Path.GetDirectoryName(sourcePath), "test.exe"); var csc = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/nologo", "/preferreduilang:en", $"/out:{exePath}", sourcePath }); - csc.FileOpen = (file, mode, access, share) => + csc.FileSystem = TestableFileSystem.CreateForStandard(openFileFunc: (file, mode, access, share) => { if (file == exePath) { @@ -8803,7 +8774,7 @@ public void IOFailure_OpenOutputFile() } return File.Open(file, mode, access, share); - }; + }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); Assert.Equal(1, csc.Run(outWriter)); @@ -8821,7 +8792,7 @@ public void IOFailure_OpenPdbFileNotCalled() string exePath = Path.Combine(Path.GetDirectoryName(sourcePath), "test.exe"); string pdbPath = Path.ChangeExtension(exePath, ".pdb"); var csc = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/nologo", "/debug-", $"/out:{exePath}", sourcePath }); - csc.FileOpen = (file, mode, access, share) => + csc.FileSystem = TestableFileSystem.CreateForStandard(openFileFunc: (file, mode, access, share) => { if (file == pdbPath) { @@ -8829,7 +8800,7 @@ public void IOFailure_OpenPdbFileNotCalled() } return File.Open(file, (FileMode)mode, (FileAccess)access, (FileShare)share); - }; + }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); Assert.Equal(0, csc.Run(outWriter)); @@ -8846,7 +8817,7 @@ public void IOFailure_OpenXmlFinal() string sourcePath = MakeTrivialExe(); string xmlPath = Path.Combine(WorkingDirectory, "Test.xml"); var csc = CreateCSharpCompiler(null, WorkingDirectory, new[] { "/nologo", "/preferreduilang:en", "/doc:" + xmlPath, sourcePath }); - csc.FileOpen = (file, mode, access, share) => + csc.FileSystem = TestableFileSystem.CreateForStandard(openFileFunc: (file, mode, access, share) => { if (file == xmlPath) { @@ -8856,7 +8827,7 @@ public void IOFailure_OpenXmlFinal() { return File.Open(file, (FileMode)mode, (FileAccess)access, (FileShare)share); } - }; + }); var outWriter = new StringWriter(CultureInfo.InvariantCulture); int exitCode = csc.Run(outWriter); diff --git a/src/Compilers/CSharp/Test/Emit/PDB/CSharpDeterministicBuildCompilationTests.cs b/src/Compilers/CSharp/Test/Emit/PDB/CSharpDeterministicBuildCompilationTests.cs index 50e4bcc9c546b..7b67e0ef72645 100644 --- a/src/Compilers/CSharp/Test/Emit/PDB/CSharpDeterministicBuildCompilationTests.cs +++ b/src/Compilers/CSharp/Test/Emit/PDB/CSharpDeterministicBuildCompilationTests.cs @@ -58,13 +58,12 @@ private static void TestDeterministicCompilationCSharp( TestMetadataReferenceInfo[] metadataReferences, int? debugDocumentsCount = null) { + var targetFramework = TargetFramework.NetCoreApp; var originalCompilation = CreateCompilation( syntaxTrees, references: metadataReferences.SelectAsArray(r => r.MetadataReference), options: compilationOptions, - // TFM needs to specified so the references are always the same, and not - // dependent on the testrun environment - targetFramework: TargetFramework.NetCoreApp); + targetFramework: targetFramework); var peBlob = originalCompilation.EmitToArray(options: emitOptions); @@ -88,7 +87,7 @@ private static void TestDeterministicCompilationCSharp( Assert.Equal(debugDocumentsCount ?? syntaxTrees.Length, pdbReader.Documents.Count); VerifyCompilationOptions(compilationOptions, originalCompilation, emitOptions, compilationOptionsReader, langVersion, syntaxTrees.Length); - DeterministicBuildCompilationTestHelpers.VerifyReferenceInfo(metadataReferences, metadataReferenceReader); + DeterministicBuildCompilationTestHelpers.VerifyReferenceInfo(metadataReferences, targetFramework, metadataReferenceReader); } } } @@ -342,8 +341,6 @@ private static IEnumerable GetCompilationOptions() yield return defaultOptions.WithNullableContextOptions(NullableContextOptions.Disable); yield return defaultOptions.WithNullableContextOptions(NullableContextOptions.Warnings); yield return defaultOptions.WithOptimizationLevel(OptimizationLevel.Release); - yield return defaultOptions.WithDebugPlusMode(true); - yield return defaultOptions.WithOptimizationLevel(OptimizationLevel.Release).WithDebugPlusMode(true); yield return defaultOptions.WithAssemblyIdentityComparer(new DesktopAssemblyIdentityComparer(new AssemblyPortabilityPolicy(suppressSilverlightLibraryAssembliesPortability: false, suppressSilverlightPlatformAssembliesPortability: false))); yield return defaultOptions.WithAssemblyIdentityComparer(new DesktopAssemblyIdentityComparer(new AssemblyPortabilityPolicy(suppressSilverlightLibraryAssembliesPortability: true, suppressSilverlightPlatformAssembliesPortability: false))); yield return defaultOptions.WithAssemblyIdentityComparer(new DesktopAssemblyIdentityComparer(new AssemblyPortabilityPolicy(suppressSilverlightLibraryAssembliesPortability: false, suppressSilverlightPlatformAssembliesPortability: true))); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 4e1e3a02e33f6..b8b457c0e01bb 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { - public class LambdaTests : CompilingTestBase + public class LambdaTests : CSharpTestBase { [Fact, WorkItem(37456, "https://github.com/dotnet/roslyn/issues/37456")] public void Verify37456() @@ -568,10 +568,10 @@ static void Main() "; var vbMetadata = vbProject.EmitToArray(options: new EmitOptions(metadataOnly: true)); var csProject = CreateCompilation(Parse(csSource), new[] { MetadataReference.CreateFromImage(vbMetadata) }); - - var diagnostics = csProject.GetDiagnostics().Select(DumpDiagnostic); - Assert.Equal(1, diagnostics.Count()); - Assert.Equal("'x' error CS0721: 'GC': static types cannot be used as parameters", diagnostics.First()); + csProject.VerifyDiagnostics( + // (6,15): error CS0721: 'GC': static types cannot be used as parameters + // M.F = x=>{}; + Diagnostic(ErrorCode.ERR_ParameterIsStaticClass, "x").WithArguments("System.GC").WithLocation(6, 15)); } [WorkItem(540251, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/540251")] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index 12eccfd572f1d..f6189db3f1727 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -20772,5 +20772,18 @@ partial void M(in int i) {} // partial void M(in int i) {} Diagnostic(ErrorCode.ERR_PartialMethodMustHaveLatent, "M").WithArguments("C.M(in int)").WithLocation(4, 18)); } + + [Fact] + public void MethodWithNoReturnTypeShouldNotComplainAboutStaticCtor() + { + CreateCompilation(@" +class X +{ + private static Y(int i) {} +}").VerifyDiagnostics( + // (4,20): error CS1520: Method must have a return type + // private static Y(int i) {} + Diagnostic(ErrorCode.ERR_MemberNeedsType, "Y").WithLocation(4, 20)); + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs index 4101ceb06b9cc..2e8fa09adecb3 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs @@ -198,6 +198,50 @@ public void TestNormalizeStatement1() TestNormalizeStatement("Func f = blah;", "Func f = blah;"); } + [Theory] + [InlineData("int*p;", "int* p;")] + [InlineData("int *p;", "int* p;")] + [InlineData("int*p1,p2;", "int* p1, p2;")] + [InlineData("int *p1, p2;", "int* p1, p2;")] + [InlineData("int**p;", "int** p;")] + [InlineData("int **p;", "int** p;")] + [InlineData("int**p1,p2;", "int** p1, p2;")] + [InlineData("int **p1, p2;", "int** p1, p2;")] + [WorkItem(49733, "https://github.com/dotnet/roslyn/issues/49733")] + public void TestNormalizeAsteriskInPointerDeclaration(string text, string expected) + { + TestNormalizeStatement(text, expected); + } + + [Fact] + [WorkItem(49733, "https://github.com/dotnet/roslyn/issues/49733")] + public void TestNormalizeAsteriskInPointerReturnTypeOfIndexer() + { + var text = @"public unsafe class C +{ + int*this[int x,int y]{get=>(int*)0;} +}"; + var expected = @"public unsafe class C +{ + int* this[int x, int y] { get => (int*)0; } +}"; + TestNormalizeDeclaration(text, expected); + } + + [Fact] + public void TestNormalizeAsteriskInVoidPointerCast() + { + var text = @"public unsafe class C +{ + void*this[int x,int y]{get => ( void * ) 0;} +}"; + var expected = @"public unsafe class C +{ + void* this[int x, int y] { get => (void*)0; } +}"; + TestNormalizeDeclaration(text, expected); + } + private void TestNormalizeStatement(string text, string expected) { var node = SyntaxFactory.ParseStatement(text); @@ -649,6 +693,92 @@ public void TestNormalizeTuples() TestNormalizeDeclaration("public (string prefix,string uri)Foo()", "public (string prefix, string uri) Foo()"); } + [Fact] + [WorkItem(50664, "https://github.com/dotnet/roslyn/issues/50664")] + public void TestNormalizeFunctionPointer() + { + var content = +@"unsafe class C +{ + delegate * < int , int > functionPointer; +}"; + + var expected = +@"unsafe class C +{ + delegate* functionPointer; +}"; + + TestNormalizeDeclaration(content, expected); + } + + [Fact] + [WorkItem(50664, "https://github.com/dotnet/roslyn/issues/50664")] + public void TestNormalizeFunctionPointerWithManagedCallingConvention() + { + var content = +@"unsafe class C +{ + delegate *managed < int , int > functionPointer; +}"; + + var expected = +@"unsafe class C +{ + delegate* managed functionPointer; +}"; + + TestNormalizeDeclaration(content, expected); + } + + [Fact] + [WorkItem(50664, "https://github.com/dotnet/roslyn/issues/50664")] + public void TestNormalizeFunctionPointerWithUnmanagedCallingConvention() + { + var content = +@"unsafe class C +{ + delegate *unmanaged < int , int > functionPointer; +}"; + + var expected = +@"unsafe class C +{ + delegate* unmanaged functionPointer; +}"; + + TestNormalizeDeclaration(content, expected); + } + + [Fact] + [WorkItem(50664, "https://github.com/dotnet/roslyn/issues/50664")] + public void TestNormalizeFunctionPointerWithUnmanagedCallingConventionAndSpecifiers() + { + var content = +@"unsafe class C +{ + delegate *unmanaged [ Cdecl , Thiscall ] < int , int > functionPointer; +}"; + + var expected = +@"unsafe class C +{ + delegate* unmanaged[Cdecl, Thiscall] functionPointer; +}"; + + TestNormalizeDeclaration(content, expected); + } + + [Fact] + [WorkItem(49732, "https://github.com/dotnet/roslyn/issues/49732")] + public void TestNormalizeXmlInDocComment() + { + var code = @"/// +/// If this method succeeds, it returns S_OK. +/// "; + TestNormalizeDeclaration(code, code); + } + [Theory] [InlineData("_=()=>{};", "_ = () =>\r\n{\r\n};")] [InlineData("_=x=>{};", "_ = x =>\r\n{\r\n};")] diff --git a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs index 40a732904aa5a..79769dc19af09 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Analyzers/AnalyzerFileReferenceTests.cs @@ -391,6 +391,82 @@ public void Initialize(GeneratorInitializationContext context) {{ }} } } + [Fact] + [WorkItem(52035, "https://github.com/dotnet/roslyn/issues/52035")] + public void TestLoadedAnalyzerOrderIsDeterministic() + { + AnalyzerFileReference reference = CreateAnalyzerFileReference(Assembly.GetExecutingAssembly().Location); + + var csharpAnalyzers = reference.GetAnalyzers(LanguageNames.CSharp).Select(a => a.GetType().FullName).ToArray(); + Assert.Equal(4, csharpAnalyzers.Length); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+SomeType+NestedAnalyzer", csharpAnalyzers[0]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+TestAnalyzer", csharpAnalyzers[1]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+TestAnalyzerCS", csharpAnalyzers[2]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.TestAnalyzerCSVB", csharpAnalyzers[3]); + + var vbAnalyzers = reference.GetAnalyzers(LanguageNames.VisualBasic).Select(a => a.GetType().FullName).ToArray(); + Assert.Equal(4, vbAnalyzers.Length); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+SomeType+NestedAnalyzer", vbAnalyzers[0]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+TestAnalyzer", vbAnalyzers[1]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+TestAnalyzerVB", vbAnalyzers[2]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.TestAnalyzerCSVB", vbAnalyzers[3]); + + // analyzers return C#, then VB, including duplicates + var allAnalyzers = reference.GetAnalyzersForAllLanguages().Select(a => a.GetType().FullName).ToArray(); + Assert.Equal(8, allAnalyzers.Length); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+SomeType+NestedAnalyzer", allAnalyzers[0]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+TestAnalyzer", allAnalyzers[1]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+TestAnalyzerCS", allAnalyzers[2]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.TestAnalyzerCSVB", allAnalyzers[3]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+SomeType+NestedAnalyzer", allAnalyzers[4]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+TestAnalyzer", allAnalyzers[5]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+TestAnalyzerVB", allAnalyzers[6]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.TestAnalyzerCSVB", allAnalyzers[7]); + } + + [ConditionalFact(typeof(CoreClrOnly), Reason = "Can't load a framework targeting generator, which these are in desktop")] + [WorkItem(52035, "https://github.com/dotnet/roslyn/issues/52035")] + public void TestLoadedGeneratorOrderIsDeterministic() + { + AnalyzerFileReference reference = CreateAnalyzerFileReference(Assembly.GetExecutingAssembly().Location); + + var csharpGenerators = reference.GetGenerators(LanguageNames.CSharp).Select(a => a.GetType().FullName).ToArray(); + Assert.Equal(8, csharpGenerators.Length); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+SomeType+NestedGenerator", csharpGenerators[0]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+TestGenerator", csharpGenerators[1]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.BaseGenerator", csharpGenerators[2]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.CSharpAndVisualBasicGenerator", csharpGenerators[3]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.ExplicitCSharpOnlyGenerator", csharpGenerators[4]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.SubClassedGenerator", csharpGenerators[5]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.TestGenerator", csharpGenerators[6]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.VisualBasicAndCSharpGenerator", csharpGenerators[7]); + + var vbGenerators = reference.GetGenerators(LanguageNames.VisualBasic).Select(a => a.GetType().FullName).ToArray(); + Assert.Equal(3, vbGenerators.Length); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.CSharpAndVisualBasicGenerator", vbGenerators[0]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.VisualBasicAndCSharpGenerator", vbGenerators[1]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.VisualBasicOnlyGenerator", vbGenerators[2]); + + // generators load in language order (C#, F#, VB), and *do not* include duplicates + var allGenerators = reference.GetGeneratorsForAllLanguages().Select(g => g.GetType().FullName).ToArray(); + Assert.Equal(10, allGenerators.Length); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+SomeType+NestedGenerator", allGenerators[0]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.AnalyzerFileReferenceTests+TestGenerator", allGenerators[1]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.BaseGenerator", allGenerators[2]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.CSharpAndVisualBasicGenerator", allGenerators[3]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.ExplicitCSharpOnlyGenerator", allGenerators[4]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.SubClassedGenerator", allGenerators[5]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.TestGenerator", allGenerators[6]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.VisualBasicAndCSharpGenerator", allGenerators[7]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.FSharpGenerator", allGenerators[8]); + Assert.Equal("Microsoft.CodeAnalysis.UnitTests.VisualBasicOnlyGenerator", allGenerators[9]); + } + + // NOTE: the order in which these are emitted can change the test 'TestLoadedAnalyzerOrderIsDeterministic' + // and other determinism tests in this file. + // Ensure you do not re-arrange them alphabetically, as that will invalidate the tests, without + // explicitly failing them + [DiagnosticAnalyzer(LanguageNames.CSharp, new string[] { LanguageNames.VisualBasic })] public class TestAnalyzer : DiagnosticAnalyzer { diff --git a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs index 025896ce62492..8c16096b12924 100644 --- a/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs +++ b/src/Compilers/Core/Portable/Collections/ImmutableArrayExtensions.cs @@ -10,6 +10,7 @@ using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.PooledObjects; @@ -226,13 +227,13 @@ public static ImmutableArray SelectAsArray(this Immutab /// /// Maps an immutable array through a function that returns ValueTasks, returning the new ImmutableArray. /// - public static async ValueTask> SelectAsArrayAsync(this ImmutableArray array, Func> selector) + public static async ValueTask> SelectAsArrayAsync(this ImmutableArray array, Func> selector, CancellationToken cancellationToken) { var builder = ArrayBuilder.GetInstance(array.Length); foreach (var item in array) { - builder.Add(await selector(item).ConfigureAwait(false)); + builder.Add(await selector(item, cancellationToken).ConfigureAwait(false)); } return builder.ToImmutableAndFree(); diff --git a/src/Compilers/Core/Portable/CommandLine/CommonCompiler.CompilerEmitStreamProvider.cs b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.CompilerEmitStreamProvider.cs index 6ff955bfe8003..b855b0854210c 100644 --- a/src/Compilers/Core/Portable/CommandLine/CommonCompiler.CompilerEmitStreamProvider.cs +++ b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.CompilerEmitStreamProvider.cs @@ -110,7 +110,7 @@ public void Close(DiagnosticBag diagnostics) private Stream OpenFileStream() { - return _streamToDispose = _compiler.FileOpen(_filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None); + return _streamToDispose = _compiler.FileSystem.OpenFile(_filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None); } private void ReportOpenFileDiagnostic(DiagnosticBag diagnostics, Exception e) diff --git a/src/Compilers/Core/Portable/CommandLine/CommonCompiler.CompilerRelativePathResolver.cs b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.CompilerRelativePathResolver.cs new file mode 100644 index 0000000000000..c8a093686851f --- /dev/null +++ b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.CompilerRelativePathResolver.cs @@ -0,0 +1,35 @@ +// 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.Diagnostics; +using System.IO; +using System.Linq; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis +{ + internal abstract partial class CommonCompiler + { + /// + /// Looks for metadata references among the assembly file references given to the compilation when constructed. + /// When scripts are included into a project we don't want #r's to reference other assemblies than those + /// specified explicitly in the project references. + /// + internal sealed class CompilerRelativePathResolver : RelativePathResolver + { + internal ICommonCompilerFileSystem FileSystem { get; } + + internal CompilerRelativePathResolver(ICommonCompilerFileSystem fileSystem, ImmutableArray searchPaths, string? baseDirectory) + : base(searchPaths, baseDirectory) + { + FileSystem = fileSystem; + } + + protected override bool FileExists(string fullPath) => FileSystem.FileExists(fullPath); + } + } +} diff --git a/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs index b71fde50eb41b..960a07d8e35af 100644 --- a/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs +++ b/src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs @@ -80,6 +80,11 @@ internal abstract partial class CommonCompiler /// public IReadOnlySet EmbeddedSourcePaths { get; } + /// + /// The used to access the file system inside this instance. + /// + internal ICommonCompilerFileSystem FileSystem { get; set; } = StandardFileSystem.Instance; + private readonly HashSet _reportedDiagnostics = new HashSet(); public abstract Compilation? CreateCompilation( @@ -200,12 +205,16 @@ internal string GetCultureName() internal virtual Func GetMetadataProvider() { - return (path, properties) => MetadataReference.CreateFromFile(path, properties); + return (path, properties) => + { + var peStream = FileSystem.OpenFileWithNormalizedException(path, FileMode.Open, FileAccess.Read, FileShare.Read); + return MetadataReference.CreateFromFile(peStream, path, properties); + }; } internal virtual MetadataReferenceResolver GetCommandLineMetadataReferenceResolver(TouchedFileLogger? loggerOpt) { - var pathResolver = new RelativePathResolver(Arguments.ReferencePaths, Arguments.BaseDirectory); + var pathResolver = new CompilerRelativePathResolver(FileSystem, Arguments.ReferencePaths, Arguments.BaseDirectory!); return new LoggingMetadataFileReferenceResolver(pathResolver, GetMetadataProvider(), loggerOpt); } @@ -266,8 +275,7 @@ internal List ResolveMetadataReferences( } else { - using var data = OpenFileForReadWithSmallBufferOptimization(filePath); - normalizedFilePath = data.Name; + using var data = OpenFileForReadWithSmallBufferOptimization(filePath, out normalizedFilePath); return EncodedStringText.Create(data, _fallbackEncoding, Arguments.Encoding, Arguments.ChecksumAlgorithm, canBeEmbedded: EmbeddedSourcePaths.Contains(file.Path)); } } @@ -358,8 +366,7 @@ internal bool TryGetAnalyzerConfigSet( { try { - var data = OpenFileForReadWithSmallBufferOptimization(filePath); - normalizedPath = data.Name; + var data = OpenFileForReadWithSmallBufferOptimization(filePath, out normalizedPath); using (var reader = new StreamReader(data, Encoding.UTF8)) { return reader.ReadToEnd(); @@ -373,25 +380,24 @@ internal bool TryGetAnalyzerConfigSet( } } - private static FileStream OpenFileForReadWithSmallBufferOptimization(string filePath) - { + private Stream OpenFileForReadWithSmallBufferOptimization(string filePath, out string normalizedFilePath) // PERF: Using a very small buffer size for the FileStream opens up an optimization within EncodedStringText/EmbeddedText where // we read the entire FileStream into a byte array in one shot. For files that are actually smaller than the buffer // size, FileStream.Read still allocates the internal buffer. - return new FileStream( + => FileSystem.OpenFileEx( filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize: 1, - options: FileOptions.None); - } + options: FileOptions.None, + out normalizedFilePath); internal EmbeddedText? TryReadEmbeddedFileContent(string filePath, DiagnosticBag diagnostics) { try { - using (var stream = OpenFileForReadWithSmallBufferOptimization(filePath)) + using (var stream = OpenFileForReadWithSmallBufferOptimization(filePath, out _)) { const int LargeObjectHeapLimit = 80 * 1024; if (stream.Length < LargeObjectHeapLimit) @@ -1187,7 +1193,7 @@ private void CompileAndEmit( using (xmlStreamDisposerOpt) { - using (var win32ResourceStreamOpt = GetWin32Resources(MessageProvider, Arguments, compilation, diagnostics)) + using (var win32ResourceStreamOpt = GetWin32Resources(FileSystem, MessageProvider, Arguments, compilation, diagnostics)) { if (HasUnsuppressableErrors(diagnostics)) { @@ -1464,17 +1470,6 @@ private static void ReportAnalyzerExecutionTime(TextWriter consoleOutput, Analyz /// protected abstract string GetOutputFileName(Compilation compilation, CancellationToken cancellationToken); - /// - /// Test hook for intercepting File.Open. - /// - internal Func FileOpen - { - get { return _fileOpen ?? ((path, mode, access, share) => new FileStream(path, mode, access, share)); } - set { _fileOpen = value; } - } - - private Func? _fileOpen; - private Stream? OpenFile( string filePath, DiagnosticBag diagnostics, @@ -1484,7 +1479,7 @@ internal Func FileOpen { try { - return FileOpen(filePath, mode, access, share); + return FileSystem.OpenFile(filePath, mode, access, share); } catch (Exception e) { @@ -1495,18 +1490,20 @@ internal Func FileOpen // internal for testing internal static Stream? GetWin32ResourcesInternal( + ICommonCompilerFileSystem fileSystem, CommonMessageProvider messageProvider, CommandLineArguments arguments, Compilation compilation, out IEnumerable errors) { var diagnostics = DiagnosticBag.GetInstance(); - var stream = GetWin32Resources(messageProvider, arguments, compilation, diagnostics); + var stream = GetWin32Resources(fileSystem, messageProvider, arguments, compilation, diagnostics); errors = diagnostics.ToReadOnlyAndFree().SelectAsArray(diag => new DiagnosticInfo(messageProvider, diag.IsWarningAsError, diag.Code, (object[])diag.Arguments)); return stream; } private static Stream? GetWin32Resources( + ICommonCompilerFileSystem fileSystem, CommonMessageProvider messageProvider, CommandLineArguments arguments, Compilation compilation, @@ -1514,12 +1511,12 @@ internal Func FileOpen { if (arguments.Win32ResourceFile != null) { - return OpenStream(messageProvider, arguments.Win32ResourceFile, arguments.BaseDirectory, messageProvider.ERR_CantOpenWin32Resource, diagnostics); + return OpenStream(fileSystem, messageProvider, arguments.Win32ResourceFile, arguments.BaseDirectory, messageProvider.ERR_CantOpenWin32Resource, diagnostics); } - using (Stream? manifestStream = OpenManifestStream(messageProvider, compilation.Options.OutputKind, arguments, diagnostics)) + using (Stream? manifestStream = OpenManifestStream(fileSystem, messageProvider, compilation.Options.OutputKind, arguments, diagnostics)) { - using (Stream? iconStream = OpenStream(messageProvider, arguments.Win32Icon, arguments.BaseDirectory, messageProvider.ERR_CantOpenWin32Icon, diagnostics)) + using (Stream? iconStream = OpenStream(fileSystem, messageProvider, arguments.Win32Icon, arguments.BaseDirectory, messageProvider.ERR_CantOpenWin32Icon, diagnostics)) { try { @@ -1535,14 +1532,14 @@ internal Func FileOpen return null; } - private static Stream? OpenManifestStream(CommonMessageProvider messageProvider, OutputKind outputKind, CommandLineArguments arguments, DiagnosticBag diagnostics) + private static Stream? OpenManifestStream(ICommonCompilerFileSystem fileSystem, CommonMessageProvider messageProvider, OutputKind outputKind, CommandLineArguments arguments, DiagnosticBag diagnostics) { return outputKind.IsNetModule() ? null - : OpenStream(messageProvider, arguments.Win32Manifest, arguments.BaseDirectory, messageProvider.ERR_CantOpenWin32Manifest, diagnostics); + : OpenStream(fileSystem, messageProvider, arguments.Win32Manifest, arguments.BaseDirectory, messageProvider.ERR_CantOpenWin32Manifest, diagnostics); } - private static Stream? OpenStream(CommonMessageProvider messageProvider, string? path, string? baseDirectory, int errorCode, DiagnosticBag diagnostics) + private static Stream? OpenStream(ICommonCompilerFileSystem fileSystem, CommonMessageProvider messageProvider, string? path, string? baseDirectory, int errorCode, DiagnosticBag diagnostics) { if (path == null) { @@ -1557,7 +1554,7 @@ internal Func FileOpen try { - return new FileStream(fullPath, FileMode.Open, FileAccess.Read); + return fileSystem.OpenFile(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read); } catch (Exception ex) { diff --git a/src/Compilers/Core/Portable/Compilation/ControlFlowAnalysis.cs b/src/Compilers/Core/Portable/Compilation/ControlFlowAnalysis.cs index 00d2657557572..af90e0885af16 100644 --- a/src/Compilers/Core/Portable/Compilation/ControlFlowAnalysis.cs +++ b/src/Compilers/Core/Portable/Compilation/ControlFlowAnalysis.cs @@ -38,7 +38,7 @@ public abstract class ControlFlowAnalysis public abstract ImmutableArray ReturnStatements { get; } /// - /// Returns true iff analysis was successful. Analysis can fail if the region does not properly span a single expression, + /// Returns true if and only if analysis was successful. Analysis can fail if the region does not properly span a single expression, /// a single statement, or a contiguous series of statements within the enclosing block. /// public abstract bool Succeeded { get; } diff --git a/src/Compilers/Core/Portable/Compilation/DataFlowAnalysis.cs b/src/Compilers/Core/Portable/Compilation/DataFlowAnalysis.cs index b9ec8795d52c6..3e834d0aa6ac0 100644 --- a/src/Compilers/Core/Portable/Compilation/DataFlowAnalysis.cs +++ b/src/Compilers/Core/Portable/Compilation/DataFlowAnalysis.cs @@ -104,7 +104,7 @@ public abstract class DataFlowAnalysis public abstract ImmutableArray UsedLocalFunctions { get; } /// - /// Returns true iff analysis was successful. Analysis can fail if the region does not + /// Returns true if and only if analysis was successful. Analysis can fail if the region does not /// properly span a single expression, a single statement, or a contiguous series of /// statements within the enclosing block. /// diff --git a/src/Compilers/Core/Portable/Compilation/OptimizationLevel.cs b/src/Compilers/Core/Portable/Compilation/OptimizationLevel.cs index 7e1948a13b88c..ac457e8fa9d22 100644 --- a/src/Compilers/Core/Portable/Compilation/OptimizationLevel.cs +++ b/src/Compilers/Core/Portable/Compilation/OptimizationLevel.cs @@ -48,42 +48,46 @@ public enum OptimizationLevel internal static class OptimizationLevelFacts { + internal static (OptimizationLevel OptimizationLevel, bool DebugPlus) DefaultValues => (OptimizationLevel.Debug, false); + public static string ToPdbSerializedString(this OptimizationLevel optimization, bool debugPlusMode) - => optimization switch - { - OptimizationLevel.Release => "release", - OptimizationLevel.Debug => debugPlusMode ? "debug-plus" : "debug", - _ => throw ExceptionUtilities.UnexpectedValue(optimization) - }; + => (optimization, debugPlusMode) switch + { + (OptimizationLevel.Release, true) => "release-debug-plus", + (OptimizationLevel.Release, false) => "release", + (OptimizationLevel.Debug, true) => "debug-plus", + (OptimizationLevel.Debug, false) => "debug", + _ => throw ExceptionUtilities.UnexpectedValue(optimization) + }; public static bool TryParsePdbSerializedString(string value, out OptimizationLevel optimizationLevel, out bool debugPlusMode) { - if (value == "release") - { - optimizationLevel = OptimizationLevel.Release; - debugPlusMode = false; - return true; - } - else if (value == "debug") + switch (value) { - optimizationLevel = OptimizationLevel.Debug; - debugPlusMode = false; - return true; + case "release-debug-plus": + optimizationLevel = OptimizationLevel.Release; + debugPlusMode = true; + return true; + case "release": + optimizationLevel = OptimizationLevel.Release; + debugPlusMode = false; + return true; + case "debug-plus": + optimizationLevel = OptimizationLevel.Debug; + debugPlusMode = true; + return true; + case "debug": + optimizationLevel = OptimizationLevel.Debug; + debugPlusMode = false; + return true; + default: + optimizationLevel = OptimizationLevel.Debug; + debugPlusMode = false; + return false; } - else if (value == "debug-plus") - { - optimizationLevel = OptimizationLevel.Debug; - debugPlusMode = true; - return true; - } - - optimizationLevel = default; - debugPlusMode = default; - return false; } } - internal static partial class EnumBounds { internal static bool IsValid(this OptimizationLevel value) diff --git a/src/Compilers/Core/Portable/Compilation/SemanticModel.cs b/src/Compilers/Core/Portable/Compilation/SemanticModel.cs index d7c7447a81c1b..d147e4dda26ff 100644 --- a/src/Compilers/Core/Portable/Compilation/SemanticModel.cs +++ b/src/Compilers/Core/Portable/Compilation/SemanticModel.cs @@ -78,7 +78,7 @@ public SyntaxTree SyntaxTree { return GetOperationCore(node, cancellationToken); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { // Log a Non-fatal-watson and then ignore the crash in the attempt of getting operation Debug.Assert(false, "\n" + e.ToString()); diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs index ffc3c5095af0b..d5fac8ff065d1 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs @@ -122,7 +122,7 @@ public async Task OnCompilationEventsGeneratedAsync( OnCompilationEventsGenerated_NoLock(getCompilationEvents(eventQueue, additionalFiles)); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs index c6a37673b4bf0..cb29f833221ae 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs @@ -1408,7 +1408,7 @@ private async Task ProcessCompilationEventsAsync(AnalysisScope analysisScope, An await ProcessEventAsync(completedEvent, analysisScope, analysisState, cancellationToken).ConfigureAwait(false); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -1467,7 +1467,7 @@ private async Task ProcessCompilationEventsAsync(AnalysisScope analysisScope, An return completedEvent; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -2687,7 +2687,7 @@ ImmutableArray getOperationsToAnalyzeWithStackGuard(ImmutableArray> GetAnalyzerTypeNameMap() + internal ImmutableSortedDictionary> GetAnalyzerTypeNameMap() { return _diagnosticAnalyzers.GetExtensionTypeNameMap(); } @@ -222,7 +222,7 @@ internal ImmutableDictionary> GetAnalyzerTypeNa /// The PE image format is invalid. /// IO error reading the metadata. [PerformanceSensitive("https://github.com/dotnet/roslyn/issues/30449")] - private static ImmutableDictionary> GetAnalyzerTypeNameMap(string fullPath, Type attributeType, AttributeLanguagesFunc languagesFunc) + private static ImmutableSortedDictionary> GetAnalyzerTypeNameMap(string fullPath, Type attributeType, AttributeLanguagesFunc languagesFunc) { using var assembly = AssemblyMetadata.CreateFromFile(fullPath); @@ -238,7 +238,7 @@ where supportedLanguages.Any() from supportedLanguage in supportedLanguages group typeName by supportedLanguage; - return typeNameMap.ToImmutableDictionary(g => g.Key, g => g.ToImmutableHashSet()); + return typeNameMap.ToImmutableSortedDictionary(g => g.Key, g => g.ToImmutableSortedSet(StringComparer.OrdinalIgnoreCase), StringComparer.OrdinalIgnoreCase); } private static IEnumerable GetSupportedLanguages(TypeDefinition typeDef, PEModule peModule, Type attributeType, AttributeLanguagesFunc languagesFunc) @@ -347,7 +347,7 @@ private sealed class Extensions private readonly bool _allowNetFramework; private ImmutableArray _lazyAllExtensions; private ImmutableDictionary> _lazyExtensionsPerLanguage; - private ImmutableDictionary>? _lazyExtensionTypeNameMap; + private ImmutableSortedDictionary>? _lazyExtensionTypeNameMap; internal Extensions(AnalyzerFileReference reference, Type attributeType, AttributeLanguagesFunc languagesFunc, bool allowNetFramework) { @@ -372,7 +372,7 @@ internal ImmutableArray GetExtensionsForAllLanguages(bool includeDup private static ImmutableArray CreateExtensionsForAllLanguages(Extensions extensions, bool includeDuplicates) { // Get all analyzers in the assembly. - var map = ImmutableDictionary.CreateBuilder>(); + var map = ImmutableSortedDictionary.CreateBuilder>(StringComparer.OrdinalIgnoreCase); extensions.AddExtensions(map); var builder = ImmutableArray.CreateBuilder(); @@ -421,7 +421,7 @@ private static ImmutableArray CreateLanguageSpecificExtensions(strin return builder.ToImmutable(); } - internal ImmutableDictionary> GetExtensionTypeNameMap() + internal ImmutableSortedDictionary> GetExtensionTypeNameMap() { if (_lazyExtensionTypeNameMap == null) { @@ -432,9 +432,9 @@ internal ImmutableDictionary> GetExtensionTypeN return _lazyExtensionTypeNameMap; } - internal void AddExtensions(ImmutableDictionary>.Builder builder) + internal void AddExtensions(ImmutableSortedDictionary>.Builder builder) { - ImmutableDictionary> analyzerTypeNameMap; + ImmutableSortedDictionary> analyzerTypeNameMap; Assembly analyzerAssembly; try @@ -478,7 +478,7 @@ internal void AddExtensions(ImmutableDictionary.Builder builder, string language) { - ImmutableDictionary> analyzerTypeNameMap; + ImmutableSortedDictionary> analyzerTypeNameMap; Assembly analyzerAssembly; try @@ -519,9 +519,9 @@ internal void AddExtensions(ImmutableArray.Builder builder, string l } } - private ImmutableArray GetLanguageSpecificAnalyzers(Assembly analyzerAssembly, ImmutableDictionary> analyzerTypeNameMap, string language, ref bool reportedError) + private ImmutableArray GetLanguageSpecificAnalyzers(Assembly analyzerAssembly, ImmutableSortedDictionary> analyzerTypeNameMap, string language, ref bool reportedError) { - ImmutableHashSet? languageSpecificAnalyzerTypeNames; + ImmutableSortedSet? languageSpecificAnalyzerTypeNames; if (!analyzerTypeNameMap.TryGetValue(language, out languageSpecificAnalyzerTypeNames)) { return ImmutableArray.Empty; diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs index 3d5ce4257d1fa..ddfb456e8690a 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs @@ -593,7 +593,7 @@ private async Task ComputeAnalyzerSyntaxDiagnosticsAsync(AnalysisScope analysisS await ComputeAnalyzerDiagnosticsAsync(pendingAnalysisScope, getPendingEventsOpt: null, taskToken, cancellationToken).ConfigureAwait(false); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -868,7 +868,7 @@ await Task.WhenAll(partialTrees.Select(tree => FreeDriver(driver); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -961,7 +961,7 @@ private async Task GetAnalyzerDriverAsync(CancellationToken canc } } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -1008,7 +1008,7 @@ private async Task ComputeAnalyzerDiagnosticsCoreAsync(AnalyzerDriver driver, As } } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -1138,7 +1138,7 @@ private async Task SetActiveTreeAnalysisTaskAsync(Func GetAnalyzerTelemetryInfoAsync(Diagnosti var executionTime = GetAnalyzerExecutionTime(analyzer); return new AnalyzerTelemetryInfo(actionCounts, suppressionActionCounts, executionTime); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs b/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs index e6b4c219f31df..3bf027cb0843d 100644 --- a/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs +++ b/src/Compilers/Core/Portable/FileSystem/FileUtilities.cs @@ -398,29 +398,5 @@ internal static long GetFileLength(string fullPath) throw new IOException(e.Message, e); } } - - internal static Stream OpenFileStream(string path) - { - try - { - return File.OpenRead(path); - } - catch (ArgumentException) - { - throw; - } - catch (DirectoryNotFoundException e) - { - throw new FileNotFoundException(e.Message, path, e); - } - catch (IOException) - { - throw; - } - catch (Exception e) - { - throw new IOException(e.Message, e); - } - } } } diff --git a/src/Compilers/Core/Portable/FileSystem/ICommonCompilerFileSystem.cs b/src/Compilers/Core/Portable/FileSystem/ICommonCompilerFileSystem.cs new file mode 100644 index 0000000000000..cfa7021d448cb --- /dev/null +++ b/src/Compilers/Core/Portable/FileSystem/ICommonCompilerFileSystem.cs @@ -0,0 +1,73 @@ +// 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.Diagnostics; +using System.IO; + +namespace Roslyn.Utilities +{ + /// + /// Abstraction over the file system that is useful for test hooks + /// + internal interface ICommonCompilerFileSystem + { + bool FileExists(string filePath); + + Stream OpenFile(string filePath, FileMode mode, FileAccess access, FileShare share); + + Stream OpenFileEx(string filePath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, out string normalizedFilePath); + } + + internal static class CommonCompilerFileSystemExtensions + { + /// + /// Open a file and ensure common exception types are wrapped to . + /// + internal static Stream OpenFileWithNormalizedException(this ICommonCompilerFileSystem fileSystem, string filePath, FileMode fileMode, FileAccess fileAccess, FileShare fileShare) + { + try + { + return fileSystem.OpenFile(filePath, fileMode, fileAccess, fileShare); + } + catch (ArgumentException) + { + throw; + } + catch (DirectoryNotFoundException e) + { + throw new FileNotFoundException(e.Message, filePath, e); + } + catch (IOException) + { + throw; + } + catch (Exception e) + { + throw new IOException(e.Message, e); + } + } + } + + internal sealed class StandardFileSystem : ICommonCompilerFileSystem + { + public static StandardFileSystem Instance { get; } = new StandardFileSystem(); + + private StandardFileSystem() + { + } + + public bool FileExists(string filePath) => File.Exists(filePath); + + public Stream OpenFile(string filePath, FileMode mode, FileAccess access, FileShare share) + => new FileStream(filePath, mode, access, share); + + public Stream OpenFileEx(string filePath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, out string normalizedFilePath) + { + var fileStream = new FileStream(filePath, mode, access, share, bufferSize, options); + normalizedFilePath = fileStream.Name; + return fileStream; + } + } +} diff --git a/src/Compilers/Core/Portable/InternalUtilities/ConcurrentLruCache.cs b/src/Compilers/Core/Portable/InternalUtilities/ConcurrentLruCache.cs index 579c982671bf0..15fe814d1144b 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/ConcurrentLruCache.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/ConcurrentLruCache.cs @@ -87,7 +87,7 @@ public void Add(K key, V value) private void MoveNodeToTop(LinkedListNode node) { - if (!object.ReferenceEquals(_nodeList.First, node)) + if (!ReferenceEquals(_nodeList.First, node)) { _nodeList.Remove(node); _nodeList.AddFirst(node); diff --git a/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs b/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs index 8f440bad5d980..bda79fdeed995 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs @@ -7,6 +7,11 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; +#if NET20 +// Some APIs referenced by documentation comments are not available on .NET Framework 2.0. +#pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved +#endif + #if COMPILERCORE namespace Microsoft.CodeAnalysis #else @@ -79,11 +84,10 @@ private static bool IsCurrentOperationBeingCancelled(Exception exception, Cancel => exception is OperationCanceledException && cancellationToken.IsCancellationRequested; /// - /// Use in an exception filter to report a fatal error. - /// Unless the exception is - /// it calls . The exception is passed through (the method returns false). + /// Use in an exception filter to report a fatal error (by calling ), unless the + /// operation has been cancelled. The exception is never caught. /// - /// False to avoid catching the exception. + /// to avoid catching the exception. [DebuggerHidden] public static bool ReportAndPropagateUnlessCanceled(Exception exception) { @@ -96,15 +100,27 @@ public static bool ReportAndPropagateUnlessCanceled(Exception exception) } /// - /// Use in an exception filter to report a fatal error. - /// Calls unless the operation has been cancelled. - /// The exception is passed through (the method returns false). + /// Use in an exception filter to report a fatal error (by calling ), unless the + /// operation has been cancelled at the request of . The exception is + /// never caught. + /// + /// Cancellable operations are only expected to throw if the + /// applicable indicates cancellation is requested by setting + /// . Unexpected cancellation, i.e. an + /// which occurs without + /// requesting cancellation, is treated as an error by this method. + /// + /// This method does not require to match + /// , provided cancellation is expected per the previous + /// paragraph. /// - /// False to avoid catching the exception. + /// A which will have + /// set if cancellation is expected. + /// to avoid catching the exception. [DebuggerHidden] - public static bool ReportAndPropagateUnlessCanceled(Exception exception, CancellationToken cancellationToken) + public static bool ReportAndPropagateUnlessCanceled(Exception exception, CancellationToken contextCancellationToken) { - if (IsCurrentOperationBeingCancelled(exception, cancellationToken)) + if (IsCurrentOperationBeingCancelled(exception, contextCancellationToken)) { return false; } @@ -113,11 +129,11 @@ public static bool ReportAndPropagateUnlessCanceled(Exception exception, Cancell } /// - /// Use in an exception filter to report a non-fatal error. - /// Unless the exception is - /// it calls . The exception isn't passed through (the method returns true). + /// Use in an exception filter to report a non-fatal error (by calling ) and catch + /// the exception, unless the operation was cancelled. /// - /// True to catch the exception. + /// to catch the exception if the non-fatal error was reported; otherwise, + /// to propagate the exception if the operation was cancelled. [DebuggerHidden] public static bool ReportAndCatchUnlessCanceled(Exception exception) { @@ -130,15 +146,28 @@ public static bool ReportAndCatchUnlessCanceled(Exception exception) } /// - /// Use in an exception filter to report a non-fatal error. - /// Calls unless the operation has been cancelled. - /// The exception isn't passed through (the method returns true). + /// Use in an exception filter to report a non-fatal error (by calling ) and + /// catch the exception, unless the operation was cancelled at the request of + /// . + /// + /// Cancellable operations are only expected to throw if the + /// applicable indicates cancellation is requested by setting + /// . Unexpected cancellation, i.e. an + /// which occurs without + /// requesting cancellation, is treated as an error by this method. + /// + /// This method does not require to match + /// , provided cancellation is expected per the previous + /// paragraph. /// - /// True to catch the exception. + /// A which will have + /// set if cancellation is expected. + /// to catch the exception if the non-fatal error was reported; otherwise, + /// to propagate the exception if the operation was cancelled. [DebuggerHidden] - public static bool ReportAndCatchUnlessCanceled(Exception exception, CancellationToken cancellationToken) + public static bool ReportAndCatchUnlessCanceled(Exception exception, CancellationToken contextCancellationToken) { - if (IsCurrentOperationBeingCancelled(exception, cancellationToken)) + if (IsCurrentOperationBeingCancelled(exception, contextCancellationToken)) { return false; } @@ -147,10 +176,10 @@ public static bool ReportAndCatchUnlessCanceled(Exception exception, Cancellatio } /// - /// Use in an exception filter to report a fatal error. - /// Calls and passes the exception through (the method returns false). + /// Use in an exception filter to report a fatal error without catching the exception. + /// The error is reported by calling . /// - /// False to avoid catching the exception. + /// to avoid catching the exception. [DebuggerHidden] public static bool ReportAndPropagate(Exception exception) { diff --git a/src/Compilers/Core/Portable/InternalUtilities/NoThrowStreamDisposer.cs b/src/Compilers/Core/Portable/InternalUtilities/NoThrowStreamDisposer.cs index faefc87654f3e..959db5f897c1e 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/NoThrowStreamDisposer.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/NoThrowStreamDisposer.cs @@ -27,7 +27,7 @@ internal class NoThrowStreamDisposer : IDisposable public Stream Stream { get; } /// - /// True iff an exception was thrown during a call to + /// True if and only if an exception was thrown during a call to /// public bool HasFailedToDispose { diff --git a/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs b/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs index 748468b7d3217..76d3d5226fc8a 100644 --- a/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs +++ b/src/Compilers/Core/Portable/MetadataReference/MetadataReference.cs @@ -228,9 +228,18 @@ public static PortableExecutableReference CreateFromFile( string path, MetadataReferenceProperties properties = default, DocumentationProvider? documentation = null) - { - var peStream = FileUtilities.OpenFileStream(path); + => CreateFromFile( + StandardFileSystem.Instance.OpenFileWithNormalizedException(path, FileMode.Open, FileAccess.Read, FileShare.Read), + path, + properties, + documentation); + internal static PortableExecutableReference CreateFromFile( + Stream peStream, + string path, + MetadataReferenceProperties properties = default, + DocumentationProvider? documentation = null) + { // prefetch image, close stream to avoid locking it: var module = ModuleMetadata.CreateFromStream(peStream, PEStreamOptions.PrefetchEntireImage); @@ -324,7 +333,7 @@ internal static PortableExecutableReference CreateFromAssemblyInternal( throw new NotSupportedException(CodeAnalysisResources.CantCreateReferenceToAssemblyWithoutLocation); } - Stream peStream = FileUtilities.OpenFileStream(location); + Stream peStream = StandardFileSystem.Instance.OpenFileWithNormalizedException(location, FileMode.Open, FileAccess.Read, FileShare.Read); // The file is locked by the CLR assembly loader, so we can create a lazily read metadata, // which might also lock the file until the reference is GC'd. diff --git a/src/Compilers/Core/Portable/MetadataReference/ModuleMetadata.cs b/src/Compilers/Core/Portable/MetadataReference/ModuleMetadata.cs index 166240066474b..90ecda00c8244 100644 --- a/src/Compilers/Core/Portable/MetadataReference/ModuleMetadata.cs +++ b/src/Compilers/Core/Portable/MetadataReference/ModuleMetadata.cs @@ -195,7 +195,7 @@ public static ModuleMetadata CreateFromStream(Stream peStream, PEStreamOptions o /// Reading from a file path is not supported by the platform. public static ModuleMetadata CreateFromFile(string path) { - return CreateFromStream(FileUtilities.OpenFileStream(path)); + return CreateFromStream(StandardFileSystem.Instance.OpenFileWithNormalizedException(path, FileMode.Open, FileAccess.Read, FileShare.Read)); } /// diff --git a/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj b/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj index 410dd75511424..89f574eceeac0 100644 --- a/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj +++ b/src/Compilers/Core/Portable/Microsoft.CodeAnalysis.csproj @@ -52,7 +52,7 @@ - + diff --git a/src/Compilers/Core/Portable/Operations/ControlFlowGraph.cs b/src/Compilers/Core/Portable/Operations/ControlFlowGraph.cs index 72290a4baabdb..7661a7f470fd8 100644 --- a/src/Compilers/Core/Portable/Operations/ControlFlowGraph.cs +++ b/src/Compilers/Core/Portable/Operations/ControlFlowGraph.cs @@ -183,7 +183,7 @@ internal static ControlFlowGraph CreateCore(IOperation operation, string argumen Debug.Assert(controlFlowGraph.OriginalOperation == operation); return controlFlowGraph; } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { // Log a Non-fatal-watson and then ignore the crash in the attempt of getting flow graph. Debug.Assert(false, "\n" + e.ToString()); diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs index 079ee33a28268..d405f7e0ff4be 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs @@ -883,7 +883,7 @@ private void EmbedCompilationOptions(BlobReader? pdbCompilationOptionsReader, Co var optimizationLevel = module.CommonCompilation.Options.OptimizationLevel; var debugPlusMode = module.CommonCompilation.Options.DebugPlusMode; - if (optimizationLevel != OptimizationLevel.Debug || debugPlusMode) + if ((optimizationLevel, debugPlusMode) != OptimizationLevelFacts.DefaultValues) { WriteValue(CompilationOptionNames.Optimization, optimizationLevel.ToPdbSerializedString(debugPlusMode)); } diff --git a/src/Compilers/Core/Rebuild/CSharpCompilationFactory.cs b/src/Compilers/Core/Rebuild/CSharpCompilationFactory.cs index 19e1d41ce38b8..df17c3dcf1b13 100644 --- a/src/Compilers/Core/Rebuild/CSharpCompilationFactory.cs +++ b/src/Compilers/Core/Rebuild/CSharpCompilationFactory.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Text; using CS = Microsoft.CodeAnalysis.CSharp; -namespace BuildValidator +namespace Microsoft.CodeAnalysis.Rebuild { public sealed class CSharpCompilationFactory : CompilationFactory { diff --git a/src/Compilers/Core/Rebuild/CompilationFactory.cs b/src/Compilers/Core/Rebuild/CompilationFactory.cs index c09e60a752abf..573d37f2a74f9 100644 --- a/src/Compilers/Core/Rebuild/CompilationFactory.cs +++ b/src/Compilers/Core/Rebuild/CompilationFactory.cs @@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Text; -namespace BuildValidator +namespace Microsoft.CodeAnalysis.Rebuild { public abstract class CompilationFactory { @@ -126,14 +126,20 @@ public unsafe EmitResult Emit( } } - protected static (OptimizationLevel, bool) GetOptimizationLevel(string? optimizationLevel) - => optimizationLevel switch + protected static (OptimizationLevel OptimizationLevel, bool DebugPlus) GetOptimizationLevel(string? value) + { + if (value is null) { - null or "debug" => (OptimizationLevel.Debug, false), - "debug-plus" => (OptimizationLevel.Debug, true), - "release" => (OptimizationLevel.Release, false), - _ => throw new InvalidDataException($"Optimization \"{optimizationLevel}\" level not recognized") - }; + return OptimizationLevelFacts.DefaultValues; + } + + if (!OptimizationLevelFacts.TryParsePdbSerializedString(value, out OptimizationLevel optimizationLevel, out bool debugPlus)) + { + throw new InvalidOperationException(); + } + + return (optimizationLevel, debugPlus); + } protected static Platform GetPlatform(string? platform) => platform is null diff --git a/src/Compilers/Core/Rebuild/CompilationOptionsReader.cs b/src/Compilers/Core/Rebuild/CompilationOptionsReader.cs index d07e4e06ebc79..1186105c49bbb 100644 --- a/src/Compilers/Core/Rebuild/CompilationOptionsReader.cs +++ b/src/Compilers/Core/Rebuild/CompilationOptionsReader.cs @@ -20,7 +20,7 @@ using Microsoft.Extensions.Logging; using Roslyn.Utilities; -namespace BuildValidator +namespace Microsoft.CodeAnalysis.Rebuild { public class CompilationOptionsReader { diff --git a/src/Compilers/Core/Rebuild/Extensions.cs b/src/Compilers/Core/Rebuild/Extensions.cs index 296ca185e880b..0bca8051fcc8f 100644 --- a/src/Compilers/Core/Rebuild/Extensions.cs +++ b/src/Compilers/Core/Rebuild/Extensions.cs @@ -8,7 +8,7 @@ using System.Reflection.Metadata; using System.Reflection.PortableExecutable; -namespace BuildValidator +namespace Microsoft.CodeAnalysis.Rebuild { public static class Extensions { diff --git a/src/Compilers/Core/Rebuild/MetadataCompilationOptions.cs b/src/Compilers/Core/Rebuild/MetadataCompilationOptions.cs index 3c3e9d5b4c8f0..f46b9f67c7900 100644 --- a/src/Compilers/Core/Rebuild/MetadataCompilationOptions.cs +++ b/src/Compilers/Core/Rebuild/MetadataCompilationOptions.cs @@ -8,7 +8,7 @@ using System; using Microsoft.Extensions.Logging; -namespace BuildValidator +namespace Microsoft.CodeAnalysis.Rebuild { internal class MetadataCompilationOptions { diff --git a/src/Compilers/Core/Rebuild/MetadataReferenceInfo.cs b/src/Compilers/Core/Rebuild/MetadataReferenceInfo.cs index 7693f69238046..f0a9b13b9739a 100644 --- a/src/Compilers/Core/Rebuild/MetadataReferenceInfo.cs +++ b/src/Compilers/Core/Rebuild/MetadataReferenceInfo.cs @@ -7,7 +7,7 @@ using System.IO; using Microsoft.CodeAnalysis; -namespace BuildValidator +namespace Microsoft.CodeAnalysis.Rebuild { public readonly struct MetadataReferenceInfo { diff --git a/src/Compilers/Core/Rebuild/Rebuild.csproj b/src/Compilers/Core/Rebuild/Microsoft.CodeAnalysis.Rebuild.csproj similarity index 94% rename from src/Compilers/Core/Rebuild/Rebuild.csproj rename to src/Compilers/Core/Rebuild/Microsoft.CodeAnalysis.Rebuild.csproj index b1b38256ba4ec..b56ea247ad62d 100644 --- a/src/Compilers/Core/Rebuild/Rebuild.csproj +++ b/src/Compilers/Core/Rebuild/Microsoft.CodeAnalysis.Rebuild.csproj @@ -4,6 +4,7 @@ Library + Microsoft.CodeAnalysis.Rebuild netcoreapp3.1;netstandard2.0 AnyCPU enable diff --git a/src/Compilers/Core/Rebuild/Records.cs b/src/Compilers/Core/Rebuild/Records.cs index 62a525c94a5d4..38fa2411ec403 100644 --- a/src/Compilers/Core/Rebuild/Records.cs +++ b/src/Compilers/Core/Rebuild/Records.cs @@ -7,6 +7,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; -namespace BuildValidator +namespace Microsoft.CodeAnalysis.Rebuild { } diff --git a/src/Compilers/Core/Rebuild/SourceFileInfo.cs b/src/Compilers/Core/Rebuild/SourceFileInfo.cs index 5f6cfbca06398..180f0c7a9d5f5 100644 --- a/src/Compilers/Core/Rebuild/SourceFileInfo.cs +++ b/src/Compilers/Core/Rebuild/SourceFileInfo.cs @@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis.Text; -namespace BuildValidator +namespace Microsoft.CodeAnalysis.Rebuild { public readonly struct SourceFileInfo { diff --git a/src/Compilers/Core/Rebuild/SourceLink.cs b/src/Compilers/Core/Rebuild/SourceLink.cs index 7c23433e65233..39764edbe5a7d 100644 --- a/src/Compilers/Core/Rebuild/SourceLink.cs +++ b/src/Compilers/Core/Rebuild/SourceLink.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Text; -namespace BuildValidator +namespace Microsoft.CodeAnalysis.Rebuild { /// An entry in the source-link.json dictionary. public readonly struct SourceLink diff --git a/src/Compilers/Core/Rebuild/VisualBasicCompilationFactory.cs b/src/Compilers/Core/Rebuild/VisualBasicCompilationFactory.cs index 10b7dfb606f88..8f467e7c4f4ef 100644 --- a/src/Compilers/Core/Rebuild/VisualBasicCompilationFactory.cs +++ b/src/Compilers/Core/Rebuild/VisualBasicCompilationFactory.cs @@ -15,7 +15,7 @@ using Roslyn.Utilities; using VB = Microsoft.CodeAnalysis.VisualBasic; -namespace BuildValidator +namespace Microsoft.CodeAnalysis.Rebuild { public sealed class VisualBasicCompilationFactory : CompilationFactory { diff --git a/src/Compilers/Core/RebuildTest/CSharpRebuildTests.cs b/src/Compilers/Core/RebuildTest/CSharpRebuildTests.cs index be91d5d5ae955..c2cd09dbd34a8 100644 --- a/src/Compilers/Core/RebuildTest/CSharpRebuildTests.cs +++ b/src/Compilers/Core/RebuildTest/CSharpRebuildTests.cs @@ -5,9 +5,9 @@ using System.Collections.Immutable; using System.Linq; using System.Reflection.PortableExecutable; -using BuildValidator; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Rebuild; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.Extensions.Logging; using Xunit; diff --git a/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj b/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj index 1642cfaf33538..532e1ed841b3d 100644 --- a/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj +++ b/src/Compilers/Core/RebuildTest/Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj @@ -7,6 +7,9 @@ true net5.0;net472 + + + @@ -14,7 +17,7 @@ - + diff --git a/src/Compilers/Core/RebuildTest/OptionRoundTripTests.cs b/src/Compilers/Core/RebuildTest/OptionRoundTripTests.cs index db3c332fd6501..ebdf23eb4e72f 100644 --- a/src/Compilers/Core/RebuildTest/OptionRoundTripTests.cs +++ b/src/Compilers/Core/RebuildTest/OptionRoundTripTests.cs @@ -10,12 +10,12 @@ using System.Reflection.PortableExecutable; using System.Text; using System.Threading; -using BuildValidator; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Rebuild; using Microsoft.CodeAnalysis.VisualBasic; using Microsoft.Extensions.Logging; using Xunit; @@ -32,104 +32,6 @@ public class OptionRoundTripTests : CSharpTestBase public static readonly object[][] Platforms = ((Platform[])Enum.GetValues(typeof(Platform))).Select(p => new[] { (object)p }).ToArray(); - private static void VerifyRoundTrip(TCompilation original) - where TCompilation : Compilation - { - Assert.True(original.SyntaxTrees.All(x => !string.IsNullOrEmpty(x.FilePath))); - Assert.True(original.Options.Deterministic); - - original.VerifyDiagnostics(); - var originalBytes = original.EmitToArray(new EmitOptions(debugInformationFormat: DebugInformationFormat.Embedded)); - var originalReader = new PEReader(originalBytes); - var originalPdbReader = originalReader.GetEmbeddedPdbMetadataReader(); - - var factory = LoggerFactory.Create(configure => { }); - var logger = factory.CreateLogger("RoundTripVerification"); - var optionsReader = new CompilationOptionsReader(logger, originalPdbReader, originalReader); - var assemblyFileName = original.AssemblyName!; - if (typeof(TCompilation) == typeof(CSharpCompilation)) - { - var assemblyFileExtension = original.Options.OutputKind switch - { - OutputKind.DynamicallyLinkedLibrary => ".dll", - OutputKind.ConsoleApplication => ".exe", - _ => throw new InvalidOperationException(), - }; - assemblyFileName += assemblyFileExtension; - } - - var compilationFactory = CompilationFactory.Create(assemblyFileName, optionsReader); - var rebuild = compilationFactory.CreateCompilation( - original.SyntaxTrees.Select(x => compilationFactory.CreateSyntaxTree(x.FilePath, x.GetText())).ToImmutableArray(), - original.References.ToImmutableArray()); - - Assert.IsType(rebuild); - VerifyCompilationOptions(original.Options, rebuild.Options); - - using var rebuildStream = new MemoryStream(); - var result = compilationFactory.Emit( - rebuildStream, - rebuild, - embeddedTexts: ImmutableArray.Empty, - CancellationToken.None); - Assert.Empty(result.Diagnostics); - Assert.True(result.Success); - Assert.Equal(originalBytes.ToArray(), rebuildStream.ToArray()); - } - -#pragma warning disable 612 - private static void VerifyCompilationOptions(CompilationOptions originalOptions, CompilationOptions rebuildOptions) - { - var type = originalOptions.GetType(); - foreach (var propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) - { - switch (propertyInfo.Name) - { - case nameof(CompilationOptions.GeneralDiagnosticOption): - case nameof(CompilationOptions.Features): - case nameof(CompilationOptions.ModuleName): - case nameof(CompilationOptions.MainTypeName): - case nameof(CompilationOptions.ConcurrentBuild): - case nameof(CompilationOptions.WarningLevel): - // Can be different and are special cased - break; - case nameof(VisualBasicCompilationOptions.ParseOptions): - { - var originalValue = propertyInfo.GetValue(originalOptions)!; - var rebuildValue = propertyInfo.GetValue(rebuildOptions)!; - VerifyParseOptions((ParseOptions)originalValue, (ParseOptions)rebuildValue); - } - break; - default: - { - var originalValue = propertyInfo.GetValue(originalOptions); - var rebuildValue = propertyInfo.GetValue(rebuildOptions); - Assert.Equal(originalValue, rebuildValue); - } - break; - } - } - } -#pragma warning restore 612 - - private static void VerifyParseOptions(ParseOptions originalOptions, ParseOptions rebuildOptions) - { - var type = originalOptions.GetType(); - foreach (var propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) - { - // Several options are expected to be different and they are special cased here. - if (propertyInfo.Name == nameof(VisualBasicParseOptions.SpecifiedLanguageVersion)) - { - continue; - } - - var originalValue = propertyInfo.GetValue(originalOptions); - var rebuildValue = propertyInfo.GetValue(rebuildOptions); - - Assert.Equal(originalValue, rebuildValue); - } - } - [Theory] [MemberData(nameof(Platforms))] public void Platform_RoundTrip(Platform platform) @@ -139,7 +41,7 @@ public void Platform_RoundTrip(Platform platform) options: BaseCSharpCompilationOptions.WithPlatform(platform), sourceFileName: "test.cs"); - VerifyRoundTrip(original); + RoundTripUtil.VerifyRoundTrip(original); } [Theory] @@ -157,7 +59,17 @@ End Sub assemblyName: "test", sourceFileName: "test.vb"); - VerifyRoundTrip(original); + RoundTripUtil.VerifyRoundTrip(original); + } + + [Theory] + [CombinatorialData] + public void OptimizationLevel_ParsePdbSerializedString(OptimizationLevel optimization, bool debugPlus) + { + var data = OptimizationLevelFacts.ToPdbSerializedString(optimization, debugPlus); + Assert.True(OptimizationLevelFacts.TryParsePdbSerializedString(data, out var optimization2, out var debugPlus2)); + Assert.Equal(optimization, optimization2); + Assert.Equal(debugPlus, debugPlus2); } } } diff --git a/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.CSharpRebuildCompiler.cs b/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.CSharpRebuildCompiler.cs new file mode 100644 index 0000000000000..6a5c96f9678be --- /dev/null +++ b/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.CSharpRebuildCompiler.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.CSharp; + +namespace Microsoft.CodeAnalysis.Rebuild.UnitTests +{ + public partial class RebuildCommandLineTests + { + private sealed class CSharpRebuildCompiler : CSharpCompiler + { + internal CSharpRebuildCompiler(string[] args) + : base(CSharpCommandLineParser.Default, responseFile: null, args, StandardBuildPaths, additionalReferenceDirectories: null, new DefaultAnalyzerAssemblyLoader()) + { + } + } + } +} diff --git a/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.VisualBasicRebuildCompiler.cs b/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.VisualBasicRebuildCompiler.cs new file mode 100644 index 0000000000000..8cf958b08aeb1 --- /dev/null +++ b/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.VisualBasicRebuildCompiler.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.VisualBasic; + +namespace Microsoft.CodeAnalysis.Rebuild.UnitTests +{ + public partial class RebuildCommandLineTests + { + private sealed class VisualBasicRebuildCompiler : VisualBasicCompiler + { + internal VisualBasicRebuildCompiler(string[] args) + : base(VisualBasicCommandLineParser.Default, responseFile: null, args, StandardBuildPaths, additionalReferenceDirectories: null, new DefaultAnalyzerAssemblyLoader()) + { + } + } + } +} diff --git a/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.cs b/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.cs new file mode 100644 index 0000000000000..9f2c7cb7dce37 --- /dev/null +++ b/src/Compilers/Core/RebuildTest/RebuildCommandLineTests.cs @@ -0,0 +1,289 @@ +// 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.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.Rebuild.UnitTests +{ + public sealed partial class RebuildCommandLineTests : CSharpTestBase + { + private record CommandInfo(string CommandLine, string PeFileName, string? PdbFileName); + + internal static string RootDirectory => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @"q:\" : "/"; + internal static string ClientDirectory => Path.Combine(RootDirectory, "compiler"); + internal static string WorkingDirectory => Path.Combine(RootDirectory, "rebuild"); + internal static string SdkDirectory => Path.Combine(RootDirectory, "sdk"); + internal static string OutputDirectory => Path.Combine(RootDirectory, "output"); + + internal static BuildPaths StandardBuildPaths => new BuildPaths(ClientDirectory, WorkingDirectory, SdkDirectory, tempDir: null); + + public ITestOutputHelper TestOutputHelper { get; } + public Dictionary FilePathToStreamMap { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); + + public RebuildCommandLineTests(ITestOutputHelper testOutputHelper) + { + TestOutputHelper = testOutputHelper; + } + + private void AddSourceFile(string filePath, string content) + { + FilePathToStreamMap.Add(Path.Combine(WorkingDirectory, filePath), new TestableFile(content)); + } + + private void AddReference(string filePath, byte[] imageBytes) + { + FilePathToStreamMap.Add(Path.Combine(SdkDirectory, filePath), new TestableFile(imageBytes)); + } + + private void AddOutputFile(ref string? filePath) + { + if (filePath is object) + { + filePath = Path.Combine(OutputDirectory, filePath); + FilePathToStreamMap.Add(filePath, new TestableFile()); + } + } + + private void VerifyRoundTrip(CommonCompiler commonCompiler, string peFilePath, string? pdbFilePath = null, CancellationToken cancellationToken = default) + { + Assert.True(commonCompiler.Arguments.CompilationOptions.Deterministic); + using var writer = new StringWriter(); + commonCompiler.FileSystem = TestableFileSystem.CreateForMap(FilePathToStreamMap); + var result = commonCompiler.Run(writer, cancellationToken); + TestOutputHelper.WriteLine(writer.ToString()); + Assert.Equal(0, result); + + var peStream = FilePathToStreamMap[peFilePath].GetStream(); + var pdbStream = pdbFilePath is object ? FilePathToStreamMap[pdbFilePath].GetStream() : null; + + var compilation = commonCompiler.CreateCompilation( + writer, + touchedFilesLogger: null, + errorLoggerOpt: null, + analyzerConfigOptions: default, + globalConfigOptions: default); + AssertEx.NotNull(compilation); + RoundTripUtil.VerifyCompilationOptions(commonCompiler.Arguments.CompilationOptions, compilation.Options); + + RoundTripUtil.VerifyRoundTrip( + peStream, + pdbStream, + Path.GetFileName(peFilePath), + compilation.SyntaxTrees.ToImmutableArray(), + compilation.References.ToImmutableArray()); + } + + private void AddCSharpSourceFiles() + { + AddSourceFile("hw.cs", @" +using System; +Console.WriteLine(""Hello World""); +"); + + AddSourceFile("lib1.cs", @" +using System; + +class Library +{ + void Method() + { + var lib = new Library(); + Console.WriteLine(lib); + } +} +"); + } + + public static IEnumerable GetCSharpData() + { + var list = new List(); + + Add(Permutate(new CommandInfo("hw.cs /target:exe /debug:embedded", "test.exe", null))); + Add(Permutate(new CommandInfo("lib1.cs /target:library /debug:embedded", "test.dll", null))); + + return list; + + IEnumerable Permutate(CommandInfo commandInfo) + { + IEnumerable e = new[] { commandInfo }; + e = e.SelectMany(PermutateOptimizations); + return e; + } + + IEnumerable PermutateOptimizations(CommandInfo commandInfo) + { + // No options at all for optimization + yield return commandInfo; + yield return commandInfo with + { + CommandLine = commandInfo.CommandLine + " /debug+ /optimize+" + }; + yield return commandInfo with + { + CommandLine = commandInfo.CommandLine + " /debug+ /optimize-" + }; + yield return commandInfo with + { + CommandLine = commandInfo.CommandLine + " /optimize-" + }; + yield return commandInfo with + { + CommandLine = commandInfo.CommandLine + " /optimize+" + }; + } + + void Add(IEnumerable commandInfos) + { + foreach (var commandInfo in commandInfos) + { + list.Add(new object?[] { commandInfo.CommandLine, commandInfo.PeFileName, commandInfo.PdbFileName }); + } + } + } + + [Theory] + [MemberData(nameof(GetCSharpData))] + public void CSharp(string commandLine, string peFilePath, string? pdbFilePath) + { + TestOutputHelper.WriteLine($"Command Line: {commandLine}"); + AddCSharpSourceFiles(); + var args = new List(commandLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)); + args.Add("/nostdlib"); + args.Add("/deterministic"); + foreach (var referenceInfo in TestMetadata.ResourcesNetCoreApp.All) + { + AddReference(referenceInfo.FileName, referenceInfo.ImageBytes); + args.Add($"/r:{referenceInfo.FileName}"); + } + + AddOutputFile(ref peFilePath!); + args.Add($"/out:{peFilePath}"); + AddOutputFile(ref pdbFilePath); + if (pdbFilePath is object) + { + args.Add($"/pdb:{pdbFilePath}"); + } + + TestOutputHelper.WriteLine($"Final Line: {string.Join(" ", args)}"); + var compiler = new CSharpRebuildCompiler(args.ToArray()); + VerifyRoundTrip(compiler, peFilePath, pdbFilePath); + } + + private void AddVisualBasicSourceFiles() + { + AddSourceFile("hw.vb", @" +Imports System +Public Module M + Public Sub Main() + Console.WriteLine(CStr(True)) + End Sub +End Module +"); + } + + public static IEnumerable GetVisualBasicData() + { + var list = new List(); + + Add(Permutate(new CommandInfo("hw.vb /target:exe /debug:embedded", "test.exe", null))); + + return list; + + IEnumerable Permutate(CommandInfo commandInfo) + { + IEnumerable e = new[] { commandInfo }; + e = e.SelectMany(PermutateOptimizations); + e = e.SelectMany(PermutateRuntime); + return e; + } + + IEnumerable PermutateOptimizations(CommandInfo commandInfo) + { + // No options at all for optimization + yield return commandInfo; + yield return commandInfo with + { + CommandLine = commandInfo.CommandLine + " /debug+ /optimize+" + }; + yield return commandInfo with + { + CommandLine = commandInfo.CommandLine + " /debug+ /optimize-" + }; + yield return commandInfo with + { + CommandLine = commandInfo.CommandLine + " /optimize-" + }; + yield return commandInfo with + { + CommandLine = commandInfo.CommandLine + " /optimize+" + }; + } + + IEnumerable PermutateRuntime(CommandInfo commandInfo) + { + yield return commandInfo with + { + CommandLine = commandInfo.CommandLine + " /vbruntime*" + }; + + yield return commandInfo with + { + CommandLine = commandInfo.CommandLine + @" /d:_MYTYPE=""Empty"" /vbruntime:Microsoft.VisualBasic.dll" + }; + } + + void Add(IEnumerable commandInfos) + { + foreach (var commandInfo in commandInfos) + { + list.Add(new object?[] { commandInfo.CommandLine, commandInfo.PeFileName, commandInfo.PdbFileName }); + } + } + } + + [ConditionalTheory(typeof(IsEnglishLocal))] + [MemberData(nameof(GetVisualBasicData))] + public void VisualBasic(string commandLine, string peFilePath, string? pdbFilePath) + { + TestOutputHelper.WriteLine($"Command Line: {commandLine}"); + AddVisualBasicSourceFiles(); + var args = new List(commandLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)); + args.Add("/nostdlib"); + args.Add("/deterministic"); + foreach (var referenceInfo in TestMetadata.ResourcesNetCoreApp.All) + { + AddReference(referenceInfo.FileName, referenceInfo.ImageBytes); + + // The command line needs to make a decision about how to embed the VB runtime + if (referenceInfo.FileName != "Microsoft.VisualBasic.dll") + { + args.Add($"/r:{referenceInfo.FileName}"); + } + } + + AddOutputFile(ref peFilePath!); + args.Add($"/out:{peFilePath}"); + AddOutputFile(ref pdbFilePath); + if (pdbFilePath is object) + { + args.Add($"/pdb:{pdbFilePath}"); + } + + TestOutputHelper.WriteLine($"Final Line: {string.Join(" ", args)}"); + var compiler = new VisualBasicRebuildCompiler(args.ToArray()); + VerifyRoundTrip(compiler, peFilePath, pdbFilePath); + } + } +} diff --git a/src/Compilers/Core/RebuildTest/RoundTripUtil.cs b/src/Compilers/Core/RebuildTest/RoundTripUtil.cs new file mode 100644 index 0000000000000..73673559ea858 --- /dev/null +++ b/src/Compilers/Core/RebuildTest/RoundTripUtil.cs @@ -0,0 +1,159 @@ +// 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.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.PortableExecutable; +using System.Threading; +using Microsoft.CodeAnalysis.Rebuild; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.Extensions.Logging; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Rebuild.UnitTests +{ + internal static class RoundTripUtil + { + public static void VerifyRoundTrip( + MemoryStream peStream, + MemoryStream? pdbStream, + string assemblyFileName, + ImmutableArray syntaxTrees, + ImmutableArray metadataReferences, + CancellationToken cancellationToken = default) + { + // https://github.com/dotnet/roslyn/issues/51890 + // Will be null until we add support for non-embedded PDBs. When this assert fires + // the below logic needs to be updated to support non-embedded PDBs. Should be straight + // forward + Assert.Null(pdbStream); + var factory = LoggerFactory.Create(configure => { }); + var logger = factory.CreateLogger("RoundTripVerification"); + + using var peReader = new PEReader(peStream); + var optionsReader = new CompilationOptionsReader(logger, peReader.GetEmbeddedPdbMetadataReader(), peReader); + var compilationFactory = CompilationFactory.Create( + assemblyFileName, + optionsReader); + using var rebuildPeStream = new MemoryStream(); + var emitResult = compilationFactory.Emit(rebuildPeStream, syntaxTrees, metadataReferences, cancellationToken); + Assert.True(emitResult.Success); + + Assert.True(peStream.ToArray().SequenceEqual(rebuildPeStream.ToArray())); + } + + public static void VerifyRoundTrip(TCompilation original) + where TCompilation : Compilation + { + Assert.True(original.SyntaxTrees.All(x => !string.IsNullOrEmpty(x.FilePath))); + Assert.True(original.Options.Deterministic); + + original.VerifyDiagnostics(); + var originalBytes = original.EmitToArray(new EmitOptions(debugInformationFormat: DebugInformationFormat.Embedded)); + var originalReader = new PEReader(originalBytes); + var originalPdbReader = originalReader.GetEmbeddedPdbMetadataReader(); + + var factory = LoggerFactory.Create(configure => { }); + var logger = factory.CreateLogger("RoundTripVerification"); + var optionsReader = new CompilationOptionsReader(logger, originalPdbReader, originalReader); + var assemblyFileName = original.AssemblyName!; + if (typeof(TCompilation) == typeof(CSharpCompilation)) + { + var assemblyFileExtension = original.Options.OutputKind switch + { + OutputKind.DynamicallyLinkedLibrary => ".dll", + OutputKind.ConsoleApplication => ".exe", + _ => throw new InvalidOperationException(), + }; + assemblyFileName += assemblyFileExtension; + } + + var compilationFactory = CompilationFactory.Create(assemblyFileName, optionsReader); + var rebuild = compilationFactory.CreateCompilation( + original.SyntaxTrees.SelectAsArray(x => compilationFactory.CreateSyntaxTree(x.FilePath, x.GetText())), + original.References.ToImmutableArray()); + + Assert.IsType(rebuild); + VerifyCompilationOptions(original.Options, rebuild.Options); + + using var rebuildStream = new MemoryStream(); + var result = compilationFactory.Emit( + rebuildStream, + rebuild, + embeddedTexts: ImmutableArray.Empty, + CancellationToken.None); + Assert.Empty(result.Diagnostics); + Assert.True(result.Success); + Assert.Equal(originalBytes.ToArray(), rebuildStream.ToArray()); + } + +#pragma warning disable 612 // 'CompilationOptions.Features' is obsolete + + public static void VerifyCompilationOptions(CompilationOptions originalOptions, CompilationOptions rebuildOptions) + { + var type = originalOptions.GetType(); + foreach (var propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) + { + switch (propertyInfo.Name) + { + case nameof(CompilationOptions.GeneralDiagnosticOption): + case nameof(CompilationOptions.Features): + case nameof(CompilationOptions.ModuleName): + case nameof(CompilationOptions.MainTypeName): + case nameof(CompilationOptions.ConcurrentBuild): + case nameof(CompilationOptions.WarningLevel): + case nameof(CompilationOptions.SyntaxTreeOptionsProvider): + case nameof(CompilationOptions.MetadataReferenceResolver): + case nameof(CompilationOptions.XmlReferenceResolver): + case nameof(CompilationOptions.SourceReferenceResolver): + case nameof(CompilationOptions.StrongNameProvider): + case nameof(CompilationOptions.AssemblyIdentityComparer): + // Can be different and are special cased + break; + case nameof(VisualBasicCompilationOptions.ParseOptions): + { + var originalValue = propertyInfo.GetValue(originalOptions)!; + var rebuildValue = propertyInfo.GetValue(rebuildOptions)!; + VerifyParseOptions((ParseOptions)originalValue, (ParseOptions)rebuildValue); + } + break; + default: + { + var originalValue = propertyInfo.GetValue(originalOptions); + var rebuildValue = propertyInfo.GetValue(rebuildOptions); + Assert.Equal(originalValue, rebuildValue); + } + break; + } + } + } +#pragma warning restore 612 + + private static void VerifyParseOptions(ParseOptions originalOptions, ParseOptions rebuildOptions) + { + var type = originalOptions.GetType(); + foreach (var propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) + { + // Several options are expected to be different and they are special cased here. + if (propertyInfo.Name == nameof(VisualBasicParseOptions.SpecifiedLanguageVersion)) + { + continue; + } + + var originalValue = propertyInfo.GetValue(originalOptions); + var rebuildValue = propertyInfo.GetValue(rebuildOptions); + + Assert.Equal(originalValue, rebuildValue); + } + } + } +} diff --git a/src/Compilers/Test/Core/Assert/AssertEx.cs b/src/Compilers/Test/Core/Assert/AssertEx.cs index aedcf9f43e783..833239de41661 100644 --- a/src/Compilers/Test/Core/Assert/AssertEx.cs +++ b/src/Compilers/Test/Core/Assert/AssertEx.cs @@ -732,25 +732,6 @@ IEnumerable GetLines(string str) => expectedValueSourceLine: expectedValueSourceLine); } - public static void Throws(Action action, Action checker = null) - where TException : Exception - { - try - { - action(); - } - catch (Exception e) - { - if (e is AggregateException agg && agg.InnerExceptions.Count == 1) - { - e = agg.InnerExceptions[0]; - } - - Assert.Equal(typeof(TException), e.GetType()); - checker?.Invoke((TException)e); - } - } - public static void Equal(bool[,] expected, Func getResult, int size) { Equal(expected, getResult, (b1, b2) => b1 == b2, b => b ? "true" : "false", "{0,-6:G}", size); diff --git a/src/Compilers/Test/Core/Compilation/MetadataReferenceExtensions.cs b/src/Compilers/Test/Core/Compilation/MetadataReferenceExtensions.cs new file mode 100644 index 0000000000000..cd6e72b7021ed --- /dev/null +++ b/src/Compilers/Test/Core/Compilation/MetadataReferenceExtensions.cs @@ -0,0 +1,48 @@ +// 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.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using Roslyn.Test.Utilities; + +namespace Microsoft.CodeAnalysis.Test.Utilities +{ + public static class MetadataReferenceExtensions + { + public static Guid GetModuleVersionId(this MetadataReference metadataReference) + => GetManifestModuleMetadata(metadataReference).GetModuleVersionId(); + + public static AssemblyIdentity GetAssemblyIdentity(this MetadataReference reference) + => reference.GetManifestModuleMetadata().MetadataReader.ReadAssemblyIdentityOrThrow(); + + public static ModuleMetadata GetManifestModuleMetadata(this MetadataReference reference) + => reference is PortableExecutableReference peReference + ? peReference.GetManifestModuleMetadata() + : throw new InvalidOperationException(); + + public static ModuleMetadata GetManifestModuleMetadata(this PortableExecutableReference peReference) + { + switch (peReference.GetMetadata()) + { + case AssemblyMetadata assemblyMetadata: + { + if (assemblyMetadata.GetModules() is { Length: 1 } modules) + { + return modules[0]; + } + } + break; + case ModuleMetadata moduleMetadata: + return moduleMetadata; + } + + throw new InvalidOperationException(); + } + } +} diff --git a/src/Compilers/Test/Core/Generate.ps1 b/src/Compilers/Test/Core/Generate.ps1 index 3373aed32601a..995b29410f780 100644 --- a/src/Compilers/Test/Core/Generate.ps1 +++ b/src/Compilers/Test/Core/Generate.ps1 @@ -11,6 +11,12 @@ function Add-TargetFramework($name, $packagePath, $list) public static class $name { +"@ + + $refAllContent = @" + public static ReferenceInfo[] All => new[] + { + "@ $name = $name.ToLower() @@ -31,6 +37,7 @@ function Add-TargetFramework($name, $packagePath, $list) $logicalName = "$($name).$($dll)"; } + $dllFileName = "$($dllName).dll" $link = "Resources\ReferenceAssemblies\$name\$dll" $script:targetsContent += @" @@ -46,16 +53,23 @@ function Add-TargetFramework($name, $packagePath, $list) private static byte[] $fieldName; public static byte[] $propName => ResourceLoader.GetOrCreateResource(ref $fieldName, "$logicalName"); +"@ + + $refAllContent += @" + new ReferenceInfo("$dllFileName", $propName), + "@ $refContent += @" - public static PortableExecutableReference $propName { get; } = AssemblyMetadata.CreateFromImage($($resourceTypeName).$($propName)).GetReference(display: "$dll ($name)"); + public static PortableExecutableReference $propName { get; } = AssemblyMetadata.CreateFromImage($($resourceTypeName).$($propName)).GetReference(display: "$dll ($name)", filePath: "$dllFileName"); "@ } + $script:codeContent += $refAllContent $script:codeContent += @" + }; } "@ @@ -88,6 +102,16 @@ namespace Roslyn.Test.Utilities { public static class TestMetadata { + public readonly struct ReferenceInfo + { + public string FileName { get; } + public byte[] ImageBytes { get; } + public ReferenceInfo(string fileName, byte[] imageBytes) + { + FileName = fileName; + ImageBytes = imageBytes; + } + } "@ @@ -157,7 +181,8 @@ Add-TargetFramework "NetCoreApp" '$(PkgMicrosoft_NETCore_App_Ref)\ref\net5.0' @( 'System.Threading.Tasks.dll', 'netstandard.dll', 'Microsoft.CSharp.dll', - 'Microsoft.VisualBasic.dll' + 'Microsoft.VisualBasic.dll', + 'Microsoft.VisualBasic.Core.dll' ) Add-TargetFramework "NetStandard20" '$(NuGetPackageRoot)\netstandard.library\2.0.3\build\netstandard2.0\ref' @( diff --git a/src/Compilers/Test/Core/Generated.cs b/src/Compilers/Test/Core/Generated.cs index 7cc3f66162a86..a178a668d51f2 100644 --- a/src/Compilers/Test/Core/Generated.cs +++ b/src/Compilers/Test/Core/Generated.cs @@ -12,6 +12,16 @@ namespace Roslyn.Test.Utilities { public static class TestMetadata { + public readonly struct ReferenceInfo + { + public string FileName { get; } + public byte[] ImageBytes { get; } + public ReferenceInfo(string fileName, byte[] imageBytes) + { + FileName = fileName; + ImageBytes = imageBytes; + } + } public static class ResourcesNet20 { private static byte[] _mscorlib; @@ -20,21 +30,31 @@ public static class ResourcesNet20 public static byte[] System => ResourceLoader.GetOrCreateResource(ref _System, "net20.System.dll"); private static byte[] _MicrosoftVisualBasic; public static byte[] MicrosoftVisualBasic => ResourceLoader.GetOrCreateResource(ref _MicrosoftVisualBasic, "net20.Microsoft.VisualBasic.dll"); + public static ReferenceInfo[] All => new[] + { + new ReferenceInfo("mscorlib.dll", mscorlib), + new ReferenceInfo("System.dll", System), + new ReferenceInfo("Microsoft.VisualBasic.dll", MicrosoftVisualBasic), + }; } public static class Net20 { - public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet20.mscorlib).GetReference(display: "mscorlib.dll (net20)"); - public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet20.System).GetReference(display: "System.dll (net20)"); - public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet20.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (net20)"); + public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet20.mscorlib).GetReference(display: "mscorlib.dll (net20)", filePath: "mscorlib.dll"); + public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet20.System).GetReference(display: "System.dll (net20)", filePath: "System.dll"); + public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet20.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (net20)", filePath: "Microsoft.VisualBasic.dll"); } public static class ResourcesNet35 { private static byte[] _SystemCore; public static byte[] SystemCore => ResourceLoader.GetOrCreateResource(ref _SystemCore, "net35.System.Core.dll"); + public static ReferenceInfo[] All => new[] + { + new ReferenceInfo("System.Core.dll", SystemCore), + }; } public static class Net35 { - public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet35.SystemCore).GetReference(display: "System.Core.dll (net35)"); + public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet35.SystemCore).GetReference(display: "System.Core.dll (net35)", filePath: "System.Core.dll"); } public static class ResourcesNet40 { @@ -54,17 +74,28 @@ public static class ResourcesNet40 public static byte[] MicrosoftVisualBasic => ResourceLoader.GetOrCreateResource(ref _MicrosoftVisualBasic, "net40.Microsoft.VisualBasic.dll"); private static byte[] _MicrosoftCSharp; public static byte[] MicrosoftCSharp => ResourceLoader.GetOrCreateResource(ref _MicrosoftCSharp, "net40.Microsoft.CSharp.dll"); + public static ReferenceInfo[] All => new[] + { + new ReferenceInfo("mscorlib.dll", mscorlib), + new ReferenceInfo("System.dll", System), + new ReferenceInfo("System.Core.dll", SystemCore), + new ReferenceInfo("System.Data.dll", SystemData), + new ReferenceInfo("System.Xml.dll", SystemXml), + new ReferenceInfo("System.Xml.Linq.dll", SystemXmlLinq), + new ReferenceInfo("Microsoft.VisualBasic.dll", MicrosoftVisualBasic), + new ReferenceInfo("Microsoft.CSharp.dll", MicrosoftCSharp), + }; } public static class Net40 { - public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.mscorlib).GetReference(display: "mscorlib.dll (net40)"); - public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.System).GetReference(display: "System.dll (net40)"); - public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemCore).GetReference(display: "System.Core.dll (net40)"); - public static PortableExecutableReference SystemData { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemData).GetReference(display: "System.Data.dll (net40)"); - public static PortableExecutableReference SystemXml { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemXml).GetReference(display: "System.Xml.dll (net40)"); - public static PortableExecutableReference SystemXmlLinq { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemXmlLinq).GetReference(display: "System.Xml.Linq.dll (net40)"); - public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (net40)"); - public static PortableExecutableReference MicrosoftCSharp { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.dll (net40)"); + public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.mscorlib).GetReference(display: "mscorlib.dll (net40)", filePath: "mscorlib.dll"); + public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.System).GetReference(display: "System.dll (net40)", filePath: "System.dll"); + public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemCore).GetReference(display: "System.Core.dll (net40)", filePath: "System.Core.dll"); + public static PortableExecutableReference SystemData { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemData).GetReference(display: "System.Data.dll (net40)", filePath: "System.Data.dll"); + public static PortableExecutableReference SystemXml { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemXml).GetReference(display: "System.Xml.dll (net40)", filePath: "System.Xml.dll"); + public static PortableExecutableReference SystemXmlLinq { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.SystemXmlLinq).GetReference(display: "System.Xml.Linq.dll (net40)", filePath: "System.Xml.Linq.dll"); + public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (net40)", filePath: "Microsoft.VisualBasic.dll"); + public static PortableExecutableReference MicrosoftCSharp { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet40.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.dll (net40)", filePath: "Microsoft.CSharp.dll"); } public static class ResourcesNet451 { @@ -106,28 +137,50 @@ public static class ResourcesNet451 public static byte[] SystemThreading => ResourceLoader.GetOrCreateResource(ref _SystemThreading, "net451.System.Threading.dll"); private static byte[] _SystemThreadingTasks; public static byte[] SystemThreadingTasks => ResourceLoader.GetOrCreateResource(ref _SystemThreadingTasks, "net451.System.Threading.Tasks.dll"); + public static ReferenceInfo[] All => new[] + { + new ReferenceInfo("mscorlib.dll", mscorlib), + new ReferenceInfo("System.dll", System), + new ReferenceInfo("System.Configuration.dll", SystemConfiguration), + new ReferenceInfo("System.Core.dll", SystemCore), + new ReferenceInfo("System.Data.dll", SystemData), + new ReferenceInfo("System.Drawing.dll", SystemDrawing), + new ReferenceInfo("System.EnterpriseServices.dll", SystemEnterpriseServices), + new ReferenceInfo("System.Runtime.Serialization.dll", SystemRuntimeSerialization), + new ReferenceInfo("System.Windows.Forms.dll", SystemWindowsForms), + new ReferenceInfo("System.Web.Services.dll", SystemWebServices), + new ReferenceInfo("System.Xml.dll", SystemXml), + new ReferenceInfo("System.Xml.Linq.dll", SystemXmlLinq), + new ReferenceInfo("Microsoft.CSharp.dll", MicrosoftCSharp), + new ReferenceInfo("Microsoft.VisualBasic.dll", MicrosoftVisualBasic), + new ReferenceInfo("System.ObjectModel.dll", SystemObjectModel), + new ReferenceInfo("System.Runtime.dll", SystemRuntime), + new ReferenceInfo("System.Runtime.InteropServices.WindowsRuntime.dll", SystemRuntimeInteropServicesWindowsRuntime), + new ReferenceInfo("System.Threading.dll", SystemThreading), + new ReferenceInfo("System.Threading.Tasks.dll", SystemThreadingTasks), + }; } public static class Net451 { - public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.mscorlib).GetReference(display: "mscorlib.dll (net451)"); - public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.System).GetReference(display: "System.dll (net451)"); - public static PortableExecutableReference SystemConfiguration { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemConfiguration).GetReference(display: "System.Configuration.dll (net451)"); - public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemCore).GetReference(display: "System.Core.dll (net451)"); - public static PortableExecutableReference SystemData { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemData).GetReference(display: "System.Data.dll (net451)"); - public static PortableExecutableReference SystemDrawing { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemDrawing).GetReference(display: "System.Drawing.dll (net451)"); - public static PortableExecutableReference SystemEnterpriseServices { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemEnterpriseServices).GetReference(display: "System.EnterpriseServices.dll (net451)"); - public static PortableExecutableReference SystemRuntimeSerialization { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntimeSerialization).GetReference(display: "System.Runtime.Serialization.dll (net451)"); - public static PortableExecutableReference SystemWindowsForms { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemWindowsForms).GetReference(display: "System.Windows.Forms.dll (net451)"); - public static PortableExecutableReference SystemWebServices { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemWebServices).GetReference(display: "System.Web.Services.dll (net451)"); - public static PortableExecutableReference SystemXml { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemXml).GetReference(display: "System.Xml.dll (net451)"); - public static PortableExecutableReference SystemXmlLinq { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemXmlLinq).GetReference(display: "System.Xml.Linq.dll (net451)"); - public static PortableExecutableReference MicrosoftCSharp { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.dll (net451)"); - public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (net451)"); - public static PortableExecutableReference SystemObjectModel { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemObjectModel).GetReference(display: "System.ObjectModel.dll (net451)"); - public static PortableExecutableReference SystemRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntime).GetReference(display: "System.Runtime.dll (net451)"); - public static PortableExecutableReference SystemRuntimeInteropServicesWindowsRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntimeInteropServicesWindowsRuntime).GetReference(display: "System.Runtime.InteropServices.WindowsRuntime.dll (net451)"); - public static PortableExecutableReference SystemThreading { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemThreading).GetReference(display: "System.Threading.dll (net451)"); - public static PortableExecutableReference SystemThreadingTasks { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemThreadingTasks).GetReference(display: "System.Threading.Tasks.dll (net451)"); + public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.mscorlib).GetReference(display: "mscorlib.dll (net451)", filePath: "mscorlib.dll"); + public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.System).GetReference(display: "System.dll (net451)", filePath: "System.dll"); + public static PortableExecutableReference SystemConfiguration { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemConfiguration).GetReference(display: "System.Configuration.dll (net451)", filePath: "System.Configuration.dll"); + public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemCore).GetReference(display: "System.Core.dll (net451)", filePath: "System.Core.dll"); + public static PortableExecutableReference SystemData { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemData).GetReference(display: "System.Data.dll (net451)", filePath: "System.Data.dll"); + public static PortableExecutableReference SystemDrawing { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemDrawing).GetReference(display: "System.Drawing.dll (net451)", filePath: "System.Drawing.dll"); + public static PortableExecutableReference SystemEnterpriseServices { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemEnterpriseServices).GetReference(display: "System.EnterpriseServices.dll (net451)", filePath: "System.EnterpriseServices.dll"); + public static PortableExecutableReference SystemRuntimeSerialization { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntimeSerialization).GetReference(display: "System.Runtime.Serialization.dll (net451)", filePath: "System.Runtime.Serialization.dll"); + public static PortableExecutableReference SystemWindowsForms { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemWindowsForms).GetReference(display: "System.Windows.Forms.dll (net451)", filePath: "System.Windows.Forms.dll"); + public static PortableExecutableReference SystemWebServices { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemWebServices).GetReference(display: "System.Web.Services.dll (net451)", filePath: "System.Web.Services.dll"); + public static PortableExecutableReference SystemXml { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemXml).GetReference(display: "System.Xml.dll (net451)", filePath: "System.Xml.dll"); + public static PortableExecutableReference SystemXmlLinq { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemXmlLinq).GetReference(display: "System.Xml.Linq.dll (net451)", filePath: "System.Xml.Linq.dll"); + public static PortableExecutableReference MicrosoftCSharp { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.dll (net451)", filePath: "Microsoft.CSharp.dll"); + public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (net451)", filePath: "Microsoft.VisualBasic.dll"); + public static PortableExecutableReference SystemObjectModel { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemObjectModel).GetReference(display: "System.ObjectModel.dll (net451)", filePath: "System.ObjectModel.dll"); + public static PortableExecutableReference SystemRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntime).GetReference(display: "System.Runtime.dll (net451)", filePath: "System.Runtime.dll"); + public static PortableExecutableReference SystemRuntimeInteropServicesWindowsRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemRuntimeInteropServicesWindowsRuntime).GetReference(display: "System.Runtime.InteropServices.WindowsRuntime.dll (net451)", filePath: "System.Runtime.InteropServices.WindowsRuntime.dll"); + public static PortableExecutableReference SystemThreading { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemThreading).GetReference(display: "System.Threading.dll (net451)", filePath: "System.Threading.dll"); + public static PortableExecutableReference SystemThreadingTasks { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet451.SystemThreadingTasks).GetReference(display: "System.Threading.Tasks.dll (net451)", filePath: "System.Threading.Tasks.dll"); } public static class ResourcesNet461 { @@ -145,16 +198,26 @@ public static class ResourcesNet461 public static byte[] MicrosoftCSharp => ResourceLoader.GetOrCreateResource(ref _MicrosoftCSharp, "net461.Microsoft.CSharp.dll"); private static byte[] _MicrosoftVisualBasic; public static byte[] MicrosoftVisualBasic => ResourceLoader.GetOrCreateResource(ref _MicrosoftVisualBasic, "net461.Microsoft.VisualBasic.dll"); + public static ReferenceInfo[] All => new[] + { + new ReferenceInfo("mscorlib.dll", mscorlib), + new ReferenceInfo("System.dll", System), + new ReferenceInfo("System.Core.dll", SystemCore), + new ReferenceInfo("System.Runtime.dll", SystemRuntime), + new ReferenceInfo("System.Threading.Tasks.dll", SystemThreadingTasks), + new ReferenceInfo("Microsoft.CSharp.dll", MicrosoftCSharp), + new ReferenceInfo("Microsoft.VisualBasic.dll", MicrosoftVisualBasic), + }; } public static class Net461 { - public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.mscorlib).GetReference(display: "mscorlib.dll (net461)"); - public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.System).GetReference(display: "System.dll (net461)"); - public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.SystemCore).GetReference(display: "System.Core.dll (net461)"); - public static PortableExecutableReference SystemRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.SystemRuntime).GetReference(display: "System.Runtime.dll (net461)"); - public static PortableExecutableReference SystemThreadingTasks { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.SystemThreadingTasks).GetReference(display: "System.Threading.Tasks.dll (net461)"); - public static PortableExecutableReference MicrosoftCSharp { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.dll (net461)"); - public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (net461)"); + public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.mscorlib).GetReference(display: "mscorlib.dll (net461)", filePath: "mscorlib.dll"); + public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.System).GetReference(display: "System.dll (net461)", filePath: "System.dll"); + public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.SystemCore).GetReference(display: "System.Core.dll (net461)", filePath: "System.Core.dll"); + public static PortableExecutableReference SystemRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.SystemRuntime).GetReference(display: "System.Runtime.dll (net461)", filePath: "System.Runtime.dll"); + public static PortableExecutableReference SystemThreadingTasks { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.SystemThreadingTasks).GetReference(display: "System.Threading.Tasks.dll (net461)", filePath: "System.Threading.Tasks.dll"); + public static PortableExecutableReference MicrosoftCSharp { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.dll (net461)", filePath: "Microsoft.CSharp.dll"); + public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNet461.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (net461)", filePath: "Microsoft.VisualBasic.dll"); } public static class ResourcesNetCoreApp { @@ -184,22 +247,42 @@ public static class ResourcesNetCoreApp public static byte[] MicrosoftCSharp => ResourceLoader.GetOrCreateResource(ref _MicrosoftCSharp, "netcoreapp.Microsoft.CSharp.dll"); private static byte[] _MicrosoftVisualBasic; public static byte[] MicrosoftVisualBasic => ResourceLoader.GetOrCreateResource(ref _MicrosoftVisualBasic, "netcoreapp.Microsoft.VisualBasic.dll"); + private static byte[] _MicrosoftVisualBasicCore; + public static byte[] MicrosoftVisualBasicCore => ResourceLoader.GetOrCreateResource(ref _MicrosoftVisualBasicCore, "netcoreapp.Microsoft.VisualBasic.Core.dll"); + public static ReferenceInfo[] All => new[] + { + new ReferenceInfo("mscorlib.dll", mscorlib), + new ReferenceInfo("System.dll", System), + new ReferenceInfo("System.Core.dll", SystemCore), + new ReferenceInfo("System.Collections.dll", SystemCollections), + new ReferenceInfo("System.Console.dll", SystemConsole), + new ReferenceInfo("System.Linq.dll", SystemLinq), + new ReferenceInfo("System.Linq.Expressions.dll", SystemLinqExpressions), + new ReferenceInfo("System.Runtime.dll", SystemRuntime), + new ReferenceInfo("System.Runtime.InteropServices.dll", SystemRuntimeInteropServices), + new ReferenceInfo("System.Threading.Tasks.dll", SystemThreadingTasks), + new ReferenceInfo("netstandard.dll", netstandard), + new ReferenceInfo("Microsoft.CSharp.dll", MicrosoftCSharp), + new ReferenceInfo("Microsoft.VisualBasic.dll", MicrosoftVisualBasic), + new ReferenceInfo("Microsoft.VisualBasic.Core.dll", MicrosoftVisualBasicCore), + }; } public static class NetCoreApp { - public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.mscorlib).GetReference(display: "mscorlib.dll (netcoreapp)"); - public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.System).GetReference(display: "System.dll (netcoreapp)"); - public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemCore).GetReference(display: "System.Core.dll (netcoreapp)"); - public static PortableExecutableReference SystemCollections { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemCollections).GetReference(display: "System.Collections.dll (netcoreapp)"); - public static PortableExecutableReference SystemConsole { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemConsole).GetReference(display: "System.Console.dll (netcoreapp)"); - public static PortableExecutableReference SystemLinq { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemLinq).GetReference(display: "System.Linq.dll (netcoreapp)"); - public static PortableExecutableReference SystemLinqExpressions { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemLinqExpressions).GetReference(display: "System.Linq.Expressions.dll (netcoreapp)"); - public static PortableExecutableReference SystemRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemRuntime).GetReference(display: "System.Runtime.dll (netcoreapp)"); - public static PortableExecutableReference SystemRuntimeInteropServices { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemRuntimeInteropServices).GetReference(display: "System.Runtime.InteropServices.dll (netcoreapp)"); - public static PortableExecutableReference SystemThreadingTasks { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemThreadingTasks).GetReference(display: "System.Threading.Tasks.dll (netcoreapp)"); - public static PortableExecutableReference netstandard { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.netstandard).GetReference(display: "netstandard.dll (netcoreapp)"); - public static PortableExecutableReference MicrosoftCSharp { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.dll (netcoreapp)"); - public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (netcoreapp)"); + public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.mscorlib).GetReference(display: "mscorlib.dll (netcoreapp)", filePath: "mscorlib.dll"); + public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.System).GetReference(display: "System.dll (netcoreapp)", filePath: "System.dll"); + public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemCore).GetReference(display: "System.Core.dll (netcoreapp)", filePath: "System.Core.dll"); + public static PortableExecutableReference SystemCollections { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemCollections).GetReference(display: "System.Collections.dll (netcoreapp)", filePath: "System.Collections.dll"); + public static PortableExecutableReference SystemConsole { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemConsole).GetReference(display: "System.Console.dll (netcoreapp)", filePath: "System.Console.dll"); + public static PortableExecutableReference SystemLinq { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemLinq).GetReference(display: "System.Linq.dll (netcoreapp)", filePath: "System.Linq.dll"); + public static PortableExecutableReference SystemLinqExpressions { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemLinqExpressions).GetReference(display: "System.Linq.Expressions.dll (netcoreapp)", filePath: "System.Linq.Expressions.dll"); + public static PortableExecutableReference SystemRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemRuntime).GetReference(display: "System.Runtime.dll (netcoreapp)", filePath: "System.Runtime.dll"); + public static PortableExecutableReference SystemRuntimeInteropServices { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemRuntimeInteropServices).GetReference(display: "System.Runtime.InteropServices.dll (netcoreapp)", filePath: "System.Runtime.InteropServices.dll"); + public static PortableExecutableReference SystemThreadingTasks { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.SystemThreadingTasks).GetReference(display: "System.Threading.Tasks.dll (netcoreapp)", filePath: "System.Threading.Tasks.dll"); + public static PortableExecutableReference netstandard { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.netstandard).GetReference(display: "netstandard.dll (netcoreapp)", filePath: "netstandard.dll"); + public static PortableExecutableReference MicrosoftCSharp { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.MicrosoftCSharp).GetReference(display: "Microsoft.CSharp.dll (netcoreapp)", filePath: "Microsoft.CSharp.dll"); + public static PortableExecutableReference MicrosoftVisualBasic { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.MicrosoftVisualBasic).GetReference(display: "Microsoft.VisualBasic.dll (netcoreapp)", filePath: "Microsoft.VisualBasic.dll"); + public static PortableExecutableReference MicrosoftVisualBasicCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetCoreApp.MicrosoftVisualBasicCore).GetReference(display: "Microsoft.VisualBasic.Core.dll (netcoreapp)", filePath: "Microsoft.VisualBasic.Core.dll"); } public static class ResourcesNetStandard20 { @@ -219,17 +302,28 @@ public static class ResourcesNetStandard20 public static byte[] SystemRuntime => ResourceLoader.GetOrCreateResource(ref _SystemRuntime, "netstandard20.System.Runtime.dll"); private static byte[] _netstandard; public static byte[] netstandard => ResourceLoader.GetOrCreateResource(ref _netstandard, "netstandard20.netstandard.dll"); + public static ReferenceInfo[] All => new[] + { + new ReferenceInfo("mscorlib.dll", mscorlib), + new ReferenceInfo("System.dll", System), + new ReferenceInfo("System.Core.dll", SystemCore), + new ReferenceInfo("System.Dynamic.Runtime.dll", SystemDynamicRuntime), + new ReferenceInfo("System.Linq.dll", SystemLinq), + new ReferenceInfo("System.Linq.Expressions.dll", SystemLinqExpressions), + new ReferenceInfo("System.Runtime.dll", SystemRuntime), + new ReferenceInfo("netstandard.dll", netstandard), + }; } public static class NetStandard20 { - public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.mscorlib).GetReference(display: "mscorlib.dll (netstandard20)"); - public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.System).GetReference(display: "System.dll (netstandard20)"); - public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.SystemCore).GetReference(display: "System.Core.dll (netstandard20)"); - public static PortableExecutableReference SystemDynamicRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.SystemDynamicRuntime).GetReference(display: "System.Dynamic.Runtime.dll (netstandard20)"); - public static PortableExecutableReference SystemLinq { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.SystemLinq).GetReference(display: "System.Linq.dll (netstandard20)"); - public static PortableExecutableReference SystemLinqExpressions { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.SystemLinqExpressions).GetReference(display: "System.Linq.Expressions.dll (netstandard20)"); - public static PortableExecutableReference SystemRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.SystemRuntime).GetReference(display: "System.Runtime.dll (netstandard20)"); - public static PortableExecutableReference netstandard { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.netstandard).GetReference(display: "netstandard.dll (netstandard20)"); + public static PortableExecutableReference mscorlib { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.mscorlib).GetReference(display: "mscorlib.dll (netstandard20)", filePath: "mscorlib.dll"); + public static PortableExecutableReference System { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.System).GetReference(display: "System.dll (netstandard20)", filePath: "System.dll"); + public static PortableExecutableReference SystemCore { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.SystemCore).GetReference(display: "System.Core.dll (netstandard20)", filePath: "System.Core.dll"); + public static PortableExecutableReference SystemDynamicRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.SystemDynamicRuntime).GetReference(display: "System.Dynamic.Runtime.dll (netstandard20)", filePath: "System.Dynamic.Runtime.dll"); + public static PortableExecutableReference SystemLinq { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.SystemLinq).GetReference(display: "System.Linq.dll (netstandard20)", filePath: "System.Linq.dll"); + public static PortableExecutableReference SystemLinqExpressions { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.SystemLinqExpressions).GetReference(display: "System.Linq.Expressions.dll (netstandard20)", filePath: "System.Linq.Expressions.dll"); + public static PortableExecutableReference SystemRuntime { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.SystemRuntime).GetReference(display: "System.Runtime.dll (netstandard20)", filePath: "System.Runtime.dll"); + public static PortableExecutableReference netstandard { get; } = AssemblyMetadata.CreateFromImage(ResourcesNetStandard20.netstandard).GetReference(display: "netstandard.dll (netstandard20)", filePath: "netstandard.dll"); } public static class ResourcesMicrosoftCSharp { @@ -237,20 +331,29 @@ public static class ResourcesMicrosoftCSharp public static byte[] Netstandard10 => ResourceLoader.GetOrCreateResource(ref _Netstandard10, "netstandard10.microsoftcsharp.Microsoft.CSharp.dll"); private static byte[] _Netstandard13Lib; public static byte[] Netstandard13Lib => ResourceLoader.GetOrCreateResource(ref _Netstandard13Lib, "netstandard13lib.microsoftcsharp.Microsoft.CSharp.dll"); + public static ReferenceInfo[] All => new[] + { + new ReferenceInfo("Netstandard10.dll", Netstandard10), + new ReferenceInfo("Netstandard13Lib.dll", Netstandard13Lib), + }; } public static class MicrosoftCSharp { - public static PortableExecutableReference Netstandard10 { get; } = AssemblyMetadata.CreateFromImage(ResourcesMicrosoftCSharp.Netstandard10).GetReference(display: "Microsoft.CSharp.dll (microsoftcsharp)"); - public static PortableExecutableReference Netstandard13Lib { get; } = AssemblyMetadata.CreateFromImage(ResourcesMicrosoftCSharp.Netstandard13Lib).GetReference(display: "Microsoft.CSharp.dll (microsoftcsharp)"); + public static PortableExecutableReference Netstandard10 { get; } = AssemblyMetadata.CreateFromImage(ResourcesMicrosoftCSharp.Netstandard10).GetReference(display: "Microsoft.CSharp.dll (microsoftcsharp)", filePath: "Netstandard10.dll"); + public static PortableExecutableReference Netstandard13Lib { get; } = AssemblyMetadata.CreateFromImage(ResourcesMicrosoftCSharp.Netstandard13Lib).GetReference(display: "Microsoft.CSharp.dll (microsoftcsharp)", filePath: "Netstandard13Lib.dll"); } public static class ResourcesMicrosoftVisualBasic { private static byte[] _Netstandard11; public static byte[] Netstandard11 => ResourceLoader.GetOrCreateResource(ref _Netstandard11, "netstandard11.microsoftvisualbasic.Microsoft.VisualBasic.dll"); + public static ReferenceInfo[] All => new[] + { + new ReferenceInfo("Netstandard11.dll", Netstandard11), + }; } public static class MicrosoftVisualBasic { - public static PortableExecutableReference Netstandard11 { get; } = AssemblyMetadata.CreateFromImage(ResourcesMicrosoftVisualBasic.Netstandard11).GetReference(display: "Microsoft.VisualBasic.dll (microsoftvisualbasic)"); + public static PortableExecutableReference Netstandard11 { get; } = AssemblyMetadata.CreateFromImage(ResourcesMicrosoftVisualBasic.Netstandard11).GetReference(display: "Microsoft.VisualBasic.dll (microsoftvisualbasic)", filePath: "Netstandard11.dll"); } public static class ResourcesSystemThreadingTasksExtensions { @@ -258,20 +361,29 @@ public static class ResourcesSystemThreadingTasksExtensions public static byte[] PortableLib => ResourceLoader.GetOrCreateResource(ref _PortableLib, "portablelib.systemthreadingtasksextensions.System.Threading.Tasks.Extensions.dll"); private static byte[] _NetStandard20Lib; public static byte[] NetStandard20Lib => ResourceLoader.GetOrCreateResource(ref _NetStandard20Lib, "netstandard20lib.systemthreadingtasksextensions.System.Threading.Tasks.Extensions.dll"); + public static ReferenceInfo[] All => new[] + { + new ReferenceInfo("PortableLib.dll", PortableLib), + new ReferenceInfo("NetStandard20Lib.dll", NetStandard20Lib), + }; } public static class SystemThreadingTasksExtensions { - public static PortableExecutableReference PortableLib { get; } = AssemblyMetadata.CreateFromImage(ResourcesSystemThreadingTasksExtensions.PortableLib).GetReference(display: "System.Threading.Tasks.Extensions.dll (systemthreadingtasksextensions)"); - public static PortableExecutableReference NetStandard20Lib { get; } = AssemblyMetadata.CreateFromImage(ResourcesSystemThreadingTasksExtensions.NetStandard20Lib).GetReference(display: "System.Threading.Tasks.Extensions.dll (systemthreadingtasksextensions)"); + public static PortableExecutableReference PortableLib { get; } = AssemblyMetadata.CreateFromImage(ResourcesSystemThreadingTasksExtensions.PortableLib).GetReference(display: "System.Threading.Tasks.Extensions.dll (systemthreadingtasksextensions)", filePath: "PortableLib.dll"); + public static PortableExecutableReference NetStandard20Lib { get; } = AssemblyMetadata.CreateFromImage(ResourcesSystemThreadingTasksExtensions.NetStandard20Lib).GetReference(display: "System.Threading.Tasks.Extensions.dll (systemthreadingtasksextensions)", filePath: "NetStandard20Lib.dll"); } public static class ResourcesBuildExtensions { private static byte[] _NetStandardToNet461; public static byte[] NetStandardToNet461 => ResourceLoader.GetOrCreateResource(ref _NetStandardToNet461, "netstandardtonet461.buildextensions.netstandard.dll"); + public static ReferenceInfo[] All => new[] + { + new ReferenceInfo("NetStandardToNet461.dll", NetStandardToNet461), + }; } public static class BuildExtensions { - public static PortableExecutableReference NetStandardToNet461 { get; } = AssemblyMetadata.CreateFromImage(ResourcesBuildExtensions.NetStandardToNet461).GetReference(display: "netstandard.dll (buildextensions)"); + public static PortableExecutableReference NetStandardToNet461 { get; } = AssemblyMetadata.CreateFromImage(ResourcesBuildExtensions.NetStandardToNet461).GetReference(display: "netstandard.dll (buildextensions)", filePath: "NetStandardToNet461.dll"); } } } diff --git a/src/Compilers/Test/Core/Generated.targets b/src/Compilers/Test/Core/Generated.targets index 4a8749b6331b5..fb3778bea78ab 100644 --- a/src/Compilers/Test/Core/Generated.targets +++ b/src/Compilers/Test/Core/Generated.targets @@ -204,6 +204,10 @@ netcoreapp.Microsoft.VisualBasic.dll Resources\ReferenceAssemblies\netcoreapp\Microsoft.VisualBasic.dll + + netcoreapp.Microsoft.VisualBasic.Core.dll + Resources\ReferenceAssemblies\netcoreapp\Microsoft.VisualBasic.Core.dll + netstandard20.mscorlib.dll Resources\ReferenceAssemblies\netstandard20\mscorlib.dll diff --git a/src/Compilers/Test/Core/IsExternalInit.cs b/src/Compilers/Test/Core/IsExternalInit.cs new file mode 100644 index 0000000000000..a4bb39e36e058 --- /dev/null +++ b/src/Compilers/Test/Core/IsExternalInit.cs @@ -0,0 +1,10 @@ +// 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. + +namespace System.Runtime.CompilerServices +{ + public static class IsExternalInit + { + } +} diff --git a/src/Compilers/Test/Core/ModuleInitializerAttribute.cs b/src/Compilers/Test/Core/ModuleInitializerAttribute.cs index ee59bba2525a0..92de1528ef3ac 100644 --- a/src/Compilers/Test/Core/ModuleInitializerAttribute.cs +++ b/src/Compilers/Test/Core/ModuleInitializerAttribute.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 - #if !NET5_0 namespace System.Runtime.CompilerServices diff --git a/src/Compilers/Test/Core/PDB/DeterministicBuildCompilationTestHelpers.cs b/src/Compilers/Test/Core/PDB/DeterministicBuildCompilationTestHelpers.cs index 46ad72a20abbb..26d9857e0dc4f 100644 --- a/src/Compilers/Test/Core/PDB/DeterministicBuildCompilationTestHelpers.cs +++ b/src/Compilers/Test/Core/PDB/DeterministicBuildCompilationTestHelpers.cs @@ -15,6 +15,7 @@ using Microsoft.Cci; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; namespace Roslyn.Test.Utilities.PDB @@ -72,18 +73,25 @@ internal static void AssertCommonOptions(EmitOptions emitOptions, CompilationOpt Assert.Equal(compilation.Language, pdbOptions["language"]); } - public static void VerifyReferenceInfo(TestMetadataReferenceInfo[] references, BlobReader metadataReferenceReader) + public static void VerifyReferenceInfo(TestMetadataReferenceInfo[] references, TargetFramework targetFramework, BlobReader metadataReferenceReader) { - foreach (var reference in references) + var frameworkReferences = TargetFrameworkUtil.GetReferences(targetFramework); + var count = 0; + while (metadataReferenceReader.RemainingBytes > 0) { var info = ParseMetadataReferenceInfo(ref metadataReferenceReader); - var originalInfo = reference.MetadataReferenceInfo; + if (frameworkReferences.Any(x => x.GetModuleVersionId() == info.Mvid)) + { + count++; + continue; + } - originalInfo.AssertEqual(info); + var testReference = references.Single(x => x.MetadataReferenceInfo.Mvid == info.Mvid); + testReference.MetadataReferenceInfo.AssertEqual(info); + count++; } - // Make sure we read all the data - Assert.Equal(0, metadataReferenceReader.RemainingBytes); + Assert.Equal(references.Length + frameworkReferences.Length, count); } public static BlobReader GetSingleBlob(Guid infoGuid, MetadataReader pdbReader) diff --git a/src/Compilers/Test/Core/TestableFile.cs b/src/Compilers/Test/Core/TestableFile.cs new file mode 100644 index 0000000000000..05cb0fde9eaed --- /dev/null +++ b/src/Compilers/Test/Core/TestableFile.cs @@ -0,0 +1,95 @@ +// 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.Diagnostics; +using System.IO; +using System.Text; +using Microsoft.CodeAnalysis; +using Roslyn.Utilities; + +namespace Roslyn.Test.Utilities +{ + /// + /// This works with to have an "in memory" file that can + /// be manipulated by consumers of + /// + /// This isn't meant to handle complex file system interactions but the basic cases of open, + /// close, create, read and write. + /// + public sealed class TestableFile + { + private sealed class TestableFileStream : MemoryStream + { + public TestableFile MemoryFile { get; } + public bool CopyBack { get; } + + public TestableFileStream(TestableFile memoryFile) + { + Debug.Assert(!memoryFile.Exists); + MemoryFile = memoryFile; + MemoryFile.Exists = true; + CopyBack = true; + } + + public TestableFileStream(TestableFile memoryFile, byte[] bytes, bool writable) + : base(bytes, writable) + { + Debug.Assert(memoryFile.Exists); + MemoryFile = memoryFile; + CopyBack = writable; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (CopyBack) + { + MemoryFile.Contents.Clear(); + MemoryFile.Contents.AddRange(this.ToArray()); + } + } + + base.Dispose(disposing); + } + } + + public bool Exists { get; private set; } + public List Contents { get; } = new List(); + + public TestableFile() + { + } + + public TestableFile(string contents) + { + Exists = true; + Contents.AddRange(Encoding.UTF8.GetBytes(contents)); + } + + public TestableFile(byte[] contents) + { + Exists = true; + Contents.AddRange(contents); + } + + public MemoryStream GetStream(FileAccess access = FileAccess.ReadWrite) + { + var writable = access is FileAccess.Write or FileAccess.ReadWrite; + if (!Exists) + { + if (!writable) + { + throw new InvalidOperationException(); + } + + return new TestableFileStream(this); + } + + return new TestableFileStream(this, Contents.ToArray(), writable); + } + } +} diff --git a/src/Compilers/Test/Core/TestableFileSystem.cs b/src/Compilers/Test/Core/TestableFileSystem.cs new file mode 100644 index 0000000000000..b0b644d9f11d4 --- /dev/null +++ b/src/Compilers/Test/Core/TestableFileSystem.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.IO; +using Roslyn.Utilities; + +namespace Roslyn.Test.Utilities +{ + public delegate Stream OpenFileExFunc(string filePath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, out string normalizedFilePath); + public delegate Stream OpenFileFunc(string filePath, FileMode mode, FileAccess access, FileShare share); + + public sealed class TestableFileSystem : ICommonCompilerFileSystem + { + public OpenFileFunc OpenFileFunc { get; set; } = delegate { throw new InvalidOperationException(); }; + public OpenFileExFunc OpenFileExFunc { get; set; } = (string _, FileMode _, FileAccess _, FileShare _, int _, FileOptions _, out string _) => throw new InvalidOperationException(); + public Func FileExistsFunc { get; set; } = delegate { throw new InvalidOperationException(); }; + + public Stream OpenFile(string filePath, FileMode mode, FileAccess access, FileShare share) + => OpenFileFunc(filePath, mode, access, share); + + public Stream OpenFileEx(string filePath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, out string normalizedFilePath) + => OpenFileExFunc(filePath, mode, access, share, bufferSize, options, out normalizedFilePath); + + public bool FileExists(string filePath) => FileExistsFunc(filePath); + + public static TestableFileSystem CreateForStandard( + OpenFileFunc? openFileFunc = null, + OpenFileExFunc? openFileExFunc = null, + Func? fileExistsFunc = null) + => new TestableFileSystem() + { + OpenFileFunc = openFileFunc ?? StandardFileSystem.Instance.OpenFile, + OpenFileExFunc = openFileExFunc ?? StandardFileSystem.Instance.OpenFileEx, + FileExistsFunc = fileExistsFunc ?? StandardFileSystem.Instance.FileExists, + }; + + public static TestableFileSystem CreateForOpenFile(OpenFileFunc openFileFunc) + => new TestableFileSystem() { OpenFileFunc = openFileFunc }; + + public static TestableFileSystem CreateForExistingPaths(IEnumerable existingPaths, StringComparer? comparer = null) + { + comparer ??= StringComparer.OrdinalIgnoreCase; + var set = new HashSet(existingPaths, comparer); + return new TestableFileSystem() + { + FileExistsFunc = filePath => set.Contains(filePath) + }; + } + + public static TestableFileSystem CreateForMap(Dictionary map) + => new TestableFileSystem() + { + OpenFileExFunc = (string filePath, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options, out string normalizedFilePath) => + { + normalizedFilePath = filePath; + return map[filePath].GetStream(access); + }, + + OpenFileFunc = (string filePath, FileMode mode, FileAccess access, FileShare share) => map[filePath].GetStream(access), + FileExistsFunc = filePath => map.ContainsKey(filePath), + }; + } +} diff --git a/src/Compilers/Test/Core/Traits/Traits.cs b/src/Compilers/Test/Core/Traits/Traits.cs index 2b72c0685c0ab..b21f3558c22ba 100644 --- a/src/Compilers/Test/Core/Traits/Traits.cs +++ b/src/Compilers/Test/Core/Traits/Traits.cs @@ -227,6 +227,7 @@ public static class Features public const string DocCommentFormatting = nameof(DocCommentFormatting); public const string DocumentationComments = nameof(DocumentationComments); public const string EditorConfig = nameof(EditorConfig); + public const string EditorConfigUI = nameof(EditorConfigUI); public const string EncapsulateField = nameof(EncapsulateField); public const string EndConstructGeneration = nameof(EndConstructGeneration); public const string ErrorList = nameof(ErrorList); diff --git a/src/Compilers/Test/Utilities/CSharp/CompilingTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CompilingTestBase.cs index 55d03fb0613dd..d9896abd7721c 100644 --- a/src/Compilers/Test/Utilities/CSharp/CompilingTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CompilingTestBase.cs @@ -5,11 +5,9 @@ #nullable disable using System; -using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Emit; using Roslyn.Test.Utilities; @@ -43,28 +41,6 @@ internal static BoundBlock ParseAndBindMethodBody(string program, string typeNam return block; } - public static string DumpDiagnostic(Diagnostic diagnostic) - { - return string.Format("'{0}' {1}", - diagnostic.Location.SourceTree.GetText().ToString(diagnostic.Location.SourceSpan), - DiagnosticFormatter.Instance.Format(diagnostic.WithLocation(Location.None), EnsureEnglishUICulture.PreferredOrNull)); - } - - [Obsolete("Use VerifyDiagnostics", true)] - public static void TestDiagnostics(IEnumerable diagnostics, params string[] diagStrings) - { - AssertEx.SetEqual(diagStrings, diagnostics.Select(DumpDiagnostic)); - } - - // Do a full compilation and check all the errors. - [Obsolete("Use VerifyDiagnostics", true)] - public void TestAllErrors(string code, params string[] errors) - { - var compilation = CreateCompilation(code); - var diagnostics = compilation.GetDiagnostics(); - AssertEx.SetEqual(errors, diagnostics.Select(DumpDiagnostic)); - } - public const string LINQ = #region the string LINQ defines a complete LINQ API called List1 (for instance method) and List2 (for extension methods) @"using System; diff --git a/src/Compilers/Test/Utilities/CSharp/DiagnosticTestUtilities.cs b/src/Compilers/Test/Utilities/CSharp/DiagnosticTestUtilities.cs index e074dc75115b7..586c80e12437c 100644 --- a/src/Compilers/Test/Utilities/CSharp/DiagnosticTestUtilities.cs +++ b/src/Compilers/Test/Utilities/CSharp/DiagnosticTestUtilities.cs @@ -7,10 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; -using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -33,38 +30,6 @@ public override string ToString() public abstract class DiagnosticsUtils { - /// - /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead. - /// - public static void VerifyErrorCodes(CSharpCompilation comp, params ErrorDescription[] expectedErrors) - { - var actualErrors = comp.GetDiagnostics(); - DiagnosticsUtils.VerifyErrorCodes(actualErrors, expectedErrors); - } - - /// - /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead. - /// - [Obsolete("Use VerifyDiagnostics", true)] - public static void TestDiagnostics(string source, params string[] diagStrings) - { - var comp = CSharpTestBase.CreateCompilation(source); - var diagnostics = comp.GetDiagnostics(); - CompilingTestBase.TestDiagnostics(diagnostics, diagStrings); - } - - /// - /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead. - /// - [Obsolete("Use VerifyDiagnostics", true)] - public static void TestDiagnosticsExact(string source, params string[] diagStrings) - { - var comp = CSharpTestBase.CreateCompilation(source); - var diagnostics = comp.GetDiagnostics(); - Assert.Equal(diagStrings.Length, diagnostics.Length); - CompilingTestBase.TestDiagnostics(diagnostics, diagStrings); - } - /// /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead. /// diff --git a/src/Compilers/VisualBasic/BasicAnalyzerDriver/VisualBasicDeclarationComputer.vb b/src/Compilers/VisualBasic/BasicAnalyzerDriver/VisualBasicDeclarationComputer.vb index bb313219db18a..32fd08277aabf 100644 --- a/src/Compilers/VisualBasic/BasicAnalyzerDriver/VisualBasicDeclarationComputer.vb +++ b/src/Compilers/VisualBasic/BasicAnalyzerDriver/VisualBasicDeclarationComputer.vb @@ -17,7 +17,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic getSymbol As Boolean, builder As ArrayBuilder(Of DeclarationInfo), cancellationToken As CancellationToken) - ComputeDeclarationsCore(model, model.SyntaxTree.GetRoot(), + ComputeDeclarationsCore(model, model.SyntaxTree.GetRoot(cancellationToken), Function(node, level) Not node.Span.OverlapsWith(span) OrElse InvalidLevel(level), getSymbol, builder, Nothing, cancellationToken) End Sub diff --git a/src/Compilers/VisualBasic/Portable/Compilation/DocumentationComments/UnprocessedDocumentationCommentFinder.vb b/src/Compilers/VisualBasic/Portable/Compilation/DocumentationComments/UnprocessedDocumentationCommentFinder.vb index f3852f7b94b87..1700ef1f15e3d 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/DocumentationComments/UnprocessedDocumentationCommentFinder.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/DocumentationComments/UnprocessedDocumentationCommentFinder.vb @@ -43,7 +43,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Shared Sub ReportUnprocessed(tree As SyntaxTree, filterSpanWithinTree As TextSpan?, diagnostics As DiagnosticBag, cancellationToken As CancellationToken) If tree.ReportDocumentationCommentDiagnostics() Then Dim finder As New MislocatedDocumentationCommentFinder(diagnostics, filterSpanWithinTree, cancellationToken) - finder.Visit(tree.GetRoot()) + finder.Visit(tree.GetRoot(cancellationToken)) End If End Sub diff --git a/src/Compilers/VisualBasic/Portable/Compilation/SemanticModel.vb b/src/Compilers/VisualBasic/Portable/Compilation/SemanticModel.vb index 60c4671953ae0..04993b31fb4b9 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/SemanticModel.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/SemanticModel.vb @@ -2399,7 +2399,7 @@ _Default: Dim tupleTypeSyntax = TryCast(elementSyntax.Parent, TupleTypeSyntax) If tupleTypeSyntax IsNot Nothing Then - Return TryCast(GetSymbolInfo(tupleTypeSyntax).Symbol, TupleTypeSymbol)?.TupleElements.ElementAtOrDefault(tupleTypeSyntax.Elements.IndexOf(elementSyntax)) + Return TryCast(GetSymbolInfo(tupleTypeSyntax, cancellationToken).Symbol, TupleTypeSymbol)?.TupleElements.ElementAtOrDefault(tupleTypeSyntax.Elements.IndexOf(elementSyntax)) End If Return Nothing diff --git a/src/Compilers/VisualBasic/Portable/Compilation/SyntaxTreeSemanticModel.vb b/src/Compilers/VisualBasic/Portable/Compilation/SyntaxTreeSemanticModel.vb index 81f6d449a47e1..4e0c843a67102 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/SyntaxTreeSemanticModel.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/SyntaxTreeSemanticModel.vb @@ -988,7 +988,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Case SyntaxKind.CompilationUnit namespaceToLookInForImplicitType = Me._sourceModule.RootNamespace Case SyntaxKind.NamespaceBlock - namespaceToLookInForImplicitType = GetDeclaredSymbol(DirectCast(statementSyntax.Parent, NamespaceBlockSyntax)) + namespaceToLookInForImplicitType = GetDeclaredSymbol(DirectCast(statementSyntax.Parent, NamespaceBlockSyntax), cancellationToken) End Select If namespaceToLookInForImplicitType IsNot Nothing Then diff --git a/src/Compilers/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.vbproj b/src/Compilers/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.vbproj index 8fda18d4b1b3e..840b7ecd76e75 100644 --- a/src/Compilers/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.vbproj +++ b/src/Compilers/VisualBasic/Portable/Microsoft.CodeAnalysis.VisualBasic.vbproj @@ -53,6 +53,7 @@ + diff --git a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb index 06f2bb78f20fb..ba37369b1598b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb @@ -927,7 +927,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Function ''' - ''' True iff this type or some containing type has type parameters. + ''' True if and only if this type or some containing type has type parameters. ''' Public ReadOnly Property IsGenericType As Boolean Implements INamedTypeSymbol.IsGenericType Get diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamespaceSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamespaceSymbol.vb index 383b0d1d6d638..c330eb142b80b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamespaceSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamespaceSymbol.vb @@ -480,7 +480,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End If Dim currentTree = syntaxRef.SyntaxTree - Dim node As VisualBasicSyntaxNode = syntaxRef.GetVisualBasicSyntax() + Dim node As VisualBasicSyntaxNode = syntaxRef.GetVisualBasicSyntax(cancellationToken) Select Case node.Kind Case SyntaxKind.IdentifierName ValidateNamespaceNameSyntax(DirectCast(node, IdentifierNameSyntax), diagnostics, reportedNamespaceMismatch) diff --git a/src/Compilers/VisualBasic/Portable/Syntax/BeginOfBlockSyntaxReference.vb b/src/Compilers/VisualBasic/Portable/Syntax/BeginOfBlockSyntaxReference.vb index f7920d31f8789..1bef94966eac6 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/BeginOfBlockSyntaxReference.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/BeginOfBlockSyntaxReference.vb @@ -17,7 +17,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Sub Protected Overrides Function Translate(reference As SyntaxReference, cancellationToken As CancellationToken) As SyntaxNode - Return SyntaxFacts.BeginOfBlockStatementIfAny(reference.GetSyntax()) + Return SyntaxFacts.BeginOfBlockStatementIfAny(reference.GetSyntax(cancellationToken)) End Function End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Syntax/NamespaceDeclarationSyntaxReference.vb b/src/Compilers/VisualBasic/Portable/Syntax/NamespaceDeclarationSyntaxReference.vb index f2f7dc17f0cfd..a6e2c0670c667 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/NamespaceDeclarationSyntaxReference.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/NamespaceDeclarationSyntaxReference.vb @@ -19,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Sub Protected Overrides Function Translate(reference As SyntaxReference, cancellationToken As CancellationToken) As SyntaxNode - Dim node = reference.GetSyntax() + Dim node = reference.GetSyntax(cancellationToken) ' If the node is a name syntax, it's something like "X" or "X.Y" in : ' Namespace X.Y.Z diff --git a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb index 03d079223948b..907e01fc7e04f 100644 --- a/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb +++ b/src/Compilers/VisualBasic/Test/CommandLine/CommandLineTests.vb @@ -919,38 +919,38 @@ a.vb Dim parsedArgs = DefaultParse(args, _baseDirectory) Dim compilation = CreateCompilationWithMscorlib40(New VisualBasicSyntaxTree() {}) Dim errors As IEnumerable(Of DiagnosticInfo) = Nothing - CommonCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, errors) + CommonCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, errors) Assert.Equal(1, errors.Count()) Assert.Equal(DirectCast(ERRID.ERR_UnableToReadUacManifest2, Integer), errors.First().Code) Assert.Equal(2, errors.First().Arguments.Count()) args = {"/Win32icon:\bogus"} parsedArgs = DefaultParse(args, _baseDirectory) - CommonCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, errors) + CommonCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, errors) Assert.Equal(1, errors.Count()) Assert.Equal(DirectCast(ERRID.ERR_UnableToOpenResourceFile1, Integer), errors.First().Code) Assert.Equal(2, errors.First().Arguments.Count()) args = {"/Win32Resource:\bogus"} parsedArgs = DefaultParse(args, _baseDirectory) - CommonCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, errors) + CommonCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, errors) Assert.Equal(1, errors.Count()) Assert.Equal(DirectCast(ERRID.ERR_UnableToOpenResourceFile1, Integer), errors.First().Code) Assert.Equal(2, errors.First().Arguments.Count()) args = {"/win32manifest:goo.win32data:bar.win32data2"} parsedArgs = DefaultParse(args, _baseDirectory) - CommonCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, errors) + CommonCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, errors) Assert.Equal(1, errors.Count()) Assert.Equal(DirectCast(ERRID.ERR_UnableToReadUacManifest2, Integer), errors.First().Code) Assert.Equal(2, errors.First().Arguments.Count()) args = {"/Win32icon:goo.win32data:bar.win32data2"} parsedArgs = DefaultParse(args, _baseDirectory) - CommonCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, errors) + CommonCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, errors) Assert.Equal(1, errors.Count()) Assert.Equal(DirectCast(ERRID.ERR_UnableToOpenResourceFile1, Integer), errors.First().Code) Assert.Equal(2, errors.First().Arguments.Count()) args = {"/Win32Resource:goo.win32data:bar.win32data2"} parsedArgs = DefaultParse(args, _baseDirectory) - CommonCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, errors) + CommonCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, errors) Assert.Equal(1, errors.Count()) Assert.Equal(DirectCast(ERRID.ERR_UnableToOpenResourceFile1, Integer), errors.First().Code) Assert.Equal(2, errors.First().Arguments.Count()) @@ -962,7 +962,7 @@ a.vb Dim parsedArgs = DefaultParse({"/win32icon:" + tmpFileName}, _baseDirectory) Dim compilation = CreateCompilationWithMscorlib40(New VisualBasicSyntaxTree() {}) Dim errors As IEnumerable(Of DiagnosticInfo) = Nothing - CommonCompiler.GetWin32ResourcesInternal(MessageProvider.Instance, parsedArgs, compilation, errors) + CommonCompiler.GetWin32ResourcesInternal(StandardFileSystem.Instance, MessageProvider.Instance, parsedArgs, compilation, errors) Assert.Equal(1, errors.Count()) Assert.Equal(DirectCast(ERRID.ERR_ErrorCreatingWin32ResourceFile, Integer), errors.First().Code) Assert.Equal(1, errors.First().Arguments.Count()) @@ -9428,13 +9428,14 @@ End Module Dim srcPath = MakeTrivialExe(Temp.CreateDirectory().Path) Dim exePath = Path.Combine(Path.GetDirectoryName(srcPath), "test.exe") Dim vbc = New MockVisualBasicCompiler(_baseDirectory, {"/nologo", "/preferreduilang:en", $"/out:{exePath}", srcPath}) - vbc.FileOpen = Function(filePath, mode, access, share) - If filePath = exePath Then - Return New TestStream(backingStream:=New MemoryStream(), dispose:=Sub() Throw New IOException("Fake IOException")) - End If + vbc.FileSystem = TestableFileSystem.CreateForStandard(openFileFunc:= + Function(filePath, mode, access, share) + If filePath = exePath Then + Return New TestStream(backingStream:=New MemoryStream(), dispose:=Sub() Throw New IOException("Fake IOException")) + End If - Return File.Open(filePath, mode, access, share) - End Function + Return File.Open(filePath, mode, access, share) + End Function) Dim outWriter = New StringWriter(CultureInfo.InvariantCulture) Assert.Equal(1, vbc.Run(outWriter)) @@ -9447,13 +9448,14 @@ End Module Dim exePath = Path.Combine(Path.GetDirectoryName(srcPath), "test.exe") Dim pdbPath = Path.ChangeExtension(exePath, "pdb") Dim vbc = New MockVisualBasicCompiler(_baseDirectory, {"/nologo", "/preferreduilang:en", "/debug", $"/out:{exePath}", srcPath}) - vbc.FileOpen = Function(filePath, mode, access, share) - If filePath = pdbPath Then - Return New TestStream(backingStream:=New MemoryStream(), dispose:=Sub() Throw New IOException("Fake IOException")) - End If + vbc.FileSystem = TestableFileSystem.CreateForStandard(openFileFunc:= + Function(filePath, mode, access, share) + If filePath = pdbPath Then + Return New TestStream(backingStream:=New MemoryStream(), dispose:=Sub() Throw New IOException("Fake IOException")) + End If - Return File.Open(filePath, mode, access, share) - End Function + Return File.Open(filePath, mode, access, share) + End Function) Dim outWriter = New StringWriter(CultureInfo.InvariantCulture) Assert.Equal(1, vbc.Run(outWriter)) @@ -9465,13 +9467,14 @@ End Module Dim srcPath = MakeTrivialExe(Temp.CreateDirectory().Path) Dim xmlPath = Path.Combine(Path.GetDirectoryName(srcPath), "test.xml") Dim vbc = New MockVisualBasicCompiler(_baseDirectory, {"/nologo", "/preferreduilang:en", $"/doc:{xmlPath}", srcPath}) - vbc.FileOpen = Function(filePath, mode, access, share) - If filePath = xmlPath Then - Return New TestStream(backingStream:=New MemoryStream(), dispose:=Sub() Throw New IOException("Fake IOException")) - End If + vbc.FileSystem = TestableFileSystem.CreateForStandard(openFileFunc:= + Function(filePath, mode, access, share) + If filePath = xmlPath Then + Return New TestStream(backingStream:=New MemoryStream(), dispose:=Sub() Throw New IOException("Fake IOException")) + End If - Return File.Open(filePath, mode, access, share) - End Function + Return File.Open(filePath, mode, access, share) + End Function) Dim outWriter = New StringWriter(CultureInfo.InvariantCulture) Assert.Equal(1, vbc.Run(outWriter)) @@ -9485,9 +9488,10 @@ End Module Dim srcPath = MakeTrivialExe(Temp.CreateDirectory().Path) Dim sourceLinkPath = Path.Combine(Path.GetDirectoryName(srcPath), "test.json") Dim vbc = New MockVisualBasicCompiler(_baseDirectory, {"/nologo", "/preferreduilang:en", "/debug:" & format, $"/sourcelink:{sourceLinkPath}", srcPath}) - vbc.FileOpen = Function(filePath, mode, access, share) - If filePath = sourceLinkPath Then - Return New TestStream( + vbc.FileSystem = TestableFileSystem.CreateForStandard(openFileFunc:= + Function(filePath, mode, access, share) + If filePath = sourceLinkPath Then + Return New TestStream( backingStream:=New MemoryStream(Encoding.UTF8.GetBytes(" { ""documents"": { @@ -9496,10 +9500,10 @@ End Module } ")), dispose:=Sub() Throw New IOException("Fake IOException")) - End If + End If - Return File.Open(filePath, mode, access, share) - End Function + Return File.Open(filePath, mode, access, share) + End Function) Dim outWriter = New StringWriter(CultureInfo.InvariantCulture) Assert.Equal(1, vbc.Run(outWriter)) diff --git a/src/Compilers/VisualBasic/Test/Emit/PDB/VisualBasicDeterministicBuildCompilationTests.vb b/src/Compilers/VisualBasic/Test/Emit/PDB/VisualBasicDeterministicBuildCompilationTests.vb index 12a856433127e..3bf532f45b2b3 100644 --- a/src/Compilers/VisualBasic/Test/Emit/PDB/VisualBasicDeterministicBuildCompilationTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/PDB/VisualBasicDeterministicBuildCompilationTests.vb @@ -38,11 +38,12 @@ Public Class VisualBasicDeterministicBuildCompilationTests Private Sub TestDeterministicCompilationVB(syntaxTrees As SyntaxTree(), compilationOptions As VisualBasicCompilationOptions, emitOptions As EmitOptions, ParamArray metadataReferences() As TestMetadataReferenceInfo) + Dim tf = TargetFramework.NetStandard20 Dim originalCompilation = CreateCompilation( syntaxTrees, references:=metadataReferences.SelectAsArray(Of MetadataReference)(Function(r) r.MetadataReference), options:=compilationOptions, - targetFramework:=TargetFramework.NetStandard20) + targetFramework:=tf) Dim peBlob = originalCompilation.EmitToArray(emitOptions) @@ -63,7 +64,7 @@ Public Class VisualBasicDeterministicBuildCompilationTests Dim compilationOptionsReader = DeterministicBuildCompilationTestHelpers.GetSingleBlob(PortableCustomDebugInfoKinds.CompilationOptions, pdbReader) VerifyCompilationOptions(compilationOptions, compilationOptionsReader, emitOptions, originalCompilation) - DeterministicBuildCompilationTestHelpers.VerifyReferenceInfo(metadataReferences, metadataReferenceReader) + DeterministicBuildCompilationTestHelpers.VerifyReferenceInfo(metadataReferences, tf, metadataReferenceReader) End Using End Using End Sub diff --git a/src/Dependencies/Collections/SegmentedDictionary`2.cs b/src/Dependencies/Collections/SegmentedDictionary`2.cs index 2de132109938f..f8dbf0b85ebe2 100644 --- a/src/Dependencies/Collections/SegmentedDictionary`2.cs +++ b/src/Dependencies/Collections/SegmentedDictionary`2.cs @@ -318,7 +318,12 @@ private ref TValue FindValue(TKey key) var comparer = _comparer; if (comparer == null) { +#if NETCOREAPP var hashCode = (uint)key.GetHashCode(); +#else + // Avoid boxing enum types on .NET Framework + var hashCode = (uint)EqualityComparer.Default.GetHashCode(key); +#endif var i = GetBucket(hashCode); var entries = _entries; uint collisionCount = 0; @@ -462,7 +467,12 @@ private bool TryInsert(TKey key, TValue value, InsertionBehavior behavior) Debug.Assert(entries.Length > 0, "expected entries to be non-empty"); var comparer = _comparer; +#if NETCOREAPP var hashCode = (uint)((comparer == null) ? key.GetHashCode() : comparer.GetHashCode(key)); +#else + // Avoid boxing enum types on .NET Framework + var hashCode = (uint)((comparer == null) ? EqualityComparer.Default.GetHashCode(key) : comparer.GetHashCode(key)); +#endif uint collisionCount = 0; ref var bucket = ref GetBucket(hashCode); @@ -666,7 +676,12 @@ public bool Remove(TKey key) { Debug.Assert(_entries.Length > 0, "entries should be non-empty"); uint collisionCount = 0; +#if NETCOREAPP var hashCode = (uint)(_comparer?.GetHashCode(key) ?? key.GetHashCode()); +#else + // Avoid boxing enum types on .NET Framework + var hashCode = (uint)(_comparer?.GetHashCode(key) ?? EqualityComparer.Default.GetHashCode(key)); +#endif ref var bucket = ref GetBucket(hashCode); var entries = _entries; var last = -1; @@ -738,7 +753,12 @@ public bool Remove(TKey key, [MaybeNullWhen(false)] out TValue value) { Debug.Assert(_entries.Length > 0, "entries should be non-empty"); uint collisionCount = 0; +#if NETCOREAPP var hashCode = (uint)(_comparer?.GetHashCode(key) ?? key.GetHashCode()); +#else + // Avoid boxing enum types on .NET Framework + var hashCode = (uint)(_comparer?.GetHashCode(key) ?? EqualityComparer.Default.GetHashCode(key)); +#endif ref var bucket = ref GetBucket(hashCode); var entries = _entries; var last = -1; diff --git a/src/EditorFeatures/CSharp/CSharpEditorResources.resx b/src/EditorFeatures/CSharp/CSharpEditorResources.resx index dc934ab12dff9..0498beacc31e0 100644 --- a/src/EditorFeatures/CSharp/CSharpEditorResources.resx +++ b/src/EditorFeatures/CSharp/CSharpEditorResources.resx @@ -182,4 +182,259 @@ Add Missing Usings on Paste "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + + + Avoid unused value assignments + + + Discard + + + Elsewhere + + + For built-in types + + + Ignore spaces in declaration statements + + + Indent block contents + + + Indent case contents + + + Indent case contents (when block) + + + Indent case labels + + + Indent open and close braces + + + Insert spaces within parentheses of control flow statements + + + Insert spaces within square brackets + + + Insert space after cast + + + Insert space after colon for base or interface in type declaration + + + Insert space after comma + + + Insert space after dot + + + Insert space after keywords in control flow statements + + + Insert space after semicolon in "for" statement + + + Insert space before colon for base or interface in type declaration + + + Insert space before comma + + + Insert space before dot + + + Insert space before open square bracket + + + Insert space before semicolon in "for" statement + + + Insert space between method name and its opening parenthesis + + + Insert space between method name and its opening parenthesis + + + Insert space within argument list parentheses + + + Insert space within empty argument list parentheses + + + Insert space within empty parameter list parentheses + + + Insert space within empty square brackets + + + Insert space within parameter list parentheses + + + Insert space within parentheses of expressions + + + Insert space within parentheses of type casts + + + Inside namespace + + + Label Indentation + + + Leave block on single line + + + Leave statements and member declarations on the same line + + + Never + + + Place "catch" on new line + + + Place "else" on new line + + + Place "finally" on new line + + + Place members in anonymous types on new line + + + Place members in object initializers on new line + + + Place open brace on new line for anonymous methods + + + Place open brace on new line for anonymous types + + + Place open brace on new line for control blocks + + + Place open brace on new line for lambda expression + + + Place open brace on new line for methods and local functions + + + Place open brace on new line for object, collection, array, and with initializers + + + Place open brace on new line for properties, indexers, and events + + + Place open brace on new line for property, indexer, and event accessors + + + Place open brace on new line for types + + + Place query expression clauses on new line + + + Preferred 'using' directive placement + + + Prefer conditional delegate call + + + Prefer deconstructed variable declaration + + + Prefer explicit type + + + Prefer index operator + + + Prefer inlined variable declaration + + + Prefer local function over anonymous function + + + Prefer pattern matching + + + Prefer pattern matching over 'as' with 'null' check + + + Prefer pattern matching over 'is' with 'cast' check + + + Prefer pattern matching over mixed type check + + + Prefer range operator + + + Prefer simple 'default' expression + + + Prefer simple 'using' statement + + + Prefer static local functions + + + Prefer switch expression + + + Prefer throw-expression + + + Prefer 'var' + + + Set spacing for operators + + + Unused local + + + Use expression body for accessors + + + Use expression body for constructors + + + Use expression body for indexers + + + Use expression body for lambdas + + + Use expression body for local functions + + + Use expression body for methods + + + Use expression body for operators + + + Use expression body for properties + + + When on single line + + + When possible + + + When variable type is apparent + + + Outside namespace + \ No newline at end of file diff --git a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs index 23f86ad16c197..eeeb3a9ee3448 100644 --- a/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs +++ b/src/EditorFeatures/CSharp/CompleteStatement/CompleteStatementCommandHandler.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editor.Implementation.AutomaticCompletion; 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.Internal.Log; @@ -88,6 +89,11 @@ private static bool BeforeExecuteCommand(bool speculative, TypeCharCommandArgs a return false; } + if (!args.SubjectBuffer.GetFeatureOnOffOption(FeatureOnOffOptions.AutomaticallyCompleteStatementOnSemicolon)) + { + return false; + } + var caret = caretOpt.Value; var document = caret.Snapshot.GetOpenDocumentInCurrentContextWithChanges(); if (document == null) @@ -178,7 +184,9 @@ private static bool MoveCaretToSemicolonPosition( SyntaxKind.ParameterList, SyntaxKind.DefaultExpression, SyntaxKind.CheckedExpression, - SyntaxKind.UncheckedExpression)) + SyntaxKind.UncheckedExpression, + SyntaxKind.TypeOfExpression, + SyntaxKind.TupleExpression)) { // make sure the closing delimiter exists if (RequiredDelimiterIsMissing(currentNode)) @@ -520,6 +528,14 @@ private static (SyntaxToken openingDelimeter, SyntaxToken closingDelimiter) GetD var checkedExpressionSyntax = (CheckedExpressionSyntax)currentNode; return (checkedExpressionSyntax.OpenParenToken, checkedExpressionSyntax.CloseParenToken); + case SyntaxKind.TypeOfExpression: + var typeOfExpressionSyntax = (TypeOfExpressionSyntax)currentNode; + return (typeOfExpressionSyntax.OpenParenToken, typeOfExpressionSyntax.CloseParenToken); + + case SyntaxKind.TupleExpression: + var tupleExpressionSyntax = (TupleExpressionSyntax)currentNode; + return (tupleExpressionSyntax.OpenParenToken, tupleExpressionSyntax.CloseParenToken); + default: // Type of node does not have delimiters used by this feature return default; diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsLanguageServiceFactory.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsLanguageServiceFactory.cs new file mode 100644 index 0000000000000..b4ffb45e574f0 --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsLanguageServiceFactory.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 System; +using System.Composition; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.CodeStyle +{ + [ExportLanguageServiceFactory(typeof(ILanguageSettingsProviderFactory), LanguageNames.CSharp), Shared] + internal class CSharpCodeStyleSettingsLanguageServiceFactory : ILanguageServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpCodeStyleSettingsLanguageServiceFactory() + { + } + + public ILanguageService CreateLanguageService(HostLanguageServices languageServices) + { + var workspace = languageServices.WorkspaceServices.Workspace; + return new CSharpCodeStyleSettingsProviderFactory(workspace); + } + } +} diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs new file mode 100644 index 0000000000000..bce834f0c12ec --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs @@ -0,0 +1,224 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.CSharp; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.CodeStyle +{ + internal class CSharpCodeStyleSettingsProvider : SettingsProviderBase + { + public CSharpCodeStyleSettingsProvider(string fileName, OptionUpdater settingsUpdater, Workspace workspace) + : base(fileName, settingsUpdater, workspace) + { + Update(); + } + + protected override void UpdateOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions) + { + var varSettings = GetVarCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(varSettings); + + var usingSettings = GetUsingsCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(usingSettings); + + var modifierSettings = GetModifierCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(modifierSettings); + + var codeBlockSettings = GetCodeBlockCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(codeBlockSettings); + + var nullCheckingSettings = GetNullCheckingCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(nullCheckingSettings); + + var expressionSettings = GetExpressionCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(expressionSettings); + + var patternMatchingSettings = GetPatternMatchingCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(patternMatchingSettings); + + var variableSettings = GetVariableCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(variableSettings); + + var expressionBodySettings = GetExpressionBodyCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(expressionBodySettings); + + var unusedValueSettings = GetUnusedValueCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(unusedValueSettings); + } + + private static IEnumerable GetVarCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.VarForBuiltInTypes, + description: CSharpEditorResources.For_built_in_types, + trueValueDescription: CSharpEditorResources.Prefer_var, + falseValueDescription: CSharpEditorResources.Prefer_explicit_type, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.VarWhenTypeIsApparent, + description: CSharpEditorResources.When_variable_type_is_apparent, + trueValueDescription: CSharpEditorResources.Prefer_var, + falseValueDescription: CSharpEditorResources.Prefer_explicit_type, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.VarElsewhere, + description: CSharpEditorResources.Elsewhere, + trueValueDescription: CSharpEditorResources.Prefer_var, + falseValueDescription: CSharpEditorResources.Prefer_explicit_type, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetUsingsCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create( + option: CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, + description: CSharpEditorResources.Preferred_using_directive_placement, + enumValues: new[] { AddImportPlacement.InsideNamespace, AddImportPlacement.OutsideNamespace }, + valueDescriptions: new[] { CSharpEditorResources.Inside_namespace, CSharpEditorResources.Outside_namespace }, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetNullCheckingCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferThrowExpression, + description: CSharpEditorResources.Prefer_throw_expression, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferConditionalDelegateCall, + description: CSharpEditorResources.Prefer_conditional_delegate_call, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetModifierCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferStaticLocalFunction, + description: CSharpEditorResources.Prefer_static_local_functions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetCodeBlockCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferSimpleUsingStatement, + description: CSharpEditorResources.Prefer_simple_using_statement, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetExpressionCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferSwitchExpression, description: CSharpEditorResources.Prefer_switch_expression, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferSimpleDefaultExpression, description: CSharpEditorResources.Prefer_simple_default_expression, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferLocalOverAnonymousFunction, description: CSharpEditorResources.Prefer_local_function_over_anonymous_function, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferIndexOperator, description: CSharpEditorResources.Prefer_index_operator, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferRangeOperator, description: CSharpEditorResources.Prefer_range_operator, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetPatternMatchingCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferPatternMatching, description: CSharpEditorResources.Prefer_pattern_matching, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferPatternMatchingOverIsWithCastCheck, description: CSharpEditorResources.Prefer_pattern_matching_over_is_with_cast_check, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferPatternMatchingOverAsWithNullCheck, description: CSharpEditorResources.Prefer_pattern_matching_over_as_with_null_check, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferNotPattern, description: CSharpEditorResources.Prefer_pattern_matching_over_mixed_type_check, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetVariableCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferInlinedVariableDeclaration, description: CSharpEditorResources.Prefer_inlined_variable_declaration, editorConfigOptions, visualStudioOptions, updaterService); + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferDeconstructedVariableDeclaration, description: CSharpEditorResources.Prefer_deconstructed_variable_declaration, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetExpressionBodyCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + var enumValues = new[] { ExpressionBodyPreference.Never, ExpressionBodyPreference.WhenPossible, ExpressionBodyPreference.WhenOnSingleLine }; + var valueDescriptions = new[] { CSharpEditorResources.Never, CSharpEditorResources.When_possible, CSharpEditorResources.When_on_single_line }; + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedMethods, + description: CSharpEditorResources.Use_expression_body_for_methods, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, + description: CSharpEditorResources.Use_expression_body_for_constructors, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedOperators, + description: CSharpEditorResources.Use_expression_body_for_operators, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedProperties, + description: CSharpEditorResources.Use_expression_body_for_properties, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedIndexers, + description: CSharpEditorResources.Use_expression_body_for_indexers, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, + description: CSharpEditorResources.Use_expression_body_for_accessors, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedLambdas, + description: CSharpEditorResources.Use_expression_body_for_lambdas, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + yield return CodeStyleSetting.Create(option: CSharpCodeStyleOptions.PreferExpressionBodiedLocalFunctions, + description: CSharpEditorResources.Use_expression_body_for_local_functions, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: editorConfigOptions, + visualStudioOptions: visualStudioOptions, updater: updaterService); + } + + private static IEnumerable GetUnusedValueCodeStyleOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + var enumValues = new[] + { + UnusedValuePreference.UnusedLocalVariable, + UnusedValuePreference.DiscardVariable + }; + + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.UnusedValueAssignment, + description: CSharpEditorResources.Avoid_unused_value_assignments, + enumValues, + new[] { CSharpEditorResources.Unused_local, CSharpEditorResources.Discard }, + editorConfigOptions, + visualStudioOptions, + updaterService); + + yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.UnusedValueExpressionStatement, + description: CSharpEditorResources.Avoid_expression_statements_that_implicitly_ignore_value, + enumValues, + new[] { CSharpEditorResources.Unused_local, CSharpEditorResources.Discard }, + editorConfigOptions, + visualStudioOptions, + updaterService); + } + } +} diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProviderFactory.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProviderFactory.cs new file mode 100644 index 0000000000000..1af8c72ade4d0 --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProviderFactory.cs @@ -0,0 +1,21 @@ +// 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; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.CodeStyle +{ + internal class CSharpCodeStyleSettingsProviderFactory : ILanguageSettingsProviderFactory + { + private readonly Workspace _workspace; + + public CSharpCodeStyleSettingsProviderFactory(Workspace workspace) => _workspace = workspace; + + public ISettingsProvider GetForFile(string filePath) + => new CSharpCodeStyleSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace); + } +} diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsLanguageServiceFactory.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsLanguageServiceFactory.cs new file mode 100644 index 0000000000000..550c7bf77b32a --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsLanguageServiceFactory.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 System; +using System.Composition; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.Formatting +{ + [ExportLanguageServiceFactory(typeof(ILanguageSettingsProviderFactory), LanguageNames.CSharp), Shared] + internal class CSharpFormattingSettingsLanguageServiceFactory : ILanguageServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpFormattingSettingsLanguageServiceFactory() + { + } + + public ILanguageService CreateLanguageService(HostLanguageServices languageServices) + { + var workspace = languageServices.WorkspaceServices.Workspace; + return new CSharpFormattingSettingsProviderFactory(workspace); + } + } +} diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProvider.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProvider.cs new file mode 100644 index 0000000000000..00341120f9c72 --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProvider.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.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.CSharp; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.Formatting +{ + internal class CSharpFormattingSettingsProvider : SettingsProviderBase + { + public CSharpFormattingSettingsProvider(string filePath, OptionUpdater updaterService, Workspace workspace) + : base(filePath, updaterService, workspace) + { + Update(); + } + + protected override void UpdateOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions) + { + var spacingOptions = GetSpacingOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(spacingOptions.ToImmutableArray()); + var newLineOptions = GetNewLineOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(newLineOptions.ToImmutableArray()); + var indentationOptions = GetIndentationOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(indentationOptions.ToImmutableArray()); + var wrappingOptions = GetWrappingOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(wrappingOptions.ToImmutableArray()); + } + + private static IEnumerable GetSpacingOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpacingAfterMethodDeclarationName, CSharpEditorResources.Insert_space_between_method_name_and_its_opening_parenthesis2, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinMethodDeclarationParenthesis, CSharpEditorResources.Insert_space_within_parameter_list_parentheses, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBetweenEmptyMethodDeclarationParentheses, CSharpEditorResources.Insert_space_within_empty_parameter_list_parentheses, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterMethodCallName, CSharpEditorResources.Insert_space_between_method_name_and_its_opening_parenthesis1, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinMethodCallParentheses, CSharpEditorResources.Insert_space_within_argument_list_parentheses, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBetweenEmptyMethodCallParentheses, CSharpEditorResources.Insert_space_within_empty_argument_list_parentheses, editorConfigOptions, visualStudioOptions, updaterService); + + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterControlFlowStatementKeyword, CSharpEditorResources.Insert_space_after_keywords_in_control_flow_statements, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinExpressionParentheses, CSharpEditorResources.Insert_space_within_parentheses_of_expressions, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinCastParentheses, CSharpEditorResources.Insert_space_within_parentheses_of_type_casts, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinOtherParentheses, CSharpEditorResources.Insert_spaces_within_parentheses_of_control_flow_statements, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterCast, CSharpEditorResources.Insert_space_after_cast, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpacesIgnoreAroundVariableDeclaration, CSharpEditorResources.Ignore_spaces_in_declaration_statements, editorConfigOptions, visualStudioOptions, updaterService); + + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBeforeOpenSquareBracket, CSharpEditorResources.Insert_space_before_open_square_bracket, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBetweenEmptySquareBrackets, CSharpEditorResources.Insert_space_within_empty_square_brackets, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceWithinSquareBrackets, CSharpEditorResources.Insert_spaces_within_square_brackets, editorConfigOptions, visualStudioOptions, updaterService); + + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterColonInBaseTypeDeclaration, CSharpEditorResources.Insert_space_after_colon_for_base_or_interface_in_type_declaration, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterComma, CSharpEditorResources.Insert_space_after_comma, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterDot, CSharpEditorResources.Insert_space_after_dot, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceAfterSemicolonsInForStatement, CSharpEditorResources.Insert_space_after_semicolon_in_for_statement, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBeforeColonInBaseTypeDeclaration, CSharpEditorResources.Insert_space_before_colon_for_base_or_interface_in_type_declaration, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBeforeComma, CSharpEditorResources.Insert_space_before_comma, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBeforeDot, CSharpEditorResources.Insert_space_before_dot, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpaceBeforeSemicolonsInForStatement, CSharpEditorResources.Insert_space_before_semicolon_in_for_statement, editorConfigOptions, visualStudioOptions, updaterService); + + yield return FormattingSetting.Create(CSharpFormattingOptions2.SpacingAroundBinaryOperator, CSharpEditorResources.Set_spacing_for_operators, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetNewLineOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInTypes, CSharpEditorResources.Place_open_brace_on_new_line_for_types, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInMethods, CSharpEditorResources.Place_open_brace_on_new_line_for_methods_local_functions, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInProperties, CSharpEditorResources.Place_open_brace_on_new_line_for_properties_indexers_and_events, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInAccessors, CSharpEditorResources.Place_open_brace_on_new_line_for_property_indexer_and_event_accessors, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInAnonymousMethods, CSharpEditorResources.Place_open_brace_on_new_line_for_anonymous_methods, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInControlBlocks, CSharpEditorResources.Place_open_brace_on_new_line_for_control_blocks, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInAnonymousTypes, CSharpEditorResources.Place_open_brace_on_new_line_for_anonymous_types, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInObjectCollectionArrayInitializers, CSharpEditorResources.Place_open_brace_on_new_line_for_object_collection_array_and_with_initializers, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLinesForBracesInLambdaExpressionBody, CSharpEditorResources.Place_open_brace_on_new_line_for_lambda_expression, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForElse, CSharpEditorResources.Place_else_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForCatch, CSharpEditorResources.Place_catch_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForFinally, CSharpEditorResources.Place_finally_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForMembersInObjectInit, CSharpEditorResources.Place_members_in_object_initializers_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForMembersInAnonymousTypes, CSharpEditorResources.Place_members_in_anonymous_types_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.NewLineForClausesInQuery, CSharpEditorResources.Place_query_expression_clauses_on_new_line, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetIndentationOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return FormattingSetting.Create(CSharpFormattingOptions2.IndentBlock, CSharpEditorResources.Indent_block_contents, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.IndentBraces, CSharpEditorResources.Indent_open_and_close_braces, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.IndentSwitchCaseSection, CSharpEditorResources.Indent_case_contents, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.IndentSwitchCaseSectionWhenBlock, CSharpEditorResources.Indent_case_contents_when_block, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.IndentSwitchSection, CSharpEditorResources.Indent_case_labels, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.LabelPositioning, CSharpEditorResources.Label_Indentation, editorConfigOptions, visualStudioOptions, updaterService); + } + + private static IEnumerable GetWrappingOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updaterService) + { + yield return FormattingSetting.Create(CSharpFormattingOptions2.WrappingPreserveSingleLine, CSharpEditorResources.Leave_block_on_single_line, editorConfigOptions, visualStudioOptions, updaterService); + yield return FormattingSetting.Create(CSharpFormattingOptions2.WrappingKeepStatementsOnSingleLine, CSharpEditorResources.Leave_statements_and_member_declarations_on_the_same_line, editorConfigOptions, visualStudioOptions, updaterService); + } + } +} diff --git a/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProviderFactory.cs b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProviderFactory.cs new file mode 100644 index 0000000000000..543617276493a --- /dev/null +++ b/src/EditorFeatures/CSharp/EditorConfigSettings/DataProvider/Formatting/CSharpFormattingSettingsProviderFactory.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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings.DataProvider.Formatting +{ + internal class CSharpFormattingSettingsProviderFactory : ILanguageSettingsProviderFactory + { + private readonly Workspace _workspace; + + public CSharpFormattingSettingsProviderFactory(Workspace workspace) + { + _workspace = workspace; + } + + public ISettingsProvider GetForFile(string filePath) + { + var updaterService = new OptionUpdater(_workspace, filePath); + return new CSharpFormattingSettingsProvider(filePath, updaterService, _workspace); + } + } +} diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf index a53460dd12507..a07969485d458 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.cs.xlf @@ -12,6 +12,16 @@ Přidávají se chybějící direktivy using... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Zvolená verze: {0} @@ -32,11 +42,26 @@ Protokol o dekompilaci + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Opravit interpolovaný doslovný řetězec + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Pro {1} se našlo několik ({0}) sestavení: @@ -62,6 +87,166 @@ Generovat odběr událostí + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Načíst z {0} @@ -72,6 +257,181 @@ Modul se nenašel! + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Pro vložení stiskněte TAB.) @@ -87,6 +447,11 @@ Přeložit modul: {0} z {1} + + Set spacing for operators + Set spacing for operators + + Smart Indenting Chytré odsazování @@ -97,11 +462,71 @@ Rozdělit řetězec + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' UPOZORNĚNÍ: Neshoda verzí. Očekáváno: {0}, získáno: {1} + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache Počet položek v mezipaměti: {0} diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf index 59b46f4f98c59..f83defa306236 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.de.xlf @@ -12,6 +12,16 @@ Fehlende using-Anweisungen werden hinzugefügt... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Ausgewählte Version: {0} @@ -32,11 +42,26 @@ Dekompilierungsprotokoll + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Interpolierte ausführliche Zeichenfolge korrigieren + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': {0} Assemblys für "{1}" gefunden: @@ -62,6 +87,166 @@ Ereignisabonnement generieren + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Laden von: {0} @@ -72,6 +257,181 @@ Das Modul wurde nicht gefunden. + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Zum Einfügen TAB-TASTE drücken) @@ -87,6 +447,11 @@ Modul auflösen: {0} von {1} + + Set spacing for operators + Set spacing for operators + + Smart Indenting Intelligenter Einzug @@ -97,11 +462,71 @@ Zeichenfolge teilen + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' WARNUNG: Versionskonflikt. Erwartet: "{0}", erhalten: "{1}" + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache {0} Elemente im Cache diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf index ac2c95c4042de..ca9a0cd38dd0d 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.es.xlf @@ -12,6 +12,16 @@ Agregando los valores using que faltan... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Versión elegida: "{0}" @@ -32,11 +42,26 @@ Registro de descompilación + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Corregir cadena textual interpolada + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Se encontraron "{0}" ensamblados para "{1}": @@ -62,6 +87,166 @@ Generar suscripción de eventos + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Cargar desde: "{0}" @@ -72,6 +257,181 @@ No se encontró el módulo. + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Presione TAB para insertar) @@ -87,6 +447,11 @@ Resolver el módulo: "{0}" de "{1}" + + Set spacing for operators + Set spacing for operators + + Smart Indenting Sangría inteligente @@ -97,11 +462,71 @@ Dividir cadena + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' AVISO: No coinciden las versiones. Se esperaba "{0}", se obtuvo "{1}" + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache "{0}" elementos en caché diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf index 507debfc81da8..71feeb87ccb24 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.fr.xlf @@ -12,6 +12,16 @@ Ajout des usings manquants... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Version choisie : '{0}' @@ -32,11 +42,26 @@ Journal de décompilation + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Corriger la chaîne verbatim interpolée + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': '{0}' assemblys trouvés pour '{1}' : @@ -62,6 +87,166 @@ Générer un abonnement à des événements + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Charger à partir de : '{0}' @@ -72,6 +257,181 @@ Module introuvable ! + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Appuyez sur TAB pour insérer) @@ -87,6 +447,11 @@ Résoudre le module '{0}' sur '{1}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting Retrait intelligent @@ -97,11 +462,71 @@ Fractionner la chaîne + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' AVERTISSEMENT : Incompatibilité de version. Attendu : '{0}'. Reçu : '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache '{0}' éléments dans le cache diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf index b79f46f23136b..21c83449bca2e 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.it.xlf @@ -12,6 +12,16 @@ Aggiunta di using mancanti... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Versione selezionata: '{0}' @@ -32,11 +42,26 @@ Log di decompilazione + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Correggi stringa verbatim interpolata + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Sono stati trovati '{0}' assembly per '{1}': @@ -62,6 +87,166 @@ Genera sottoscrizione di eventi + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Carica da: '{0}' @@ -72,6 +257,181 @@ Modulo non trovato. + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Premere TAB per inserire) @@ -87,6 +447,11 @@ Risolvi il modulo: '{0}' di '{1}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting Rientro automatico @@ -97,11 +462,71 @@ Dividi stringa + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' AVVISO: versione non corrispondente. Prevista: '{0}'. Ottenuta: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache '{0}' elementi nella cache diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf index 3a15f023b5aa7..a2619effa7f17 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ja.xlf @@ -12,6 +12,16 @@ 欠落している usings を追加しています... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' 選択されたバージョン: '{0}' @@ -32,11 +42,26 @@ 逆コンパイルのログ + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string 挿入された逐語的文字列を修正します + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': '{1}' の '{0}' 個のアセンブリが見つかりました: @@ -62,6 +87,166 @@ イベント サブスクリプションの生成 + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' 読み込み元: '{0}' @@ -72,6 +257,181 @@ モジュールが見つかりません + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Tab キーを押して挿入) @@ -87,6 +447,11 @@ モジュールの解決: '{1}' の '{0}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting スマート インデント @@ -97,11 +462,71 @@ 文字列を分割します + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' 警告: バージョンが一致しません。必要なバージョン: '{0}'、現在のバージョン: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache キャッシュ内の '{0}' 個の項目 diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf index bd89b0cb2c745..b5f3de05a1c71 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ko.xlf @@ -12,6 +12,16 @@ 누락된 using 추가 중... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' 선택한 버전: '{0}' @@ -32,11 +42,26 @@ 디컴파일 로그 + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string 보간된 축자 문자열 수정 + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': '{1}'의 어셈블리를 '{0}'개 찾았습니다. @@ -62,6 +87,166 @@ 이벤트 구독 생성 + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' 로드 위치: '{0}' @@ -72,6 +257,181 @@ 모듈을 찾을 수 없습니다. + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (삽입하려면 <Tab> 키 누름) @@ -87,6 +447,11 @@ 모듈 확인: '{0}'/'{1}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting 스마트 들여쓰기 @@ -97,11 +462,71 @@ 문자열 분할 + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' WARN: 버전이 일치하지 않습니다. 예상: '{0}', 실제: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache 캐시의 '{0}'개 항목 diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf index f00d3e310b8f7..1dd96fe018a20 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pl.xlf @@ -12,6 +12,16 @@ Trwa dodawanie brakujących dyrektyw using... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Wybrana wersja: „{0}” @@ -32,11 +42,26 @@ Dziennik dekompilacji + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Napraw interpolowany ciąg dosłowny wyrażenia + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Znaleziono zestawy („{0}”) dla elementu „{1}”: @@ -62,6 +87,166 @@ Generuj subskrypcję zdarzenia + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Załaduj z: „{0}” @@ -72,6 +257,181 @@ Nie znaleziono modułu. + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Naciśnij klawisz TAB, aby wstawić) @@ -87,6 +447,11 @@ Rozpoznaj moduł: „{0}” z „{1}” + + Set spacing for operators + Set spacing for operators + + Smart Indenting Inteligentne tworzenie wcięć @@ -97,11 +462,71 @@ Rozdziel ciąg + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' OSTRZEŻENIE: niezgodność wersji. Oczekiwano: „{0}”, uzyskano: „{1}” + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache Elementy w pamięci podręcznej: „{0}” diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf index 231aca00a20ae..248bf1ba90a5c 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.pt-BR.xlf @@ -12,6 +12,16 @@ Adicionando as usings ausentes... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Versão escolhida: '{0}' @@ -32,11 +42,26 @@ Log de descompilação + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Corrigir cadeia de caracteres verbatim interpolada + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Foram encontrados '{0}' assemblies para '{1}': @@ -62,6 +87,166 @@ Gerar Assinatura de Evento + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Carregar de: '{0}' @@ -72,6 +257,181 @@ Módulo não encontrado. + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Pressione TAB para inserir) @@ -87,6 +447,11 @@ Resolver o módulo: '{0}' de '{1}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting Recuo Inteligente @@ -97,11 +462,71 @@ Dividir cadeia de caracteres + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' AVISO: incompatibilidade de versão. Esperado: '{0}', Obtido: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache '{0}' itens no cache diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf index b1a1ee7d0a8d7..965ebbbf69613 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.ru.xlf @@ -12,6 +12,16 @@ Добавление недостающих директив using… Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Выбранная версия: "{0}" @@ -32,11 +42,26 @@ Журнал декомпиляции + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Исправить интерполированную буквальную строку + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': Обнаружены сборки ("{0}") для "{1}": @@ -62,6 +87,166 @@ Создать подписку на события + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Загрузить из: "{0}" @@ -72,6 +257,181 @@ Модуль не найден. + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Нажмите клавишу TAB для вставки) @@ -87,6 +447,11 @@ Разрешить модуль: "{0}" из "{1}" + + Set spacing for operators + Set spacing for operators + + Smart Indenting Интеллектуальные отступы @@ -97,11 +462,71 @@ Разделить строку + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' Внимание! Несовпадение версий. Ожидалось: "{0}", получено: "{1}" + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache Элементов в кэше: "{0}" diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf index 0710b15a98b3a..9ff6a72081600 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.tr.xlf @@ -12,6 +12,16 @@ Eksik using yönergeleri ekleniyor... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' Seçilen sürüm: '{0}' @@ -32,11 +42,26 @@ Kaynak koda dönüştürme günlüğü + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string Ara değer olarak eklenmiş tam dizeyi düzelt + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': '{1}' için '{0}' bütünleştirilmiş kod bulundu: @@ -62,6 +87,166 @@ Olay Aboneliği Oluştur + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' Şuradan yükle: '{0}' @@ -72,6 +257,181 @@ Modül bulunamadı! + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (Eklemek için TAB tuşuna basın) @@ -87,6 +447,11 @@ '{1}' modül içinden '{0}' modülü çözümle + + Set spacing for operators + Set spacing for operators + + Smart Indenting Akıllı Girintileme @@ -97,11 +462,71 @@ Dizeyi böl + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' UYARI: Sürüm uyumsuzluğu. Beklenen: '{0}', Alınan: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache Önbellekteki '{0}' öğe diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf index ec33113284dae..ead8ce446a96d 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hans.xlf @@ -12,6 +12,16 @@ 正在添加缺少的 usings… Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' 所选版本: "{0}" @@ -32,11 +42,26 @@ 反编译日志 + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string 修复插值的逐字字符串 + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': 找到 “{1}”的“{0}”个程序集: @@ -62,6 +87,166 @@ 生成事件订阅 + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' 从以下位置加载: "{0}" @@ -72,6 +257,181 @@ 找不到模块! + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (按 Tab 插入) @@ -87,6 +447,11 @@ 解析模块: "{0}" 个(共 "{1}" 个) + + Set spacing for operators + Set spacing for operators + + Smart Indenting 智能缩进 @@ -97,11 +462,71 @@ 拆分字符串 + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' 警告: 版本不匹配。应为: "{0}",实际为: "{1}" + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache 缓存中的 {0} 项 diff --git a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf index 82cf331bbb813..0bb3db86969f4 100644 --- a/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf +++ b/src/EditorFeatures/CSharp/xlf/CSharpEditorResources.zh-Hant.xlf @@ -12,6 +12,16 @@ 正在新增缺少的 using... Shown in a thread await dialog. "usings" is a language specific term and should not be localized + + Avoid expression statements that implicitly ignore value + Avoid expression statements that implicitly ignore value + + + + Avoid unused value assignments + Avoid unused value assignments + + Chosen version: '{0}' 選擇的版本: '{0}' @@ -32,11 +42,26 @@ 反向組譯記錄檔 + + Discard + Discard + + + + Elsewhere + Elsewhere + + Fix interpolated verbatim string 修正插入的逐字字串 + + For built-in types + For built-in types + + Found '{0}' assemblies for '{1}': 找到 '{0}' 個 '{1}' 的組件: @@ -62,6 +87,166 @@ 產生事件訂閱 + + Ignore spaces in declaration statements + Ignore spaces in declaration statements + + + + Indent block contents + Indent block contents + + + + Indent case contents + Indent case contents + + + + Indent case contents (when block) + Indent case contents (when block) + + + + Indent case labels + Indent case labels + + + + Indent open and close braces + Indent open and close braces + + + + Insert space after cast + Insert space after cast + + + + Insert space after colon for base or interface in type declaration + Insert space after colon for base or interface in type declaration + + + + Insert space after comma + Insert space after comma + + + + Insert space after dot + Insert space after dot + + + + Insert space after keywords in control flow statements + Insert space after keywords in control flow statements + + + + Insert space after semicolon in "for" statement + Insert space after semicolon in "for" statement + + + + Insert space before colon for base or interface in type declaration + Insert space before colon for base or interface in type declaration + + + + Insert space before comma + Insert space before comma + + + + Insert space before dot + Insert space before dot + + + + Insert space before open square bracket + Insert space before open square bracket + + + + Insert space before semicolon in "for" statement + Insert space before semicolon in "for" statement + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space between method name and its opening parenthesis + Insert space between method name and its opening parenthesis + + + + Insert space within argument list parentheses + Insert space within argument list parentheses + + + + Insert space within empty argument list parentheses + Insert space within empty argument list parentheses + + + + Insert space within empty parameter list parentheses + Insert space within empty parameter list parentheses + + + + Insert space within empty square brackets + Insert space within empty square brackets + + + + Insert space within parameter list parentheses + Insert space within parameter list parentheses + + + + Insert space within parentheses of expressions + Insert space within parentheses of expressions + + + + Insert space within parentheses of type casts + Insert space within parentheses of type casts + + + + Insert spaces within parentheses of control flow statements + Insert spaces within parentheses of control flow statements + + + + Insert spaces within square brackets + Insert spaces within square brackets + + + + Inside namespace + Inside namespace + + + + Label Indentation + Label Indentation + + + + Leave block on single line + Leave block on single line + + + + Leave statements and member declarations on the same line + Leave statements and member declarations on the same line + + Load from: '{0}' 載入來源: '{0}' @@ -72,6 +257,181 @@ 找不到模組! + + Never + Never + + + + Outside namespace + Outside namespace + + + + Place "catch" on new line + Place "catch" on new line + + + + Place "else" on new line + Place "else" on new line + + + + Place "finally" on new line + Place "finally" on new line + + + + Place members in anonymous types on new line + Place members in anonymous types on new line + + + + Place members in object initializers on new line + Place members in object initializers on new line + + + + Place open brace on new line for anonymous methods + Place open brace on new line for anonymous methods + + + + Place open brace on new line for anonymous types + Place open brace on new line for anonymous types + + + + Place open brace on new line for control blocks + Place open brace on new line for control blocks + + + + Place open brace on new line for lambda expression + Place open brace on new line for lambda expression + + + + Place open brace on new line for methods and local functions + Place open brace on new line for methods and local functions + + + + Place open brace on new line for object, collection, array, and with initializers + Place open brace on new line for object, collection, array, and with initializers + + + + Place open brace on new line for properties, indexers, and events + Place open brace on new line for properties, indexers, and events + + + + Place open brace on new line for property, indexer, and event accessors + Place open brace on new line for property, indexer, and event accessors + + + + Place open brace on new line for types + Place open brace on new line for types + + + + Place query expression clauses on new line + Place query expression clauses on new line + + + + Prefer conditional delegate call + Prefer conditional delegate call + + + + Prefer deconstructed variable declaration + Prefer deconstructed variable declaration + + + + Prefer explicit type + Prefer explicit type + + + + Prefer index operator + Prefer index operator + + + + Prefer inlined variable declaration + Prefer inlined variable declaration + + + + Prefer local function over anonymous function + Prefer local function over anonymous function + + + + Prefer pattern matching + Prefer pattern matching + + + + Prefer pattern matching over 'as' with 'null' check + Prefer pattern matching over 'as' with 'null' check + + + + Prefer pattern matching over 'is' with 'cast' check + Prefer pattern matching over 'is' with 'cast' check + + + + Prefer pattern matching over mixed type check + Prefer pattern matching over mixed type check + + + + Prefer range operator + Prefer range operator + + + + Prefer simple 'default' expression + Prefer simple 'default' expression + + + + Prefer simple 'using' statement + Prefer simple 'using' statement + + + + Prefer static local functions + Prefer static local functions + + + + Prefer switch expression + Prefer switch expression + + + + Prefer throw-expression + Prefer throw-expression + + + + Prefer 'var' + Prefer 'var' + + + + Preferred 'using' directive placement + Preferred 'using' directive placement + + (Press TAB to insert) (按 TAB 鍵插入) @@ -87,6 +447,11 @@ 解析模組: '{0}' 之 '{1}' + + Set spacing for operators + Set spacing for operators + + Smart Indenting 智慧縮排 @@ -97,11 +462,71 @@ 分割字串 + + Unused local + Unused local + + + + Use expression body for accessors + Use expression body for accessors + + + + Use expression body for constructors + Use expression body for constructors + + + + Use expression body for indexers + Use expression body for indexers + + + + Use expression body for lambdas + Use expression body for lambdas + + + + Use expression body for local functions + Use expression body for local functions + + + + Use expression body for methods + Use expression body for methods + + + + Use expression body for operators + Use expression body for operators + + + + Use expression body for properties + Use expression body for properties + + WARN: Version mismatch. Expected: '{0}', Got: '{1}' 警告: 版本不符。應為: '{0}',但取得: '{1}' + + When on single line + When on single line + + + + When possible + When possible + + + + When variable type is apparent + When variable type is apparent + + '{0}' items in cache 快取中有 '{0}' 個項目 diff --git a/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs index d14f570e32bc4..5cc4a557cf81a 100644 --- a/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/CompleteStatement/CSharpCompleteStatementCommandHandlerTests.cs @@ -6,6 +6,7 @@ using System.Linq; using Microsoft.CodeAnalysis.Editor.CSharp.CompleteStatement; +using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Editor.UnitTests.CompleteStatement; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Test.Utilities; @@ -2399,6 +2400,58 @@ void M() VerifyTypingSemicolon(code, expected); } + [WpfTheory, Trait(Traits.Feature, Traits.Features.CompleteStatement)] + [WorkItem(52137, "https://github.com/dotnet/roslyn/issues/52137")] + [InlineData("typeof(object$$)", "typeof(object)")] + [InlineData("typeof($$object)", "typeof(object)")] + public void TypeOfExpression_Handled(string expression, string expectedExpression) + { + var code = $@" +public class Class1 +{{ + void M() + {{ + var x = {expression} + }} +}}"; + + var expected = $@" +public class Class1 +{{ + void M() + {{ + var x = {expectedExpression};$$ + }} +}}"; + + VerifyTypingSemicolon(code, expected); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.CompleteStatement)] + [WorkItem(52365, "https://github.com/dotnet/roslyn/issues/52365")] + public void TupleExpression_Handled() + { + var code = @" +public class Class1 +{ + void M() + { + var x = (0, 0$$) + } +}"; + + var expected = @" +public class Class1 +{ + void M() + { + var x = (0, 0);$$ + } +}"; + + VerifyTypingSemicolon(code, expected); + } + [WpfTheory, Trait(Traits.Feature, Traits.Features.CompleteStatement)] [InlineData("default$$(object)")] [InlineData("def$$ault(object)")] @@ -4082,6 +4135,30 @@ public Delegate Task Handles(int num)$$ VerifyNoSpecialSemicolonHandling(code); } + [WpfFact, Trait(Traits.Feature, Traits.Features.CompleteStatement)] + [WorkItem(37874, "https://github.com/dotnet/roslyn/pull/37874")] + public void TestWithSettingTurnedOff() + { + var code = @" +public class ClassC +{ + private int xValue = 7; + public int XValue + { + get + { + return Math.Min(xValue$$, 1) + } + } +}"; + var expected = code.Replace("$$", ";$$"); + + Verify(code, expected, ExecuteTest, + setOptionsOpt: workspace => + { + workspace.SetOptions(workspace.Options.WithChangedOption(FeatureOnOffOptions.AutomaticallyCompleteStatementOnSemicolon, false)); + }); + } protected override TestWorkspace CreateTestWorkspace(string code) => TestWorkspace.CreateCSharp(code); } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs index bb8bfd3db76ec..26f5f83d83b26 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs @@ -38,14 +38,14 @@ private protected override Task BaseVerifyWorkerAsync( string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription = null, + string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { return base.VerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); } private protected override async Task VerifyWorkerAsync( @@ -54,19 +54,19 @@ 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, - List matchingFilters = null, CompletionItemFlags? flags = null) + bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { - await VerifyAtPositionAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, matchingFilters); - await VerifyInFrontOfCommentAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, matchingFilters); - await VerifyAtEndOfFileAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, matchingFilters); + 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 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, matchingFilters); - await VerifyInFrontOfComment_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, matchingFilters); - await VerifyAtEndOfFile_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, matchingFilters); + 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 VerifyAtEndOfFile_ItemPartiallyWrittenAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); } } @@ -78,7 +78,7 @@ private Task VerifyInFrontOfCommentAsync( string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription, List matchingFilters) + string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, List matchingFilters) { code = code.Substring(0, position) + insertText + "/**/" + code.Substring(position); position += insertText.Length; @@ -87,7 +87,7 @@ private Task VerifyInFrontOfCommentAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, - inlineDescription, matchingFilters, flags: null); + inlineDescription, isComplexTextEdit, matchingFilters, flags: null); } private Task VerifyInFrontOfCommentAsync( @@ -95,13 +95,14 @@ private Task VerifyInFrontOfCommentAsync( string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription, List matchingFilters) + string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, + List matchingFilters) { return VerifyInFrontOfCommentAsync( code, position, string.Empty, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); } private protected Task VerifyInFrontOfComment_ItemPartiallyWrittenAsync( @@ -109,13 +110,14 @@ private protected Task VerifyInFrontOfComment_ItemPartiallyWrittenAsync( string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription, List matchingFilters) + string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, + List matchingFilters) { return VerifyInFrontOfCommentAsync( code, position, ItemPartiallyWritten(expectedItemOrNull), usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); } protected static string AddInsideMethod(string text) diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ConversionCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ConversionCompletionProviderTests.cs index 043bdd78b4f23..f25ebc09047f0 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ConversionCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ConversionCompletionProviderTests.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion; using Microsoft.CodeAnalysis.Test.Utilities; @@ -147,12 +146,12 @@ public static void Main() [InlineData("c?.$$", true)] [InlineData("((C)c).$$", true)] [InlineData("(true ? c : c).$$", true)] - [InlineData("c.$$ var x=0;", false)] + [InlineData("c.$$ var x=0;", true)] public async Task ExplicitUserDefinedConversionDifferentExpressions(string expression, bool shouldSuggestConversion) { Func verifyFunc = shouldSuggestConversion ? (markup, expectedItem) => VerifyItemExistsAsync(markup, expectedItem, displayTextPrefix: "(", displayTextSuffix: ")") - : (markup, expectedItem) => VerifyItemIsAbsentAsync(markup, expectedItem); + : (markup, expectedItem) => VerifyItemIsAbsentAsync(markup, expectedItem, displayTextPrefix: "(", displayTextSuffix: ")"); await verifyFunc(@$" public class C @@ -1564,5 +1563,95 @@ await VerifyItemInEditorBrowsableContextsAsync( referencedLanguage: LanguageNames.CSharp, hideAdvancedMembers: true); } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(47511, "https://github.com/dotnet/roslyn/issues/47511")] + public async Task ExplicitUserDefinedConversionOfNullableStructAccessViaNullcondionalOffersLiftedConversion() + { + await VerifyCustomCommitProviderAsync(@" +public struct S { + public static explicit operator int(S s) => 0; +} +public class Program +{ + public static void Main() + { + S? s = null; + var i = ((S?)s)?.$$ + } +} +", "int?", @" +public struct S { + public static explicit operator int(S s) => 0; +} +public class Program +{ + public static void Main() + { + S? s = null; + var i = ((int?)((S?)s))?$$ + } +} +"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(47511, "https://github.com/dotnet/roslyn/issues/47511")] + public async Task ExplicitUserDefinedConversionOfPropertyNamedLikeItsTypeIsHandled() + { + await VerifyCustomCommitProviderAsync(@" +public struct S { + public static explicit operator int(S s) => 0; +} +public class C { + public S S { get; } +} +public class Program +{ + public static void Main() + { + var c = new C(); + var i = c.S.$$ + } +} +", "int", @" +public struct S { + public static explicit operator int(S s) => 0; +} +public class C { + public S S { get; } +} +public class Program +{ + public static void Main() + { + var c = new C(); + var i = ((int)c.S)$$ + } +} +"); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(47511, "https://github.com/dotnet/roslyn/issues/47511")] + public async Task ExplicitUserDefinedConversionOfDerefenrencedPointerIsNotOffered() + { + await VerifyNoItemsExistAsync(@" +public struct S { + public static explicit operator int(S s) => 0; +} +public class Program +{ + public static void Main() + { + unsafe{ + var s = new S(); + S* p = &s; + var i = p->$$; + } + } +} +"); + } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs index 77017fffe023a..b9e38257411fe 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/CrefCompletionProviderTests.cs @@ -33,18 +33,18 @@ private protected override async Task VerifyWorkerAsync( string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription = null, + string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { await VerifyAtPositionAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, - matchingFilters, flags); + isComplexTextEdit, matchingFilters, flags); await VerifyAtEndOfFileAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, - matchingFilters, flags); + isComplexTextEdit, matchingFilters, flags); // 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) @@ -53,12 +53,12 @@ await VerifyAtEndOfFileAsync( await VerifyAtPosition_ItemPartiallyWrittenAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); await VerifyAtEndOfFile_ItemPartiallyWrittenAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters); } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs index 3ca7347fd4759..1362cc9ea5e5c 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ExtensionMethodImportCompletionProviderTests.cs @@ -2043,7 +2043,7 @@ await VerifyImportItemExistsAsync( } private Task VerifyImportItemExistsAsync(string markup, string expectedItem, string inlineDescription, int? glyph = null, string displayTextSuffix = null, string expectedDescriptionOrNull = null, List expectedFilters = null) - => VerifyItemExistsAsync(markup, expectedItem, displayTextSuffix: displayTextSuffix, glyph: glyph, inlineDescription: inlineDescription, expectedDescriptionOrNull: expectedDescriptionOrNull, matchingFilters: expectedFilters); + => VerifyItemExistsAsync(markup, expectedItem, displayTextSuffix: displayTextSuffix, glyph: glyph, inlineDescription: inlineDescription, expectedDescriptionOrNull: expectedDescriptionOrNull, isComplexTextEdit: true, matchingFilters: expectedFilters); private Task VerifyImportItemIsAbsentAsync(string markup, string expectedItem, string inlineDescription, string displayTextSuffix = null) => VerifyItemIsAbsentAsync(markup, expectedItem, displayTextSuffix: displayTextSuffix, inlineDescription: inlineDescription); diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs index 3e42867ded91d..d119c087b2161 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/LoadDirectiveCompletionProviderTests.cs @@ -32,14 +32,14 @@ private protected override Task VerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription = null, + string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { return BaseVerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs index 12a4afd49e9d8..178e2bb855d32 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs @@ -3146,5 +3146,10 @@ record Program : Base override $$ }", "ToString()"); } + + private Task VerifyItemExistsAsync(string markup, string expectedItem) + { + return VerifyItemExistsAsync(markup, expectedItem, isComplexTextEdit: true); + } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs index 3fec045d3d119..3c25273d529b6 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/PartialMethodCompletionProviderTests.cs @@ -835,5 +835,10 @@ partial class Bar await VerifyCustomCommitProviderAsync(text, "Foo()", expected); } + + private Task VerifyItemExistsAsync(string markup, string expectedItem) + { + return VerifyItemExistsAsync(markup, expectedItem, isComplexTextEdit: true); + } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs index 0825022d2f3e3..93f5c0bcb1731 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ReferenceDirectiveCompletionProviderTests.cs @@ -36,14 +36,14 @@ private protected override Task VerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription = null, + string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { return BaseVerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs index 361a3072fad63..db05b1db2f6ce 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests_NoInteractive.cs @@ -29,14 +29,14 @@ private protected override Task VerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription, List matchingFilters, - CompletionItemFlags? flags = null) + string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, + List matchingFilters, CompletionItemFlags? flags = null) { return base.VerifyWorkerAsync(code, position, expectedItemOrNull, expectedDescriptionOrNull, SourceCodeKind.Regular, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); } [Fact, Trait(Traits.Feature, Traits.Features.Completion)] diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs index 61cf9343de22a..606e8c0377bd0 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.cs @@ -1787,7 +1787,7 @@ public void M() } private Task VerifyTypeImportItemExistsAsync(string markup, string expectedItem, int glyph, string inlineDescription, string displayTextSuffix = null, string expectedDescriptionOrNull = null, CompletionItemFlags? flags = null) - => VerifyItemExistsAsync(markup, expectedItem, displayTextSuffix: displayTextSuffix, glyph: glyph, inlineDescription: inlineDescription, expectedDescriptionOrNull: expectedDescriptionOrNull, flags: flags); + => VerifyItemExistsAsync(markup, expectedItem, displayTextSuffix: displayTextSuffix, glyph: glyph, inlineDescription: inlineDescription, expectedDescriptionOrNull: expectedDescriptionOrNull, isComplexTextEdit: true, flags: flags); private Task VerifyTypeImportItemIsAbsentAsync(string markup, string expectedItem, string inlineDescription, string displayTextSuffix = null) => VerifyItemIsAbsentAsync(markup, expectedItem, displayTextSuffix: displayTextSuffix, inlineDescription: inlineDescription); diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs index 5348478ff3c63..8a0a6aa11c25a 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/XmlDocumentationCommentCompletionProviderTests.cs @@ -42,19 +42,19 @@ private protected override async Task VerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription = null, + string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { // We don't need to try writing comments in from of items in doc comments. await VerifyAtPositionAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, - matchingFilters, flags); + isComplexTextEdit, matchingFilters, flags); await VerifyAtEndOfFileAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, - matchingFilters, flags); + isComplexTextEdit, matchingFilters, flags); // 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) @@ -63,12 +63,12 @@ await VerifyAtEndOfFileAsync( await VerifyAtPosition_ItemPartiallyWrittenAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); await VerifyAtEndOfFile_ItemPartiallyWrittenAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); } } @@ -697,6 +697,7 @@ static void Goo() } [WorkItem(11489, "https://github.com/dotnet/roslyn/issues/11490")] + [WorkItem(37504, "https://github.com/dotnet/roslyn/issues/37504")] [Fact, Trait(Traits.Feature, Traits.Features.Completion)] public async Task SeeAttributeNames() { @@ -709,7 +710,23 @@ class C static void Goo() { } -}", "cref", "langword"); +}", "cref", "langword", "href"); + } + + [WorkItem(37504, "https://github.com/dotnet/roslyn/issues/37504")] + [Fact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task SeeAlsoAttributeNames() + { + await VerifyItemsExistAsync(@" +class C +{ + /// + /// + /// + static void Goo() + { + } +}", "cref", "href"); } [WorkItem(22789, "https://github.com/dotnet/roslyn/issues/22789")] diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index 4091cf658fe0a..1f189a7c0f65d 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -586,6 +586,87 @@ public void Class_Modifiers_Update() Diagnostic(RudeEditKind.ModifiersUpdate, "public class C", FeaturesResources.class_)); } + [Fact, WorkItem(48628, "https://github.com/dotnet/roslyn/issues/48628")] + public void Class_ModifiersUpdate_IgnoreUnsafe() + { + var src1 = "public class C { }"; + var src2 = "public unsafe class C { }"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits( + "Update [public class C { }]@0 -> [public unsafe class C { }]@0"); + + edits.VerifyRudeDiagnostics(); + } + + [Fact, WorkItem(48628, "https://github.com/dotnet/roslyn/issues/48628")] + public void ModifiersUpdate_IgnoreUnsafe() + { + var src1 = @" +using System; +unsafe delegate void D(); +class C +{ + unsafe class N { } + public unsafe event Action A { add { } remove { } } + unsafe int F() => 0; + unsafe int X; + unsafe int Y { get; } + unsafe C() {} + unsafe ~C() {} +} +"; + var src2 = @" +using System; +delegate void D(); +class C +{ + class N { } + public event Action A { add { } remove { } } + int F() => 0; + int X; + int Y { get; } + C() {} + ~C() {} +} +"; + + var edits = GetTopEdits(src1, src2); + + edits.VerifyEdits( + "Update [unsafe delegate void D();]@17 -> [delegate void D();]@17", + "Update [unsafe class N { }]@60 -> [class N { }]@53", + "Update [public unsafe event Action A { add { } remove { } }]@84 -> [public event Action A { add { } remove { } }]@70", + "Update [unsafe int F() => 0;]@146 -> [int F() => 0;]@125", + "Update [unsafe int X;]@172 -> [int X;]@144", + "Update [unsafe int Y { get; }]@191 -> [int Y { get; }]@156", + "Update [unsafe C() {}]@218 -> [C() {}]@176", + "Update [unsafe ~C() {}]@237 -> [~C() {}]@188"); + + edits.VerifyRudeDiagnostics(); + } + + [Fact, WorkItem(48628, "https://github.com/dotnet/roslyn/issues/48628")] + public void ModifiersUpdate_IgnoreUnsafe2() + { + var srcA1 = "partial class C { unsafe void F() { } }"; + var srcB1 = "partial class C { }"; + var srcA2 = "partial class C { }"; + var srcB2 = "partial class C { void F() { } }"; + + EditAndContinueValidation.VerifySemantics( + new[] { GetTopEdits(srcA1, srcA2), GetTopEdits(srcB1, srcB2) }, + new[] + { + DocumentResults(), + DocumentResults(semanticEdits: new[] + { + SemanticEdit(SemanticEditKind.Update, c => c.GetMember("C").GetMember("F")) + }), + }); + } + [Fact] public void Struct_Modifiers_Ref_Update1() { @@ -687,8 +768,7 @@ public void Struct_UnsafeModifier_Update() edits.VerifyEdits( "Update [unsafe struct C { }]@0 -> [struct C { }]@0"); - edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ModifiersUpdate, "struct C", CSharpFeaturesResources.struct_)); + edits.VerifyRudeDiagnostics(); } [Fact] @@ -9376,8 +9456,7 @@ public void FieldUnsafeModifierUpdate() edits.VerifyEdits("Update [unsafe Node* left;]@14 -> [Node* left;]@14"); - edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ModifiersUpdate, "Node* left", FeaturesResources.field)); + edits.VerifyRudeDiagnostics(); } [Fact] @@ -9393,7 +9472,6 @@ public void FieldModifierAndTypeUpdate() "Update [Node* left]@21 -> [Node left]@14"); edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ModifiersUpdate, "Node left", FeaturesResources.field), Diagnostic(RudeEditKind.TypeUpdate, "Node left", FeaturesResources.field)); } @@ -9493,8 +9571,7 @@ public void PropertyWithExpressionBody_ModifierUpdate() edits.VerifyEdits("Update [int P => 1;]@10 -> [unsafe int P => 1;]@10"); - edits.VerifyRudeDiagnostics( - Diagnostic(RudeEditKind.ModifiersUpdate, "unsafe int P", FeaturesResources.property_)); + edits.VerifyRudeDiagnostics(); } [Fact] diff --git a/src/EditorFeatures/CSharpTest/EditorConfigSettings/Aggregator/SettingsAggregatorTests.cs b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Aggregator/SettingsAggregatorTests.cs new file mode 100644 index 0000000000000..42691dca0a0a9 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Aggregator/SettingsAggregatorTests.cs @@ -0,0 +1,53 @@ +// 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 Microsoft.CodeAnalysis.Editor.EditorConfigSettings; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.UnitTests; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.EditorConfigSettings.Aggregator +{ + [UseExportProvider] + public class SettingsAggregatorTests + { + public static Workspace CreateWorkspace(params Type[]? additionalParts) + => new AdhocWorkspace(EditorTestCompositions.EditorFeatures.AddParts(additionalParts).GetHostServices(), WorkspaceKind.Host); + + private static Workspace CreateWorkspaceWithProjectAndDocuments() + { + var projectId = ProjectId.CreateNewId(); + + var workspace = CreateWorkspace(); + + Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution + .AddProject(projectId, "proj1", "proj1.dll", LanguageNames.CSharp) + .AddDocument(DocumentId.CreateNewId(projectId), "goo.cs", "public class Goo { }") + .AddAdditionalDocument(DocumentId.CreateNewId(projectId), "add.txt", "text") + .AddAnalyzerConfigDocument(DocumentId.CreateNewId(projectId), "editorcfg", SourceText.From("config"), filePath: "/a/b"))); + + return workspace; + } + + private static void TestGettingProvider() + { + var workspace = CreateWorkspaceWithProjectAndDocuments(); + var settingsAggregator = workspace.Services.GetRequiredService(); + var settingsProvider = settingsAggregator.GetSettingsProvider("/a/b/config"); + Assert.NotNull(settingsProvider); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public void TestGettingCodeStyleProvider() => TestGettingProvider(); + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public void TestGettingAnalyzerProvider() => TestGettingProvider(); + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public void TestGettingFormattingProvider() => TestGettingProvider(); + } +} diff --git a/src/EditorFeatures/CSharpTest/EditorConfigSettings/DataProvider/DataProviderTests.MockAnalyzerReference.cs b/src/EditorFeatures/CSharpTest/EditorConfigSettings/DataProvider/DataProviderTests.MockAnalyzerReference.cs new file mode 100644 index 0000000000000..e022e47342116 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/EditorConfigSettings/DataProvider/DataProviderTests.MockAnalyzerReference.cs @@ -0,0 +1,118 @@ +// 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.Tasks; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.EditorConfigSettings.DataProvider +{ + public partial class DataProviderTests + { + private class MockAnalyzerReference : AnalyzerReference + { + public readonly CodeFixProvider? Fixer; + public readonly ImmutableArray Analyzers; + + private static readonly CodeFixProvider s_defaultFixer = new MockFixer(); + private static readonly ImmutableArray s_defaultAnalyzers = ImmutableArray.Create(new MockDiagnosticAnalyzer()); + + public MockAnalyzerReference(CodeFixProvider? fixer, ImmutableArray analyzers) + { + Fixer = fixer; + Analyzers = analyzers; + } + + public MockAnalyzerReference() + : this(s_defaultFixer, s_defaultAnalyzers) + { + } + + public MockAnalyzerReference(CodeFixProvider? fixer) + : this(fixer, s_defaultAnalyzers) + { + } + + public override string Display => "MockAnalyzerReference"; + + public override string FullPath => string.Empty; + + public override object Id => "MockAnalyzerReference"; + + public override ImmutableArray GetAnalyzers(string language) + => Analyzers; + + public override ImmutableArray GetAnalyzersForAllLanguages() + => Analyzers; + + public ImmutableArray GetFixers() + => Fixer != null ? ImmutableArray.Create(Fixer) : ImmutableArray.Empty; + + public class MockFixer : CodeFixProvider + { + public const string Id = "MyDiagnostic"; + public bool Called; + public int ContextDiagnosticsCount; + + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(Id); + + public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) + { + Called = true; + ContextDiagnosticsCount = context.Diagnostics.Length; + return Task.CompletedTask; + } + } + + public class MockDiagnosticAnalyzer : DiagnosticAnalyzer + { + public MockDiagnosticAnalyzer(ImmutableArray<(string id, string category)> reportedDiagnosticIdsWithCategories) + => SupportedDiagnostics = CreateSupportedDiagnostics(reportedDiagnosticIdsWithCategories); + + public MockDiagnosticAnalyzer(string diagnosticId, string category) + : this(ImmutableArray.Create((diagnosticId, category))) + { + } + + public MockDiagnosticAnalyzer(ImmutableArray reportedDiagnosticIds) + : this(reportedDiagnosticIds.SelectAsArray(id => (id, "InternalCategory"))) + { + } + + public MockDiagnosticAnalyzer() + : this(ImmutableArray.Create(MockFixer.Id)) + { + } + + private static ImmutableArray CreateSupportedDiagnostics(ImmutableArray<(string id, string category)> reportedDiagnosticIdsWithCategories) + { + var builder = ArrayBuilder.GetInstance(); + foreach (var (diagnosticId, category) in reportedDiagnosticIdsWithCategories) + { + var descriptor = new DiagnosticDescriptor(diagnosticId, "MockDiagnostic", "MockDiagnostic", category, DiagnosticSeverity.Warning, isEnabledByDefault: true); + builder.Add(descriptor); + } + + return builder.ToImmutableAndFree(); + } + + public override ImmutableArray SupportedDiagnostics { get; } + + public override void Initialize(AnalysisContext context) + { + context.RegisterSyntaxTreeAction(c => + { + foreach (var descriptor in SupportedDiagnostics) + { + c.ReportDiagnostic(Diagnostic.Create(descriptor, c.Tree.GetLocation(TextSpan.FromBounds(0, 0)))); + } + }); + } + } + } + } +} diff --git a/src/EditorFeatures/CSharpTest/EditorConfigSettings/DataProvider/DataProviderTests.TestViewModel.cs b/src/EditorFeatures/CSharpTest/EditorConfigSettings/DataProvider/DataProviderTests.TestViewModel.cs new file mode 100644 index 0000000000000..f7b15a93e7ce9 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/EditorConfigSettings/DataProvider/DataProviderTests.TestViewModel.cs @@ -0,0 +1,25 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.EditorConfigSettings.DataProvider +{ + public partial class DataProviderTests + { + private class TestViewModel : ISettingsEditorViewModel + { + public void NotifyOfUpdate() { } + + Task ISettingsEditorViewModel.UpdateEditorConfigAsync(SourceText sourceText) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/src/EditorFeatures/CSharpTest/EditorConfigSettings/DataProvider/DataProviderTests.cs b/src/EditorFeatures/CSharpTest/EditorConfigSettings/DataProvider/DataProviderTests.cs new file mode 100644 index 0000000000000..66842a26d5565 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/EditorConfigSettings/DataProvider/DataProviderTests.cs @@ -0,0 +1,136 @@ +// 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.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Editor.UnitTests; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.EditorConfigSettings.DataProvider +{ + [UseExportProvider] + public partial class DataProviderTests + { + private static Workspace GetWorkspace() + { + var projectId = ProjectId.CreateNewId(); + var workspace = new AdhocWorkspace(EditorTestCompositions.EditorFeatures.GetHostServices(), WorkspaceKind.Host); + Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution + .AddProject(projectId, "proj1", "proj1.dll", LanguageNames.CSharp) + .AddDocument(DocumentId.CreateNewId(projectId), "goo.cs", "public class Goo { }") + .AddAdditionalDocument(DocumentId.CreateNewId(projectId), "add.txt", "text") + .AddAnalyzerReference(projectId, new MockAnalyzerReference()) + .AddAnalyzerConfigDocument(DocumentId.CreateNewId(projectId), "editorcfg", SourceText.From("config"), filePath: "/a/b"))); + return workspace; + } + + private static IWorkspaceSettingsProviderFactory GettingSettingsProviderFactoryFromWorkspace() + => GetWorkspace().Services.GetRequiredService>(); + + private static ILanguageSettingsProviderFactory GettingSettingsProviderFactoryFromLanguageService(string languageName) + => GetWorkspace().Services.GetLanguageServices(languageName).GetRequiredService>(); + + private static ISettingsProvider TestGettingSettingsProviderFromWorkspace() + { + var settingsProviderFactory = GettingSettingsProviderFactoryFromWorkspace(); + var settingsProvider = settingsProviderFactory.GetForFile("/a/b/config"); + Assert.NotNull(settingsProvider); + return settingsProvider; + } + + private static ISettingsProvider TestGettingSettingsProviderFromLanguageService() + { + var settingsProviderFactory = GettingSettingsProviderFactoryFromLanguageService(LanguageNames.CSharp); + var settingsProvider = settingsProviderFactory.GetForFile("/a/b/config"); + Assert.NotNull(settingsProvider); + return settingsProvider; + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public void TestGettingAnalyzerSettingsProvider() + { + TestGettingSettingsProviderFromWorkspace(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public void TestGettingCodeStyleSettingsProvider() + { + TestGettingSettingsProviderFromWorkspace(); + TestGettingSettingsProviderFromLanguageService(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public void TestGettingFormattingSettingsProvider() + { + TestGettingSettingsProviderFromWorkspace(); + TestGettingSettingsProviderFromLanguageService(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public void TestGettingAnalyzerSettingsProviderWorkspaceServiceAsync() + { + var settingsProviderFactory = GettingSettingsProviderFactoryFromWorkspace(); + var settingsProvider = settingsProviderFactory.GetForFile("/a/b/config"); + var model = new TestViewModel(); + settingsProvider.RegisterViewModel(model); + var dataSnapShot = settingsProvider.GetCurrentDataSnapshot(); + var result = Assert.Single(dataSnapShot); + Assert.Equal("MyDiagnostic", result.Id); + Assert.Equal("MockDiagnostic", result.Title); + Assert.Equal(string.Empty, result.Description); + Assert.Equal("InternalCategory", result.Category); + Assert.True(result.IsEnabled); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public void TestGettingCodeStyleSettingProviderWorkspaceServiceAsync() + { + var settingsProviderFactory = GettingSettingsProviderFactoryFromWorkspace(); + var settingsProvider = settingsProviderFactory.GetForFile("/a/b/config"); + var model = new TestViewModel(); + settingsProvider.RegisterViewModel(model); + var dataSnapShot = settingsProvider.GetCurrentDataSnapshot(); + Assert.Equal(26, dataSnapShot.Length); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public void TestGettingCodeStyleSettingsProviderLanguageServiceAsync() + { + var settingsProviderFactory = GettingSettingsProviderFactoryFromLanguageService(LanguageNames.CSharp); + var settingsProvider = settingsProviderFactory.GetForFile("/a/b/config"); + var model = new TestViewModel(); + settingsProvider.RegisterViewModel(model); + var dataSnapShot = settingsProvider.GetCurrentDataSnapshot(); + Assert.Equal(29, dataSnapShot.Length); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public void TestGettingFormattingSettingProviderWorkspaceServiceAsync() + { + var settingsProviderFactory = GettingSettingsProviderFactoryFromWorkspace(); + var settingsProvider = settingsProviderFactory.GetForFile("/a/b/config"); + var model = new TestViewModel(); + settingsProvider.RegisterViewModel(model); + var dataSnapShot = settingsProvider.GetCurrentDataSnapshot(); + Assert.Equal(5, dataSnapShot.Length); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public void TestGettingFormattingSettingProviderLanguageServiceAsync() + { + var settingsProviderFactory = GettingSettingsProviderFactoryFromLanguageService(LanguageNames.CSharp); + var settingsProvider = settingsProviderFactory.GetForFile("/a/b/config"); + var model = new TestViewModel(); + settingsProvider.RegisterViewModel(model); + var dataSnapShot = settingsProvider.GetCurrentDataSnapshot(); + Assert.Equal(47, dataSnapShot.Length); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.TestAnalyzerConfigOptions.cs b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.TestAnalyzerConfigOptions.cs new file mode 100644 index 0000000000000..d2b3c7460dd33 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.TestAnalyzerConfigOptions.cs @@ -0,0 +1,23 @@ +// 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.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.CodeAnalysis.Editor.UnitTests +{ + public partial class SettingsUpdaterTests + { + private class TestAnalyzerConfigOptions : AnalyzerConfigOptions + { + public static TestAnalyzerConfigOptions Instance = new TestAnalyzerConfigOptions(); + + public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) + { + value = null; + return false; + } + } + } +} diff --git a/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs new file mode 100644 index 0000000000000..918323c59e58f --- /dev/null +++ b/src/EditorFeatures/CSharpTest/EditorConfigSettings/Updater/SettingsUpdaterTests.cs @@ -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. + +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.UnitTests +{ + [UseExportProvider] + public partial class SettingsUpdaterTests : TestBase + { + private static Workspace CreateWorkspaceWithProjectAndDocuments() + { + var projectId = ProjectId.CreateNewId(); + + var workspace = new AdhocWorkspace(EditorTestCompositions.EditorFeatures.GetHostServices(), WorkspaceKind.Host); + + Assert.True(workspace.TryApplyChanges(workspace.CurrentSolution + .AddProject(projectId, "proj1", "proj1.dll", LanguageNames.CSharp) + .AddDocument(DocumentId.CreateNewId(projectId), "goo.cs", "public class Goo { }") + .AddAdditionalDocument(DocumentId.CreateNewId(projectId), "add.txt", "text") + .AddAnalyzerConfigDocument(DocumentId.CreateNewId(projectId), "editorcfg", SourceText.From(""), filePath: "/a/b/config"))); + + return workspace; + } + + private static AnalyzerConfigDocument CreateAnalyzerConfigDocument(Workspace workspace, string contents) + { + var solution = workspace.CurrentSolution; + var documentId = solution.Projects.Single().State.AnalyzerConfigDocumentStates.Ids.First(); + var text = SourceText.From(contents); + var newSolution1 = solution.WithAnalyzerConfigDocumentText(documentId, text, PreservationMode.PreserveIdentity); + var analyzerConfigDocument = newSolution1.GetAnalyzerConfigDocument(documentId); + Assert.True(analyzerConfigDocument!.TryGetText(out var actualText)); + Assert.Same(text, actualText); + return analyzerConfigDocument; + } + + private static async Task TestAsync(string initialEditorConfig, string updatedEditorConfig, params (IOption2, object)[] options) + { + using var workspace = CreateWorkspaceWithProjectAndDocuments(); + var analyzerConfigDocument = CreateAnalyzerConfigDocument(workspace, initialEditorConfig); + var sourcetext = await analyzerConfigDocument.GetTextAsync(default); + var result = SettingsUpdateHelper.TryUpdateAnalyzerConfigDocument(sourcetext, analyzerConfigDocument.FilePath!, workspace.Options, options); + Assert.Equal(updatedEditorConfig, result?.ToString()); + } + + private static async Task TestAsync(string initialEditorConfig, string updatedEditorConfig, params (AnalyzerSetting, DiagnosticSeverity)[] options) + { + using var workspace = CreateWorkspaceWithProjectAndDocuments(); + var analyzerConfigDocument = CreateAnalyzerConfigDocument(workspace, initialEditorConfig); + var sourcetext = await analyzerConfigDocument.GetTextAsync(default); + var result = SettingsUpdateHelper.TryUpdateAnalyzerConfigDocument(sourcetext, analyzerConfigDocument.FilePath!, options); + Assert.Equal(updatedEditorConfig, result?.ToString()); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewWhitespaceOptionAsync() + { + await TestAsync( + string.Empty, + "[*.cs]\r\ncsharp_new_line_before_else=true", + (CSharpFormattingOptions2.NewLineForElse, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewBoolCodeStyleOptionWithSeverityAsync() + { + var option = CSharpCodeStyleOptions.PreferThrowExpression.DefaultValue; + option.Value = true; + option.Notification = CodeStyle.NotificationOption2.Suggestion; + await TestAsync( + string.Empty, + "[*.cs]\r\ncsharp_style_throw_expression=true:suggestion", + (CSharpCodeStyleOptions.PreferThrowExpression, option)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewEnumCodeStyleOptionWithSeverityAsync() + { + var option = CSharpCodeStyleOptions.PreferredUsingDirectivePlacement.DefaultValue; + option.Value = AddImportPlacement.InsideNamespace; + option.Notification = CodeStyle.NotificationOption2.Warning; + await TestAsync( + string.Empty, + "[*.cs]\r\ncsharp_using_directive_placement=inside_namespace:warning", + (CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, option)); + } + + [Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + internal async Task TestAddNewAnalyzerOptionOptionAsync( + [CombinatorialValues(Language.CSharp, Language.VisualBasic, (Language.CSharp | Language.VisualBasic))] + Language language, + [CombinatorialValues(DiagnosticSeverity.Warning, DiagnosticSeverity.Error, DiagnosticSeverity.Info, DiagnosticSeverity.Hidden)] + DiagnosticSeverity severity) + { + var expectedHeader = ""; + if (language.HasFlag(Language.CSharp) && language.HasFlag(Language.VisualBasic)) + { + expectedHeader = "[*.{cs,vb}]"; + } + else if (language.HasFlag(Language.CSharp)) + { + expectedHeader = "[*.cs]"; + } + else if (language.HasFlag(Language.VisualBasic)) + { + expectedHeader = "[*.vb]"; + } + + var expectedSeverity = severity.ToEditorConfigString(); + + var id = "Test001"; + var descriptor = new DiagnosticDescriptor(id: id, title: "", messageFormat: "", category: "Naming", defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: false); + var analyzerSetting = new AnalyzerSetting(descriptor, ReportDiagnostic.Suppress, null!, language); + + await TestAsync( + string.Empty, + $"{expectedHeader}\r\ndotnet_diagnostic.{id}.severity={expectedSeverity}", + (analyzerSetting, severity)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestUpdateExistingWhitespaceOptionAsync() + { + await TestAsync( + "[*.cs]\r\ncsharp_new_line_before_else=true", + "[*.cs]\r\ncsharp_new_line_before_else=false", + (CSharpFormattingOptions2.NewLineForElse, false)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewWhitespaceOptionToExistingFileAsync() + { + var initialEditorConfig = @" +[*.{cs,vb}] + +# CA1000: Do not declare static members on generic types +dotnet_diagnostic.CA1000.severity=false + +"; + + var updatedEditorConfig = @" +[*.{cs,vb}] + +# CA1000: Do not declare static members on generic types +dotnet_diagnostic.CA1000.severity=false + + +[*.cs] +csharp_new_line_before_else=true"; + await TestAsync( + initialEditorConfig, + updatedEditorConfig, + (CSharpFormattingOptions2.NewLineForElse, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewWhitespaceOptionToWithNonMathcingGroupsAsync() + { + var initialEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2"; + + var updatedEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 +[*.cs] +csharp_new_line_before_else=true"; + await TestAsync( + initialEditorConfig, + updatedEditorConfig, + (CSharpFormattingOptions2.NewLineForElse, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddNewWhitespaceOptionWithStarGroup() + { + var initialEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# CSharp code style settings: +[*.cs]"; + + var updatedEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# CSharp code style settings: +[*.cs] +csharp_new_line_before_else=true"; + + await TestAsync( + initialEditorConfig, + updatedEditorConfig, + (CSharpFormattingOptions2.NewLineForElse, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddMultimpleNewWhitespaceOptions() + { + await TestAsync( + string.Empty, + "[*.cs]\r\ncsharp_new_line_before_else=true\r\ncsharp_new_line_before_catch=true\r\ncsharp_new_line_before_finally=true", + (CSharpFormattingOptions2.NewLineForElse, true), + (CSharpFormattingOptions2.NewLineForCatch, true), + (CSharpFormattingOptions2.NewLineForFinally, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddOptionThatAppliesToBothLanguages() + { + var initialEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# CSharp code style settings: +[*.cs]"; + + var updatedEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] +dotnet_sort_system_directives_first=true + +# CSharp code style settings: +[*.cs]"; + + await TestAsync( + initialEditorConfig, + updatedEditorConfig, + (GenerationOptions.PlaceSystemNamespaceFirst, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAddOptionWithRelativePathGroupingPresent() + { + var initialEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# Test CSharp code style settings: +[*Test.cs] + +# CSharp code style settings: +[*.cs]"; + + var updatedEditorConfig = @" +root = true + +# Xml files +[*.xml] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] + +# Test CSharp code style settings: +[*Test.cs] + +# CSharp code style settings: +[*.cs] +csharp_new_line_before_else=true"; + + await TestAsync( + initialEditorConfig, + updatedEditorConfig, + (CSharpFormattingOptions2.NewLineForElse, true)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestAnalyzerSettingsUpdaterService() + { + var workspace = CreateWorkspaceWithProjectAndDocuments(); + var updater = new AnalyzerSettingsUpdater(workspace, "/a/b/config"); + var id = "Test001"; + var descriptor = new DiagnosticDescriptor(id: id, title: "", messageFormat: "", category: "Naming", defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: false); + var analyzerSetting = new AnalyzerSetting(descriptor, ReportDiagnostic.Suppress, updater, Language.CSharp); + analyzerSetting.ChangeSeverity(DiagnosticSeverity.Error); + var updates = await updater.GetChangedEditorConfigAsync(default); + var update = Assert.Single(updates); + Assert.Equal($"[*.cs]\r\ndotnet_diagnostic.{id}.severity=error", update.NewText); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestCodeStyleSettingUpdaterService() + { + var workspace = CreateWorkspaceWithProjectAndDocuments(); + var updater = new OptionUpdater(workspace, "/a/b/config"); + var setting = CodeStyleSetting.Create(CSharpCodeStyleOptions.AllowBlankLineAfterColonInConstructorInitializer, + "", + TestAnalyzerConfigOptions.Instance, + workspace.Options, + updater); + setting.ChangeSeverity(DiagnosticSeverity.Error); + var updates = await updater.GetChangedEditorConfigAsync(default); + var update = Assert.Single(updates); + Assert.Equal("[*.cs]\r\ncsharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental=true:error", update.NewText); + setting.ChangeValue(1); + updates = await updater.GetChangedEditorConfigAsync(default); + update = Assert.Single(updates); + Assert.Equal("[*.cs]\r\ncsharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental=false:error", update.NewText); + } + + [Fact, Trait(Traits.Feature, Traits.Features.EditorConfigUI)] + public async Task TestFormattingSettingUpdaterService() + { + var workspace = CreateWorkspaceWithProjectAndDocuments(); + var updater = new OptionUpdater(workspace, "/a/b/config"); + var setting = FormattingSetting.Create(CSharpFormattingOptions2.NewLineForElse, "", TestAnalyzerConfigOptions.Instance, workspace.Options, updater); + setting.SetValue(false); + var updates = await updater.GetChangedEditorConfigAsync(default); + var update = Assert.Single(updates); + Assert.Equal("[*.cs]\r\ncsharp_new_line_before_else=false", update.NewText); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs b/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs index dacf21e4f88c7..de10a7f7429d1 100644 --- a/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs +++ b/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs @@ -2032,5 +2032,32 @@ public static void M2([||]__arglist) }"; await VerifyCS.VerifyRefactoringAsync(code, code); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInitializeParameter)] + [WorkItem(52383, "https://github.com/dotnet/roslyn/issues/52383")] + public async Task TestImportSystem() + { + await VerifyCS.VerifyRefactoringAsync( +@" +class C +{ + public C([||]string s) + { + } +}", +@" +using System; + +class C +{ + public C(string s) + { + if (s is null) + { + throw new ArgumentNullException(nameof(s)); + } + } +}"); + } } } diff --git a/src/EditorFeatures/CSharpTest/TodoComment/NoCompilationTodoCommentTests.cs b/src/EditorFeatures/CSharpTest/TodoComment/NoCompilationTodoCommentTests.cs index b345017bbc2da..1c349c610f725 100644 --- a/src/EditorFeatures/CSharpTest/TodoComment/NoCompilationTodoCommentTests.cs +++ b/src/EditorFeatures/CSharpTest/TodoComment/NoCompilationTodoCommentTests.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; +using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Host.Mef; @@ -27,7 +28,7 @@ public class NoCompilationTodoCommentTests : AbstractTodoCommentTests { protected override TestWorkspace CreateWorkspace(string codeWithMarker) { - return TestWorkspace.CreateWorkspace(XElement.Parse( + var workspace = TestWorkspace.CreateWorkspace(XElement.Parse( $@" {codeWithMarker} @@ -36,6 +37,9 @@ protected override TestWorkspace CreateWorkspace(string codeWithMarker) typeof(NoCompilationContentTypeDefinitions), typeof(NoCompilationContentTypeLanguageService), typeof(NoCompilationTodoCommentService))); + + workspace.SetOptions(workspace.Options.WithChangedOption(TodoCommentOptions.TokenList, DefaultTokenList)); + return workspace; } [Fact, WorkItem(1192024, "https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1192024")] diff --git a/src/EditorFeatures/CSharpTest/TodoComment/TodoCommentTests.cs b/src/EditorFeatures/CSharpTest/TodoComment/TodoCommentTests.cs index ee8d13571d5d9..d0afce28ba083 100644 --- a/src/EditorFeatures/CSharpTest/TodoComment/TodoCommentTests.cs +++ b/src/EditorFeatures/CSharpTest/TodoComment/TodoCommentTests.cs @@ -5,6 +5,7 @@ #nullable disable using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities.TodoComments; @@ -16,7 +17,11 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.TodoComment public class TodoCommentTests : AbstractTodoCommentTests { protected override TestWorkspace CreateWorkspace(string codeWithMarker) - => TestWorkspace.CreateCSharp(codeWithMarker); + { + var workspace = TestWorkspace.CreateCSharp(codeWithMarker); + workspace.SetOptions(workspace.Options.WithChangedOption(TodoCommentOptions.TokenList, DefaultTokenList)); + return workspace; + } [Fact] public async Task SingleLineTodoComment_Colon() diff --git a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindImplementingMembersCommandHandler.cs b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindImplementingMembersCommandHandler.cs index 8b61ea117a9e6..ce37f9c2f5860 100644 --- a/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindImplementingMembersCommandHandler.cs +++ b/src/EditorFeatures/Core.Cocoa/NavigationCommandHandlers/FindImplementingMembersCommandHandler.cs @@ -97,7 +97,7 @@ private async Task FindImplementingMembersAsync( return; #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task - var syntaxTree = await document.GetSyntaxTreeAsync(); + var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task var documentToken = nodeRoot.FindToken(caretPosition); @@ -107,11 +107,11 @@ private async Task FindImplementingMembersAsync( // the parents should bring us to the class definition var parentTypeNode = documentToken.Parent?.Parent?.Parent?.Parent; #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task - var compilation = await document.Project.GetCompilationAsync(); + var compilation = await document.Project.GetCompilationAsync(cancellationToken); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task // let's finally get our implementing type - var namedTypeSymbol = compilation.GetSemanticModel(syntaxTree).GetDeclaredSymbol(parentTypeNode) as INamedTypeSymbol; + var namedTypeSymbol = compilation.GetSemanticModel(syntaxTree).GetDeclaredSymbol(parentTypeNode, cancellationToken: cancellationToken) as INamedTypeSymbol; // unless something went wrong, and we got an empty symbol, if (namedTypeSymbol == null) return; diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationService.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationService.cs index ae35794835d2c..cab4b5b42fb2e 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationService.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationService.cs @@ -28,7 +28,7 @@ public bool CanNavigateToLineAndOffset(Workspace workspace, DocumentId documentI public bool CanNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, CancellationToken cancellationToken) => false; - public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, CancellationToken cancellationToken) + public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, bool allowInvalidSpan, CancellationToken cancellationToken) { if (workspace is not InteractiveWindowWorkspace interactiveWorkspace) { diff --git a/src/EditorFeatures/Core.Wpf/Microsoft.CodeAnalysis.EditorFeatures.Wpf.csproj b/src/EditorFeatures/Core.Wpf/Microsoft.CodeAnalysis.EditorFeatures.Wpf.csproj index 4211ba99baff2..20b9352283106 100644 --- a/src/EditorFeatures/Core.Wpf/Microsoft.CodeAnalysis.EditorFeatures.Wpf.csproj +++ b/src/EditorFeatures/Core.Wpf/Microsoft.CodeAnalysis.EditorFeatures.Wpf.csproj @@ -68,8 +68,6 @@ - - diff --git a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplay.cs b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplay.cs index e83e493d3a787..739189b0e9308 100644 --- a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplay.cs +++ b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplay.cs @@ -53,6 +53,15 @@ private ReadOnlyCollection CreateDescriptionItems() } var sourceText = document.GetTextSynchronously(CancellationToken.None); + var item = _searchResult.NavigableItem; + var spanStart = item.SourceSpan.Start; + if (item.IsStale && spanStart > sourceText.Length) + { + // in the case of a stale item, the span may be out of bounds of the document. Cap + // us to the end of the document as that's where we're going to navigate the user + // to. + spanStart = sourceText.Length; + } var items = new List { @@ -70,7 +79,7 @@ private ReadOnlyCollection CreateDescriptionItems() new ReadOnlyCollection( new[] { new DescriptionRun("Line:", bold: true) }), new ReadOnlyCollection( - new[] { new DescriptionRun((sourceText.Lines.IndexOf(_searchResult.NavigableItem.SourceSpan.Start) + 1).ToString()) })) + new[] { new DescriptionRun((sourceText.Lines.IndexOf(spanStart) + 1).ToString()) })) }; var summary = _searchResult.Summary; @@ -102,11 +111,22 @@ public void NavigateTo() var workspace = document.Project.Solution.Workspace; var navigationService = workspace.Services.GetService(); - // Document tabs opened by NavigateTo are carefully created as preview or regular - // tabs by them; trying to specifically open them in a particular kind of tab here - // has no effect. - // TODO: Get the platform to use and pass us an operation context, or create one ourselves. - navigationService.TryNavigateToSpan(workspace, document.Id, _searchResult.NavigableItem.SourceSpan, CancellationToken.None); + // Document tabs opened by NavigateTo are carefully created as preview or regular tabs + // by them; trying to specifically open them in a particular kind of tab here has no + // effect. + // + // In the case of a stale item, don't require that the span be in bounds of the document + // as it exists right now. + // + // TODO: Get the platform to use and pass us an operation context, or create one + // ourselves. + navigationService.TryNavigateToSpan( + workspace, + document.Id, + _searchResult.NavigableItem.SourceSpan, + options: null, + allowInvalidSpan: _searchResult.NavigableItem.IsStale, + CancellationToken.None); } public int GetProvisionalViewingStatus() diff --git a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs index 65543854159ca..8dd3316a1bfd4 100644 --- a/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs +++ b/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs @@ -125,7 +125,7 @@ private async Task ComputeModelInBackgroundAsync( .WithSelectedParameter(selection.SelectedParameter); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -216,7 +216,7 @@ private static bool CompareParts(TaggedText p1, TaggedText p2) return (bestProvider, bestItems); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return (null, null); } diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/ISettingsAggregator.cs b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/ISettingsAggregator.cs new file mode 100644 index 0000000000000..74520e4ac98dc --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/ISettingsAggregator.cs @@ -0,0 +1,14 @@ +// 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.Editor.EditorConfigSettings.DataProvider; +using Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings +{ + internal interface ISettingsAggregator : IWorkspaceService + { + ISettingsProvider? GetSettingsProvider(string fileName); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs new file mode 100644 index 0000000000000..144b853d9abd9 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregator.cs @@ -0,0 +1,99 @@ +// 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 Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings +{ + internal partial class SettingsAggregator : ISettingsAggregator + { + private readonly Workspace _workspace; + private readonly ISettingsProviderFactory _analyzerProvider; + private ISettingsProviderFactory _formattingProvider; + private ISettingsProviderFactory _codeStyleProvider; + + public SettingsAggregator(Workspace workspace) + { + _workspace = workspace; + _workspace.WorkspaceChanged += UpdateProviders; + _formattingProvider = GetOptionsProviderFactory(_workspace); + _codeStyleProvider = GetOptionsProviderFactory(_workspace); + _analyzerProvider = GetOptionsProviderFactory(_workspace); + } + + private void UpdateProviders(object? sender, WorkspaceChangeEventArgs e) + { + switch (e.Kind) + { + case WorkspaceChangeKind.SolutionChanged: + case WorkspaceChangeKind.SolutionAdded: + case WorkspaceChangeKind.SolutionRemoved: + case WorkspaceChangeKind.SolutionCleared: + case WorkspaceChangeKind.SolutionReloaded: + case WorkspaceChangeKind.ProjectAdded: + case WorkspaceChangeKind.ProjectRemoved: + case WorkspaceChangeKind.ProjectChanged: + _formattingProvider = GetOptionsProviderFactory(_workspace); + _codeStyleProvider = GetOptionsProviderFactory(_workspace); + break; + default: + break; + } + } + + public ISettingsProvider? GetSettingsProvider(string fileName) + { + if (typeof(TData) == typeof(AnalyzerSetting)) + { + return (ISettingsProvider)_analyzerProvider.GetForFile(fileName); + } + + if (typeof(TData) == typeof(FormattingSetting)) + { + return (ISettingsProvider)_formattingProvider.GetForFile(fileName); + } + + if (typeof(TData) == typeof(CodeStyleSetting)) + { + return (ISettingsProvider)_codeStyleProvider.GetForFile(fileName); + } + + return null; + } + + private static ISettingsProviderFactory GetOptionsProviderFactory(Workspace workspace) + { + var providers = new List>(); + var commonProvider = workspace.Services.GetRequiredService>(); + providers.Add(commonProvider); + var solution = workspace.CurrentSolution; + var supportsCSharp = solution.Projects.Any(p => p.Language.Equals(LanguageNames.CSharp, StringComparison.OrdinalIgnoreCase)); + var supportsVisualBasic = solution.Projects.Any(p => p.Language.Equals(LanguageNames.VisualBasic, StringComparison.OrdinalIgnoreCase)); + if (supportsCSharp) + { + TryAddProviderForLanguage(LanguageNames.CSharp, workspace, providers); + } + if (supportsVisualBasic) + { + TryAddProviderForLanguage(LanguageNames.VisualBasic, workspace, providers); + } + + return new CombinedOptionsProviderFactory(providers.ToImmutableArray()); + + static void TryAddProviderForLanguage(string language, Workspace workspace, List> providers) + { + var provider = workspace.Services.GetLanguageServices(language).GetService>(); + if (provider is not null) + { + providers.Add(provider); + } + } + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregatorFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregatorFactory.cs new file mode 100644 index 0000000000000..87a8598b69e32 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Aggregator/SettingsAggregatorFactory.cs @@ -0,0 +1,25 @@ +// 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.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings +{ + + [ExportWorkspaceServiceFactory(typeof(ISettingsAggregator), ServiceLayer.Default), Shared] + internal class SettingsAggregatorFactory : IWorkspaceServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public SettingsAggregatorFactory() + { + } + + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + => new SettingsAggregator(workspaceServices.Workspace); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/AnalyzerSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/AnalyzerSetting.cs new file mode 100644 index 0000000000000..98cef0b4f22be --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/AnalyzerSetting.cs @@ -0,0 +1,57 @@ +// 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.Globalization; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal class AnalyzerSetting + { + private readonly DiagnosticDescriptor _descriptor; + private readonly AnalyzerSettingsUpdater _settingsUpdater; + + public AnalyzerSetting(DiagnosticDescriptor descriptor, + ReportDiagnostic effectiveSeverity, + AnalyzerSettingsUpdater settingsUpdater, + Language language) + { + _descriptor = descriptor; + _settingsUpdater = settingsUpdater; + DiagnosticSeverity severity = default; + if (effectiveSeverity == ReportDiagnostic.Default) + { + severity = descriptor.DefaultSeverity; + } + else if (effectiveSeverity.ToDiagnosticSeverity() is DiagnosticSeverity severity1) + { + severity = severity1; + } + + var enabled = effectiveSeverity != ReportDiagnostic.Suppress; + IsEnabled = enabled; + Severity = severity; + Language = language; + } + + public string Id => _descriptor.Id; + public string Title => _descriptor.Title.ToString(CultureInfo.CurrentCulture); + public string Description => _descriptor.Description.ToString(CultureInfo.CurrentCulture); + public string Category => _descriptor.Category; + public DiagnosticSeverity Severity { get; private set; } + public bool IsEnabled { get; private set; } + public Language Language { get; } + + internal void ChangeSeverity(DiagnosticSeverity severity) + { + if (severity == Severity) + return; + + Severity = severity; + _ = _settingsUpdater.QueueUpdateAsync(this, severity); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSetting.cs new file mode 100644 index 0000000000000..907245d073918 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSetting.cs @@ -0,0 +1,57 @@ +// 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.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private class BooleanCodeStyleSetting : BooleanCodeStyleSettingBase + { + private readonly Option2> _option; + private readonly AnalyzerConfigOptions _editorConfigOptions; + private readonly OptionSet _visualStudioOptions; + + public BooleanCodeStyleSetting(Option2> option, + string description, + string? trueValueDescription, + string? falseValueDescription, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, option.Group.Description, trueValueDescription, falseValueDescription, updater) + { + _option = option; + _editorConfigOptions = editorConfigOptions; + _visualStudioOptions = visualStudioOptions; + } + + public override bool IsDefinedInEditorConfig => _editorConfigOptions.TryGetEditorConfigOption>(_option, out _); + + protected override void ChangeSeverity(NotificationOption2 severity) + { + var option = GetOption(); + option.Notification = severity; + _ = Updater.QueueUpdateAsync(_option, option); + } + + public override void ChangeValue(int valueIndex) + { + var value = valueIndex == 0; + var option = GetOption(); + option.Value = value; + _ = Updater.QueueUpdateAsync(_option, option); + } + + protected override CodeStyleOption2 GetOption() + => _editorConfigOptions.TryGetEditorConfigOption(_option, out CodeStyleOption2? value) && value is not null + ? value + : _visualStudioOptions.GetOption(_option); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSettingBase.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSettingBase.cs new file mode 100644 index 0000000000000..bd2e3822b24b7 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.BooleanCodeStyleSettingBase.cs @@ -0,0 +1,40 @@ +// 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 Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private abstract class BooleanCodeStyleSettingBase : CodeStyleSetting + { + private readonly string _trueValueDescription; + private readonly string _falseValueDescription; + + public BooleanCodeStyleSettingBase(string description, + string category, + string? trueValueDescription, + string? falseValueDescription, + OptionUpdater updater) + : base(description, updater) + { + Category = category; + _trueValueDescription = trueValueDescription ?? EditorFeaturesResources.Yes; + _falseValueDescription = falseValueDescription ?? EditorFeaturesResources.No; + } + + public override string Category { get; } + public override Type Type => typeof(bool); + public override DiagnosticSeverity Severity => GetOption().Notification.Severity.ToDiagnosticSeverity() ?? DiagnosticSeverity.Hidden; + public override string GetCurrentValue() => GetOption().Value ? _trueValueDescription : _falseValueDescription; + public override object? Value => GetOption().Value; + public override string[] GetValues() => new[] { _trueValueDescription, _falseValueDescription }; + protected abstract CodeStyleOption2 GetOption(); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSetting.cs new file mode 100644 index 0000000000000..8506d092f0315 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSetting.cs @@ -0,0 +1,58 @@ +// 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 Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private class EnumCodeStyleSetting : EnumCodeStyleSettingBase + where T : Enum + { + private readonly Option2> _option; + private readonly AnalyzerConfigOptions _editorConfigOptions; + private readonly OptionSet _visualStudioOptions; + + public EnumCodeStyleSetting(Option2> option, + string description, + T[] enumValues, + string[] valueDescriptions, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, enumValues, valueDescriptions, option.Group.Description, updater) + { + _option = option; + _editorConfigOptions = editorConfigOptions; + _visualStudioOptions = visualStudioOptions; + } + + public override bool IsDefinedInEditorConfig => _editorConfigOptions.TryGetEditorConfigOption>(_option, out _); + + protected override void ChangeSeverity(NotificationOption2 severity) + { + var option = GetOption(); + option.Notification = severity; + _ = Updater.QueueUpdateAsync(_option, option); + } + + public override void ChangeValue(int valueIndex) + { + var option = GetOption(); + option.Value = _enumValues[valueIndex]; + _ = Updater.QueueUpdateAsync(_option, option); + } + + protected override CodeStyleOption2 GetOption() + => _editorConfigOptions.TryGetEditorConfigOption(_option, out CodeStyleOption2? value) && value is not null + ? value + : _visualStudioOptions.GetOption(_option); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSettingBase.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSettingBase.cs new file mode 100644 index 0000000000000..8856236da98cc --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.EnumCodeStyleSettingBase.cs @@ -0,0 +1,46 @@ +// 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 Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private abstract class EnumCodeStyleSettingBase : CodeStyleSetting + where T : Enum + { + protected readonly T[] _enumValues; + private readonly string[] _valueDescriptions; + + public EnumCodeStyleSettingBase(string description, + T[] enumValues, + string[] valueDescriptions, + string category, + OptionUpdater updater) + : base(description, updater) + { + if (enumValues.Length != valueDescriptions.Length) + { + throw new InvalidOperationException("Values and descriptions must have matching number of elements"); + } + _enumValues = enumValues; + _valueDescriptions = valueDescriptions; + Category = category; + } + + public override string Category { get; } + public override Type Type => typeof(T); + public override string GetCurrentValue() => _valueDescriptions[_enumValues.IndexOf(GetOption().Value)]; + public override object? Value => GetOption().Value; + public override DiagnosticSeverity Severity => GetOption().Notification.Severity.ToDiagnosticSeverity() ?? DiagnosticSeverity.Hidden; + public override string[] GetValues() => _valueDescriptions; + protected abstract CodeStyleOption2 GetOption(); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageBooleanCodeStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageBooleanCodeStyleSetting.cs new file mode 100644 index 0000000000000..b71d06986e1a5 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageBooleanCodeStyleSetting.cs @@ -0,0 +1,57 @@ +// 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.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private class PerLanguageBooleanCodeStyleSetting : BooleanCodeStyleSettingBase + { + private readonly PerLanguageOption2> _option; + private readonly AnalyzerConfigOptions _editorConfigOptions; + private readonly OptionSet _visualStudioOptions; + + public PerLanguageBooleanCodeStyleSetting(PerLanguageOption2> option, + string description, + string? trueValueDescription, + string? falseValueDescription, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, option.Group.Description, trueValueDescription, falseValueDescription, updater) + { + _option = option; + _editorConfigOptions = editorConfigOptions; + _visualStudioOptions = visualStudioOptions; + } + + public override bool IsDefinedInEditorConfig => _editorConfigOptions.TryGetEditorConfigOption>(_option, out _); + + protected override void ChangeSeverity(NotificationOption2 severity) + { + var option = GetOption(); + option.Notification = severity; + _ = Updater.QueueUpdateAsync(_option, option); + } + + public override void ChangeValue(int valueIndex) + { + var value = valueIndex == 0; + var option = GetOption(); + option.Value = value; + _ = Updater.QueueUpdateAsync(_option, option); + } + + protected override CodeStyleOption2 GetOption() + => _editorConfigOptions.TryGetEditorConfigOption(_option, out CodeStyleOption2? value) && value is not null + ? value + : _visualStudioOptions.GetOption>(new OptionKey2(_option, LanguageNames.CSharp)); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageEnumCodeStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageEnumCodeStyleSetting.cs new file mode 100644 index 0000000000000..df33ae0c833e6 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.PerLanguageEnumCodeStyleSetting.cs @@ -0,0 +1,60 @@ +// 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 Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + private class PerLanguageEnumCodeStyleSetting : EnumCodeStyleSettingBase + where T : Enum + { + private readonly PerLanguageOption2> _option; + private readonly AnalyzerConfigOptions _editorConfigOptions; + private readonly OptionSet _visualStudioOptions; + + public PerLanguageEnumCodeStyleSetting(PerLanguageOption2> option, + string description, + T[] enumValues, + string[] valueDescriptions, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, enumValues, valueDescriptions, option.Group.Description, updater) + { + _option = option; + _editorConfigOptions = editorConfigOptions; + _visualStudioOptions = visualStudioOptions; + } + + public override bool IsDefinedInEditorConfig => _editorConfigOptions.TryGetEditorConfigOption>(_option, out _); + + protected override void ChangeSeverity(NotificationOption2 severity) + { + var option = GetOption(); + option.Notification = severity; + _ = Updater.QueueUpdateAsync(_option, option); + } + + public override void ChangeValue(int valueIndex) + { + var option = GetOption(); + option.Value = _enumValues[valueIndex]; + _ = Updater.QueueUpdateAsync(_option, option); + } + + protected override CodeStyleOption2 GetOption() + => _editorConfigOptions.TryGetEditorConfigOption(_option, out CodeStyleOption2? value) && value is not null + ? value + // TODO(jmarolf): Should we expose duplicate options if the user has a different setting in VB vs. C#? + // Today this code will choose whatever option is set for C# as the default. + : _visualStudioOptions.GetOption>(new OptionKey2(_option, LanguageNames.CSharp)); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.cs new file mode 100644 index 0000000000000..c00bb71b00617 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/CodeStyle/CodeStyleSetting.cs @@ -0,0 +1,96 @@ +// 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 Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract partial class CodeStyleSetting + { + public string Description { get; } + + protected readonly OptionUpdater Updater; + + public abstract string Category { get; } + public abstract object? Value { get; } + public abstract Type Type { get; } + public abstract string[] GetValues(); + public abstract string GetCurrentValue(); + public abstract DiagnosticSeverity Severity { get; } + public abstract bool IsDefinedInEditorConfig { get; } + + public CodeStyleSetting(string description, OptionUpdater updater) + { + Description = description; + Updater = updater; + } + + public void ChangeSeverity(DiagnosticSeverity severity) + { + var notification = severity switch + { + DiagnosticSeverity.Hidden => NotificationOption2.Silent, + DiagnosticSeverity.Info => NotificationOption2.Suggestion, + DiagnosticSeverity.Warning => NotificationOption2.Warning, + DiagnosticSeverity.Error => NotificationOption2.Error, + _ => NotificationOption2.None, + }; + + ChangeSeverity(notification); + } + + protected abstract void ChangeSeverity(NotificationOption2 severity); + public abstract void ChangeValue(int valueIndex); + + internal static CodeStyleSetting Create(Option2> option, + string description, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater, + string? trueValueDescription = null, + string? falseValueDescription = null) + { + return new BooleanCodeStyleSetting(option, description, trueValueDescription, falseValueDescription, editorConfigOptions, visualStudioOptions, updater); + } + + internal static CodeStyleSetting Create(PerLanguageOption2> option, + string description, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater, + string? trueValueDescription = null, + string? falseValueDescription = null) + { + return new PerLanguageBooleanCodeStyleSetting(option, description, trueValueDescription, falseValueDescription, editorConfigOptions, visualStudioOptions, updater); + } + + internal static CodeStyleSetting Create(Option2> option, + string description, + T[] enumValues, + string[] valueDescriptions, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + where T : Enum + { + return new EnumCodeStyleSetting(option, description, enumValues, valueDescriptions, editorConfigOptions, visualStudioOptions, updater); + } + + internal static CodeStyleSetting Create(PerLanguageOption2> option, + string description, + T[] enumValues, + string[] valueDescriptions, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + where T : Enum + { + return new PerLanguageEnumCodeStyleSetting(option, description, enumValues, valueDescriptions, editorConfigOptions, visualStudioOptions, updater); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting.cs new file mode 100644 index 0000000000000..a013f3ad40551 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting.cs @@ -0,0 +1,52 @@ +// 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 Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal abstract class FormattingSetting + { + protected OptionUpdater Updater { get; } + protected string? Language { get; } + + protected FormattingSetting(string description, OptionUpdater updater, string? language = null) + { + Description = description ?? throw new ArgumentNullException(nameof(description)); + Updater = updater; + Language = language; + } + + public string Description { get; } + public abstract string Category { get; } + public abstract Type Type { get; } + public abstract OptionKey2 Key { get; } + public abstract void SetValue(object value); + public abstract object? GetValue(); + public abstract bool IsDefinedInEditorConfig { get; } + + public static PerLanguageFormattingSetting Create(PerLanguageOption2 option, + string description, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + where TOption : notnull + { + return new PerLanguageFormattingSetting(option, description, editorConfigOptions, visualStudioOptions, updater); + } + + public static FormattingSetting Create(Option2 option, + string description, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + where TOption : struct + { + return new FormattingSetting(option, description, editorConfigOptions, visualStudioOptions, updater); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting`1.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting`1.cs new file mode 100644 index 0000000000000..0fcfecad99b36 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/FormattingSetting`1.cs @@ -0,0 +1,76 @@ +// 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 Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal sealed class FormattingSetting : FormattingSetting + where T : notnull + { + public override bool IsDefinedInEditorConfig => _options.TryGetEditorConfigOption(_option, out _); + + private bool _isValueSet; + private T? _value; + public T Value + { + private set + { + if (!_isValueSet) + { + _isValueSet = true; + } + + _value = value; + } + get + { + if (_value is not null && _isValueSet) + { + return _value; + } + + if (_options.TryGetEditorConfigOption(_option, out T? value) && + value is not null) + { + return value; + } + + return _visualStudioOptions.GetOption(_option); + } + } + + public override Type Type => typeof(T); + public override string Category => _option.Group.Description; + + public override OptionKey2 Key => new(_option, _option.OptionDefinition.IsPerLanguage ? Language ?? LanguageNames.CSharp : null); + + private readonly Option2 _option; + private readonly AnalyzerConfigOptions _options; + private readonly OptionSet _visualStudioOptions; + + public FormattingSetting(Option2 option, + string description, + AnalyzerConfigOptions options, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, updater) + { + _option = option; + _options = options; + _visualStudioOptions = visualStudioOptions; + } + + public override void SetValue(object value) + { + Value = (T)value; + _ = Updater.QueueUpdateAsync(_option, value); + } + + public override object? GetValue() => Value; + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/PerLanguageFormattingSetting.cs b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/PerLanguageFormattingSetting.cs new file mode 100644 index 0000000000000..aebf191e07ba2 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Data/Formatting/PerLanguageFormattingSetting.cs @@ -0,0 +1,76 @@ +// 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 Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data +{ + internal sealed class PerLanguageFormattingSetting : FormattingSetting + where T : notnull + { + private bool _isValueSet; + private T? _value; + public T Value + { + private set + { + if (!_isValueSet) + { + _isValueSet = true; + } + + _value = value; + } + get + { + if (_value is not null && _isValueSet) + { + return _value; + } + + if (_editorConfigOptions.TryGetEditorConfigOption(_option, out T? value) && + value is not null) + { + return value; + } + + return (T)_visualStudioOptions.GetOption(Key)!; + } + } + + private readonly PerLanguageOption2 _option; + private readonly AnalyzerConfigOptions _editorConfigOptions; + private readonly OptionSet _visualStudioOptions; + + public PerLanguageFormattingSetting(PerLanguageOption2 option, + string description, + AnalyzerConfigOptions editorConfigOptions, + OptionSet visualStudioOptions, + OptionUpdater updater) + : base(description, updater) + { + _option = option; + _editorConfigOptions = editorConfigOptions; + _visualStudioOptions = visualStudioOptions; + } + + public override string Category => _option.Group.Description; + public override Type Type => typeof(T); + + public override OptionKey2 Key => new(_option, _option.OptionDefinition.IsPerLanguage ? Language ?? LanguageNames.CSharp : null); + + public override bool IsDefinedInEditorConfig => _editorConfigOptions.TryGetEditorConfigOption(_option, out _); + + public override void SetValue(object value) + { + Value = (T)value; + _ = Updater.QueueUpdateAsync(_option, value); + } + + public override object? GetValue() => Value; + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs new file mode 100644 index 0000000000000..61f2157801f12 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProvider.cs @@ -0,0 +1,88 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Analyzer +{ + internal class AnalyzerSettingsProvider : SettingsProviderBase + { + private readonly IDiagnosticAnalyzerService _analyzerService; + + public AnalyzerSettingsProvider(string fileName, AnalyzerSettingsUpdater settingsUpdater, Workspace workspace, IDiagnosticAnalyzerService analyzerService) + : base(fileName, settingsUpdater, workspace) + { + _analyzerService = analyzerService; + Update(); + } + + protected override void UpdateOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet _) + { + var solution = Workspace.CurrentSolution; + var projects = solution.GetProjectsForPath(FileName); + var analyzerReferences = projects.SelectMany(p => p.AnalyzerReferences).DistinctBy(a => a.Id).ToImmutableArray(); + foreach (var analyzerReference in analyzerReferences) + { + var configSettings = GetSettings(analyzerReference, editorConfigOptions); + AddRange(configSettings); + } + } + + private IEnumerable GetSettings(AnalyzerReference analyzerReference, AnalyzerConfigOptions editorConfigOptions) + { + IEnumerable csharpAnalyzers = analyzerReference.GetAnalyzers(LanguageNames.CSharp); + IEnumerable visualBasicAnalyzers = analyzerReference.GetAnalyzers(LanguageNames.VisualBasic); + var dotnetAnalyzers = csharpAnalyzers.Intersect(visualBasicAnalyzers, DiagnosticAnalyzerComparer.Instance); + csharpAnalyzers = csharpAnalyzers.Except(dotnetAnalyzers, DiagnosticAnalyzerComparer.Instance); + visualBasicAnalyzers = visualBasicAnalyzers.Except(dotnetAnalyzers, DiagnosticAnalyzerComparer.Instance); + + var csharpSettings = ToAnalyzerSetting(csharpAnalyzers, Language.CSharp); + var csharpAndVisualBasicSettings = csharpSettings.Concat(ToAnalyzerSetting(visualBasicAnalyzers, Language.VisualBasic)); + return csharpAndVisualBasicSettings.Concat(ToAnalyzerSetting(dotnetAnalyzers, Language.CSharp | Language.VisualBasic)); + + IEnumerable ToAnalyzerSetting(IEnumerable analyzers, + Language language) + { + return analyzers + .SelectMany(a => _analyzerService.AnalyzerInfoCache.GetDiagnosticDescriptors(a)) + .GroupBy(d => d.Id) + .OrderBy(g => g.Key, StringComparer.CurrentCulture) + .Select(g => + { + var selectedDiagnostic = g.First(); + var severity = selectedDiagnostic.GetEffectiveSeverity(editorConfigOptions); + return new AnalyzerSetting(selectedDiagnostic, severity, SettingsUpdater, language); + }); + } + } + + private class DiagnosticAnalyzerComparer : IEqualityComparer + { + public static readonly DiagnosticAnalyzerComparer Instance = new(); + + public bool Equals(DiagnosticAnalyzer? x, DiagnosticAnalyzer? y) + { + if (x is null && y is null) + return true; + + if (x is null || y is null) + return false; + + return x.GetAnalyzerIdAndVersion().GetHashCode() == y.GetAnalyzerIdAndVersion().GetHashCode(); + } + + public int GetHashCode(DiagnosticAnalyzer obj) => obj.GetAnalyzerIdAndVersion().GetHashCode(); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProviderFactory.cs new file mode 100644 index 0000000000000..9f145c3f021d0 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsProviderFactory.cs @@ -0,0 +1,28 @@ +// 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; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Analyzer +{ + internal class AnalyzerSettingsProviderFactory : IWorkspaceSettingsProviderFactory + { + private readonly Workspace _workspace; + private readonly IDiagnosticAnalyzerService _analyzerService; + + public AnalyzerSettingsProviderFactory(Workspace workspace, IDiagnosticAnalyzerService analyzerService) + { + _workspace = workspace; + _analyzerService = analyzerService; + } + + public ISettingsProvider GetForFile(string filePath) + { + var updater = new AnalyzerSettingsUpdater(_workspace, filePath); + return new AnalyzerSettingsProvider(filePath, updater, _workspace, _analyzerService); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs new file mode 100644 index 0000000000000..5b7ed248bf9d8 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Analyzer/AnalyzerSettingsWorkspaceServiceFactory.cs @@ -0,0 +1,29 @@ +// 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.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Analyzer +{ + [ExportWorkspaceServiceFactory(typeof(IWorkspaceSettingsProviderFactory)), Shared] + internal class AnalyzerSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory + { + private readonly IDiagnosticAnalyzerService _analyzerService; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public AnalyzerSettingsWorkspaceServiceFactory(IDiagnosticAnalyzerService analyzerService) + { + _analyzerService = analyzerService; + } + + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + => new AnalyzerSettingsProviderFactory(workspaceServices.Workspace, _analyzerService); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProvider.cs new file mode 100644 index 0000000000000..adcba7ae06210 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProvider.cs @@ -0,0 +1,190 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.CodeStyle +{ + internal class CommonCodeStyleSettingsProvider : SettingsProviderBase + { + public CommonCodeStyleSettingsProvider(string filePath, OptionUpdater settingsUpdater, Workspace workspace) + : base(filePath, settingsUpdater, workspace) + { + Update(); + } + + protected override void UpdateOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions) + { + var qualifySettings = GetQualifyCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(qualifySettings); + + var predefinedTypesSettings = GetPredefinedTypesCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(predefinedTypesSettings); + + var nullCheckingSettings = GetNullCheckingCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(nullCheckingSettings); + + var modifierSettings = GetModifierCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(modifierSettings); + + var codeBlockSettings = GetCodeBlockCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(codeBlockSettings); + + var expressionSettings = GetExpressionCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(expressionSettings); + + var parameterSettings = GetParameterCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(parameterSettings); + + var parenthesesSettings = GetParenthesesCodeStyleOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(parenthesesSettings); + + // TODO(jmarolf): set as stable + } + + private static IEnumerable GetQualifyCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.QualifyFieldAccess, + description: EditorFeaturesResources.Qualify_field_access_with_this_or_Me, + trueValueDescription: EditorFeaturesResources.Prefer_this_or_Me, + falseValueDescription: EditorFeaturesResources.Do_not_prefer_this_or_Me, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.QualifyPropertyAccess, + description: EditorFeaturesResources.Qualify_property_access_with_this_or_Me, + trueValueDescription: EditorFeaturesResources.Prefer_this_or_Me, + falseValueDescription: EditorFeaturesResources.Do_not_prefer_this_or_Me, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.QualifyMethodAccess, + description: EditorFeaturesResources.Qualify_method_access_with_this_or_Me, + trueValueDescription: EditorFeaturesResources.Prefer_this_or_Me, + falseValueDescription: EditorFeaturesResources.Do_not_prefer_this_or_Me, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.QualifyEventAccess, + description: EditorFeaturesResources.Qualify_event_access_with_this_or_Me, + trueValueDescription: EditorFeaturesResources.Prefer_this_or_Me, + falseValueDescription: EditorFeaturesResources.Do_not_prefer_this_or_Me, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + + private static IEnumerable GetPredefinedTypesCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, + description: EditorFeaturesResources.For_locals_parameters_and_members, + trueValueDescription: EditorFeaturesResources.Prefer_predefined_type, + falseValueDescription: EditorFeaturesResources.Prefer_framework_type, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, + description: EditorFeaturesResources.For_member_access_expressions, + trueValueDescription: EditorFeaturesResources.Prefer_predefined_type, + falseValueDescription: EditorFeaturesResources.Prefer_framework_type, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + + private static IEnumerable GetNullCheckingCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferCoalesceExpression, + description: EditorFeaturesResources.Prefer_coalesce_expression, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferNullPropagation, + description: EditorFeaturesResources.Prefer_null_propagation, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferIsNullCheckOverReferenceEqualityMethod, + description: EditorFeaturesResources.Prefer_is_null_for_reference_equality_checks, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + + private static IEnumerable GetModifierCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferReadonly, + description: EditorFeaturesResources.Prefer_readonly_fields, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + + private static IEnumerable GetCodeBlockCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferAutoProperties, + description: EditorFeaturesResources.analyzer_Prefer_auto_properties, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.PreferSystemHashCode, + description: EditorFeaturesResources.Prefer_System_HashCode_in_GetHashCode, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + + private static IEnumerable GetExpressionCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferObjectInitializer, description: EditorFeaturesResources.Prefer_object_initializer, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferCollectionInitializer, description: EditorFeaturesResources.Prefer_collection_initializer, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferSimplifiedBooleanExpressions, description: EditorFeaturesResources.Prefer_simplified_boolean_expressions, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferConditionalExpressionOverAssignment, description: EditorFeaturesResources.Prefer_conditional_expression_over_if_with_assignments, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferConditionalExpressionOverReturn, description: EditorFeaturesResources.Prefer_conditional_expression_over_if_with_returns, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferExplicitTupleNames, description: EditorFeaturesResources.Prefer_explicit_tuple_name, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferInferredTupleNames, description: EditorFeaturesResources.Prefer_inferred_tuple_names, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferInferredAnonymousTypeMemberNames, description: EditorFeaturesResources.Prefer_inferred_anonymous_type_member_names, options, visualStudioOptions, updater); + yield return CodeStyleSetting.Create(CodeStyleOptions2.PreferCompoundAssignment, description: EditorFeaturesResources.Prefer_compound_assignments, options, visualStudioOptions, updater); + } + + private static IEnumerable GetParenthesesCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + var enumValues = new[] { ParenthesesPreference.AlwaysForClarity, ParenthesesPreference.NeverIfUnnecessary }; + var valueDescriptions = new[] { EditorFeaturesResources.Always_for_clarity, EditorFeaturesResources.Never_if_unnecessary }; + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.ArithmeticBinaryParentheses, + description: EditorFeaturesResources.In_arithmetic_binary_operators, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.OtherBinaryParentheses, + description: EditorFeaturesResources.In_other_binary_operators, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.RelationalBinaryParentheses, + description: EditorFeaturesResources.In_relational_binary_operators, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + + yield return CodeStyleSetting.Create(option: CodeStyleOptions2.OtherParentheses, + description: EditorFeaturesResources.In_other_operators, + enumValues: enumValues, + valueDescriptions: valueDescriptions, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + + } + + private static IEnumerable GetParameterCodeStyleOptions(AnalyzerConfigOptions options, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return CodeStyleSetting.Create( + option: CodeStyleOptions2.UnusedParameters, + description: EditorFeaturesResources.Avoid_unused_parameters, + enumValues: new[] { UnusedParametersPreference.NonPublicMethods, UnusedParametersPreference.AllMethods }, + new[] { EditorFeaturesResources.Non_public_methods, EditorFeaturesResources.All_methods }, + editorConfigOptions: options, + visualStudioOptions: visualStudioOptions, updater: updater); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProviderFactory.cs new file mode 100644 index 0000000000000..2477ecf668c1c --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsProviderFactory.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.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.CodeStyle +{ + internal class CommonCodeStyleSettingsProviderFactory : IWorkspaceSettingsProviderFactory + { + private readonly Workspace _workspace; + + public CommonCodeStyleSettingsProviderFactory(Workspace workspace) => _workspace = workspace; + + public ISettingsProvider GetForFile(string filePath) + => new CommonCodeStyleSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsWorkspaceServiceFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsWorkspaceServiceFactory.cs new file mode 100644 index 0000000000000..2a34627f74a2d --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CodeStyle/CommonCodeStyleSettingsWorkspaceServiceFactory.cs @@ -0,0 +1,23 @@ +// 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.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.CodeStyle +{ + [ExportWorkspaceServiceFactory(typeof(IWorkspaceSettingsProviderFactory)), Shared] + internal class CommonCodeStyleSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CommonCodeStyleSettingsWorkspaceServiceFactory() { } + + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + => new CommonCodeStyleSettingsProviderFactory(workspaceServices.Workspace); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedOptionsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedOptionsProviderFactory.cs new file mode 100644 index 0000000000000..1000896c6a68e --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedOptionsProviderFactory.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 System.Collections.Immutable; +using Microsoft.CodeAnalysis.Shared.Collections; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal class CombinedOptionsProviderFactory : ISettingsProviderFactory + { + private ImmutableArray> _factories; + + public CombinedOptionsProviderFactory(ImmutableArray> factories) + { + _factories = factories; + } + + public ISettingsProvider GetForFile(string filePath) + { + var providers = TemporaryArray>.Empty; + foreach (var factory in _factories) + { + providers.Add(factory.GetForFile(filePath)); + } + + return new CombinedProvider(providers.ToImmutableAndClear()); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs new file mode 100644 index 0000000000000..f7eef8dddc1e7 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/CombinedProvider.cs @@ -0,0 +1,49 @@ +// 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.Tasks; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal class CombinedProvider : ISettingsProvider + { + private readonly ImmutableArray> _providers; + + public CombinedProvider(ImmutableArray> providers) + { + _providers = providers; + } + + public async Task GetChangedEditorConfigAsync(SourceText sourceText) + { + foreach (var provider in _providers) + { + sourceText = await provider.GetChangedEditorConfigAsync(sourceText).ConfigureAwait(false); + } + + return sourceText; + } + + public ImmutableArray GetCurrentDataSnapshot() + { + var snapShot = ImmutableArray.Empty; + foreach (var provider in _providers) + { + snapShot = snapShot.Concat(provider.GetCurrentDataSnapshot()); + } + + return snapShot; + } + + public void RegisterViewModel(ISettingsEditorViewModel model) + { + foreach (var provider in _providers) + { + provider.RegisterViewModel(model); + } + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProvider.cs new file mode 100644 index 0000000000000..4a9a86ad21ada --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProvider.cs @@ -0,0 +1,38 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Formatting +{ + internal class CommonFormattingSettingsProvider : SettingsProviderBase + { + public CommonFormattingSettingsProvider(string fileName, OptionUpdater settingsUpdater, Workspace workspace) + : base(fileName, settingsUpdater, workspace) + { + Update(); + } + + protected override void UpdateOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions) + { + var defaultOptions = GetDefaultOptions(editorConfigOptions, visualStudioOptions, SettingsUpdater); + AddRange(defaultOptions); + } + + private static IEnumerable GetDefaultOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions, OptionUpdater updater) + { + yield return FormattingSetting.Create(FormattingOptions2.UseTabs, EditorFeaturesResources.Use_Tabs, editorConfigOptions, visualStudioOptions, updater); + yield return FormattingSetting.Create(FormattingOptions2.TabSize, EditorFeaturesResources.Tab_Size, editorConfigOptions, visualStudioOptions, updater); + yield return FormattingSetting.Create(FormattingOptions2.IndentationSize, EditorFeaturesResources.Indentation_Size, editorConfigOptions, visualStudioOptions, updater); + yield return FormattingSetting.Create(FormattingOptions2.NewLine, EditorFeaturesResources.New_Line, editorConfigOptions, visualStudioOptions, updater); + yield return FormattingSetting.Create(FormattingOptions2.InsertFinalNewLine, EditorFeaturesResources.Insert_Final_Newline, editorConfigOptions, visualStudioOptions, updater); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProviderFactory.cs new file mode 100644 index 0000000000000..21d130c599f42 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsProviderFactory.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.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Formatting +{ + internal class CommonFormattingSettingsProviderFactory : IWorkspaceSettingsProviderFactory + { + private readonly Workspace _workspace; + + public CommonFormattingSettingsProviderFactory(Workspace workspace) => _workspace = workspace; + + public ISettingsProvider GetForFile(string filePath) + => new CommonFormattingSettingsProvider(filePath, new OptionUpdater(_workspace, filePath), _workspace); + + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsWorkspaceServiceFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsWorkspaceServiceFactory.cs new file mode 100644 index 0000000000000..878bd1198987d --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/Formatting/CommonFormattingSettingsWorkspaceServiceFactory.cs @@ -0,0 +1,23 @@ +// 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.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.Formatting +{ + [ExportWorkspaceServiceFactory(typeof(IWorkspaceSettingsProviderFactory)), Shared] + internal class CommonFormattingSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CommonFormattingSettingsWorkspaceServiceFactory() { } + + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + => new CommonFormattingSettingsProviderFactory(workspaceServices.Workspace); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ILanguageSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ILanguageSettingsProviderFactory.cs new file mode 100644 index 0000000000000..800df15d4f056 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ILanguageSettingsProviderFactory.cs @@ -0,0 +1,12 @@ +// 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.Host; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal interface ILanguageSettingsProviderFactory : ISettingsProviderFactory, ILanguageService + { + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProvider.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProvider.cs new file mode 100644 index 0000000000000..7eaece9b9f9ed --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProvider.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 System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal interface ISettingsProvider + { + void RegisterViewModel(ISettingsEditorViewModel model); + ImmutableArray GetCurrentDataSnapshot(); + Task GetChangedEditorConfigAsync(SourceText sourceText); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProviderFactory.cs new file mode 100644 index 0000000000000..4c87bfb021ae3 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/ISettingsProviderFactory.cs @@ -0,0 +1,11 @@ +// 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. + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal interface ISettingsProviderFactory + { + ISettingsProvider GetForFile(string filePath); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/IWorkspaceSettingsProviderFactory.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/IWorkspaceSettingsProviderFactory.cs new file mode 100644 index 0000000000000..a241256ac0d26 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/IWorkspaceSettingsProviderFactory.cs @@ -0,0 +1,12 @@ +// 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.Host; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal interface IWorkspaceSettingsProviderFactory : ISettingsProviderFactory, IWorkspaceService + { + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs new file mode 100644 index 0000000000000..c39d19813506b --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/DataProvider/SettingsProviderBase.cs @@ -0,0 +1,130 @@ +// 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.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Utilities; +using static Microsoft.CodeAnalysis.ProjectState; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider +{ + internal abstract class SettingsProviderBase : ISettingsProvider + where TOptionsUpdater : ISettingUpdater + { + private readonly List _snapshot = new(); + private static readonly object s_gate = new(); + private ISettingsEditorViewModel? _viewModel; + protected readonly string FileName; + protected readonly TOptionsUpdater SettingsUpdater; + protected readonly Workspace Workspace; + + protected abstract void UpdateOptions(AnalyzerConfigOptions editorConfigOptions, OptionSet visualStudioOptions); + + protected SettingsProviderBase(string fileName, TOptionsUpdater settingsUpdater, Workspace workspace) + { + FileName = fileName; + SettingsUpdater = settingsUpdater; + Workspace = workspace; + } + + protected void Update() + { + var givenFolder = new DirectoryInfo(FileName).Parent; + var solution = Workspace.CurrentSolution; + var projects = solution.GetProjectsForPath(FileName); + var project = projects.First(); + var configOptionsProvider = new WorkspaceAnalyzerConfigOptionsProvider(project.State); + var workspaceOptions = configOptionsProvider.GetOptionsForSourcePath(givenFolder.FullName); + var result = project.GetAnalyzerConfigOptions(); + var options = new CombinedAnalyzerConfigOptions(workspaceOptions, result); + UpdateOptions(options, Workspace.Options); + } + + public async Task GetChangedEditorConfigAsync(SourceText sourceText) + { + if (!await SettingsUpdater.HasAnyChangesAsync().ConfigureAwait(false)) + { + return sourceText; + } + + var text = await SettingsUpdater.GetChangedEditorConfigAsync(sourceText, default).ConfigureAwait(false); + return text is not null ? text : sourceText; + } + + public ImmutableArray GetCurrentDataSnapshot() + { + lock (s_gate) + { + return _snapshot.ToImmutableArray(); + } + } + + protected void AddRange(IEnumerable items) + { + lock (s_gate) + { + _snapshot.AddRange(items); + } + + _viewModel?.NotifyOfUpdate(); + } + + public void RegisterViewModel(ISettingsEditorViewModel viewModel) + => _viewModel = viewModel ?? throw new ArgumentNullException(nameof(viewModel)); + + private sealed class CombinedAnalyzerConfigOptions : AnalyzerConfigOptions + { + private readonly AnalyzerConfigOptions _workspaceOptions; + private readonly AnalyzerConfigOptionsResult? _result; + + public CombinedAnalyzerConfigOptions(AnalyzerConfigOptions workspaceOptions, AnalyzerConfigOptionsResult? result) + { + _workspaceOptions = workspaceOptions; + _result = result; + } + + public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) + { + if (_workspaceOptions.TryGetValue(key, out value)) + { + return true; + } + + if (!_result.HasValue) + { + value = null; + return false; + } + + if (_result.Value.AnalyzerOptions.TryGetValue(key, out value)) + { + return true; + } + + var diagnosticKey = "dotnet_diagnostic.(?.*).severity"; + var match = Regex.Match(key, diagnosticKey); + if (match.Success && match.Groups["key"].Value is string isolatedKey && + _result.Value.TreeOptions.TryGetValue(isolatedKey, out var severity)) + { + value = severity.ToEditorConfigString(); + return true; + } + + value = null; + return false; + } + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Extensions/EnumerableExtensions.cs b/src/EditorFeatures/Core/EditorConfigSettings/Extensions/EnumerableExtensions.cs new file mode 100644 index 0000000000000..6ef0a5228cda0 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Extensions/EnumerableExtensions.cs @@ -0,0 +1,24 @@ +// 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; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions +{ + internal static class EnumerableExtensions + { + public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) + { + var seenKeys = new HashSet(); + foreach (var element in source) + { + if (seenKeys.Add(keySelector(element))) + { + yield return element; + } + } + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.cs b/src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.cs new file mode 100644 index 0000000000000..fe06a29a6b5c8 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Extensions/SolutionExtensions.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.Immutable; +using System.IO; +using System.Linq; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions +{ + internal static class SolutionExtensions + { + public static ImmutableArray GetProjectsForPath(this Solution solution, string givenPath) + { + if (Path.GetDirectoryName(givenPath) is not string givenFolderPath || + solution.FilePath is null) + { + return solution.Projects.ToImmutableArray(); + } + + var givenFolder = new DirectoryInfo(givenFolderPath); + if (givenFolder.FullName == (new DirectoryInfo(solution.FilePath).Parent).FullName) + { + return solution.Projects.ToImmutableArray(); + } + + var builder = ArrayBuilder.GetInstance(); + foreach (var (projectDirectoryPath, project) in solution.Projects.Select(p => (new DirectoryInfo(p.FilePath).Parent, p))) + { + if (ContainsPath(givenFolder, projectDirectoryPath)) + { + builder.Add(project); + } + } + + return builder.ToImmutableAndFree(); + + static bool ContainsPath(DirectoryInfo givenPath, DirectoryInfo projectPath) + { + if (projectPath.FullName == givenPath.FullName) + { + return true; + } + + while (projectPath.Parent is not null) + { + if (projectPath.Parent.FullName == givenPath.FullName) + { + return true; + } + projectPath = projectPath.Parent; + } + + return false; + } + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/ISettingsEditorViewModel.cs b/src/EditorFeatures/Core/EditorConfigSettings/ISettingsEditorViewModel.cs new file mode 100644 index 0000000000000..5cabb84670fd5 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/ISettingsEditorViewModel.cs @@ -0,0 +1,16 @@ +// 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.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor +{ + internal interface ISettingsEditorViewModel + { + void NotifyOfUpdate(); + Task UpdateEditorConfigAsync(SourceText sourceText); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Language.cs b/src/EditorFeatures/Core/EditorConfigSettings/Language.cs new file mode 100644 index 0000000000000..54002e7c301c0 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Language.cs @@ -0,0 +1,15 @@ +// 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; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings +{ + [Flags] + internal enum Language + { + CSharp = 1, + VisualBasic = 2, + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/AnalyzerSettingsUpdater.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/AnalyzerSettingsUpdater.cs new file mode 100644 index 0000000000000..f96b83172e91a --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/AnalyzerSettingsUpdater.cs @@ -0,0 +1,24 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater +{ + internal class AnalyzerSettingsUpdater : SettingsUpdaterBase + { + public AnalyzerSettingsUpdater(Workspace workspace, string editorconfigPath) : base(workspace, editorconfigPath) + { + } + + protected override SourceText? GetNewText(SourceText sourceText, + IReadOnlyList<(AnalyzerSetting option, DiagnosticSeverity value)> settingsToUpdate, + CancellationToken token) + => SettingsUpdateHelper.TryUpdateAnalyzerConfigDocument(sourceText, EditorconfigPath, settingsToUpdate); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/ISettingUpdater.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/ISettingUpdater.cs new file mode 100644 index 0000000000000..fac1c922c97b6 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/ISettingUpdater.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 System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater +{ + internal interface ISettingUpdater + { + Task QueueUpdateAsync(TSetting setting, TValue value); + Task GetChangedEditorConfigAsync(SourceText sourceText, CancellationToken token); + Task HasAnyChangesAsync(); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/OptionUpdater.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/OptionUpdater.cs new file mode 100644 index 0000000000000..f57e0d103d397 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/OptionUpdater.cs @@ -0,0 +1,26 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater +{ + + internal class OptionUpdater : SettingsUpdaterBase + { + public OptionUpdater(Workspace workspace, string editorconfigPath) + : base(workspace, editorconfigPath) + { + } + + protected override SourceText? GetNewText(SourceText SourceText, + IReadOnlyList<(IOption2 option, object value)> settingsToUpdate, + CancellationToken token) + => SettingsUpdateHelper.TryUpdateAnalyzerConfigDocument(SourceText, EditorconfigPath, Workspace.Options, settingsToUpdate); + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs new file mode 100644 index 0000000000000..dd5ca9a124dc7 --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdateHelper.cs @@ -0,0 +1,352 @@ +// 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.RegularExpressions; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater +{ + internal static partial class SettingsUpdateHelper + { + private const string DiagnosticOptionPrefix = "dotnet_diagnostic."; + private const string SeveritySuffix = ".severity"; + + public static SourceText? TryUpdateAnalyzerConfigDocument(SourceText originalText, + string filePath, + IReadOnlyList<(AnalyzerSetting option, DiagnosticSeverity value)> settingsToUpdate) + { + if (originalText is null) + return null; + if (settingsToUpdate is null) + return null; + if (filePath is null) + return null; + + var settings = settingsToUpdate.Select(x => TryGetOptionValueAndLanguage(x.option, x.value)).ToList(); + + return TryUpdateAnalyzerConfigDocument(originalText, filePath, settings); + + static (string option, string value, Language language) TryGetOptionValueAndLanguage(AnalyzerSetting diagnostic, DiagnosticSeverity severity) + { + var optionName = $"{DiagnosticOptionPrefix}{diagnostic.Id}{SeveritySuffix}"; + var optionValue = severity.ToEditorConfigString(); + var language = diagnostic.Language; + return (optionName, optionValue, language); + } + } + + public static SourceText? TryUpdateAnalyzerConfigDocument(SourceText originalText, + string filePath, + OptionSet optionSet, + IReadOnlyList<(IOption2 option, object value)> settingsToUpdate) + { + if (originalText is null) + return null; + if (settingsToUpdate is null) + return null; + if (filePath is null) + return null; + + var updatedText = originalText; + var settings = settingsToUpdate.Select(x => TryGetOptionValueAndLanguage(x.option, x.value, optionSet)) + .Where(x => x.success) + .Select(x => (x.option, x.value, x.language)) + .ToList(); + + return TryUpdateAnalyzerConfigDocument(originalText, filePath, settings); + + static (bool success, string option, string value, Language language) TryGetOptionValueAndLanguage(IOption2 option, object value, OptionSet optionSet) + { + if (option.StorageLocations.FirstOrDefault(x => x is IEditorConfigStorageLocation2) is not IEditorConfigStorageLocation2 storageLocation) + { + return (false, null!, null!, default); + } + + var optionName = storageLocation.KeyName; + var optionValue = storageLocation.GetEditorConfigStringValue(value, optionSet); + if (value is ICodeStyleOption codeStyleOption && !optionValue.Contains(':')) + { + var severity = codeStyleOption.Notification switch + { + { Severity: ReportDiagnostic.Hidden } => "silent", + { Severity: ReportDiagnostic.Info } => "suggestion", + { Severity: ReportDiagnostic.Warn } => "warning", + { Severity: ReportDiagnostic.Error } => "error", + _ => string.Empty + }; + optionValue = $"{optionValue}:{severity}"; + } + + var language = option.IsPerLanguage ? Language.CSharp | Language.VisualBasic : Language.CSharp; + return (true, optionName, optionValue, language); + } + } + + public static SourceText? TryUpdateAnalyzerConfigDocument(SourceText originalText, + string filePath, + IReadOnlyList<(string option, string value, Language language)> settingsToUpdate) + { + if (originalText is null) + throw new ArgumentNullException(nameof(originalText)); + if (filePath is null) + throw new ArgumentNullException(nameof(filePath)); + if (settingsToUpdate is null) + throw new ArgumentNullException(nameof(settingsToUpdate)); + + var updatedText = originalText; + TextLine? lastValidHeaderSpanEnd; + TextLine? lastValidSpecificHeaderSpanEnd; + foreach (var (option, value, language) in settingsToUpdate) + { + SourceText? newText; + (newText, lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd) = UpdateIfExistsInFile(updatedText, filePath, option, value, language); + if (newText != null) + { + updatedText = newText; + continue; + } + + (newText, lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd) = AddMissingRule(updatedText, lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd, option, value, language); + if (newText != null) + { + updatedText = newText; + } + } + + return updatedText.Equals(originalText) ? null : updatedText; + } + + /// + /// Regular expression for .editorconfig header. + /// For example: "[*.cs] # Optional comment" + /// "[*.{vb,cs}]" + /// "[*] ; Optional comment" + /// "[ConsoleApp/Program.cs]" + /// + private static readonly Regex s_headerPattern = new(@"\[(\*|[^ #;\[\]]+\.({[^ #;{}\.\[\]]+}|[^ #;{}\.\[\]]+))\]\s*([#;].*)?"); + + /// + /// Regular expression for .editorconfig code style option entry. + /// For example: + /// 1. "dotnet_style_object_initializer = true # Optional comment" + /// 2. "dotnet_style_object_initializer = true:suggestion ; Optional comment" + /// 3. "dotnet_diagnostic.CA2000.severity = suggestion # Optional comment" + /// 4. "dotnet_analyzer_diagnostic.category-Security.severity = suggestion # Optional comment" + /// 5. "dotnet_analyzer_diagnostic.severity = suggestion # Optional comment" + /// Regex groups: + /// 1. Option key + /// 2. Option value + /// 3. Optional severity suffix in option value, i.e. ':severity' suffix + /// 4. Optional comment suffix + /// + private static readonly Regex s_optionEntryPattern = new($@"(.*)=([\w, ]*)(:[\w]+)?([ ]*[;#].*)?"); + + private static (SourceText? newText, TextLine? lastValidHeaderSpanEnd, TextLine? lastValidSpecificHeaderSpanEnd) UpdateIfExistsInFile(SourceText editorConfigText, + string filePath, + string optionName, + string optionValue, + Language language) + { + var editorConfigDirectory = PathUtilities.GetDirectoryName(filePath); + Assumes.NotNull(editorConfigDirectory); + var relativePath = PathUtilities.GetRelativePath(editorConfigDirectory.ToLowerInvariant(), filePath); + + TextLine? mostRecentHeader = null; + TextLine? lastValidHeader = null; + TextLine? lastValidHeaderSpanEnd = null; + + TextLine? lastValidSpecificHeader = null; + TextLine? lastValidSpecificHeaderSpanEnd = null; + + var textChange = new TextChange(); + foreach (var curLine in editorConfigText.Lines) + { + var curLineText = curLine.ToString(); + if (s_optionEntryPattern.IsMatch(curLineText)) + { + var groups = s_optionEntryPattern.Match(curLineText).Groups; + var (untrimmedKey, key, value, severity, comment) = GetGroups(groups); + + // Verify the most recent header is a valid header + if (IsValidHeader(mostRecentHeader, lastValidHeader) && + string.Equals(key, optionName, StringComparison.OrdinalIgnoreCase)) + { + // We found the rule in the file -- replace it with updated option value. + textChange = new TextChange(curLine.Span, $"{untrimmedKey}={optionValue}{comment}"); + } + } + else if (s_headerPattern.IsMatch(curLineText.Trim())) + { + mostRecentHeader = curLine; + if (ShouldSetAsLastValidHeader(curLineText, out var mostRecentHeaderText)) + { + lastValidHeader = mostRecentHeader; + } + else + { + var (fileName, splicedFileExtensions) = ParseHeaderParts(mostRecentHeaderText); + if ((relativePath.IsEmpty() || new Regex(fileName).IsMatch(relativePath)) && + HeaderMatchesLanguageRequirements(language, splicedFileExtensions)) + { + lastValidHeader = mostRecentHeader; + } + } + } + + // We want to keep track of how far this (valid) section spans. + if (IsValidHeader(mostRecentHeader, lastValidHeader) && IsNotEmptyOrComment(curLineText)) + { + lastValidHeaderSpanEnd = curLine; + if (lastValidSpecificHeader != null && mostRecentHeader.Equals(lastValidSpecificHeader)) + { + lastValidSpecificHeaderSpanEnd = curLine; + } + } + } + + // We return only the last text change in case of duplicate entries for the same rule. + if (textChange != default) + { + return (editorConfigText.WithChanges(textChange), lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd); + } + + // Rule not found. + return (null, lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd); + + static (string untrimmedKey, string key, string value, string severitySuffixInValue, string commentValue) GetGroups(GroupCollection groups) + { + var untrimmedKey = groups[1].Value.ToString(); + var key = untrimmedKey.Trim(); + var value = groups[2].Value.ToString(); + var severitySuffixInValue = groups[3].Value.ToString(); + var commentValue = groups[4].Value.ToString(); + return (untrimmedKey, key, value, severitySuffixInValue, commentValue); + } + + static bool IsValidHeader(TextLine? mostRecentHeader, TextLine? lastValidHeader) + { + return mostRecentHeader is not null && + lastValidHeader is not null && + mostRecentHeader.Equals(lastValidHeader); + } + + static bool ShouldSetAsLastValidHeader(string curLineText, out string mostRecentHeaderText) + { + var groups = s_headerPattern.Match(curLineText.Trim()).Groups; + mostRecentHeaderText = groups[1].Value.ToString().ToLowerInvariant(); + return mostRecentHeaderText.Equals("*", StringComparison.Ordinal); + } + + static (string fileName, string[] splicedFileExtensions) ParseHeaderParts(string mostRecentHeaderText) + { + // We splice on the last occurrence of '.' to account for filenames containing periods. + var nameExtensionSplitIndex = mostRecentHeaderText.LastIndexOf('.'); + var fileName = mostRecentHeaderText.Substring(0, nameExtensionSplitIndex); + var splicedFileExtensions = mostRecentHeaderText[(nameExtensionSplitIndex + 1)..].Split(',', ' ', '{', '}'); + + // Replacing characters in the header with the regex equivalent. + fileName = fileName.Replace(".", @"\."); + fileName = fileName.Replace("*", ".*"); + fileName = fileName.Replace("/", @"\/"); + + return (fileName, splicedFileExtensions); + } + + static bool IsNotEmptyOrComment(string currentLineText) + { + return !string.IsNullOrWhiteSpace(currentLineText) && !currentLineText.Trim().StartsWith("#", StringComparison.OrdinalIgnoreCase); + } + + static bool HeaderMatchesLanguageRequirements(Language language, string[] splicedFileExtensions) + { + return IsCSharpOnly(language, splicedFileExtensions) || IsVisualBasicOnly(language, splicedFileExtensions) || IsBothVisualBasicAndCSharp(language, splicedFileExtensions); + } + + static bool IsCSharpOnly(Language language, string[] splicedFileExtensions) + { + return language.HasFlag(Language.CSharp) && !language.HasFlag(Language.VisualBasic) && splicedFileExtensions.Contains("cs") && splicedFileExtensions.Length == 1; + } + + static bool IsVisualBasicOnly(Language language, string[] splicedFileExtensions) + { + return language.HasFlag(Language.VisualBasic) && !language.HasFlag(Language.CSharp) && splicedFileExtensions.Contains("vb") && splicedFileExtensions.Length == 1; + } + + static bool IsBothVisualBasicAndCSharp(Language language, string[] splicedFileExtensions) + { + return language.HasFlag(Language.VisualBasic) && language.HasFlag(Language.CSharp) && splicedFileExtensions.Contains("vb") && splicedFileExtensions.Contains("cs"); + } + } + + private static (SourceText? newText, TextLine? lastValidHeaderSpanEnd, TextLine? lastValidSpecificHeaderSpanEnd) AddMissingRule(SourceText editorConfigText, + TextLine? lastValidHeaderSpanEnd, + TextLine? lastValidSpecificHeaderSpanEnd, + string optionName, + string optionValue, + Language language) + { + var newEntry = $"{optionName}={optionValue}"; + if (lastValidSpecificHeaderSpanEnd.HasValue) + { + if (lastValidSpecificHeaderSpanEnd.Value.ToString().Trim().Length != 0) + { + newEntry = "\r\n" + newEntry; // TODO(jmarolf): do we need to read in the users newline settings? + } + + return (editorConfigText.WithChanges((TextChange)new TextChange(new TextSpan(lastValidSpecificHeaderSpanEnd.Value.Span.End, 0), newEntry)), lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd); + } + else if (lastValidHeaderSpanEnd.HasValue) + { + if (lastValidHeaderSpanEnd.Value.ToString().Trim().Length != 0) + { + newEntry = "\r\n" + newEntry; // TODO(jmarolf): do we need to read in the users newline settings? + } + + return (editorConfigText.WithChanges((TextChange)new TextChange(new TextSpan(lastValidHeaderSpanEnd.Value.Span.End, 0), newEntry)), lastValidHeaderSpanEnd, lastValidSpecificHeaderSpanEnd); + } + + // We need to generate a new header such as '[*.cs]' or '[*.vb]': + // - For compiler diagnostic entries and code style entries which have per-language option = false, generate only [*.cs] or [*.vb]. + // - For the remainder, generate [*.{cs,vb}] + // Insert a newline if not already present + var lines = editorConfigText.Lines; + var lastLine = lines.Count > 0 ? lines[^1] : default; + var prefix = string.Empty; + if (lastLine.ToString().Trim().Length != 0) + { + prefix = "\r\n"; + } + + // Insert newline if file is not empty + if (lines.Count > 1 && lastLine.ToString().Trim().Length == 0) + { + prefix += "\r\n"; + } + + if (language.HasFlag(Language.CSharp) && language.HasFlag(Language.VisualBasic)) + { + prefix += "[*.{cs,vb}]\r\n"; + } + else if (language.HasFlag(Language.CSharp)) + { + prefix += "[*.cs]\r\n"; + } + else if (language.HasFlag(Language.VisualBasic)) + { + prefix += "[*.vb]\r\n"; + } + + var result = editorConfigText.WithChanges((TextChange)new TextChange(new TextSpan(editorConfigText.Length, 0), prefix + newEntry)); + return (result, lastValidHeaderSpanEnd, result.Lines[^2]); + } + } +} diff --git a/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdaterBase.cs b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdaterBase.cs new file mode 100644 index 0000000000000..e9eea754fdfcc --- /dev/null +++ b/src/EditorFeatures/Core/EditorConfigSettings/Updater/SettingsUpdaterBase.cs @@ -0,0 +1,103 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater +{ + internal abstract class SettingsUpdaterBase : ISettingUpdater + { + private readonly List<(TOption option, TValue value)> _queue = new(); + private readonly SemaphoreSlim _guard = new(1); + protected readonly Workspace Workspace; + protected readonly string EditorconfigPath; + + protected abstract SourceText? GetNewText(SourceText analyzerConfigDocument, IReadOnlyList<(TOption option, TValue value)> settingsToUpdate, CancellationToken token); + + protected SettingsUpdaterBase(Workspace workspace, string editorconfigPath) + { + Workspace = workspace; + EditorconfigPath = editorconfigPath; + } + + public async Task QueueUpdateAsync(TOption setting, TValue value) + { + using (await _guard.DisposableWaitAsync().ConfigureAwait(false)) + { + _queue.Add((setting, value)); + } + + return true; + } + + public async Task GetChangedEditorConfigAsync(AnalyzerConfigDocument analyzerConfigDocument, CancellationToken token) + { + if (analyzerConfigDocument is null) + return null; + + var originalText = await analyzerConfigDocument.GetTextAsync(token).ConfigureAwait(false); + using (await _guard.DisposableWaitAsync(token).ConfigureAwait(false)) + { + var newText = GetNewText(originalText, _queue, token); + if (newText is null || newText.Equals(originalText)) + { + _queue.Clear(); + return null; + } + else + { + _queue.Clear(); + return newText; + } + } + } + + public async Task?> GetChangedEditorConfigAsync(CancellationToken token) + { + var solution = Workspace.CurrentSolution; + var analyzerConfigDocument = solution.Projects + .SelectMany(p => p.AnalyzerConfigDocuments) + .FirstOrDefault(d => d.FilePath == EditorconfigPath); + var newText = await GetChangedEditorConfigAsync(analyzerConfigDocument, token).ConfigureAwait(false); + if (newText is null) + { + return null; + } + + var originalText = await analyzerConfigDocument.GetTextAsync(token).ConfigureAwait(false); + return newText.GetTextChanges(originalText); + } + + public async Task GetChangedEditorConfigAsync(SourceText originalText, CancellationToken token) + { + using (await _guard.DisposableWaitAsync(token).ConfigureAwait(false)) + { + var newText = GetNewText(originalText, _queue, token); + if (newText is null || newText.Equals(originalText)) + { + _queue.Clear(); + return null; + } + else + { + _queue.Clear(); + return newText; + } + } + } + + public async Task HasAnyChangesAsync() + { + using (await _guard.DisposableWaitAsync().ConfigureAwait(false)) + { + return _queue.Any(); + } + } + } +} diff --git a/src/EditorFeatures/Core/EditorFeaturesResources.resx b/src/EditorFeatures/Core/EditorFeaturesResources.resx index 78f79c7e0045c..2f6899e590dce 100644 --- a/src/EditorFeatures/Core/EditorFeaturesResources.resx +++ b/src/EditorFeatures/Core/EditorFeaturesResources.resx @@ -951,4 +951,127 @@ Do you want to proceed? Gathering Suggestions - Waiting for the solution to fully load + + No + + + Yes + + + Always for clarity + + + Prefer auto properties + + + Avoid unused parameters + + + Do not prefer 'this.' or 'Me.' + + + For locals, parameters and members + + + For member access expressions + + + In arithmetic operators + + + In other binary operators + + + In other operators + + + In relational operators + + + Never if unnecessary + + + Non-public methods + + + Prefer coalesce expression + + + Prefer collection initializer + + + Prefer compound assignments + + + Prefer conditional expression over 'if' with assignments + + + Prefer conditional expression over 'if' with returns + + + Prefer explicit tuple name + + + Prefer framework type + + + Prefer inferred anonymous type member names + + + Prefer inferred tuple element names + + + Prefer 'is null' for reference equality checks + + + Prefer null propagation + + + Prefer object initializer + + + Prefer predefined type + + + Prefer readonly fields + + + Prefer simplified boolean expressions + + + Prefer 'System.HashCode' in 'GetHashCode' + + + Prefer 'this.' or 'Me.' + + + Qualify event access with 'this' or 'Me' + + + Qualify field access with 'this' or 'Me' + + + Qualify method access with 'this' or 'Me' + + + Qualify property access with 'this' or 'Me' + + + Indentation Size + + + Insert Final Newline + + + New Line + + + Tab Size + + + Use Tabs + + + All methods + \ No newline at end of file diff --git a/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameSession.OpenTextBufferManager.cs b/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameSession.OpenTextBufferManager.cs index 4b6f5cff8a1aa..72926d07b4379 100644 --- a/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameSession.OpenTextBufferManager.cs +++ b/src/EditorFeatures/Core/Implementation/InlineRename/InlineRenameSession.OpenTextBufferManager.cs @@ -575,7 +575,7 @@ private static async Task> GetTextChangesFromTextDiffere return await textDiffService.GetTextChangesAsync(oldDocument, newDocument, cancellationToken).ConfigureAwait(false); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs index 1f3392502d905..d823111a2c14e 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs @@ -78,7 +78,7 @@ public async Task GetQuickInfoItemAsync(IAsyncQuickIn return null; } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs b/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs index 5f15c01a7d742..38303ffe9bd5d 100644 --- a/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs +++ b/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.StateMachine.cs @@ -318,7 +318,7 @@ public bool CanInvokeRename( return default; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.cs b/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.cs index 43ca512dd0487..bedb12af88e09 100644 --- a/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/RenameTracking/RenameTrackingTaggerProvider.cs @@ -125,7 +125,7 @@ public static (CodeAction action, TextSpan renameSpan) TryGetCodeAction( return default; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs index 758e74f32f202..a9b67d3afb5ce 100644 --- a/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs +++ b/src/EditorFeatures/Core/Shared/Options/FeatureOnOffOptions.cs @@ -85,8 +85,13 @@ internal static class FeatureOnOffOptions storageLocations: new RoamingProfileStorageLocation($"TextEditor.%LANGUAGE%.Specific.{nameof(AddImportsOnPaste)}")); public static readonly Option2 OfferRemoveUnusedReferences = new( - nameof(FeatureOnOffOptions), nameof(OfferRemoveUnusedReferences), defaultValue: null, + nameof(FeatureOnOffOptions), nameof(OfferRemoveUnusedReferences), defaultValue: true, storageLocations: new RoamingProfileStorageLocation($"TextEditor.{nameof(OfferRemoveUnusedReferences)}")); + + public static readonly Option2 AutomaticallyCompleteStatementOnSemicolon = new( + nameof(FeatureOnOffOptions), nameof(AutomaticallyCompleteStatementOnSemicolon), defaultValue: true, + storageLocations: new RoamingProfileStorageLocation($"TextEditor.{nameof(AutomaticallyCompleteStatementOnSemicolon)}")); + } [ExportOptionProvider, Shared] @@ -117,6 +122,7 @@ public FeatureOnOffOptionsProvider() FeatureOnOffOptions.NavigateToDecompiledSources, FeatureOnOffOptions.UseEnhancedColors, FeatureOnOffOptions.AddImportsOnPaste, - FeatureOnOffOptions.OfferRemoveUnusedReferences); + FeatureOnOffOptions.OfferRemoveUnusedReferences, + FeatureOnOffOptions.AutomaticallyCompleteStatementOnSemicolon); } } diff --git a/src/EditorFeatures/Core/Shared/Utilities/WorkspaceThreadingService.cs b/src/EditorFeatures/Core/Shared/Utilities/WorkspaceThreadingService.cs new file mode 100644 index 0000000000000..ec046b340bf44 --- /dev/null +++ b/src/EditorFeatures/Core/Shared/Utilities/WorkspaceThreadingService.cs @@ -0,0 +1,31 @@ +// 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 System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities +{ + [Export(typeof(IWorkspaceThreadingService))] + [Shared] + internal sealed class WorkspaceThreadingService : IWorkspaceThreadingService + { + private readonly IThreadingContext _threadingContext; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public WorkspaceThreadingService(IThreadingContext threadingContext) + { + _threadingContext = threadingContext; + } + + public TResult Run(Func> asyncMethod) + { + return _threadingContext.JoinableTaskFactory.Run(asyncMethod); + } + } +} diff --git a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.Update.cs b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.Update.cs index 14b5bdb515406..6678a04b17f11 100644 --- a/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.Update.cs +++ b/src/EditorFeatures/Core/SymbolSearch/SymbolSearchUpdateEngine.Update.cs @@ -638,7 +638,11 @@ private async Task ConvertContentAttributeAsync(XAttribute contentsAttri using (var inStream = new MemoryStream(compressedBytes)) using (var deflateStream = new DeflateStream(inStream, CompressionMode.Decompress)) { +#if NETCOREAPP + await deflateStream.CopyToAsync(outStream, cancellationToken).ConfigureAwait(false); +#else await deflateStream.CopyToAsync(outStream).ConfigureAwait(false); +#endif } var bytes = outStream.ToArray(); diff --git a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs index e02d6e9449114..bc682bd43152b 100644 --- a/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs +++ b/src/EditorFeatures/Core/Tagging/AbstractAsynchronousTaggerProvider.TagSource_ProduceTags.cs @@ -566,7 +566,7 @@ private void ProcessNewTagTrees( { await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); UpdateStateAndReportChanges(newTagTrees, bufferToChanges, newState, initialTags); - }).CompletesAsyncOperation(asyncToken); + }, CancellationToken.None).CompletesAsyncOperation(asyncToken); // TODO: What should the cancellation behavior be here? passing CancellationToken.None for now } else { diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf index f021a47cec7e1..6539fa8dcfff7 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Relace přejmenování na řádku je pro identifikátor {0} aktivní. Pokud chcete získat přístup k dalším možnostem, znovu volejte přejmenování na řádku. Můžete kdykoli pokračovat v úpravách identifikátoru, který se přejmenovává. @@ -12,6 +22,11 @@ Aplikují se změny. + + Avoid unused parameters + Avoid unused parameters + + Change configuration Změnit konfiguraci @@ -27,6 +42,11 @@ Nakonfigurovat teď + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Tuto zprávu už příště nezobrazovat @@ -57,6 +77,16 @@ Filtr Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup Příkaz Formátovat dokument provedl další čištění. @@ -87,11 +117,41 @@ Přejít na základní typ + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Vložené nápovědy + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Neplatný název sestavení @@ -112,6 +172,26 @@ Hledají se báze... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operátor – přetížení @@ -122,6 +202,91 @@ Sledování vkládání + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Text preprocesoru @@ -132,6 +297,26 @@ Interpunkce + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Přejmenovat _soubor (typ neodpovídá názvu souboru) @@ -162,6 +347,11 @@ Symbol – statický + + Tab Size + Tab Size + + The symbol has no base. Tento symbol nemá žádný základ. @@ -187,6 +377,11 @@ Přepíná se komentář k řádku... + + Use Tabs + Use Tabs + + User Members - Constants Uživatelské členy – konstanty @@ -412,6 +607,11 @@ Při přejmenování dojde k aktualizaci {0} odkazů v {1} souborech. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Tento element nejde přejmenovat, protože je obsažen v souboru jen pro čtení. @@ -632,6 +832,11 @@ Už se sleduje dokument se shodným klíčem. + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked Dokument se aktuálně nesleduje. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf index d95dac708cd4a..7dab8aa18dd1f 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Für den Bezeichner "{0}" ist eine Inline-Umbenennungssitzung aktiv. Rufen Sie die Inline-Umbenennung erneut auf, um auf zusätzliche Optionen zuzugreifen. Sie können den Bezeichner, der gerade umbenannt wird, jederzeit weiterbearbeiten. @@ -12,6 +22,11 @@ Änderungen werden übernommen + + Avoid unused parameters + Avoid unused parameters + + Change configuration Konfiguration ändern @@ -27,6 +42,11 @@ Jetzt konfigurieren + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Diese Meldung nicht mehr anzeigen @@ -57,6 +77,16 @@ Filter Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup Bei der Dokumentformatierung wurde eine zusätzliche Bereinigung durchgeführt. @@ -87,11 +117,41 @@ Zu Basis wechseln + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Inlinehinweise + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Ungültiger Assemblyname. @@ -112,6 +172,26 @@ Basen werden gesucht... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operator - überladen @@ -122,6 +202,91 @@ Nachverfolgung von Einfügevorgängen + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Präprozessortext @@ -132,6 +297,26 @@ Interpunktion + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) _Datei umbenennen (Typ entspricht nicht dem Dateinamen) @@ -162,6 +347,11 @@ Symbol – statisch + + Tab Size + Tab Size + + The symbol has no base. Das Symbol verfügt über keine Basis. @@ -187,6 +377,11 @@ Kommentarzeile wird ein-/ausgeschaltet... + + Use Tabs + Use Tabs + + User Members - Constants Benutzermember – Konstanten @@ -412,6 +607,11 @@ Durch das Umbenennen werden {0} Verweise in {1} Dateien aktualisiert. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Dieses Element kann nicht umbenannt werden, weil es in einer schreibgeschützten Datei enthalten ist. @@ -632,6 +832,11 @@ Dokument mit identischem Schlüssel wird bereits verfolgt + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked Dokument wird aktuell nicht verfolgt diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf index 1851eb7accc6d..91f0299c0d109 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Hay una sesión de cambio de nombre insertado que está activa para el identificador "{0}". Vuelva a invocar el cambio de nombre insertado para acceder a más opciones. Puede continuar editando el identificador cuyo nombre se va a cambiar en cualquier momento. @@ -12,6 +22,11 @@ Aplicando cambios + + Avoid unused parameters + Avoid unused parameters + + Change configuration Configuración de cambio @@ -27,6 +42,11 @@ Configúrela ahora + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again No volver a mostrar este mensaje @@ -57,6 +77,16 @@ Filtrar Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup El formateo del documento realizó una limpieza adicional @@ -87,11 +117,41 @@ Ir a base + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Sugerencias insertadas + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Nombre de ensamblado no válido @@ -112,6 +172,26 @@ Buscando las bases... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operador: sobrecargado @@ -122,6 +202,91 @@ Seguimiento de pegado + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Texto del preprocesador @@ -132,6 +297,26 @@ Puntuación + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Ca_mbiar nombre de archivo (el tipo no coincide con el nombre de archivo) @@ -162,6 +347,11 @@ Símbolo: estático + + Tab Size + Tab Size + + The symbol has no base. El símbolo no tiene base. @@ -187,6 +377,11 @@ Alternando comentario de línea... + + Use Tabs + Use Tabs + + User Members - Constants Usuarios miembros: constantes @@ -412,6 +607,11 @@ Al cambiar el nombre se actualizarán {0} referencias en {1} archivos. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. No se puede cambiar el nombre de este elemento porque está incluido en un archivo de solo lectura. @@ -632,6 +832,11 @@ Ya se está siguiendo un documento con una clave idéntica + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked el documento no es objeto de seguimiento actualmente diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf index 9f7a1b08820e4..734ca3ccf60db 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Une session de renommage inline est active pour l'identificateur '{0}'. Appelez à nouveau le renommage inline pour accéder à des options supplémentaires. Vous pouvez continuer à modifier l'identificateur renommé à tout moment. @@ -12,6 +22,11 @@ Application des changements + + Avoid unused parameters + Avoid unused parameters + + Change configuration Changer la configuration @@ -27,6 +42,11 @@ Configurer maintenant + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Ne plus afficher ce message @@ -57,6 +77,16 @@ Filtrer Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup L'opération Mettre en forme le document a effectué un nettoyage supplémentaire @@ -87,11 +117,41 @@ Accéder à la base + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Indicateurs inline + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Nom d'assembly non valide @@ -112,6 +172,26 @@ Localisation des bases... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Opérateur - surchargé @@ -122,6 +202,91 @@ Suivi du collage + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Texte du préprocesseur @@ -132,6 +297,26 @@ Ponctuation + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Renommer le _fichier (le type ne correspond pas au nom du fichier) @@ -162,6 +347,11 @@ Symbole - statique + + Tab Size + Tab Size + + The symbol has no base. Le symbole n'a pas de base. @@ -187,6 +377,11 @@ Activation/désactivation du commentaire de ligne... + + Use Tabs + Use Tabs + + User Members - Constants Membres utilisateurs - constantes @@ -412,6 +607,11 @@ Le renommage va entraîner la mise à jour de {0} références dans {1} fichiers. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Vous ne pouvez pas renommer cet élément, car il est contenu dans un fichier en lecture seule. @@ -632,6 +832,11 @@ Suivi du document déjà initié avec une clé identique + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked Le document ne fait pas actuellement l'objet d'un suivi diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf index 9f33e8372d21d..ca26b60ca9ecd 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Per l'identificatore '{0}' è attiva una sessione di ridenominazione inline. Richiamare nuovamente la ridenominazione inline per accedere alle opzioni aggiuntive. È possibile continuare a modificare l'identificatore da rinominare in qualsiasi momento. @@ -12,6 +22,11 @@ Applicazione delle modifiche in corso + + Avoid unused parameters + Avoid unused parameters + + Change configuration Cambia la configurazione @@ -27,6 +42,11 @@ Configura ora + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Non visualizzare più questo messaggio @@ -57,6 +77,16 @@ Filtro Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup Formatta documento ha eseguito una pulizia aggiuntiva @@ -87,11 +117,41 @@ Vai a base + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Suggerimenti inline + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Nome di assembly non valido @@ -112,6 +172,26 @@ Individuazione delle basi... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operatore - Overload @@ -122,6 +202,91 @@ Verifica Incolla + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Testo preprocessore @@ -132,6 +297,26 @@ Punteggiatura + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Rinomina _file (il tipo non corrisponde al nome file) @@ -162,6 +347,11 @@ Simbolo - Statico + + Tab Size + Tab Size + + The symbol has no base. Non è presente alcuna base per il simbolo. @@ -187,6 +377,11 @@ Attivazione/disattivazione del commento per la riga... + + Use Tabs + Use Tabs + + User Members - Constants Membri utente - Costanti @@ -412,6 +607,11 @@ Con la ridenominazione verranno aggiornati {0} riferimenti in {1} file. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Non è possibile rinominare questo elemento perché è contenuto in un file di sola lettura. @@ -632,6 +832,11 @@ La verifica del documento con chiave identica è già in corso + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked al momento il documento non è sottoposto a verifica diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf index c8db7e1a59d4a..5508feabfa76b 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. 識別子 '{0}' のインラインの名前変更セッションがアクティブです。追加オプションにアクセスするには、インラインの名前変更をもう一度呼び出します。名前を変更する識別子はいつでも引き続き編集できます。 @@ -12,6 +22,11 @@ 変更の適用 + + Avoid unused parameters + Avoid unused parameters + + Change configuration 構成の変更 @@ -27,6 +42,11 @@ 今すぐ構成する + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again 今後、このメッセージを表示しない @@ -57,6 +77,16 @@ フィルター Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup ドキュメントのフォーマットで追加のクリーンアップが実行されました @@ -87,11 +117,41 @@ 基本へ移動 + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints インラインのヒント + + Insert Final Newline + Insert Final Newline + + Invalid assembly name 無効なアセンブリ名 @@ -112,6 +172,26 @@ ベースを検索しています... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded 演算子 - オーバーロード @@ -122,6 +202,91 @@ 追跡の貼り付け + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text プリプロセッサ テキスト @@ -132,6 +297,26 @@ 句読点 + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) ファイル名の変更 (種類がファイル名と一致しません)(_F) @@ -162,6 +347,11 @@ シンボル - 静的 + + Tab Size + Tab Size + + The symbol has no base. シンボルにベースがありません。 @@ -187,6 +377,11 @@ 行コメントを切り替えています... + + Use Tabs + Use Tabs + + User Members - Constants ユーザー メンバー - 定数 @@ -412,6 +607,11 @@ 名前を変更すると、{1} 個のファイル内の {0} 個の参照が更新されます。 + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. この要素は、読み取り専用ファイルに含まれているため、名前を変更できません。 @@ -632,6 +832,11 @@ 同じキーを持つドキュメントを既に追跡しています + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked ドキュメントが現在追跡されていません diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf index 2c53542b5f05f..295e6f802a05b 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. 식별자 '{0}'의 인라인 이름 바꾸기 세션이 활성 상태입니다. 추가 옵션에 액세스하려면 인라인 이름 바꾸기를 다시 호출하세요. 언제든지 이름을 바꾸려는 식별자를 계속 편집할 수 있습니다. @@ -12,6 +22,11 @@ 변경 내용 적용 + + Avoid unused parameters + Avoid unused parameters + + Change configuration 구성 변경 @@ -27,6 +42,11 @@ 지금 구성 + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again 이 메시지를 다시 표시하지 않음 @@ -57,6 +77,16 @@ 필터 Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup 추가 정리를 수행 하는 문서 @@ -87,11 +117,41 @@ 기본으로 이동 + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints 인라인 힌트 + + Insert Final Newline + Insert Final Newline + + Invalid assembly name 잘못된 어셈블리 이름 @@ -112,6 +172,26 @@ 베이스를 찾는 중... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded 연산자 - 오버로드됨 @@ -122,6 +202,91 @@ 붙여넣기 추적 + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text 전처리기 텍스트 @@ -132,6 +297,26 @@ 문장 부호 + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) 파일 이름 바꾸기(형식이 파일 이름과 일치하지 않음)(_F) @@ -162,6 +347,11 @@ 기호 - 정적 + + Tab Size + Tab Size + + The symbol has no base. 기호에 베이스가 없습니다. @@ -187,6 +377,11 @@ 줄 주석을 토글하는 중... + + Use Tabs + Use Tabs + + User Members - Constants 사용자 멤버 - 상수 @@ -412,6 +607,11 @@ 이름 바꾸기로 {1}개의 파일에서 {0}개의 참조가 업데이트됩니다. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. 이 요소는 읽기 전용 파일에 포함되어 있으므로 이름을 바꿀 수 없습니다. @@ -632,6 +832,11 @@ 동일한 키로 이미 문서를 추적하는 중 + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked 문서를 현재 추적하고 있지 않습니다. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf index d4635cf956c79..823fd239c3d54 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Wbudowana sesja zmieniania nazwy jest aktywna dla identyfikatora „{0}”. Wywołaj ponownie wbudowane zmienianie nazwy, aby uzyskać dostęp do dodatkowych opcji. W dowolnym momencie możesz kontynuować edytowanie identyfikatora, którego nazwa jest zmieniana. @@ -12,6 +22,11 @@ Stosowanie zmian + + Avoid unused parameters + Avoid unused parameters + + Change configuration Zmień konfigurację @@ -27,6 +42,11 @@ Skonfiguruj je teraz + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Nie pokazuj tego komunikatu ponownie @@ -57,6 +77,16 @@ Filtr Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup Funkcja formatowania dokumentu wykonała dodatkowe czyszczenie @@ -87,11 +117,41 @@ Przejdź do podstawy + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Wskazówki w tekście + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Nieprawidłowa nazwa zestawu @@ -112,6 +172,26 @@ Trwa lokalizowanie baz... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operator — przeciążony @@ -122,6 +202,91 @@ Śledzenie wklejania + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Tekst preprocesora @@ -132,6 +297,26 @@ Interpunkcja + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Zmień nazwę _pliku (typ nie zgadza się z nazwą pliku) @@ -162,6 +347,11 @@ Symbol — statyczny + + Tab Size + Tab Size + + The symbol has no base. Symbol nie ma wartości podstawowej. @@ -187,6 +377,11 @@ Trwa przełączanie komentarza wiersza... + + Use Tabs + Use Tabs + + User Members - Constants Składowe użytkowników — stałe @@ -412,6 +607,11 @@ Zmiana nazwy spowoduje zaktualizowanie odwołań ({0}) w plikach ({1}). + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Nie możesz zmienić nazwy tego elementu, ponieważ jest on zawarty w pliku tylko do odczytu. @@ -632,6 +832,11 @@ Dokument z identycznym kluczem jest już śledzony + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked dokument obecnie nie jest śledzony diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf index 7e76a95441135..00eb77d4bcf95 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Uma sessão de renomeação embutida está ativa para o identificador '{0}'. Invoque a renomeação embutida novamente para acessar opções adicionais. Você pode continuar a editar o identificador que está sendo renomeado a qualquer momento. @@ -12,6 +22,11 @@ Aplicando mudanças + + Avoid unused parameters + Avoid unused parameters + + Change configuration Alterar configuração @@ -27,6 +42,11 @@ Configurar agora + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Não mostrar esta mensagem novamente @@ -57,6 +77,16 @@ Filtrar Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup A Formatação do Documento executou uma limpeza adicional @@ -87,11 +117,41 @@ Ir Para a Base + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Dicas Embutidas + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Nome do assembly inválido @@ -112,6 +172,26 @@ Localizando as bases... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Operador – Sobrecarregado @@ -122,6 +202,91 @@ Colar Acompanhamento + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Texto de Pré-Processador @@ -132,6 +297,26 @@ Pontuação + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Renomear _arquivo (o tipo não corresponde ao nome do arquivo) @@ -162,6 +347,11 @@ Símbolo – Estático + + Tab Size + Tab Size + + The symbol has no base. O símbolo não tem nenhuma base. @@ -187,6 +377,11 @@ Ativando/desativando o comentário de linha... + + Use Tabs + Use Tabs + + User Members - Constants Membros de Usuário – Constantes @@ -412,6 +607,11 @@ Renomear atualizará {0} referências em {1} arquivos. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Você não pode renomear este elemento porque ele está contido em um arquivo somente leitura. @@ -632,6 +832,11 @@ Já está a rastrear o documento com chave idêntica + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked documento não está sendo rastreado no momento diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf index 9ca80001bed53..e797ae4690a91 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. Встроенный сеанс переименования активен для идентификатора "{0}". Снова вызовите встроенное переименование, чтобы получить доступ к дополнительным параметрам. Вы можете в любое время продолжить изменение переименованного идентификатора. @@ -12,6 +22,11 @@ Применение изменений + + Avoid unused parameters + Avoid unused parameters + + Change configuration Изменить конфигурацию @@ -27,6 +42,11 @@ Настройте ее сейчас + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Больше не показывать это сообщение @@ -57,6 +77,16 @@ Фильтр Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup При форматировании документа была выполнена дополнительная очистка @@ -87,11 +117,41 @@ Перейти к базовому + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Встроенные подсказки + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Недопустимое имя сборки @@ -112,6 +172,26 @@ Обнаружение баз… + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded Оператор — перегружен @@ -122,6 +202,91 @@ Вставить отслеживание + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Текст препроцессора @@ -132,6 +297,26 @@ Пунктуация + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) Переименовать фай_л (тип не соответствует имени файла) @@ -162,6 +347,11 @@ Символ — статический + + Tab Size + Tab Size + + The symbol has no base. У этого символа нет основания. @@ -187,6 +377,11 @@ Переключение комментария строки... + + Use Tabs + Use Tabs + + User Members - Constants Участники-пользователи — константы @@ -412,6 +607,11 @@ При переименовании будут обновлены ссылки в количестве {0} шт. в следующем числе файлов: {1}. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Невозможно переименовать этот элемент, так как он содержится в файле, доступном только для чтения. @@ -632,6 +832,11 @@ Документ с идентичным ключом уже отслеживается. + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked Документ в настоящее время не отслеживается. diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf index 0d35b1572e24f..42dd9347671f5 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. '{0}' tanımlayıcısı için bir satır içi yeniden adlandırma oturumu etkin. Ek seçeneklere erişmek için satır içi yeniden adlandırmayı tekrar çağırın. İstediğiniz zaman yeniden adlandırılan tanımlayıcıyı düzenlemeye devam edebilirsiniz. @@ -12,6 +22,11 @@ Değişiklikler uygulanıyor + + Avoid unused parameters + Avoid unused parameters + + Change configuration Değiştir yapılandırma @@ -27,6 +42,11 @@ Hemen yapılandırın + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again Bu iletiyi bir daha gösterme @@ -57,6 +77,16 @@ Filtre Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup Biçimi belge ek temizleme işlemi @@ -87,11 +117,41 @@ Tabana Git + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints Satır İçi İpuçları + + Insert Final Newline + Insert Final Newline + + Invalid assembly name Geçersiz derleme adı @@ -112,6 +172,26 @@ Tabanlar bulunuyor... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded İşleç - Aşırı Yüklenmiş @@ -122,6 +202,91 @@ İzleme Yapıştır + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text Ön İşlemci Metni @@ -132,6 +297,26 @@ Noktalama İşareti + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) _Dosyayı yeniden adlandır (tür, dosya adıyla eşleşmiyor) @@ -162,6 +347,11 @@ Sembol - statik + + Tab Size + Tab Size + + The symbol has no base. Sembolde taban yok. @@ -187,6 +377,11 @@ Satır açıklaması değiştiriliyor... + + Use Tabs + Use Tabs + + User Members - Constants Kullanıcı Üyeler - Sabitler @@ -412,6 +607,11 @@ Yeniden adlandırma işlemi {1} dosyadaki {0} başvuruyu güncelleştirecek. + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. Salt okunur bir dosyada bulunduğundan bu öğeyi yeniden adlandıramazsınız. @@ -632,6 +832,11 @@ Belge zaten özdeş anahtar ile izleniyor + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked Belge şu anda izlenmiyor diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf index 30322875c1dff..01cd292694cf0 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. 标识符“{0}”的内联重命名会话处于活动状态。再次调用内联重命名以访问其他选项。可随时继续编辑正在重命名的标识符。 @@ -12,6 +22,11 @@ 应用更改 + + Avoid unused parameters + Avoid unused parameters + + Change configuration 更改配置 @@ -27,6 +42,11 @@ 立即配置 + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again 不再显示此消息 @@ -57,6 +77,16 @@ 筛选 Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup 格式文档执行了额外的清理 @@ -87,11 +117,41 @@ 转到基础映像 + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints 内联提示 + + Insert Final Newline + Insert Final Newline + + Invalid assembly name 程序集名称无效 @@ -112,6 +172,26 @@ 正在查找基... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded 运算符-重载 @@ -122,6 +202,91 @@ 粘贴跟踪信息 + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text 预处理器文本 @@ -132,6 +297,26 @@ 标点 + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) 重命名文件(类型与文件名不匹配)(_F) @@ -162,6 +347,11 @@ 符号-静态 + + Tab Size + Tab Size + + The symbol has no base. 符号没有基数。 @@ -187,6 +377,11 @@ 正在切换为行注释... + + Use Tabs + Use Tabs + + User Members - Constants 用户成员-常量 @@ -412,6 +607,11 @@ 重命名将更新 {1} 个文件中的 {0} 个引用。 + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. 无法重命名此元素,因为它包含在只读文件中。 @@ -632,6 +832,11 @@ 已使用等价键跟踪文档 + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked 当前未跟踪文档 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf index 75f00e8d42a2b..285e7d9493df4 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf @@ -2,6 +2,16 @@ + + All methods + All methods + + + + Always for clarity + Always for clarity + + An inline rename session is active for identifier '{0}'. Invoke inline rename again to access additional options. You may continue to edit the identifier being renamed at any time. 識別碼 '{0}' 有正在使用的內嵌重新命名工作階段。再次叫用內嵌重新命名可存取其他選項。您隨時可以繼續編輯正在重新命名的識別碼。 @@ -12,6 +22,11 @@ 正在套用變更 + + Avoid unused parameters + Avoid unused parameters + + Change configuration 變更組態 @@ -27,6 +42,11 @@ 立即設定 + + Do not prefer 'this.' or 'Me.' + Do not prefer 'this.' or 'Me.' + + Do not show this message again 不再顯示此訊息 @@ -57,6 +77,16 @@ 篩選 Caption/tooltip for "Filter" image element displayed in completion popup. + + For locals, parameters and members + For locals, parameters and members + + + + For member access expressions + For member access expressions + + Format Document performed additional cleanup 執行額外清除的格式化文件 @@ -87,11 +117,41 @@ 移至基底 + + In arithmetic operators + In arithmetic operators + + + + In other binary operators + In other binary operators + + + + In other operators + In other operators + + + + In relational operators + In relational operators + + + + Indentation Size + Indentation Size + + Inline Hints 內嵌提示 + + Insert Final Newline + Insert Final Newline + + Invalid assembly name 組件名稱無效 @@ -112,6 +172,26 @@ 正在尋找基底... + + Never if unnecessary + Never if unnecessary + + + + New Line + New Line + + + + No + No + + + + Non-public methods + Non-public methods + + Operator - Overloaded 運算子 - 多載 @@ -122,6 +202,91 @@ 貼上追蹤 + + Prefer 'System.HashCode' in 'GetHashCode' + Prefer 'System.HashCode' in 'GetHashCode' + + + + Prefer coalesce expression + Prefer coalesce expression + + + + Prefer collection initializer + Prefer collection initializer + + + + Prefer compound assignments + Prefer compound assignments + + + + Prefer conditional expression over 'if' with assignments + Prefer conditional expression over 'if' with assignments + + + + Prefer conditional expression over 'if' with returns + Prefer conditional expression over 'if' with returns + + + + Prefer explicit tuple name + Prefer explicit tuple name + + + + Prefer framework type + Prefer framework type + + + + Prefer inferred anonymous type member names + Prefer inferred anonymous type member names + + + + Prefer inferred tuple element names + Prefer inferred tuple element names + + + + Prefer 'is null' for reference equality checks + Prefer 'is null' for reference equality checks + + + + Prefer null propagation + Prefer null propagation + + + + Prefer object initializer + Prefer object initializer + + + + Prefer predefined type + Prefer predefined type + + + + Prefer readonly fields + Prefer readonly fields + + + + Prefer simplified boolean expressions + Prefer simplified boolean expressions + + + + Prefer 'this.' or 'Me.' + Prefer 'this.' or 'Me.' + + Preprocessor Text 前置處理器文字 @@ -132,6 +297,26 @@ 標點符號 + + Qualify event access with 'this' or 'Me' + Qualify event access with 'this' or 'Me' + + + + Qualify field access with 'this' or 'Me' + Qualify field access with 'this' or 'Me' + + + + Qualify method access with 'this' or 'Me' + Qualify method access with 'this' or 'Me' + + + + Qualify property access with 'this' or 'Me' + Qualify property access with 'this' or 'Me' + + Rename _file (type does not match file name) 重新命名檔案 (類型不符合檔案名稱)(_F) @@ -162,6 +347,11 @@ 符號 - 靜態 + + Tab Size + Tab Size + + The symbol has no base. 該符號沒有任何基底。 @@ -187,6 +377,11 @@ 正在切換行註解... + + Use Tabs + Use Tabs + + User Members - Constants 使用者成員 - 常數 @@ -412,6 +607,11 @@ 重新命名會更新 {1} 個檔案中的 {0} 個參考。 + + Yes + Yes + + You cannot rename this element because it is contained in a read-only file. 因為此項目包含在唯讀檔案中,所以無法重新命名。 @@ -632,6 +832,11 @@ 已追蹤具有相同索引鍵的文件 + + Prefer auto properties + Prefer auto properties + + document is not currently being tracked 文件目前未加以追蹤 diff --git a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs index 23f0b1f3571a6..3d2865bff6ed4 100644 --- a/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs +++ b/src/EditorFeatures/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs @@ -1610,9 +1610,6 @@ public async Task BreakMode_ValidSignificantChange_EmitError() // no change in non-remappable regions since we didn't have any active statements: Assert.Empty(editSession.DebuggingSession.NonRemappableRegions); - // no open module readers since we didn't defer any module update: - Assert.Empty(editSession.DebuggingSession.GetBaselineModuleReaders()); - // solution update status after discarding an update (still has update ready): Assert.True(await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: null, CancellationToken.None)); @@ -1957,17 +1954,20 @@ public async Task ValidSignificantChange_EmitSuccessful(bool breakMode, bool com var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(service, workspace.CurrentSolution); Assert.Empty(emitDiagnostics); Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); - - // check emitted delta: - var delta = updates.Updates.Single(); - Assert.Empty(delta.ActiveStatements); - Assert.NotEmpty(delta.ILDelta); - Assert.NotEmpty(delta.MetadataDelta); - Assert.NotEmpty(delta.PdbDelta); - Assert.Equal(0x06000001, delta.UpdatedMethods.Single()); - Assert.Equal(moduleId, delta.Module); - Assert.Empty(delta.ExceptionRegions); - Assert.Empty(delta.SequencePoints); + ValidateDelta(updates.Updates.Single()); + + void ValidateDelta(ManagedModuleUpdate delta) + { + // check emitted delta: + Assert.Empty(delta.ActiveStatements); + Assert.NotEmpty(delta.ILDelta); + Assert.NotEmpty(delta.MetadataDelta); + Assert.NotEmpty(delta.PdbDelta); + Assert.Equal(0x06000001, delta.UpdatedMethods.Single()); + Assert.Equal(moduleId, delta.Module); + Assert.Empty(delta.ExceptionRegions); + Assert.Empty(delta.SequencePoints); + } // the update should be stored on the service: var pendingUpdate = editSession.Test_GetPendingSolutionUpdate(); @@ -1976,7 +1976,7 @@ public async Task ValidSignificantChange_EmitSuccessful(bool breakMode, bool com Assert.Equal(project.Id, baselineProjectId); Assert.Equal(moduleId, newBaseline.OriginalMetadata.GetModuleVersionId()); - var readers = pendingUpdate.ModuleReaders; + var readers = debuggingSession.GetBaselineModuleReaders(); Assert.Equal(2, readers.Length); Assert.NotNull(readers[0]); Assert.NotNull(readers[1]); @@ -2013,6 +2013,12 @@ public async Task ValidSignificantChange_EmitSuccessful(bool breakMode, bool com // solution update status after committing an update: var discardedUpdateSolutionStatus = await service.HasChangesAsync(workspace.CurrentSolution, s_noSolutionActiveSpans, sourceFilePath: null, CancellationToken.None); Assert.True(discardedUpdateSolutionStatus); + + (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(service, workspace.CurrentSolution); + Assert.Empty(emitDiagnostics); + Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + + ValidateDelta(updates.Updates.Single()); } if (breakMode) @@ -2077,6 +2083,7 @@ public async Task BreakMode_ValidSignificantChange_EmitSuccessful_UpdateDeferred var service = CreateEditAndContinueService(); await StartDebuggingSessionAsync(service, workspace.CurrentSolution); + var debuggingSession = service.Test_GetDebuggingSession(); // module is not loaded: EnterBreakState(service, activeStatements); @@ -2108,7 +2115,7 @@ public async Task BreakMode_ValidSignificantChange_EmitSuccessful_UpdateDeferred var pendingUpdate = editSession.Test_GetPendingSolutionUpdate(); var (baselineProjectId, newBaseline) = pendingUpdate.EmitBaselines.Single(); - var readers = pendingUpdate.ModuleReaders; + var readers = debuggingSession.GetBaselineModuleReaders(); Assert.Equal(2, readers.Length); Assert.NotNull(readers[0]); Assert.NotNull(readers[1]); @@ -2124,12 +2131,6 @@ public async Task BreakMode_ValidSignificantChange_EmitSuccessful_UpdateDeferred // no change in non-remappable regions since we didn't have any active statements: Assert.Empty(editSession.DebuggingSession.NonRemappableRegions); - // deferred module readers tracked: - var baselineReaders = editSession.DebuggingSession.GetBaselineModuleReaders(); - Assert.Equal(2, baselineReaders.Length); - Assert.Same(readers[0], baselineReaders[0]); - Assert.Same(readers[1], baselineReaders[1]); - // verify that baseline is added: Assert.Same(newBaseline, editSession.DebuggingSession.Test_GetProjectEmitBaseline(project.Id)); @@ -2150,26 +2151,18 @@ public async Task BreakMode_ValidSignificantChange_EmitSuccessful_UpdateDeferred (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(service, workspace.CurrentSolution); Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); Assert.Empty(emitDiagnostics); - - ExitBreakState(); - EndDebuggingSession(service); - - // open module readers should be disposed when the debugging session ends: - VerifyReadersDisposed(readers); } else { service.DiscardSolutionUpdate(); Assert.Null(editSession.Test_GetPendingSolutionUpdate()); + } - // no open module readers since we didn't defer any module update: - Assert.Empty(editSession.DebuggingSession.GetBaselineModuleReaders()); - - VerifyReadersDisposed(readers); + ExitBreakState(); + EndDebuggingSession(service); - ExitBreakState(); - EndDebuggingSession(service); - } + // open module readers should be disposed when the debugging session ends: + VerifyReadersDisposed(readers); } [Fact] @@ -2659,7 +2652,7 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() var baselineA0 = newBaselineA1.GetInitialEmitBaseline(); var baselineB0 = newBaselineB1.GetInitialEmitBaseline(); - var readers = pendingUpdate.ModuleReaders; + var readers = debuggingSession.GetBaselineModuleReaders(); Assert.Equal(4, readers.Length); Assert.False(readers.Any(r => r is null)); @@ -2672,10 +2665,6 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() // no change in non-remappable regions since we didn't have any active statements: Assert.Empty(debuggingSession.NonRemappableRegions); - // deferred module readers tracked: - var baselineReaders = debuggingSession.GetBaselineModuleReaders(); - AssertEx.Equal(readers, baselineReaders); - // verify that baseline is added for both modules: Assert.Same(newBaselineA1, debuggingSession.Test_GetProjectEmitBaseline(projectA.Id)); Assert.Same(newBaselineB1, debuggingSession.Test_GetProjectEmitBaseline(projectB.Id)); @@ -2718,7 +2707,8 @@ public async Task TwoUpdatesWithLoadedAndUnloadedModule() Assert.Same(baselineB0.OriginalMetadata, newBaselineB2.OriginalMetadata); // no new module readers: - Assert.Empty(pendingUpdate.ModuleReaders); + var baselineReaders = debuggingSession.GetBaselineModuleReaders(); + AssertEx.Equal(readers, baselineReaders); CommitSolutionUpdate(service); Assert.Null(editSession.Test_GetPendingSolutionUpdate()); @@ -3160,7 +3150,6 @@ static void F() /// - edit, but not apply the edits /// - break /// - /// [Fact] public async Task BreakInPresenceOfUnappliedChanges() { @@ -3280,5 +3269,91 @@ static void F() ExitBreakState(); } + + /// + /// Scenario: + /// - F5 + /// - edit and apply edit that deletes non-leaf active statement + /// - break + /// + [Fact, WorkItem(52100, "https://github.com/dotnet/roslyn/issues/52100")] + public async Task BreakAfterRunModeChangeDeletesNonLeafActiveStatement() + { + var markedSource1 = +@"class Test +{ + static bool B() => true; + static void G() { while (B()); } + + static void F() + { + G(); + } +}"; + + var markedSource2 = +@"class Test +{ + static bool B() => true; + static void G() { while (B()); } + + static void F() + { + } +}"; + var moduleId = EmitAndLoadLibraryToDebuggee(ActiveStatementsDescription.ClearTags(markedSource1)); + + using var workspace = CreateWorkspace(); + var project = AddDefaultTestProject(workspace, ActiveStatementsDescription.ClearTags(markedSource1)); + var documentId = project.DocumentIds.Single(); + var solution = project.Solution; + + var service = CreateEditAndContinueService(); + var debuggingSession = await StartDebuggingSessionAsync(service, solution); + + // Apply update: F v1 -> v2. + + solution = solution.WithDocumentText(documentId, SourceText.From(ActiveStatementsDescription.ClearTags(markedSource2), Encoding.UTF8)); + + var (updates, emitDiagnostics) = await EmitSolutionUpdateAsync(service, solution); + Assert.Empty(emitDiagnostics); + Assert.Equal(0x06000003, updates.Updates.Single().UpdatedMethods.Single()); + Assert.Equal(ManagedModuleUpdateStatus.Ready, updates.Status); + + CommitSolutionUpdate(service); + + // Break + + EnterBreakState(service, GetActiveStatementDebugInfos( + new[] { markedSource1 }, + modules: new[] { moduleId, moduleId }, + methodRowIds: new[] { 2, 3 }, + methodVersions: new[] { 1, 1 }, // frame F v1 is still executing (G has not returned) + flags: new[] + { + ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.IsLeafFrame, // G + ActiveStatementFlags.IsNonLeafFrame, // F + })); + + // check that the active statement is mapped correctly to snapshot v2: + var expectedSpanG1 = new LinePositionSpan(new LinePosition(3, 41), new LinePosition(3, 42)); + + var activeInstructionF1 = new ManagedInstructionId(new ManagedMethodId(moduleId, 0x06000003, version: 1), ilOffset: 0); + var span = await service.GetCurrentActiveStatementPositionAsync(solution, s_noSolutionActiveSpans, activeInstructionF1, CancellationToken.None); + Assert.Null(span); + + var spans = (await service.GetBaseActiveStatementSpansAsync(solution, ImmutableArray.Create(documentId), CancellationToken.None)).Single(); + AssertEx.Equal(new[] + { + (expectedSpanG1, ActiveStatementFlags.MethodUpToDate | ActiveStatementFlags.IsLeafFrame), + + // TODO: https://github.com/dotnet/roslyn/issues/52100 + // This is incorrect: the active statement shouldn't be reported since it has been deleted. + // We need the debugger to mark the method version as replaced by run-mode update. + (new LinePositionSpan(new LinePosition(7, 14), new LinePosition(7, 18)), ActiveStatementFlags.IsNonLeafFrame) + }, spans); + + ExitBreakState(); + } } } diff --git a/src/EditorFeatures/Test/EditorConfigSettings/Data/CodeStyleSettingsTest.cs b/src/EditorFeatures/Test/EditorConfigSettings/Data/CodeStyleSettingsTest.cs new file mode 100644 index 0000000000000..295ab30e205a6 --- /dev/null +++ b/src/EditorFeatures/Test/EditorConfigSettings/Data/CodeStyleSettingsTest.cs @@ -0,0 +1,95 @@ +// 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. + +extern alias WORKSPACES; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using WORKSPACES::Microsoft.CodeAnalysis.Options; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.UnitTests.EditorConfigSettings.Data +{ + public class CodeStyleSettingsTest + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public static void CodeStyleSettingBoolFactory(bool defaultValue) + { + var option = CreateBoolOption(defaultValue); + var editorConfigOptions = new TestAnalyzerConfigOptions(); + var visualStudioOptions = new TestOptionSet(option.DefaultValue); + var setting = CodeStyleSetting.Create(option, description: "TestDesciption", editorConfigOptions, visualStudioOptions, updater: null!); + Assert.Equal(string.Empty, setting.Category); + Assert.Equal("TestDesciption", setting.Description); + Assert.False(setting.IsDefinedInEditorConfig); + Assert.Equal(typeof(bool), setting.Type); + Assert.Equal(defaultValue, setting.Value); + } + + [Theory] + [InlineData(DayOfWeek.Monday)] + [InlineData(DayOfWeek.Friday)] + public static void CodeStyleSettingEnumFactory(DayOfWeek defaultValue) + { + var option = CreateEnumOption(defaultValue); + var editorConfigOptions = new TestAnalyzerConfigOptions(); + var visualStudioOptions = new TestOptionSet(option.DefaultValue); + var setting = CodeStyleSetting.Create(option, + description: "TestDesciption", + enumValues: (DayOfWeek[])Enum.GetValues(typeof(DayOfWeek)), + valueDescriptions: Enum.GetNames(typeof(DayOfWeek)), + editorConfigOptions, + visualStudioOptions, + updater: null!); + Assert.Equal(string.Empty, setting.Category); + Assert.Equal("TestDesciption", setting.Description); + Assert.False(setting.IsDefinedInEditorConfig); + Assert.Equal(typeof(DayOfWeek), setting.Type); + Assert.Equal(defaultValue, setting.Value); + } + + private static Option2> CreateBoolOption(bool @default = false) + { + var option = CodeStyleOption2.Default; + option.Value = @default; + return new Option2>(feature: "TestFeature", + name: "TestOption", + defaultValue: option); + } + + private static Option2> CreateEnumOption(T @default) + where T : notnull, Enum + { + var option = CodeStyleOption2.Default; + option.Value = @default; + return new Option2>(feature: "TestFeature", + name: "TestOption", + defaultValue: option); + } + + private class TestAnalyzerConfigOptions : AnalyzerConfigOptions + { + private readonly IDictionary _dictionary; + public TestAnalyzerConfigOptions((string, string)[]? options = null) + => _dictionary = options?.ToDictionary(x => x.Item1, x => x.Item2) ?? new Dictionary(); + public override bool TryGetValue(string key, [NotNullWhen(true)] out string? value) + => _dictionary.TryGetValue(key, out value); + } + + private class TestOptionSet : OptionSet + { + private readonly object? _value; + public TestOptionSet(CodeStyleOption2 value) => _value = value; + public override OptionSet WithChangedOption(OptionKey optionAndLanguage, object? value) => this; + internal override IEnumerable GetChangedOptions(OptionSet optionSet) => Array.Empty(); + private protected override object? GetOptionCore(OptionKey optionKey) => _value; + } + } +} diff --git a/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs b/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs index ca814e68648ff..a01bff35edaa1 100644 --- a/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs +++ b/src/EditorFeatures/Test/Workspaces/ProjectCacheHostServiceFactoryTests.cs @@ -273,7 +273,7 @@ public MockHostWorkspaceServices(HostServices hostServices, Workspace workspace) _hostServices = hostServices; _workspace = workspace; - var globalOptionService = new GlobalOptionService(ImmutableArray>.Empty, ImmutableArray>.Empty); + var globalOptionService = new GlobalOptionService(workspaceThreadingService: null, ImmutableArray>.Empty, ImmutableArray>.Empty); _optionService = new OptionServiceFactory.OptionService(globalOptionService, this); } diff --git a/src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb b/src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb index 7f93613ef9f78..7ec0fc594a4b4 100644 --- a/src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb +++ b/src/EditorFeatures/Test2/Simplification/SimplifierAPITests.vb @@ -11,142 +11,128 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Simplification Public Class SimplifierAPITests - Public Sub TestExpandAsync() - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim expandedNode = Simplifier.ExpandAsync(Of SyntaxNode)(Nothing, Nothing).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "node")) - End Sub + Public Async Function TestExpandAsync() As Task + Await Assert.ThrowsAsync(Of ArgumentNullException)("node", + Function() + Return Simplifier.ExpandAsync(Of SyntaxNode)(Nothing, Nothing) + End Function) + End Function - Public Sub TestExpandAsync2() + Public Async Function TestExpandAsync2() As Task Dim node = GetSyntaxNode() - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim expandedNode = Simplifier.ExpandAsync(node, Nothing).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() As Task + Return Simplifier.ExpandAsync(node, Nothing) + End Function) + End Function Public Sub TestExpand() - AssertEx.Throws(Of ArgumentNullException)( + Assert.Throws(Of ArgumentNullException)("node", Sub() - Dim expandedNode = Simplifier.Expand(Of SyntaxNode)(Nothing, Nothing, Nothing) - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "node")) + Simplifier.Expand(Of SyntaxNode)(Nothing, Nothing, Nothing) + End Sub) End Sub Public Sub TestExpand2() Dim node = GetSyntaxNode() - AssertEx.Throws(Of ArgumentNullException)( + Assert.Throws(Of ArgumentNullException)("semanticModel", Sub() - Dim expandedNode = Simplifier.Expand(node, Nothing, Nothing) - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "semanticModel")) + Simplifier.Expand(node, Nothing, Nothing) + End Sub) End Sub Public Sub TestExpand3() Dim node = GetSyntaxNode() Dim semanticModel = GetSemanticModel() - AssertEx.Throws(Of ArgumentNullException)( + Assert.Throws(Of ArgumentNullException)("workspace", Sub() - Dim expandedNode = Simplifier.Expand(node, semanticModel, Nothing) - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "workspace")) + Simplifier.Expand(node, semanticModel, Nothing) + End Sub) End Sub - Public Sub TestTokenExpandAsync() - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim expandedNode = Simplifier.ExpandAsync(Nothing, Nothing).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Public Async Function TestTokenExpandAsync() As Task + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() + Return Simplifier.ExpandAsync(Nothing, Nothing) + End Function) + End Function Public Sub TestTokenExpand() - AssertEx.Throws(Of ArgumentNullException)( + Assert.Throws(Of ArgumentNullException)("semanticModel", Sub() Dim expandedNode = Simplifier.Expand(Nothing, Nothing, Nothing) - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "semanticModel")) + End Sub) End Sub Public Sub TestTokenExpand2() Dim semanticModel = GetSemanticModel() - AssertEx.Throws(Of ArgumentNullException)( + Assert.Throws(Of ArgumentNullException)("workspace", Sub() Dim expandedNode = Simplifier.Expand(Nothing, semanticModel, Nothing) - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "workspace")) + End Sub) End Sub - Public Sub TestReduceAsync() - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(Nothing).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Public Async Function TestReduceAsync() As Task + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() + Return Simplifier.ReduceAsync(Nothing) + End Function) + End Function - Public Sub TestReduceAsync2() + Public Async Function TestReduceAsync2() As Task Dim syntaxAnnotation As SyntaxAnnotation = Nothing - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(Nothing, syntaxAnnotation).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() + Return Simplifier.ReduceAsync(Nothing, syntaxAnnotation) + End Function) + End Function - Public Sub TestReduceAsync3() + Public Async Function TestReduceAsync3() As Task Dim syntaxAnnotation As SyntaxAnnotation = Nothing Dim document = GetDocument() - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(document, syntaxAnnotation).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "annotation")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("annotation", + Function() + Return Simplifier.ReduceAsync(document, syntaxAnnotation) + End Function) + End Function - Public Sub TestReduceAsync4() + Public Async Function TestReduceAsync4() As Task Dim textSpan As TextSpan = Nothing - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(Nothing, textSpan).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() + Return Simplifier.ReduceAsync(Nothing, textSpan) + End Function) + End Function - Public Sub TestReduceAsync5() + Public Async Function TestReduceAsync5() As Task Dim spans As IEnumerable(Of TextSpan) = Nothing - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(Nothing, spans).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "document")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("document", + Function() + Return Simplifier.ReduceAsync(Nothing, spans) + End Function) + End Function - Public Sub TestReduceAsync6() + Public Async Function TestReduceAsync6() As Task Dim document = GetDocument() Dim spans As IEnumerable(Of TextSpan) = Nothing - AssertEx.Throws(Of ArgumentNullException)( - Sub() - Dim simplifiedNode = Simplifier.ReduceAsync(document, spans).Result - End Sub, - Sub(exception) Assert.Equal(exception.ParamName, "spans")) - End Sub + Await Assert.ThrowsAsync(Of ArgumentNullException)("spans", + Function() As Task + Return Simplifier.ReduceAsync(document, spans) + End Function) + End Function Private Shared Function GetDocument() As Document Dim workspace = New AdhocWorkspace() diff --git a/src/EditorFeatures/TestUtilities/CompleteStatement/AbstractCompleteStatementTests.cs b/src/EditorFeatures/TestUtilities/CompleteStatement/AbstractCompleteStatementTests.cs index 05ac5e582815e..af9b63ed79cdc 100644 --- a/src/EditorFeatures/TestUtilities/CompleteStatement/AbstractCompleteStatementTests.cs +++ b/src/EditorFeatures/TestUtilities/CompleteStatement/AbstractCompleteStatementTests.cs @@ -52,16 +52,17 @@ protected void VerifyNoSpecialSemicolonHandling(string initialMarkup) /// protected void VerifyTypingSemicolon(string initialMarkup, string expectedMarkup) { - Verify(initialMarkup, expectedMarkup, - execute: (view, workspace) => - { - var commandHandler = GetCommandHandler(workspace); + Verify(initialMarkup, expectedMarkup, ExecuteTest); + } + + protected void ExecuteTest(IWpfTextView view, TestWorkspace workspace) + { + var commandHandler = GetCommandHandler(workspace); - var commandArgs = new TypeCharCommandArgs(view, view.TextBuffer, semicolon); - var nextHandler = CreateInsertTextHandler(view, semicolon.ToString()); + var commandArgs = new TypeCharCommandArgs(view, view.TextBuffer, semicolon); + var nextHandler = CreateInsertTextHandler(view, semicolon.ToString()); - commandHandler.ExecuteCommand(commandArgs, nextHandler, TestCommandExecutionContext.Create()); - }); + commandHandler.ExecuteCommand(commandArgs, nextHandler, TestCommandExecutionContext.Create()); } private static Action CreateInsertTextHandler(ITextView textView, string text) @@ -74,7 +75,7 @@ private static Action CreateInsertTextHandler(ITextView textView, string text) }; } - private void Verify(string initialMarkup, string expectedMarkup, + protected void Verify(string initialMarkup, string expectedMarkup, Action execute, Action setOptionsOpt = null) { diff --git a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs index 73c8b05b72c85..dafd58921fba1 100644 --- a/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs +++ b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs @@ -91,8 +91,8 @@ private protected abstract Task BaseVerifyWorkerAsync( string code, int position, string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription, List matchingFilters, - CompletionItemFlags? flags); + string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, + List matchingFilters, CompletionItemFlags? flags); internal static Task GetCompletionListAsync( CompletionService service, @@ -110,6 +110,7 @@ private protected async Task CheckResultsAsync( bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionModeItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription, + bool? isComplexTextEdit, List matchingFilters, CompletionItemFlags? flags) { var code = (await document.GetTextAsync()).ToString(); @@ -184,6 +185,8 @@ bool Predicate(RoslynCompletion.CompletionItem c) return false; if (flags != null && flags.Value != c.Flags) return false; + if (isComplexTextEdit is bool textEdit && textEdit != c.IsComplexTextEdit) + return false; return true; } @@ -208,8 +211,8 @@ private async Task VerifyAsync( string markup, string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionModeItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription, List matchingFilters, - CompletionItemFlags? flags) + string displayTextPrefix, string inlineDescription, bool? isComplexTextEdit, + List matchingFilters, CompletionItemFlags? flags) { using var workspaceFixture = GetOrCreateWorkspaceFixture(); @@ -223,7 +226,7 @@ await VerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionModeItem, displayTextSuffix, displayTextPrefix, - inlineDescription, matchingFilters, flags).ConfigureAwait(false); + inlineDescription, isComplexTextEdit, matchingFilters, flags).ConfigureAwait(false); } protected async Task GetCompletionListAsync(string markup, string workspaceKind = null) @@ -294,7 +297,7 @@ 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, - List matchingFilters = null, CompletionItemFlags? flags = null) + bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { if (sourceCodeKind.HasValue) { @@ -303,7 +306,7 @@ await VerifyAsync(markup, expectedItem, expectedDescriptionOrNull, glyph: glyph, matchPriority: matchPriority, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, - matchingFilters: matchingFilters, flags: flags); + isComplexTextEdit: isComplexTextEdit, matchingFilters: matchingFilters, flags: flags); } else { @@ -312,14 +315,14 @@ await VerifyAsync( checkForAbsence: false, glyph: glyph, matchPriority: matchPriority, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, - matchingFilters: matchingFilters, flags: flags); + isComplexTextEdit: isComplexTextEdit, matchingFilters: matchingFilters, flags: flags); await VerifyAsync( markup, expectedItem, expectedDescriptionOrNull, SourceCodeKind.Script, usePreviousCharAsTrigger, checkForAbsence: false, glyph: glyph, matchPriority: matchPriority, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, - matchingFilters: matchingFilters, flags: flags); + isComplexTextEdit: isComplexTextEdit, matchingFilters: matchingFilters, flags: flags); } } @@ -328,7 +331,7 @@ private protected async Task VerifyItemIsAbsentAsync( SourceCodeKind? sourceCodeKind = null, bool usePreviousCharAsTrigger = false, bool? hasSuggestionModeItem = null, string displayTextSuffix = null, string displayTextPrefix = null, string inlineDescription = null, - List matchingFilters = null, CompletionItemFlags? flags = null) + bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { if (sourceCodeKind.HasValue) { @@ -336,7 +339,7 @@ await VerifyAsync(markup, expectedItem, expectedDescriptionOrNull, sourceCodeKin usePreviousCharAsTrigger, checkForAbsence: true, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, - matchingFilters: matchingFilters, flags: flags); + isComplexTextEdit: isComplexTextEdit, matchingFilters: matchingFilters, flags: flags); } else { @@ -344,12 +347,12 @@ await VerifyAsync(markup, expectedItem, expectedDescriptionOrNull, SourceCodeKin usePreviousCharAsTrigger, checkForAbsence: true, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, - matchingFilters: matchingFilters, flags: flags); + isComplexTextEdit: isComplexTextEdit, matchingFilters: matchingFilters, flags: flags); await VerifyAsync(markup, expectedItem, expectedDescriptionOrNull, SourceCodeKind.Script, usePreviousCharAsTrigger, checkForAbsence: true, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, - matchingFilters: matchingFilters, flags: flags); + isComplexTextEdit: isComplexTextEdit, matchingFilters: matchingFilters, flags: flags); } } @@ -364,8 +367,8 @@ await VerifyAsync(markup, expectedItemOrNull: null, expectedDescriptionOrNull: n sourceCodeKind: sourceCodeKind.Value, usePreviousCharAsTrigger: usePreviousCharAsTrigger, checkForAbsence: false, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, - displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, matchingFilters: null, - flags: null); + displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, + isComplexTextEdit: null, matchingFilters: null, flags: null); } else { @@ -374,14 +377,14 @@ await VerifyAsync( sourceCodeKind: SourceCodeKind.Regular, usePreviousCharAsTrigger: usePreviousCharAsTrigger, checkForAbsence: false, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, - displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, matchingFilters: null, - flags: null); + displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, + isComplexTextEdit: null, matchingFilters: null, flags: null); await VerifyAsync(markup, expectedItemOrNull: null, expectedDescriptionOrNull: null, sourceCodeKind: SourceCodeKind.Script, usePreviousCharAsTrigger: usePreviousCharAsTrigger, checkForAbsence: false, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, - displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, matchingFilters: null, - flags: null); + displayTextPrefix: displayTextPrefix, inlineDescription: inlineDescription, + isComplexTextEdit: null, matchingFilters: null, flags: null); } } @@ -397,7 +400,8 @@ await VerifyAsync( sourceCodeKind: sourceCodeKind.Value, usePreviousCharAsTrigger: usePreviousCharAsTrigger, checkForAbsence: true, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, - displayTextPrefix: null, inlineDescription: inlineDescription, matchingFilters: null, flags: null); + displayTextPrefix: null, inlineDescription: inlineDescription, + isComplexTextEdit: null, matchingFilters: null, flags: null); } else { @@ -405,13 +409,15 @@ await VerifyAsync(markup, expectedItemOrNull: null, expectedDescriptionOrNull: n sourceCodeKind: SourceCodeKind.Regular, usePreviousCharAsTrigger: usePreviousCharAsTrigger, checkForAbsence: true, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, - displayTextPrefix: null, inlineDescription: inlineDescription, matchingFilters: null, flags: null); + displayTextPrefix: null, inlineDescription: inlineDescription, + isComplexTextEdit: null, matchingFilters: null, flags: null); await VerifyAsync( markup, expectedItemOrNull: null, expectedDescriptionOrNull: null, sourceCodeKind: SourceCodeKind.Script, usePreviousCharAsTrigger: usePreviousCharAsTrigger, checkForAbsence: true, glyph: null, matchPriority: null, hasSuggestionModeItem: hasSuggestionModeItem, displayTextSuffix: displayTextSuffix, - displayTextPrefix: null, inlineDescription: inlineDescription, matchingFilters: null, flags: null); + displayTextPrefix: null, inlineDescription: inlineDescription, + isComplexTextEdit: null, matchingFilters: null, flags: null); } } @@ -432,7 +438,7 @@ private protected virtual async Task VerifyWorkerAsync( bool usePreviousCharAsTrigger, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionModeItem, string displayTextSuffix, string displayTextPrefix, - string inlineDescription, + string inlineDescription, bool? isComplexTextEdit, List matchingFilters, CompletionItemFlags? flags) { using var workspaceFixture = GetOrCreateWorkspaceFixture(); @@ -445,7 +451,7 @@ await CheckResultsAsync( expectedDescriptionOrNull, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionModeItem, displayTextSuffix, displayTextPrefix, - inlineDescription, matchingFilters, flags); + inlineDescription, isComplexTextEdit, matchingFilters, flags); if (await CanUseSpeculativeSemanticModelAsync(document1, position)) { @@ -454,7 +460,7 @@ await CheckResultsAsync( document2, position, expectedItemOrNull, expectedDescriptionOrNull, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionModeItem, displayTextSuffix, displayTextPrefix, - inlineDescription, matchingFilters, flags); + inlineDescription, isComplexTextEdit, matchingFilters, flags); } } @@ -943,7 +949,7 @@ private protected Task VerifyAtPositionAsync( SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, string displayTextPrefix, string inlineDescription = null, - List matchingFilters = null, CompletionItemFlags? flags = null) + bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { code = code.Substring(0, position) + insertText + code.Substring(position); position += insertText.Length; @@ -952,7 +958,7 @@ private protected Task VerifyAtPositionAsync( expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); } private protected Task VerifyAtPositionAsync( @@ -960,14 +966,14 @@ private protected Task VerifyAtPositionAsync( string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription = null, + string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { return VerifyAtPositionAsync( code, position, string.Empty, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, - inlineDescription, matchingFilters, flags); + inlineDescription, isComplexTextEdit, matchingFilters, flags); } private protected async Task VerifyAtEndOfFileAsync( @@ -975,7 +981,7 @@ private protected async Task VerifyAtEndOfFileAsync( string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription = null, + string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { // only do this if the placeholder was at the end of the text. @@ -991,7 +997,7 @@ await BaseVerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, - inlineDescription, matchingFilters, flags); + inlineDescription, isComplexTextEdit, matchingFilters, flags); } private protected Task VerifyAtPosition_ItemPartiallyWrittenAsync( @@ -999,14 +1005,14 @@ private protected Task VerifyAtPosition_ItemPartiallyWrittenAsync( string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription = null, + string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { return VerifyAtPositionAsync( code, position, ItemPartiallyWritten(expectedItemOrNull), usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); } private protected Task VerifyAtEndOfFileAsync( @@ -1014,13 +1020,13 @@ private protected Task VerifyAtEndOfFileAsync( string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription = null, + string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { return VerifyAtEndOfFileAsync(code, position, string.Empty, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, - displayTextPrefix, inlineDescription, matchingFilters, flags); + displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags); } private protected Task VerifyAtEndOfFile_ItemPartiallyWrittenAsync( @@ -1028,14 +1034,14 @@ private protected Task VerifyAtEndOfFile_ItemPartiallyWrittenAsync( string expectedItemOrNull, string expectedDescriptionOrNull, SourceCodeKind sourceCodeKind, bool checkForAbsence, int? glyph, int? matchPriority, bool? hasSuggestionItem, string displayTextSuffix, - string displayTextPrefix, string inlineDescription = null, + string displayTextPrefix, string inlineDescription = null, bool? isComplexTextEdit = null, List matchingFilters = null, CompletionItemFlags? flags = null) { return VerifyAtEndOfFileAsync( code, position, ItemPartiallyWritten(expectedItemOrNull), usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, - matchingFilters, flags); + isComplexTextEdit, matchingFilters, flags); } protected void VerifyTextualTriggerCharacter( diff --git a/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.cs b/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.cs index f12e5f639cae5..846ceda99d15c 100644 --- a/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.cs +++ b/src/EditorFeatures/TestUtilities/TestOptionsServiceFactory.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; @@ -12,7 +10,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; -using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests @@ -20,13 +18,16 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests [ExportWorkspaceServiceFactory(typeof(IOptionService), ServiceLayer.Test), Shared, PartNotDiscoverable] internal class TestOptionsServiceFactory : IWorkspaceServiceFactory { + private readonly IWorkspaceThreadingService? _workspaceThreadingService; private readonly ImmutableArray> _providers; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public TestOptionsServiceFactory( + [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionProviders) { + _workspaceThreadingService = workspaceThreadingService; _providers = optionProviders.ToImmutableArray(); } @@ -34,7 +35,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { // give out new option service per workspace return new OptionServiceFactory.OptionService( - new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), + new GlobalOptionService(_workspaceThreadingService, _providers, SpecializedCollections.EmptyEnumerable>()), workspaceServices); } } diff --git a/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.cs b/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.cs index fc67ba83138fa..d72d4b71f1669 100644 --- a/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.cs +++ b/src/EditorFeatures/TestUtilities/TestOptionsServiceWithSharedGlobalOptionsServiceFactory.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; @@ -12,6 +10,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; +using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.UnitTests @@ -29,9 +28,10 @@ internal class TestOptionsServiceWithSharedGlobalOptionsServiceFactory : IWorksp [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public TestOptionsServiceWithSharedGlobalOptionsServiceFactory( + [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionProviders) { - _globalOptionService = new GlobalOptionService(optionProviders.ToImmutableArray(), SpecializedCollections.EmptyEnumerable>()); + _globalOptionService = new GlobalOptionService(workspaceThreadingService, optionProviders.ToImmutableArray(), SpecializedCollections.EmptyEnumerable>()); } public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) diff --git a/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs b/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs index 900a29ed0783c..13ca0f4ef358b 100644 --- a/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs +++ b/src/EditorFeatures/TestUtilities/TodoComments/AbtractTodoCommentTests.cs @@ -25,6 +25,8 @@ namespace Microsoft.CodeAnalysis.Test.Utilities.TodoComments { public abstract class AbstractTodoCommentTests { + protected const string DefaultTokenList = "HACK:1|TODO:1|UNDONE:1|UnresolvedMergeConflict:0"; + protected abstract TestWorkspace CreateWorkspace(string codeWithMarker); protected async Task TestAsync(string codeWithMarker) @@ -38,7 +40,7 @@ protected async Task TestAsync(string codeWithMarker) var document = workspace.CurrentSolution.GetDocument(documentId); var service = document.GetLanguageService(); var todoComments = await service.GetTodoCommentsAsync(document, - TodoCommentDescriptor.Parse(TodoCommentOptions.TokenList.DefaultValue), + TodoCommentDescriptor.Parse(workspace.Options.GetOption(TodoCommentOptions.TokenList)), CancellationToken.None); using var _ = ArrayBuilder.GetInstance(out var converted); diff --git a/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockDocumentNavigationService.vb b/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockDocumentNavigationService.vb index c17c8bfca2029..d8638f223f8ea 100644 --- a/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockDocumentNavigationService.vb +++ b/src/EditorFeatures/TestUtilities2/Utilities/GoToHelpers/MockDocumentNavigationService.vb @@ -59,7 +59,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities.GoToHelpers Return _canNavigateToPosition End Function - Public Function TryNavigateToSpan(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As OptionSet, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToSpan + Public Function TryNavigateToSpan(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As OptionSet, allowInvalidSpan As Boolean, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToSpan _triedNavigationToSpan = True _documentId = documentId _options = options diff --git a/src/EditorFeatures/TestUtilities2/Utilities/MockDocumentNavigationServiceProvider.vb b/src/EditorFeatures/TestUtilities2/Utilities/MockDocumentNavigationServiceProvider.vb index ff787a425f1da..7b29643d7681b 100644 --- a/src/EditorFeatures/TestUtilities2/Utilities/MockDocumentNavigationServiceProvider.vb +++ b/src/EditorFeatures/TestUtilities2/Utilities/MockDocumentNavigationServiceProvider.vb @@ -87,7 +87,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Return TryNavigateToPositionReturnValue End Function - Public Function TryNavigateToSpan(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As OptionSet, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToSpan + Public Function TryNavigateToSpan(workspace As Workspace, documentId As DocumentId, textSpan As TextSpan, options As OptionSet, allowInvalidSpans As Boolean, cancellationToken As CancellationToken) As Boolean Implements IDocumentNavigationService.TryNavigateToSpan Me.ProvidedDocumentId = documentId Me.ProvidedTextSpan = textSpan Me.ProvidedOptions = options diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb index 6c54a27301016..276120645efd8 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, - matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?) As Task + isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?) As Task Return MyBase.VerifyWorkerAsync( code, position, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, usePreviousCharAsTrigger, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, - matchingFilters, flags) + isComplexTextEdit, matchingFilters, flags) 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, - matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?) As Task + isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?) 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,12 +53,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Await VerifyAtPositionAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, - matchingFilters, flags) + isComplexTextEdit, matchingFilters, flags) Await VerifyAtEndOfFileAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, - matchingFilters, flags) + isComplexTextEdit, matchingFilters, flags) ' 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) @@ -66,12 +66,12 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Await VerifyAtPosition_ItemPartiallyWrittenAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, - displayTextSuffix, displayTextPrefix, inlineDescription, matchingFilters) + displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters) Await VerifyAtEndOfFile_ItemPartiallyWrittenAsync( code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, - displayTextSuffix, displayTextPrefix, inlineDescription, matchingFilters) + displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters) End If End Function diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.vb index 072b496c40acd..eb2636346cdd2 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, - matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?) As Task + isComplexTextEdit As Boolean?, matchingFilters As List(Of CompletionFilter), flags As CompletionItemFlags?) 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, - matchingFilters, flags) + isComplexTextEdit, matchingFilters, flags) End Function diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb index 76dc8c703a11b..a3264cc94b7e8 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/OverrideCompletionProviderTests.vb @@ -564,7 +564,7 @@ End Class.Value Dim position As Integer MarkupTestFile.GetPosition(markup.NormalizeLineEndings(), code, position) - Await BaseVerifyWorkerAsync(code, position, "[Class]()", "Sub CBase.Class()", SourceCodeKind.Regular, False, False, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing) + Await BaseVerifyWorkerAsync(code, position, "[Class]()", "Sub CBase.Class()", SourceCodeKind.Regular, False, False, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing) End Function @@ -585,7 +585,7 @@ End Class.Value Await BaseVerifyWorkerAsync( code, position, "[Class]", "Property CBase.Class As Integer", - SourceCodeKind.Regular, False, False, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing) + SourceCodeKind.Regular, False, False, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing) End Function @@ -1856,5 +1856,9 @@ public class C Assert.False(completionList.Items.Any(Function(c) c.DisplayText = "e")) End Using End Function + + Public Overloads Function VerifyItemExistsAsync(markup As String, expectedItem As String) As Task + Return VerifyItemExistsAsync(markup, expectedItem, isComplexTextEdit:=True) + End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb index ad573e1311093..d9003472ed7e5 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb @@ -7815,10 +7815,10 @@ End Namespace Dim position = workspace.DocumentWithCursor.CursorPosition.Value Await CheckResultsAsync(document, position, "InstanceMethod", expectedDescriptionOrNull:=Nothing, usePreviousCharAsTrigger:=False, checkForAbsence:=False, glyph:=Nothing, matchPriority:=Nothing, hasSuggestionModeItem:=Nothing, displayTextSuffix:=Nothing, displayTextPrefix:=Nothing, inlineDescription:=Nothing, - matchingFilters:=Nothing, flags:=Nothing) + isComplexTextEdit:=Nothing, matchingFilters:=Nothing, flags:=Nothing) Await CheckResultsAsync(document, position, "SharedMethod", expectedDescriptionOrNull:=Nothing, usePreviousCharAsTrigger:=False, checkForAbsence:=False, glyph:=Nothing, matchPriority:=Nothing, hasSuggestionModeItem:=Nothing, displayTextSuffix:=Nothing, displayTextPrefix:=Nothing, inlineDescription:=Nothing, - matchingFilters:=Nothing, flags:=Nothing) + isComplexTextEdit:=Nothing, matchingFilters:=Nothing, flags:=Nothing) End Using End Function diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.vb index a21a9f8bafc6a..706dcba795447 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/TypeImportCompletionProviderTests.vb @@ -59,7 +59,7 @@ Public Class Bar End Class]]>.Value Dim markup = CreateMarkupForSingleProject(file2, file1, LanguageNames.VisualBasic) - Await VerifyItemExistsAsync(markup, "My", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", expectedDescriptionOrNull:="Class Foo.MyAttribute") + Await VerifyItemExistsAsync(markup, "My", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", expectedDescriptionOrNull:="Class Foo.MyAttribute", isComplexTextEdit:=True) Await VerifyItemIsAbsentAsync(markup, "MyAttributeWithoutSuffix", inlineDescription:="Foo") ' We intentionally ignore attribute types without proper suffix for perf reason Await VerifyItemIsAbsentAsync(markup, "MyAttribute", inlineDescription:="Foo") Await VerifyItemIsAbsentAsync(markup, "MyVBClass", inlineDescription:="Foo") @@ -90,9 +90,9 @@ Public Class Bar End Class]]>.Value Dim markup = CreateMarkupForSingleProject(file2, file1, LanguageNames.VisualBasic) - Await VerifyItemExistsAsync(markup, "MyAttribute", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", expectedDescriptionOrNull:="Class Foo.MyAttribute") - Await VerifyItemExistsAsync(markup, "MyAttributeWithoutSuffix", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", expectedDescriptionOrNull:="Class Foo.MyAttributeWithoutSuffix") - Await VerifyItemExistsAsync(markup, "MyVBClass", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", expectedDescriptionOrNull:="Class Foo.MyVBClass") + Await VerifyItemExistsAsync(markup, "MyAttribute", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", expectedDescriptionOrNull:="Class Foo.MyAttribute", isComplexTextEdit:=True) + Await VerifyItemExistsAsync(markup, "MyAttributeWithoutSuffix", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", expectedDescriptionOrNull:="Class Foo.MyAttributeWithoutSuffix", isComplexTextEdit:=True) + Await VerifyItemExistsAsync(markup, "MyVBClass", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", expectedDescriptionOrNull:="Class Foo.MyVBClass", isComplexTextEdit:=True) Await VerifyItemIsAbsentAsync(markup, "My", inlineDescription:="Foo") End Function @@ -141,7 +141,7 @@ Public Class Bar End Class]]>.Value Dim markup = CreateMarkupForProjectWithProjectReference(file2, file1, LanguageNames.VisualBasic, LanguageNames.CSharp) - Await VerifyItemExistsAsync(markup, "My", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", expectedDescriptionOrNull:="Class Foo.Myattribute") + Await VerifyItemExistsAsync(markup, "My", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", expectedDescriptionOrNull:="Class Foo.Myattribute", isComplexTextEdit:=True) Await VerifyItemIsAbsentAsync(markup, "Myattribute", inlineDescription:="Foo") End Function @@ -163,7 +163,7 @@ Public Class Bar End Class]]>.Value Dim markup = CreateMarkupForSingleProject(file2, file1, LanguageNames.VisualBasic) - Await VerifyItemExistsAsync(markup, "MyGenericClass", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", displayTextSuffix:="(Of ...)", expectedDescriptionOrNull:="Class Foo.MyGenericClass(Of T)") + Await VerifyItemExistsAsync(markup, "MyGenericClass", glyph:=Glyph.ClassPublic, inlineDescription:="Foo", displayTextSuffix:="(Of ...)", expectedDescriptionOrNull:="Class Foo.MyGenericClass(Of T)", isComplexTextEdit:=True) End Function @@ -260,7 +260,7 @@ Namespace Foo1 End Namespace" Dim markup = CreateMarkupForSingleProject(file1, file2, LanguageNames.VisualBasic) - Await VerifyItemExistsAsync(markup, "Foo4", glyph:=Glyph.ClassPublic, inlineDescription:="Foo1.Foo2.Foo3", displayTextSuffix:="(Of ...)") + Await VerifyItemExistsAsync(markup, "Foo4", glyph:=Glyph.ClassPublic, inlineDescription:="Foo1.Foo2.Foo3", displayTextSuffix:="(Of ...)", isComplexTextEdit:=True) End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb index 4926a0a87ae48..4fba5c0c239d2 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/XmlDocCommentCompletionProviderTests.vb @@ -22,9 +22,9 @@ 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, - 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, matchingFilters, flags) - Await VerifyAtEndOfFileAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, matchingFilters, flags) + 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) + Await VerifyAtEndOfFileAsync(code, position, usePreviousCharAsTrigger, expectedItemOrNull, expectedDescriptionOrNull, sourceCodeKind, checkForAbsence, glyph, matchPriority, hasSuggestionItem, displayTextSuffix, displayTextPrefix, inlineDescription, isComplexTextEdit, matchingFilters, flags) End Function Private Async Function VerifyItemsExistAsync(markup As String, ParamArray items() As String) As Task diff --git a/src/EditorFeatures/VisualBasicTest/InitializeParameter/AddParameterCheckTests.vb b/src/EditorFeatures/VisualBasicTest/InitializeParameter/AddParameterCheckTests.vb index 38da8c38a421a..c21573fa7f0d0 100644 --- a/src/EditorFeatures/VisualBasicTest/InitializeParameter/AddParameterCheckTests.vb +++ b/src/EditorFeatures/VisualBasicTest/InitializeParameter/AddParameterCheckTests.vb @@ -69,10 +69,12 @@ class C end sub end class", " +Imports System + class C public sub new(byref s as string) If s Is Nothing Then - Throw New System.ArgumentNullException(NameOf(s)) + Throw New ArgumentNullException(NameOf(s)) End If end sub end class") @@ -89,11 +91,12 @@ class C end sub end class", " +Imports System Imports System.Runtime.InteropServices class C public sub new( byref s as string) If s Is Nothing Then - Throw New System.ArgumentNullException(NameOf(s)) + Throw New ArgumentNullException(NameOf(s)) End If end sub end class") @@ -628,6 +631,28 @@ Class C Sub M(a As Action(Of Integer, Integer)) M(Sub(x[||] End Sub +End Class") + End Function + + + + Public Async Function TestImportSystem() As Task + Await TestInRegularAndScript1Async( +" +Class C + Sub M([||]s As String) + + End Sub +End Class", +" +Imports System + +Class C + Sub M(s As String) + If s Is Nothing Then + Throw New ArgumentNullException(NameOf(s)) + End If + End Sub End Class") End Function End Class diff --git a/src/EditorFeatures/VisualBasicTest/TodoComment/TodoCommentTests.vb b/src/EditorFeatures/VisualBasicTest/TodoComment/TodoCommentTests.vb index ee22f45fe47b8..6d18c7bbe7f70 100644 --- a/src/EditorFeatures/VisualBasicTest/TodoComment/TodoCommentTests.vb +++ b/src/EditorFeatures/VisualBasicTest/TodoComment/TodoCommentTests.vb @@ -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. +Imports Microsoft.CodeAnalysis.Editor.Implementation.TodoComments Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Test.Utilities.TodoComments @@ -12,7 +13,9 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.TodoComment Inherits AbstractTodoCommentTests Protected Overrides Function CreateWorkspace(codeWithMarker As String) As TestWorkspace - Return TestWorkspace.CreateVisualBasic(codeWithMarker) + Dim workspace = TestWorkspace.CreateVisualBasic(codeWithMarker) + workspace.SetOptions(workspace.Options.WithChangedOption(TodoCommentOptions.TokenList, DefaultTokenList)) + Return workspace End Function diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/WinMdTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/WinMdTests.cs index 81a17c0fd0ab6..8fdd619f7236f 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/WinMdTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/WinMdTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.CSharp.UnitTests; using Microsoft.CodeAnalysis.ExpressionEvaluator; using Microsoft.CodeAnalysis.ExpressionEvaluator.UnitTests; +using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Debugger.Evaluation; using Roslyn.Test.PdbUtilities; using Roslyn.Test.Utilities; diff --git a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs index 04dfc1523e410..a347e1ef0c368 100644 --- a/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs +++ b/src/ExpressionEvaluator/Core/Test/ExpressionCompiler/ExpressionCompilerTestHelpers.cs @@ -499,29 +499,6 @@ internal static ModuleInstance GetModuleInstanceForIL(string ilSource) return ModuleInstance.Create(peBytes, SymReaderFactory.CreateReader(pdbBytes), includeLocalSignatures: true); } - internal static AssemblyIdentity GetAssemblyIdentity(this MetadataReference reference) - { - using (var moduleMetadata = GetManifestModuleMetadata(reference)) - { - return moduleMetadata.MetadataReader.ReadAssemblyIdentityOrThrow(); - } - } - - internal static Guid GetModuleVersionId(this MetadataReference reference) - { - using (var moduleMetadata = GetManifestModuleMetadata(reference)) - { - return moduleMetadata.MetadataReader.GetModuleVersionIdOrThrow(); - } - } - - private static ModuleMetadata GetManifestModuleMetadata(MetadataReference reference) - { - // make a copy to avoid disposing shared reference metadata: - var metadata = ((MetadataImageReference)reference).GetMetadata(); - return (metadata as AssemblyMetadata)?.GetModules()[0] ?? (ModuleMetadata)metadata; - } - internal static void VerifyLocal( this CompilationTestData testData, string typeName, diff --git a/src/Features/CSharp/Portable/BraceCompletion/ParenthesisBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/ParenthesisBraceCompletionService.cs index 16d44d24618f5..26e051943636a 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/ParenthesisBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/ParenthesisBraceCompletionService.cs @@ -46,10 +46,10 @@ protected override async Task IsValidOpenBraceTokenAtPositionAsync(SyntaxT } // now check whether parser think whether there is already counterpart closing parenthesis - var (openBrace, closeBrace) = token.Parent.GetParentheses(); + var (openParen, closeParen) = token.Parent.GetParentheses(); // We can complete the brace if the closing brace is missing or the incorrect kind. - if (closeBrace.Kind() != SyntaxKind.CloseParenToken || closeBrace.Span.Length == 0) + if (closeParen.Kind() != SyntaxKind.CloseParenToken || closeParen.Span.Length == 0) { return true; } @@ -58,7 +58,7 @@ protected override async Task IsValidOpenBraceTokenAtPositionAsync(SyntaxT // brace completion session higher up on the stack. If that's the case then we can // complete the opening brace here, so return this as valid for completion. var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - return text.Lines.GetLineFromPosition(openBrace.SpanStart).LineNumber == text.Lines.GetLineFromPosition(closeBrace.Span.End).LineNumber; + return text.Lines.GetLineFromPosition(openParen.SpanStart).LineNumber == text.Lines.GetLineFromPosition(closeParen.Span.End).LineNumber; } } } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/PreprocessorCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/PreprocessorCompletionProvider.cs index ffa02944ab0fb..9c5271c40e451 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/PreprocessorCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/PreprocessorCompletionProvider.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Composition; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Completion.Providers; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs index c3791004f2aa7..57a8d38828ad3 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.cs @@ -156,7 +156,7 @@ protected override async Task> GetItemsWorkerAsync( items.AddRange(GetAlwaysVisibleItems()); return items; } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return SpecializedCollections.EmptyEnumerable(); } diff --git a/src/Features/CSharp/Portable/ConvertAnonymousTypeToClass/CSharpConvertAnonymousTypeToClassCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertAnonymousTypeToClass/CSharpConvertAnonymousTypeToClassCodeRefactoringProvider.cs index 9fa62ee72c4e8..819c0861d1d76 100644 --- a/src/Features/CSharp/Portable/ConvertAnonymousTypeToClass/CSharpConvertAnonymousTypeToClassCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertAnonymousTypeToClass/CSharpConvertAnonymousTypeToClassCodeRefactoringProvider.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.ConvertAnonymousTypeToClass; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/CSharp/Portable/Debugging/CSharpBreakpointResolutionService.cs b/src/Features/CSharp/Portable/Debugging/CSharpBreakpointResolutionService.cs index 367066f9412dc..fa69eec0b2ff0 100644 --- a/src/Features/CSharp/Portable/Debugging/CSharpBreakpointResolutionService.cs +++ b/src/Features/CSharp/Portable/Debugging/CSharpBreakpointResolutionService.cs @@ -47,7 +47,7 @@ public async Task ResolveBreakpointAsync(Document do return BreakpointResolutionResult.CreateSpanResult(document, span); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return null; } diff --git a/src/Features/CSharp/Portable/Debugging/CSharpProximityExpressionsService.cs b/src/Features/CSharp/Portable/Debugging/CSharpProximityExpressionsService.cs index 157285d85bffd..fd2ffb1304cb8 100644 --- a/src/Features/CSharp/Portable/Debugging/CSharpProximityExpressionsService.cs +++ b/src/Features/CSharp/Portable/Debugging/CSharpProximityExpressionsService.cs @@ -94,7 +94,7 @@ public async Task> GetProximityExpressionsAsync( var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); return GetProximityExpressions(tree, position, cancellationToken); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return null; } diff --git a/src/Features/CSharp/Portable/Debugging/DataTipInfoGetter.cs b/src/Features/CSharp/Portable/Debugging/DataTipInfoGetter.cs index fd952bef4f7f8..e713c7e1366df 100644 --- a/src/Features/CSharp/Portable/Debugging/DataTipInfoGetter.cs +++ b/src/Features/CSharp/Portable/Debugging/DataTipInfoGetter.cs @@ -87,7 +87,7 @@ internal static async Task GetInfoAsync(Document document, int return new DebugDataTipInfo(expression.Span, textOpt); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return default; } diff --git a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs index ace0587368a01..e0e62cceef9c2 100644 --- a/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs +++ b/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs @@ -2378,7 +2378,7 @@ private void ClassifyUpdate(TypeDeclarationSyntax oldNode, TypeDeclarationSyntax } // Allow partial keyword to be added or removed. - if (!AreModifiersEquivalent(oldNode.Modifiers, newNode.Modifiers, ignore: SyntaxKind.PartialKeyword)) + if (!AreModifiersEquivalent(oldNode.Modifiers, newNode.Modifiers, ignore: SyntaxKind.PartialKeyword, ignore2: SyntaxKind.UnsafeKeyword)) { ReportError(RudeEditKind.ModifiersUpdate); return; @@ -2422,7 +2422,7 @@ private void ClassifyUpdate(EnumDeclarationSyntax oldNode, EnumDeclarationSyntax private void ClassifyUpdate(DelegateDeclarationSyntax oldNode, DelegateDeclarationSyntax newNode) { - if (!SyntaxFactory.AreEquivalent(oldNode.Modifiers, newNode.Modifiers)) + if (!AreModifiersEquivalent(oldNode.Modifiers, newNode.Modifiers, ignore: SyntaxKind.UnsafeKeyword)) { ReportError(RudeEditKind.ModifiersUpdate); return; @@ -2434,8 +2434,10 @@ private void ClassifyUpdate(DelegateDeclarationSyntax oldNode, DelegateDeclarati return; } - Debug.Assert(!SyntaxFactory.AreEquivalent(oldNode.Identifier, newNode.Identifier)); - ReportError(RudeEditKind.Renamed); + if (!SyntaxFactory.AreEquivalent(oldNode.Identifier, newNode.Identifier)) + { + ReportError(RudeEditKind.Renamed); + } } private void ClassifyUpdate(BaseFieldDeclarationSyntax oldNode, BaseFieldDeclarationSyntax newNode) @@ -2446,9 +2448,11 @@ private void ClassifyUpdate(BaseFieldDeclarationSyntax oldNode, BaseFieldDeclara return; } - Debug.Assert(!SyntaxFactory.AreEquivalent(oldNode.Modifiers, newNode.Modifiers)); - ReportError(RudeEditKind.ModifiersUpdate); - return; + if (!AreModifiersEquivalent(oldNode.Modifiers, newNode.Modifiers, ignore: SyntaxKind.UnsafeKeyword)) + { + ReportError(RudeEditKind.ModifiersUpdate); + return; + } } private void ClassifyUpdate(VariableDeclarationSyntax oldNode, VariableDeclarationSyntax newNode) @@ -2508,7 +2512,7 @@ private void ClassifyUpdate(MethodDeclarationSyntax oldNode, MethodDeclarationSy } // Ignore async keyword when matching modifiers. Async checks are done in ComputeBodyMatch. - if (!AreModifiersEquivalent(oldNode.Modifiers, newNode.Modifiers, ignore: SyntaxKind.AsyncKeyword)) + if (!AreModifiersEquivalent(oldNode.Modifiers, newNode.Modifiers, ignore: SyntaxKind.AsyncKeyword, ignore2: SyntaxKind.UnsafeKeyword)) { ReportError(RudeEditKind.ModifiersUpdate); return; @@ -2625,7 +2629,7 @@ private void ClassifyUpdate(EnumMemberDeclarationSyntax oldNode, EnumMemberDecla private void ClassifyUpdate(ConstructorDeclarationSyntax oldNode, ConstructorDeclarationSyntax newNode) { - if (!SyntaxFactory.AreEquivalent(oldNode.Modifiers, newNode.Modifiers)) + if (!AreModifiersEquivalent(oldNode.Modifiers, newNode.Modifiers, ignore: SyntaxKind.UnsafeKeyword)) { ReportError(RudeEditKind.ModifiersUpdate); return; @@ -2649,7 +2653,7 @@ private void ClassifyUpdate(DestructorDeclarationSyntax oldNode, DestructorDecla private void ClassifyUpdate(PropertyDeclarationSyntax oldNode, PropertyDeclarationSyntax newNode) { - if (!SyntaxFactory.AreEquivalent(oldNode.Modifiers, newNode.Modifiers)) + if (!AreModifiersEquivalent(oldNode.Modifiers, newNode.Modifiers, ignore: SyntaxKind.UnsafeKeyword)) { ReportError(RudeEditKind.ModifiersUpdate); return; @@ -2692,17 +2696,18 @@ private void ClassifyUpdate(PropertyDeclarationSyntax oldNode, PropertyDeclarati return; } - Debug.Assert(!SyntaxFactory.AreEquivalent(oldNode.Initializer, newNode.Initializer)); - - if (containingType.Arity > 0) + if (!SyntaxFactory.AreEquivalent(oldNode.Initializer, newNode.Initializer)) { - ReportError(RudeEditKind.GenericTypeInitializerUpdate); - return; - } + if (containingType.Arity > 0) + { + ReportError(RudeEditKind.GenericTypeInitializerUpdate); + return; + } - if (newNode.Initializer != null) - { - ClassifyDeclarationBodyRudeUpdates(newNode.Initializer); + if (newNode.Initializer != null) + { + ClassifyDeclarationBodyRudeUpdates(newNode.Initializer); + } } } @@ -2798,7 +2803,7 @@ private void ClassifyUpdate(AttributeListSyntax oldNode, AttributeListSyntax new // changes in attribute separators are not interesting: } - private static bool AreModifiersEquivalent(SyntaxTokenList oldModifiers, SyntaxTokenList newModifiers, SyntaxKind ignore) + private static bool AreModifiersEquivalent(SyntaxTokenList oldModifiers, SyntaxTokenList newModifiers, SyntaxKind ignore, SyntaxKind? ignore2 = null) { var oldIgnoredModifierIndex = oldModifiers.IndexOf(ignore); var newIgnoredModifierIndex = newModifiers.IndexOf(ignore); @@ -2813,7 +2818,9 @@ private static bool AreModifiersEquivalent(SyntaxTokenList oldModifiers, SyntaxT newModifiers = newModifiers.RemoveAt(newIgnoredModifierIndex); } - return SyntaxFactory.AreEquivalent(oldModifiers, newModifiers); + return ignore2 is null + ? SyntaxFactory.AreEquivalent(oldModifiers, newModifiers) + : AreModifiersEquivalent(oldModifiers, newModifiers, ignore2.Value); } private void ClassifyMethodBodyRudeUpdate( diff --git a/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs index bda84557b7e92..8dd818a168142 100644 --- a/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/InitializeParameter/CSharpAddParameterCheckCodeRefactoringProvider.cs @@ -4,9 +4,11 @@ #nullable disable +using System; using System.Composition; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; @@ -26,7 +28,7 @@ internal class CSharpAddParameterCheckCodeRefactoringProvider : BinaryExpressionSyntax> { [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpAddParameterCheckCodeRefactoringProvider() { } diff --git a/src/Features/Core/Portable/Completion/CompletionHelper.cs b/src/Features/Core/Portable/Completion/CompletionHelper.cs index a06e5d8669467..4b4b57cef0455 100644 --- a/src/Features/Core/Portable/Completion/CompletionHelper.cs +++ b/src/Features/Core/Portable/Completion/CompletionHelper.cs @@ -40,7 +40,7 @@ public ImmutableArray GetHighlightedSpans( /// /// Returns true if the completion item matches the pattern so far. Returns 'true' - /// iff the completion item matches and should be included in the filtered completion + /// if and only if the completion item matches and should be included in the filtered completion /// results, or false if it should not be. /// public bool MatchesPattern(string text, string pattern, CultureInfo culture) diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractDocCommentCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractDocCommentCompletionProvider.cs index a05e28df20ba6..a33a0baacf034 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractDocCommentCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractDocCommentCompletionProvider.cs @@ -52,7 +52,9 @@ internal abstract class AbstractDocCommentCompletionProvider : LSPCompl new[] { PermissionElementName, CrefAttributeName, $"{CrefAttributeName}=\"", "\"" }, new[] { SeeElementName, CrefAttributeName, $"{CrefAttributeName}=\"", "\"" }, new[] { SeeElementName, LangwordAttributeName, $"{LangwordAttributeName}=\"", "\"" }, + new[] { SeeElementName, HrefAttributeName, $"{HrefAttributeName}=\"", "\"" }, new[] { SeeAlsoElementName, CrefAttributeName, $"{CrefAttributeName}=\"", "\"" }, + new[] { SeeAlsoElementName, HrefAttributeName, $"{HrefAttributeName}=\"", "\"" }, new[] { ListElementName, TypeAttributeName, $"{TypeAttributeName}=\"", "\"" }, new[] { ParameterElementName, NameAttributeName, $"{NameAttributeName}=\"", "\"" }, new[] { ParameterReferenceElementName, NameAttributeName, $"{NameAttributeName}=\"", "\"" }, diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractPreprocessorCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractPreprocessorCompletionProvider.cs index eefe9243597e7..1106336ce1d58 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractPreprocessorCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractPreprocessorCompletionProvider.cs @@ -6,13 +6,12 @@ using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers +namespace Microsoft.CodeAnalysis.Completion.Providers { internal abstract class AbstractPreprocessorCompletionProvider : LSPCompletionProvider { diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.ExtensionMethodSymbolComputer.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.ExtensionMethodSymbolComputer.cs index cf98d70292ea1..d111b4bd14e21 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.ExtensionMethodSymbolComputer.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ExtensionMethodImportCompletionHelper.ExtensionMethodSymbolComputer.cs @@ -222,7 +222,7 @@ private ImmutableArray GetExtensionMethodsForSymbolsFromDifferent { cancellationToken.ThrowIfCancellationRequested(); - var declaredReceiverTypeInOriginatingCompilation = SymbolFinder.FindSimilarSymbols(declaredReceiverType, _originatingSemanticModel.Compilation).FirstOrDefault(); + var declaredReceiverTypeInOriginatingCompilation = SymbolFinder.FindSimilarSymbols(declaredReceiverType, _originatingSemanticModel.Compilation, cancellationToken).FirstOrDefault(); if (declaredReceiverTypeInOriginatingCompilation == null) { // Bug: https://github.com/dotnet/roslyn/issues/45404 diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ImportCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ImportCompletionItem.cs index e67a4a9f00dc3..3d84f2452cce8 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ImportCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/ImportCompletionItem.cs @@ -73,7 +73,8 @@ public static CompletionItem Create( rules: CompletionItemRules.Default, displayTextPrefix: null, displayTextSuffix: arity == 0 ? string.Empty : genericTypeSuffix, - inlineDescription: containingNamespace); + inlineDescription: containingNamespace, + isComplexTextEdit: true); if (includedInTargetTypeCompletion) { @@ -102,7 +103,8 @@ public static CompletionItem CreateAttributeItemWithoutSuffix(CompletionItem att rules: attributeItem.Rules, displayTextPrefix: attributeItem.DisplayTextPrefix, displayTextSuffix: attributeItem.DisplayTextSuffix, - inlineDescription: attributeItem.InlineDescription); + inlineDescription: attributeItem.InlineDescription, + isComplexTextEdit: true); item.Flags = flags; return item; diff --git a/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs index 2de5b01be4715..59bad4dfc00e8 100644 --- a/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs @@ -22,7 +22,7 @@ using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.CSharp.ConvertAnonymousTypeToClass +namespace Microsoft.CodeAnalysis.ConvertAnonymousTypeToClass { internal abstract class AbstractConvertAnonymousTypeToClassCodeRefactoringProvider< TExpressionSyntax, diff --git a/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs b/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs index 69f6109df4e39..ae65a42adb921 100644 --- a/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs +++ b/src/Features/Core/Portable/Debugging/AbstractBreakpointResolver.cs @@ -114,7 +114,7 @@ public async Task> DoAsync(CancellationT return members.Where(m => IsApplicable(m, parameterCount, cancellationToken)). Select(CreateBreakpoint).ToImmutableArrayOrEmpty(); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return ImmutableArray.Empty; } @@ -150,7 +150,7 @@ private async Task> FindMembersAsync( return FindMembers(containers, nameParts.ToArray()); } } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return ImmutableArray.Empty; } diff --git a/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs b/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs index b4644fa2c466e..d607e18a7bb80 100644 --- a/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs +++ b/src/Features/Core/Portable/DesignerAttribute/AbstractDesignerAttributeIncrementalAnalyzer.cs @@ -157,7 +157,7 @@ private async Task AnalyzeProjectAsync(Project project, Document? specificDocume return (document, data); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return default; } diff --git a/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs b/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs index 289bac11adfa3..8af079a925384 100644 --- a/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs +++ b/src/Features/Core/Portable/Diagnostics/DocumentAnalysisExecutor.cs @@ -293,12 +293,12 @@ async Task VerifySpanBasedCompilerDiagnosticsAsync() // make sure what we got from range is same as what we got from whole diagnostics var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var rangeDeclaractionDiagnostics = model.GetDeclarationDiagnostics(span.Value).ToArray(); - var rangeMethodBodyDiagnostics = model.GetMethodBodyDiagnostics(span.Value).ToArray(); + var rangeDeclaractionDiagnostics = model.GetDeclarationDiagnostics(span.Value, cancellationToken).ToArray(); + var rangeMethodBodyDiagnostics = model.GetMethodBodyDiagnostics(span.Value, cancellationToken).ToArray(); var rangeDiagnostics = rangeDeclaractionDiagnostics.Concat(rangeMethodBodyDiagnostics).Where(shouldInclude).ToArray(); - var wholeDeclarationDiagnostics = model.GetDeclarationDiagnostics().ToArray(); - var wholeMethodBodyDiagnostics = model.GetMethodBodyDiagnostics().ToArray(); + var wholeDeclarationDiagnostics = model.GetDeclarationDiagnostics(cancellationToken: cancellationToken).ToArray(); + var wholeMethodBodyDiagnostics = model.GetMethodBodyDiagnostics(cancellationToken: cancellationToken).ToArray(); var wholeDiagnostics = wholeDeclarationDiagnostics.Concat(wholeMethodBodyDiagnostics).Where(shouldInclude).ToArray(); if (!AnalyzerHelper.AreEquivalent(rangeDiagnostics, wholeDiagnostics)) diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs index 6e1a9554da44b..919ae99005d41 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer.Executor.cs @@ -47,7 +47,7 @@ internal partial class DiagnosticIncrementalAnalyzer return null; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -82,7 +82,7 @@ private static async Task ComputeDocumentAnalysisDataAsync // we only care about local diagnostics return new DocumentAnalysisData(version, existingData.Items, diagnostics.ToImmutableArrayOrEmpty()); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -128,7 +128,7 @@ private async Task GetProjectAnalysisDataAsync( return new ProjectAnalysisData(project.Id, version, existingData.Result, result); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -211,7 +211,7 @@ private async Task service.ReportAnalyzerPerformanceAsync(performanceInfo, count, cancellationToken), cancellationToken).ConfigureAwait(false); } - catch (Exception ex) when (FatalError.ReportAndCatchUnlessCanceled(ex)) + catch (Exception ex) when (FatalError.ReportAndCatchUnlessCanceled(ex, cancellationToken)) { // ignore all, this is fire and forget method } diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs index f2f5985cfedc0..399553f0d052a 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_GetDiagnosticsForSpan.cs @@ -140,7 +140,7 @@ public async Task TryGetAsync(ArrayBuilder list, Cancellat Debug.Assert(!_blockForData || containsFullResult); return containsFullResult; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs index 9a84271a4bc1e..f1074dc73b870 100644 --- a/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs +++ b/src/Features/Core/Portable/Diagnostics/EngineV2/DiagnosticIncrementalAnalyzer_IncrementalAnalyzer.cs @@ -83,7 +83,7 @@ private async Task AnalyzeDocumentForKindAsync(TextDocument document, AnalysisKi } } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -163,7 +163,7 @@ private async Task AnalyzeProjectAsync(Project project, bool forceAnalyzerRun, C RaiseProjectDiagnosticsIfNeeded(project, stateSets, result.OldResult, result.Result); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs index be8b57266d566..30ca572b91487 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -622,7 +622,7 @@ public async Task AnalyzeDocumentAsync( hasChanges: true, hasSyntaxErrors: false); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { // The same behavior as if there was a syntax error - we are unable to analyze the document. // We expect OOM to be thrown during the analysis if the number of top-level entities is too large. @@ -1138,7 +1138,7 @@ private void AnalyzeChangedMemberBody( newActiveStatements[ordinal] = oldActiveStatements[ordinal].WithSpan(newText.Lines.GetLinePositionSpan(newSpan)); } } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { // Set the new spans of active statements overlapping the method body to match the old spans. // Even though these might be now outside of the method body it's ok since we report a rude edit and don't allow to continue. @@ -2642,7 +2642,7 @@ private async Task> AnalyzeSemanticsAsync( // The property itself is being updated. Currently we do not allow any modifiers or attributes to be updated, // so the only case when this happens is in C# for a property/indexer that has an expression body. // The symbol that's actually being updated is the getter. - // TODO: This will need to be revisited in https://github.com/dotnet/roslyn/issues/48628 + // TODO: This will need to be revisited in https://github.com/dotnet/roslyn/issues/52300 if (newSymbol is IPropertySymbol { GetMethod: var propertyGetter and not null }) { newSymbol = propertyGetter; diff --git a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs index 81e2704fb4fee..6a37cef18cc20 100644 --- a/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs @@ -32,17 +32,22 @@ internal sealed class DebuggingSession : IDisposable /// /// MVIDs read from the assembly built for given project id. /// - private readonly Dictionary _projectModuleIds; + private readonly Dictionary _projectModuleIds = new(); private readonly object _projectModuleIdsGuard = new(); /// /// The current baseline for given project id. /// The baseline is updated when changes are committed at the end of edit session. - /// The backing module readers of some baselines need to be kept alive -- store them in - /// and dispose them at the end of the debugging session + /// The backing module readers of initial baselines need to be kept alive -- store them in + /// and dispose them at the end of the debugging session. /// - private readonly Dictionary _projectEmitBaselines; - private List? _lazyBaselineModuleReaders; + /// + /// The baseline of each updated project is linked to its initial baseline that reads from the on-disk metadata and PDB. + /// Therefore once an initial baseline is created it needs to be kept alive till the end of the debugging session, + /// even whne it's replaced in by a newer baseline. + /// + private readonly Dictionary _projectEmitBaselines = new(); + private readonly List _initialBaselineModuleReaders = new(); private readonly object _projectEmitBaselinesGuard = new(); // Maps active statement instructions reported by the debugger to their latest spans that might not yet have been applied @@ -80,7 +85,7 @@ internal sealed class DebuggingSession : IDisposable // internal ImmutableDictionary> NonRemappableRegions { get; private set; } - private readonly HashSet _modulesPreparedForUpdate; + private readonly HashSet _modulesPreparedForUpdate = new(); private readonly object _modulesPreparedForUpdateGuard = new(); /// @@ -99,9 +104,6 @@ internal DebuggingSession( IEnumerable> initialDocumentStates) { _compilationOutputsProvider = compilationOutputsProvider; - _projectModuleIds = new Dictionary(); - _projectEmitBaselines = new Dictionary(); - _modulesPreparedForUpdate = new HashSet(); DebuggerService = debuggerService; LastCommittedSolution = new CommittedSolution(this, solution, initialDocumentStates); @@ -135,7 +137,7 @@ internal ImmutableArray GetBaselineModuleReaders() { lock (_projectEmitBaselinesGuard) { - return _lazyBaselineModuleReaders.ToImmutableArrayOrEmpty(); + return _initialBaselineModuleReaders.ToImmutableArrayOrEmpty(); } } @@ -185,12 +187,6 @@ from region in moduleRegions.Regions { _projectEmitBaselines[projectId] = baseline; } - - if (!update.ModuleReaders.IsEmpty) - { - _lazyBaselineModuleReaders ??= new List(); - _lazyBaselineModuleReaders.AddRange(update.ModuleReaders); - } } LastCommittedSolution.CommitSolution(update.Solution); @@ -249,11 +245,7 @@ from region in moduleRegions.Regions /// Get for given project. /// /// True unless the project outputs can't be read. - public bool TryGetOrCreateEmitBaseline( - Project project, - ArrayBuilder readers, - out ImmutableArray diagnostics, - [NotNullWhen(true)] out EmitBaseline? baseline) + public bool TryGetOrCreateEmitBaseline(Project project, out ImmutableArray diagnostics, [NotNullWhen(true)] out EmitBaseline? baseline) { lock (_projectEmitBaselinesGuard) { @@ -282,10 +274,11 @@ public bool TryGetOrCreateEmitBaseline( } _projectEmitBaselines[project.Id] = newBaseline; + + _initialBaselineModuleReaders.Add(metadataReaderProvider); + _initialBaselineModuleReaders.Add(debugInfoReaderProvider); } - readers.Add(metadataReaderProvider); - readers.Add(debugInfoReaderProvider); baseline = newBaseline; return true; } diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs index 88d9b32080603..622b89a776cfd 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueDocumentAnalysesCache.cs @@ -37,7 +37,7 @@ public async ValueTask> GetActiveStatementsAsync var results = await GetDocumentAnalysisAsync(baseDocument.Project, document, activeStatementSpans, cancellationToken).ConfigureAwait(false); return results.ActiveStatements; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -60,7 +60,7 @@ public async ValueTask> GetDocumentAnaly return allResults.ToImmutableArray(); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -85,7 +85,7 @@ public async ValueTask GetDocumentAnalysisAsync(Project return await lazyResults.GetValueAsync(cancellationToken).ConfigureAwait(false); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -127,7 +127,7 @@ private AsyncLazy GetDocumentAnalysisNoLock(Project bas return await analyzer.AnalyzeDocumentAsync(baseProject, documentBaseActiveStatements, document, activeStatementSpans, cancellationToken).ConfigureAwait(false); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs index c47bdfde17a67..6b6de216976cd 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueWorkspaceService.cs @@ -241,7 +241,7 @@ public async ValueTask> GetDocumentDiagnosticsAsync(D var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); return analysis.RudeEditErrors.SelectAsArray((e, t) => e.ToDiagnostic(t), tree); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return ImmutableArray.Empty; } @@ -314,11 +314,7 @@ public void DiscardSolutionUpdate() var editSession = _editSession; Contract.ThrowIfNull(editSession); - var pendingUpdate = editSession.RetrievePendingUpdate(); - foreach (var moduleReader in pendingUpdate.ModuleReaders) - { - moduleReader.Dispose(); - } + _ = editSession.RetrievePendingUpdate(); } public async ValueTask>> GetBaseActiveStatementSpansAsync(Solution solution, ImmutableArray documentIds, CancellationToken cancellationToken) @@ -451,7 +447,7 @@ public void DiscardSolutionUpdate() return currentActiveStatements[baseActiveStatement.PrimaryDocumentOrdinal].Span; } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return null; } @@ -491,7 +487,7 @@ public void DiscardSolutionUpdate() // If the document is out-of-sync the exception regions can't be determined. return baseExceptionRegions.Spans.IsDefault ? (bool?)null : baseExceptionRegions.IsActiveStatementCovered; } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return null; } diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index a883e2888ab31..ae0848c51ac4c 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -112,7 +112,7 @@ private async Task GetBaseActiveStatementsAsync(Cancellatio // Last committed solution reflects the state of the source that is in sync with the binaries that are loaded in the debuggee. return CreateActiveStatementsMap(await DebuggingSession.DebuggerService.GetActiveStatementsAsync(cancellationToken).ConfigureAwait(false)); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return new ActiveStatementsMap( SpecializedCollections.EmptyReadOnlyDictionary>(), @@ -284,7 +284,7 @@ internal async Task> GetBaseActi return result; } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return ImmutableArray.Empty; } @@ -543,7 +543,7 @@ from documentId in solution.GetDocumentIdsWithFilePath(sourceFilePath) return false; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -637,7 +637,7 @@ internal static ProjectChanges GetProjectChanges( addedSymbols, activeStatementsInChangedDocuments.ToImmutable()); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -755,10 +755,9 @@ public async Task EmitSolutionUpdateAsync(Solution solution, Sol using var _1 = ArrayBuilder.GetInstance(out var deltas); using var _2 = ArrayBuilder<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)>)>.GetInstance(out var nonRemappableRegions); using var _3 = ArrayBuilder<(ProjectId, EmitBaseline)>.GetInstance(out var emitBaselines); - using var _4 = ArrayBuilder.GetInstance(out var readers); - using var _5 = ArrayBuilder<(ProjectId, ImmutableArray)>.GetInstance(out var diagnostics); - using var _6 = ArrayBuilder.GetInstance(out var changedOrAddedDocuments); - using var _7 = ArrayBuilder<(DocumentId, ImmutableArray)>.GetInstance(out var documentsWithRudeEdits); + using var _4 = ArrayBuilder<(ProjectId, ImmutableArray)>.GetInstance(out var diagnostics); + using var _5 = ArrayBuilder.GetInstance(out var changedOrAddedDocuments); + using var _6 = ArrayBuilder<(DocumentId, ImmutableArray)>.GetInstance(out var documentsWithRudeEdits); var oldSolution = DebuggingSession.LastCommittedSolution; @@ -855,7 +854,7 @@ public async Task EmitSolutionUpdateAsync(Solution solution, Sol continue; } - if (!DebuggingSession.TryGetOrCreateEmitBaseline(newProject, readers, out var createBaselineDiagnostics, out var baseline)) + if (!DebuggingSession.TryGetOrCreateEmitBaseline(newProject, out var createBaselineDiagnostics, out var baseline)) { Debug.Assert(!createBaselineDiagnostics.IsEmpty); @@ -881,13 +880,13 @@ public async Task EmitSolutionUpdateAsync(Solution solution, Sol // since we already checked that no changed document is out-of-sync above. var oldActiveExceptionRegions = await GetBaseActiveExceptionRegionsAsync(solution, cancellationToken).ConfigureAwait(false); - var lineEdits = await projectChanges.LineChanges.SelectAsArrayAsync(async lineChange => + var lineEdits = await projectChanges.LineChanges.SelectAsArrayAsync(async (lineChange, cancellationToken) => { var document = await newProject.GetDocumentAsync(lineChange.DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); Contract.ThrowIfNull(document); Contract.ThrowIfNull(document.FilePath); return new SequencePointUpdates(document.FilePath, lineChange.Changes); - }).ConfigureAwait(false); + }, cancellationToken).ConfigureAwait(false); using var pdbStream = SerializableBytes.CreateWritableStream(); using var metadataStream = SerializableBytes.CreateWritableStream(); @@ -962,11 +961,6 @@ public async Task EmitSolutionUpdateAsync(Solution solution, Sol if (isBlocked) { - foreach (var reader in readers) - { - reader.Dispose(); - } - return SolutionUpdate.Blocked(diagnostics.ToImmutable(), documentsWithRudeEdits.ToImmutable()); } @@ -975,12 +969,12 @@ public async Task EmitSolutionUpdateAsync(Solution solution, Sol (deltas.Count > 0) ? ManagedModuleUpdateStatus.Ready : ManagedModuleUpdateStatus.None, deltas.ToImmutable()), nonRemappableRegions.ToImmutable(), - readers.ToImmutable(), + emitBaselines.ToImmutable(), diagnostics.ToImmutable(), documentsWithRudeEdits.ToImmutable()); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -1131,8 +1125,7 @@ internal void StorePendingUpdate(Solution solution, SolutionUpdate update) solution, update.EmitBaselines, update.ModuleUpdates.Updates, - update.NonRemappableRegions, - update.ModuleReaders)); + update.NonRemappableRegions)); // commit/discard was not called: Contract.ThrowIfFalse(previousPendingUpdate == null); diff --git a/src/Features/Core/Portable/EditAndContinue/PendingSolutionUpdate.cs b/src/Features/Core/Portable/EditAndContinue/PendingSolutionUpdate.cs index a356cec4818b9..b362c933c56e7 100644 --- a/src/Features/Core/Portable/EditAndContinue/PendingSolutionUpdate.cs +++ b/src/Features/Core/Portable/EditAndContinue/PendingSolutionUpdate.cs @@ -15,20 +15,17 @@ internal sealed class PendingSolutionUpdate public readonly ImmutableArray<(ProjectId ProjectId, EmitBaseline Baseline)> EmitBaselines; public readonly ImmutableArray Deltas; public readonly ImmutableArray<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)> Regions)> NonRemappableRegions; - public readonly ImmutableArray ModuleReaders; public PendingSolutionUpdate( Solution solution, ImmutableArray<(ProjectId ProjectId, EmitBaseline Baseline)> emitBaselines, ImmutableArray deltas, - ImmutableArray<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)>)> nonRemappableRegions, - ImmutableArray moduleReaders) + ImmutableArray<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)>)> nonRemappableRegions) { Solution = solution; EmitBaselines = emitBaselines; Deltas = deltas; NonRemappableRegions = nonRemappableRegions; - ModuleReaders = moduleReaders; } } } diff --git a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteEditAndContinueServiceProxy.cs b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteEditAndContinueServiceProxy.cs index 94c17aa86be98..0262f4a6935f9 100644 --- a/src/Features/Core/Portable/EditAndContinue/Remote/RemoteEditAndContinueServiceProxy.cs +++ b/src/Features/Core/Portable/EditAndContinue/Remote/RemoteEditAndContinueServiceProxy.cs @@ -65,7 +65,7 @@ public async ValueTask> GetSpansAsync(CancellationToken { return await _documentProvider(cancellationToken).ConfigureAwait(false); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return ImmutableArray.Empty; } @@ -88,7 +88,7 @@ public async ValueTask> GetSpansAsync(DocumentId docume { return await _solutionProvider(documentId, cancellationToken).ConfigureAwait(false); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return ImmutableArray.Empty; } @@ -110,7 +110,7 @@ public async ValueTask> GetActiv { return await _debuggerService.GetActiveStatementsAsync(cancellationToken).ConfigureAwait(false); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return ImmutableArray.Empty; } @@ -122,7 +122,7 @@ public async ValueTask GetAvailabilityAsync( { return await _debuggerService.GetAvailabilityAsync(mvid, cancellationToken).ConfigureAwait(false); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return new ManagedEditAndContinueAvailability(ManagedEditAndContinueAvailabilityStatus.InternalError, e.Message); } @@ -134,7 +134,7 @@ public async ValueTask PrepareModuleForUpdateAsync(Guid mvid, CancellationToken { await _debuggerService.PrepareModuleForUpdateAsync(mvid, cancellationToken).ConfigureAwait(false); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { // nop } diff --git a/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs b/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs index 1dee7155e3853..36f2d68d06681 100644 --- a/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs +++ b/src/Features/Core/Portable/EditAndContinue/SolutionUpdate.cs @@ -13,7 +13,6 @@ internal readonly struct SolutionUpdate { public readonly ManagedModuleUpdates ModuleUpdates; public readonly ImmutableArray<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)>)> NonRemappableRegions; - public readonly ImmutableArray ModuleReaders; public readonly ImmutableArray<(ProjectId ProjectId, EmitBaseline Baseline)> EmitBaselines; public readonly ImmutableArray<(ProjectId ProjectId, ImmutableArray Diagnostic)> Diagnostics; public readonly ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> DocumentsWithRudeEdits; @@ -21,7 +20,6 @@ internal readonly struct SolutionUpdate public SolutionUpdate( ManagedModuleUpdates moduleUpdates, ImmutableArray<(Guid ModuleId, ImmutableArray<(ManagedModuleMethodId Method, NonRemappableRegion Region)>)> nonRemappableRegions, - ImmutableArray moduleReaders, ImmutableArray<(ProjectId ProjectId, EmitBaseline Baseline)> emitBaselines, ImmutableArray<(ProjectId ProjectId, ImmutableArray Diagnostics)> diagnostics, ImmutableArray<(DocumentId DocumentId, ImmutableArray Diagnostics)> documentsWithRudeEdits) @@ -29,7 +27,6 @@ public SolutionUpdate( ModuleUpdates = moduleUpdates; NonRemappableRegions = nonRemappableRegions; EmitBaselines = emitBaselines; - ModuleReaders = moduleReaders; Diagnostics = diagnostics; DocumentsWithRudeEdits = documentsWithRudeEdits; } @@ -40,7 +37,6 @@ public static SolutionUpdate Blocked( => new( new(ManagedModuleUpdateStatus.Blocked, ImmutableArray.Empty), ImmutableArray<(Guid, ImmutableArray<(ManagedModuleMethodId, NonRemappableRegion)>)>.Empty, - ImmutableArray.Empty, ImmutableArray<(ProjectId, EmitBaseline)>.Empty, diagnostics, documentsWithRudeEdits); diff --git a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigateToSearchService.cs b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigateToSearchService.cs index 08759c29fdb2a..9fe6adb1dba81 100644 --- a/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigateToSearchService.cs +++ b/src/Features/Core/Portable/ExternalAccess/VSTypeScript/VSTypeScriptNavigateToSearchService.cs @@ -37,7 +37,8 @@ public VSTypeScriptNavigateToSearchService( public async Task SearchDocumentAsync( Document document, string searchPattern, IImmutableSet kinds, - Func onResultFound, CancellationToken cancellationToken) + Func onResultFound, + bool isFullyLoaded, CancellationToken cancellationToken) { if (_searchService == null) return; @@ -49,7 +50,8 @@ public async Task SearchDocumentAsync( public async Task SearchProjectAsync( Project project, ImmutableArray priorityDocuments, string searchPattern, - IImmutableSet kinds, Func onResultFound, CancellationToken cancellationToken) + IImmutableSet kinds, Func onResultFound, + bool isFullyLoaded, CancellationToken cancellationToken) { if (_searchService == null) return; @@ -126,6 +128,8 @@ public WrappedNavigableItem(IVSTypeScriptNavigableItem navigableItem) public TextSpan SourceSpan => _navigableItem.SourceSpan; + public bool IsStale => false; + public ImmutableArray ChildItems => _navigableItem.ChildItems.IsDefault ? default diff --git a/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs b/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs index edf29e693ec83..44fef86da77f6 100644 --- a/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs +++ b/src/Features/Core/Portable/FindUsages/IRemoteFindUsagesService.cs @@ -244,7 +244,7 @@ public static SerializableDefinitionItem Dehydrate(int id, DefinitionItem item) public async ValueTask RehydrateAsync(Solution solution, CancellationToken cancellationToken) { - var sourceSpans = await SourceSpans.SelectAsArrayAsync(ss => ss.RehydrateAsync(solution, cancellationToken)).ConfigureAwait(false); + var sourceSpans = await SourceSpans.SelectAsArrayAsync((ss, cancellationToken) => ss.RehydrateAsync(solution, cancellationToken), cancellationToken).ConfigureAwait(false); return new DefinitionItem.DefaultDefinitionItem( Tags, diff --git a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs index 8484f82d7b7e2..559e93a4657dc 100644 --- a/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/GenerateConstructorFromMembers/AbstractGenerateConstructorFromMembersCodeRefactoringProvider.cs @@ -178,7 +178,7 @@ private async Task ComputeRefactoringsAsync( var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); // Only supported on classes/structs. - var containingType = semanticModel.GetDeclaredSymbol(typeDeclaration) as INamedTypeSymbol; + var containingType = semanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken: cancellationToken) as INamedTypeSymbol; if (containingType?.TypeKind != TypeKind.Class && containingType?.TypeKind != TypeKind.Struct) { return null; diff --git a/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs b/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs index 62afdb1fc5aff..4ae0e8529db09 100644 --- a/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/AbstractInlineParameterNameHintsService.cs @@ -85,7 +85,7 @@ void AddHintsIfAppropriate() result.Add(new InlineHint( new TextSpan(position, 0), ImmutableArray.Create(new TaggedText(TextTags.Text, parameter.Name + ": ")), - InlineHintHelpers.GetDescriptionFunction(position, parameter.GetSymbolKey()))); + InlineHintHelpers.GetDescriptionFunction(position, parameter.GetSymbolKey(cancellationToken: cancellationToken)))); } } } diff --git a/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs b/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs index afc8e779cf383..b49ce72cfc707 100644 --- a/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs +++ b/src/Features/Core/Portable/InlineHints/AbstractInlineTypeHintsService.cs @@ -79,7 +79,7 @@ public async Task> GetInlineHintsAsync( result.Add(new InlineHint( span, finalParts.ToTaggedText(), - InlineHintHelpers.GetDescriptionFunction(span.Start, type.GetSymbolKey()))); + InlineHintHelpers.GetDescriptionFunction(span.Start, type.GetSymbolKey(cancellationToken: cancellationToken)))); } return result.ToImmutable(); diff --git a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs index fdf72c80dd21d..01328f2178506 100644 --- a/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs +++ b/src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs @@ -134,7 +134,7 @@ public async Task GetGeneratedFileAsync(Project project, I useDecompiler = false; } } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { useDecompiler = false; } diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs index dbcc69b31ab86..be4b472ed866d 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.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; @@ -12,8 +10,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.Navigation; using Microsoft.CodeAnalysis.PatternMatching; +using Microsoft.CodeAnalysis.PersistentStorage; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -38,17 +36,17 @@ internal abstract partial class AbstractNavigateToSearchService // Map our value to 'Fuzzy' as that's the lower value the platform supports. (PatternMatchKind.LowercaseSubstring, NavigateToMatchKind.Fuzzy)); - public static Task SearchProjectInCurrentProcessAsync( + public static Task SearchFullyLoadedProjectInCurrentProcessAsync( Project project, ImmutableArray priorityDocuments, string searchPattern, - IImmutableSet kinds, Func onResultFound, CancellationToken cancellationToken) + IImmutableSet kinds, Func onResultFound, CancellationToken cancellationToken) { return FindSearchResultsAsync( project, priorityDocuments, searchDocument: null, pattern: searchPattern, kinds, onResultFound, cancellationToken); } - public static Task SearchDocumentInCurrentProcessAsync( + public static Task SearchFullyLoadedDocumentInCurrentProcessAsync( Document document, string searchPattern, IImmutableSet kinds, - Func onResultFound, CancellationToken cancellationToken) + Func onResultFound, CancellationToken cancellationToken) { return FindSearchResultsAsync( document.Project, priorityDocuments: ImmutableArray.Empty, @@ -57,77 +55,152 @@ public static Task SearchDocumentInCurrentProcessAsync( private static async Task FindSearchResultsAsync( Project project, ImmutableArray priorityDocuments, - Document searchDocument, string pattern, IImmutableSet kinds, - Func onResultFound, CancellationToken cancellationToken) + Document? searchDocument, string pattern, IImmutableSet kinds, + Func onResultFound, CancellationToken cancellationToken) { // If the user created a dotted pattern then we'll grab the last part of the name var (patternName, patternContainerOpt) = PatternMatcher.GetNameAndContainer(pattern); - var nameMatcher = PatternMatcher.CreatePatternMatcher(patternName, includeMatchedSpans: true, allowFuzzyMatching: true); - var containerMatcherOpt = patternContainerOpt != null - ? PatternMatcher.CreateDotSeparatedContainerMatcher(patternContainerOpt) - : null; + var declaredSymbolInfoKindsSet = new DeclaredSymbolInfoKindSet(kinds); - using (nameMatcher) - using (containerMatcherOpt) - { - using var _1 = ArrayBuilder.GetInstance(out var nameMatches); - using var _2 = ArrayBuilder.GetInstance(out var containerMatches); + // Prioritize the active documents if we have any. + var highPriDocs = priorityDocuments.Where(d => project.ContainsDocument(d.Id)).ToSet(); + await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, highPriDocs, cancellationToken).ConfigureAwait(false); + + // Then process non-priority documents. + var lowPriDocs = project.Documents.Where(d => !highPriDocs.Contains(d)).ToSet(); + await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, lowPriDocs, cancellationToken).ConfigureAwait(false); + + // if the caller is only searching a single doc, and we already covered it above, don't bother computing + // source-generator docs. + if (searchDocument != null && (highPriDocs.Contains(searchDocument) || lowPriDocs.Contains(searchDocument))) + return; + + // Finally, generate and process and source-generated docs. this may take some time, so we always want to + // do this after the other documents. + var generatedDocs = await project.GetSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false); + await ProcessDocumentsAsync(searchDocument, patternName, patternContainerOpt, declaredSymbolInfoKindsSet, onResultFound, generatedDocs.ToSet(), cancellationToken).ConfigureAwait(false); + } - var declaredSymbolInfoKindsSet = new DeclaredSymbolInfoKindSet(kinds); + private static async Task ProcessDocumentsAsync( + Document? searchDocument, string patternName, string? patternContainer, DeclaredSymbolInfoKindSet kinds, + Func onResultFound, ISet documents, CancellationToken cancellationToken) + { + using var _ = ArrayBuilder.GetInstance(out var tasks); - await ComputeSearchResultsAsync( - project, priorityDocuments, searchDocument, nameMatcher, containerMatcherOpt, - declaredSymbolInfoKindsSet, nameMatches, containerMatches, onResultFound, cancellationToken).ConfigureAwait(false); + foreach (var document in documents) + { + if (searchDocument != null && searchDocument != document) + continue; + + cancellationToken.ThrowIfCancellationRequested(); + tasks.Add(Task.Run(() => + ProcessDocumentAsync(document, patternName, patternContainer, kinds, onResultFound, cancellationToken), cancellationToken)); } + + await Task.WhenAll(tasks).ConfigureAwait(false); } - private static async Task ComputeSearchResultsAsync( - Project project, ImmutableArray priorityDocuments, Document searchDocument, - PatternMatcher nameMatcher, PatternMatcher containerMatcherOpt, - DeclaredSymbolInfoKindSet kinds, - ArrayBuilder nameMatches, ArrayBuilder containerMatches, - Func onResultFound, CancellationToken cancellationToken) + private static async Task ProcessDocumentAsync( + Document document, string patternName, string? patternContainer, DeclaredSymbolInfoKindSet kinds, + Func onResultFound, CancellationToken cancellationToken) { - // Prioritize the active documents if we have any. - var highPriDocs = priorityDocuments.WhereAsArray(d => project.ContainsDocument(d.Id)); + var index = await SyntaxTreeIndex.GetRequiredIndexAsync(document, cancellationToken).ConfigureAwait(false); - var highPriDocsSet = highPriDocs.ToSet(); - var lowPriDocs = (await project.GetAllRegularAndSourceGeneratedDocumentsAsync(cancellationToken).ConfigureAwait(false)) - .Where(d => !highPriDocsSet.Contains(d)); + await ProcessIndexAsync( + document.Id, document, patternName, patternContainer, kinds, onResultFound, index, cancellationToken).ConfigureAwait(false); + } - var orderedDocs = highPriDocs.AddRange(lowPriDocs); + public static async Task SearchCachedDocumentsInCurrentProcessAsync( + Workspace workspace, + ImmutableArray documentKeys, + ImmutableArray priorityDocumentKeys, + string searchPattern, + IImmutableSet kinds, + Func onItemFound, + CancellationToken cancellationToken) + { + var stringTable = new StringTable(); - Debug.Assert(priorityDocuments.All(d => project.ContainsDocument(d.Id)), "Priority docs included doc not from project."); - Debug.Assert(orderedDocs.Distinct().Length == orderedDocs.Length, "Ordered list contained a duplicate!"); - Debug.Assert(project.Documents.All(d => orderedDocs.Contains(d)), "At least one document from the project was missing from the ordered list!"); + var highPriDocsSet = priorityDocumentKeys.ToSet(); + var lowPriDocs = documentKeys.WhereAsArray(d => !highPriDocsSet.Contains(d)); - foreach (var document in orderedDocs) - { - if (searchDocument != null && document != searchDocument) - continue; + // If the user created a dotted pattern then we'll grab the last part of the name + var (patternName, patternContainer) = PatternMatcher.GetNameAndContainer(searchPattern); + var declaredSymbolInfoKindsSet = new DeclaredSymbolInfoKindSet(kinds); - cancellationToken.ThrowIfCancellationRequested(); - var declarationInfo = await document.GetSyntaxTreeIndexAsync(cancellationToken).ConfigureAwait(false); + await SearchCachedDocumentsInCurrentProcessAsync( + workspace, priorityDocumentKeys, patternName, patternContainer, declaredSymbolInfoKindsSet, onItemFound, stringTable, cancellationToken).ConfigureAwait(false); - foreach (var declaredSymbolInfo in declarationInfo.DeclaredSymbolInfos) + await SearchCachedDocumentsInCurrentProcessAsync( + workspace, lowPriDocs, patternName, patternContainer, declaredSymbolInfoKindsSet, onItemFound, stringTable, cancellationToken).ConfigureAwait(false); + } + + private static async Task SearchCachedDocumentsInCurrentProcessAsync( + Workspace workspace, + ImmutableArray documentKeys, + string patternName, + string patternContainer, + DeclaredSymbolInfoKindSet kinds, + Func onItemFound, + StringTable stringTable, + CancellationToken cancellationToken) + { + using var _ = ArrayBuilder.GetInstance(out var tasks); + + foreach (var documentKey in documentKeys) + { + tasks.Add(Task.Run(async () => { - await AddResultIfMatchAsync( - document, declaredSymbolInfo, - nameMatcher, containerMatcherOpt, - kinds, - nameMatches, containerMatches, - onResultFound, cancellationToken).ConfigureAwait(false); - } + var index = await SyntaxTreeIndex.LoadAsync( + workspace, documentKey, checksum: null, stringTable, cancellationToken).ConfigureAwait(false); + if (index == null) + return; + + await ProcessIndexAsync( + documentKey.Id, document: null, patternName, patternContainer, kinds, onItemFound, index, cancellationToken).ConfigureAwait(false); + }, cancellationToken)); + } + + await Task.WhenAll(tasks).ConfigureAwait(false); + } + + private static async Task ProcessIndexAsync( + DocumentId documentId, Document? document, + string patternName, string? patternContainer, + DeclaredSymbolInfoKindSet kinds, + Func onResultFound, + SyntaxTreeIndex index, + CancellationToken cancellationToken) + { + var containerMatcher = patternContainer != null + ? PatternMatcher.CreateDotSeparatedContainerMatcher(patternContainer) + : null; + + using var nameMatcher = PatternMatcher.CreatePatternMatcher(patternName, includeMatchedSpans: true, allowFuzzyMatching: true); + using var _1 = containerMatcher; + using var _2 = ArrayBuilder.GetInstance(out var nameMatches); + using var _3 = ArrayBuilder.GetInstance(out var containerMatches); + + foreach (var declaredSymbolInfo in index.DeclaredSymbolInfos) + { + await AddResultIfMatchAsync( + documentId, document, + declaredSymbolInfo, + nameMatcher, containerMatcher, + kinds, + nameMatches, containerMatches, + onResultFound, cancellationToken).ConfigureAwait(false); } } private static async Task AddResultIfMatchAsync( - Document document, DeclaredSymbolInfo declaredSymbolInfo, - PatternMatcher nameMatcher, PatternMatcher containerMatcherOpt, + DocumentId documentId, Document? document, + DeclaredSymbolInfo declaredSymbolInfo, + PatternMatcher nameMatcher, PatternMatcher? containerMatcher, DeclaredSymbolInfoKindSet kinds, ArrayBuilder nameMatches, ArrayBuilder containerMatches, - Func onResultFound, CancellationToken cancellationToken) + Func onResultFound, CancellationToken cancellationToken) { nameMatches.Clear(); containerMatches.Clear(); @@ -135,17 +208,20 @@ private static async Task AddResultIfMatchAsync( cancellationToken.ThrowIfCancellationRequested(); if (kinds.Contains(declaredSymbolInfo.Kind) && nameMatcher.AddMatches(declaredSymbolInfo.Name, nameMatches) && - containerMatcherOpt?.AddMatches(declaredSymbolInfo.FullyQualifiedContainerName, containerMatches) != false) + containerMatcher?.AddMatches(declaredSymbolInfo.FullyQualifiedContainerName, containerMatches) != false) { var result = await ConvertResultAsync( - declaredSymbolInfo, document, nameMatches, containerMatches, cancellationToken).ConfigureAwait(false); + documentId, document, declaredSymbolInfo, nameMatches, containerMatches, cancellationToken).ConfigureAwait(false); await onResultFound(result).ConfigureAwait(false); } } - private static async Task ConvertResultAsync( - DeclaredSymbolInfo declaredSymbolInfo, Document document, - ArrayBuilder nameMatches, ArrayBuilder containerMatches, + private static async Task ConvertResultAsync( + DocumentId documentId, + Document? document, + DeclaredSymbolInfo declaredSymbolInfo, + ArrayBuilder nameMatches, + ArrayBuilder containerMatches, CancellationToken cancellationToken) { var matchKind = GetNavigateToMatchKind(nameMatches); @@ -154,38 +230,52 @@ private static async Task ConvertResultAsync( // case sensitive. var isCaseSensitive = nameMatches.All(m => m.IsCaseSensitive) && containerMatches.All(m => m.IsCaseSensitive); var kind = GetItemKind(declaredSymbolInfo); - var navigableItem = NavigableItemFactory.GetItemFromDeclaredSymbolInfo(declaredSymbolInfo, document); using var _ = ArrayBuilder.GetInstance(out var matchedSpans); foreach (var match in nameMatches) matchedSpans.AddRange(match.MatchedSpans); - // See if we have a match in a linked file. If so, see if we have the same match in other projects that - // this file is linked in. If so, include the full set of projects the match is in so we can display that - // well in the UI. - var additionalMatchingProjects = await GetAdditionalProjectsWithMatchAsync( - document, declaredSymbolInfo, cancellationToken).ConfigureAwait(false); - return new SearchResult( - document, declaredSymbolInfo, kind, matchKind, isCaseSensitive, navigableItem, - matchedSpans.ToImmutable(), additionalMatchingProjects); + // See if we have a match in a linked file. If so, see if we have the same match in + // other projects that this file is linked in. If so, include the full set of projects + // the match is in so we can display that well in the UI. + // + // We can only do this in the case where the solution is loaded and thus we can examine + // the relationship between this document and the other documents linked to it. In the + // case where the solution isn't fully loaded and we're just reading in cached data, we + // don't know what other files we're linked to and can't merge results in this fashion. + var additionalMatchingProjects = document == null + ? ImmutableArray.Empty + : await GetAdditionalProjectsWithMatchAsync(document, declaredSymbolInfo, cancellationToken).ConfigureAwait(false); + + // If we were not given a Document instance, then we're finding matches in cached data + // and thus could be 'stale'. + return new RoslynNavigateToItem( + isStale: document == null, + documentId, + additionalMatchingProjects, + declaredSymbolInfo, + kind, + matchKind, + isCaseSensitive, + matchedSpans.ToImmutable()); } - private static async Task> GetAdditionalProjectsWithMatchAsync( + private static async Task> GetAdditionalProjectsWithMatchAsync( Document document, DeclaredSymbolInfo declaredSymbolInfo, CancellationToken cancellationToken) { - using var _ = ArrayBuilder.GetInstance(out var result); + using var _ = ArrayBuilder.GetInstance(out var result); var solution = document.Project.Solution; var linkedDocumentIds = document.GetLinkedDocumentIds(); foreach (var linkedDocumentId in linkedDocumentIds) { var linkedDocument = solution.GetRequiredDocument(linkedDocumentId); - var index = await linkedDocument.GetSyntaxTreeIndexAsync(cancellationToken).ConfigureAwait(false); + var index = await SyntaxTreeIndex.GetRequiredIndexAsync(linkedDocument, cancellationToken).ConfigureAwait(false); // See if the index for the other file also contains this same info. If so, merge the results so the // user only sees them as a single hit in the UI. if (index.DeclaredSymbolInfoSet.Contains(declaredSymbolInfo)) - result.Add(linkedDocument.Project); + result.Add(linkedDocument.Project.Id); } result.RemoveDuplicates(); diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.SearchResult.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.SearchResult.cs deleted file mode 100644 index f220fbba5208e..0000000000000 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.SearchResult.cs +++ /dev/null @@ -1,144 +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.IO; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.Navigation; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.NavigateTo -{ - internal abstract partial class AbstractNavigateToSearchService - { - private class SearchResult : INavigateToSearchResult - { - private static readonly char[] s_dotArray = { '.' }; - - public string AdditionalInformation { get; } - public string Kind { get; } - public NavigateToMatchKind MatchKind { get; } - public bool IsCaseSensitive { get; } - public string Name { get; } - public ImmutableArray NameMatchSpans { get; } - public string SecondarySort { get; } - public string? Summary => null; - - public INavigableItem NavigableItem { get; } - - public SearchResult( - Document document, - DeclaredSymbolInfo declaredSymbolInfo, - string kind, - NavigateToMatchKind matchKind, - bool isCaseSensitive, - INavigableItem navigableItem, - ImmutableArray nameMatchSpans, - ImmutableArray additionalMatchingProjects) - { - Name = declaredSymbolInfo.Name; - Kind = kind; - MatchKind = matchKind; - IsCaseSensitive = isCaseSensitive; - NavigableItem = navigableItem; - NameMatchSpans = nameMatchSpans; - AdditionalInformation = ComputeAdditionalInfo(document, declaredSymbolInfo, additionalMatchingProjects); - SecondarySort = ConstructSecondarySortString(document, declaredSymbolInfo); - } - - private static string ComputeAdditionalInfo(Document document, DeclaredSymbolInfo info, ImmutableArray additionalMatchingProjects) - { - var projectName = ComputeProjectName(document, additionalMatchingProjects); - - // For partial types, state what file they're in so the user can disambiguate the results. - if (info.IsPartial) - { - return IsNonNestedNamedType(info) - ? string.Format(FeaturesResources._0_dash_1, document.Name, projectName) - : string.Format(FeaturesResources.in_0_1_2, info.ContainerDisplayName, document.Name, projectName); - } - else - { - return IsNonNestedNamedType(info) - ? string.Format(FeaturesResources.project_0, projectName) - : string.Format(FeaturesResources.in_0_project_1, info.ContainerDisplayName, projectName); - } - } - - private static string ComputeProjectName(Document document, ImmutableArray additionalMatchingProjects) - { - // If there aren't any additional matches in other projects, we don't need to merge anything. - if (additionalMatchingProjects.Length > 0) - { - // First get the simple project name and flavor for the actual project we got a hit in. If we can't - // figure this out, we can't create a merged name. - var firstProject = document.Project; - var (firstProjectName, firstProjectFlavor) = firstProject.State.NameAndFlavor; - if (firstProjectName != null) - { - - using var _ = ArrayBuilder.GetInstance(out var flavors); - flavors.Add(firstProjectFlavor!); - - // Now, do the same for the other projects where we had a match. As above, if we can't figure out the - // simple name/flavor, or if the simple project name doesn't match the simple project name we started - // with then we can't merge these. - foreach (var additionalProject in additionalMatchingProjects) - { - var (projectName, projectFlavor) = additionalProject.State.NameAndFlavor; - if (projectName == firstProjectName) - flavors.Add(projectFlavor!); - } - - flavors.RemoveDuplicates(); - flavors.Sort(); - - return $"{firstProjectName} ({string.Join(", ", flavors)})"; - } - } - - // Couldn't compute a merged project name (or only had one project). Just return the name of hte project itself. - return document.Project.Name; - } - - private static bool IsNonNestedNamedType(DeclaredSymbolInfo info) - => !info.IsNestedType && IsNamedType(info); - - private static bool IsNamedType(DeclaredSymbolInfo info) - { - switch (info.Kind) - { - case DeclaredSymbolInfoKind.Class: - case DeclaredSymbolInfoKind.Record: - case DeclaredSymbolInfoKind.Enum: - case DeclaredSymbolInfoKind.Interface: - case DeclaredSymbolInfoKind.Module: - case DeclaredSymbolInfoKind.Struct: - return true; - default: - return false; - } - } - - private static string ConstructSecondarySortString(Document document, DeclaredSymbolInfo declaredSymbolInfo) - { - using var _ = ArrayBuilder.GetInstance(out var parts); - - parts.Add(declaredSymbolInfo.ParameterCount.ToString("X4")); - parts.Add(declaredSymbolInfo.TypeParameterCount.ToString("X4")); - parts.Add(declaredSymbolInfo.Name); - - // For partial types, we break up the file name into pieces. i.e. If we have - // Outer.cs and Outer.Inner.cs then we add "Outer" and "Outer Inner" to - // the secondary sort string. That way "Outer.cs" will be weighted above - // "Outer.Inner.cs" - var fileName = Path.GetFileNameWithoutExtension(document.FilePath ?? ""); - parts.AddRange(fileName.Split(s_dotArray)); - - return string.Join(" ", parts); - } - } - } -} diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs index 61877c6e44d7b..66c0ba360f60b 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.cs @@ -3,12 +3,12 @@ // 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.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.PersistentStorage; using Microsoft.CodeAnalysis.Remote; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.NavigateTo { @@ -31,47 +31,118 @@ internal abstract partial class AbstractNavigateToSearchService : INavigateToSea public bool CanFilter => true; - public async Task SearchDocumentAsync( - Document document, string searchPattern, IImmutableSet kinds, - Func onResultFound, CancellationToken cancellationToken) + private static Func GetOnItemFoundCallback( + Solution solution, Func onResultFound, CancellationToken cancellationToken) { + return async item => + { + var result = await item.TryCreateSearchResultAsync(solution, cancellationToken).ConfigureAwait(false); + if (result != null) + await onResultFound(result).ConfigureAwait(false); + }; + } + + public Task SearchDocumentAsync(Document document, string searchPattern, IImmutableSet kinds, Func onResultFound, bool isFullyLoaded, CancellationToken cancellationToken) + { + return isFullyLoaded + ? SearchFullyLoadedDocumentAsync(document, searchPattern, kinds, onResultFound, cancellationToken) + : SearchCachedDocumentsAsync(ImmutableArray.Create(document), ImmutableArray.Empty, searchPattern, kinds, onResultFound, cancellationToken); + } + + private static async Task SearchFullyLoadedDocumentAsync( + Document document, + string searchPattern, + IImmutableSet kinds, + Func onResultFound, + CancellationToken cancellationToken) + { + var solution = document.Project.Solution; + var onItemFound = GetOnItemFoundCallback(solution, onResultFound, cancellationToken); var client = await RemoteHostClient.TryGetClientAsync(document.Project, cancellationToken).ConfigureAwait(false); if (client != null) { - var solution = document.Project.Solution; - var callback = new NavigateToSearchServiceCallback(solution, onResultFound, cancellationToken); + var callback = new NavigateToSearchServiceCallback(onItemFound); await client.TryInvokeAsync( solution, - (service, solutionInfo, callbackId, cancellationToken) => service.SearchDocumentAsync(solutionInfo, document.Id, searchPattern, kinds.ToImmutableArray(), callbackId, cancellationToken), + (service, solutionInfo, callbackId, cancellationToken) => + service.SearchFullyLoadedDocumentAsync(solutionInfo, document.Id, searchPattern, kinds.ToImmutableArray(), callbackId, cancellationToken), callback, cancellationToken).ConfigureAwait(false); return; } - await SearchDocumentInCurrentProcessAsync( - document, searchPattern, kinds, onResultFound, cancellationToken).ConfigureAwait(false); + await SearchFullyLoadedDocumentInCurrentProcessAsync( + document, searchPattern, kinds, onItemFound, cancellationToken).ConfigureAwait(false); } - public async Task SearchProjectAsync( - Project project, ImmutableArray priorityDocuments, string searchPattern, - IImmutableSet kinds, Func onResultFound, CancellationToken cancellationToken) + public Task SearchProjectAsync(Project project, ImmutableArray priorityDocuments, string searchPattern, IImmutableSet kinds, Func onResultFound, bool isFullyLoaded, CancellationToken cancellationToken) { + return isFullyLoaded + ? SearchFullyLoadedProjectAsync(project, priorityDocuments, searchPattern, kinds, onResultFound, cancellationToken) + : SearchCachedDocumentsAsync(project.Documents.ToImmutableArray(), priorityDocuments, searchPattern, kinds, onResultFound, cancellationToken); + } + + private static async Task SearchFullyLoadedProjectAsync( + Project project, + ImmutableArray priorityDocuments, + string searchPattern, + IImmutableSet kinds, + Func onResultFound, + CancellationToken cancellationToken) + { + var solution = project.Solution; var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false); + var onItemFound = GetOnItemFoundCallback(solution, onResultFound, cancellationToken); + if (client != null) { - var solution = project.Solution; var priorityDocumentIds = priorityDocuments.SelectAsArray(d => d.Id); - var callback = new NavigateToSearchServiceCallback(solution, onResultFound, cancellationToken); + var callback = new NavigateToSearchServiceCallback(onItemFound); await client.TryInvokeAsync( solution, - (service, solutionInfo, callbackId, cancellationToken) => service.SearchProjectAsync(solutionInfo, project.Id, priorityDocumentIds, searchPattern, kinds.ToImmutableArray(), callbackId, cancellationToken), + (service, solutionInfo, callbackId, cancellationToken) => + service.SearchFullyLoadedProjectAsync(solutionInfo, project.Id, priorityDocumentIds, searchPattern, kinds.ToImmutableArray(), callbackId, cancellationToken), + callback, cancellationToken).ConfigureAwait(false); + + return; + } + + await SearchFullyLoadedProjectInCurrentProcessAsync( + project, priorityDocuments, searchPattern, kinds, onItemFound, cancellationToken).ConfigureAwait(false); + } + + private static async Task SearchCachedDocumentsAsync( + ImmutableArray documents, + ImmutableArray priorityDocuments, + string searchPattern, + IImmutableSet kinds, + Func onResultFound, + CancellationToken cancellationToken) + { + var document = documents.FirstOrDefault() ?? priorityDocuments.FirstOrDefault(); + if (document == null) + return; + + var project = document.Project; + var solution = project.Solution; + var client = await RemoteHostClient.TryGetClientAsync(project, cancellationToken).ConfigureAwait(false); + var onItemFound = GetOnItemFoundCallback(solution, onResultFound, cancellationToken); + + var documentKeys = project.Documents.Select(d => DocumentKey.ToDocumentKey(d)).ToImmutableArray(); + var priorityDocumentKeys = priorityDocuments.SelectAsArray(d => DocumentKey.ToDocumentKey(d)); + if (client != null) + { + var callback = new NavigateToSearchServiceCallback(onItemFound); + await client.TryInvokeAsync( + (service, callbackId, cancellationToken) => + service.SearchCachedDocumentsAsync(documentKeys, priorityDocumentKeys, searchPattern, kinds.ToImmutableArray(), callbackId, cancellationToken), callback, cancellationToken).ConfigureAwait(false); return; } - await SearchProjectInCurrentProcessAsync( - project, priorityDocuments, searchPattern, kinds, onResultFound, cancellationToken).ConfigureAwait(false); + await SearchCachedDocumentsInCurrentProcessAsync( + solution.Workspace, documentKeys, priorityDocumentKeys, searchPattern, kinds, onItemFound, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Features/Core/Portable/NavigateTo/INavigateToSearchService.cs b/src/Features/Core/Portable/NavigateTo/INavigateToSearchService.cs index 1a0e5f7149c56..0580e34be0d84 100644 --- a/src/Features/Core/Portable/NavigateTo/INavigateToSearchService.cs +++ b/src/Features/Core/Portable/NavigateTo/INavigateToSearchService.cs @@ -15,7 +15,13 @@ internal interface INavigateToSearchService : ILanguageService IImmutableSet KindsProvided { get; } bool CanFilter { get; } - Task SearchProjectAsync(Project project, ImmutableArray priorityDocuments, string searchPattern, IImmutableSet kinds, Func onResultFound, CancellationToken cancellationToken); - Task SearchDocumentAsync(Document document, string searchPattern, IImmutableSet kinds, Func onResultFound, CancellationToken cancellationToken); + /// + /// Searches the documents inside for symbols that matches + /// . is an optional + /// subset of the documents from that can be used to prioritize + /// work. + /// + Task SearchProjectAsync(Project project, ImmutableArray priorityDocuments, string searchPattern, IImmutableSet kinds, Func onResultFound, bool isFullyLoaded, CancellationToken cancellationToken); + Task SearchDocumentAsync(Document document, string searchPattern, IImmutableSet kinds, Func onResultFound, bool isFullyLoaded, CancellationToken cancellationToken); } } diff --git a/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs b/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs index cdcf3f92dc285..a578860b0c659 100644 --- a/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs +++ b/src/Features/Core/Portable/NavigateTo/IRemoteNavigateToSearchService.cs @@ -8,21 +8,20 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.PersistentStorage; using Microsoft.CodeAnalysis.Remote; namespace Microsoft.CodeAnalysis.NavigateTo { internal interface IRemoteNavigateToSearchService { - ValueTask SearchDocumentAsync( - PinnedSolutionInfo solutionInfo, DocumentId documentId, string searchPattern, ImmutableArray kinds, RemoteServiceCallbackId callbackId, CancellationToken cancellationToken); - - ValueTask SearchProjectAsync( - PinnedSolutionInfo solutionInfo, ProjectId projectId, ImmutableArray priorityDocumentIds, string searchPattern, ImmutableArray kinds, RemoteServiceCallbackId callbackId, CancellationToken cancellationToken); + ValueTask SearchFullyLoadedDocumentAsync(PinnedSolutionInfo solutionInfo, DocumentId documentId, string searchPattern, ImmutableArray kinds, RemoteServiceCallbackId callbackId, CancellationToken cancellationToken); + ValueTask SearchFullyLoadedProjectAsync(PinnedSolutionInfo solutionInfo, ProjectId projectId, ImmutableArray priorityDocumentIds, string searchPattern, ImmutableArray kinds, RemoteServiceCallbackId callbackId, CancellationToken cancellationToken); + ValueTask SearchCachedDocumentsAsync(ImmutableArray documentKeys, ImmutableArray priorityDocumentKeys, string searchPattern, ImmutableArray kinds, RemoteServiceCallbackId callbackId, CancellationToken cancellationToken); public interface ICallback { - ValueTask OnResultFoundAsync(RemoteServiceCallbackId callbackId, SerializableNavigateToSearchResult result); + ValueTask OnResultFoundAsync(RemoteServiceCallbackId callbackId, RoslynNavigateToItem result); } } @@ -38,27 +37,20 @@ public NavigateToSearchServiceServerCallbackDispatcher() private new NavigateToSearchServiceCallback GetCallback(RemoteServiceCallbackId callbackId) => (NavigateToSearchServiceCallback)base.GetCallback(callbackId); - public ValueTask OnResultFoundAsync(RemoteServiceCallbackId callbackId, SerializableNavigateToSearchResult result) + public ValueTask OnResultFoundAsync(RemoteServiceCallbackId callbackId, RoslynNavigateToItem result) => GetCallback(callbackId).OnResultFoundAsync(result); } internal sealed class NavigateToSearchServiceCallback { - private readonly Solution _solution; - private readonly Func _onResultFound; - private readonly CancellationToken _cancellationToken; + private readonly Func _onResultFound; - public NavigateToSearchServiceCallback( - Solution solution, - Func onResultFound, - CancellationToken cancellationToken) + public NavigateToSearchServiceCallback(Func onResultFound) { - _solution = solution; _onResultFound = onResultFound; - _cancellationToken = cancellationToken; } - public async ValueTask OnResultFoundAsync(SerializableNavigateToSearchResult result) - => await _onResultFound(await result.RehydrateAsync(_solution, _cancellationToken).ConfigureAwait(false)).ConfigureAwait(false); + public async ValueTask OnResultFoundAsync(RoslynNavigateToItem result) + => await _onResultFound(result).ConfigureAwait(false); } } diff --git a/src/Features/Core/Portable/NavigateTo/NavigateToSearcher.cs b/src/Features/Core/Portable/NavigateTo/NavigateToSearcher.cs index fa1873275ce96..9204ee4385f6f 100644 --- a/src/Features/Core/Portable/NavigateTo/NavigateToSearcher.cs +++ b/src/Features/Core/Portable/NavigateTo/NavigateToSearcher.cs @@ -72,7 +72,7 @@ internal async Task SearchAsync() using var navigateToSearch = Logger.LogBlock(FunctionId.NavigateTo_Search, KeyValueLogMessage.Create(LogType.UserAction), _cancellationToken); using var asyncToken = _asyncListener.BeginAsyncOperation(GetType() + ".Search"); await _progress.AddItemsAsync(_solution.Projects.Count()).ConfigureAwait(false); - await SearchAllProjectsAsync().ConfigureAwait(false); + await SearchAllProjectsAsync(isFullyLoaded).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -85,7 +85,7 @@ internal async Task SearchAsync() } } - private async Task SearchAllProjectsAsync() + private async Task SearchAllProjectsAsync(bool isFullyLoaded) { var seenItems = new HashSet(NavigateToSearchResultComparer.Instance); var processedProjects = new HashSet(); @@ -112,7 +112,7 @@ private async Task SearchAllProjectsAsync() // Search the active project first. That way we can deliver results that are // closer in scope to the user quicker without forcing them to do something like // NavToInCurrentDoc - await Task.Run(() => SearchAsync(activeProject, priorityDocs, seenItems), _cancellationToken).ConfigureAwait(false); + await Task.Run(() => SearchAsync(activeProject, priorityDocs, seenItems, isFullyLoaded), _cancellationToken).ConfigureAwait(false); } // Now, process all visible docs that were not from the active project. @@ -121,7 +121,7 @@ private async Task SearchAllProjectsAsync() { // make sure we only process this project if we didn't already process it above. if (processedProjects.Add(currentProject)) - tasks.Add(Task.Run(() => SearchAsync(currentProject, priorityDocs.ToImmutableArray(), seenItems), _cancellationToken)); + tasks.Add(Task.Run(() => SearchAsync(currentProject, priorityDocs.Where(d => d.Project == currentProject).ToImmutableArray(), seenItems, isFullyLoaded), _cancellationToken)); } await Task.WhenAll(tasks).ConfigureAwait(false); @@ -132,7 +132,7 @@ private async Task SearchAllProjectsAsync() { // make sure we only process this project if we didn't already process it above. if (processedProjects.Add(currentProject)) - tasks.Add(Task.Run(() => SearchAsync(currentProject, ImmutableArray.Empty, seenItems), _cancellationToken)); + tasks.Add(Task.Run(() => SearchAsync(currentProject, ImmutableArray.Empty, seenItems, isFullyLoaded), _cancellationToken)); } await Task.WhenAll(tasks).ConfigureAwait(false); @@ -141,11 +141,12 @@ private async Task SearchAllProjectsAsync() private async Task SearchAsync( Project project, ImmutableArray priorityDocuments, - HashSet seenItems) + HashSet seenItems, + bool isFullyLoaded) { try { - await SearchCoreAsync(project, priorityDocuments, seenItems).ConfigureAwait(false); + await SearchCoreAsync(project, priorityDocuments, seenItems, isFullyLoaded).ConfigureAwait(false); } finally { @@ -156,40 +157,35 @@ private async Task SearchAsync( private async Task SearchCoreAsync( Project project, ImmutableArray priorityDocuments, - HashSet seenItems) + HashSet seenItems, + bool isFullyLoaded) { if (_searchCurrentDocument && _currentDocument?.Project != project) return; - var cacheService = project.Solution.Services.CacheService; - if (cacheService != null) + var service = project.GetLanguageService(); + if (service == null) + return; + + var task = _currentDocument != null + ? service.SearchDocumentAsync(_currentDocument, _searchPattern, _kinds, OnResultFound, isFullyLoaded, _cancellationToken) + : service.SearchProjectAsync(project, priorityDocuments, _searchPattern, _kinds, OnResultFound, isFullyLoaded, _cancellationToken); + + await task.ConfigureAwait(false); + return; + + async Task OnResultFound(INavigateToSearchResult result) { - using (cacheService.EnableCaching(project.Id)) + // If we're seeing a dupe in another project, then filter it out here. The results from + // the individual projects will already contain the information about all the projects + // leading to a better condensed view that doesn't look like it contains duplicate info. + lock (seenItems) { - var service = project.GetLanguageService(); - if (service != null) - { - Func onResultFound = async (result) => - { - // If we're seeing a dupe in another project, then filter it out here. The results from - // the individual projects will already contain the information about all the projects - // leading to a better condensed view that doesn't look like it contains duplicate info. - lock (seenItems) - { - if (!seenItems.Add(result)) - return; - } - - await _callback.AddItemAsync(project, result, _cancellationToken).ConfigureAwait(false); - }; - - var task = _currentDocument != null - ? service.SearchDocumentAsync(_currentDocument, _searchPattern, _kinds, onResultFound, _cancellationToken) - : service.SearchProjectAsync(project, priorityDocuments, _searchPattern, _kinds, onResultFound, _cancellationToken); - - await task.ConfigureAwait(false); - } + if (!seenItems.Add(result)) + return; } + + await _callback.AddItemAsync(project, result, _cancellationToken).ConfigureAwait(false); } } } diff --git a/src/Features/Core/Portable/NavigateTo/RoslynNavigateToItem.cs b/src/Features/Core/Portable/NavigateTo/RoslynNavigateToItem.cs new file mode 100644 index 0000000000000..979ee6a3c5c4d --- /dev/null +++ b/src/Features/Core/Portable/NavigateTo/RoslynNavigateToItem.cs @@ -0,0 +1,293 @@ +// 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.CodeAnalysis; +using System.IO; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.Navigation; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.NavigateTo +{ + /// + /// Data about a navigate to match. Only intended for use by C# and VB. Carries enough rich information to + /// rehydrate everything needed quickly on either the host or remote side. + /// + [DataContract] + internal readonly struct RoslynNavigateToItem + { + [DataMember(Order = 0)] + public readonly bool IsStale; + + [DataMember(Order = 1)] + public readonly DocumentId DocumentId; + + [DataMember(Order = 2)] + public readonly ImmutableArray AdditionalMatchingProjects; + + [DataMember(Order = 3)] + public readonly DeclaredSymbolInfo DeclaredSymbolInfo; + + /// + /// Will be one of the values from . + /// + [DataMember(Order = 4)] + public readonly string Kind; + + [DataMember(Order = 5)] + public readonly NavigateToMatchKind MatchKind; + + [DataMember(Order = 6)] + public readonly bool IsCaseSensitive; + + [DataMember(Order = 7)] + public readonly ImmutableArray NameMatchSpans; + + public RoslynNavigateToItem( + bool isStale, + DocumentId documentId, + ImmutableArray additionalMatchingProjects, + DeclaredSymbolInfo declaredSymbolInfo, + string kind, + NavigateToMatchKind matchKind, + bool isCaseSensitive, + ImmutableArray nameMatchSpans) + { + IsStale = isStale; + DocumentId = documentId; + AdditionalMatchingProjects = additionalMatchingProjects; + DeclaredSymbolInfo = declaredSymbolInfo; + Kind = kind; + MatchKind = matchKind; + IsCaseSensitive = isCaseSensitive; + NameMatchSpans = nameMatchSpans; + } + + public async Task TryCreateSearchResultAsync(Solution solution, CancellationToken cancellationToken) + { + if (IsStale) + { + // may refer to a document that doesn't exist anymore. Bail out gracefully in that case. + var document = solution.GetDocument(DocumentId); + if (document == null) + return null; + + return new NavigateToSearchResult(this, document); + } + else + { + var document = await solution.GetRequiredDocumentAsync( + DocumentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); + return new NavigateToSearchResult(this, document); + } + } + + private class NavigateToSearchResult : INavigateToSearchResult, INavigableItem + { + private static readonly char[] s_dotArray = { '.' }; + + private readonly RoslynNavigateToItem _item; + private readonly Document _document; + private readonly string _additionalInformation; + + public NavigateToSearchResult(RoslynNavigateToItem item, Document document) + { + _item = item; + _document = document; + _additionalInformation = ComputeAdditionalInformation(); + } + + private string ComputeAdditionalInformation() + { + // For partial types, state what file they're in so the user can disambiguate the results. + var combinedProjectName = ComputeCombinedProjectName(); + return (_item.DeclaredSymbolInfo.IsPartial, IsNonNestedNamedType()) switch + { + (true, true) => string.Format(FeaturesResources._0_dash_1, _document.Name, combinedProjectName), + (true, false) => string.Format(FeaturesResources.in_0_1_2, _item.DeclaredSymbolInfo.ContainerDisplayName, _document.Name, combinedProjectName), + (false, true) => string.Format(FeaturesResources.project_0, combinedProjectName), + (false, false) => string.Format(FeaturesResources.in_0_project_1, _item.DeclaredSymbolInfo.ContainerDisplayName, combinedProjectName), + }; + } + + private string ComputeCombinedProjectName() + { + // If there aren't any additional matches in other projects, we don't need to merge anything. + if (_item.AdditionalMatchingProjects.Length > 0) + { + // First get the simple project name and flavor for the actual project we got a hit in. If we can't + // figure this out, we can't create a merged name. + var firstProject = _document.Project; + var (firstProjectName, firstProjectFlavor) = firstProject.State.NameAndFlavor; + + if (firstProjectName != null) + { + var solution = firstProject.Solution; + + using var _ = ArrayBuilder.GetInstance(out var flavors); + flavors.Add(firstProjectFlavor!); + + // Now, do the same for the other projects where we had a match. As above, if we can't figure out the + // simple name/flavor, or if the simple project name doesn't match the simple project name we started + // with then we can't merge these. + foreach (var additionalProjectId in _item.AdditionalMatchingProjects) + { + var additionalProject = solution.GetRequiredProject(additionalProjectId); + var (projectName, projectFlavor) = additionalProject.State.NameAndFlavor; + if (projectName == firstProjectName) + flavors.Add(projectFlavor!); + } + + flavors.RemoveDuplicates(); + flavors.Sort(); + + return $"{firstProjectName} ({string.Join(", ", flavors)})"; + } + } + + // Couldn't compute a merged project name (or only had one project). Just return the name of hte project itself. + return _document.Project.Name; + } + + string INavigateToSearchResult.AdditionalInformation => _additionalInformation; + + private bool IsNonNestedNamedType() + => !_item.DeclaredSymbolInfo.IsNestedType && IsNamedType(); + + private bool IsNamedType() + { + switch (_item.DeclaredSymbolInfo.Kind) + { + case DeclaredSymbolInfoKind.Class: + case DeclaredSymbolInfoKind.Record: + case DeclaredSymbolInfoKind.Enum: + case DeclaredSymbolInfoKind.Interface: + case DeclaredSymbolInfoKind.Module: + case DeclaredSymbolInfoKind.Struct: + return true; + default: + return false; + } + } + + string INavigateToSearchResult.Kind => _item.Kind; + + NavigateToMatchKind INavigateToSearchResult.MatchKind => _item.MatchKind; + + bool INavigateToSearchResult.IsCaseSensitive => _item.IsCaseSensitive; + + string INavigateToSearchResult.Name => _item.DeclaredSymbolInfo.Name; + + ImmutableArray INavigateToSearchResult.NameMatchSpans => _item.NameMatchSpans; + + string INavigateToSearchResult.SecondarySort + { + get + { + + // For partial types, we break up the file name into pieces. i.e. If we have + // Outer.cs and Outer.Inner.cs then we add "Outer" and "Outer Inner" to + // the secondary sort string. That way "Outer.cs" will be weighted above + // "Outer.Inner.cs" + var fileName = Path.GetFileNameWithoutExtension(_document.FilePath ?? ""); + + using var _ = ArrayBuilder.GetInstance(out var parts); + + parts.Add(_item.DeclaredSymbolInfo.ParameterCount.ToString("X4")); + parts.Add(_item.DeclaredSymbolInfo.TypeParameterCount.ToString("X4")); + parts.Add(_item.DeclaredSymbolInfo.Name); + parts.AddRange(fileName.Split(s_dotArray)); + + return string.Join(" ", parts); + } + } + + string? INavigateToSearchResult.Summary => null; + + INavigableItem INavigateToSearchResult.NavigableItem => this; + + #region INavigableItem + + Glyph INavigableItem.Glyph => GetGlyph(_item.DeclaredSymbolInfo.Kind, _item.DeclaredSymbolInfo.Accessibility); + + private static Glyph GetPublicGlyph(DeclaredSymbolInfoKind kind) + => kind switch + { + DeclaredSymbolInfoKind.Class => Glyph.ClassPublic, + DeclaredSymbolInfoKind.Constant => Glyph.ConstantPublic, + DeclaredSymbolInfoKind.Constructor => Glyph.MethodPublic, + DeclaredSymbolInfoKind.Delegate => Glyph.DelegatePublic, + DeclaredSymbolInfoKind.Enum => Glyph.EnumPublic, + DeclaredSymbolInfoKind.EnumMember => Glyph.EnumMemberPublic, + DeclaredSymbolInfoKind.Event => Glyph.EventPublic, + DeclaredSymbolInfoKind.ExtensionMethod => Glyph.ExtensionMethodPublic, + DeclaredSymbolInfoKind.Field => Glyph.FieldPublic, + DeclaredSymbolInfoKind.Indexer => Glyph.PropertyPublic, + DeclaredSymbolInfoKind.Interface => Glyph.InterfacePublic, + DeclaredSymbolInfoKind.Method => Glyph.MethodPublic, + DeclaredSymbolInfoKind.Module => Glyph.ModulePublic, + DeclaredSymbolInfoKind.Property => Glyph.PropertyPublic, + DeclaredSymbolInfoKind.Struct => Glyph.StructurePublic, + _ => Glyph.ClassPublic, + }; + + private static Glyph GetGlyph(DeclaredSymbolInfoKind kind, Accessibility accessibility) + { + // Glyphs are stored in this order: + // ClassPublic, + // ClassProtected, + // ClassPrivate, + // ClassInternal, + + var rawGlyph = GetPublicGlyph(kind); + + switch (accessibility) + { + case Accessibility.Private: + rawGlyph += (Glyph.ClassPrivate - Glyph.ClassPublic); + break; + case Accessibility.Internal: + rawGlyph += (Glyph.ClassInternal - Glyph.ClassPublic); + break; + case Accessibility.Protected: + case Accessibility.ProtectedOrInternal: + case Accessibility.ProtectedAndInternal: + rawGlyph += (Glyph.ClassProtected - Glyph.ClassPublic); + break; + } + + return rawGlyph; + } + + ImmutableArray INavigableItem.DisplayTaggedParts + => ImmutableArray.Create(new TaggedText( + TextTags.Text, _item.DeclaredSymbolInfo.Name + _item.DeclaredSymbolInfo.NameSuffix)); + + bool INavigableItem.DisplayFileLocation => false; + + /// + /// DeclaredSymbolInfos always come from some actual declaration in source. So they're + /// never implicitly declared. + /// + bool INavigableItem.IsImplicitlyDeclared => false; + + Document INavigableItem.Document => _document; + + TextSpan INavigableItem.SourceSpan => _item.DeclaredSymbolInfo.Span; + + bool INavigableItem.IsStale => _item.IsStale; + + ImmutableArray INavigableItem.ChildItems => ImmutableArray.Empty; + + #endregion + } + } +} diff --git a/src/Features/Core/Portable/Navigation/DefaultDocumentNavigationService.cs b/src/Features/Core/Portable/Navigation/DefaultDocumentNavigationService.cs index 08415b74f84b7..05943ab6cef20 100644 --- a/src/Features/Core/Portable/Navigation/DefaultDocumentNavigationService.cs +++ b/src/Features/Core/Portable/Navigation/DefaultDocumentNavigationService.cs @@ -21,7 +21,7 @@ public bool CanNavigateToLineAndOffset(Workspace workspace, DocumentId documentI public bool CanNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, CancellationToken cancellationToken) => false; - public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, CancellationToken cancellationToken) + public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, bool allowInvalidSpan, CancellationToken cancellationToken) => false; public bool TryNavigateToLineAndOffset(Workspace workspace, DocumentId documentId, int lineNumber, int offset, OptionSet options, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/Navigation/IDocumentNavigationService.cs b/src/Features/Core/Portable/Navigation/IDocumentNavigationService.cs index fa88cd3f74c72..c7672002daf51 100644 --- a/src/Features/Core/Portable/Navigation/IDocumentNavigationService.cs +++ b/src/Features/Core/Portable/Navigation/IDocumentNavigationService.cs @@ -31,7 +31,7 @@ internal interface IDocumentNavigationService : IWorkspaceService /// /// Navigates to the given position in the specified document, opening it if necessary. /// - bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, CancellationToken cancellationToken); + bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, bool allowInvalidSpan, CancellationToken cancellationToken); /// /// Navigates to the given line/offset in the specified document, opening it if necessary. @@ -52,6 +52,9 @@ public static bool CanNavigateToPosition(this IDocumentNavigationService service public static bool TryNavigateToSpan(this IDocumentNavigationService service, Workspace workspace, DocumentId documentId, TextSpan textSpan, CancellationToken cancellationToken) => service.TryNavigateToSpan(workspace, documentId, textSpan, options: null, cancellationToken); + public static bool TryNavigateToSpan(this IDocumentNavigationService service, Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, CancellationToken cancellationToken) + => service.TryNavigateToSpan(workspace, documentId, textSpan, options, allowInvalidSpan: false, cancellationToken); + public static bool TryNavigateToLineAndOffset(this IDocumentNavigationService service, Workspace workspace, DocumentId documentId, int lineNumber, int offset, CancellationToken cancellationToken) => service.TryNavigateToLineAndOffset(workspace, documentId, lineNumber, offset, options: null, cancellationToken); diff --git a/src/Features/Core/Portable/Navigation/INavigableItem.cs b/src/Features/Core/Portable/Navigation/INavigableItem.cs index 5c9a3301370b2..14b31b6a0912b 100644 --- a/src/Features/Core/Portable/Navigation/INavigableItem.cs +++ b/src/Features/Core/Portable/Navigation/INavigableItem.cs @@ -14,12 +14,14 @@ internal interface INavigableItem Glyph Glyph { get; } /// - /// The tagged parts to display for this item. If default, the line of text from is used. + /// The tagged parts to display for this item. If default, the line of text from is used. /// ImmutableArray DisplayTaggedParts { get; } /// - /// Return true to display the file path of and the span of when displaying this item. + /// Return true to display the file path of and the span of when displaying this item. /// bool DisplayFileLocation { get; } @@ -34,6 +36,14 @@ internal interface INavigableItem Document Document { get; } TextSpan SourceSpan { get; } + /// + /// True if this search result represents an item that existed in the past, but which may + /// not exist currently, or which may have moved to a different location. Consumers should + /// be resilient to that being the case and not being able to necessarily navigate to the + /// provided. + /// + bool IsStale { get; } + ImmutableArray ChildItems { get; } } } diff --git a/src/Features/Core/Portable/Navigation/NavigableItemFactory.DeclaredSymbolNavigableItem.cs b/src/Features/Core/Portable/Navigation/NavigableItemFactory.DeclaredSymbolNavigableItem.cs deleted file mode 100644 index 2a08978e5cfbe..0000000000000 --- a/src/Features/Core/Portable/Navigation/NavigableItemFactory.DeclaredSymbolNavigableItem.cs +++ /dev/null @@ -1,97 +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.Immutable; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.Navigation -{ - internal partial class NavigableItemFactory - { - internal class DeclaredSymbolNavigableItem : INavigableItem - { - private readonly DeclaredSymbolInfo _declaredSymbolInfo; - - public Document Document { get; } - - public ImmutableArray DisplayTaggedParts - => ImmutableArray.Create(new TaggedText( - TextTags.Text, _declaredSymbolInfo.Name + _declaredSymbolInfo.NameSuffix)); - - public Glyph Glyph => GetGlyph(_declaredSymbolInfo.Kind, _declaredSymbolInfo.Accessibility); - - public TextSpan SourceSpan => _declaredSymbolInfo.Span; - - public ImmutableArray ChildItems => ImmutableArray.Empty; - public bool DisplayFileLocation => false; - - /// - /// DeclaredSymbolInfos always come from some actual declaration in source. So they're - /// never implicitly declared. - /// - public bool IsImplicitlyDeclared => false; - - public DeclaredSymbolNavigableItem( - Document document, DeclaredSymbolInfo declaredSymbolInfo) - { - Document = document; - _declaredSymbolInfo = declaredSymbolInfo; - } - - private static Glyph GetPublicGlyph(DeclaredSymbolInfoKind kind) - { - switch (kind) - { - case DeclaredSymbolInfoKind.Class: return Glyph.ClassPublic; - case DeclaredSymbolInfoKind.Constant: return Glyph.ConstantPublic; - case DeclaredSymbolInfoKind.Constructor: return Glyph.MethodPublic; - case DeclaredSymbolInfoKind.Delegate: return Glyph.DelegatePublic; - case DeclaredSymbolInfoKind.Enum: return Glyph.EnumPublic; - case DeclaredSymbolInfoKind.EnumMember: return Glyph.EnumMemberPublic; - case DeclaredSymbolInfoKind.Event: return Glyph.EventPublic; - case DeclaredSymbolInfoKind.ExtensionMethod: return Glyph.ExtensionMethodPublic; - case DeclaredSymbolInfoKind.Field: return Glyph.FieldPublic; - case DeclaredSymbolInfoKind.Indexer: return Glyph.PropertyPublic; - case DeclaredSymbolInfoKind.Interface: return Glyph.InterfacePublic; - case DeclaredSymbolInfoKind.Method: return Glyph.MethodPublic; - case DeclaredSymbolInfoKind.Module: return Glyph.ModulePublic; - case DeclaredSymbolInfoKind.Property: return Glyph.PropertyPublic; - case DeclaredSymbolInfoKind.Struct: return Glyph.StructurePublic; - default: return Glyph.ClassPublic; - } - } - - private static Glyph GetGlyph(DeclaredSymbolInfoKind kind, Accessibility accessibility) - { - // Glyphs are stored in this order: - // ClassPublic, - // ClassProtected, - // ClassPrivate, - // ClassInternal, - - var rawGlyph = GetPublicGlyph(kind); - - switch (accessibility) - { - case Accessibility.Private: - rawGlyph += (Glyph.ClassPrivate - Glyph.ClassPublic); - break; - case Accessibility.Internal: - rawGlyph += (Glyph.ClassInternal - Glyph.ClassPublic); - break; - case Accessibility.Protected: - case Accessibility.ProtectedOrInternal: - case Accessibility.ProtectedAndInternal: - rawGlyph += (Glyph.ClassProtected - Glyph.ClassPublic); - break; - } - - return rawGlyph; - } - } - } -} diff --git a/src/Features/Core/Portable/Navigation/NavigableItemFactory.SymbolLocationNavigableItem.cs b/src/Features/Core/Portable/Navigation/NavigableItemFactory.SymbolLocationNavigableItem.cs index d12a184e1179d..660a4ff24284f 100644 --- a/src/Features/Core/Portable/Navigation/NavigableItemFactory.SymbolLocationNavigableItem.cs +++ b/src/Features/Core/Portable/Navigation/NavigableItemFactory.SymbolLocationNavigableItem.cs @@ -43,6 +43,8 @@ public SymbolLocationNavigableItem( public TextSpan SourceSpan => _location.SourceSpan; + public bool IsStale => false; + public ImmutableArray ChildItems => ImmutableArray.Empty; } } diff --git a/src/Features/Core/Portable/Navigation/NavigableItemFactory.cs b/src/Features/Core/Portable/Navigation/NavigableItemFactory.cs index 17651b4a73091..9a9b521ddd459 100644 --- a/src/Features/Core/Portable/Navigation/NavigableItemFactory.cs +++ b/src/Features/Core/Portable/Navigation/NavigableItemFactory.cs @@ -24,9 +24,6 @@ public static INavigableItem GetItemFromSymbolLocation( solution, symbol, location, displayTaggedParts); } - public static INavigableItem GetItemFromDeclaredSymbolInfo(DeclaredSymbolInfo declaredSymbolInfo, Document document) - => new DeclaredSymbolNavigableItem(document, declaredSymbolInfo); - public static ImmutableArray GetItemsFromPreferredSourceLocations( Solution solution, ISymbol symbol, diff --git a/src/Features/Core/Portable/Remote/RemoteArguments.cs b/src/Features/Core/Portable/Remote/RemoteArguments.cs deleted file mode 100644 index 1cdfdbe4b4444..0000000000000 --- a/src/Features/Core/Portable/Remote/RemoteArguments.cs +++ /dev/null @@ -1,219 +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.Runtime.Serialization; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.NavigateTo; -using Microsoft.CodeAnalysis.Navigation; -using Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.Remote -{ - #region NavigateTo - - [DataContract] - internal readonly struct SerializableNavigateToSearchResult - { - [DataMember(Order = 0)] - public readonly string AdditionalInformation; - - [DataMember(Order = 1)] - public readonly string Kind; - - [DataMember(Order = 2)] - public readonly NavigateToMatchKind MatchKind; - - [DataMember(Order = 3)] - public readonly bool IsCaseSensitive; - - [DataMember(Order = 4)] - public readonly string Name; - - [DataMember(Order = 5)] - public readonly ImmutableArray NameMatchSpans; - - [DataMember(Order = 6)] - public readonly string SecondarySort; - - [DataMember(Order = 7)] - public readonly string Summary; - - [DataMember(Order = 8)] - public readonly SerializableNavigableItem NavigableItem; - - public SerializableNavigateToSearchResult( - string additionalInformation, - string kind, - NavigateToMatchKind matchKind, - bool isCaseSensitive, - string name, - ImmutableArray nameMatchSpans, - string secondarySort, - string summary, - SerializableNavigableItem navigableItem) - { - AdditionalInformation = additionalInformation; - Kind = kind; - MatchKind = matchKind; - IsCaseSensitive = isCaseSensitive; - Name = name; - NameMatchSpans = nameMatchSpans; - SecondarySort = secondarySort; - Summary = summary; - NavigableItem = navigableItem; - } - - internal static SerializableNavigateToSearchResult Dehydrate(INavigateToSearchResult result) - => new(result.AdditionalInformation, - result.Kind, - result.MatchKind, - result.IsCaseSensitive, - result.Name, - result.NameMatchSpans, - result.SecondarySort, - result.Summary, - SerializableNavigableItem.Dehydrate(result.NavigableItem)); - - internal async ValueTask RehydrateAsync(Solution solution, CancellationToken cancellationToken) - { - return new NavigateToSearchResult( - AdditionalInformation, Kind, MatchKind, IsCaseSensitive, - Name, NameMatchSpans, - SecondarySort, Summary, await NavigableItem.RehydrateAsync(solution, cancellationToken).ConfigureAwait(false)); - } - - private class NavigateToSearchResult : INavigateToSearchResult - { - public string AdditionalInformation { get; } - public string Kind { get; } - public NavigateToMatchKind MatchKind { get; } - public bool IsCaseSensitive { get; } - public string Name { get; } - public ImmutableArray NameMatchSpans { get; } - public string SecondarySort { get; } - public string Summary { get; } - - public INavigableItem NavigableItem { get; } - - public NavigateToSearchResult( - string additionalInformation, string kind, NavigateToMatchKind matchKind, - bool isCaseSensitive, string name, ImmutableArray nameMatchSpans, - string secondarySort, string summary, INavigableItem navigableItem) - { - AdditionalInformation = additionalInformation; - Kind = kind; - MatchKind = matchKind; - IsCaseSensitive = isCaseSensitive; - Name = name; - NameMatchSpans = nameMatchSpans; - SecondarySort = secondarySort; - Summary = summary; - NavigableItem = navigableItem; - } - } - } - - /// - /// Note: this is intentionally a class, not struct, to avoid hitting .NET Framework loader bug - /// that fails to load a struct S declaring a field of type ImmutableArray of S. - /// - [DataContract] - internal sealed class SerializableNavigableItem - { - [DataMember(Order = 0)] - public readonly Glyph Glyph; - - [DataMember(Order = 1)] - public readonly ImmutableArray DisplayTaggedParts; - - [DataMember(Order = 2)] - public readonly bool DisplayFileLocation; - - [DataMember(Order = 3)] - public readonly bool IsImplicitlyDeclared; - - [DataMember(Order = 4)] - public readonly DocumentId Document; - - [DataMember(Order = 5)] - public readonly TextSpan SourceSpan; - - [DataMember(Order = 6)] - public readonly ImmutableArray ChildItems; - - public SerializableNavigableItem( - Glyph glyph, - ImmutableArray displayTaggedParts, - bool displayFileLocation, - bool isImplicitlyDeclared, - DocumentId document, - TextSpan sourceSpan, - ImmutableArray childItems) - { - Glyph = glyph; - DisplayTaggedParts = displayTaggedParts; - DisplayFileLocation = displayFileLocation; - IsImplicitlyDeclared = isImplicitlyDeclared; - Document = document; - SourceSpan = sourceSpan; - ChildItems = childItems; - } - - public static SerializableNavigableItem Dehydrate(INavigableItem item) - => new(item.Glyph, - item.DisplayTaggedParts, - item.DisplayFileLocation, - item.IsImplicitlyDeclared, - item.Document.Id, - item.SourceSpan, - item.ChildItems.SelectAsArray(Dehydrate)); - - public async ValueTask RehydrateAsync(Solution solution, CancellationToken cancellationToken) - { - var childItems = ChildItems == null - ? ImmutableArray.Empty - : await ChildItems.SelectAsArrayAsync(c => c.RehydrateAsync(solution, cancellationToken)).ConfigureAwait(false); - - return new NavigableItem( - Glyph, DisplayTaggedParts, - DisplayFileLocation, IsImplicitlyDeclared, - solution.GetDocument(Document) ?? await solution.GetSourceGeneratedDocumentAsync(Document, cancellationToken).ConfigureAwait(false), - SourceSpan, - childItems); - } - - private class NavigableItem : INavigableItem - { - public Glyph Glyph { get; } - public ImmutableArray DisplayTaggedParts { get; } - public bool DisplayFileLocation { get; } - public bool IsImplicitlyDeclared { get; } - - public Document Document { get; } - public TextSpan SourceSpan { get; } - - public ImmutableArray ChildItems { get; } - - public NavigableItem( - Glyph glyph, ImmutableArray displayTaggedParts, - bool displayFileLocation, bool isImplicitlyDeclared, Document document, TextSpan sourceSpan, ImmutableArray childItems) - { - Glyph = glyph; - DisplayTaggedParts = displayTaggedParts; - DisplayFileLocation = displayFileLocation; - IsImplicitlyDeclared = isImplicitlyDeclared; - Document = document; - SourceSpan = sourceSpan; - ChildItems = childItems; - } - } - } - - #endregion -} diff --git a/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs b/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs index 8118957769e96..76456f29fd714 100644 --- a/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs +++ b/src/Features/Core/Portable/Shared/Utilities/ExtractTypeHelpers.cs @@ -85,7 +85,7 @@ internal static class ExtractTypeHelpers newTypeDocument = newTypeDocument.WithSyntaxRoot(annotatedRoot); var simplified = await Simplifier.ReduceAsync(newTypeDocument, cancellationToken: cancellationToken).ConfigureAwait(false); - var formattedDocument = await Formatter.FormatAsync(simplified).ConfigureAwait(false); + var formattedDocument = await Formatter.FormatAsync(simplified, cancellationToken: cancellationToken).ConfigureAwait(false); return (formattedDocument, typeAnnotation); } diff --git a/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs b/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs index fc774bdeca90c..46507e86acd7f 100644 --- a/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs +++ b/src/Features/Core/Portable/SolutionCrawler/AbstractDocumentDifferenceService.cs @@ -94,7 +94,7 @@ internal abstract class AbstractDocumentDifferenceService : IDocumentDifferenceS return new DocumentDifferenceResult(InvocationReasons.DocumentChanged); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs index b9f9af2eed534..edcb55e313bd0 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.HighPriorityProcessor.cs @@ -199,7 +199,7 @@ private async Task ProcessDocumentAsync(Solution solution, ImmutableArray an // re-run just the body await RunAnalyzersAsync(analyzers, document, workItem, (a, d, c) => a.AnalyzeDocumentAsync(d, activeMember, reasons, c), cancellationToken).ConfigureAwait(false); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.LowPriorityProcessor.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.LowPriorityProcessor.cs index 20cf1398f8b98..3c4eb2fca1e26 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.LowPriorityProcessor.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.LowPriorityProcessor.cs @@ -157,7 +157,7 @@ private async Task ProcessProjectAsync(ImmutableArray anal } } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.NormalPriorityProcessor.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.NormalPriorityProcessor.cs index ad6f19aadff86..6794c08832399 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.NormalPriorityProcessor.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.NormalPriorityProcessor.cs @@ -365,7 +365,7 @@ private async Task ProcessDocumentAsync(ImmutableArray ana } } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -470,7 +470,7 @@ private async Task ProcessReanalyzeDocumentAsync(WorkItem workItem, TextDocument await Processor.RunAnalyzersAsync(reanalyzers, sourceDocument, workItem, (a, d, c) => a.AnalyzeDocumentAsync(d, null, reasons, c), cancellationToken).ConfigureAwait(false); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Features/Core/Portable/TodoComments/AbstractTodoCommentService.cs b/src/Features/Core/Portable/TodoComments/AbstractTodoCommentService.cs index 0fb45669359f3..fde046b3e7fa7 100644 --- a/src/Features/Core/Portable/TodoComments/AbstractTodoCommentService.cs +++ b/src/Features/Core/Portable/TodoComments/AbstractTodoCommentService.cs @@ -29,6 +29,9 @@ public async Task> GetTodoCommentsAsync( ImmutableArray commentDescriptors, CancellationToken cancellationToken) { + if (commentDescriptors.IsEmpty) + return ImmutableArray.Empty; + cancellationToken.ThrowIfCancellationRequested(); // strongly hold onto text and tree diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs index 6355eaa3a6487..13713c94431b0 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Symbols/WorkspaceSymbolsTests.cs @@ -3,10 +3,10 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Roslyn.Test.Utilities; using Xunit; @@ -16,6 +16,9 @@ namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests.Symbols { public class WorkspaceSymbolsTests : AbstractLanguageServerProtocolTests { + private static void AssertSetEquals(LSP.SymbolInformation[] expected, LSP.SymbolInformation[] results) + => Assert.True(expected.ToHashSet().SetEquals(results)); + [Fact] public async Task TestGetWorkspaceSymbolsAsync_Class() { @@ -33,7 +36,7 @@ void M() }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "A").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact] @@ -59,8 +62,7 @@ void M() Assert.Null(results); results = progress.GetValues().ToArray(); - - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact] @@ -80,7 +82,7 @@ public async Task TestGetWorkspaceSymbolsAsync_Method() }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "M").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact(Skip = "GetWorkspaceSymbolsAsync does not yet support locals.")] @@ -103,7 +105,7 @@ void M() }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "i").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact] @@ -131,7 +133,7 @@ class {|class:F|} }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "F").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact] @@ -161,7 +163,7 @@ public async Task TestGetWorkspaceSymbolsAsync_MultipleDocuments() }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "M").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } [Fact] @@ -195,7 +197,7 @@ End Sub }; var results = await RunGetWorkspaceSymbolsAsync(testLspServer, "A").ConfigureAwait(false); - AssertJsonEquals(expected, results); + AssertSetEquals(expected, results); } private static async Task RunGetWorkspaceSymbolsAsync(TestLspServer testLspServer, string query, IProgress? progress = null) diff --git a/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb b/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb index 9e4eb55749f12..da9d187d8a6a3 100644 --- a/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb +++ b/src/Features/VisualBasic/Portable/ChangeSignature/VisualBasicChangeSignatureService.vb @@ -127,7 +127,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature If matchingNode.Kind() = SyntaxKind.ObjectCreationExpression Then Dim objectCreation = DirectCast(matchingNode, ObjectCreationExpressionSyntax) If token.Parent.AncestorsAndSelf().Any(Function(a) a Is objectCreation.Type) Then - Dim typeSymbol = semanticModel.GetSymbolInfo(objectCreation.Type).Symbol + Dim typeSymbol = semanticModel.GetSymbolInfo(objectCreation.Type, cancellationToken).Symbol If typeSymbol IsNot Nothing AndAlso typeSymbol.IsKind(SymbolKind.NamedType) AndAlso DirectCast(typeSymbol, ITypeSymbol).TypeKind = TypeKind.Delegate Then Return (typeSymbol, 0) End If @@ -316,7 +316,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature If vbnode.IsKind(SyntaxKind.RaiseEventStatement) Then Dim raiseEventStatement = DirectCast(vbnode, RaiseEventStatementSyntax) Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) - Dim delegateInvokeMethod = DirectCast(DirectCast(semanticModel.GetSymbolInfo(raiseEventStatement.Name).Symbol, IEventSymbol).Type, INamedTypeSymbol).DelegateInvokeMethod + Dim delegateInvokeMethod = DirectCast(DirectCast(semanticModel.GetSymbolInfo(raiseEventStatement.Name, cancellationToken).Symbol, IEventSymbol).Type, INamedTypeSymbol).DelegateInvokeMethod Return raiseEventStatement.WithArgumentList(Await UpdateArgumentListAsync( delegateInvokeMethod, @@ -335,7 +335,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) Dim isReducedExtensionMethod = False - Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, InvocationExpressionSyntax)) + Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, InvocationExpressionSyntax), cancellationToken) Dim methodSymbol = TryCast(symbolInfo.Symbol, IMethodSymbol) If methodSymbol IsNot Nothing AndAlso methodSymbol.MethodKind = MethodKind.ReducedExtension Then isReducedExtensionMethod = True @@ -375,7 +375,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Dim attribute = DirectCast(vbnode, AttributeSyntax) Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) - Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, AttributeSyntax)) + Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, AttributeSyntax), cancellationToken) Dim methodSymbol = TryCast(symbolInfo.Symbol, IMethodSymbol) Return attribute.WithArgumentList(Await UpdateArgumentListAsync( @@ -394,7 +394,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature Dim objectCreation = DirectCast(vbnode, ObjectCreationExpressionSyntax) Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) - Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, ObjectCreationExpressionSyntax)) + Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(originalNode, ObjectCreationExpressionSyntax), cancellationToken) Dim methodSymbol = TryCast(symbolInfo.Symbol, IMethodSymbol) Dim paramsArrayExpanded = IsParamsArrayExpanded(semanticModel, objectCreation, symbolInfo, cancellationToken) @@ -670,17 +670,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature For Each n In nodes If n.IsKind(SyntaxKind.AddressOfExpression) Then Dim u = DirectCast(n, UnaryExpressionSyntax) - Dim convertedType As ISymbol = semanticModel.GetTypeInfo(u).ConvertedType + Dim convertedType As ISymbol = semanticModel.GetTypeInfo(u, cancellationToken).ConvertedType If convertedType IsNot Nothing Then convertedType = convertedType.OriginalDefinition End If If convertedType IsNot Nothing Then - convertedType = If(Await SymbolFinder.FindSourceDefinitionAsync(convertedType, document.Project.Solution).ConfigureAwait(False), convertedType) + convertedType = If(Await SymbolFinder.FindSourceDefinitionAsync(convertedType, document.Project.Solution, cancellationToken).ConfigureAwait(False), convertedType) End If If Equals(convertedType, symbol.ContainingType) Then - convertedType = semanticModel.GetSymbolInfo(u.Operand).Symbol + convertedType = semanticModel.GetSymbolInfo(u.Operand, cancellationToken).Symbol If convertedType IsNot Nothing Then results.Add(convertedType) End If @@ -688,18 +688,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ChangeSignature ElseIf n.IsKind(SyntaxKind.EventStatement) Then Dim cast = DirectCast(n, EventStatementSyntax) If cast.AsClause IsNot Nothing Then - Dim nodeType = semanticModel.GetSymbolInfo(cast.AsClause.Type).Symbol + Dim nodeType = semanticModel.GetSymbolInfo(cast.AsClause.Type, cancellationToken).Symbol If nodeType IsNot Nothing Then nodeType = nodeType.OriginalDefinition End If If nodeType IsNot Nothing Then - nodeType = If(Await SymbolFinder.FindSourceDefinitionAsync(nodeType, document.Project.Solution).ConfigureAwait(False), nodeType) + nodeType = If(Await SymbolFinder.FindSourceDefinitionAsync(nodeType, document.Project.Solution, cancellationToken).ConfigureAwait(False), nodeType) End If If Equals(nodeType, symbol.ContainingType) Then - results.Add(semanticModel.GetDeclaredSymbol(cast.Identifier.Parent)) + results.Add(semanticModel.GetDeclaredSymbol(cast.Identifier.Parent, cancellationToken)) End If End If End If diff --git a/src/Features/VisualBasic/Portable/CodeFixes/ConvertToAsync/VisualBasicConvertToAsyncFunctionCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/ConvertToAsync/VisualBasicConvertToAsyncFunctionCodeFixProvider.vb index 8e5bbd3fdf0d1..4f0a7bd9b8f07 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/ConvertToAsync/VisualBasicConvertToAsyncFunctionCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/ConvertToAsync/VisualBasicConvertToAsyncFunctionCodeFixProvider.vb @@ -55,7 +55,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.ConvertToAsync Return Nothing End If - Dim methodSymbol = TryCast(semanticModel.GetSymbolInfo(oldNode).Symbol, IMethodSymbol) + Dim methodSymbol = TryCast(semanticModel.GetSymbolInfo(oldNode, cancellationToken).Symbol, IMethodSymbol) If methodSymbol Is Nothing Then Return Nothing End If diff --git a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb index c3a059cb31beb..b9c13314614a7 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/GenerateEvent/GenerateEventCodeFixProvider.vb @@ -245,13 +245,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent ' Does this name already bind? Dim semanticModel = Await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(False) - Dim nameToGenerate = semanticModel.GetSymbolInfo(node).Symbol + Dim nameToGenerate = semanticModel.GetSymbolInfo(node, cancellationToken).Symbol If nameToGenerate IsNot Nothing Then Return Nothing End If - Dim targetType = TryCast(Await SymbolFinder.FindSourceDefinitionAsync(semanticModel.GetSymbolInfo(node.Left).Symbol, document.Project.Solution, cancellationToken).ConfigureAwait(False), INamedTypeSymbol) + Dim targetType = TryCast(Await SymbolFinder.FindSourceDefinitionAsync(semanticModel.GetSymbolInfo(node.Left, cancellationToken).Symbol, document.Project.Solution, cancellationToken).ConfigureAwait(False), INamedTypeSymbol) If targetType Is Nothing OrElse (targetType.TypeKind <> TypeKind.Interface AndAlso targetType.TypeKind <> TypeKind.Class) Then Return Nothing End If @@ -358,7 +358,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.GenerateEvent ' Our target type may be from a CSharp file, in which case we should resolve it to our VB compilation. Dim originalTargetType = targetType - targetType = DirectCast(targetType.GetSymbolKey().Resolve(semanticModel.Compilation).Symbol, INamedTypeSymbol) + targetType = DirectCast(targetType.GetSymbolKey(cancellationToken).Resolve(semanticModel.Compilation, cancellationToken:=cancellationToken).Symbol, INamedTypeSymbol) If targetType Is Nothing Then Return Nothing diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.ReferenceRewriter.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.ReferenceRewriter.vb index d8b419e76df4b..d2ad63b502178 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.ReferenceRewriter.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.ReferenceRewriter.vb @@ -32,7 +32,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary _semanticModel = semanticModel _expressionToInline = expressionToInline _cancellationToken = cancellationToken - _localSymbol = DirectCast(_semanticModel.GetDeclaredSymbol(_definition), ILocalSymbol) + _localSymbol = DirectCast(_semanticModel.GetDeclaredSymbol(_definition, cancellationToken), ILocalSymbol) End Sub Private Function IsReference(node As SimpleNameSyntax) As Boolean diff --git a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.vb index 805a2ddc47e07..06441b73d0fa9 100644 --- a/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeRefactorings/InlineTemporary/InlineTemporaryCodeRefactoringProvider.vb @@ -153,7 +153,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeRefactorings.InlineTemporary ' Next, get the top-most statement of the local declaration Dim variableDeclarator = DirectCast(modifiedIdentifier.Parent, VariableDeclaratorSyntax) Dim localDeclaration = DirectCast(variableDeclarator.Parent, LocalDeclarationStatementSyntax) - Dim originalInitializerSymbolInfo = semanticModel.GetSymbolInfo(variableDeclarator.GetInitializer()) + Dim originalInitializerSymbolInfo = semanticModel.GetSymbolInfo(variableDeclarator.GetInitializer(), cancellationToken) Dim topMostStatementOfLocalDeclaration = If(localDeclaration.HasAncestor(Of ExpressionSyntax), localDeclaration.Ancestors().OfType(Of ExpressionSyntax).Last().FirstAncestorOrSelf(Of StatementSyntax)(), diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/PreprocessorCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/PreprocessorCompletionProvider.vb index 4391429d75988..e3b606cce18f9 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/PreprocessorCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/PreprocessorCompletionProvider.vb @@ -5,7 +5,7 @@ Imports System.Collections.Immutable Imports System.Composition Imports Microsoft.CodeAnalysis.Completion -Imports Microsoft.CodeAnalysis.CSharp.Completion.Providers +Imports Microsoft.CodeAnalysis.Completion.Providers Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Text diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb index bbec4f9ee2128..29c5befe0a147 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/XmlDocCommentCompletionProvider.vb @@ -159,7 +159,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers End If Return items - Catch e As Exception When FatalError.ReportAndCatchUnlessCanceled(e) + Catch e As Exception When FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken) Return SpecializedCollections.EmptyEnumerable(Of CompletionItem) End Try End Function diff --git a/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Declarations/ImplementsKeywordRecommender.vb b/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Declarations/ImplementsKeywordRecommender.vb index c9c9586093edc..561434b0d5f80 100644 --- a/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Declarations/ImplementsKeywordRecommender.vb +++ b/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Declarations/ImplementsKeywordRecommender.vb @@ -35,10 +35,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.KeywordRecommenders.Decl If typeBlock IsNot Nothing Then ' We need to check to see if any of the partial types parts declare an implements statement. ' If not, we don't show the Implements keyword. - Dim typeSymbol = context.SemanticModel.GetDeclaredSymbol(typeBlock) + Dim typeSymbol = context.SemanticModel.GetDeclaredSymbol(typeBlock, cancellationToken) If typeSymbol IsNot Nothing Then For Each reference In typeSymbol.DeclaringSyntaxReferences - Dim typeStatement = TryCast(reference.GetSyntax(), TypeStatementSyntax) + Dim typeStatement = TryCast(reference.GetSyntax(cancellationToken), TypeStatementSyntax) If typeStatement IsNot Nothing AndAlso TypeOf typeStatement.Parent Is TypeBlockSyntax AndAlso diff --git a/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Expressions/BinaryOperatorKeywordRecommender.vb b/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Expressions/BinaryOperatorKeywordRecommender.vb index dc00230b5dc81..208fcd8b1d132 100644 --- a/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Expressions/BinaryOperatorKeywordRecommender.vb +++ b/src/Features/VisualBasic/Portable/Completion/KeywordRecommenders/Expressions/BinaryOperatorKeywordRecommender.vb @@ -56,7 +56,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.KeywordRecommenders.Expr If identifierName IsNot Nothing Then Dim text = token.ToString() If (SyntaxFacts.GetContextualKeywordKind(text) = SyntaxKind.FromKeyword OrElse SyntaxFacts.GetContextualKeywordKind(text) = SyntaxKind.AggregateKeyword) Then - Dim symbol = context.SemanticModel.GetSymbolInfo(identifierName).Symbol + Dim symbol = context.SemanticModel.GetSymbolInfo(identifierName, cancellationToken).Symbol If symbol Is Nothing Then Return False End If diff --git a/src/Features/VisualBasic/Portable/ConvertAnonymousTypeToClass/VisualBasicConvertAnonymousTypeToClassCodeRefactoringProvider.vb b/src/Features/VisualBasic/Portable/ConvertAnonymousTypeToClass/VisualBasicConvertAnonymousTypeToClassCodeRefactoringProvider.vb index c30b57e50a05e..80c30a274aea2 100644 --- a/src/Features/VisualBasic/Portable/ConvertAnonymousTypeToClass/VisualBasicConvertAnonymousTypeToClassCodeRefactoringProvider.vb +++ b/src/Features/VisualBasic/Portable/ConvertAnonymousTypeToClass/VisualBasicConvertAnonymousTypeToClassCodeRefactoringProvider.vb @@ -5,7 +5,7 @@ Imports System.Composition Imports System.Diagnostics.CodeAnalysis Imports Microsoft.CodeAnalysis.CodeRefactorings -Imports Microsoft.CodeAnalysis.CSharp.ConvertAnonymousTypeToClass +Imports Microsoft.CodeAnalysis.ConvertAnonymousTypeToClass Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.ConvertAnonymousTypeToClass diff --git a/src/Features/VisualBasic/Portable/Debugging/VisualBasicBreakpointService.vb b/src/Features/VisualBasic/Portable/Debugging/VisualBasicBreakpointService.vb index e7f8eda741a80..632f198b43ff6 100644 --- a/src/Features/VisualBasic/Portable/Debugging/VisualBasicBreakpointService.vb +++ b/src/Features/VisualBasic/Portable/Debugging/VisualBasicBreakpointService.vb @@ -66,7 +66,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Debugging End If Return BreakpointResolutionResult.CreateSpanResult(document, span) - Catch e As Exception When FatalError.ReportAndCatchUnlessCanceled(e) + Catch e As Exception When FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken) Return Nothing End Try End Function diff --git a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb index fee8776a07fd0..8579b85422ad7 100644 --- a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb @@ -99,7 +99,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames inDeclaration = False diagnosticId = IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId ElseIf expression.Kind = SyntaxKind.SimpleMemberAccessExpression Then - Dim method = model.GetMemberGroup(expression) + Dim method = model.GetMemberGroup(expression, cancellationToken) If method.Length = 1 Then Dim symbol = method.First() If (symbol.IsOverrides Or symbol.IsOverridable) And memberAccess.Expression.Kind = SyntaxKind.MyClassExpression Then diff --git a/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb b/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb index 7282d3b1a5e9d..a803ca6f207f6 100644 --- a/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb +++ b/src/Features/VisualBasic/Portable/GenerateType/VisualBasicGenerateTypeService.vb @@ -431,7 +431,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateType Dim containerList = New List(Of String)(containers) Dim enclosingNamespace = GetDeclaringNamespace(containerList, 0, compilationUnit) If enclosingNamespace IsNot Nothing Then - Dim enclosingNamespaceSymbol = semanticModel.GetSymbolInfo(enclosingNamespace.Name) + Dim enclosingNamespaceSymbol = semanticModel.GetSymbolInfo(enclosingNamespace.Name, cancellationToken) If enclosingNamespaceSymbol.Symbol IsNot Nothing Then Return (DirectCast(enclosingNamespaceSymbol.Symbol, INamespaceSymbol), namedTypeSymbol, diff --git a/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb b/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb index 719cdfdadf8da..9a71722c8dced 100644 --- a/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb +++ b/src/Features/VisualBasic/Portable/NavigationBar/VisualBasicNavigationBarItemService.vb @@ -92,7 +92,7 @@ Namespace Microsoft.CodeAnalysis.NavigationBar Loop Return typesAndDeclarations.Select(Function(kvp) Tuple.Create(kvp.Key, kvp.Value)).OrderBy(Function(t) t.Item1.Name) - Catch ex As Exception When FatalError.ReportAndPropagateUnlessCanceled(ex) + Catch ex As Exception When FatalError.ReportAndPropagateUnlessCanceled(ex, cancellationToken) Throw ExceptionUtilities.Unreachable End Try End Function diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb index 8d4eb3a2681e5..56adfb481d19b 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb @@ -93,7 +93,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp memberGroup = memberGroup.SelectAsArray(Function(m) If(Equals(matchedMethodSymbol.OriginalDefinition, m), matchedMethodSymbol, m)) End If - Dim enclosingSymbol = semanticModel.GetEnclosingSymbol(position) + Dim enclosingSymbol = semanticModel.GetEnclosingSymbol(position, cancellationToken) If enclosingSymbol.IsConstructor() Then memberGroup = memberGroup.WhereAsArray(Function(m) Not m.Equals(enclosingSymbol)) End If diff --git a/src/Interactive/Host/Interactive/Core/InteractiveHost.LazyRemoteService.cs b/src/Interactive/Host/Interactive/Core/InteractiveHost.LazyRemoteService.cs index 814844ef4e07d..6e3d51c9bf249 100644 --- a/src/Interactive/Host/Interactive/Core/InteractiveHost.LazyRemoteService.cs +++ b/src/Interactive/Host/Interactive/Core/InteractiveHost.LazyRemoteService.cs @@ -123,7 +123,12 @@ private async Task TryStartAndInitializeProcessAsync(C return new InitializedRemoteService(remoteService, result); } +#pragma warning disable CA2016 // Forward the 'CancellationToken' parameter to methods + // await ExecuteRemoteAsync above does not take cancellationToken + // - we don't currently support cancellation of the RPC call, + // but JsonRpc.InvokeAsync that we use still claims it may throw OperationCanceledException.. catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) +#pragma warning restore CA2016 { throw ExceptionUtilities.Unreachable; } diff --git a/src/Scripting/VisualBasicTest/ScriptTests.vb b/src/Scripting/VisualBasicTest/ScriptTests.vb index c30cb3f5aab3b..e1a903ddca8a4 100644 --- a/src/Scripting/VisualBasicTest/ScriptTests.vb +++ b/src/Scripting/VisualBasicTest/ScriptTests.vb @@ -12,9 +12,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Scripting.UnitTests Public Class ScriptTests Inherits TestBase + ''' + ''' Need to create a without a file path here. Scripting + ''' will attempt to validate file paths and one does not exist for this reference as it's an in + ''' memory item. + ''' + Private Shared ReadOnly s_msvbReference As PortableExecutableReference = AssemblyMetadata.CreateFromImage(TestMetadata.ResourcesNet451.MicrosoftVisualBasic).GetReference() + ' It shouldn't be necessary to include VB runtime assembly ' explicitly in VisualBasicScript.Create. - Private Shared ReadOnly s_defaultOptions As ScriptOptions = ScriptOptions.Default.AddReferences(MsvbRef) + Private Shared ReadOnly s_defaultOptions As ScriptOptions = ScriptOptions.Default.AddReferences(s_msvbReference) Public Sub TestCreateScript() diff --git a/src/Tools/BuildValidator/BuildValidator.csproj b/src/Tools/BuildValidator/BuildValidator.csproj index b803ef35af869..36399f90ac233 100644 --- a/src/Tools/BuildValidator/BuildValidator.csproj +++ b/src/Tools/BuildValidator/BuildValidator.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/Tools/BuildValidator/BuildValidator.sln b/src/Tools/BuildValidator/BuildValidator.sln index 1eb504e978f5a..965162faad65e 100644 --- a/src/Tools/BuildValidator/BuildValidator.sln +++ b/src/Tools/BuildValidator/BuildValidator.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 16.0.30905.15 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildValidator", "BuildValidator.csproj", "{F3EDD192-7E74-441D-B096-16C0FE2731E3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rebuild", "..\..\Compilers\Core\Rebuild\Rebuild.csproj", "{04CCBB7F-B1E3-4E76-A4A7-C648EBE77CBB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Rebuild", "..\..\Compilers\Core\Rebuild\Microsoft.CodeAnalysis.Rebuild.csproj", "{04CCBB7F-B1E3-4E76-A4A7-C648EBE77CBB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Rebuild.UnitTests", "..\..\Compilers\Core\RebuildTest\Microsoft.CodeAnalysis.Rebuild.UnitTests.csproj", "{48B87FA3-669F-48D2-A23A-50E43D875C61}" EndProject diff --git a/src/Tools/BuildValidator/CompilationDiff.cs b/src/Tools/BuildValidator/CompilationDiff.cs index 522e8334abdaa..b7bb075b8aa23 100644 --- a/src/Tools/BuildValidator/CompilationDiff.cs +++ b/src/Tools/BuildValidator/CompilationDiff.cs @@ -18,6 +18,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Rebuild; using Microsoft.CodeAnalysis.Text; using Microsoft.DiaSymReader.Tools; using Microsoft.Extensions.Logging; diff --git a/src/Tools/BuildValidator/LocalReferenceResolver.cs b/src/Tools/BuildValidator/LocalReferenceResolver.cs index e75cf109aa8a5..a7e5ff4030316 100644 --- a/src/Tools/BuildValidator/LocalReferenceResolver.cs +++ b/src/Tools/BuildValidator/LocalReferenceResolver.cs @@ -13,6 +13,7 @@ using System.Reflection.PortableExecutable; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Rebuild; using Microsoft.Extensions.Logging; namespace BuildValidator diff --git a/src/Tools/BuildValidator/LocalSourceResolver.cs b/src/Tools/BuildValidator/LocalSourceResolver.cs index cb4928116d93e..a5fe7d187b83d 100644 --- a/src/Tools/BuildValidator/LocalSourceResolver.cs +++ b/src/Tools/BuildValidator/LocalSourceResolver.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Rebuild; using Microsoft.CodeAnalysis.Text; using Microsoft.Extensions.Logging; diff --git a/src/Tools/BuildValidator/Program.cs b/src/Tools/BuildValidator/Program.cs index a4ddb3c7d3751..f7a59276a6616 100644 --- a/src/Tools/BuildValidator/Program.cs +++ b/src/Tools/BuildValidator/Program.cs @@ -17,6 +17,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Rebuild; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Console; using Newtonsoft.Json; diff --git a/src/Tools/BuildValidator/Records.cs b/src/Tools/BuildValidator/Records.cs index f6a29b26ab5bc..b0c600999efb5 100644 --- a/src/Tools/BuildValidator/Records.cs +++ b/src/Tools/BuildValidator/Records.cs @@ -6,6 +6,7 @@ using System.IO; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; +using Microsoft.CodeAnalysis.Rebuild; using Microsoft.CodeAnalysis.Text; namespace BuildValidator diff --git a/src/Tools/ExternalAccess/FSharp/Internal/NavigateTo/FSharpNavigateToSearchService.cs b/src/Tools/ExternalAccess/FSharp/Internal/NavigateTo/FSharpNavigateToSearchService.cs index 26381b09c7926..ad6bf31991d68 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/NavigateTo/FSharpNavigateToSearchService.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/NavigateTo/FSharpNavigateToSearchService.cs @@ -32,7 +32,8 @@ public FSharpNavigateToSearchService(IFSharpNavigateToSearchService service) public async Task SearchDocumentAsync( Document document, string searchPattern, IImmutableSet kinds, - Func onResultFound, CancellationToken cancellationToken) + Func onResultFound, + bool isFullyLoaded, CancellationToken cancellationToken) { var results = await _service.SearchDocumentAsync(document, searchPattern, kinds, cancellationToken).ConfigureAwait(false); foreach (var result in results) @@ -41,7 +42,8 @@ public async Task SearchDocumentAsync( public async Task SearchProjectAsync( Project project, ImmutableArray priorityDocuments, string searchPattern, - IImmutableSet kinds, Func onResultFound, CancellationToken cancellationToken) + IImmutableSet kinds, Func onResultFound, + bool isFullyLoaded, CancellationToken cancellationToken) { var results = await _service.SearchProjectAsync(project, priorityDocuments, searchPattern, kinds, cancellationToken).ConfigureAwait(false); foreach (var result in results) diff --git a/src/Tools/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs b/src/Tools/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs index 284c0644799c2..158a8d99bb399 100644 --- a/src/Tools/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs +++ b/src/Tools/ExternalAccess/FSharp/Internal/Navigation/InternalFSharpNavigableItem.cs @@ -33,6 +33,8 @@ public InternalFSharpNavigableItem(FSharpNavigableItem item) public TextSpan SourceSpan { get; } + public bool IsStale => false; + public ImmutableArray ChildItems => ImmutableArray.Empty; } } diff --git a/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj b/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj index 3f01b08a719de..99384a461d79c 100644 --- a/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj +++ b/src/Tools/ExternalAccess/Razor/Microsoft.CodeAnalysis.ExternalAccess.Razor.csproj @@ -20,6 +20,8 @@ + + @@ -42,4 +44,4 @@ - \ No newline at end of file + diff --git a/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj b/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj index bbf9dd53d33d4..b065f2f981f14 100644 --- a/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj +++ b/src/Tools/IdeBenchmarks/IdeBenchmarks.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj b/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj index 96f5f69e160da..759610bb4ce53 100644 --- a/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj +++ b/src/Tools/IdeCoreBenchmarks/IdeCoreBenchmarks.csproj @@ -14,9 +14,11 @@ + + diff --git a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs index 95d25ea3856d2..d61028cb6b9ff 100644 --- a/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs +++ b/src/Tools/IdeCoreBenchmarks/NavigateToBenchmarks.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; @@ -31,8 +32,8 @@ public class NavigateToBenchmarks public NavigateToBenchmarks() { - var roslynRoot = Environment.GetEnvironmentVariable(Program.RoslynRootPathEnvVariableName); - _solutionPath = Path.Combine(roslynRoot, @"C:\github\roslyn\Compilers.sln"); + // var roslynRoot = Environment.GetEnvironmentVariable(Program.RoslynRootPathEnvVariableName); + _solutionPath = @"C:\github\roslyn\Roslyn.sln"; if (!File.Exists(_solutionPath)) throw new ArgumentException("Couldn't find Roslyn.sln"); @@ -74,6 +75,8 @@ public void Cleanup() [Benchmark] public async Task RunNavigateTo() { + var sw = new Stopwatch(); + sw.Start(); var solution = _workspace.CurrentSolution; // Search each project with an independent threadpool task. var searchTasks = solution.Projects.Select( @@ -81,23 +84,24 @@ public async Task RunNavigateTo() var result = await Task.WhenAll(searchTasks).ConfigureAwait(false); var sum = result.Sum(); + sw.Stop(); + + Console.WriteLine($"Time: {sw.ElapsedMilliseconds}"); } private async Task SearchAsync(Project project, ImmutableArray priorityDocuments) { var service = project.LanguageServices.GetService(); - var results = new List(); + var count = 0; await service.SearchProjectAsync( project, priorityDocuments, "Document", service.KindsProvided, r => { - lock (results) - results.Add(r); - + Interlocked.Increment(ref count); return Task.CompletedTask; - }, CancellationToken.None); + }, isFullyLoaded: true, CancellationToken.None); - return results.Count; + return count; } } } diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/BoundNodeClassWriter.cs b/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/BoundNodeClassWriter.cs index a3ede2a8fa14e..2ad56cefb8014 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/BoundNodeClassWriter.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/BoundTreeGenerator/BoundNodeClassWriter.cs @@ -783,9 +783,9 @@ private NullHandling FieldNullHandling(TreeType node, string fieldName) if (f.Null != null) { - if (_targetLang == TargetLanguage.CSharp && f.Null.ToUpperInvariant() == "ALLOW" && !f.Type.EndsWith('?') && !IsValueType(f.Type)) + if (_targetLang == TargetLanguage.CSharp && (f.Null.ToUpperInvariant() is ("ALLOW" or "ALWAYS")) && !f.Type.EndsWith('?') && !IsValueType(f.Type)) { - throw new ArgumentException($"Field '{fieldName}' on node '{node.Name}' should have a nullable type, since it isn't a value type and it is marked null=allow"); + throw new ArgumentException($"Field '{fieldName}' on node '{node.Name}' should have a nullable type, since it isn't a value type and it is marked null=allow or null=always"); } switch (f.Null.ToUpperInvariant()) @@ -828,7 +828,7 @@ private Field GetField(TreeType node, string fieldName) throw new InvalidOperationException($"Field {fieldName} not found in type {node.Name}"); } - private void WriteField(Field field) + private void WriteField(TreeType node, Field field) { switch (_targetLang) { @@ -842,13 +842,14 @@ private void WriteField(Field field) else if (field.Override) { // We emit a suppression here because the bound nodes use a pattern which is safe, but can't be tracked. + var suppression = FieldNullHandling(node, field.Name) is (NullHandling.Allow or NullHandling.Always) ? "" : "!"; // The point of overriding a property is to change its nullability, usually // from nullable to non-nullable. The base is annotated as nullable, // but since the base property is always set via the base call in the // constructor, as long as the parameter to the current class's constructor is not // nullable, the base property is always non-null. - WriteLine($"public new {field.Type} {field.Name} => base.{field.Name}!;"); + WriteLine($"public new {field.Type} {field.Name} => base.{field.Name}{suppression};"); } else { @@ -892,7 +893,6 @@ private void WriteAccept(string name) WriteLine("Return visitor.Visit{0}(Me)", StripBound(name)); Outdent(); WriteLine("End Function"); - break; default: @@ -922,7 +922,7 @@ private void WriteType(TreeType node) // Only C# can express nullable reference types foreach (var field in (_targetLang == TargetLanguage.CSharp ? FieldsIncludingOverrides(node) : Fields(node))) { - WriteField(field); + WriteField(node, field); } if (node is Node) { diff --git a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CachingSourceGenerator.cs b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CachingSourceGenerator.cs index 7a900e634bb2d..6872819048150 100644 --- a/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CachingSourceGenerator.cs +++ b/src/Tools/Source/CompilerGeneratorTools/Source/CSharpSyntaxGenerator/CachingSourceGenerator.cs @@ -7,7 +7,9 @@ using System; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; @@ -60,9 +62,21 @@ public void Execute(GeneratorExecutionContext context) if (diagnostics.IsEmpty) { + var result = new CachedSourceGeneratorResult(currentChecksum, sources); + + // Default Large Object Heap size threshold + // https://github.com/dotnet/runtime/blob/c9d69e38d0e54bea5d188593ef6c3b30139f3ab1/src/coreclr/src/gc/gc.h#L111 + const int Threshold = 85000; + // Overwrite the cached result with the new result. This is an opportunistic cache, so as long as - // the write is atomic (which it is for SetTarget) synchronization is unnecessary. - s_cachedResult.SetTarget(new CachedSourceGeneratorResult(currentChecksum, sources)); + // the write is atomic (which it is for SetTarget) synchronization is unnecessary. We allocate an + // array on the Large Object Heap (which is always part of Generation 2) and give it a reference to + // the cached object to ensure this weak reference is not reclaimed prior to a full GC pass. + var largeArray = new CachedSourceGeneratorResult[Threshold / Unsafe.SizeOf()]; + Debug.Assert(GC.GetGeneration(largeArray) >= 2); + largeArray[0] = result; + s_cachedResult.SetTarget(result); + GC.KeepAlive(largeArray); } else { diff --git a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx index f2327fc726e58..0f4ab0b7f04fc 100644 --- a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx +++ b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx @@ -373,8 +373,8 @@ Place _code snippets in completion lists - - Completion Lists + + Completion Selection In Completion List @@ -637,4 +637,7 @@ Allow blank line after colon in constructor initializer - + + Automatically complete statement on semicolon + + \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModel.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModel.cs new file mode 100644 index 0000000000000..18186ed974e12 --- /dev/null +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModel.cs @@ -0,0 +1,44 @@ +// 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 Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings +{ + internal class BinaryOperatorSpacingOptionsViewModel : EnumSettingViewModel + { + private readonly FormattingSetting _setting; + + public BinaryOperatorSpacingOptionsViewModel(FormattingSetting setting) + { + _setting = setting; + } + + protected override void ChangePropertyTo(BinaryOperatorSpacingOptions newValue) + { + _setting.SetValue(newValue); + } + + protected override BinaryOperatorSpacingOptions GetCurrentValue() + { + return (BinaryOperatorSpacingOptions)_setting.GetValue()!; + } + + protected override IReadOnlyDictionary GetValuesAndDescriptions() + { + return EnumerateOptions().ToDictionary(x => x.description, x => x.value); + + static IEnumerable<(string description, BinaryOperatorSpacingOptions value)> EnumerateOptions() + { + yield return (CSharpVSResources.Ignore_spaces_around_binary_operators, BinaryOperatorSpacingOptions.Ignore); + yield return (CSharpVSResources.Remove_spaces_before_and_after_binary_operators, BinaryOperatorSpacingOptions.Remove); + yield return (CSharpVSResources.Insert_space_before_and_after_binary_operators, BinaryOperatorSpacingOptions.Single); + } + } + } +} diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModelFactory.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModelFactory.cs new file mode 100644 index 0000000000000..6a5085101a91b --- /dev/null +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/BinaryOperatorSpacingOptionsViewModelFactory.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 System; +using System.Composition; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings +{ + [Export(typeof(IEnumSettingViewModelFactory)), Shared] + internal class BinaryOperatorSpacingOptionsViewModelFactory : IEnumSettingViewModelFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public BinaryOperatorSpacingOptionsViewModelFactory() + { + } + + public IEnumSettingViewModel CreateViewModel(FormattingSetting setting) + { + return new BinaryOperatorSpacingOptionsViewModel(setting); + } + + public bool IsSupported(OptionKey2 key) + => key.Option.Type == typeof(BinaryOperatorSpacingOptions); + } +} diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/LabelPositionOptionsViewModel.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/LabelPositionOptionsViewModel.cs new file mode 100644 index 0000000000000..bbbfcda4f07d9 --- /dev/null +++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/LabelPositionOptionsViewModel.cs @@ -0,0 +1,67 @@ +// 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.Composition; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Formatting; +using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings.Common; + +namespace Microsoft.VisualStudio.LanguageServices.CSharp.EditorConfigSettings +{ + + [Export(typeof(IEnumSettingViewModelFactory)), Shared] + internal class LabelPositionOptionsViewModelFactory : IEnumSettingViewModelFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public LabelPositionOptionsViewModelFactory() + { + } + + public IEnumSettingViewModel CreateViewModel(FormattingSetting setting) + { + return new LabelPositionOptionsViewModel(setting); + } + + public bool IsSupported(OptionKey2 key) + => key.Option.Type == typeof(LabelPositionOptions); + } + + internal class LabelPositionOptionsViewModel : EnumSettingViewModel + { + private readonly FormattingSetting _setting; + + public LabelPositionOptionsViewModel(FormattingSetting setting) + { + _setting = setting; + } + + protected override void ChangePropertyTo(LabelPositionOptions newValue) + { + _setting.SetValue(newValue); + } + + protected override LabelPositionOptions GetCurrentValue() + { + return (LabelPositionOptions)_setting.GetValue()!; + } + + protected override IReadOnlyDictionary GetValuesAndDescriptions() + { + return EnumerateOptions().ToDictionary(x => x.description, x => x.value); + + static IEnumerable<(string description, LabelPositionOptions value)> EnumerateOptions() + { + yield return ("place goto labels in leftmost column", LabelPositionOptions.LeftMost); + yield return ("indent labels normally", LabelPositionOptions.NoIndent); + yield return ("place goto labels one indent less than current", LabelPositionOptions.OneLess); + } + } + } +} diff --git a/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj b/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj index 8eb596e8f12be..3a8ea68c1b12b 100644 --- a/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj +++ b/src/VisualStudio/CSharp/Impl/Microsoft.VisualStudio.LanguageServices.CSharp.csproj @@ -15,18 +15,9 @@ false - - - + + + diff --git a/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml index 7c8d8cf6f865f..8de912a87e7e5 100644 --- a/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml +++ b/src/VisualStudio/CSharp/Impl/Options/IntelliSenseOptionPageControl.xaml @@ -13,7 +13,7 @@ + Header="{x:Static local:IntelliSenseOptionPageStrings.Option_Completion}"> + + - [Export(typeof(IOptionPersister))] internal sealed class LanguageSettingsPersister : ForegroundThreadAffinitizedObject, IVsTextManagerEvents4, IOptionPersister { private readonly IVsTextManager4 _textManager; @@ -49,15 +45,13 @@ internal sealed class LanguageSettingsPersister : ForegroundThreadAffinitizedObj /// /// We make sure this code is from the UI by asking for all in /// - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public LanguageSettingsPersister( IThreadingContext threadingContext, - [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, + IVsTextManager4 textManager, IGlobalOptionService optionService) : base(threadingContext, assertIsForeground: true) { - _textManager = (IVsTextManager4)serviceProvider.GetService(typeof(SVsTextManager)); + _textManager = textManager; _optionService = optionService; // TODO: make this configurable diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs new file mode 100644 index 0000000000000..7e534f45b9e57 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersisterProvider.cs @@ -0,0 +1,54 @@ +// 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 System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.TextManager.Interop; +using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; +using SAsyncServiceProvider = Microsoft.VisualStudio.Shell.Interop.SAsyncServiceProvider; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +{ + [Export(typeof(IOptionPersisterProvider))] + internal sealed class LanguageSettingsPersisterProvider : IOptionPersisterProvider + { + private readonly IThreadingContext _threadingContext; + private readonly IAsyncServiceProvider _serviceProvider; + private readonly IGlobalOptionService _optionService; + private LanguageSettingsPersister? _lazyPersister; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public LanguageSettingsPersisterProvider( + IThreadingContext threadingContext, + [Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider, + IGlobalOptionService optionService) + { + _threadingContext = threadingContext; + _serviceProvider = serviceProvider; + _optionService = optionService; + } + + public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) + { + if (_lazyPersister is not null) + { + return _lazyPersister; + } + + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var textManager = (IVsTextManager4?)await _serviceProvider.GetServiceAsync(typeof(SVsTextManager)).ConfigureAwait(true); + Assumes.Present(textManager); + + _lazyPersister ??= new LanguageSettingsPersister(_threadingContext, textManager, _optionService); + return _lazyPersister; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs index b37f26d496c78..e1582bef9a6e9 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersister.cs @@ -5,12 +5,11 @@ #nullable disable using System; -using System.ComponentModel.Composition; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; @@ -21,7 +20,6 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options /// /// Serializes options marked with to the local hive-specific registry. /// - [Export(typeof(IOptionPersister))] internal sealed class LocalUserRegistryOptionPersister : IOptionPersister { /// @@ -30,12 +28,16 @@ internal sealed class LocalUserRegistryOptionPersister : IOptionPersister private readonly object _gate = new(); private readonly RegistryKey _registryKey; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public LocalUserRegistryOptionPersister([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + public LocalUserRegistryOptionPersister(IThreadingContext threadingContext, IServiceProvider serviceProvider) { - // Starting in Dev16, the ILocalRegistry service behind this call is free-threaded, and since the service is offered by msenv.dll can be requested - // without any marshalling (explicit or otherwise) to the UI thread. + // Starting with Dev16, the ILocalRegistry service is expected to be free-threaded, and aquiring it from the + // global service provider is expected to complete without any UI thread marshaling requirements. However, + // since none of this is publicly documented, we keep this assertion for maximum compatibility assurance. + // https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.shell.vsregistry.registryroot + // https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.shell.interop.ilocalregistry + // https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.shell.interop.slocalregistry + threadingContext.ThrowIfNotOnUIThread(); + this._registryKey = VSRegistry.RegistryRoot(serviceProvider, __VsLocalRegistryType.RegType_UserSettings, writable: true); } diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs new file mode 100644 index 0000000000000..5e408cdbcccda --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Options/LocalUserRegistryOptionPersisterProvider.cs @@ -0,0 +1,46 @@ +// 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 System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.Shell; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options +{ + [Export(typeof(IOptionPersisterProvider))] + internal sealed class LocalUserRegistryOptionPersisterProvider : IOptionPersisterProvider + { + private readonly IThreadingContext _threadingContext; + private readonly IServiceProvider _serviceProvider; + private LocalUserRegistryOptionPersister? _lazyPersister; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public LocalUserRegistryOptionPersisterProvider( + IThreadingContext threadingContext, + [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + { + _threadingContext = threadingContext; + _serviceProvider = serviceProvider; + } + + public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) + { + if (_lazyPersister is not null) + { + return _lazyPersister; + } + + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + _lazyPersister ??= new LocalUserRegistryOptionPersister(_threadingContext, _serviceProvider); + return _lazyPersister; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs index 8ae75996ce521..a44ed3c153297 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs @@ -2,12 +2,9 @@ // 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.ComponentModel; -using System.ComponentModel.Composition; using System.Diagnostics; using System.Linq; using System.Reflection; @@ -16,11 +13,9 @@ using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServices.Setup; using Microsoft.VisualStudio.Settings; -using Microsoft.VisualStudio.Shell; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options @@ -28,14 +23,13 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options /// /// Serializes settings marked with to and from the user's roaming profile. /// - [Export(typeof(IOptionPersister))] internal sealed class RoamingVisualStudioProfileOptionPersister : ForegroundThreadAffinitizedObject, IOptionPersister { // NOTE: This service is not public or intended for use by teams/individuals outside of Microsoft. Any data stored is subject to deletion without warning. [Guid("9B164E40-C3A2-4363-9BC5-EB4039DEF653")] private class SVsSettingsPersistenceManager { }; - private readonly ISettingsManager _settingManager; + private readonly ISettingsManager? _settingManager; private readonly IGlobalOptionService _globalOptionService; /// @@ -49,14 +43,12 @@ private class SVsSettingsPersistenceManager { }; /// /// We make sure this code is from the UI by asking for all in /// - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RoamingVisualStudioProfileOptionPersister(IThreadingContext threadingContext, IGlobalOptionService globalOptionService, [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) - : base(threadingContext, assertIsForeground: true) // The GetService call requires being on the UI thread or else it will marshal and risk deadlock + public RoamingVisualStudioProfileOptionPersister(IThreadingContext threadingContext, IGlobalOptionService globalOptionService, ISettingsManager? settingsManager) + : base(threadingContext, assertIsForeground: true) { Contract.ThrowIfNull(globalOptionService); - _settingManager = (ISettingsManager)serviceProvider.GetService(typeof(SVsSettingsPersistenceManager)); + _settingManager = settingsManager; _globalOptionService = globalOptionService; // While the settings persistence service should be available in all SKUs it is possible an ISO shell author has undefined the @@ -71,7 +63,7 @@ public RoamingVisualStudioProfileOptionPersister(IThreadingContext threadingCont private System.Threading.Tasks.Task OnSettingChangedAsync(object sender, PropertyChangedEventArgs args) { - List optionsToRefresh = null; + List? optionsToRefresh = null; lock (_optionsToMonitorForChangesGate) { @@ -101,8 +93,10 @@ private System.Threading.Tasks.Task OnSettingChangedAsync(object sender, Propert return System.Threading.Tasks.Task.CompletedTask; } - private object GetFirstOrDefaultValue(OptionKey optionKey, IEnumerable roamingSerializations) + private object? GetFirstOrDefaultValue(OptionKey optionKey, IEnumerable roamingSerializations) { + Contract.ThrowIfNull(_settingManager); + // There can be more than 1 roaming location in the order of their priority. // When fetching a value, we iterate all of them until we find the first one that exists. // When persisting a value, we always use the first location. @@ -126,7 +120,7 @@ private object GetFirstOrDefaultValue(OptionKey optionKey, IEnumerable GetOrCreatePersisterAsync(CancellationToken cancellationToken) + { + if (_lazyPersister is not null) + { + return _lazyPersister; + } + + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var settingsManager = (ISettingsManager?)await _serviceProvider.GetServiceAsync(typeof(SVsSettingsPersistenceManager)).ConfigureAwait(true); + + _lazyPersister ??= new RoamingVisualStudioProfileOptionPersister(_threadingContext, _optionService, settingsManager); + return _lazyPersister; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/FileChangeTracker.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/FileChangeTracker.cs index ff92d82793e5c..7a41ce6cac66e 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/FileChangeTracker.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/FileChangeTracker.cs @@ -111,7 +111,8 @@ public Task StartFileChangeListeningAsync() { try { - return await ((IVsAsyncFileChangeEx)_fileChangeService).AdviseFileChangeAsync(_filePath, _fileChangeFlags, this).ConfigureAwait(false); + // TODO: Should we pass in cancellationToken here insead of CancellationToken.None? + return await ((IVsAsyncFileChangeEx)_fileChangeService).AdviseFileChangeAsync(_filePath, _fileChangeFlags, this, CancellationToken.None).ConfigureAwait(false); } catch (Exception e) when (ReportException(e)) { diff --git a/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/VisualStudioSemanticClassificationCacheService.cs b/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/VisualStudioSemanticClassificationCacheService.cs index de8ba6ee6c8a8..06322b7964a41 100644 --- a/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/VisualStudioSemanticClassificationCacheService.cs +++ b/src/VisualStudio/Core/Def/Implementation/SemanticClassificationCache/VisualStudioSemanticClassificationCacheService.cs @@ -51,7 +51,7 @@ public async Task> GetCachedSemanticClassificatio } var classifiedSpans = await client.TryInvokeAsync( - (service, cancellationToken) => service.GetCachedSemanticClassificationsAsync(documentKey.Dehydrate(), textSpan, checksum, cancellationToken), + (service, cancellationToken) => service.GetCachedSemanticClassificationsAsync(documentKey, textSpan, checksum, cancellationToken), cancellationToken).ConfigureAwait(false); if (!classifiedSpans.HasValue || classifiedSpans.Value == null) diff --git a/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs b/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs index f1243358170a9..d05d04721374c 100644 --- a/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs +++ b/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs @@ -23,6 +23,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -479,7 +480,7 @@ public virtual bool TryInsertExpansion(int startPositionInSubjectBuffer, int end } var buffer = EditorAdaptersFactoryService.GetBufferAdapter(textViewModel.DataBuffer); - if (buffer == null || !(buffer is IVsExpansion expansion)) + if (buffer is not IVsExpansion expansion) { return false; } @@ -495,6 +496,12 @@ public virtual bool TryInsertExpansion(int startPositionInSubjectBuffer, int end iEndIndex = endIndex }; + if (TryInsertArgumentCompletionSnippet(triggerSpan, dataBufferSpan, expansion, textSpan, cancellationToken)) + { + Debug.Assert(_state.IsFullMethodCallSnippet); + return true; + } + if (expansion.InsertExpansion(textSpan, textSpan, this, LanguageServiceGuid, out _state._expansionSession) == VSConstants.S_OK) { // This expansion is not derived from a symbol, so make sure the state isn't tracking any symbol @@ -503,6 +510,11 @@ public virtual bool TryInsertExpansion(int startPositionInSubjectBuffer, int end return true; } + return false; + } + + private bool TryInsertArgumentCompletionSnippet(SnapshotSpan triggerSpan, SnapshotSpan dataBufferSpan, IVsExpansion expansion, VsTextSpan textSpan, CancellationToken cancellationToken) + { if (!(SubjectBuffer.GetFeatureOnOffOption(CompletionOptions.EnableArgumentCompletionSnippets) ?? false)) { // Argument completion snippets are not enabled @@ -521,6 +533,7 @@ public virtual bool TryInsertExpansion(int startPositionInSubjectBuffer, int end var methodSymbols = symbols.OfType().ToImmutableArray(); if (methodSymbols.Any()) { + // This is the method name as it appears in source text var methodName = dataBufferSpan.GetText(); var snippet = CreateMethodCallSnippet(methodName, includeMethod: true, ImmutableArray.Empty, ImmutableDictionary.Empty, cancellationToken); @@ -530,7 +543,7 @@ public virtual bool TryInsertExpansion(int startPositionInSubjectBuffer, int end if (expansion.InsertSpecificExpansion(doc, textSpan, this, LanguageServiceGuid, pszRelativePath: null, out _state._expansionSession) == VSConstants.S_OK) { Debug.Assert(_state._expansionSession != null); - _state._methodNameForInsertFullMethodCall = methodName; + _state._methodNameForInsertFullMethodCall = methodSymbols.First().Name; Debug.Assert(_state._method == null); if (_signatureHelpControllerProvider.GetController(TextView, SubjectBuffer) is { } controller) @@ -722,7 +735,8 @@ private static async Task> GetReferencedSymbolsToLeftOfC CancellationToken cancellationToken) { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var token = await semanticModel.SyntaxTree.GetTouchingTokenAsync(caretPosition.Position, cancellationToken).ConfigureAwait(false); + + var token = await semanticModel.SyntaxTree.GetTouchingWordAsync(caretPosition.Position, document.GetRequiredLanguageService(), cancellationToken).ConfigureAwait(false); var semanticInfo = semanticModel.GetSemanticInfo(token, document.Project.Solution.Workspace, cancellationToken); return semanticInfo.ReferencedSymbols; } @@ -1167,8 +1181,8 @@ private sealed class State public IVsExpansionSession? _expansionSession; /// - /// The name of the method that we have invoked insert full method call on. Null if the session is - /// a regular snippets session. + /// The symbol name of the method that we have invoked insert full method call on; or + /// if there is no active snippet session or the active session is a regular snippets session. /// public string? _methodNameForInsertFullMethodCall; diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs index 00eb6e2070ef6..e487304dfe9f5 100644 --- a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs @@ -2,39 +2,30 @@ // 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.ComponentModel; -using System.ComponentModel.Composition; using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Shell.Interop; namespace Microsoft.VisualStudio.LanguageServices.Implementation.TaskList { - [Export(typeof(IOptionPersister))] internal class CommentTaskTokenSerializer : IOptionPersister { - private readonly ITaskList _taskList; + private readonly ITaskList? _taskList; private readonly IGlobalOptionService _globalOptionService; - private string _lastCommentTokenCache = null; + private string? _lastCommentTokenCache = null; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CommentTaskTokenSerializer( IGlobalOptionService globalOptionService, - [Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) + ITaskList? taskList) { _globalOptionService = globalOptionService; // The SVsTaskList may not be available or doesn't actually implement ITaskList // in the "devenv /build" scenario - _taskList = serviceProvider.GetService(typeof(SVsTaskList)) as ITaskList; + _taskList = taskList; // GetTaskTokenList is safe in the face of nulls _lastCommentTokenCache = GetTaskTokenList(_taskList); @@ -45,7 +36,7 @@ public CommentTaskTokenSerializer( } } - public bool TryFetch(OptionKey optionKey, out object value) + public bool TryFetch(OptionKey optionKey, out object? value) { value = string.Empty; if (optionKey != TodoCommentOptions.TokenList) @@ -57,7 +48,7 @@ public bool TryFetch(OptionKey optionKey, out object value) return true; } - public bool TryPersist(OptionKey optionKey, object value) + public bool TryPersist(OptionKey optionKey, object? value) { // it never persists return false; @@ -85,7 +76,7 @@ private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) _globalOptionService.RefreshOption(TodoCommentOptions.TokenList, _lastCommentTokenCache); } - private static string GetTaskTokenList(ITaskList taskList) + private static string GetTaskTokenList(ITaskList? taskList) { var commentTokens = taskList?.CommentTokens; if (commentTokens == null || commentTokens.Count == 0) @@ -101,7 +92,7 @@ private static string GetTaskTokenList(ITaskList taskList) continue; } - result.Add($"{commentToken.Text}:{((int)commentToken.Priority).ToString()}"); + result.Add($"{commentToken.Text}:{(int)commentToken.Priority}"); } return string.Join("|", result); diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs new file mode 100644 index 0000000000000..399ea1cb82607 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializerProvider.cs @@ -0,0 +1,54 @@ +// 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 System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Options; +using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; +using ITaskList = Microsoft.VisualStudio.Shell.ITaskList; +using SAsyncServiceProvider = Microsoft.VisualStudio.Shell.Interop.SAsyncServiceProvider; +using SVsTaskList = Microsoft.VisualStudio.Shell.Interop.SVsTaskList; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.TaskList +{ + [Export(typeof(IOptionPersisterProvider))] + internal sealed class CommentTaskTokenSerializerProvider : IOptionPersisterProvider + { + private readonly IThreadingContext _threadingContext; + private readonly IAsyncServiceProvider _serviceProvider; + private readonly IGlobalOptionService _optionService; + private CommentTaskTokenSerializer? _lazyPersister; + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CommentTaskTokenSerializerProvider( + IThreadingContext threadingContext, + [Import(typeof(SAsyncServiceProvider))] IAsyncServiceProvider serviceProvider, + IGlobalOptionService optionService) + { + _threadingContext = threadingContext; + _serviceProvider = serviceProvider; + _optionService = optionService; + } + + public async ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) + { + if (_lazyPersister is not null) + { + return _lazyPersister; + } + + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + // Not all SVsTaskList implementations implement ITaskList, but when it does we will use it + var taskList = await _serviceProvider.GetServiceAsync(typeof(SVsTaskList)).ConfigureAwait(true) as ITaskList; + _lazyPersister ??= new CommentTaskTokenSerializer(_optionService, taskList); + return _lazyPersister; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs index ff69e7f618317..29c0c6b63ced8 100644 --- a/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs +++ b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs @@ -218,7 +218,7 @@ public async ValueTask ReportTodoCommentDataAsync(DocumentId documentId, Immutab var workQueue = await _workQueueSource.Task.ConfigureAwait(false); workQueue.AddWork(new DocumentAndComments(documentId, infos)); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { // report NFW before returning back to the remote process throw ExceptionUtilities.Unreachable; diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioDocumentNavigationService.cs b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioDocumentNavigationService.cs index bebfce04b5a37..cb0f903ba132b 100644 --- a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioDocumentNavigationService.cs +++ b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioDocumentNavigationService.cs @@ -141,19 +141,19 @@ public bool CanNavigateToPosition(Workspace workspace, DocumentId documentId, in return CanMapFromSecondaryBufferToPrimaryBuffer(workspace, documentId, vsTextSpan); } - public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, CancellationToken cancellationToken) + public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, bool allowInvalidSpan, CancellationToken cancellationToken) { return TryNavigateToLocation(workspace, documentId, _ => textSpan, - text => GetVsTextSpan(text, textSpan), + text => GetVsTextSpan(text, textSpan, allowInvalidSpan), options, cancellationToken); - static VsTextSpan GetVsTextSpan(SourceText text, TextSpan textSpan) + static VsTextSpan GetVsTextSpan(SourceText text, TextSpan textSpan, bool allowInvalidSpan) { var boundedTextSpan = GetSpanWithinDocumentBounds(textSpan, text.Length); - if (boundedTextSpan != textSpan) + if (boundedTextSpan != textSpan && !allowInvalidSpan) { try { diff --git a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj index 5fab552e80282..1eb93e319b038 100644 --- a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj +++ b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj @@ -33,7 +33,7 @@ 6cf2e545-6109-4730-8883-cf43d7aec3e1 - + @@ -199,8 +199,7 @@ - + diff --git a/src/VisualStudio/Core/Def/PackageRegistration.pkgdef b/src/VisualStudio/Core/Def/PackageRegistration.pkgdef index 27e41b380e9ba..cf0c02e3f8465 100644 --- a/src/VisualStudio/Core/Def/PackageRegistration.pkgdef +++ b/src/VisualStudio/Core/Def/PackageRegistration.pkgdef @@ -24,3 +24,14 @@ "Value"=dword:00000000 "Title"="Enable experimental C#/VB LSP completion experience" "PreviewPaneChannels"="IntPreview,int.main" + +// 68b46364-d378-42f2-9e72-37d86c5f4468 is the guid for SettingsEditorFactory +// 6cf2e545-6109-4730-8883-cf43d7aec3e1 is the guid for RoslynPackage +[$RootKey$\Editors\{68b46364-d378-42f2-9e72-37d86c5f4468}] +"Package"="{6cf2e545-6109-4730-8883-cf43d7aec3e1}" +[$RootKey$\Editors\{68b46364-d378-42f2-9e72-37d86c5f4468}\Extensions] +// dword must be larger that 26 (the priority of the textmate editor) +// we set it to 100 (64 in hex) here +"editorconfig"=dword:00000064 +[$RootKey$\Editors\{68b46364-d378-42f2-9e72-37d86c5f4468}\LogicalViews] +"{7651a703-06e5-11d1-8ebd-00a0c90f26ea}"="" diff --git a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs index 89955807b932d..469440e01e35e 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs @@ -552,7 +552,7 @@ private async Task ProcessProjectChangeAsync( return new ProjectState(installedPackages.ToImmutableDictionary()); } - catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { return null; } diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs index 7261ce5c45d59..6839f66f2cf12 100644 --- a/src/VisualStudio/Core/Def/RoslynPackage.cs +++ b/src/VisualStudio/Core/Def/RoslynPackage.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Immutable; using System.ComponentModel.Design; using System.Diagnostics; using System.IO; @@ -24,6 +25,7 @@ using Microsoft.CodeAnalysis.Versions; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.LanguageServices.ColorSchemes; +using Microsoft.VisualStudio.LanguageServices.EditorConfigSettings; using Microsoft.VisualStudio.LanguageServices.Experimentation; using Microsoft.VisualStudio.LanguageServices.Implementation; using Microsoft.VisualStudio.LanguageServices.Implementation.DesignerAttribute; @@ -113,7 +115,10 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke Assumes.Present(_componentModel); // Ensure the options persisters are loaded since we have to fetch options from the shell - _componentModel.GetExtensions(); + foreach (var provider in await GetOptionPersistersAsync(_componentModel, cancellationToken).ConfigureAwait(true)) + { + _ = await provider.GetOrCreatePersisterAsync(cancellationToken).ConfigureAwait(true); + } _workspace = _componentModel.GetService(); _workspace.Services.GetService(); @@ -136,6 +141,18 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke _solutionEventMonitor = new SolutionEventMonitor(_workspace); TrackBulkFileOperations(); + + var settingsEditorFactory = _componentModel.GetService(); + RegisterEditorFactory(settingsEditorFactory); + + static async Task> GetOptionPersistersAsync(IComponentModel componentModel, CancellationToken cancellationToken) + { + // Switch to a background thread to ensure assembly loads don't show up as UI delays attributed to + // InitializeAsync. + await TaskScheduler.Default; + + return componentModel.GetExtensions().ToImmutableArray(); + } } private void InitializeColors() diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 46b3381616243..4b383c59a84d9 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -1653,4 +1653,55 @@ I agree to all of the foregoing: This action cannot be undone. Do you wish to continue? + + Analyzers + + + Carrage Return + Newline (\\r\\n) + + + Carrage Return (\\r) + + + Category + + + Code Style + + + Disabled + + + Enabled + + + Error + + + Formatting + + + Id + + + Newline (\\n) + + + Refactoring Only + + + Suggestion + + + Title + + + Value + + + Warning + + + Search Settings + \ No newline at end of file diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index b5189e1a7fc45..78d2b64d74833 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -77,6 +77,11 @@ Vždy kvůli srozumitelnosti + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Lokalita volání + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Dokončila se analýza kódu pro {0}. @@ -217,6 +242,11 @@ Aktuální parametr + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Při podržení kláves Alt+F1 zobrazit všechny nápovědy @@ -267,6 +297,11 @@ Povolit diagnostiku pull (experimentální, vyžaduje restart) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Zadejte hodnotu místa volání, nebo zvolte jiný druh vložení hodnoty. @@ -282,6 +317,11 @@ Celé řešení + + Error + Error + + Evaluating ({0} tasks in queue) Vyhodnocování (počet úloh ve frontě: {0}) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Generovat soubor .editorconfig z nastavení @@ -312,6 +357,11 @@ Zvýrazňovat související komponenty pod kurzorem + + Id + Id + + In other operators V jiných operátorech @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Stáhnout členy + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Uložit soubor .editorconfig + + Search Settings + Search Settings + + Select destination Vybrat cíl @@ -917,6 +982,11 @@ Některé barvy barevného schématu se přepsaly změnami na stránce možností Prostředí > Písma a barvy. Pokud chcete zrušit všechna přizpůsobení, vyberte na stránce Písma a barvy možnost Použít výchozí. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Potlačit nápovědy, když název parametru odpovídá záměru metody @@ -967,6 +1037,11 @@ Toto je neplatný obor názvů. + + Title + Title + + Type name: Název typu: @@ -1027,6 +1102,11 @@ Použít pojmenovaný argument "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Zde přiřazená hodnota se nikdy nepoužije. @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Upozornění: duplicitní název parametru diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index 6bf8f12101348..e60716fd3d02b 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -77,6 +77,11 @@ Immer zur besseren Unterscheidung + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Aufrufsite + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Die Codeanalyse für "{0}" wurde abgeschlossen. @@ -217,6 +242,11 @@ Aktueller Parameter + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Alle Hinweise beim Drücken von ALT+F1 anzeigen @@ -267,6 +297,11 @@ Pull-Diagnose aktivieren (experimentell, Neustart erforderlich) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Geben Sie einen Aufrufsitewert ein, oder wählen Sie eine andere Art der Werteingabe aus. @@ -282,6 +317,11 @@ Gesamte Projektmappe + + Error + Error + + Evaluating ({0} tasks in queue) Auswertung ({0} Tasks in der Warteschlange) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings EDITORCONFIG-Datei aus Einstellungen generieren @@ -312,6 +357,11 @@ Zugehörige Komponenten unter dem Cursor markieren + + Id + Id + + In other operators In anderen Operatoren @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Member nach oben ziehen + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ EDITORCONFIG-Datei speichern + + Search Settings + Search Settings + + Select destination Ziel auswählen @@ -917,6 +982,11 @@ Einige Farbschemafarben werden durch Änderungen überschrieben, die auf der Optionsseite "Umgebung" > "Schriftarten und Farben" vorgenommen wurden. Wählen Sie auf der Seite "Schriftarten und Farben" die Option "Standardwerte verwenden" aus, um alle Anpassungen rückgängig zu machen. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Hinweise unterdrücken, wenn der Parametername mit der Methodenabsicht übereinstimmt @@ -967,6 +1037,11 @@ Dies ist ein ungültiger Namespace. + + Title + Title + + Type name: Typenname: @@ -1027,6 +1102,11 @@ Benanntes Argument verwenden "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Der hier zugewiesene Wert wird nie verwendet. @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Warnung: doppelter Parametername diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 0773ae1ab3d10..42add4119c7dd 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -77,6 +77,11 @@ Siempre por claridad + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Sitio de llamada + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. El análisis de código se ha completado para "{0}". @@ -217,6 +242,11 @@ Parámetro actual + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Mostrar todas las sugerencias al presionar Alt+F1 @@ -267,6 +297,11 @@ Habilitar diagnósticos "pull" (experimental, requiere reiniciar) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Escriba un valor de sitio de llamada o elija otro tipo de inserción de valor. @@ -282,6 +317,11 @@ Toda la solución + + Error + Error + + Evaluating ({0} tasks in queue) Evaluando ({0} tareas en cola) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Generar archivo .editorconfig a partir de la configuración @@ -312,6 +357,11 @@ Resaltar componentes relacionados bajo el cursor + + Id + Id + + In other operators En otros operadores @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Extraer miembros + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Guardar archivo .editorconfig + + Search Settings + Search Settings + + Select destination Seleccionar destino @@ -917,6 +982,11 @@ Algunos de los colores de la combinación se reemplazan por los cambios realizados en la página de opciones de Entorno > Fuentes y colores. Elija "Usar valores predeterminados" en la página Fuentes y colores para revertir todas las personalizaciones. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Suprimir las sugerencias cuando el nombre del parámetro coincida con la intención del método @@ -967,6 +1037,11 @@ Este espacio de nombres no es válido + + Title + Title + + Type name: Nombre de tipo: @@ -1027,6 +1102,11 @@ Usar argumento con nombre "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used El valor asignado aquí no se usa nunca @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Advertencia: Nombre de parámetro duplicado diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index 66ca64f575e7b..ce66c20ea3ed9 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -77,6 +77,11 @@ Toujours pour plus de clarté + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Site d'appel + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Analyse du code effectuée pour '{0}'. @@ -217,6 +242,11 @@ Paramètre actuel + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Afficher tous les indicateurs en appuyant sur Alt+F1 @@ -267,6 +297,11 @@ Activer les diagnostics de 'tirage (pull)' (expérimental, nécessite un redémarrage) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Entrer une valeur de site d'appel ou choisir un autre type d'injection de valeur @@ -282,6 +317,11 @@ Solution complète + + Error + Error + + Evaluating ({0} tasks in queue) Évaluation ({0} tâches en file d'attente) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Générer le fichier .editorconfig à partir des paramètres @@ -312,6 +357,11 @@ Surligner les composants liés sous le curseur + + Id + Id + + In other operators Dans les autres opérateurs @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Élever les membres + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Enregistrer le fichier .editorconfig + + Search Settings + Search Settings + + Select destination Sélectionner la destination @@ -917,6 +982,11 @@ Certaines couleurs du modèle de couleurs sont substituées à la suite des changements apportés dans la page d'options Environnement > Polices et couleurs. Choisissez Utiliser les valeurs par défaut dans la page Polices et couleurs pour restaurer toutes les personnalisations. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Supprimer les indicateurs quand le nom de paramètre correspond à l'intention de la méthode @@ -967,6 +1037,11 @@ Ceci est un espace de noms non valide + + Title + Title + + Type name: Nom du type : @@ -1027,6 +1102,11 @@ Utiliser un argument nommé "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used La valeur affectée ici n'est jamais utilisée @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Avertissement : Nom de paramètre dupliqué diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index 84d6b5b8418ce..72a65ec3d00c1 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -77,6 +77,11 @@ Sempre per chiarezza + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Sito di chiamata + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Esecuzione di Code Analysis completata per '{0}'. @@ -217,6 +242,11 @@ Parametro corrente + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Visualizza tutti i suggerimenti quando si preme ALT+F1 @@ -267,6 +297,11 @@ Abilita diagnostica 'pull' (sperimentale, richiede il riavvio) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Immettere un valore per il sito di chiamata o scegliere un tipo di inserimento valori diverso @@ -282,6 +317,11 @@ Intera soluzione + + Error + Error + + Evaluating ({0} tasks in queue) In fase di valutazione ({0} attività in coda) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Genera file con estensione editorconfig dalle impostazioni @@ -312,6 +357,11 @@ Evidenzia i componenti correlati sotto il cursore + + Id + Id + + In other operators In altri operatori @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Recupera membri + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Salva file con estensione editorconfig + + Search Settings + Search Settings + + Select destination Seleziona destinazione @@ -917,6 +982,11 @@ Alcuni colori della combinazione colori sono sostituiti dalle modifiche apportate nella pagina di opzioni Ambiente > Tipi di carattere e colori. Scegliere `Usa impostazioni predefinite` nella pagina Tipi di carattere e colori per ripristinare tutte le personalizzazioni. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Non visualizzare suggerimenti quando il nome del parametro corrisponde alla finalità del metodo @@ -967,6 +1037,11 @@ Questo è uno spazio dei nomi non valido + + Title + Title + + Type name: Nome del tipo: @@ -1027,6 +1102,11 @@ Usa l'argomento denominato "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Il valore assegnato qui non viene mai usato @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Avviso: nome di parametro duplicato diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index 0c2d35a055059..7f21ef693eaec 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -77,6 +77,11 @@ わかりやすくするために常に + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ 呼び出しサイト + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. '{0}' のコード分析が完了しました。 @@ -217,6 +242,11 @@ 現在のパラメーター + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Alt+F1 を押しながらすべてのヒントを表示する @@ -267,6 +297,11 @@ 'pull' 診断を有効にする (試験段階、再起動が必要) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind 呼び出しサイトの値を入力するか、別の値の挿入の種類を選択してください @@ -282,6 +317,11 @@ ソリューション全体 + + Error + Error + + Evaluating ({0} tasks in queue) 評価中 ({0} 個のタスクがキューにあります) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings 設定から .editorconfig ファイルを生成 @@ -312,6 +357,11 @@ カーソルの下にある関連コンポーネントをハイライトする + + Id + Id + + In other operators その他の演算子内で @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ メンバーをプルアップ + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ .editorconfig ファイルの保存 + + Search Settings + Search Settings + + Select destination 宛先の選択 @@ -917,6 +982,11 @@ 一部の配色パターンの色は、[環境] > [フォントおよび色] オプション ページで行われた変更によって上書きされます。[フォントおよび色] オプション ページで [既定値を使用] を選択すると、すべてのカスタマイズが元に戻ります。 + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent パラメーター名がメソッドの意図と一致する場合にヒントを非表示にする @@ -967,6 +1037,11 @@ これは無効な名前空間です + + Title + Title + + Type name: 種類の名前: @@ -1027,6 +1102,11 @@ 名前付き引数を使用する "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used ここで割り当てた値は一度も使用されません @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name 警告: パラメーター名が重複しています diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index c9dffedffb7a8..2e500eba7fddc 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -77,6 +77,11 @@ 명확하게 하기 위해 항상 + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ 호출 사이트 + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. '{0}'에 대한 코드 분석이 완료되었습니다. @@ -217,6 +242,11 @@ 현재 매개 변수 + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Alt+F1을 누른 채 모든 힌트 표시 @@ -267,6 +297,11 @@ '풀' 진단 사용(실험적, 다시 시작 필요) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind 호출 사이트 값을 입력하거나 다른 값 삽입 종류를 선택하세요. @@ -282,6 +317,11 @@ 전체 솔루션 + + Error + Error + + Evaluating ({0} tasks in queue) 평가 중(큐의 {0}개 작업) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings 설정에서 .editorconfig 파일 생성 @@ -312,6 +357,11 @@ 커서 아래의 관련 구성 요소 강조 + + Id + Id + + In other operators 기타 연산자 @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ 멤버 풀하기 + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ editorconfig 파일 저장 + + Search Settings + Search Settings + + Select destination 대상 선택 @@ -917,6 +982,11 @@ 색 구성표의 일부 색이 [환경] > [글꼴 및 색] 옵션 페이지에서 변경한 내용에 따라 재정의됩니다. 모든 사용자 지정을 되돌리려면 [글꼴 및 색] 페이지에서 '기본값 사용'을 선택하세요. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent 매개 변수 이름이 메서드의 의도와 일치하는 경우 힌트 표시 안 함 @@ -967,6 +1037,11 @@ 잘못된 네임스페이스입니다. + + Title + Title + + Type name: 형식 이름: @@ -1027,6 +1102,11 @@ 명명된 인수 사용 "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used 여기에 할당된 값은 사용되지 않습니다. @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name 경고: 매개 변수 이름이 중복되었습니다. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index 7ec15693ddf5f..b5b68596d83b9 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -77,6 +77,11 @@ Zawsze w celu zachowania jednoznaczności + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Miejsce wywołania + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Ukończono analizę kodu dla elementu „{0}”. @@ -217,6 +242,11 @@ Bieżący parametr + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Wyświetl wszystkie wskazówki po naciśnięciu klawiszy Alt+F1 @@ -267,6 +297,11 @@ Włącz diagnostykę operacji „pull” (eksperymentalne, wymaga ponownego uruchomienia) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Wprowadź wartość lokalizacji wywołania lub wybierz inny rodzaj iniekcji wartości @@ -282,6 +317,11 @@ Całe rozwiązanie + + Error + Error + + Evaluating ({0} tasks in queue) Szacowanie (zadania w kolejce: {0}) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Wygeneruj plik .editorconfig na podstawie ustawień @@ -312,6 +357,11 @@ Wyróżnij powiązane składniki pod kursorem + + Id + Id + + In other operators W innych operatorach @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Podciągnij składowe w górę + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Zapisz plik .editorconfig + + Search Settings + Search Settings + + Select destination Wybierz miejsce docelowe @@ -917,6 +982,11 @@ Niektóre kolory w schemacie kolorów są przesłaniane przez zmiany wprowadzone na stronie opcji Środowisko > Czcionki i kolory. Wybierz pozycję „Użyj ustawień domyślnych” na stronie Czcionki i kolory, aby wycofać wszystkie dostosowania. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Pomiń wskazówki, gdy nazwa parametru pasuje do intencji metody @@ -967,6 +1037,11 @@ To jest nieprawidłowa przestrzeń nazw + + Title + Title + + Type name: Nazwa typu: @@ -1027,6 +1102,11 @@ Użyj nazwanego argumentu "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Przypisana tu wartość nigdy nie jest używana @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Ostrzeżenie: zduplikowana nazwa parametru diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index e81125728c3a4..ca39ce2664ea6 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -77,6 +77,11 @@ Sempre para esclarecimento + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Chamar site + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Análise de código concluída para '{0}'. @@ -217,6 +242,11 @@ Parâmetro atual + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Exibir todas as dicas ao pressionar Alt+F1 @@ -267,6 +297,11 @@ Habilitar o diagnóstico de 'pull' (experimental, exige uma reinicialização) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Insira um valor de site de chamada ou escolha um tipo de injeção de valor diferente @@ -282,6 +317,11 @@ Solução Inteira + + Error + Error + + Evaluating ({0} tasks in queue) Avaliando ({0} tarefas na fila) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Gerar o arquivo .editorconfig das configurações @@ -312,6 +357,11 @@ Realçar componentes relacionados usando o cursor + + Id + Id + + In other operators Em outros operadores @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Levantar os membros + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Salvar arquivo .editorconfig + + Search Settings + Search Settings + + Select destination Selecionar destino @@ -917,6 +982,11 @@ Algumas cores do esquema de cores estão sendo substituídas pelas alterações feitas na página de Ambiente > Opções de Fontes e Cores. Escolha 'Usar Padrões' na página Fontes e Cores para reverter todas as personalizações. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Suprimir as dicas quando o nome do parâmetro corresponder à intenção do método @@ -967,6 +1037,11 @@ Este é um namespace inválido + + Title + Title + + Type name: Nome do tipo: @@ -1027,6 +1102,11 @@ Usar argumento nomeado "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used O valor atribuído aqui nunca é usado @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Aviso: nome de parâmetro duplicado diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index e69cabe68805d..185ab2ad080a5 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -77,6 +77,11 @@ Всегда использовать для ясности + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Место вызова + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. Анализ кода для "{0}" выполнен. @@ -217,6 +242,11 @@ Текущий параметр + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Отображать все подсказки при нажатии клавиш ALT+F1 @@ -267,6 +297,11 @@ Включить диагностику "pull" (экспериментальная функция, требуется перезапуск) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Введите значение места вызова или выберите другой тип введения значения @@ -282,6 +317,11 @@ Все решение + + Error + Error + + Evaluating ({0} tasks in queue) Оценка (задач в очереди: {0}) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Создать файл EDITORCONFIG на основе параметров @@ -312,6 +357,11 @@ Выделить связанные компоненты под курсором + + Id + Id + + In other operators В других операторах @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Повышение элементов + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ Сохранить файл EDITORCONFIG + + Search Settings + Search Settings + + Select destination Выбрать место назначения @@ -917,6 +982,11 @@ Некоторые цвета цветовой схемы переопределяются изменениями, сделанными на странице "Среда" > "Шрифты и цвета". Выберите "Использовать значения по умолчанию" на странице "Шрифты и цвета", чтобы отменить все настройки. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Скрывать подсказки, если имя параметра соответствует намерению метода. @@ -967,6 +1037,11 @@ Это недопустимое пространство имен. + + Title + Title + + Type name: Имя типа: @@ -1027,6 +1102,11 @@ Использовать именованный аргумент "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Заданное здесь значение не используется. @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Предупреждение: повторяющееся имя параметра. diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index 0fb7479558408..72f968d5f2ff6 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -77,6 +77,11 @@ Açıklık sağlamak için her zaman + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ Çağrı konumu + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. '{0}' için kod analizi tamamlandı. @@ -217,6 +242,11 @@ Geçerli parametre + + Disabled + Disabled + + Display all hints while pressing Alt+F1 Alt+F1 tuşlarına basılırken tüm ipuçlarını görüntüle @@ -267,6 +297,11 @@ 'Pull' tanılamasını etkinleştir (deneysel, yeniden başlatma gerekir) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind Bir çağrı sitesi değeri girin veya farklı bir değer yerleştirme tipi seçin @@ -282,6 +317,11 @@ Tüm çözüm + + Error + Error + + Evaluating ({0} tasks in queue) Değerlendiriliyor (kuyrukta {0} görev var) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings Ayarlardan .editorconfig dosyası oluştur @@ -312,6 +357,11 @@ İmlecin altında ilgili bileşenleri vurgula + + Id + Id + + In other operators Diğer işleçlerde @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ Üyeleri Yukarı Çek + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ .editorconfig dosyasını kaydet + + Search Settings + Search Settings + + Select destination Hedef seçin @@ -917,6 +982,11 @@ Bazı renk düzeni renkleri, Ortam > Yazı Tipleri ve Renkler seçenek sayfasında yapılan değişiklikler tarafından geçersiz kılınıyor. Tüm özelleştirmeleri geri döndürmek için Yazı Tipleri ve Renkler sayfasında `Varsayılanları Kullan` seçeneğini belirleyin. + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent Parametre adı metodun hedefi ile eşleştiğinde ipuçlarını gizle @@ -967,6 +1037,11 @@ Bu geçersiz bir ad alanı + + Title + Title + + Type name: Tür adı: @@ -1027,6 +1102,11 @@ Adlandırılmış bağımsız değişken kullan "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used Burada atanan değer hiçbir zaman kullanılmadı @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name Uyarı: Yinelenen parametre adı diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index 444999fa40114..81c3fdd8502ae 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -77,6 +77,11 @@ 为始终保持清楚起见 + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ 调用站点 + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. “{0}”的代码分析已完成。 @@ -217,6 +242,11 @@ 当前参数 + + Disabled + Disabled + + Display all hints while pressing Alt+F1 按 Alt+F1 时显示所有提示 @@ -267,6 +297,11 @@ 启用“拉取”诊断(实验性,需要重启) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind 输入调用站点值或选择其他值注入类型 @@ -282,6 +317,11 @@ 整个解决方案 + + Error + Error + + Evaluating ({0} tasks in queue) 正在评估(队列中有 {0} 个任务) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings 基于设置生成 .editorconfig 文件 @@ -312,6 +357,11 @@ 突出显示光标下的相关组件 + + Id + Id + + In other operators 在其他运算符中 @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ 拉取成员 + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ 保存 .editorconfig 文件 + + Search Settings + Search Settings + + Select destination 选择目标 @@ -917,6 +982,11 @@ 在“环境”>“字体和颜色”选项页中所做的更改将替代某些配色方案颜色。在“字体和颜色”页中选择“使用默认值”,还原所有自定义项。 + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent 当参数名称与方法的意图匹配时禁止显示提示 @@ -967,6 +1037,11 @@ 这是一个无效的命名空间 + + Title + Title + + Type name: 类型名称: @@ -1027,6 +1102,11 @@ 使用命名参数 "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used 此处分配的值从未使用过 @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name 警告: 参数名重复 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index b4e5db7539867..eafb48be3a897 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -77,6 +77,11 @@ 一律使用以明確表示 + + Analyzers + Analyzers + + Analyzing project references... Analyzing project references... @@ -157,11 +162,31 @@ 呼叫網站 + + Carrage Return + Newline (\\r\\n) + Carrage Return + Newline (\\r\\n) + + + + Carrage Return (\\r) + Carrage Return (\\r) + + + + Category + Category + + Choose which action you would like to perform on the unused references. Choose which action you would like to perform on the unused references. + + Code Style + Code Style + + Code analysis completed for '{0}'. '{0}' 的程式碼分析已完成。 @@ -217,6 +242,11 @@ 目前的參數 + + Disabled + Disabled + + Display all hints while pressing Alt+F1 按 Alt+F1 時顯示所有提示 @@ -267,6 +297,11 @@ 啟用 'pull' 診斷 (實驗性,需要重新啟動) + + Enabled + Enabled + + Enter a call site value or choose a different value injection kind 請輸入呼叫位置值,或選擇其他值插入種類 @@ -282,6 +317,11 @@ 整個解決方案 + + Error + Error + + Evaluating ({0} tasks in queue) 正在評估 (佇列中的 {0} 工作) @@ -302,6 +342,11 @@ Format document + + Formatting + Formatting + + Generate .editorconfig file from settings 從設定產生 .editorconfig 檔案 @@ -312,6 +357,11 @@ 反白資料指標下的相關元件 + + Id + Id + + In other operators 其他運算子中 @@ -612,6 +662,11 @@ New line preferences (experimental): + + Newline (\\n) + Newline (\\n) + + No unused references were found. No unused references were found. @@ -757,6 +812,11 @@ 提升成員 + + Refactoring Only + Refactoring Only + + Reference Reference @@ -842,6 +902,11 @@ 儲存 .editorconfig 檔案 + + Search Settings + Search Settings + + Select destination 選取目的地 @@ -917,6 +982,11 @@ [環境] > [字型和色彩選項] 頁面中所做的變更覆寫了某些色彩配置的色彩。請選擇 [字型和色彩] 頁面中的 [使用預設] 來還原所有自訂。 + + Suggestion + Suggestion + + Suppress hints when parameter name matches the method's intent 當參數名稱符合方法的意圖時,不出現提示 @@ -967,6 +1037,11 @@ 這是無效的命名空間 + + Title + Title + + Type name: 類型名稱: @@ -1027,6 +1102,11 @@ 使用具名引數 "argument" is a programming term for a value passed to a function + + Value + Value + + Value assigned here is never used 這裡指派的值從未使用過 @@ -1057,6 +1137,11 @@ Visual Studio 2019 + + Warning + Warning + + Warning: duplicate parameter name 警告: 參數名稱重複 diff --git a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProjectFactory.cs b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProjectFactory.cs index 5857e66907340..7d2aa93f7c6f2 100644 --- a/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProjectFactory.cs +++ b/src/VisualStudio/Core/Impl/ProjectSystem/CPS/CPSProjectFactory.cs @@ -58,7 +58,7 @@ public async Task CreateProjectContextAsync( string binOutputPath, CancellationToken cancellationToken) { - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var creationInfo = new VisualStudioProjectCreationInfo { diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs index a002ab577a59b..ce9a3a34c4740 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/SourceGeneratedFileItems/SourceGeneratedFileItemSource.cs @@ -73,7 +73,7 @@ private async Task UpdateSourceGeneratedFileItemsAsync(Solution solution, Cancel var sourceGeneratedDocumentsForGeneratorById = sourceGeneratedDocuments.Where(d => d.SourceGenerator == _parentGeneratorItem.Generator).ToDictionary(d => d.Id); // We must update the list on the UI thread, since the WPF elements bound to our list expect that - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); + await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); try { diff --git a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs index 235f616df98a6..8862614262558 100644 --- a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.DesignerAttribute; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments; using Microsoft.CodeAnalysis.Editor.UnitTests.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Options; @@ -24,6 +25,7 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.TodoComments; using Microsoft.CodeAnalysis.UnitTests; +using Microsoft.VisualStudio.Threading; using Nerdbank.Streams; using Roslyn.Test.Utilities; using Roslyn.Utilities; @@ -121,6 +123,7 @@ public async Task TestTodoComments() // TODO: Test"; using var workspace = CreateWorkspace(); + workspace.SetOptions(workspace.Options.WithChangedOption(TodoCommentOptions.TokenList, "HACK:1|TODO:1|UNDONE:1|UnresolvedMergeConflict:0")); workspace.InitializeDocuments(LanguageNames.CSharp, files: new[] { source }, openDocuments: false); using var client = await InProcRemoteHostClient.GetTestClientAsync(workspace).ConfigureAwait(false); @@ -142,7 +145,7 @@ public async Task TestTodoComments() (service, callbackId, cancellationToken) => service.ComputeTodoCommentsAsync(callbackId, cancellationToken), cancellationTokenSource.Token); - var data = await callback.Data; + var data = await callback.Data.WithTimeout(TimeSpan.FromMinutes(1)); Assert.Equal(solution.Projects.Single().Documents.Single().Id, data.Item1); Assert.Equal(1, data.Item2.Length); diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpArgumentProvider.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpArgumentProvider.cs index 705cb61770764..99237db591d1b 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpArgumentProvider.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpArgumentProvider.cs @@ -57,6 +57,83 @@ public void Method() VisualStudio.Editor.Verify.CurrentLineText("f.ToString()$$", assertCaretPosition: true); } + [WpfFact] + public void TabTabCompleteObjectEquals() + { + SetUpEditor(@" +public class Test +{ + public void Method() + { + $$ + } +} +"); + + VisualStudio.Editor.SendKeys("object.Equ"); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Editor.Verify.CurrentLineText("object.Equals$$", assertCaretPosition: true); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Workspace.WaitForAllAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.SignatureHelp); + VisualStudio.Editor.Verify.CurrentLineText("object.Equals(null$$)", assertCaretPosition: true); + } + + [WpfFact] + public void TabTabCompleteNewObject() + { + SetUpEditor(@" +public class Test +{ + public void Method() + { + var value = $$ + } +} +"); + + VisualStudio.Editor.SendKeys("new obje"); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Editor.Verify.CurrentLineText("var value = new object$$", assertCaretPosition: true); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Workspace.WaitForAllAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.SignatureHelp); + VisualStudio.Editor.Verify.CurrentLineText("var value = new object($$)", assertCaretPosition: true); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Editor.Verify.CurrentLineText("var value = new object()$$", assertCaretPosition: true); + } + + [WpfFact] + public void TabTabBeforeSemicolon() + { + SetUpEditor(@" +public class Test +{ + private object f; + + public void Method() + { + $$; + } +} +"); + + VisualStudio.Editor.SendKeys("f.ToSt"); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Editor.Verify.CurrentLineText("f.ToString$$;", assertCaretPosition: true); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Workspace.WaitForAllAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.SignatureHelp); + VisualStudio.Editor.Verify.CurrentLineText("f.ToString($$);", assertCaretPosition: true); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Editor.Verify.CurrentLineText("f.ToString()$$;", assertCaretPosition: true); + } + [WpfFact] public void TabTabCompletionWithArguments() { diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpFormatting.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpFormatting.cs index c44530d4f5661..a2c2b77349327 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpFormatting.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpFormatting.cs @@ -249,8 +249,7 @@ static void Main() }"); } - [WpfFact(Skip = "https://github.com/dotnet/roslyn/issues/18065"), - Trait(Traits.Feature, Traits.Features.Formatting)] + [WpfFact, Trait(Traits.Feature, Traits.Features.Formatting)] public void ShiftEnterWithIntelliSenseAndBraceMatching() { SetUpEditor(@" diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicArgumentProvider.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicArgumentProvider.cs index 3dd8e176c3b14..86d0af4ea63aa 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicArgumentProvider.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicArgumentProvider.cs @@ -55,6 +55,51 @@ End Class VisualStudio.Editor.Verify.CurrentLineText("f.ToString()$$", assertCaretPosition: true); } + [WpfFact] + public void TabTabCompleteObjectEquals() + { + SetUpEditor(@" +Public Class Test + Public Sub Method() + $$ + End Sub +End Class +"); + + VisualStudio.Editor.SendKeys("Object.Equ"); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Editor.Verify.CurrentLineText("Object.Equals$$", assertCaretPosition: true); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Workspace.WaitForAllAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.SignatureHelp); + VisualStudio.Editor.Verify.CurrentLineText("Object.Equals(Nothing$$)", assertCaretPosition: true); + } + + [WpfFact] + public void TabTabCompleteNewObject() + { + SetUpEditor(@" +Public Class Test + Public Sub Method() + Dim value = $$ + End Sub +End Class +"); + + VisualStudio.Editor.SendKeys("New Obje"); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Editor.Verify.CurrentLineText("Dim value = New Object$$", assertCaretPosition: true); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Workspace.WaitForAllAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.SignatureHelp); + VisualStudio.Editor.Verify.CurrentLineText("Dim value = New Object($$)", assertCaretPosition: true); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Editor.Verify.CurrentLineText("Dim value = New Object()$$", assertCaretPosition: true); + } + [WpfFact] public void TabTabCompletionWithArguments() { diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicAutomaticBraceCompletion.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicAutomaticBraceCompletion.cs index 9684b520b4096..324d5b96ff05f 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicAutomaticBraceCompletion.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/VisualBasic/BasicAutomaticBraceCompletion.cs @@ -5,12 +5,12 @@ #nullable disable using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.IntegrationTest.Utilities; using Microsoft.VisualStudio.IntegrationTest.Utilities.Input; using Roslyn.Test.Utilities; using Xunit; -using Xunit.Abstractions; namespace Roslyn.VisualStudio.IntegrationTests.VisualBasic { @@ -24,9 +24,11 @@ public BasicAutomaticBraceCompletion(VisualStudioInstanceFactory instanceFactory { } - [WpfFact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] - public void Braces_InsertionAndTabCompleting() + [WpfTheory, CombinatorialData, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] + public void Braces_InsertionAndTabCompleting(bool argumentCompletion) { + VisualStudio.Workspace.SetArgumentCompletionSnippetsOption(argumentCompletion); + SetUpEditor(@" Class C Sub Goo() @@ -42,7 +44,21 @@ End Sub VirtualKey.Escape, VirtualKey.Tab); - VisualStudio.Editor.Verify.CurrentLineText("Dim x = {New Object}$$", assertCaretPosition: true); + if (argumentCompletion) + { + VisualStudio.Editor.Verify.CurrentLineText("Dim x = {New Object($$)}", assertCaretPosition: true); + VisualStudio.Workspace.WaitForAllAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.SignatureHelp); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Editor.Verify.CurrentLineText("Dim x = {New Object()$$}", assertCaretPosition: true); + + VisualStudio.Editor.SendKeys(VirtualKey.Tab); + VisualStudio.Editor.Verify.CurrentLineText("Dim x = {New Object()}$$", assertCaretPosition: true); + } + else + { + VisualStudio.Editor.Verify.CurrentLineText("Dim x = {New Object}$$", assertCaretPosition: true); + } } [WpfFact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/TextViewWindow_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/TextViewWindow_InProc.cs index 82f13f864a6e7..d3925b2a9fc84 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/TextViewWindow_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/TextViewWindow_InProc.cs @@ -68,38 +68,17 @@ public string GetCurrentCompletionItem() public void ShowLightBulb() { - // ⚠ The workarounds below (delays, retries) can be removed once integration test machines are updated to - // 16.9 Preview 2. https://devdiv.visualstudio.com/DevDiv/_git/VS-Platform/pullrequest/283203 - - // Start by sleeping 600ms to try and avoid the dismissal below - Thread.Sleep(600); - - InvokeSmartTasks(); - - // The editor has an asynchronous background operation that dismisses the light bulb if it was shown within - // 500ms of the operation starting. Wait 1000ms and make sure the menu is still present. - // https://devdiv.visualstudio.com/DevDiv/_git/VS-Platform/pullrequest/268277 - Thread.Sleep(1000); - - if (!IsLightBulbSessionExpanded()) - { - InvokeSmartTasks(); - } - - void InvokeSmartTasks() + InvokeOnUIThread(cancellationToken => { - InvokeOnUIThread(cancellationToken => - { - var shell = GetGlobalService(); - var cmdGroup = typeof(VSConstants.VSStd2KCmdID).GUID; - var cmdExecOpt = OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER; - - const VSConstants.VSStd2KCmdID ECMD_SMARTTASKS = (VSConstants.VSStd2KCmdID)147; - var cmdID = ECMD_SMARTTASKS; - object obj = null; - shell.PostExecCommand(cmdGroup, (uint)cmdID, (uint)cmdExecOpt, ref obj); - }); - } + var shell = GetGlobalService(); + var cmdGroup = typeof(VSConstants.VSStd2KCmdID).GUID; + var cmdExecOpt = OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER; + + const VSConstants.VSStd2KCmdID ECMD_SMARTTASKS = (VSConstants.VSStd2KCmdID)147; + var cmdID = ECMD_SMARTTASKS; + object obj = null; + shell.PostExecCommand(cmdGroup, (uint)cmdID, (uint)cmdExecOpt, ref obj); + }); } public void WaitForLightBulbSession() @@ -278,6 +257,17 @@ protected Action GetExecuteOnActionViewCallback(Action + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + + var broker = GetComponentModelService(); + await broker.TriggerQuickInfoAsync(GetActiveTextView()); + }); + } + public string GetQuickInfo() => ExecuteOnActiveView(view => { diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs index 29d06af07a00a..4049fe63c9973 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs @@ -10,6 +10,7 @@ using System.Runtime.InteropServices; using System.Text; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; @@ -178,6 +179,29 @@ public void CleanUpWorkspace() _visualStudioWorkspace.TestHookPartialSolutionsDisabled = true; }); + /// + /// Reset options that are manipulated by integration tests back to their default values. + /// + public void ResetOptions() + { + ResetOption(CompletionOptions.EnableArgumentCompletionSnippets); + return; + + // Local function + void ResetOption(IOption option) + { + if (option is IPerLanguageOption) + { + SetOption(new OptionKey(option, LanguageNames.CSharp), option.DefaultValue); + SetOption(new OptionKey(option, LanguageNames.VisualBasic), option.DefaultValue); + } + else + { + SetOption(new OptionKey(option), option.DefaultValue); + } + } + } + public void CleanUpWaitingService() => InvokeOnUIThread(cancellationToken => { diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/OutOfProcComponent.cs b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/OutOfProcComponent.cs index 6ce5ce9791c8f..4a4ab31b50d7d 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/OutOfProcComponent.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/OutOfProcComponent.cs @@ -30,12 +30,5 @@ protected void WaitForCompletionSet() protected void WaitForSignatureHelp() => VisualStudioInstance.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.SignatureHelp); - - protected void WaitForQuickInfo() - { - VisualStudioInstance.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.DiagnosticService); - VisualStudioInstance.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.ErrorSquiggles); - VisualStudioInstance.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.QuickInfo); - } } } diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/TextViewWindow_OutOfProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/TextViewWindow_OutOfProc.cs index fe87537227db4..514759057762f 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/TextViewWindow_OutOfProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/TextViewWindow_OutOfProc.cs @@ -59,10 +59,7 @@ public string[] GetCurrentClassifications() => _textViewWindowInProc.GetCurrentClassifications(); public string GetQuickInfo() - { - WaitForQuickInfo(); - return _textViewWindowInProc.GetQuickInfo(); - } + => _textViewWindowInProc.GetQuickInfo(); public void VerifyTags(string tagTypeName, int expectedCount) => _textViewWindowInProc.VerifyTags(tagTypeName, expectedCount); @@ -118,9 +115,6 @@ public void InvokeCodeActionListWithoutWaiting() } public void InvokeQuickInfo() - { - _instance.ExecuteCommand(WellKnownCommandNames.Edit_QuickInfo); - _instance.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.QuickInfo); - } + => _textViewWindowInProc.InvokeQuickInfo(); } } diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/VisualStudioWorkspace_OutOfProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/VisualStudioWorkspace_OutOfProc.cs index a3e3f1773e8a0..197ed7abd8115 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/VisualStudioWorkspace_OutOfProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/VisualStudioWorkspace_OutOfProc.cs @@ -56,6 +56,9 @@ public void WaitForAllAsyncOperationsOrFail(TimeSpan timeout, params string[] fe public void CleanUpWorkspace() => _inProc.CleanUpWorkspace(); + public void ResetOptions() + => _inProc.ResetOptions(); + public void CleanUpWaitingService() => _inProc.CleanUpWaitingService(); diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs index b4b41f6c123e7..67fca07709bfc 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs @@ -15,7 +15,6 @@ using Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess; using Microsoft.VisualStudio.IntegrationTest.Utilities.Input; using Microsoft.VisualStudio.IntegrationTest.Utilities.OutOfProcess; -using Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature; using Process = System.Diagnostics.Process; namespace Microsoft.VisualStudio.IntegrationTest.Utilities @@ -235,6 +234,7 @@ public void CleanUp() // Prevent the start page from showing after each solution closes StartPage.SetEnabled(false); + Workspace.ResetOptions(); } public void Close(bool exitHostProcess = true) diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownCommandNames.cs b/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownCommandNames.cs index cbe0ead05e6ba..a4386b9222dd5 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownCommandNames.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownCommandNames.cs @@ -16,7 +16,6 @@ public static class WellKnownCommandNames public const string Edit_GoToImplementation = "Edit.GoToImplementation"; public const string Edit_ListMembers = "Edit.ListMembers"; public const string Edit_ParameterInfo = "Edit.ParameterInfo"; - public const string Edit_QuickInfo = "Edit.QuickInfo"; public const string Edit_ToggleCompletionMode = "Edit.ToggleCompletionMode"; public const string Edit_Undo = "Edit.Undo"; public const string Edit_Redo = "Edit.Redo"; diff --git a/src/VisualStudio/LiveShare/Test/MockDocumentNavigationServiceFactory.cs b/src/VisualStudio/LiveShare/Test/MockDocumentNavigationServiceFactory.cs index 0746afcccaa44..37ca5abb31188 100644 --- a/src/VisualStudio/LiveShare/Test/MockDocumentNavigationServiceFactory.cs +++ b/src/VisualStudio/LiveShare/Test/MockDocumentNavigationServiceFactory.cs @@ -44,7 +44,7 @@ private class MockDocumentNavigationService : IDocumentNavigationService public bool TryNavigateToPosition(Workspace workspace, DocumentId documentId, int position, int virtualSpace, OptionSet options, CancellationToken cancellationToken) => true; - public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, CancellationToken cancellationToken) => true; + public bool TryNavigateToSpan(Workspace workspace, DocumentId documentId, TextSpan textSpan, OptionSet options, bool allowInvalidSpans, CancellationToken cancellationToken) => true; } } } diff --git a/src/VisualStudio/VisualBasic/Impl/Help/VisualBasicHelpContextService.vb b/src/VisualStudio/VisualBasic/Impl/Help/VisualBasicHelpContextService.vb index eca269a3a4d3d..4f4f7c4fb3d93 100644 --- a/src/VisualStudio/VisualBasic/Impl/Help/VisualBasicHelpContextService.vb +++ b/src/VisualStudio/VisualBasic/Impl/Help/VisualBasicHelpContextService.vb @@ -50,7 +50,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Help Return visitor.result End If - Dim trivia = tree.GetRoot().FindTrivia(span.Start, findInsideTrivia:=True) + Dim trivia = tree.GetRoot(cancellationToken).FindTrivia(span.Start, findInsideTrivia:=True) Dim text = If(trivia.ToFullString(), String.Empty).Replace(" ", "").TrimStart("'"c) If text.StartsWith("TODO:", StringComparison.CurrentCultureIgnoreCase) Then diff --git a/src/Workspaces/CSharp/Portable/FindSymbols/CSharpDeclaredSymbolInfoFactoryService.cs b/src/Workspaces/CSharp/Portable/FindSymbols/CSharpDeclaredSymbolInfoFactoryService.cs index 72b0aaf3718d5..d3fa6a2825ce3 100644 --- a/src/Workspaces/CSharp/Portable/FindSymbols/CSharpDeclaredSymbolInfoFactoryService.cs +++ b/src/Workspaces/CSharp/Portable/FindSymbols/CSharpDeclaredSymbolInfoFactoryService.cs @@ -165,38 +165,33 @@ public override bool TryGetDeclaredSymbolInfo(StringTable stringTable, SyntaxNod switch (node.Kind()) { case SyntaxKind.ClassDeclaration: - var classDecl = (ClassDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( - stringTable, - classDecl.Identifier.ValueText, - GetTypeParameterSuffix(classDecl.TypeParameterList), - GetContainerDisplayName(node.Parent), - GetFullyQualifiedContainerName(node.Parent), - classDecl.Modifiers.Any(SyntaxKind.PartialKeyword), - DeclaredSymbolInfoKind.Class, - GetAccessibility(classDecl, classDecl.Modifiers), - classDecl.Identifier.Span, - GetInheritanceNames(stringTable, classDecl.BaseList), - IsNestedType(classDecl)); - return true; case SyntaxKind.RecordDeclaration: - var recordDecl = (RecordDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.StructDeclaration: + var typeDecl = (TypeDeclarationSyntax)node; + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, - recordDecl.Identifier.ValueText, - GetTypeParameterSuffix(recordDecl.TypeParameterList), + typeDecl.Identifier.ValueText, + GetTypeParameterSuffix(typeDecl.TypeParameterList), GetContainerDisplayName(node.Parent), GetFullyQualifiedContainerName(node.Parent), - recordDecl.Modifiers.Any(SyntaxKind.PartialKeyword), - DeclaredSymbolInfoKind.Record, - GetAccessibility(recordDecl, recordDecl.Modifiers), - recordDecl.Identifier.Span, - GetInheritanceNames(stringTable, recordDecl.BaseList), - IsNestedType(recordDecl)); + typeDecl.Modifiers.Any(SyntaxKind.PartialKeyword), + node.Kind() switch + { + SyntaxKind.ClassDeclaration => DeclaredSymbolInfoKind.Class, + SyntaxKind.RecordDeclaration => DeclaredSymbolInfoKind.Record, + SyntaxKind.InterfaceDeclaration => DeclaredSymbolInfoKind.Interface, + SyntaxKind.StructDeclaration => DeclaredSymbolInfoKind.Struct, + _ => throw ExceptionUtilities.UnexpectedValue(node.Kind()), + }, + GetAccessibility(typeDecl, typeDecl.Modifiers), + typeDecl.Identifier.Span, + GetInheritanceNames(stringTable, typeDecl.BaseList), + IsNestedType(typeDecl)); return true; case SyntaxKind.EnumDeclaration: var enumDecl = (EnumDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, enumDecl.Identifier.ValueText, null, GetContainerDisplayName(node.Parent), @@ -208,37 +203,9 @@ public override bool TryGetDeclaredSymbolInfo(StringTable stringTable, SyntaxNod inheritanceNames: ImmutableArray.Empty, isNestedType: IsNestedType(enumDecl)); return true; - case SyntaxKind.InterfaceDeclaration: - var interfaceDecl = (InterfaceDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( - stringTable, - interfaceDecl.Identifier.ValueText, GetTypeParameterSuffix(interfaceDecl.TypeParameterList), - GetContainerDisplayName(node.Parent), - GetFullyQualifiedContainerName(node.Parent), - interfaceDecl.Modifiers.Any(SyntaxKind.PartialKeyword), - DeclaredSymbolInfoKind.Interface, - GetAccessibility(interfaceDecl, interfaceDecl.Modifiers), - interfaceDecl.Identifier.Span, - GetInheritanceNames(stringTable, interfaceDecl.BaseList), - IsNestedType(interfaceDecl)); - return true; - case SyntaxKind.StructDeclaration: - var structDecl = (StructDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( - stringTable, - structDecl.Identifier.ValueText, GetTypeParameterSuffix(structDecl.TypeParameterList), - GetContainerDisplayName(node.Parent), - GetFullyQualifiedContainerName(node.Parent), - structDecl.Modifiers.Any(SyntaxKind.PartialKeyword), - DeclaredSymbolInfoKind.Struct, - GetAccessibility(structDecl, structDecl.Modifiers), - structDecl.Identifier.Span, - GetInheritanceNames(stringTable, structDecl.BaseList), - IsNestedType(structDecl)); - return true; case SyntaxKind.ConstructorDeclaration: var ctorDecl = (ConstructorDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, ctorDecl.Identifier.ValueText, GetConstructorSuffix(ctorDecl), @@ -253,7 +220,7 @@ public override bool TryGetDeclaredSymbolInfo(StringTable stringTable, SyntaxNod return true; case SyntaxKind.DelegateDeclaration: var delegateDecl = (DelegateDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, delegateDecl.Identifier.ValueText, GetTypeParameterSuffix(delegateDecl.TypeParameterList), @@ -267,7 +234,7 @@ public override bool TryGetDeclaredSymbolInfo(StringTable stringTable, SyntaxNod return true; case SyntaxKind.EnumMemberDeclaration: var enumMember = (EnumMemberDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, enumMember.Identifier.ValueText, null, GetContainerDisplayName(node.Parent), @@ -280,7 +247,7 @@ public override bool TryGetDeclaredSymbolInfo(StringTable stringTable, SyntaxNod return true; case SyntaxKind.EventDeclaration: var eventDecl = (EventDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, eventDecl.Identifier.ValueText, null, GetContainerDisplayName(node.Parent), @@ -293,7 +260,7 @@ public override bool TryGetDeclaredSymbolInfo(StringTable stringTable, SyntaxNod return true; case SyntaxKind.IndexerDeclaration: var indexerDecl = (IndexerDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, "this", GetIndexerSuffix(indexerDecl), GetContainerDisplayName(node.Parent), @@ -306,7 +273,7 @@ public override bool TryGetDeclaredSymbolInfo(StringTable stringTable, SyntaxNod return true; case SyntaxKind.MethodDeclaration: var method = (MethodDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, method.Identifier.ValueText, GetMethodSuffix(method), GetContainerDisplayName(node.Parent), @@ -321,7 +288,7 @@ public override bool TryGetDeclaredSymbolInfo(StringTable stringTable, SyntaxNod return true; case SyntaxKind.PropertyDeclaration: var property = (PropertyDeclarationSyntax)node; - declaredSymbolInfo = new DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, property.Identifier.ValueText, null, GetContainerDisplayName(node.Parent), @@ -344,7 +311,7 @@ public override bool TryGetDeclaredSymbolInfo(StringTable stringTable, SyntaxNod ? DeclaredSymbolInfoKind.Constant : DeclaredSymbolInfoKind.Field; - declaredSymbolInfo = new DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, variableDeclarator.Identifier.ValueText, null, GetContainerDisplayName(fieldDeclaration.Parent), diff --git a/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs b/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs index 12d497e6061eb..618972f1a79c3 100644 --- a/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs +++ b/src/Workspaces/CSharp/Portable/Recommendations/CSharpRecommendationServiceRunner.cs @@ -255,43 +255,12 @@ private RecommendedSymbols GetSymbolsOffOfName(NameSyntax name) return GetSymbolsOffOfExpression(name); } - // Check if we're in an interesting situation like this: - // - // int i = 5; - // i. // <-- here - // List ml = new List(); - // - // The problem is that "i.List" gets parsed as a type. In this case we need - // to try binding again as if "i" is an expression and not a type. In order to do - // that, we need to speculate as to what 'i' meant if it wasn't part of a local - // declaration's type. - // - // Another interesting case is something like: - // - // stringList. - // await Test2(); - // - // Here "stringList.await" is thought of as the return type of a local function. - - if (name.IsFoundUnder(d => d.ReturnType) || - name.IsFoundUnder(d => d.Declaration.Type) || - name.IsFoundUnder(d => d.Declaration.Type)) - { - var speculativeBinding = _context.SemanticModel.GetSpeculativeSymbolInfo( - name.SpanStart, name, SpeculativeBindingOption.BindAsExpression); - - var container = _context.SemanticModel.GetSpeculativeTypeInfo( - name.SpanStart, name, SpeculativeBindingOption.BindAsExpression).Type; - - var speculativeResult = GetSymbolsOffOfBoundExpression(name, name, speculativeBinding, container); - - return speculativeResult; - } + if (ShouldBeTreatedAsTypeInsteadOfExpression(name, out var nameBinding, out var container)) + return GetSymbolsOffOfBoundExpression(name, name, nameBinding, container); // We're in a name-only context, since if we were an expression we'd be a // MemberAccessExpressionSyntax. Thus, let's do other namespaces and types. - var nameBinding = _context.SemanticModel.GetSymbolInfo(name, _cancellationToken); - + nameBinding = _context.SemanticModel.GetSymbolInfo(name, _cancellationToken); if (nameBinding.Symbol is INamespaceOrTypeSymbol symbol) { if (_context.IsNameOfContext) @@ -330,6 +299,46 @@ private RecommendedSymbols GetSymbolsOffOfName(NameSyntax name) return default; } + /// + /// DeterminesCheck if we're in an interesting situation like this: + /// + /// int i = 5; + /// i. // -- here + /// List ml = new List(); + /// + /// The problem is that "i.List" gets parsed as a type. In this case we need to try binding again as if "i" is + /// an expression and not a type. In order to do that, we need to speculate as to what 'i' meant if it wasn't + /// part of a local declaration's type. + /// + /// Another interesting case is something like: + /// + /// stringList. + /// await Test2(); + /// + /// Here "stringList.await" is thought of as the return type of a local function. + /// + private bool ShouldBeTreatedAsTypeInsteadOfExpression( + ExpressionSyntax name, + out SymbolInfo leftHandBinding, + out ITypeSymbol? container) + { + if (name.IsFoundUnder(d => d.ReturnType) || + name.IsFoundUnder(d => d.Declaration.Type) || + name.IsFoundUnder(d => d.Declaration.Type)) + { + leftHandBinding = _context.SemanticModel.GetSpeculativeSymbolInfo( + name.SpanStart, name, SpeculativeBindingOption.BindAsExpression); + + container = _context.SemanticModel.GetSpeculativeTypeInfo( + name.SpanStart, name, SpeculativeBindingOption.BindAsExpression).Type; + return true; + } + + leftHandBinding = default; + container = null; + return false; + } + private RecommendedSymbols GetSymbolsOffOfExpression(ExpressionSyntax? originalExpression) { if (originalExpression == null) @@ -497,10 +506,8 @@ private RecommendedSymbols GetSymbolsOffOfBoundExpression( private ImmutableArray GetUnnamedSymbols(ExpressionSyntax originalExpression) { - using var _ = ArrayBuilder.GetInstance(out var symbols); - var semanticModel = _context.SemanticModel; - var container = semanticModel.GetTypeInfo(originalExpression, _cancellationToken).Type; + var container = GetContainerForUnnamedSymbols(semanticModel, originalExpression); if (container == null) return ImmutableArray.Empty; @@ -510,6 +517,8 @@ private ImmutableArray GetUnnamedSymbols(ExpressionSyntax originalExpre if (originalExpression.GetRootConditionalAccessExpression() != null) container = TryMakeNullable(semanticModel.Compilation, container); + using var _ = ArrayBuilder.GetInstance(out var symbols); + AddIndexers(container, symbols); AddOperators(container, symbols); AddConversions(container, symbols); @@ -517,6 +526,13 @@ private ImmutableArray GetUnnamedSymbols(ExpressionSyntax originalExpre return symbols.ToImmutable(); } + private ITypeSymbol? GetContainerForUnnamedSymbols(SemanticModel semanticModel, ExpressionSyntax originalExpression) + { + return ShouldBeTreatedAsTypeInsteadOfExpression(originalExpression, out _, out var container) + ? container + : semanticModel.GetTypeInfo(originalExpression, _cancellationToken).Type; + } + private void AddIndexers(ITypeSymbol container, ArrayBuilder symbols) { var containingType = _context.SemanticModel.GetEnclosingNamedType(_context.Position, _cancellationToken); diff --git a/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs b/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs index cd7a72e85aea5..9f8e144d6e4dd 100644 --- a/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs +++ b/src/Workspaces/CSharp/Portable/Rename/CSharpRenameRewriterLanguageService.cs @@ -936,7 +936,7 @@ renamedSymbol.ContainingSymbol is IMethodSymbol methodSymbol && return conflicts.ToImmutableAndFree(); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -964,7 +964,7 @@ renamedSymbol.ContainingSymbol is IMethodSymbol methodSymbol && return null; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs index 102627684df1c..6e78c2153f060 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs @@ -1804,7 +1804,7 @@ public void TestUnsafeFieldDeclarationFromSymbol() VerifySyntax( Generator.Declaration( _emptyCompilation.GetTypeByMetadataName("System.IntPtr").GetMembers("ToPointer").Single()), -@"public unsafe void *ToPointer() +@"public unsafe void* ToPointer() { }"); } diff --git a/src/Workspaces/Core/MSBuild/Host/Mef/MSBuildMefHostServices.cs b/src/Workspaces/Core/MSBuild/Host/Mef/MSBuildMefHostServices.cs index 80cc769517be6..81c2683ccae6d 100644 --- a/src/Workspaces/Core/MSBuild/Host/Mef/MSBuildMefHostServices.cs +++ b/src/Workspaces/Core/MSBuild/Host/Mef/MSBuildMefHostServices.cs @@ -50,5 +50,17 @@ private static ImmutableArray CreateDefaultAssemblies() return MefHostServices.DefaultAssemblies.Concat( MefHostServicesHelpers.LoadNearbyAssemblies(assemblyNames)); } + + internal readonly struct TestAccessor + { + /// + /// Allows tests to clear services between runs. + /// + internal static void ClearCachedServices() + { + // The existing host, if any, is not retained past this call. + s_defaultServices = null; + } + } } } diff --git a/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj b/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj index c3f5dbc186c9b..3bd6d6398e3a0 100644 --- a/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj +++ b/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj @@ -41,6 +41,7 @@ + diff --git a/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationCacheService.cs b/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationCacheService.cs index 77850fa7090ac..95961020d2893 100644 --- a/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationCacheService.cs +++ b/src/Workspaces/Core/Portable/Classification/IRemoteSemanticClassificationCacheService.cs @@ -26,7 +26,7 @@ ValueTask CacheSemanticClassificationsAsync( /// Pass in . This will ensure that the cached /// classifications are only returned if they match the content the file currently has. ValueTask GetCachedSemanticClassificationsAsync( - SerializableDocumentKey documentKey, + DocumentKey documentKey, TextSpan textSpan, Checksum checksum, CancellationToken cancellationToken); diff --git a/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs b/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs index 3745565f27b34..b3a7c98fe03aa 100644 --- a/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs +++ b/src/Workspaces/Core/Portable/Classification/SyntaxClassification/AbstractSyntaxClassificationService.cs @@ -38,7 +38,7 @@ public async Task AddSemanticClassificationsAsync( var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); AddSemanticClassifications(semanticModel, textSpan, document.Project.Solution.Workspace, getNodeClassifiers, getTokenClassifiers, result, cancellationToken); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Workspaces/Core/Portable/FindSymbols/DeclaredSymbolInfo.cs b/src/Workspaces/Core/Portable/FindSymbols/DeclaredSymbolInfo.cs index 421d37e3ed31c..52acb4f38e8c3 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/DeclaredSymbolInfo.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/DeclaredSymbolInfo.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; using System.Threading; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.PooledObjects; @@ -33,18 +34,21 @@ internal enum DeclaredSymbolInfoKind : byte Struct, } + [DataContract] internal readonly struct DeclaredSymbolInfo : IEquatable { /// /// The name to pattern match against, and to show in a final presentation layer. /// - public string Name { get; } + [DataMember(Order = 0)] + public readonly string Name; /// /// An optional suffix to be shown in a presentation layer appended to . /// Can be null. /// - public string NameSuffix { get; } + [DataMember(Order = 1)] + public readonly string NameSuffix; /// /// Container of the symbol that can be shown in a final presentation layer. @@ -53,7 +57,8 @@ internal enum DeclaredSymbolInfoKind : byte /// then be shown with something like "type System.Collections.Generic.Dictionary<TKey, TValue>" /// to indicate where the symbol is located. /// - public string ContainerDisplayName { get; } + [DataMember(Order = 2)] + public readonly string ContainerDisplayName; /// /// Dotted container name of the symbol, used for pattern matching. For example @@ -62,13 +67,22 @@ internal enum DeclaredSymbolInfoKind : byte /// This way someone can search for "D.KVP" and have the "D" part of the pattern /// match against this. This should not be shown in a presentation layer. /// - public string FullyQualifiedContainerName { get; } + [DataMember(Order = 3)] + public readonly string FullyQualifiedContainerName; - public TextSpan Span { get; } + [DataMember(Order = 4)] + public readonly TextSpan Span; + + /// + /// The names directly referenced in source that this type inherits from. + /// + [DataMember(Order = 5)] + public ImmutableArray InheritanceNames { get; } // Store the kind, accessibility, parameter-count, and type-parameter-count // in a single int. Each gets 4 bits which is ample and gives us more space // for flags in the future. + [DataMember(Order = 6)] private readonly uint _flags; private const uint Lower4BitMask = 0b1111; @@ -80,12 +94,26 @@ internal enum DeclaredSymbolInfoKind : byte public bool IsNestedType => GetIsNestedType(_flags); public bool IsPartial => GetIsPartial(_flags); - /// - /// The names directly referenced in source that this type inherits from. - /// - public ImmutableArray InheritanceNames { get; } - + [Obsolete("Do not call directly. Only around for serialization. Use Create instead")] public DeclaredSymbolInfo( + string name, + string nameSuffix, + string containerDisplayName, + string fullyQualifiedContainerName, + TextSpan span, + ImmutableArray inheritanceNames, + uint flags) + { + Name = name; + NameSuffix = nameSuffix; + ContainerDisplayName = containerDisplayName; + FullyQualifiedContainerName = fullyQualifiedContainerName; + Span = span; + InheritanceNames = inheritanceNames; + _flags = flags; + } + + public static DeclaredSymbolInfo Create( StringTable stringTable, string name, string nameSuffix, @@ -98,26 +126,32 @@ public DeclaredSymbolInfo( ImmutableArray inheritanceNames, bool isNestedType = false, int parameterCount = 0, int typeParameterCount = 0) { - Name = Intern(stringTable, name); - NameSuffix = Intern(stringTable, nameSuffix); - ContainerDisplayName = Intern(stringTable, containerDisplayName); - FullyQualifiedContainerName = Intern(stringTable, fullyQualifiedContainerName); - Span = span; - InheritanceNames = inheritanceNames; - const uint MaxFlagValue = 0b1111; + Contract.ThrowIfTrue((uint)accessibility > MaxFlagValue); Contract.ThrowIfTrue((uint)kind > MaxFlagValue); + parameterCount = Math.Min(parameterCount, (byte)MaxFlagValue); typeParameterCount = Math.Min(typeParameterCount, (byte)MaxFlagValue); - _flags = + var flags = (uint)kind | ((uint)accessibility << 4) | ((uint)parameterCount << 8) | ((uint)typeParameterCount << 12) | ((isNestedType ? 1u : 0u) << 16) | ((isPartial ? 1u : 0u) << 17); + +#pragma warning disable CS0618 // Type or member is obsolete + return new DeclaredSymbolInfo( + Intern(stringTable, name), + Intern(stringTable, nameSuffix), + Intern(stringTable, containerDisplayName), + Intern(stringTable, fullyQualifiedContainerName), + span, + inheritanceNames, + flags); +#pragma warning restore CS0618 // Type or member is obsolete } [return: NotNullIfNotNull("name")] @@ -173,7 +207,7 @@ internal static DeclaredSymbolInfo ReadFrom_ThrowsOnFailure(StringTable stringTa builder.Add(reader.ReadString()); var span = new TextSpan(spanStart, spanLength); - return new DeclaredSymbolInfo( + return Create( stringTable, name: name, nameSuffix: nameSuffix, diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ProjectIndex.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ProjectIndex.cs index 245df2ef70648..8141e0a29c731 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ProjectIndex.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/DependentTypeFinder_ProjectIndex.cs @@ -58,7 +58,7 @@ private static async Task CreateIndexAsync(Project project, Cancel foreach (var document in project.Documents) { - var syntaxTreeIndex = await document.GetSyntaxTreeIndexAsync(cancellationToken).ConfigureAwait(false); + var syntaxTreeIndex = await SyntaxTreeIndex.GetRequiredIndexAsync(document, cancellationToken).ConfigureAwait(false); foreach (var info in syntaxTreeIndex.DeclaredSymbolInfos) { switch (info.Kind) diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs index ba890f19328fb..113ff4ff76f93 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder.cs @@ -91,8 +91,7 @@ protected static Task> FindDocumentsAsync( { return FindDocumentsAsync(project, documents, async (d, c) => { - var info = await SyntaxTreeIndex.GetIndexAsync(d, c).ConfigureAwait(false); - + var info = await SyntaxTreeIndex.GetRequiredIndexAsync(d, c).ConfigureAwait(false); if (findInGlobalSuppressions && info.ContainsGlobalAttributes) { return true; @@ -123,7 +122,7 @@ protected static Task> FindDocumentsAsync( return FindDocumentsAsync(project, documents, async (d, c) => { - var info = await SyntaxTreeIndex.GetIndexAsync(d, c).ConfigureAwait(false); + var info = await SyntaxTreeIndex.GetRequiredIndexAsync(d, c).ConfigureAwait(false); return info.ContainsPredefinedType(predefinedType); }, cancellationToken); } @@ -141,7 +140,7 @@ protected static Task> FindDocumentsAsync( return FindDocumentsAsync(project, documents, async (d, c) => { - var info = await SyntaxTreeIndex.GetIndexAsync(d, c).ConfigureAwait(false); + var info = await SyntaxTreeIndex.GetRequiredIndexAsync(d, c).ConfigureAwait(false); // NOTE: Predefined operators can be referenced in global suppression attributes. return info.ContainsPredefinedOperator(op) || info.ContainsGlobalAttributes; @@ -225,7 +224,7 @@ protected static async Task> GetIdentifierOrGlobalNa { // It's very costly to walk an entire tree. So if the tree is simple and doesn't contain // any unicode escapes in it, then we do simple string matching to find the tokens. - var info = await SyntaxTreeIndex.GetIndexAsync(document, cancellationToken).ConfigureAwait(false); + var info = await SyntaxTreeIndex.GetRequiredIndexAsync(document, cancellationToken).ConfigureAwait(false); if (!info.ProbablyContainsIdentifier(identifier)) return ImmutableArray.Empty; @@ -472,7 +471,7 @@ protected static Task> FindDocumentsWithPredicateAsync( { return FindDocumentsAsync(project, documents, async (d, c) => { - var info = await SyntaxTreeIndex.GetIndexAsync(d, c).ConfigureAwait(false); + var info = await SyntaxTreeIndex.GetRequiredIndexAsync(d, c).ConfigureAwait(false); return predicate(info); }, cancellationToken); } @@ -502,7 +501,7 @@ protected static async Task> FindReferencesInDocu CollectMatchingReferences collectMatchingReferences, CancellationToken cancellationToken) { - var syntaxTreeInfo = await SyntaxTreeIndex.GetIndexAsync(document, cancellationToken).ConfigureAwait(false); + var syntaxTreeInfo = await SyntaxTreeIndex.GetRequiredIndexAsync(document, cancellationToken).ConfigureAwait(false); if (isRelevantDocument(syntaxTreeInfo)) { var syntaxFacts = document.GetRequiredLanguageService(); diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder_GlobalSuppressions.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder_GlobalSuppressions.cs index 254812a3fb3e5..5450352c9ed44 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder_GlobalSuppressions.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/AbstractReferenceFinder_GlobalSuppressions.cs @@ -59,7 +59,7 @@ protected static async ValueTask> FindReferencesI CancellationToken cancellationToken) { // Check if we have any relevant global attributes in this document. - var info = await SyntaxTreeIndex.GetIndexAsync(document, cancellationToken).ConfigureAwait(false); + var info = await SyntaxTreeIndex.GetRequiredIndexAsync(document, cancellationToken).ConfigureAwait(false); if (!info.ContainsGlobalAttributes) { return ImmutableArray.Empty; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs index e420bde4daa9c..56d67ff697fc7 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ConstructorInitializerSymbolReferenceFinder.cs @@ -26,7 +26,7 @@ protected override Task> DetermineDocumentsToSearchAsyn { return FindDocumentsAsync(project, documents, async (d, c) => { - var index = await SyntaxTreeIndex.GetIndexAsync(d, c).ConfigureAwait(false); + var index = await SyntaxTreeIndex.GetRequiredIndexAsync(d, c).ConfigureAwait(false); if (index.ContainsBaseConstructorInitializer) { return true; diff --git a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.cs b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.cs index d777cadcddce2..31ab46d43bc63 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/FindReferences/Finders/ExplicitConversionSymbolReferenceFinder.cs @@ -48,7 +48,7 @@ protected override async Task> DetermineDocumentsToSear // Ignore any documents that don't also have an explicit cast in them. foreach (var document in documentsWithName.Concat(documentsWithType).Distinct()) { - var index = await SyntaxTreeIndex.GetIndexAsync(document, cancellationToken).ConfigureAwait(false); + var index = await SyntaxTreeIndex.GetRequiredIndexAsync(document, cancellationToken).ConfigureAwait(false); if (index.ContainsConversion) result.Add(document); } diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.cs index cfcd5e19d2be7..82ab256777262 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex.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.Diagnostics; @@ -26,7 +24,7 @@ internal sealed partial class SyntaxTreeIndex private readonly Lazy> _declaredSymbolInfoSet; private SyntaxTreeIndex( - Checksum checksum, + Checksum? checksum, LiteralInfo literalInfo, IdentifierInfo identifierInfo, ContextInfo contextInfo, @@ -42,8 +40,8 @@ private SyntaxTreeIndex( _declaredSymbolInfoSet = new(() => new(this.DeclaredSymbolInfos)); } - private static readonly ConditionalWeakTable s_documentToIndex = new(); - private static readonly ConditionalWeakTable s_documentIdToIndex = new(); + private static readonly ConditionalWeakTable s_documentToIndex = new(); + private static readonly ConditionalWeakTable s_documentIdToIndex = new(); public static async Task PrecalculateAsync(Document document, CancellationToken cancellationToken) { @@ -68,11 +66,18 @@ public static async Task PrecalculateAsync(Document document, CancellationToken } } - public static ValueTask GetIndexAsync(Document document, CancellationToken cancellationToken) + public static async ValueTask GetRequiredIndexAsync(Document document, CancellationToken cancellationToken) + { + var index = await GetIndexAsync(document, cancellationToken).ConfigureAwait(false); + Contract.ThrowIfNull(index); + return index; + } + + public static ValueTask GetIndexAsync(Document document, CancellationToken cancellationToken) => GetIndexAsync(document, loadOnly: false, cancellationToken); [PerformanceSensitive("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1224834", OftenCompletesSynchronously = true)] - public static async ValueTask GetIndexAsync( + public static async ValueTask GetIndexAsync( Document document, bool loadOnly, CancellationToken cancellationToken) @@ -98,7 +103,7 @@ public static async ValueTask GetIndexAsync( return index; } - private static async Task GetIndexWorkerAsync( + private static async Task GetIndexWorkerAsync( Document document, bool loadOnly, CancellationToken cancellationToken) @@ -108,7 +113,7 @@ private static async Task GetIndexWorkerAsync( // Check if we have an index for a previous version of this document. If our // checksums match, we can just use that. if (s_documentIdToIndex.TryGetValue(document.Id, out var index) && - index.Checksum == checksum) + index?.Checksum == checksum) { // The previous index we stored with this documentId is still valid. Just // return that. diff --git a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs index 518e4a3cdeb7f..c6617bf377617 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SyntaxTree/SyntaxTreeIndex_Persistence.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.PersistentStorage; using Microsoft.CodeAnalysis.Serialization; using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; @@ -17,23 +18,27 @@ internal sealed partial class SyntaxTreeIndex : IObjectWritable private const string PersistenceName = ""; private static readonly Checksum SerializationFormatChecksum = Checksum.Create("22"); - public readonly Checksum Checksum; + public readonly Checksum? Checksum; - private static async Task LoadAsync( - Document document, Checksum checksum, CancellationToken cancellationToken) - { - var solution = document.Project.Solution; - var persistentStorageService = (IChecksummedPersistentStorageService)solution.Workspace.Services.GetRequiredService(); + private static Task LoadAsync(Document document, Checksum checksum, CancellationToken cancellationToken) + => LoadAsync(document.Project.Solution.Workspace, DocumentKey.ToDocumentKey(document), checksum, GetStringTable(document.Project), cancellationToken); + public static async Task LoadAsync( + Workspace workspace, DocumentKey documentKey, Checksum? checksum, StringTable stringTable, CancellationToken cancellationToken) + { try { - // attempt to load from persisted state - var storage = await persistentStorageService.GetStorageAsync(solution, checkBranchId: false, cancellationToken).ConfigureAwait(false); + var persistentStorageService = (IChecksummedPersistentStorageService)workspace.Services.GetRequiredService(); + + var storage = await persistentStorageService.GetStorageAsync( + workspace, documentKey.Project.Solution, checkBranchId: false, cancellationToken).ConfigureAwait(false); await using var _ = storage.ConfigureAwait(false); - using var stream = await storage.ReadStreamAsync(document, PersistenceName, checksum, cancellationToken).ConfigureAwait(false); + + // attempt to load from persisted state + using var stream = await storage.ReadStreamAsync(documentKey, PersistenceName, checksum, cancellationToken).ConfigureAwait(false); using var reader = ObjectReader.TryGetReader(stream, cancellationToken: cancellationToken); if (reader != null) - return ReadFrom(GetStringTable(document.Project), reader, checksum); + return ReadFrom(stringTable, reader, checksum); } catch (Exception e) when (IOUtilities.IsNormalIOException(e)) { @@ -129,7 +134,7 @@ public void WriteTo(ObjectWriter writer) } private static SyntaxTreeIndex? ReadFrom( - StringTable stringTable, ObjectReader reader, Checksum checksum) + StringTable stringTable, ObjectReader reader, Checksum? checksum) { var literalInfo = LiteralInfo.TryReadFrom(reader); var identifierInfo = IdentifierInfo.TryReadFrom(reader); diff --git a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs index d9575b789f9e6..619dafa118740 100644 --- a/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs +++ b/src/Workspaces/Core/Portable/Options/GlobalOptionService.cs @@ -9,12 +9,15 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options.Providers; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Options @@ -25,8 +28,9 @@ internal class GlobalOptionService : IGlobalOptionService private static readonly ImmutableDictionary s_emptyEditorConfigKeysToOptions = ImmutableDictionary.Create(AnalyzerConfigOptions.KeyComparer); + private readonly IWorkspaceThreadingService? _workspaceThreadingService; private readonly Lazy> _lazyAllOptions; - private readonly ImmutableArray> _optionSerializers; + private readonly ImmutableArray> _optionSerializerProviders; private readonly ImmutableDictionary>> _serializableOptionsByLanguage; private readonly HashSet _forceComputedLanguages; @@ -38,6 +42,8 @@ internal class GlobalOptionService : IGlobalOptionService private ImmutableDictionary _visualBasicEditorConfigKeysToOptions = s_emptyEditorConfigKeysToOptions; #pragma warning restore IDE0044 // Add readonly modifier + private ImmutableArray _lazyOptionSerializers; + private ImmutableDictionary _currentValues; private ImmutableHashSet _changedOptionKeys; private ImmutableArray _registeredWorkspaces; @@ -45,11 +51,13 @@ internal class GlobalOptionService : IGlobalOptionService [ImportingConstructor] [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] public GlobalOptionService( + [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionProviders, - [ImportMany] IEnumerable> optionSerializers) + [ImportMany] IEnumerable> optionSerializers) { + _workspaceThreadingService = workspaceThreadingService; _lazyAllOptions = new Lazy>(() => optionProviders.SelectMany(p => p.Value.Options).ToImmutableHashSet()); - _optionSerializers = optionSerializers.ToImmutableArray(); + _optionSerializerProviders = optionSerializers.ToImmutableArray(); _serializableOptionsByLanguage = CreateLazySerializableOptionsByLanguage(optionProviders); _forceComputedLanguages = new HashSet(); _registeredWorkspaces = ImmutableArray.Empty; @@ -91,12 +99,52 @@ static ImmutableHashSet ComputeSerializableOptionsFromProviders(Immutab } } + private ImmutableArray GetOptionPersisters() + { + // If _lazyOptionSerializers is already initialized, return its value directly. + if (_lazyOptionSerializers is { IsDefault: false } optionSerializers) + { + return optionSerializers; + } + + ImmutableInterlocked.InterlockedInitialize( + ref _lazyOptionSerializers, + GetOptionPersistersSlow(_workspaceThreadingService, _optionSerializerProviders, CancellationToken.None)); + + return _lazyOptionSerializers; + + // Local functions + static ImmutableArray GetOptionPersistersSlow( + IWorkspaceThreadingService? workspaceThreadingService, + ImmutableArray> optionSerializerProviders, + CancellationToken cancellationToken) + { + if (workspaceThreadingService is not null) + { + return workspaceThreadingService.Run(() => GetOptionPersistersAsync(optionSerializerProviders, cancellationToken)); + } + else + { + return GetOptionPersistersAsync(optionSerializerProviders, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); + } + } + + static async Task> GetOptionPersistersAsync( + ImmutableArray> optionSerializerProviders, + CancellationToken cancellationToken) + { + return await optionSerializerProviders.SelectAsArrayAsync( + static (lazyProvider, cancellationToken) => lazyProvider.Value.GetOrCreatePersisterAsync(cancellationToken), + cancellationToken).ConfigureAwait(false); + } + } + private object? LoadOptionFromSerializerOrGetDefault(OptionKey optionKey) { - foreach (var serializer in _optionSerializers) + foreach (var serializer in GetOptionPersisters()) { // We have a deserializer, so deserialize and use that value. - if (serializer.Value.TryFetch(optionKey, out var deserializedValue)) + if (serializer.TryFetch(optionKey, out var deserializedValue)) { return deserializedValue; } @@ -288,6 +336,12 @@ public T GetOption(PerLanguageOption2 option, string? language) _currentValues = _currentValues.Add(optionKey, value); + // Track options with non-default values from serializers as changed options. + if (!object.Equals(value, optionKey.Option.DefaultValue)) + { + _changedOptionKeys = _changedOptionKeys.Add(optionKey); + } + return value; } @@ -326,9 +380,9 @@ public void SetOptions(OptionSet optionSet) SetOptionCore(optionKey, setValue); - foreach (var serializer in _optionSerializers) + foreach (var serializer in GetOptionPersisters()) { - if (serializer.Value.TryPersist(optionKey, setValue)) + if (serializer.TryPersist(optionKey, setValue)) { break; } diff --git a/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs b/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs new file mode 100644 index 0000000000000..d5e118dc30336 --- /dev/null +++ b/src/Workspaces/Core/Portable/Options/IOptionPersisterProvider.cs @@ -0,0 +1,23 @@ +// 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; + +namespace Microsoft.CodeAnalysis.Options +{ + internal interface IOptionPersisterProvider + { + /// + /// Gets the . If the persister does not already exist, it is created. + /// + /// + /// This method is safe for concurrent use from any thread. No guarantees are made regarding the use of the UI + /// thread. + /// + /// A cancellation token the operation may observe. + /// The option persister. + ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken); + } +} diff --git a/src/Workspaces/Core/Portable/Options/OptionSet.cs b/src/Workspaces/Core/Portable/Options/OptionSet.cs index bcafaea49ad2c..d2e481a90e16a 100644 --- a/src/Workspaces/Core/Portable/Options/OptionSet.cs +++ b/src/Workspaces/Core/Portable/Options/OptionSet.cs @@ -22,7 +22,7 @@ public abstract partial class OptionSet private readonly Func _getOptionCore; - public OptionSet() + protected OptionSet() { _getOptionCore = GetOptionCore; } diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs index 854537adf0dd8..b2261a39a2e85 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.Session.cs @@ -728,7 +728,7 @@ private async Task AddDocumentsWithPotentialConflictsAsync(IEnumerable continue; } - var info = await SyntaxTreeIndex.GetIndexAsync(document, _cancellationToken).ConfigureAwait(false); + var info = await SyntaxTreeIndex.GetRequiredIndexAsync(document, _cancellationToken).ConfigureAwait(false); if (info.ProbablyContainsEscapedIdentifier(_originalText)) { _documentsIdsToBeCheckedForConflict.Add(document.Id); diff --git a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs index a4c7935760335..58ef365ce2940 100644 --- a/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs +++ b/src/Workspaces/Core/Portable/Rename/ConflictEngine/ConflictResolver.cs @@ -290,7 +290,7 @@ private static async Task AddDeclarationConflictsAsync( } } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { // A NullReferenceException is happening in this method, but the dumps do not // contain information about this stack frame because this method is async and diff --git a/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs b/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs index 85ba604d2241b..cfad9f4788b98 100644 --- a/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs +++ b/src/Workspaces/Core/Portable/Serialization/SerializerService_Reference.cs @@ -377,14 +377,18 @@ private static bool TryWritePortableExecutableReferenceBackedByTemporaryStorageT metadataKind = (MetadataImageKind)reader.ReadInt32(); Contract.ThrowIfFalse(metadataKind == MetadataImageKind.Module); +#pragma warning disable CA2016 // https://github.com/dotnet/roslyn-analyzers/issues/4985 pooledMetadata.Object.Add(ReadModuleMetadataFrom(reader, kind)); +#pragma warning restore CA2016 } return (AssemblyMetadata.Create(pooledMetadata.Object), storages: default); } Contract.ThrowIfFalse(metadataKind == MetadataImageKind.Module); +#pragma warning disable CA2016 // https://github.com/dotnet/roslyn-analyzers/issues/4985 return (ReadModuleMetadataFrom(reader, kind), storages: default); +#pragma warning restore CA2016 } if (metadataKind == MetadataImageKind.Assembly) diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs index 7ea946e8ec3ef..746560365de01 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/DocumentExtensions.cs @@ -15,10 +15,10 @@ internal static partial class DocumentExtensions public static bool IsFromPrimaryBranch(this Document document) => document.Project.Solution.BranchId == document.Project.Solution.Workspace.PrimaryBranchId; - public static ValueTask GetSyntaxTreeIndexAsync(this Document document, CancellationToken cancellationToken) + public static ValueTask GetSyntaxTreeIndexAsync(this Document document, CancellationToken cancellationToken) => SyntaxTreeIndex.GetIndexAsync(document, loadOnly: false, cancellationToken); - public static ValueTask GetSyntaxTreeIndexAsync(this Document document, bool loadOnly, CancellationToken cancellationToken) + public static ValueTask GetSyntaxTreeIndexAsync(this Document document, bool loadOnly, CancellationToken cancellationToken) => SyntaxTreeIndex.GetIndexAsync(document, loadOnly, cancellationToken); /// diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs index c1eade3c8cfa4..7a83a7e25e1aa 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs @@ -176,7 +176,7 @@ private static SyntaxNode CreateNewArgumentNullException(SyntaxGenerator factory => factory.ObjectCreationExpression( compilation.GetTypeByMetadataName("System.ArgumentNullException"), factory.NameOfExpression( - factory.IdentifierName(parameter.Name))); + factory.IdentifierName(parameter.Name))).WithAdditionalAnnotations(Simplifier.AddImportsAnnotation); public static SyntaxNode CreateNullCheckAndThrowStatement( this SyntaxGenerator factory, diff --git a/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs b/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs index 3deed2dcd3837..522170e6cb6d0 100644 --- a/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs +++ b/src/Workspaces/Core/Portable/Shared/TestHooks/FeatureAttribute.cs @@ -32,7 +32,6 @@ internal static class FeatureAttribute public const string NavigationBar = nameof(NavigationBar); public const string Outlining = nameof(Outlining); public const string PackageInstaller = nameof(PackageInstaller); - public const string QuickInfo = nameof(QuickInfo); public const string ReferenceHighlighting = nameof(ReferenceHighlighting); public const string Rename = nameof(Rename); public const string RenameTracking = nameof(RenameTracking); diff --git a/src/Workspaces/Core/Portable/Shared/Utilities/IWorkspaceThreadingService.cs b/src/Workspaces/Core/Portable/Shared/Utilities/IWorkspaceThreadingService.cs new file mode 100644 index 0000000000000..bd68191deea62 --- /dev/null +++ b/src/Workspaces/Core/Portable/Shared/Utilities/IWorkspaceThreadingService.cs @@ -0,0 +1,29 @@ +// 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.Tasks; + +namespace Microsoft.CodeAnalysis.Shared.Utilities +{ + /// + /// An optional interface which allows an environment to customize the behavior for synchronous methods that need to + /// block on the result of an asynchronous invocation. An implementation of this is provided in the MEF catalog when + /// applicable. + /// + /// + /// For Visual Studio, Microsoft.VisualStudio.Threading provides the JoinableTaskFactory.Run method, which is + /// the expected way to invoke an asynchronous method from a synchronous entry point and block on its completion. + /// Other environments may choose to use this or any other strategy, or omit an implementation of this interface to + /// allow callers to simply use . + /// + /// New code is expected to use fully-asynchronous programming where possible. In cases where external APIs + /// restrict ability to be asynchronous, this service allows Roslyn to adhere to environmental policies related to + /// joining asynchronous work. + /// + internal interface IWorkspaceThreadingService + { + TResult Run(Func> asyncMethod); + } +} diff --git a/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs b/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs index 75d04b04128e8..c396453c3bf18 100644 --- a/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs +++ b/src/Workspaces/Core/Portable/Storage/AbstractPersistentStorageService.cs @@ -95,7 +95,8 @@ internal async ValueTask GetStorageWorkerAsync( // This will remove the single ref count we ourselves added when we cached the // instance. Then once all other existing clients who are holding onto this // instance let go, it will finally get truly disposed. - _ = Task.Run(() => storageToDispose.Dispose()); + // This operation is not safe to cancel (as dispose must happen). + _ = Task.Run(() => storageToDispose.Dispose(), CancellationToken.None); _currentPersistentStorage = null; _currentPersistentStorageSolutionId = null; @@ -151,9 +152,12 @@ private async ValueTask CreatePersistentStorageAs // some sort of issue (like DB corruption). We'll then try to delete the DB and can // try to create it again. If we can't create it the second time, then there's nothing // we can do and we have to store things in memory. - return await TryCreatePersistentStorageAsync(solutionKey, workingFolderPath).ConfigureAwait(false) ?? - await TryCreatePersistentStorageAsync(solutionKey, workingFolderPath).ConfigureAwait(false) ?? - NoOpPersistentStorage.Instance; + var result = await TryCreatePersistentStorageAsync(solutionKey, workingFolderPath).ConfigureAwait(false) ?? + await TryCreatePersistentStorageAsync(solutionKey, workingFolderPath).ConfigureAwait(false); + if (result != null) + return result; + + return NoOpPersistentStorage.Instance; } private async ValueTask TryCreatePersistentStorageAsync(SolutionKey solutionKey, string workingFolderPath) diff --git a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorageService.cs b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorageService.cs index 7d6110b2c53a4..772eec42395af 100644 --- a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorageService.cs +++ b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorageService.cs @@ -49,6 +49,7 @@ protected override string GetDatabaseFilePath(string workingFolderPath) return new((IChecksummedPersistentStorage?)null); } + Contract.ThrowIfNull(solutionKey.FilePath); return new(SQLitePersistentStorage.TryCreate( _connectionPoolService, workingFolderPath, diff --git a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_StringIds.cs b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_StringIds.cs index 96c6da04b2b98..d927f3422677b 100644 --- a/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_StringIds.cs +++ b/src/Workspaces/Core/Portable/Storage/SQLite/v2/SQLitePersistentStorage_StringIds.cs @@ -15,7 +15,7 @@ internal partial class SQLitePersistentStorage { private readonly ConcurrentDictionary _stringToIdMap = new(); - private int? TryGetStringId(SqlConnection connection, string value) + private int? TryGetStringId(SqlConnection connection, string? value) { // Null strings are not supported at all. Just ignore these. Any read/writes // to null values will fail and will return 'false/null' to indicate failure diff --git a/src/Workspaces/Core/Portable/TodoComments/TodoCommentOptions.cs b/src/Workspaces/Core/Portable/TodoComments/TodoCommentOptions.cs index 1816e77dbfbb8..7192c322c6ec2 100644 --- a/src/Workspaces/Core/Portable/TodoComments/TodoCommentOptions.cs +++ b/src/Workspaces/Core/Portable/TodoComments/TodoCommentOptions.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.TodoComments { internal static class TodoCommentOptions { - public static readonly Option TokenList = new(nameof(TodoCommentOptions), nameof(TokenList), defaultValue: "HACK:1|TODO:1|UNDONE:1|UnresolvedMergeConflict:0"); + public static readonly Option TokenList = new(nameof(TodoCommentOptions), nameof(TokenList), defaultValue: ""); } [ExportOptionProvider, Shared] diff --git a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs index 767182f21a196..b17e84e027093 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/DocumentKey.cs @@ -2,8 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - +using System.Collections.Generic; using System.Runtime.Serialization; using Microsoft.CodeAnalysis.Host; @@ -15,45 +14,22 @@ namespace Microsoft.CodeAnalysis.PersistentStorage /// This is useful for cases where acquiring an entire snapshot might be expensive (for example, during /// solution load), but querying the data is still desired. /// - internal readonly struct DocumentKey - { - public readonly ProjectKey Project; - - public readonly DocumentId Id; - public readonly string FilePath; - public readonly string Name; - - public DocumentKey(ProjectKey project, DocumentId id, string filePath, string name) - { - Project = project; - Id = id; - FilePath = filePath; - Name = name; - } - - public static DocumentKey ToDocumentKey(Document document) - => new(ProjectKey.ToProjectKey(document.Project), document.Id, document.FilePath, document.Name); - - public SerializableDocumentKey Dehydrate() - => new(Project.Dehydrate(), Id, FilePath, Name); - } - [DataContract] - internal readonly struct SerializableDocumentKey + internal readonly struct DocumentKey : IEqualityComparer { [DataMember(Order = 0)] - public readonly SerializableProjectKey Project; + public readonly ProjectKey Project; [DataMember(Order = 1)] public readonly DocumentId Id; [DataMember(Order = 2)] - public readonly string FilePath; + public readonly string? FilePath; [DataMember(Order = 3)] public readonly string Name; - public SerializableDocumentKey(SerializableProjectKey project, DocumentId id, string filePath, string name) + public DocumentKey(ProjectKey project, DocumentId id, string? filePath, string name) { Project = project; Id = id; @@ -61,7 +37,13 @@ public SerializableDocumentKey(SerializableProjectKey project, DocumentId id, st Name = name; } - public DocumentKey Rehydrate() - => new(Project.Rehydrate(), Id, FilePath, Name); + public static DocumentKey ToDocumentKey(Document document) + => new(ProjectKey.ToProjectKey(document.Project), document.Id, document.FilePath, document.Name); + + public bool Equals(DocumentKey x, DocumentKey y) + => x.Id == y.Id; + + public int GetHashCode(DocumentKey obj) + => obj.Id.GetHashCode(); } } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/ProjectKey.cs b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/ProjectKey.cs index 4b04854054ce9..5a36a9dc26704 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/ProjectKey.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/ProjectKey.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.Runtime.Serialization; using Microsoft.CodeAnalysis.Host; @@ -15,45 +13,17 @@ namespace Microsoft.CodeAnalysis.PersistentStorage /// This is useful for cases where acquiring an entire snapshot might be expensive (for example, during /// solution load), but querying the data is still desired. /// - internal readonly struct ProjectKey - { - public readonly SolutionKey Solution; - - public readonly ProjectId Id; - public readonly string FilePath; - public readonly string Name; - public readonly Checksum ParseOptionsChecksum; - - public ProjectKey(SolutionKey solution, ProjectId id, string filePath, string name, Checksum parseOptionsChecksum) - { - Solution = solution; - Id = id; - FilePath = filePath; - Name = name; - ParseOptionsChecksum = parseOptionsChecksum; - } - - public static ProjectKey ToProjectKey(Project project) - => ToProjectKey(project.Solution.State, project.State); - - public static ProjectKey ToProjectKey(SolutionState solutionState, ProjectState projectState) - => new(SolutionKey.ToSolutionKey(solutionState), projectState.Id, projectState.FilePath, projectState.Name, projectState.GetParseOptionsChecksum()); - - public SerializableProjectKey Dehydrate() - => new(Solution.Dehydrate(), Id, FilePath, Name, ParseOptionsChecksum); - } - [DataContract] - internal readonly struct SerializableProjectKey + internal readonly struct ProjectKey { [DataMember(Order = 0)] - public readonly SerializableSolutionKey Solution; + public readonly SolutionKey Solution; [DataMember(Order = 1)] public readonly ProjectId Id; [DataMember(Order = 2)] - public readonly string FilePath; + public readonly string? FilePath; [DataMember(Order = 3)] public readonly string Name; @@ -61,7 +31,7 @@ internal readonly struct SerializableProjectKey [DataMember(Order = 4)] public readonly Checksum ParseOptionsChecksum; - public SerializableProjectKey(SerializableSolutionKey solution, ProjectId id, string filePath, string name, Checksum parseOptionsChecksum) + public ProjectKey(SolutionKey solution, ProjectId id, string? filePath, string name, Checksum parseOptionsChecksum) { Solution = solution; Id = id; @@ -70,7 +40,10 @@ public SerializableProjectKey(SerializableSolutionKey solution, ProjectId id, st ParseOptionsChecksum = parseOptionsChecksum; } - public ProjectKey Rehydrate() - => new(Solution.Rehydrate(), Id, FilePath, Name, ParseOptionsChecksum); + public static ProjectKey ToProjectKey(Project project) + => ToProjectKey(project.Solution.State, project.State); + + public static ProjectKey ToProjectKey(SolutionState solutionState, ProjectState projectState) + => new(SolutionKey.ToSolutionKey(solutionState), projectState.Id, projectState.FilePath, projectState.Name, projectState.GetParseOptionsChecksum()); } } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/SolutionKey.cs b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/SolutionKey.cs index 2b457d1b73c8b..8832d2baf50d0 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/SolutionKey.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/PersistentStorage/SolutionKey.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.Runtime.Serialization; using Microsoft.CodeAnalysis.Host; @@ -15,13 +13,17 @@ namespace Microsoft.CodeAnalysis.PersistentStorage /// This is useful for cases where acquiring an entire snapshot might be expensive (for example, during /// solution load), but querying the data is still desired. /// + [DataContract] internal readonly struct SolutionKey { + [DataMember(Order = 0)] public readonly SolutionId Id; - public readonly string FilePath; + [DataMember(Order = 1)] + public readonly string? FilePath; + [DataMember(Order = 2)] public readonly bool IsPrimaryBranch; - public SolutionKey(SolutionId id, string filePath, bool isPrimaryBranch) + public SolutionKey(SolutionId id, string? filePath, bool isPrimaryBranch) { Id = id; FilePath = filePath; @@ -33,31 +35,5 @@ public static SolutionKey ToSolutionKey(Solution solution) public static SolutionKey ToSolutionKey(SolutionState solutionState) => new(solutionState.Id, solutionState.FilePath, solutionState.BranchId == solutionState.Workspace.PrimaryBranchId); - - public SerializableSolutionKey Dehydrate() - => new(Id, FilePath, IsPrimaryBranch); - } - - [DataContract] - internal readonly struct SerializableSolutionKey - { - [DataMember(Order = 0)] - public readonly SolutionId Id; - - [DataMember(Order = 1)] - public readonly string FilePath; - - [DataMember(Order = 2)] - public readonly bool IsPrimaryBranch; - - public SerializableSolutionKey(SolutionId id, string filePath, bool isPrimaryBranch) - { - Id = id; - FilePath = filePath; - IsPrimaryBranch = isPrimaryBranch; - } - - public SolutionKey Rehydrate() - => new(Id, FilePath, IsPrimaryBranch); } } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs b/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs index fa8e5dedb6edf..7340b38f9aa5e 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/Document.cs @@ -310,7 +310,7 @@ public bool TryGetSemanticModel([NotNullWhen(returnValue: true)] out SemanticMod return result; } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -414,7 +414,7 @@ public async Task> GetTextChangesAsync(Document oldDocum return text.GetTextChanges(oldText).ToList(); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs index b140d36b44f48..fcab0b0159287 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs @@ -207,7 +207,7 @@ private static async Task IncrementallyParseTreeAsync( return IncrementallyParse(newTextAndVersion, oldTreeAndVersion, cancellationToken); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -228,7 +228,7 @@ private static TreeAndVersion IncrementallyParseTree( return IncrementallyParse(newTextAndVersion, oldTreeAndVersion, cancellationToken); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs index d5533c1114d22..300b3bb806e4b 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState.cs @@ -284,7 +284,7 @@ public async Task> GetAnalyzerOptionsForPath return _lazyAnalyzerConfigSet.GetValue(CancellationToken.None).GetOptionsForSourcePath(sourceFilePath); } - private sealed class WorkspaceAnalyzerConfigOptionsProvider : AnalyzerConfigOptionsProvider + internal sealed class WorkspaceAnalyzerConfigOptionsProvider : AnalyzerConfigOptionsProvider { private readonly ProjectState _projectState; @@ -303,6 +303,9 @@ public override AnalyzerConfigOptions GetOptions(AdditionalText textFile) return new WorkspaceAnalyzerConfigOptions(_projectState._lazyAnalyzerConfigSet.GetValue(CancellationToken.None).GetOptionsForSourcePath(textFile.Path)); } + public AnalyzerConfigOptions GetOptionsForSourcePath(string path) + => new WorkspaceAnalyzerConfigOptions(_projectState._lazyAnalyzerConfigSet.GetValue(CancellationToken.None).GetOptionsForSourcePath(path)); + private sealed class WorkspaceAnalyzerConfigOptions : AnalyzerConfigOptions { private readonly ImmutableDictionary _backing; diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs index 18c50562daef9..2a46ac195f118 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectState_Checksum.cs @@ -76,7 +76,7 @@ private async Task ComputeChecksumsAsync(CancellationToke new AnalyzerConfigDocumentChecksumCollection(analyzerConfigDocumentChecksums)); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.CompilationTracker.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.CompilationTracker.cs index 3deff2742590e..3f9acc2af2fdb 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.CompilationTracker.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.CompilationTracker.cs @@ -501,7 +501,7 @@ private async Task GetOrBuildDeclarationCompilationAsync(SolutionSe return compilation; } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -544,7 +544,7 @@ private async Task GetOrBuildCompilationInfoAsync( } } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -615,7 +615,7 @@ private async Task BuildCompilationInfoFromScratchAsync( return await FinalizeCompilationAsync(solution, compilation, authoritativeGeneratedDocuments: null, nonAuthoritativeGeneratedDocuments: TextDocumentStates.Empty, cancellationToken).ConfigureAwait(false); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -645,7 +645,7 @@ private async Task BuildDeclarationCompilationFromScratchAsync( WriteState(new FullDeclarationState(compilation, TextDocumentStates.Empty, generatedDocumentsAreFinal: false), solutionServices); return compilation; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -678,7 +678,7 @@ private async Task BuildFinalStateFromInProgressStateAsync( var compilation = await BuildDeclarationCompilationFromInProgressAsync(solution.Services, state, inProgressCompilation, cancellationToken).ConfigureAwait(false); return await FinalizeCompilationAsync(solution, compilation, authoritativeGeneratedDocuments: null, nonAuthoritativeGeneratedDocuments: state.GeneratedDocuments, cancellationToken).ConfigureAwait(false); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -704,7 +704,7 @@ private async Task BuildDeclarationCompilationFromInProgressAsync( return inProgressCompilation; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -825,7 +825,7 @@ private async Task FinalizeCompilationAsync( if (generatorDriver != null) { - generatorDriver = generatorDriver.RunGenerators(compilationWithoutGeneratedFiles); + generatorDriver = generatorDriver.RunGenerators(compilationWithoutGeneratedFiles, cancellationToken); foreach (var generatorResult in generatorDriver.GetRunResult().Results) { @@ -882,7 +882,7 @@ private async Task FinalizeCompilationAsync( return new CompilationInfo(compilation, hasSuccessfullyLoaded, generatedDocuments); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -972,7 +972,7 @@ public async Task GetMetadataReferenceAsync( return await this.GetMetadataOnlyImageReferenceAsync(solution, projectReference, cancellationToken).ConfigureAwait(false); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -1036,7 +1036,7 @@ private async Task GetMetadataOnlyImageReferenceAsync( return reference; } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs index 4e1ae6e4ba623..7992315c9fefc 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs @@ -1673,7 +1673,7 @@ public SolutionState WithFrozenPartialCompilationIncludingSpecificDocument(Docum return currentPartialSolution; } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } @@ -1794,7 +1794,7 @@ public Task GetMetadataReferenceAsync(ProjectReference projec var tracker = this.GetCompilationTracker(projectReference.ProjectId); return tracker.GetMetadataReferenceAsync(this, fromProject, projectReference, cancellationToken); } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState_Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState_Checksum.cs index aa66e1488aa27..ac3f55c1d101a 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState_Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState_Checksum.cs @@ -54,7 +54,7 @@ private async Task ComputeChecksumsAsync(CancellationTok return new SolutionStateChecksums(infoChecksum, optionsChecksum, new ProjectChecksumCollection(projectChecksums), analyzerReferenceChecksums); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState_Checksum.cs b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState_Checksum.cs index 31bdfadcd0592..51919803bb69e 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState_Checksum.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/TextDocumentState_Checksum.cs @@ -42,7 +42,7 @@ private async Task ComputeChecksumsAsync(CancellationTok return new DocumentStateChecksums(infoChecksum, textChecksum); } } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs index 0fd51261e3ffa..5b909ce48f51d 100644 --- a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs +++ b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionService.cs @@ -3,24 +3,35 @@ // 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; -using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; namespace Microsoft.CodeAnalysis.UnitTests { internal static class TestOptionService { - public static OptionServiceFactory.OptionService GetService(Workspace workspace, IOptionProvider? optionProvider = null) + public static OptionServiceFactory.OptionService GetService(Workspace workspace, IOptionProvider? optionProvider = null, IOptionPersisterProvider? optionPersisterProvider = null) { - return new OptionServiceFactory.OptionService(new GlobalOptionService(new[] + var mefHostServices = (IMefHostExportProvider)workspace.Services.HostServices; + var workspaceThreadingService = mefHostServices.GetExportedValues().SingleOrDefault(); + return new OptionServiceFactory.OptionService(new GlobalOptionService( + workspaceThreadingService, + new[] { new Lazy(() => optionProvider ??= new TestOptionsProvider(), new LanguageMetadata(LanguageNames.CSharp)) }, - Enumerable.Empty>()), workspaceServices: workspace.Services); + new[] + { + new Lazy(() => optionPersisterProvider ??= new TestOptionsPersisterProvider()) + }), + workspaceServices: workspace.Services); } internal class TestOptionsProvider : IOptionProvider @@ -28,5 +39,30 @@ internal class TestOptionsProvider : IOptionProvider public ImmutableArray Options { get; } = ImmutableArray.Create( new Option("Test Feature", "Test Name", false)); } + + internal sealed class TestOptionsPersisterProvider : IOptionPersisterProvider + { + private readonly ValueTask _optionPersisterTask; + + public TestOptionsPersisterProvider(IOptionPersister? optionPersister = null) + => _optionPersisterTask = new(optionPersister ?? new TestOptionsPersister()); + + public ValueTask GetOrCreatePersisterAsync(CancellationToken cancellationToken) + => _optionPersisterTask; + } + + internal sealed class TestOptionsPersister : IOptionPersister + { + private ImmutableDictionary _options = ImmutableDictionary.Empty; + + public bool TryFetch(OptionKey optionKey, out object? value) + => _options.TryGetValue(optionKey, out value); + + public bool TryPersist(OptionKey optionKey, object? value) + { + _options = _options.SetItem(optionKey, value); + return true; + } + } } } diff --git a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.cs b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.cs index f2b3c951bc5fd..9f9bea5445824 100644 --- a/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.cs +++ b/src/Workspaces/CoreTest/Host/WorkspaceServices/TestOptionsServiceFactory.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; @@ -12,6 +10,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; +using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.UnitTests @@ -19,13 +18,16 @@ namespace Microsoft.CodeAnalysis.UnitTests [ExportWorkspaceServiceFactory(typeof(IOptionService), ServiceLayer.Host), Shared] internal class TestOptionsServiceFactory : IWorkspaceServiceFactory { + private readonly IWorkspaceThreadingService? _workspaceThreadingService; private readonly ImmutableArray> _providers; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public TestOptionsServiceFactory( + [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionProviders) { + _workspaceThreadingService = workspaceThreadingService; _providers = optionProviders.ToImmutableArray(); } @@ -33,7 +35,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { // give out new option service per workspace return new OptionServiceFactory.OptionService( - new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), + new GlobalOptionService(_workspaceThreadingService, _providers, SpecializedCollections.EmptyEnumerable>()), workspaceServices); } } diff --git a/src/Workspaces/CoreTest/WorkspaceServiceTests/OptionServiceTests.cs b/src/Workspaces/CoreTest/WorkspaceServiceTests/OptionServiceTests.cs index 806a2a513542e..300679fbf4fd5 100644 --- a/src/Workspaces/CoreTest/WorkspaceServiceTests/OptionServiceTests.cs +++ b/src/Workspaces/CoreTest/WorkspaceServiceTests/OptionServiceTests.cs @@ -292,6 +292,36 @@ public void TestChangedTodoCommentOptions() Assert.Equal(newOptionValue, serializableOptionSet.GetOption(changedOptionKey)); } + [Fact, WorkItem(1128126, "https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1128126")] + public void TestPersistedTodoCommentOptions() + { + var hostServices = FeaturesTestCompositions.Features.AddParts(typeof(TestOptionsServiceFactory)).GetHostServices(); + + using var workspace = new AdhocWorkspace(hostServices); + var option = TodoCommentOptions.TokenList; + var newOptionValue = option.DefaultValue + "|name:value"; + + var persister = new TestOptionService.TestOptionsPersister(); + var persisted = persister.TryPersist(option, newOptionValue); + Assert.True(persisted); + Assert.True(persister.TryFetch(option, out var persistedValue)); + Assert.Equal(newOptionValue, persistedValue); + + var provider = ((IMefHostExportProvider)hostServices).GetExportedValues().OfType().FirstOrDefault(); + var persisterProvider = new TestOptionService.TestOptionsPersisterProvider(persister); + var optionService = TestOptionService.GetService(workspace, provider, persisterProvider); + var optionSet = optionService.GetOptions(); + var optionKey = new OptionKey(option); + Assert.Equal(newOptionValue, (string?)optionSet.GetOption(optionKey)); + + var languages = ImmutableHashSet.Create(LanguageNames.CSharp); + var serializableOptionSet = optionService.GetSerializableOptionsSnapshot(languages); + var changedOptions = serializableOptionSet.GetChangedOptions(); + var changedOptionKey = Assert.Single(changedOptions); + Assert.Equal(optionKey, changedOptionKey); + Assert.Equal(newOptionValue, serializableOptionSet.GetOption(changedOptionKey)); + } + [Fact] public void TestPerLanguageCodeStyleOptions() { diff --git a/src/Workspaces/CoreTestUtilities/MEF/UseExportProviderAttribute.cs b/src/Workspaces/CoreTestUtilities/MEF/UseExportProviderAttribute.cs index d5a98c493913d..efc21f82745a2 100644 --- a/src/Workspaces/CoreTestUtilities/MEF/UseExportProviderAttribute.cs +++ b/src/Workspaces/CoreTestUtilities/MEF/UseExportProviderAttribute.cs @@ -68,6 +68,8 @@ static UseExportProviderAttribute() public override void Before(MethodInfo? methodUnderTest) { + // Need to clear cached MefHostServices between test runs. + MSBuildMefHostServices.TestAccessor.ClearCachedServices(); MefHostServices.TestAccessor.HookServiceCreation(CreateMefHostServices); // make sure we enable this for all unit tests @@ -96,6 +98,8 @@ public override void After(MethodInfo? methodUnderTest) } finally { + // Need to clear cached MefHostServices between test runs. + MSBuildMefHostServices.TestAccessor.ClearCachedServices(); // Replace hooks with ones that always throw exceptions. These hooks detect cases where code executing // after the end of a test attempts to create an ExportProvider. MefHostServices.TestAccessor.HookServiceCreation(DenyMefHostServicesCreationBetweenTests); diff --git a/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj b/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj index 547a45c1ad232..79f73759c2c96 100644 --- a/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj +++ b/src/Workspaces/CoreTestUtilities/Microsoft.CodeAnalysis.Workspaces.Test.Utilities.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs b/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs index 0606f9146f182..0e7713f1b7e99 100644 --- a/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs +++ b/src/Workspaces/MSBuildTest/MSBuildWorkspaceTests.cs @@ -807,42 +807,38 @@ public async Task TestOpenProject_WithDuplicateFile() } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithInvalidFileExtension() + public async Task TestOpenProject_WithInvalidFileExtensionAsync() { // make sure the file does in fact exist, but with an unrecognized extension const string ProjFileName = @"CSharpProject\CSharpProject.csproj.nyi"; CreateFiles(GetSimpleCSharpSolutionFiles() .WithFile(ProjFileName, Resources.ProjectFiles.CSharp.CSharpProject)); - AssertEx.Throws(delegate + var e = await Assert.ThrowsAsync(async delegate { - MSBuildWorkspace.Create().OpenProjectAsync(GetSolutionFileName(ProjFileName)).Wait(); - }, - (e) => - { - var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, GetSolutionFileName(ProjFileName), ".nyi"); - Assert.Equal(expected, e.Message); + await MSBuildWorkspace.Create().OpenProjectAsync(GetSolutionFileName(ProjFileName)); }); + + var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, GetSolutionFileName(ProjFileName), ".nyi"); + Assert.Equal(expected, e.Message); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_ProjectFileExtensionAssociatedWithUnknownLanguage() + public async Task TestOpenProject_ProjectFileExtensionAssociatedWithUnknownLanguageAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); var projFileName = GetSolutionFileName(@"CSharpProject\CSharpProject.csproj"); var language = "lingo"; - AssertEx.Throws(delegate + var e = await Assert.ThrowsAsync(async delegate { var ws = MSBuildWorkspace.Create(); ws.AssociateFileExtensionWithLanguage("csproj", language); // non-existent language - ws.OpenProjectAsync(projFileName).Wait(); - }, - (e) => - { - // the exception should tell us something about the language being unrecognized. - var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_language_1_is_not_supported, projFileName, language); - Assert.Equal(expected, e.Message); + await ws.OpenProjectAsync(projFileName); }); + + // the exception should tell us something about the language being unrecognized. + var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_language_1_is_not_supported, projFileName, language); + Assert.Equal(expected, e.Message); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] @@ -883,28 +879,28 @@ public async Task TestOpenProject_WithAssociatedLanguageExtension2_IgnoreCase() } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithNonExistentSolutionFile_Fails() + public async Task TestOpenSolution_WithNonExistentSolutionFile_FailsAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); var solutionFilePath = GetSolutionFileName("NonExistentSolution.sln"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenSolutionAsync(solutionFilePath).Wait(); + await workspace.OpenSolutionAsync(solutionFilePath); }); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithInvalidSolutionFile_Fails() + public async Task TestOpenSolution_WithInvalidSolutionFile_FailsAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); var solutionFilePath = GetSolutionFileName(@"http://localhost/Invalid/InvalidSolution.sln"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenSolutionAsync(solutionFilePath).Wait(); + await workspace.OpenSolutionAsync(solutionFilePath); }); } @@ -999,7 +995,7 @@ public async Task HandleSolutionProjectTypeSolutionFolder() } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithInvalidProjectPath_SkipFalse_Fails() + public async Task TestOpenSolution_WithInvalidProjectPath_SkipFalse_Fails() { // when not skipped we should get an exception for the invalid project @@ -1010,7 +1006,7 @@ public void TestOpenSolution_WithInvalidProjectPath_SkipFalse_Fails() using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - AssertEx.Throws(() => workspace.OpenSolutionAsync(solutionFilePath).Wait()); + await Assert.ThrowsAsync(() => workspace.OpenSolutionAsync(solutionFilePath)); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] @@ -1029,7 +1025,7 @@ public async Task TestOpenSolution_WithNonExistentProject_SkipTrue_SucceedsWithF } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithNonExistentProject_SkipFalse_Fails() + public async Task TestOpenSolution_WithNonExistentProject_SkipFalse_Fails() { // when skipped we should see an exception for the non-existent project @@ -1040,7 +1036,7 @@ public void TestOpenSolution_WithNonExistentProject_SkipFalse_Fails() using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - AssertEx.Throws(() => workspace.OpenSolutionAsync(solutionFilePath).Wait()); + await Assert.ThrowsAsync(() => workspace.OpenSolutionAsync(solutionFilePath)); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] @@ -1088,7 +1084,7 @@ public async Task TestOpenSolution_WithUnrecognizedProjectTypeGuidAndUnrecognize } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithUnrecognizedProjectTypeGuidAndUnrecognizedExtension_WithSkipFalse_Fails() + public async Task TestOpenSolution_WithUnrecognizedProjectTypeGuidAndUnrecognizedExtension_WithSkipFalse_FailsAsync() { // proves that if both project type guid and file extension are unrecognized, then open project fails. const string NoProjFileName = @"CSharpProject\CSharpProject.noproj"; @@ -1098,42 +1094,38 @@ public void TestOpenSolution_WithUnrecognizedProjectTypeGuidAndUnrecognizedExten var solutionFilePath = GetSolutionFileName(@"TestSolution.sln"); - AssertEx.Throws(() => + var e = await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - workspace.OpenSolutionAsync(solutionFilePath).Wait(); - }, - e => - { - var noProjFullFileName = GetSolutionFileName(NoProjFileName); - var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, noProjFullFileName, ".noproj"); - Assert.Equal(expected, e.Message); + await workspace.OpenSolutionAsync(solutionFilePath); }); + + var noProjFullFileName = GetSolutionFileName(NoProjFileName); + var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, noProjFullFileName, ".noproj"); + Assert.Equal(expected, e.Message); } private readonly IEnumerable _defaultAssembliesWithoutCSharp = MefHostServices.DefaultAssemblies.Where(a => !a.FullName.Contains("CSharp")); [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] [WorkItem(3931, "https://github.com/dotnet/roslyn/issues/3931")] - public void TestOpenSolution_WithMissingLanguageLibraries_WithSkipFalse_Throws() + public async Task TestOpenSolution_WithMissingLanguageLibraries_WithSkipFalse_ThrowsAsync() { // proves that if the language libraries are missing then the appropriate error occurs CreateFiles(GetSimpleCSharpSolutionFiles()); var solutionFilePath = GetSolutionFileName(@"TestSolution.sln"); - AssertEx.Throws(() => + var e = await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(MefHostServices.Create(_defaultAssembliesWithoutCSharp)); workspace.SkipUnrecognizedProjects = false; - workspace.OpenSolutionAsync(solutionFilePath).Wait(); - }, - e => - { - var projFileName = GetSolutionFileName(@"CSharpProject\CSharpProject.csproj"); - var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, projFileName, ".csproj"); - Assert.Equal(expected, e.Message); + await workspace.OpenSolutionAsync(solutionFilePath); }); + + var projFileName = GetSolutionFileName(@"CSharpProject\CSharpProject.csproj"); + var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, projFileName, ".csproj"); + Assert.Equal(expected, e.Message); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] @@ -1156,47 +1148,42 @@ public async Task TestOpenSolution_WithMissingLanguageLibraries_WithSkipTrue_Suc [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] [WorkItem(3931, "https://github.com/dotnet/roslyn/issues/3931")] - public void TestOpenProject_WithMissingLanguageLibraries_Throws() + public async Task TestOpenProject_WithMissingLanguageLibraries_Throws() { // proves that if the language libraries are missing then the appropriate error occurs CreateFiles(GetSimpleCSharpSolutionFiles()); var projectName = GetSolutionFileName(@"CSharpProject\CSharpProject.csproj"); using var workspace = MSBuildWorkspace.Create(MefHostServices.Create(_defaultAssembliesWithoutCSharp)); - AssertEx.Throws(() => - { - var project = workspace.OpenProjectAsync(projectName).Result; - }, - e => - { - var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, projectName, ".csproj"); - Assert.Equal(expected, e.Message); - }); + var e = await Assert.ThrowsAsync(() => workspace.OpenProjectAsync(projectName)); + + var expected = string.Format(WorkspacesResources.Cannot_open_project_0_because_the_file_extension_1_is_not_associated_with_a_language, projectName, ".csproj"); + Assert.Equal(expected, e.Message); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithInvalidFilePath_Fails() + public async Task TestOpenProject_WithInvalidFilePath_Fails() { CreateFiles(GetSimpleCSharpSolutionFiles()); var projectFilePath = GetSolutionFileName(@"http://localhost/Invalid/InvalidProject.csproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenProjectAsync(projectFilePath).Wait(); + await workspace.OpenProjectAsync(projectFilePath); }); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithNonExistentProjectFile_Fails() + public async Task TestOpenProject_WithNonExistentProjectFile_FailsAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); var projectFilePath = GetSolutionFileName(@"CSharpProject\NonExistentProject.csproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenProjectAsync(projectFilePath).Wait(); + await workspace.OpenProjectAsync(projectFilePath); }); } @@ -1218,17 +1205,17 @@ public async Task TestOpenProject_WithInvalidProjectReference_SkipTrue_SucceedsW } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithInvalidProjectReference_SkipFalse_Fails() + public async Task TestOpenProject_WithInvalidProjectReference_SkipFalse_Fails() { CreateFiles(GetMultiProjectSolutionFiles() .WithFile(@"VisualBasicProject\VisualBasicProject.vbproj", Resources.ProjectFiles.VisualBasic.InvalidProjectReference)); var projectFilePath = GetSolutionFileName(@"VisualBasicProject\VisualBasicProject.vbproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - workspace.OpenProjectAsync(projectFilePath).Wait(); + await workspace.OpenProjectAsync(projectFilePath); }); } @@ -1250,17 +1237,17 @@ public async Task TestOpenProject_WithNonExistentProjectReference_SkipTrue_Succe } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithNonExistentProjectReference_SkipFalse_Fails() + public async Task TestOpenProject_WithNonExistentProjectReference_SkipFalse_FailsAsync() { CreateFiles(GetMultiProjectSolutionFiles() .WithFile(@"VisualBasicProject\VisualBasicProject.vbproj", Resources.ProjectFiles.VisualBasic.NonExistentProjectReference)); var projectFilePath = GetSolutionFileName(@"VisualBasicProject\VisualBasicProject.vbproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - workspace.OpenProjectAsync(projectFilePath).Wait(); + await workspace.OpenProjectAsync(projectFilePath); }); } @@ -1283,18 +1270,18 @@ public async Task TestOpenProject_WithUnrecognizedProjectReferenceFileExtension_ } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithUnrecognizedProjectReferenceFileExtension_SkipFalse_Fails() + public async Task TestOpenProject_WithUnrecognizedProjectReferenceFileExtension_SkipFalse_Fails() { CreateFiles(GetMultiProjectSolutionFiles() .WithFile(@"VisualBasicProject\VisualBasicProject.vbproj", Resources.ProjectFiles.VisualBasic.UnknownProjectExtension) .WithFile(@"CSharpProject\CSharpProject.noproj", Resources.ProjectFiles.CSharp.CSharpProject)); var projectFilePath = GetSolutionFileName(@"VisualBasicProject\VisualBasicProject.vbproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); workspace.SkipUnrecognizedProjects = false; - workspace.OpenProjectAsync(projectFilePath).Wait(); + await workspace.OpenProjectAsync(projectFilePath); }); } @@ -2541,8 +2528,8 @@ public async Task TestOpenProject_CrossLanguageSkeletonReferenceHasDocComments() Assert.Equal(cscomment, vbcomment); } - [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithProjectFileLocked() + [ConditionalFact(typeof(VisualStudioMSBuildInstalled), typeof(IsEnglishLocal)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] + public async Task TestOpenProject_WithProjectFileLockedAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); @@ -2550,39 +2537,38 @@ public void TestOpenProject_WithProjectFileLocked() var projectFile = GetSolutionFileName(@"CSharpProject\CSharpProject.csproj"); using (File.Open(projectFile, FileMode.Open, FileAccess.ReadWrite)) { - AssertEx.Throws(() => - { - using var workspace = CreateMSBuildWorkspace(); - workspace.OpenProjectAsync(projectFile).Wait(); - }); + using var workspace = CreateMSBuildWorkspace(); + await workspace.OpenProjectAsync(projectFile); + var diagnostic = Assert.Single(workspace.Diagnostics); + Assert.Contains("The process cannot access the file", diagnostic.Message); } } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenProject_WithNonExistentProjectFile() + public async Task TestOpenProject_WithNonExistentProjectFileAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); // open for read-write so no-one else can read var projectFile = GetSolutionFileName(@"CSharpProject\NoProject.csproj"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenProjectAsync(projectFile).Wait(); + await workspace.OpenProjectAsync(projectFile); }); } [ConditionalFact(typeof(VisualStudioMSBuildInstalled)), Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] - public void TestOpenSolution_WithNonExistentSolutionFile() + public async Task TestOpenSolution_WithNonExistentSolutionFileAsync() { CreateFiles(GetSimpleCSharpSolutionFiles()); // open for read-write so no-one else can read var solutionFile = GetSolutionFileName(@"NoSolution.sln"); - AssertEx.Throws(() => + await Assert.ThrowsAsync(async () => { using var workspace = CreateMSBuildWorkspace(); - workspace.OpenSolutionAsync(solutionFile).Wait(); + await workspace.OpenSolutionAsync(solutionFile); }); } diff --git a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs index 19e29c7119419..073814b02d144 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.cs @@ -163,7 +163,7 @@ private async Task CreateSolution_NoLockAsync( var workspace = new TemporaryWorkspace(Services.HostServices, WorkspaceKind.RemoteTemporaryWorkspace, solutionInfo, options); return workspace.CurrentSolution; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs b/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs index b4eab22359401..effa4bfe07047 100644 --- a/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs +++ b/src/Workspaces/Remote/ServiceHub/Host/TemporaryWorkspaceOptionsServiceFactory.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Options.Providers; +using Microsoft.CodeAnalysis.Shared.Utilities; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote @@ -17,13 +18,16 @@ namespace Microsoft.CodeAnalysis.Remote [ExportWorkspaceServiceFactory(typeof(IOptionService), WorkspaceKind.RemoteTemporaryWorkspace), Shared] internal class TemporaryWorkspaceOptionsServiceFactory : IWorkspaceServiceFactory { + private readonly IWorkspaceThreadingService? _workspaceThreadingService; private readonly ImmutableArray> _providers; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public TemporaryWorkspaceOptionsServiceFactory( + [Import(AllowDefault = true)] IWorkspaceThreadingService? workspaceThreadingService, [ImportMany] IEnumerable> optionProviders) { + _workspaceThreadingService = workspaceThreadingService; _providers = optionProviders.ToImmutableArray(); } @@ -31,7 +35,7 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { // give out new option service per workspace return new OptionServiceFactory.OptionService( - new GlobalOptionService(_providers, SpecializedCollections.EmptyEnumerable>()), + new GlobalOptionService(_workspaceThreadingService, _providers, SpecializedCollections.EmptyEnumerable>()), workspaceServices); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/Host/ThrowingTraceListener.cs b/src/Workspaces/Remote/ServiceHub/Services/Host/ThrowingTraceListener.cs index 3c3a8fbda08e2..d4837a5aa5104 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/Host/ThrowingTraceListener.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/Host/ThrowingTraceListener.cs @@ -21,7 +21,9 @@ public override void Fail(string message, string detailMessage) } } - throw new InvalidOperationException(message + Environment.NewLine + detailMessage); + throw new InvalidOperationException( + (string.IsNullOrEmpty(message) ? "Assertion failed" : message) + + (string.IsNullOrEmpty(detailMessage) ? "" : Environment.NewLine + detailMessage)); } public override void Write(object o) diff --git a/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs b/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs index 20e99af45ff0b..a74a8a31aa95c 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/NavigateToSearch/RemoteNavigateToSearchService.cs @@ -4,10 +4,11 @@ using System; using System.Collections.Immutable; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.NavigateTo; +using Microsoft.CodeAnalysis.PersistentStorage; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Remote { @@ -28,7 +29,15 @@ public RemoteNavigateToSearchService(in ServiceConstructionArguments arguments, _callback = callback; } - public ValueTask SearchDocumentAsync( + private Func GetCallback( + RemoteServiceCallbackId callbackId, CancellationToken cancellationToken) + { + return async i => await _callback.InvokeAsync((callback, c) => + callback.OnResultFoundAsync(callbackId, i), + cancellationToken).ConfigureAwait(false); + } + + public ValueTask SearchFullyLoadedDocumentAsync( PinnedSolutionInfo solutionInfo, DocumentId documentId, string searchPattern, @@ -39,15 +48,15 @@ public ValueTask SearchDocumentAsync( return RunServiceAsync(async cancellationToken => { var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); - var document = solution.GetDocument(documentId); + var document = solution.GetRequiredDocument(documentId); var callback = GetCallback(callbackId, cancellationToken); - await AbstractNavigateToSearchService.SearchDocumentInCurrentProcessAsync( + await AbstractNavigateToSearchService.SearchFullyLoadedDocumentInCurrentProcessAsync( document, searchPattern, kinds.ToImmutableHashSet(), callback, cancellationToken).ConfigureAwait(false); }, cancellationToken); } - public ValueTask SearchProjectAsync( + public ValueTask SearchFullyLoadedProjectAsync( PinnedSolutionInfo solutionInfo, ProjectId projectId, ImmutableArray priorityDocumentIds, @@ -59,23 +68,28 @@ public ValueTask SearchProjectAsync( return RunServiceAsync(async cancellationToken => { var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false); - var project = solution.GetProject(projectId); + var project = solution.GetRequiredProject(projectId); var callback = GetCallback(callbackId, cancellationToken); - var priorityDocuments = priorityDocumentIds.Select(d => solution.GetDocument(d)) - .ToImmutableArray(); + var priorityDocuments = priorityDocumentIds.SelectAsArray(d => solution.GetRequiredDocument(d)); - await AbstractNavigateToSearchService.SearchProjectInCurrentProcessAsync( + await AbstractNavigateToSearchService.SearchFullyLoadedProjectInCurrentProcessAsync( project, priorityDocuments, searchPattern, kinds.ToImmutableHashSet(), callback, cancellationToken).ConfigureAwait(false); }, cancellationToken); } - private Func GetCallback( - RemoteServiceCallbackId callbackId, CancellationToken cancellationToken) + public ValueTask SearchCachedDocumentsAsync(ImmutableArray documentKeys, ImmutableArray priorityDocumentKeys, string searchPattern, ImmutableArray kinds, RemoteServiceCallbackId callbackId, CancellationToken cancellationToken) { - return async r => await _callback.InvokeAsync((callback, c) => - callback.OnResultFoundAsync(callbackId, SerializableNavigateToSearchResult.Dehydrate(r)), - cancellationToken).ConfigureAwait(false); + return RunServiceAsync(async cancellationToken => + { + // Intentionally do not call GetSolutionAsync here. We do not want the cost of + // synchronizing the solution over to the remote side. Instead, we just directly + // check whatever cached data we have from the previous vs session. + var callback = GetCallback(callbackId, cancellationToken); + + await AbstractNavigateToSearchService.SearchCachedDocumentsInCurrentProcessAsync( + GetWorkspace(), documentKeys, priorityDocumentKeys, searchPattern, kinds.ToImmutableHashSet(), callback, cancellationToken).ConfigureAwait(false); + }, cancellationToken); } } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassificationCache/RemoteSemanticClassificationCacheService.cs b/src/Workspaces/Remote/ServiceHub/Services/SemanticClassificationCache/RemoteSemanticClassificationCacheService.cs index 8ceebb90a08b1..f9af7086df322 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/SemanticClassificationCache/RemoteSemanticClassificationCacheService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/SemanticClassificationCache/RemoteSemanticClassificationCacheService.cs @@ -181,12 +181,12 @@ private static void WriteTo(List classifiedSpans, ObjectWriter w } public ValueTask GetCachedSemanticClassificationsAsync( - SerializableDocumentKey documentKey, TextSpan textSpan, Checksum checksum, CancellationToken cancellationToken) + DocumentKey documentKey, TextSpan textSpan, Checksum checksum, CancellationToken cancellationToken) { return RunServiceAsync(async cancellationToken => { var classifiedSpans = await TryGetOrReadCachedSemanticClassificationsAsync( - documentKey.Rehydrate(), checksum, cancellationToken).ConfigureAwait(false); + documentKey, checksum, cancellationToken).ConfigureAwait(false); if (classifiedSpans.IsDefault) return null; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs index 16926dcb5bc7c..49724219205b3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs @@ -136,6 +136,17 @@ public static bool IsKind([NotNullWhen(returnValue: true)] this SyntaxNode? node return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3 || csharpKind == kind4 || csharpKind == kind5 || csharpKind == kind6 || csharpKind == kind7 || csharpKind == kind8; } + public static bool IsKind([NotNullWhen(returnValue: true)] this SyntaxNode? node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5, SyntaxKind kind6, SyntaxKind kind7, SyntaxKind kind8, SyntaxKind kind9, SyntaxKind kind10) + { + if (node == null) + { + return false; + } + + var csharpKind = node.Kind(); + return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3 || csharpKind == kind4 || csharpKind == kind5 || csharpKind == kind6 || csharpKind == kind7 || csharpKind == kind8 || csharpKind == kind9 || csharpKind == kind10; + } + public static bool IsKind([NotNullWhen(returnValue: true)] this SyntaxNode? node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5, SyntaxKind kind6, SyntaxKind kind7, SyntaxKind kind8, SyntaxKind kind9, SyntaxKind kind10, SyntaxKind kind11) { if (node == null) @@ -890,7 +901,7 @@ internal static SyntaxNodeOrToken ChildThatContainsPosition(this SyntaxNode self throw new ArgumentOutOfRangeException(nameof(position)); } - public static (SyntaxToken openBrace, SyntaxToken closeBrace) GetParentheses(this SyntaxNode node) + public static (SyntaxToken openParen, SyntaxToken closeParen) GetParentheses(this SyntaxNode node) { switch (node) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs index 3afb0f2b755e8..63c3322d77652 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/DiagnosticDescriptorExtensions.cs @@ -6,12 +6,14 @@ using System.Diagnostics; using System.Linq; +using Microsoft.CodeAnalysis.Diagnostics; namespace Microsoft.CodeAnalysis.Shared.Extensions { internal static class DiagnosticDescriptorExtensions { private const string DotnetAnalyzerDiagnosticPrefix = "dotnet_analyzer_diagnostic"; + private const string DotnetDiagnosticPrefix = "dotnet_diagnostic"; private const string CategoryPrefix = "category"; private const string SeveritySuffix = "severity"; @@ -43,6 +45,48 @@ public static ReportDiagnostic GetEffectiveSeverity(this DiagnosticDescriptor de return effectiveSeverity; } + public static ReportDiagnostic GetEffectiveSeverity(this DiagnosticDescriptor descriptor, AnalyzerConfigOptions analyzerConfigOptions) + { + // Check if the option is defined explicitly in the editorconfig + var diagnosticKey = $"{DotnetDiagnosticPrefix}.{descriptor.Id}.{SeveritySuffix}"; + if (analyzerConfigOptions.TryGetValue(diagnosticKey, out var value) && + EditorConfigSeverityStrings.TryParse(value, out var severity)) + { + return severity; + } + + // Check if the option is defined as part of a bulk configuration + // Analyzer bulk configuration does not apply to: + // 1. Disabled by default diagnostics + // 2. Compiler diagnostics + // 3. Non-configurable diagnostics + if (!descriptor.IsEnabledByDefault || + descriptor.CustomTags.Any(tag => tag == WellKnownDiagnosticTags.Compiler || tag == WellKnownDiagnosticTags.NotConfigurable)) + { + return ReportDiagnostic.Default; + } + + // If user has explicitly configured default severity for the diagnostic category, that should be respected. + // For example, 'dotnet_analyzer_diagnostic.category-security.severity = error' + var categoryBasedKey = $"{DotnetAnalyzerDiagnosticPrefix}.{CategoryPrefix}-{descriptor.Category}.{SeveritySuffix}"; + if (analyzerConfigOptions.TryGetValue(categoryBasedKey, out value) && + EditorConfigSeverityStrings.TryParse(value, out severity)) + { + return severity; + } + + // Otherwise, if user has explicitly configured default severity for all analyzer diagnostics, that should be respected. + // For example, 'dotnet_analyzer_diagnostic.severity = error' + if (analyzerConfigOptions.TryGetValue(DotnetAnalyzerDiagnosticSeverityKey, out value) && + EditorConfigSeverityStrings.TryParse(value, out severity)) + { + return severity; + } + + // option not defined in editorconfig, assumed to be the default + return ReportDiagnostic.Default; + } + /// /// Tries to get configured severity for the given /// from bulk configuration analyzer config options, i.e. diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/RoamingProfileStorageLocation.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/RoamingProfileStorageLocation.cs index 6a0fa0667b7e7..435d9ab802415 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/RoamingProfileStorageLocation.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Options/RoamingProfileStorageLocation.cs @@ -11,9 +11,9 @@ namespace Microsoft.CodeAnalysis.Options /// internal sealed class RoamingProfileStorageLocation : OptionStorageLocation2 { - private readonly Func _keyNameFromLanguageName; + private readonly Func _keyNameFromLanguageName; - public string GetKeyNameForLanguage(string languageName) + public string GetKeyNameForLanguage(string? languageName) { var unsubstitutedKeyName = _keyNameFromLanguageName(languageName); @@ -38,7 +38,7 @@ public RoamingProfileStorageLocation(string keyName) /// Creates a that has different key names for different languages. /// /// A function that maps from a value to the key name. - public RoamingProfileStorageLocation(Func keyNameFromLanguageName) + public RoamingProfileStorageLocation(Func keyNameFromLanguageName) => _keyNameFromLanguageName = keyNameFromLanguageName; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/System.Text/Rune.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/System.Text/Rune.cs index 830be412733ed..f8e47c1be127c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/System.Text/Rune.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/System.Text/Rune.cs @@ -774,13 +774,13 @@ public static Rune GetRuneAt(string input, int index) } /// - /// Returns iff is a valid Unicode scalar + /// Returns if and only if is a valid Unicode scalar /// value, i.e., is in [ U+0000..U+D7FF ], inclusive; or [ U+E000..U+10FFFF ], inclusive. /// public static bool IsValid(int value) => IsValid((uint)value); /// - /// Returns iff is a valid Unicode scalar + /// Returns if and only if is a valid Unicode scalar /// value, i.e., is in [ U+0000..U+D7FF ], inclusive; or [ U+E000..U+10FFFF ], inclusive. /// public static bool IsValid(uint value) => UnicodeUtility.IsValidUnicodeScalar(value); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/System.Text/UnicodeUtility.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/System.Text/UnicodeUtility.cs index a07a630df3958..232692988db65 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/System.Text/UnicodeUtility.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/System.Text/UnicodeUtility.cs @@ -119,7 +119,7 @@ public static int GetUtf8SequenceLength(uint value) } /// - /// Returns iff is an ASCII + /// Returns if and only if is an ASCII /// character ([ U+0000..U+007F ]). /// /// @@ -129,49 +129,49 @@ public static int GetUtf8SequenceLength(uint value) public static bool IsAsciiCodePoint(uint value) => value <= 0x7Fu; /// - /// Returns iff is in the + /// Returns if and only if is in the /// Basic Multilingual Plane (BMP). /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsBmpCodePoint(uint value) => value <= 0xFFFFu; /// - /// Returns iff is a UTF-16 high surrogate code point, + /// Returns if and only if is a UTF-16 high surrogate code point, /// i.e., is in [ U+D800..U+DBFF ], inclusive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsHighSurrogateCodePoint(uint value) => IsInRangeInclusive(value, 0xD800U, 0xDBFFU); /// - /// Returns iff is between + /// Returns if and only if is between /// and , inclusive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInRangeInclusive(uint value, uint lowerBound, uint upperBound) => (value - lowerBound) <= (upperBound - lowerBound); /// - /// Returns iff is a UTF-16 low surrogate code point, + /// Returns if and only if is a UTF-16 low surrogate code point, /// i.e., is in [ U+DC00..U+DFFF ], inclusive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsLowSurrogateCodePoint(uint value) => IsInRangeInclusive(value, 0xDC00U, 0xDFFFU); /// - /// Returns iff is a UTF-16 surrogate code point, + /// Returns if and only if is a UTF-16 surrogate code point, /// i.e., is in [ U+D800..U+DFFF ], inclusive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsSurrogateCodePoint(uint value) => IsInRangeInclusive(value, 0xD800U, 0xDFFFU); /// - /// Returns iff is a valid Unicode code + /// Returns if and only if is a valid Unicode code /// point, i.e., is in [ U+0000..U+10FFFF ], inclusive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsValidCodePoint(uint codePoint) => codePoint <= 0x10FFFFU; /// - /// Returns iff is a valid Unicode scalar + /// Returns if and only if is a valid Unicode scalar /// value, i.e., is in [ U+0000..U+D7FF ], inclusive; or [ U+E000..U+10FFFF ], inclusive. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb index 5ab6b254a1e45..536b10a5fff46 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Services/SemanticFacts/VisualBasicSemanticFacts.vb @@ -64,7 +64,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Not TypeOf ancestor Is ExpressionRangeVariableSyntax AndAlso Not TypeOf ancestor Is InferredFieldInitializerSyntax Then - Dim symbol = semanticModel.GetDeclaredSymbol(ancestor) + Dim symbol = semanticModel.GetDeclaredSymbol(ancestor, cancellationToken) If symbol IsNot Nothing Then If symbol.Locations.Contains(location) Then diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Utilities/CastAnalyzer.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Utilities/CastAnalyzer.vb index e902d3d020d31..451ce43657070 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Utilities/CastAnalyzer.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/VisualBasic/Utilities/CastAnalyzer.vb @@ -93,11 +93,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Dim parentAssignmentStatement = TryCast(parent, AssignmentStatementSyntax) If parentAssignmentStatement IsNot Nothing AndAlso parent.Kind = SyntaxKind.SimpleAssignmentStatement Then - Return semanticModel.GetTypeInfo(parentAssignmentStatement.Left).Type + Return semanticModel.GetTypeInfo(parentAssignmentStatement.Left, cancellationToken).Type End If Dim parentUnaryExpression = TryCast(parentExpression, UnaryExpressionSyntax) - If parentUnaryExpression IsNot Nothing AndAlso Not semanticModel.GetConversion(expression).IsUserDefined Then + If parentUnaryExpression IsNot Nothing AndAlso Not semanticModel.GetConversion(expression, cancellationToken).IsUserDefined Then Dim parentTypeInfo = semanticModel.GetTypeInfo(parentUnaryExpression, cancellationToken) Return GetOuterCastType(parentUnaryExpression, parentTypeInfo, semanticModel, cancellationToken) End If @@ -110,7 +110,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions parentTernaryConditional.WhenFalse, parentTernaryConditional.WhenTrue) - Return semanticModel.GetTypeInfo(otherExpression).Type + Return semanticModel.GetTypeInfo(otherExpression, cancellationToken).Type End If Dim parentSimpleArgument = TryCast(parent, SimpleArgumentSyntax) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs index 8658e9f2dedd6..9b0cadc0c9d4c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.cs @@ -138,7 +138,7 @@ public static bool ContainingTypesOrSelfHasUnsafeKeyword(this ITypeSymbol contai return null; } - catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e)) + catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken)) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ISolutionExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ISolutionExtensions.cs index 4c2fc705e3251..06ab4e6c127a5 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ISolutionExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/Core/Extensions/ISolutionExtensions.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; namespace Microsoft.CodeAnalysis.Shared.Extensions { @@ -43,15 +45,14 @@ public static Project GetRequiredProject(this Solution solution, ProjectId proje } public static Document GetRequiredDocument(this Solution solution, DocumentId documentId) - { - var document = solution.GetDocument(documentId); - if (document == null) - { - throw new InvalidOperationException(WorkspaceExtensionsResources.The_solution_does_not_contain_the_specified_document); - } + => solution.GetDocument(documentId) ?? throw new InvalidOperationException(WorkspaceExtensionsResources.The_solution_does_not_contain_the_specified_document); - return document; - } +#if !CODE_STYLE + + public static async Task GetRequiredDocumentAsync(this Solution solution, DocumentId documentId, bool includeSourceGenerated = false, CancellationToken cancellationToken = default) + => (await solution.GetDocumentAsync(documentId, includeSourceGenerated, cancellationToken).ConfigureAwait(false)) ?? throw new InvalidOperationException(WorkspaceExtensionsResources.The_solution_does_not_contain_the_specified_document); + +#endif public static TextDocument GetRequiredAdditionalDocument(this Solution solution, DocumentId documentId) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/ContextQuery/SyntaxTreeExtensions.vb b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/ContextQuery/SyntaxTreeExtensions.vb index fd22c79977074..610820363645e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/ContextQuery/SyntaxTreeExtensions.vb +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/VisualBasic/Extensions/ContextQuery/SyntaxTreeExtensions.vb @@ -322,7 +322,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery If targetToken.Parent.IsKind(SyntaxKind.ArgumentList) AndAlso TypeOf targetToken.Parent.Parent Is NewExpressionSyntax Then - Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(targetToken.Parent.Parent, NewExpressionSyntax).Type()) + Dim symbolInfo = semanticModel.GetSymbolInfo(DirectCast(targetToken.Parent.Parent, NewExpressionSyntax).Type(), cancellationToken) Dim objectCreationType = TryCast(symbolInfo.Symbol, ITypeSymbol) If objectCreationType IsNot Nothing AndAlso objectCreationType.TypeKind = TypeKind.Delegate Then @@ -788,7 +788,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Return False End If - Dim leftHandBinding = semanticModel.GetSymbolInfo(leftExpression) + Dim leftHandBinding = semanticModel.GetSymbolInfo(leftExpression, cancellationToken) Dim symbol = leftHandBinding.GetBestOrAllSymbols().FirstOrDefault() If symbol Is Nothing Then diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/NamedTypeGenerator.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/NamedTypeGenerator.vb index daeb98fe41f7e..1a6aa8db3f493 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/NamedTypeGenerator.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/NamedTypeGenerator.vb @@ -56,7 +56,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration service.AddMembers(declaration, GetMembers(namedType), options, cancellationToken), declaration) - Return AddFormatterAndCodeGeneratorAnnotationsTo(ConditionallyAddDocumentationCommentTo(declaration, namedType, options)) + Return AddFormatterAndCodeGeneratorAnnotationsTo(ConditionallyAddDocumentationCommentTo(declaration, namedType, options, cancellationToken)) End Function Public Function UpdateNamedTypeDeclaration(service As ICodeGenerationService, diff --git a/src/Workspaces/VisualBasic/Portable/FindSymbols/VisualBasicDeclaredSymbolInfoFactoryService.vb b/src/Workspaces/VisualBasic/Portable/FindSymbols/VisualBasicDeclaredSymbolInfoFactoryService.vb index 5e5722394d653..08d4b155a0393 100644 --- a/src/Workspaces/VisualBasic/Portable/FindSymbols/VisualBasicDeclaredSymbolInfoFactoryService.vb +++ b/src/Workspaces/VisualBasic/Portable/FindSymbols/VisualBasicDeclaredSymbolInfoFactoryService.vb @@ -131,25 +131,29 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.FindSymbols Return False End If - Select Case node.Kind() - Case SyntaxKind.ClassBlock - Dim classDecl = CType(node, ClassBlockSyntax) - declaredSymbolInfo = New DeclaredSymbolInfo( + Dim kind = node.Kind() + Select Case kind + Case SyntaxKind.ClassBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ModuleBlock, SyntaxKind.StructureBlock + Dim typeBlock = CType(node, TypeBlockSyntax) + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, - classDecl.ClassStatement.Identifier.ValueText, - GetTypeParameterSuffix(classDecl.ClassStatement.TypeParameterList), + typeDecl.BlockStatement.Identifier.ValueText, + GetTypeParameterSuffix(typeBlock.BlockStatement.TypeParameterList), GetContainerDisplayName(node.Parent), GetFullyQualifiedContainerName(node.Parent, rootNamespace), - classDecl.ClassStatement.Modifiers.Any(SyntaxKind.PartialKeyword), - DeclaredSymbolInfoKind.Class, - GetAccessibility(classDecl, classDecl.ClassStatement.Modifiers), - classDecl.ClassStatement.Identifier.Span, - GetInheritanceNames(stringTable, classDecl), - IsNestedType(classDecl)) + typeBlock.BlockStatement.Modifiers.Any(SyntaxKind.PartialKeyword), + If(kind = SyntaxKind.ClassBlock, DeclaredSymbolInfoKind.Class, + If(kind = SyntaxKind.InterfaceBlock, DeclaredSymbolInfoKind.Interface, + If(kind = SyntaxKind.ModuleBlock, DeclaredSymbolInfoKind.Module, + DeclaredSymbolInfoKind.Struct))), + GetAccessibility(typeBlock, typeBlock.BlockStatement.Modifiers), + typeBlock.BlockStatement.Identifier.Span, + GetInheritanceNames(stringTable, typeBlock), + IsNestedType(typeBlock)) Return True Case SyntaxKind.EnumBlock Dim enumDecl = CType(node, EnumBlockSyntax) - declaredSymbolInfo = New DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, enumDecl.EnumStatement.Identifier.ValueText, Nothing, GetContainerDisplayName(node.Parent), @@ -161,56 +165,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.FindSymbols ImmutableArray(Of String).Empty, IsNestedType(enumDecl)) Return True - Case SyntaxKind.InterfaceBlock - Dim interfaceDecl = CType(node, InterfaceBlockSyntax) - declaredSymbolInfo = New DeclaredSymbolInfo( - stringTable, - interfaceDecl.InterfaceStatement.Identifier.ValueText, - GetTypeParameterSuffix(interfaceDecl.InterfaceStatement.TypeParameterList), - GetContainerDisplayName(node.Parent), - GetFullyQualifiedContainerName(node.Parent, rootNamespace), - interfaceDecl.InterfaceStatement.Modifiers.Any(SyntaxKind.PartialKeyword), - DeclaredSymbolInfoKind.Interface, - GetAccessibility(interfaceDecl, interfaceDecl.InterfaceStatement.Modifiers), - interfaceDecl.InterfaceStatement.Identifier.Span, - GetInheritanceNames(stringTable, interfaceDecl), - IsNestedType(interfaceDecl)) - Return True - Case SyntaxKind.ModuleBlock - Dim moduleDecl = CType(node, ModuleBlockSyntax) - declaredSymbolInfo = New DeclaredSymbolInfo( - stringTable, - moduleDecl.ModuleStatement.Identifier.ValueText, - GetTypeParameterSuffix(moduleDecl.ModuleStatement.TypeParameterList), - GetContainerDisplayName(node.Parent), - GetFullyQualifiedContainerName(node.Parent, rootNamespace), - moduleDecl.ModuleStatement.Modifiers.Any(SyntaxKind.PartialKeyword), - DeclaredSymbolInfoKind.Module, - GetAccessibility(moduleDecl, moduleDecl.ModuleStatement.Modifiers), - moduleDecl.ModuleStatement.Identifier.Span, - GetInheritanceNames(stringTable, moduleDecl), - IsNestedType(moduleDecl)) - Return True - Case SyntaxKind.StructureBlock - Dim structDecl = CType(node, StructureBlockSyntax) - declaredSymbolInfo = New DeclaredSymbolInfo( - stringTable, - structDecl.StructureStatement.Identifier.ValueText, - GetTypeParameterSuffix(structDecl.StructureStatement.TypeParameterList), - GetContainerDisplayName(node.Parent), - GetFullyQualifiedContainerName(node.Parent, rootNamespace), - structDecl.StructureStatement.Modifiers.Any(SyntaxKind.PartialKeyword), - DeclaredSymbolInfoKind.Struct, - GetAccessibility(structDecl, structDecl.StructureStatement.Modifiers), - structDecl.StructureStatement.Identifier.Span, - GetInheritanceNames(stringTable, structDecl), - IsNestedType(structDecl)) - Return True Case SyntaxKind.ConstructorBlock Dim constructor = CType(node, ConstructorBlockSyntax) Dim typeBlock = TryCast(constructor.Parent, TypeBlockSyntax) If typeBlock IsNot Nothing Then - declaredSymbolInfo = New DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, typeBlock.BlockStatement.Identifier.ValueText, GetConstructorSuffix(constructor), @@ -227,7 +186,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.FindSymbols End If Case SyntaxKind.DelegateFunctionStatement, SyntaxKind.DelegateSubStatement Dim delegateDecl = CType(node, DelegateStatementSyntax) - declaredSymbolInfo = New DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, delegateDecl.Identifier.ValueText, GetTypeParameterSuffix(delegateDecl.TypeParameterList), @@ -241,7 +200,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.FindSymbols Return True Case SyntaxKind.EnumMemberDeclaration Dim enumMember = CType(node, EnumMemberDeclarationSyntax) - declaredSymbolInfo = New DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, enumMember.Identifier.ValueText, Nothing, GetContainerDisplayName(node.Parent), @@ -256,7 +215,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.FindSymbols Dim eventDecl = CType(node, EventStatementSyntax) Dim statementOrBlock = If(TypeOf node.Parent Is EventBlockSyntax, node.Parent, node) Dim eventParent = statementOrBlock.Parent - declaredSymbolInfo = New DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, eventDecl.Identifier.ValueText, Nothing, GetContainerDisplayName(eventParent), @@ -269,7 +228,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.FindSymbols Return True Case SyntaxKind.FunctionBlock, SyntaxKind.SubBlock Dim funcDecl = CType(node, MethodBlockSyntax) - declaredSymbolInfo = New DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, funcDecl.SubOrFunctionStatement.Identifier.ValueText, GetMethodSuffix(funcDecl), @@ -288,16 +247,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.FindSymbols Dim variableDeclarator = TryCast(modifiedIdentifier.Parent, VariableDeclaratorSyntax) Dim fieldDecl = TryCast(variableDeclarator?.Parent, FieldDeclarationSyntax) If fieldDecl IsNot Nothing Then - Dim kind = If(fieldDecl.Modifiers.Any(Function(m) m.Kind() = SyntaxKind.ConstKeyword), - DeclaredSymbolInfoKind.Constant, - DeclaredSymbolInfoKind.Field) - declaredSymbolInfo = New DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, modifiedIdentifier.Identifier.ValueText, Nothing, GetContainerDisplayName(fieldDecl.Parent), GetFullyQualifiedContainerName(fieldDecl.Parent, rootNamespace), fieldDecl.Modifiers.Any(SyntaxKind.PartialKeyword), - kind, + If(fieldDecl.Modifiers.Any(Function(m) m.Kind() = SyntaxKind.ConstKeyword), + DeclaredSymbolInfoKind.Constant, + DeclaredSymbolInfoKind.Field), GetAccessibility(fieldDecl, fieldDecl.Modifiers), modifiedIdentifier.Identifier.Span, ImmutableArray(Of String).Empty) @@ -307,7 +265,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.FindSymbols Dim propertyDecl = CType(node, PropertyStatementSyntax) Dim statementOrBlock = If(TypeOf node.Parent Is PropertyBlockSyntax, node.Parent, node) Dim propertyParent = statementOrBlock.Parent - declaredSymbolInfo = New DeclaredSymbolInfo( + declaredSymbolInfo = DeclaredSymbolInfo.Create( stringTable, propertyDecl.Identifier.ValueText, GetPropertySuffix(propertyDecl), diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb index f7160f1b1317a..b7e67bd324505 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Reducers/VisualBasicExtensionMethodReducer.vb @@ -31,7 +31,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification If invocationExpression.Expression?.Kind = SyntaxKind.SimpleMemberAccessExpression Then Dim memberAccess = DirectCast(invocationExpression.Expression, MemberAccessExpressionSyntax) - Dim targetSymbol = semanticModel.GetSymbolInfo(memberAccess.Name) + Dim targetSymbol = semanticModel.GetSymbolInfo(memberAccess.Name, cancellationToken) If (Not targetSymbol.Symbol Is Nothing) AndAlso targetSymbol.Symbol.Kind = SymbolKind.Method Then Dim targetMethodSymbol = DirectCast(targetSymbol.Symbol, IMethodSymbol) @@ -49,7 +49,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Dim rewrittenArgumentList = argumentList.WithArguments(newArguments) Dim candidateRewrittenNode = SyntaxFactory.InvocationExpression(newMemberAccess, rewrittenArgumentList) - Dim oldSymbol = semanticModel.GetSymbolInfo(invocationExpression).Symbol + Dim oldSymbol = semanticModel.GetSymbolInfo(invocationExpression, cancellationToken).Symbol Dim newSymbol = semanticModel.GetSpeculativeSymbolInfo( invocationExpression.SpanStart, candidateRewrittenNode, diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb index 283e802cade97..56100edb88125 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/ExpressionSimplifier.vb @@ -271,7 +271,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers ByRef issueSpan As TextSpan, cancellationToken As CancellationToken) As Boolean If memberAccess.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) Then - Dim symbolForMemberAccess = semanticModel.GetSymbolInfo(DirectCast(memberAccess.Parent, MemberAccessExpressionSyntax)).Symbol + Dim symbolForMemberAccess = semanticModel.GetSymbolInfo(DirectCast(memberAccess.Parent, MemberAccessExpressionSyntax), cancellationToken).Symbol If symbolForMemberAccess.IsModuleMember Then replacementNode = memberAccess.Expression.WithLeadingTrivia(memberAccess.GetLeadingTrivia()) issueSpan = memberAccess.Name.Span diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb index 88d97a7f626ba..cffebfafa94e9 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/Simplifiers/NameSimplifier.vb @@ -153,7 +153,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers ' QualifiedNames can't contain PredefinedTypeNames (although MemberAccessExpressions can). ' In other words, the left side of a QualifiedName can't be a PredefinedTypeName. If nameHasNoAlias AndAlso aliasInfo Is Nothing AndAlso Not name.Parent.IsKind(SyntaxKind.QualifiedName) Then - Dim type = semanticModel.GetTypeInfo(name).Type + Dim type = semanticModel.GetTypeInfo(name, cancellationToken).Type If type IsNot Nothing Then Dim keywordKind = GetPredefinedKeywordKind(type.SpecialType) If keywordKind <> SyntaxKind.None Then @@ -320,7 +320,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification.Simplifiers Private Shared Function TryOmitModuleName(name As QualifiedNameSyntax, semanticModel As SemanticModel, ByRef replacementNode As ExpressionSyntax, ByRef issueSpan As TextSpan, cancellationToken As CancellationToken) As Boolean If name.IsParentKind(SyntaxKind.QualifiedName) Then - Dim symbolForName = semanticModel.GetSymbolInfo(DirectCast(name.Parent, QualifiedNameSyntax)).Symbol + Dim symbolForName = semanticModel.GetSymbolInfo(DirectCast(name.Parent, QualifiedNameSyntax), cancellationToken).Symbol ' in case this QN is used in a "New NSName.ModuleName.MemberName()" expression ' the returned symbol is a constructor. Then we need to get the containing type. diff --git a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb index 5a8590ac89afc..fc044d52fc5d4 100644 --- a/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb +++ b/src/Workspaces/VisualBasic/Portable/Simplification/VisualBasicSimplificationService.vb @@ -150,7 +150,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification Private Const s_BC50001_UnusedImportsStatement As String = "BC50001" Protected Overrides Sub GetUnusedNamespaceImports(model As SemanticModel, namespaceImports As HashSet(Of SyntaxNode), cancellationToken As CancellationToken) - Dim root = model.SyntaxTree.GetRoot() + Dim root = model.SyntaxTree.GetRoot(cancellationToken) Dim diagnostics = model.GetDiagnostics(cancellationToken:=cancellationToken) For Each diagnostic In diagnostics