diff --git a/README.md b/README.md index 376e05f29d80c..74b1b5e1b2949 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ If you want to get started using Roslyn's APIs to analyzer your code take a look **The latest pre-release builds** are available from the following public NuGet feeds: - [Compiler](https://dev.azure.com/dnceng/public/_packaging?_a=feed&feed=dotnet-tools): `https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json` -- [IDE Services](https://devdiv.visualstudio.com/DevDiv/_packaging?_a=feed&feed=vssdk): `https://devdiv.pkgs.visualstudio.com/_packaging/vssdk/nuget/v3/index.json` +- [IDE Services](https://dev.azure.com/azure-public/vside/_packaging?_a=feed&feed=vssdk): `https://pkgs.dev.azure.com/azure-public/vside/_packaging/vssdk/nuget/v3/index.json` - [.NET SDK](https://dev.azure.com/dnceng/public/_packaging?_a=feed&feed=dotnet5): `https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json` [//]: # (Begin current test results) diff --git a/eng/config/test/Core/InstallTraceListener.cs b/eng/config/test/Core/InstallTraceListener.cs new file mode 100644 index 0000000000000..968c7d0e1a09e --- /dev/null +++ b/eng/config/test/Core/InstallTraceListener.cs @@ -0,0 +1,13 @@ +// + +using System.Runtime.CompilerServices; +using Roslyn.Test.Utilities; + +internal sealed class InitializeTestModule +{ + [ModuleInitializer] + internal static void Initializer() + { + RuntimeHelpers.RunModuleConstructor(typeof(TestBase).Module.ModuleHandle); + } +} diff --git a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems index 0efeba0ffee6c..de39f449b6d94 100644 --- a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems +++ b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems @@ -74,6 +74,7 @@ + diff --git a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx index b9bc8679ff712..6b9e29189414c 100644 --- a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx +++ b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx @@ -292,4 +292,11 @@ 'typeof' can be converted to 'nameof' + + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + + + 'new' expression can be simplified + \ No newline at end of file diff --git a/src/Analyzers/CSharp/Analyzers/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationDiagnosticAnalyzer.cs new file mode 100644 index 0000000000000..69f2daf620033 --- /dev/null +++ b/src/Analyzers/CSharp/Analyzers/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationDiagnosticAnalyzer.cs @@ -0,0 +1,126 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Utilities; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.CSharp.UseImplicitObjectCreation +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + internal class CSharpUseImplicitObjectCreationDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer + { + public CSharpUseImplicitObjectCreationDiagnosticAnalyzer() + : base(IDEDiagnosticIds.UseImplicitObjectCreationDiagnosticId, + CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent, + LanguageNames.CSharp, + new LocalizableResourceString(nameof(CSharpAnalyzersResources.Use_new), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources)), + new LocalizableResourceString(nameof(CSharpAnalyzersResources.new_expression_can_be_simplified), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources))) + { + } + + public override DiagnosticAnalyzerCategory GetAnalyzerCategory() + => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; + + protected override void InitializeWorker(AnalysisContext context) + => context.RegisterSyntaxNodeAction(AnalyzeSyntax, SyntaxKind.ObjectCreationExpression); + + private void AnalyzeSyntax(SyntaxNodeAnalysisContext context) + { + var options = context.Options; + var syntaxTree = context.Node.SyntaxTree; + var semanticModel = context.SemanticModel; + var cancellationToken = context.CancellationToken; + + // Not available prior to C# 9. + if (((CSharpParseOptions)syntaxTree.Options).LanguageVersion < LanguageVersion.CSharp9) + return; + + var optionSet = options.GetAnalyzerOptionSet(syntaxTree, cancellationToken); + var styleOption = options.GetOption(CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent, syntaxTree, cancellationToken); + if (!styleOption.Value) + { + // Bail immediately if the user has disabled this feature. + return; + } + + // type is apparent if we the object creation location is closely tied (spatially) to the explicit type. Specifically: + // + // 1. Variable declarations. i.e. `List list = new ...`. Note: we will suppress ourselves if this + // is a field and the 'var' preferences would lead to preferring this as `var list = ...` + // 2. Expression-bodied constructs with an explicit return type. i.e. `List Prop => new ...` or + // `List GetValue(...) => ...` The latter doesn't necessarily have the object creation spatially next to + // the type. However, the type is always in a very easy to ascertain location in C#, so it is treated as + // apparent. + + var objectCreation = (ObjectCreationExpressionSyntax)context.Node; + + TypeSyntax? typeNode; + + if (objectCreation.Parent.IsKind(SyntaxKind.EqualsValueClause) && + objectCreation.Parent.Parent.IsKind(SyntaxKind.VariableDeclarator) && + objectCreation.Parent.Parent.Parent is VariableDeclarationSyntax variableDeclaration && + !variableDeclaration.Type.IsVar) + { + typeNode = variableDeclaration.Type; + + var helper = CSharpUseImplicitTypeHelper.Instance; + if (helper.ShouldAnalyzeVariableDeclaration(variableDeclaration, cancellationToken) && + helper.AnalyzeTypeName(typeNode, semanticModel, optionSet, cancellationToken).IsStylePreferred) + { + // this is a case where the user would prefer 'var'. don't offer to use an implicit object here. + return; + } + } + else if (objectCreation.Parent.IsKind(SyntaxKind.ArrowExpressionClause)) + { + typeNode = objectCreation.Parent.Parent switch + { + LocalFunctionStatementSyntax localFunction => localFunction.ReturnType, + MethodDeclarationSyntax method => method.ReturnType, + ConversionOperatorDeclarationSyntax conversion => conversion.Type, + OperatorDeclarationSyntax op => op.ReturnType, + BasePropertyDeclarationSyntax property => property.Type, + AccessorDeclarationSyntax { RawKind: (int)SyntaxKind.GetAccessorDeclaration, Parent: AccessorListSyntax { Parent: BasePropertyDeclarationSyntax baseProperty } } accessor => baseProperty.Type, + _ => null, + }; + } + else + { + // more cases can be added here if we discover more cases we think the type is readily apparent from context. + return; + } + + if (typeNode == null) + return; + + // Only offer if the type being constructed is the exact same as the type being assigned into. We don't + // want to change semantics by trying to instantiate something else. + var leftType = semanticModel.GetTypeInfo(typeNode, cancellationToken).Type; + var rightType = semanticModel.GetTypeInfo(objectCreation, cancellationToken).Type; + + if (leftType is null || rightType is null) + return; + + if (leftType.IsErrorType() || rightType.IsErrorType()) + return; + + if (!leftType.Equals(rightType, SymbolEqualityComparer.Default)) + return; + + context.ReportDiagnostic(DiagnosticHelper.Create( + Descriptor, + objectCreation.Type.GetLocation(), + styleOption.Notification.Severity, + ImmutableArray.Create(objectCreation.GetLocation()), + properties: null)); + } + } +} diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf index 74920414d2772..c110e2e319041 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf @@ -202,6 +202,11 @@ Použít lokální funkci + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching Použít porovnávání vzorů @@ -262,6 +267,11 @@ Příkaz if lze zjednodušit. + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' typeof se dá převést na nameof. diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf index 84f56fc7673d1..7d5f77eead9c4 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf @@ -202,6 +202,11 @@ Lokale Funktion verwenden + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching Musterabgleich verwenden @@ -262,6 +267,11 @@ Die If-Anweisung kann vereinfacht werden. + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' 'typeof' can be converted to 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf index dafa96a93b761..dfcad1013fc27 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf @@ -202,6 +202,11 @@ Usar función local + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching Usar coincidencia de patrones @@ -262,6 +267,11 @@ La instrucción "if" se puede simplificar + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' 'typeof' can be converted to 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf index d1e988b52f723..7125856887f1a 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf @@ -202,6 +202,11 @@ Utiliser une fonction locale + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching Utiliser les critères spéciaux @@ -262,6 +267,11 @@ L'instruction 'if' peut être simplifiée + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' 'typeof' can be converted to 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf index e196b87352318..6d6539304d662 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf @@ -202,6 +202,11 @@ Usa la funzione locale + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching Usa i criteri di ricerca @@ -262,6 +267,11 @@ L'istruzione 'If' può essere semplificata + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' 'typeof' can be converted to 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf index bbffa53596a07..f921c7d68574f 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf @@ -202,6 +202,11 @@ ローカル関数を使用します + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching パターン マッチングを使用します @@ -262,6 +267,11 @@ 'if' ステートメントは簡素化できます + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' 'typeof' can be converted to 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf index 2b5f98b36e0c8..aaaadb7388852 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf @@ -202,6 +202,11 @@ 로컬 함수 사용 + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching 패턴 일치 사용 @@ -262,6 +267,11 @@ 'if' 문을 간단하게 줄일 수 있습니다. + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' 'typeof' can be converted to 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf index 0f3b263a9e11f..7eb173f653946 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf @@ -202,6 +202,11 @@ Użyj funkcji lokalnej + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching Użyj dopasowywania wzorców @@ -262,6 +267,11 @@ Instrukcja „if” może zostać uproszczona + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' 'typeof' can be converted to 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf index 2d88d00089774..bf7b815656e8b 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf @@ -202,6 +202,11 @@ Usar função local + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching Usar a correspondência de padrão @@ -262,6 +267,11 @@ A instrução 'if' pode ser simplificada + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' 'typeof' can be converted to 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf index e8a4616e472f1..e331fa8db6f3a 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf @@ -202,6 +202,11 @@ Использовать локальную функцию + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching Используйте сопоставление шаблонов @@ -262,6 +267,11 @@ Оператор if можно упростить + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' 'typeof' can be converted to 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf index f3918258c54b6..8a03e12cc00eb 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf @@ -202,6 +202,11 @@ Yerel işlev kullan + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching Desen eşleştirme kullan @@ -262,6 +267,11 @@ 'If' deyimi basitleştirilebilir + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' 'typeof' can be converted to 'nameof' diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf index 748cbed12afc5..bdbd208956dfb 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf @@ -202,6 +202,11 @@ 使用本地函数 + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching 使用模式匹配 @@ -262,6 +267,11 @@ 可简化“If”语句 + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' "typeof" 可以转换为 "nameof" diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf index bccc0489b0adc..1349e543deb3a 100644 --- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf +++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf @@ -202,6 +202,11 @@ 使用區域函式 + + Use 'new(...)' + Use 'new(...)' + {Locked="new(...)"} This is a C# construct and should not be localized. + Use pattern matching 使用模式比對 @@ -262,6 +267,11 @@ 'if' 陳述式可簡化 + + 'new' expression can be simplified + 'new' expression can be simplified + + 'typeof' can be converted to 'nameof' 'typeof' can be converted to 'nameof' diff --git a/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems b/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems index 8ba1d0e8aec03..40f5c81727d2b 100644 --- a/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems +++ b/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems @@ -48,6 +48,7 @@ + diff --git a/src/Analyzers/CSharp/CodeFixes/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationCodeFixProvider.cs new file mode 100644 index 0000000000000..b906cf9fee13e --- /dev/null +++ b/src/Analyzers/CSharp/CodeFixes/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationCodeFixProvider.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.Immutable; +using System.Composition; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Extensions; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.UseImplicitObjectCreation +{ + [ExportCodeFixProvider(LanguageNames.CSharp), Shared] + internal class CSharpUseImplicitObjectCreationCodeFixProvider : SyntaxEditorBasedCodeFixProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public CSharpUseImplicitObjectCreationCodeFixProvider() + { + } + + public override ImmutableArray FixableDiagnosticIds + => ImmutableArray.Create(IDEDiagnosticIds.UseImplicitObjectCreationDiagnosticId); + + internal sealed override CodeFixCategory CodeFixCategory => CodeFixCategory.CodeStyle; + + protected override bool IncludeDiagnosticDuringFixAll(Diagnostic diagnostic) + => !diagnostic.IsSuppressed; + + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + context.RegisterCodeFix( + new MyCodeAction(c => FixAsync(context.Document, context.Diagnostics.First(), c)), + context.Diagnostics); + return Task.CompletedTask; + } + + protected override Task FixAllAsync( + Document document, ImmutableArray diagnostics, + SyntaxEditor editor, CancellationToken cancellationToken) + { + // process from inside->out so that outer rewrites see the effects of inner changes. + foreach (var diagnostic in diagnostics.OrderBy(d => d.Location.SourceSpan.End)) + FixOne(editor, diagnostic, cancellationToken); + + return Task.CompletedTask; + } + + private static void FixOne(SyntaxEditor editor, Diagnostic diagnostic, CancellationToken cancellationToken) + { + var node = diagnostic.AdditionalLocations[0].FindNode(getInnermostNodeForTie: true, cancellationToken); + editor.ReplaceNode(node, (current, _) => + { + var currentObjectCreation = (ObjectCreationExpressionSyntax)current; + return SyntaxFactory.ImplicitObjectCreationExpression( + WithoutTrailingWhitespace(currentObjectCreation.NewKeyword), + currentObjectCreation.ArgumentList ?? SyntaxFactory.ArgumentList(), + currentObjectCreation.Initializer); + }); + } + + private static SyntaxToken WithoutTrailingWhitespace(SyntaxToken newKeyword) + { + return newKeyword.TrailingTrivia.All(t => t.IsWhitespace()) + ? newKeyword.WithoutTrailingTrivia() + : newKeyword; + } + + private class MyCodeAction : CustomCodeActions.DocumentChangeAction + { + public MyCodeAction(Func> createChangedDocument) + : base(CSharpAnalyzersResources.Use_new, createChangedDocument, CSharpAnalyzersResources.Use_new) + { + } + } + } +} diff --git a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems index 22a2b50061755..3a0e8886c5621 100644 --- a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems +++ b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems @@ -82,6 +82,7 @@ + diff --git a/src/Analyzers/CSharp/Tests/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationTests.cs b/src/Analyzers/CSharp/Tests/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationTests.cs new file mode 100644 index 0000000000000..ef80deb30a6db --- /dev/null +++ b/src/Analyzers/CSharp/Tests/UseImplicitObjectCreation/CSharpUseImplicitObjectCreationTests.cs @@ -0,0 +1,597 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.UseImplicitObjectCreation; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Testing; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseImplicitObjectCreationTests +{ + using VerifyCS = CSharpCodeFixVerifier< + CSharpUseImplicitObjectCreationDiagnosticAnalyzer, + CSharpUseImplicitObjectCreationCodeFixProvider>; + + public class UseImplicitObjectCreationTests + { + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestMissingBeforeCSharp9() + { + var source = @" +class C +{ + C c = new C(); +}"; + await new VerifyCS.Test + { + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8, + TestCode = source, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestAfterCSharp9() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + C c = new [|C|](); +}", + FixedCode = @" +class C +{ + C c = new(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithObjectInitializer() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + C c = new [|C|]() { }; +}", + FixedCode = @" +class C +{ + C c = new() { }; +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithObjectInitializerWithoutArguments() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + C c = new [|C|] { }; +}", + FixedCode = @" +class C +{ + C c = new() { }; +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithTriviaAfterNew() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + C c = new /*x*/ [|C|](); +}", + FixedCode = @" +class C +{ + C c = new /*x*/ (); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestNotWithDifferentTypes() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + object c = new C(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestNotWithErrorTypes() + { + await new VerifyCS.Test + { + TestState = { + Sources = + { + @" +class C +{ + {|#0:E|} c = new {|#1:E|}(); +}" + }, + ExpectedDiagnostics = + { + // /0/Test0.cs(4,5): error CS0246: The type or namespace name 'E' could not be found (are you missing a using directive or an assembly reference?) + DiagnosticResult.CompilerError("CS0246").WithLocation(0).WithArguments("E"), + // /0/Test0.cs(4,15): error CS0246: The type or namespace name 'E' could not be found (are you missing a using directive or an assembly reference?) + DiagnosticResult.CompilerError("CS0246").WithLocation(1).WithArguments("E"), + } + }, + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestNotWithDynamic() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + dynamic c = new C(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestNotWithArrayTypes() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + int[] c = new int[0]; +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithTypeParameter() + { + await new VerifyCS.Test + { + TestCode = @" +class C where T : new() +{ + T t = new [|T|](); +}", + FixedCode = @" +class C where T : new() +{ + T t = new(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithLocalWhenUserDoesNotPreferVar() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + void M() + { + C c = new [|C|](); + } +}", + FixedCode = @" +class C +{ + void M() + { + C c = new(); + } +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + Options = + { + { CSharpCodeStyleOptions.VarWhenTypeIsApparent, CodeStyleOptions2.FalseWithSuggestionEnforcement }, + } + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestNotWithLocalWhenUserDoesPreferVar() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + void M() + { + C c = new C(); + } +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + Options = + { + { CSharpCodeStyleOptions.VarWhenTypeIsApparent, CodeStyleOptions2.TrueWithSuggestionEnforcement }, + } + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithForVariable() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + void M() + { + for (C c = new [|C|]();;) + { + } + } +}", + FixedCode = @" +class C +{ + void M() + { + for (C c = new();;) + { + } + } +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithLocalFunctionExpressionBody() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + void M() + { + C Func() => new [|C|](); + } +}", + FixedCode = @" +class C +{ + void M() + { + C Func() => new(); + } +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithMethodExpressionBody() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + C Func() => new [|C|](); +}", + FixedCode = @" +class C +{ + C Func() => new(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithConversionExpressionBody() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + public static implicit operator C(int i) => new [|C|](); +}", + FixedCode = @" +class C +{ + public static implicit operator C(int i) => new(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithOperatorExpressionBody() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + public static C operator +(C c1, C c2) => new [|C|](); +}", + FixedCode = @" +class C +{ + public static C operator +(C c1, C c2) => new(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithPropertyExpressionBody() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + C P => new [|C|](); +}", + FixedCode = @" +class C +{ + C P => new(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithPropertyAccessorExpressionBody() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + C P { get => new [|C|](); } +}", + FixedCode = @" +class C +{ + C P { get => new(); } +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestNotWithPropertySetAccessorExpressionBody() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + C P { set => new C(); } +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithIndexerExpressionBody() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + C this[int i] => new [|C|](); +}", + FixedCode = @" +class C +{ + C this[int i] => new(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestWithIndexerAccessorExpressionBody() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + C this[int i] { get => new [|C|](); } +}", + FixedCode = @" +class C +{ + C this[int i] { get => new(); } +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestNotWithMethodBlockBody() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + C Func() { return new C(); } +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestNotInNonApparentCode1() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + void X() => Bar(new C()); + void Bar(C c) { } +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestNotInNonApparentCode2() + { + await new VerifyCS.Test + { + TestCode = @" +class C +{ + void X() + { + C c; + c = new C(); + } +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestQualifiedUnqualified1() + { + await new VerifyCS.Test + { + TestCode = @" +using System.Collections.Generic; +class C +{ + List list = new [|System.Collections.Generic.List|](); +}", + FixedCode = @" +using System.Collections.Generic; +class C +{ + List list = new(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestQualifiedUnqualified2() + { + await new VerifyCS.Test + { + TestCode = @" +using System.Collections.Generic; +class C +{ + System.Collections.Generic.List list = new [|List|](); +}", + FixedCode = @" +using System.Collections.Generic; +class C +{ + System.Collections.Generic.List list = new(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestAlias() + { + await new VerifyCS.Test + { + TestCode = @" +using System.Collections.Generic; +using X = System.Collections.Generic.List; +class C +{ + System.Collections.Generic.List list = new [|X|](); +}", + FixedCode = @" +using System.Collections.Generic; +using X = System.Collections.Generic.List; +class C +{ + System.Collections.Generic.List list = new(); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitObjectCreation)] + public async Task TestFixAll1() + { + await new VerifyCS.Test + { + TestCode = @" +using System; +class C +{ + public C() { } + public C(Action action) { } + + C c1 = new [|C|](() => + { + C c2 = new [|C|](); + }); +}", + FixedCode = @" +using System; +class C +{ + public C() { } + public C(Action action) { } + + C c1 = new(() => + { + C c2 = new(); + }); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9, + }.RunAsync(); + } + } +} diff --git a/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs b/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs index d278de0d9c790..164a035682dce 100644 --- a/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs +++ b/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs @@ -145,6 +145,8 @@ internal static class IDEDiagnosticIds public const string UseNotPatternDiagnosticId = "IDE0083"; public const string UseIsNotExpressionDiagnosticId = "IDE0084"; + public const string UseImplicitObjectCreationDiagnosticId = "IDE0090"; + // Analyzer error Ids public const string AnalyzerChangedId = "IDE1001"; public const string AnalyzerDependencyConflictId = "IDE1002"; diff --git a/src/EditorFeatures/CSharpTest/AddParameter/AddParameterTests.cs b/src/EditorFeatures/CSharpTest/AddParameter/AddParameterTests.cs index f2c7682f5a78a..784c381fbf331 100644 --- a/src/EditorFeatures/CSharpTest/AddParameter/AddParameterTests.cs +++ b/src/EditorFeatures/CSharpTest/AddParameter/AddParameterTests.cs @@ -2784,5 +2784,31 @@ void local(int x, int y, int v) } "); } + + [WorkItem(42559, "https://github.com/dotnet/roslyn/issues/42559")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddParameter)] + public async Task TestAddParameter_TargetTypedNew() + { + await TestInRegularAndScriptAsync(@" +class C +{ + C(int i) { } + + void M() + { + C c = [||]new(1, 2); + } +}", +@" +class C +{ + C(int i, int v) { } + + void M() + { + C c = new(1, 2); + } +}"); + } } } diff --git a/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs index ed899db3f6b76..a5297805fcbb4 100644 --- a/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/SemanticClassifierTests.cs @@ -13,7 +13,6 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Remote.Testing; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; @@ -34,12 +33,12 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Classification [Trait(Traits.Feature, Traits.Features.Classification)] public class SemanticClassifierTests : AbstractCSharpClassifierTests { - protected override Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions options, TestHost testHost) + protected override async Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions options, TestHost testHost) { using var workspace = CreateWorkspace(code, options, testHost); var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); - return GetSemanticClassificationsAsync(document, span); + return await GetSemanticClassificationsAsync(document, span); } [Theory] diff --git a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs index cc60724ad5cd1..f3ae5a457e2c2 100644 --- a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs @@ -8,9 +8,7 @@ using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; -using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Remote.Testing; -using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; @@ -20,12 +18,12 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Classification { public partial class SyntacticClassifierTests : AbstractCSharpClassifierTests { - protected override Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions options, TestHost testHost) + protected override async Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions options, TestHost testHost) { using var workspace = CreateWorkspace(code, options, testHost); var document = workspace.CurrentSolution.Projects.First().Documents.First(); - return GetSyntacticClassificationsAsync(document, span); + return await GetSyntacticClassificationsAsync(document, span); } [Theory] diff --git a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs index a7af23948433d..0526cfb383a93 100644 --- a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs @@ -19,12 +19,12 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Classification [Trait(Traits.Feature, Traits.Features.Classification)] public partial class TotalClassifierTests : AbstractCSharpClassifierTests { - protected override Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions options, TestHost testHost) + protected override async Task> GetClassificationSpansAsync(string code, TextSpan span, ParseOptions options, TestHost testHost) { using var workspace = CreateWorkspace(code, options, testHost); var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); - return GetAllClassificationsAsync(document, span); + return await GetAllClassificationsAsync(document, span); } [Theory] diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs index 1777bbf145a2f..642e9136b131d 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs @@ -4,6 +4,7 @@ using System; using System.Linq; +using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; @@ -3044,6 +3045,7 @@ public override bool Bar(Baz baz) } [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(47941, "https://github.com/dotnet/roslyn/issues/47941")] public async Task OverrideInRecordWithoutExplicitOverriddenMember() { await VerifyItemExistsAsync(@"record Program @@ -3053,6 +3055,7 @@ await VerifyItemExistsAsync(@"record Program } [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(47941, "https://github.com/dotnet/roslyn/issues/47941")] public async Task OverrideInRecordWithExplicitOverriddenMember() { await VerifyItemIsAbsentAsync(@"record Program @@ -3062,5 +3065,25 @@ await VerifyItemIsAbsentAsync(@"record Program override $$ }", "ToString()"); } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + [WorkItem(47973, "https://github.com/dotnet/roslyn/issues/47973")] + public async Task NoCloneInOverriddenRecord() + { + // Currently WellKnownMemberNames.CloneMethodName is not public, so we can't reference it directly. We + // could hardcode in the value "$", however if the compiler ever changed the name and we somehow + // started showing it in completion, this test would continue to pass. So this allows us to at least go + // back and explicitly validate this scenario even in that event. + var cloneMemberName = (string)typeof(WellKnownMemberNames).GetField("CloneMethodName", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null); + Assert.Equal("$", cloneMemberName); + + await VerifyItemIsAbsentAsync(@" +record Base(); + +record Program : Base +{ + override $$ +}", cloneMemberName); + } } } diff --git a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs index 8195046306ba5..6e558e0c80946 100644 --- a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs @@ -397,6 +397,9 @@ public void CSharp_VerifyIDEDiagnosticSeveritiesAreConfigurable() # IDE0083 csharp_style_prefer_not_pattern = true:suggestion +# IDE0090 +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion + # IDE1005 csharp_style_conditional_delegate_call = true:suggestion @@ -942,6 +945,9 @@ No editorconfig based code style option # IDE0083, PreferNotPattern csharp_style_prefer_not_pattern = true:suggestion +# IDE0090, ImplicitObjectCreationWhenTypeIsApparent +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion + # IDE1005, PreferConditionalDelegateCall csharp_style_conditional_delegate_call = true:suggestion diff --git a/src/EditorFeatures/VisualBasicTest/Classification/SemanticClassifierTests.vb b/src/EditorFeatures/VisualBasicTest/Classification/SemanticClassifierTests.vb index 14d9a917110b9..073776aead0e6 100644 --- a/src/EditorFeatures/VisualBasicTest/Classification/SemanticClassifierTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Classification/SemanticClassifierTests.vb @@ -5,7 +5,6 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.Classification Imports Microsoft.CodeAnalysis.Editor.UnitTests.Classification.FormattedClassifications -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Remote.Testing Imports Microsoft.CodeAnalysis.Text @@ -14,11 +13,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Classification Public Class SemanticClassifierTests Inherits AbstractVisualBasicClassifierTests - Protected Overrides Function GetClassificationSpansAsync(code As String, span As TextSpan, parseOptions As ParseOptions, testHost As TestHost) As Task(Of ImmutableArray(Of ClassifiedSpan)) + Protected Overrides Async Function GetClassificationSpansAsync(code As String, span As TextSpan, parseOptions As ParseOptions, testHost As TestHost) As Task(Of ImmutableArray(Of ClassifiedSpan)) Using workspace = CreateWorkspace(code, testHost) Dim document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id) - Return GetSemanticClassificationsAsync(document, span) + Return Await GetSemanticClassificationsAsync(document, span) End Using End Function diff --git a/src/EditorFeatures/VisualBasicTest/Classification/SyntacticClassifierTests.vb b/src/EditorFeatures/VisualBasicTest/Classification/SyntacticClassifierTests.vb index b0bba682e0bf6..d1bac7587e3de 100644 --- a/src/EditorFeatures/VisualBasicTest/Classification/SyntacticClassifierTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Classification/SyntacticClassifierTests.vb @@ -13,10 +13,10 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Classification Public Class SyntacticClassifierTests Inherits AbstractVisualBasicClassifierTests - Protected Overrides Function GetClassificationSpansAsync(code As String, span As TextSpan, parseOptions As ParseOptions, testHost As TestHost) As Task(Of ImmutableArray(Of ClassifiedSpan)) + Protected Overrides Async Function GetClassificationSpansAsync(code As String, span As TextSpan, parseOptions As ParseOptions, testHost As TestHost) As Task(Of ImmutableArray(Of ClassifiedSpan)) Using workspace = CreateWorkspace(code, testHost) Dim document = workspace.CurrentSolution.Projects.First().Documents.First() - Return GetSyntacticClassificationsAsync(document, span) + Return Await GetSyntacticClassificationsAsync(document, span) End Using End Function diff --git a/src/Features/CSharp/Portable/AddParameter/CSharpAddParameterCodeFixProvider.cs b/src/Features/CSharp/Portable/AddParameter/CSharpAddParameterCodeFixProvider.cs index 5932f2488cc89..3c8dffa24af66 100644 --- a/src/Features/CSharp/Portable/AddParameter/CSharpAddParameterCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/AddParameter/CSharpAddParameterCodeFixProvider.cs @@ -23,7 +23,7 @@ internal class CSharpAddParameterCodeFixProvider : AbstractAddParameterCodeFixPr ArgumentListSyntax, AttributeArgumentListSyntax, InvocationExpressionSyntax, - ObjectCreationExpressionSyntax> + BaseObjectCreationExpressionSyntax> { private const string CS1501 = nameof(CS1501); // error CS1501: No overload for method 'M' takes 1 arguments diff --git a/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs b/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs index 216146fef2753..96a83511489b2 100644 --- a/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs @@ -140,15 +140,25 @@ private static RegisterFixData TryGetObjectCreationFixInfo( { // Not supported if this is "new { ... }" (as there are no parameters at all. - var typeNode = syntaxFacts.GetObjectCreationType(objectCreation); + var typeNode = syntaxFacts.IsImplicitObjectCreationExpression(node) + ? node + : syntaxFacts.GetObjectCreationType(objectCreation); if (typeNode == null) { return new RegisterFixData(); } + var symbol = semanticModel.GetSymbolInfo(typeNode, cancellationToken).GetAnySymbol(); + var type = symbol switch + { + IMethodSymbol methodSymbol => methodSymbol.ContainingType, // Implicit object creation expressions + INamedTypeSymbol namedTypeSymbol => namedTypeSymbol, // Standard object creation expressions + _ => null, + }; + // If we can't figure out the type being created, or the type isn't in source, // then there's nothing we can do. - if (!(semanticModel.GetSymbolInfo(typeNode, cancellationToken).GetAnySymbol() is INamedTypeSymbol type)) + if (type == null) { return new RegisterFixData(); } diff --git a/src/Test/Utilities/Portable/Traits/Traits.cs b/src/Test/Utilities/Portable/Traits/Traits.cs index cc5e92b61e5ed..c7983b5117811 100644 --- a/src/Test/Utilities/Portable/Traits/Traits.cs +++ b/src/Test/Utilities/Portable/Traits/Traits.cs @@ -178,6 +178,7 @@ public static class Features public const string CodeActionsUseExplicitTypeForConst = "CodeActions.UseExplicitTypeForConst"; public const string CodeActionsUseExpressionBody = "CodeActions.UseExpressionBody"; public const string CodeActionsUseFrameworkType = "CodeActions.UseFrameworkType"; + public const string CodeActionsUseImplicitObjectCreation = "CodeActions.UseImplicitObjectCreation"; public const string CodeActionsUseImplicitType = "CodeActions.UseImplicitType"; public const string CodeActionsUseIndexOperator = "CodeActions.UseIndexOperator"; public const string CodeActionsUseInferredMemberName = "CodeActions.UseInferredMemberName"; diff --git a/src/Tools/Source/RunTests/AssemblyScheduler.cs b/src/Tools/Source/RunTests/AssemblyScheduler.cs index 35c7c4fdd8f26..adbdba3ec4698 100644 --- a/src/Tools/Source/RunTests/AssemblyScheduler.cs +++ b/src/Tools/Source/RunTests/AssemblyScheduler.cs @@ -2,7 +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. -using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -10,7 +9,6 @@ using System.Reflection.Metadata; using System.Reflection.PortableExecutable; using System.Text; -using System.Threading.Tasks; namespace RunTests { @@ -33,12 +31,12 @@ internal AssemblyInfo( ExtraArguments = extraArguments; } - internal AssemblyInfo(string assemblyPath, string targetFrameworkMoniker, string architecture, bool useHmtl) + internal AssemblyInfo(string assemblyPath, string targetFrameworkMoniker, string architecture, bool includeHtml) { AssemblyPath = assemblyPath; DisplayName = Path.GetFileName(assemblyPath); - var suffix = useHmtl ? "html" : "xml"; + var suffix = includeHtml ? "html" : "xml"; ResultsFileName = $"{DisplayName}_{targetFrameworkMoniker}_{architecture}.{suffix}"; ExtraArguments = string.Empty; } @@ -91,23 +89,23 @@ private sealed class AssemblyInfoBuilder private readonly StringBuilder _builder = new StringBuilder(); private readonly string _assemblyPath; private readonly int _methodLimit; - private readonly bool _useHtml; + private readonly bool _includeHtml; private readonly bool _hasEventListenerGuard; private int _currentId; private List _currentTypeInfoList = new List(); - private AssemblyInfoBuilder(string assemblyPath, int methodLimit, bool useHtml, bool hasEventListenerGuard) + private AssemblyInfoBuilder(string assemblyPath, int methodLimit, bool includeHtml, bool hasEventListenerGuard) { _assemblyPath = assemblyPath; - _useHtml = useHtml; + _includeHtml = includeHtml; _methodLimit = methodLimit; _hasEventListenerGuard = hasEventListenerGuard; } - internal static void Build(string assemblyPath, int methodLimit, bool useHtml, List typeInfoList, out List partitionList, out List assemblyInfoList) + internal static void Build(string assemblyPath, int methodLimit, bool includeHtml, List typeInfoList, out List partitionList, out List assemblyInfoList) { var hasEventListenerGuard = typeInfoList.Any(x => x.FullName == EventListenerGuardFullName); - var builder = new AssemblyInfoBuilder(assemblyPath, methodLimit, useHtml, hasEventListenerGuard); + var builder = new AssemblyInfoBuilder(assemblyPath, methodLimit, includeHtml, hasEventListenerGuard); builder.Build(typeInfoList); partitionList = builder._partitionList; assemblyInfoList = builder._assemblyInfoList; @@ -169,7 +167,7 @@ private void FinishPartition() { var assemblyName = Path.GetFileName(_assemblyPath); var displayName = $"{assemblyName}.{_currentId}"; - var suffix = _useHtml ? "html" : "xml"; + var suffix = _includeHtml ? "html" : "xml"; var resultsFileName = $"{assemblyName}.{_currentId}.{suffix}"; var assemblyInfo = new AssemblyInfo( _assemblyPath, @@ -206,7 +204,7 @@ public IEnumerable Schedule(string assemblyPath, bool force = fals var typeInfoList = GetTypeInfoList(assemblyPath); var assemblyInfoList = new List(); var partitionList = new List(); - AssemblyInfoBuilder.Build(assemblyPath, _methodLimit, _options.UseHtml, typeInfoList, out partitionList, out assemblyInfoList); + AssemblyInfoBuilder.Build(assemblyPath, _methodLimit, _options.IncludeHtml, typeInfoList, out partitionList, out assemblyInfoList); // If the scheduling didn't actually produce multiple partition then send back an unpartitioned // representation. @@ -233,7 +231,7 @@ public IEnumerable Schedule(string assemblyPath, bool force = fals public AssemblyInfo CreateAssemblyInfo(string assemblyPath) { - return new AssemblyInfo(assemblyPath, _options.TargetFrameworkMoniker, _options.Test64 ? "x64" : "x86", _options.UseHtml); + return new AssemblyInfo(assemblyPath, _options.TargetFrameworkMoniker, _options.Test64 ? "x64" : "x86", _options.IncludeHtml); } private static List GetTypeInfoList(string assemblyPath) diff --git a/src/Tools/Source/RunTests/ITestExecutor.cs b/src/Tools/Source/RunTests/ITestExecutor.cs index fd5e99afef7cc..da5838f7848a4 100644 --- a/src/Tools/Source/RunTests/ITestExecutor.cs +++ b/src/Tools/Source/RunTests/ITestExecutor.cs @@ -15,18 +15,18 @@ internal readonly struct TestExecutionOptions internal string OutputDirectory { get; } internal string Trait { get; } internal string NoTrait { get; } - internal bool UseHtml { get; } + internal bool IncludeHtml { get; } internal bool Test64 { get; } internal bool TestVsi { get; } - internal TestExecutionOptions(string xunitPath, ProcDumpInfo? procDumpInfo, string outputDirectory, string trait, string noTrait, bool useHtml, bool test64, bool testVsi) + internal TestExecutionOptions(string xunitPath, ProcDumpInfo? procDumpInfo, string outputDirectory, string trait, string noTrait, bool includeHtml, bool test64, bool testVsi) { XunitPath = xunitPath; ProcDumpInfo = procDumpInfo; OutputDirectory = outputDirectory; Trait = trait; NoTrait = noTrait; - UseHtml = useHtml; + IncludeHtml = includeHtml; Test64 = test64; TestVsi = testVsi; } diff --git a/src/Tools/Source/RunTests/Options.cs b/src/Tools/Source/RunTests/Options.cs index 11b10e572f7a3..0442b45435b45 100644 --- a/src/Tools/Source/RunTests/Options.cs +++ b/src/Tools/Source/RunTests/Options.cs @@ -23,7 +23,7 @@ internal class Options /// /// Use HTML output files. /// - public bool UseHtml { get; set; } + public bool IncludeHtml { get; set; } /// /// Use the 64 bit test runner. @@ -119,7 +119,7 @@ bool isOption(string argument, string optionName, out string value) return false; } - var opt = new Options { XunitPath = args[0], UseHtml = true, TestResultXmlOutputDirectory = Path.Combine(Directory.GetCurrentDirectory(), "TestResults") }; + var opt = new Options { XunitPath = args[0], IncludeHtml = true, TestResultXmlOutputDirectory = Path.Combine(Directory.GetCurrentDirectory(), "TestResults") }; var index = 1; var allGood = true; while (index < args.Length) @@ -137,7 +137,7 @@ bool isOption(string argument, string optionName, out string value) } else if (comparer.Equals(current, "-xml")) { - opt.UseHtml = false; + opt.IncludeHtml = false; index++; } else if (isOption(current, "-tfm", out string targetFrameworkMoniker)) diff --git a/src/Tools/Source/RunTests/ProcessTestExecutor.cs b/src/Tools/Source/RunTests/ProcessTestExecutor.cs index bc42d74fe8af2..cfe35995f65d0 100644 --- a/src/Tools/Source/RunTests/ProcessTestExecutor.cs +++ b/src/Tools/Source/RunTests/ProcessTestExecutor.cs @@ -32,11 +32,17 @@ public string GetCommandLineArguments(AssemblyInfo assemblyInfo) { var assemblyName = Path.GetFileName(assemblyInfo.AssemblyPath); var resultsFilePath = GetResultsFilePath(assemblyInfo); + var xmlResultsFilePath = Path.ChangeExtension(resultsFilePath, ".xml"); + var htmlResultsFilePath = Path.ChangeExtension(resultsFilePath, ".html"); var builder = new StringBuilder(); builder.AppendFormat(@"""{0}""", assemblyInfo.AssemblyPath); builder.AppendFormat(@" {0}", assemblyInfo.ExtraArguments); - builder.AppendFormat(@" -{0} ""{1}""", Options.UseHtml ? "html" : "xml", resultsFilePath); + builder.AppendFormat($@" -xml ""{xmlResultsFilePath}"""); + + if (Options.IncludeHtml) + builder.AppendFormat($@" -html ""{htmlResultsFilePath}"""); + builder.Append(" -noshadow -verbose"); if (!string.IsNullOrWhiteSpace(Options.Trait)) @@ -70,7 +76,7 @@ public async Task RunTestAsync(AssemblyInfo assemblyInfo, Cancellati var result = await RunTestAsyncInternal(assemblyInfo, retry: false, cancellationToken); // For integration tests (TestVsi), we make one more attempt to re-run failed tests. - if (Options.TestVsi && !Options.UseHtml && !result.Succeeded) + if (Options.TestVsi && !Options.IncludeHtml && !result.Succeeded) { return await RunTestAsyncInternal(assemblyInfo, retry: true, cancellationToken); } diff --git a/src/Tools/Source/RunTests/Program.cs b/src/Tools/Source/RunTests/Program.cs index f1cafabc69808..a96a6c7289f2a 100644 --- a/src/Tools/Source/RunTests/Program.cs +++ b/src/Tools/Source/RunTests/Program.cs @@ -328,7 +328,7 @@ private static ProcessTestExecutor CreateTestExecutor(Options options) outputDirectory: options.TestResultXmlOutputDirectory, trait: options.Trait, noTrait: options.NoTrait, - useHtml: options.UseHtml, + includeHtml: options.IncludeHtml, test64: options.Test64, testVsi: options.TestVsi); return new ProcessTestExecutor(testExecutionOptions); diff --git a/src/Tools/Source/RunTests/TestRunner.cs b/src/Tools/Source/RunTests/TestRunner.cs index 4f1ef1a0579d4..1fce3fa637aab 100644 --- a/src/Tools/Source/RunTests/TestRunner.cs +++ b/src/Tools/Source/RunTests/TestRunner.cs @@ -175,7 +175,7 @@ private void PrintFailedTestResult(TestResult testResult) } // If the results are html, use Process.Start to open in the browser. - if (_options.UseHtml && !string.IsNullOrEmpty(testResult.ResultsFilePath)) + if (_options.IncludeHtml && !string.IsNullOrEmpty(testResult.ResultsFilePath)) { Process.Start(testResult.ResultsFilePath); } diff --git a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx index 03b35c3d36437..baebad55c8450 100644 --- a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx +++ b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx @@ -620,4 +620,7 @@ Edit color scheme + + Prefer implicit object creation when type is apparent + \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs b/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs index e3126ad83364f..16c734fd652c4 100644 --- a/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs +++ b/src/VisualStudio/CSharp/Impl/Options/Formatting/StyleViewModel.cs @@ -967,6 +967,22 @@ void M2(int value) //] }} }} +"; + + private static readonly string s_preferImplicitObjectCreationWhenTypeIsApparent = $@" +using System.Collections.Generic; +class Order {{}} + +//[ +class Customer +{{ + // {ServicesVSResources.Prefer_colon} + private readonly List orders = new(); + + // {ServicesVSResources.Over_colon} + private readonly List orders = new List(); +}} +//] "; private static readonly string s_preferIndexOperator = $@" @@ -1738,6 +1754,7 @@ internal StyleViewModel(OptionStore optionStore, IServiceProvider serviceProvide CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions2.PreferInferredAnonymousTypeMemberNames, ServicesVSResources.Prefer_inferred_anonymous_type_member_names, s_preferInferredAnonymousTypeMemberName, s_preferInferredAnonymousTypeMemberName, this, optionStore, expressionPreferencesGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferLocalOverAnonymousFunction, ServicesVSResources.Prefer_local_function_over_anonymous_function, s_preferLocalFunctionOverAnonymousFunction, s_preferLocalFunctionOverAnonymousFunction, this, optionStore, expressionPreferencesGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions2.PreferCompoundAssignment, ServicesVSResources.Prefer_compound_assignments, s_preferCompoundAssignments, s_preferCompoundAssignments, this, optionStore, expressionPreferencesGroupTitle)); + CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.ImplicitObjectCreationWhenTypeIsApparent, CSharpVSResources.Prefer_implicit_object_creation_when_type_is_apparent, s_preferImplicitObjectCreationWhenTypeIsApparent, s_preferImplicitObjectCreationWhenTypeIsApparent, this, optionStore, expressionPreferencesGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferIndexOperator, ServicesVSResources.Prefer_index_operator, s_preferIndexOperator, s_preferIndexOperator, this, optionStore, expressionPreferencesGroupTitle)); CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferRangeOperator, ServicesVSResources.Prefer_range_operator, s_preferRangeOperator, s_preferRangeOperator, this, optionStore, expressionPreferencesGroupTitle)); diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf index ff0359160c483..63dae0e011360 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.cs.xlf @@ -82,6 +82,11 @@ Při formátování provést dodatečné vyčištění kódu + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks U kontrol rovnosti odkazů dávat přednost možnosti is null diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf index 98ddb6af57529..16fe049106877 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf @@ -82,6 +82,11 @@ Zusätzliche Codebereinigung während der Formatierung durchführen + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks "is null" für Verweisübereinstimmungsprüfungen vorziehen diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf index 10987923c4d52..9e8d8ac940545 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.es.xlf @@ -82,6 +82,11 @@ Realizar limpieza de código adicional durante la aplicación de formato + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks Preferir “is null” para comprobaciones de igualdad de referencias diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf index 69c632775c6c4..e8a904f712ec1 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.fr.xlf @@ -82,6 +82,11 @@ Effectuer un nettoyage supplémentaire du code pendant la mise en forme + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks Préférer 'is nul' pour les vérifications d'égalité de référence diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf index f8c7239ba7db8..be58d03e46eeb 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.it.xlf @@ -82,6 +82,11 @@ Esegui la pulizia del codice aggiuntiva durante la formattazione + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks Preferisci 'is null' per i controlli di uguaglianza dei riferimenti diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf index 9aa52084bf0e1..4b0b935e9e16a 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ja.xlf @@ -82,6 +82,11 @@ 書式設定中に追加のコード クリーンアップを実行 + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks 参照の等値性のチェックには 'is null' を優先する diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf index db3dd360fad3b..4e96246d5f5e5 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ko.xlf @@ -82,6 +82,11 @@ 서식을 지정하는 동안 추가 코드 정리 수행 + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks 참조 같음 검사에 대해 'is null' 선호 diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf index 3f6ee507fca9e..7c085f06727a2 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pl.xlf @@ -82,6 +82,11 @@ Wykonaj dodatkowe oczyszczanie kodu podczas formatowania + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks Preferuj wyrażenie „is null” w przypadku sprawdzeń odwołań pod kątem równości diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf index 16a536953ff10..990f0b01a69f0 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.pt-BR.xlf @@ -82,6 +82,11 @@ Executar limpeza de código adicional durante a formatação + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks Preferir 'is null' para as verificações de igualdade de referência diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf index aa039559bb492..82d39d253fe19 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.ru.xlf @@ -82,6 +82,11 @@ Выполнять при форматировании дополнительную очистку кода + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks Использовать "is null" вместо проверки ссылок на равенство. diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf index a42221783ec7d..6c70f26709939 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.tr.xlf @@ -82,6 +82,11 @@ Biçimlendirme sırasında ek kod temizleme gerçekleştir + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks Başvuru eşitliği denetimleri için 'is null'ı tercih et diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf index 60103c6903375..368bf4bb5256f 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hans.xlf @@ -82,6 +82,11 @@ 在格式设置期间执行其他代码清理 + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks 引用相等检查偏好 “is null” diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf index 79361ea63e4cf..f45976f52134d 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.zh-Hant.xlf @@ -82,6 +82,11 @@ 在格式化期間執行額外程式碼清除 + + Prefer implicit object creation when type is apparent + Prefer implicit object creation when type is apparent + + Prefer 'is null' for reference equality checks 參考相等檢查最好使用 'is null' diff --git a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb index c380fc6f31c8d..3bb326feab75f 100644 --- a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb +++ b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb @@ -124,6 +124,7 @@ csharp_prefer_simple_using_statement = true:suggestion # Expression-level preferences csharp_prefer_simple_default_expression = true:suggestion csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion csharp_style_inlined_variable_declaration = true:suggestion csharp_style_pattern_local_over_anonymous_function = true:suggestion csharp_style_prefer_index_operator = true:suggestion @@ -342,6 +343,7 @@ csharp_prefer_simple_using_statement = true:suggestion # Expression-level preferences csharp_prefer_simple_default_expression = true:suggestion csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion csharp_style_inlined_variable_declaration = true:suggestion csharp_style_pattern_local_over_anonymous_function = true:suggestion csharp_style_prefer_index_operator = true:suggestion diff --git a/src/Workspaces/CSharpTest/Microsoft.CodeAnalysis.CSharp.Workspaces.UnitTests.csproj b/src/Workspaces/CSharpTest/Microsoft.CodeAnalysis.CSharp.Workspaces.UnitTests.csproj index 09ac561e3492c..4a71e48c8a974 100644 --- a/src/Workspaces/CSharpTest/Microsoft.CodeAnalysis.CSharp.Workspaces.UnitTests.csproj +++ b/src/Workspaces/CSharpTest/Microsoft.CodeAnalysis.CSharp.Workspaces.UnitTests.csproj @@ -4,7 +4,7 @@ Library Microsoft.CodeAnalysis.CSharp.UnitTests - net472 + netcoreapp3.1;net472 @@ -25,18 +25,4 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Workspaces/CoreTest/BatchFixAllProviderTests.cs b/src/Workspaces/CoreTest/BatchFixAllProviderTests.cs index 7820ad8cf5f56..df5e4e2323ce4 100644 --- a/src/Workspaces/CoreTest/BatchFixAllProviderTests.cs +++ b/src/Workspaces/CoreTest/BatchFixAllProviderTests.cs @@ -105,11 +105,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) if (_nested) { -#if NETCOREAPP2_0 || NET472 fixes = new List { CodeAction.Create("Container", fixes.ToImmutableArray(), isInlinable: false) }; -#else - throw new NotSupportedException("Nested code actions are not supported on this framework."); -#endif } foreach (var fix in fixes) diff --git a/src/Workspaces/CoreTest/CodeCleanup/ReduceTokenTests.cs b/src/Workspaces/CoreTest/CodeCleanup/ReduceTokenTests.cs index d79c64f68eac0..b41574b0f2e9f 100644 --- a/src/Workspaces/CoreTest/CodeCleanup/ReduceTokenTests.cs +++ b/src/Workspaces/CoreTest/CodeCleanup/ReduceTokenTests.cs @@ -18,6 +18,12 @@ namespace Microsoft.CodeAnalysis.UnitTests.CodeCleanup [UseExportProvider] public class ReduceTokenTests { +#if NETCOREAPP + private static bool IsNetCoreApp => true; +#else + private static bool IsNetCoreApp => false; +#endif + [Fact] [WorkItem(5529, "DevDiv_Projects/Roslyn")] [Trait(Traits.Feature, Traits.Features.ReduceTokens)] @@ -225,23 +231,23 @@ End Sub End Module |]"; - var expected = @" + var expected = $@" Module Program Sub Main(args As String()) ' CATEGORY 2: 8 significant digits ' Dev11 and Roslyn behavior are identical: Always rounded off and pretty listed to <= 9 significant digits Const f_8_1 As Single = 0.14999795F ' Dev11 & Roslyn: 0.14999795F - Const f_8_2 As Single = 0.149997965F ' Dev11 & Roslyn: 0.149997965F + Const f_8_2 As Single = {(IsNetCoreApp ? "0.14999796F" : "0.149997965F")} ' Dev11 & Roslyn: 0.149997965F Const f_8_3 As Single = 0.1499797F ' Dev11 & Roslyn: Unchanged - Const f_8_4 As Single = 1.49997938F ' Dev11 & Roslyn: 1.49997938F - Const f_8_5 As Single = 1.49997973F ' Dev11 & Roslyn: 1.49997973F + Const f_8_4 As Single = {(IsNetCoreApp ? "1.4999794F" : "1.49997938F")} ' Dev11 & Roslyn: 1.49997938F + Const f_8_5 As Single = {(IsNetCoreApp ? "1.4999797F" : "1.49997973F")} ' Dev11 & Roslyn: 1.49997973F - Const f_8_6 As Single = 1499.97937F ' Dev11 & Roslyn: 1499.97937F + Const f_8_6 As Single = {(IsNetCoreApp ? "1499.9794F" : "1499.97937F")} ' Dev11 & Roslyn: 1499.97937F - Const f_8_7 As Single = 1499979.75F ' Dev11 & Roslyn: 1499979.75F + Const f_8_7 As Single = {(IsNetCoreApp ? "1499979.8F" : "1499979.75F")} ' Dev11 & Roslyn: 1499979.75F Const f_8_8 As Single = 14999797.0F ' Dev11 & Roslyn: unchanged @@ -296,23 +302,23 @@ End Sub End Module |]"; - var expected = @" + var expected = $@" Module Program Sub Main(args As String()) ' CATEGORY 2: 8 significant digits ' Dev11 and Roslyn behavior are identical: Always rounded off and pretty listed to <= 9 significant digits Const f_8_1 As Single = 0.14999795! ' Dev11 & Roslyn: 0.14999795F - Const f_8_2 As Single = 0.149997965! ' Dev11 & Roslyn: 0.149997965F + Const f_8_2 As Single = {(IsNetCoreApp ? "0.14999796!" : "0.149997965!")} ' Dev11 & Roslyn: 0.149997965F Const f_8_3 As Single = 0.1499797! ' Dev11 & Roslyn: Unchanged - Const f_8_4 As Single = 1.49997938! ' Dev11 & Roslyn: 1.49997938F - Const f_8_5 As Single = 1.49997973! ' Dev11 & Roslyn: 1.49997973F + Const f_8_4 As Single = {(IsNetCoreApp ? "1.4999794!" : "1.49997938!")} ' Dev11 & Roslyn: 1.49997938F + Const f_8_5 As Single = {(IsNetCoreApp ? "1.4999797!" : "1.49997973!")} ' Dev11 & Roslyn: 1.49997973F - Const f_8_6 As Single = 1499.97937! ' Dev11 & Roslyn: 1499.97937F + Const f_8_6 As Single = {(IsNetCoreApp ? "1499.9794!" : "1499.97937!")} ' Dev11 & Roslyn: 1499.97937F - Const f_8_7 As Single = 1499979.75! ' Dev11 & Roslyn: 1499979.75F + Const f_8_7 As Single = {(IsNetCoreApp ? "1499979.8!" : "1499979.75!")} ' Dev11 & Roslyn: 1499979.75F Const f_8_8 As Single = 14999797.0! ' Dev11 & Roslyn: unchanged @@ -379,24 +385,24 @@ End Sub End Module |]"; - var expected = @" + var expected = $@" Module Program Sub Main(args As String()) ' CATEGORY 3: > 8 significant digits ' Dev11 and Roslyn behavior are identical: Always rounded off and pretty listed to <= 9 significant digits ' (a) > 8 significant digits overall, but < 8 digits before decimal point. - Const f_9_1 As Single = 0.149997935F ' Dev11 & Roslyn: 0.149997935F - Const f_9_2 As Single = 0.149997935F ' Dev11 & Roslyn: 0.149997935F - Const f_9_3 As Single = 1.49997962F ' Dev11 & Roslyn: 1.49997962F + Const f_9_1 As Single = {(IsNetCoreApp ? "0.14999793F" : "0.149997935F")} ' Dev11 & Roslyn: 0.149997935F + Const f_9_2 As Single = {(IsNetCoreApp ? "0.14999793F" : "0.149997935F")} ' Dev11 & Roslyn: 0.149997935F + Const f_9_3 As Single = {(IsNetCoreApp ? "1.4999796F" : "1.49997962F")} ' Dev11 & Roslyn: 1.49997962F - Const f_10_1 As Single = 14999.7969F ' Dev11 & Roslyn: 14999.7969F + Const f_10_1 As Single = {(IsNetCoreApp ? "14999.797F" : "14999.7969F")} ' Dev11 & Roslyn: 14999.7969F ' (b) > 8 significant digits before decimal point. - Const f_10_2 As Single = 149997968.0F ' Dev11 & Roslyn: 149997968.0F - Const f_10_3 As Single = 1.49997965E+9F ' Dev11 & Roslyn: 1.49997965E+9F + Const f_10_2 As Single = {(IsNetCoreApp ? "149997970.0F" : "149997968.0F")} ' Dev11 & Roslyn: 149997968.0F + Const f_10_3 As Single = {(IsNetCoreApp ? "1.4999796E+9F" : "1.49997965E+9F")} ' Dev11 & Roslyn: 1.49997965E+9F - Const f_24_1 As Single = 1.11111148E+20F ' Dev11 & Roslyn: 1.11111148E+20F + Const f_24_1 As Single = {(IsNetCoreApp ? "1.1111115E+20F" : "1.11111148E+20F")} ' Dev11 & Roslyn: 1.11111148E+20F ' (c) Overflow/Underflow cases for Single: Ensure no pretty listing/round off ' Holds signed IEEE 32-bit (4-byte) single-precision floating-point numbers ranging in value from -3.4028235E+38 through -1.401298E-45 for negative values and @@ -474,24 +480,24 @@ End Sub End Module |]"; - var expected = @" + var expected = $@" Module Program Sub Main(args As String()) ' CATEGORY 3: > 8 significant digits ' Dev11 and Roslyn behavior are identical: Always rounded off and pretty listed to <= 9 significant digits ' (a) > 8 significant digits overall, but < 8 digits before decimal point. - Const f_9_1 As Single = 0.149997935! ' Dev11 & Roslyn: 0.149997935F - Const f_9_2 As Single = 0.149997935! ' Dev11 & Roslyn: 0.149997935F - Const f_9_3 As Single = 1.49997962! ' Dev11 & Roslyn: 1.49997962F + Const f_9_1 As Single = {(IsNetCoreApp ? "0.14999793!" : "0.149997935!")} ' Dev11 & Roslyn: 0.149997935F + Const f_9_2 As Single = {(IsNetCoreApp ? "0.14999793!" : "0.149997935!")} ' Dev11 & Roslyn: 0.149997935F + Const f_9_3 As Single = {(IsNetCoreApp ? "1.4999796!" : "1.49997962!")} ' Dev11 & Roslyn: 1.49997962F - Const f_10_1 As Single = 14999.7969! ' Dev11 & Roslyn: 14999.7969F + Const f_10_1 As Single = {(IsNetCoreApp ? "14999.797!" : "14999.7969!")} ' Dev11 & Roslyn: 14999.7969F ' (b) > 8 significant digits before decimal point. - Const f_10_2 As Single = 149997968.0! ' Dev11 & Roslyn: 149997968.0F - Const f_10_3 As Single = 1.49997965E+9! ' Dev11 & Roslyn: 1.49997965E+9F + Const f_10_2 As Single = {(IsNetCoreApp ? "149997970.0!" : "149997968.0!")} ' Dev11 & Roslyn: 149997968.0F + Const f_10_3 As Single = {(IsNetCoreApp ? "1.4999796E+9!" : "1.49997965E+9!")} ' Dev11 & Roslyn: 1.49997965E+9F - Const f_24_1 As Single = 1.11111148E+20! ' Dev11 & Roslyn: 1.11111148E+20F + Const f_24_1 As Single = {(IsNetCoreApp ? "1.1111115E+20!" : "1.11111148E+20!")} ' Dev11 & Roslyn: 1.11111148E+20F ' (c) Overflow/Underflow cases for Single: Ensure no pretty listing/round off ' Holds signed IEEE 32-bit (4-byte) single-precision floating-point numbers ranging in value from -3.4028235E+38 through -1.401298E-45 for negative values and @@ -731,25 +737,25 @@ End Sub End Module |]"; - var expected = @" + var expected = $@" Module Program Sub Main(args As String()) ' CATEGORY 2: 16 significant digits ' Dev11 and Roslyn behavior are identical: Always rounded off and pretty listed to <= 17 significant digits Const f_16_1 As Double = 0.1499999999799993 ' Dev11 & Roslyn: 0.1499999999799993 - Const f_16_2 As Double = 0.14999999997999969 ' Dev11 & Roslyn: 0.14999999997999969 + Const f_16_2 As Double = {(IsNetCoreApp ? "0.1499999999799997" : "0.14999999997999969")} ' Dev11 & Roslyn: 0.14999999997999969 Const f_16_3 As Double = 0.149999999799995 ' Dev11 & Roslyn: Unchanged Const f_16_4 As Double = 1.499999999799994 ' Dev11 & Roslyn: Unchanged - Const f_16_5 As Double = 1.4999999997999951 ' Dev11 & Roslyn: 1.4999999997999951 + Const f_16_5 As Double = {(IsNetCoreApp ? "1.499999999799995" : "1.4999999997999951")} ' Dev11 & Roslyn: 1.4999999997999951 Const f_16_6 As Double = 14999999.99799994 ' Dev11 & Roslyn: Unchanged - Const f_16_7 As Double = 14999999.997999949 ' Dev11 & Roslyn: 14999999.997999949 + Const f_16_7 As Double = {(IsNetCoreApp ? "14999999.99799995" : "14999999.997999949")} ' Dev11 & Roslyn: 14999999.997999949 - Const f_16_8 As Double = 149999999997999.19 ' Dev11 & Roslyn: 149999999997999.19 - Const f_16_9 As Double = 149999999997999.81 ' Dev11 & Roslyn: 149999999997999.81 + Const f_16_8 As Double = {(IsNetCoreApp ? "149999999997999.2" : "149999999997999.19")} ' Dev11 & Roslyn: 149999999997999.19 + Const f_16_9 As Double = {(IsNetCoreApp ? "149999999997999.8" : "149999999997999.81")} ' Dev11 & Roslyn: 149999999997999.81 Const f_16_10 As Double = 1499999999979995.0 ' Dev11 & Roslyn: Unchanged @@ -810,25 +816,25 @@ End Sub End Module |]"; - var expected = @" + var expected = $@" Module Program Sub Main(args As String()) ' CATEGORY 2: 16 significant digits ' Dev11 and Roslyn behavior are identical: Always rounded off and pretty listed to <= 17 significant digits Const f_16_1 As Double = 0.1499999999799993R ' Dev11 & Roslyn: 0.1499999999799993 - Const f_16_2 As Double = 0.14999999997999969R ' Dev11 & Roslyn: 0.14999999997999969 + Const f_16_2 As Double = {(IsNetCoreApp ? "0.1499999999799997R" : "0.14999999997999969R")} ' Dev11 & Roslyn: 0.14999999997999969 Const f_16_3 As Double = 0.149999999799995# ' Dev11 & Roslyn: Unchanged Const f_16_4 As Double = 1.499999999799994R ' Dev11 & Roslyn: Unchanged - Const f_16_5 As Double = 1.4999999997999951R ' Dev11 & Roslyn: 1.4999999997999951 + Const f_16_5 As Double = {(IsNetCoreApp ? "1.499999999799995R" : "1.4999999997999951R")} ' Dev11 & Roslyn: 1.4999999997999951 Const f_16_6 As Double = 14999999.99799994# ' Dev11 & Roslyn: Unchanged - Const f_16_7 As Double = 14999999.997999949R ' Dev11 & Roslyn: 14999999.997999949 + Const f_16_7 As Double = {(IsNetCoreApp ? "14999999.99799995R" : "14999999.997999949R")} ' Dev11 & Roslyn: 14999999.997999949 - Const f_16_8 As Double = 149999999997999.19R ' Dev11 & Roslyn: 149999999997999.19 - Const f_16_9 As Double = 149999999997999.81# ' Dev11 & Roslyn: 149999999997999.81 + Const f_16_8 As Double = {(IsNetCoreApp ? "149999999997999.2R" : "149999999997999.19R")} ' Dev11 & Roslyn: 149999999997999.19 + Const f_16_9 As Double = {(IsNetCoreApp ? "149999999997999.8#" : "149999999997999.81#")} ' Dev11 & Roslyn: 149999999997999.81 Const f_16_10 As Double = 1499999999979995.0R ' Dev11 & Roslyn: Unchanged @@ -915,7 +921,7 @@ End Sub End Module |]"; - var expected = @" + var expected = $@" Module Program Sub Main(args As String()) ' CATEGORY 3: > 16 significant digits @@ -927,7 +933,7 @@ Sub Main(args As String()) Const f_17_3 As Double = 0.14999999997999938 ' Dev11 & Roslyn: 0.14999999997999938 Const f_17_4 As Double = 0.1499999997999957 ' Dev11 & Roslyn: Unchanged - Const f_17_5 As Double = 0.14999999979999579 ' Dev11 & Roslyn: 0.14999999979999579 + Const f_17_5 As Double = {(IsNetCoreApp ? "0.1499999997999958" : "0.14999999979999579")} ' Dev11 & Roslyn: 0.14999999979999579 Const f_17_6 As Double = 1.4999999997999947 ' Dev11 & Roslyn: Unchanged Const f_17_7 As Double = 1.4999999997999944 ' Dev11 & Roslyn: 1.4999999997999944 @@ -938,10 +944,10 @@ Sub Main(args As String()) Const f_18_3 As Double = 14999999.997999946 ' Dev11 & Roslyn: 14999999.997999946 ' (b) > 16 significant digits before decimal point. - Const f_18_4 As Double = 1.4999999999734E+16 ' Dev11 & Roslyn: 1.4999999999734E+16 + Const f_18_4 As Double = {(IsNetCoreApp ? "14999999999734000.0" : "1.4999999999734E+16")} ' Dev11 & Roslyn: 1.4999999999734E+16 Const f_18_5 As Double = 14999999999379996.0 ' Dev11 & Roslyn: 14999999999379996.0 - Const f_24_1 As Double = 1.1111114999912469E+20 ' Dev11 & Roslyn: 1.1111114999912469E+20 + Const f_24_1 As Double = {(IsNetCoreApp ? "1.111111499991247E+20" : "1.1111114999912469E+20")} ' Dev11 & Roslyn: 1.1111114999912469E+20 ' (c) Overflow/Underflow cases for Double: Ensure no pretty listing/round off ' Holds signed IEEE 64-bit (8-byte) double-precision floating-point numbers ranging in value from -1.79769313486231570E+308 through -4.94065645841246544E-324 for negative values and @@ -1046,7 +1052,7 @@ End Sub End Module |]"; - var expected = @" + var expected = $@" Module Program Sub Main(args As String()) ' CATEGORY 3: > 16 significant digits @@ -1058,7 +1064,7 @@ Sub Main(args As String()) Const f_17_3 As Double = 0.14999999997999938# ' Dev11 & Roslyn: 0.14999999997999938 Const f_17_4 As Double = 0.1499999997999957R ' Dev11 & Roslyn: Unchanged - Const f_17_5 As Double = 0.14999999979999579R ' Dev11 & Roslyn: 0.14999999979999579 + Const f_17_5 As Double = {(IsNetCoreApp ? "0.1499999997999958R" : "0.14999999979999579R")} ' Dev11 & Roslyn: 0.14999999979999579 Const f_17_6 As Double = 1.4999999997999947# ' Dev11 & Roslyn: Unchanged Const f_17_7 As Double = 1.4999999997999944R ' Dev11 & Roslyn: 1.4999999997999944 @@ -1069,10 +1075,10 @@ Sub Main(args As String()) Const f_18_3 As Double = 14999999.997999946R ' Dev11 & Roslyn: 14999999.997999946 ' (b) > 16 significant digits before decimal point. - Const f_18_4 As Double = 1.4999999999734E+16# ' Dev11 & Roslyn: 1.4999999999734E+16 + Const f_18_4 As Double = {(IsNetCoreApp ? "14999999999734000.0#" : "1.4999999999734E+16#")} ' Dev11 & Roslyn: 1.4999999999734E+16 Const f_18_5 As Double = 14999999999379996.0R ' Dev11 & Roslyn: 14999999999379996.0 - Const f_24_1 As Double = 1.1111114999912469E+20R ' Dev11 & Roslyn: 1.1111114999912469E+20 + Const f_24_1 As Double = {(IsNetCoreApp ? "1.111111499991247E+20R" : "1.1111114999912469E+20R")} ' Dev11 & Roslyn: 1.1111114999912469E+20 ' (c) Overflow/Underflow cases for Double: Ensure no pretty listing/round off ' Holds signed IEEE 64-bit (8-byte) double-precision floating-point numbers ranging in value from -1.79769313486231570E+308 through -4.94065645841246544E-324 for negative values and @@ -1502,7 +1508,7 @@ End Sub End Module |]"; - var expected = @" + var expected = $@" Module Program Sub Main(args As String()) @@ -1530,19 +1536,19 @@ Sub Main(args As String()) Const f_4 As Single = 1.234567E-9F ' Change at -9 Const f_5 As Single = 1.234567E-10F - Const f_6 As Single = 0.00000000123456778F - Const f_7 As Single = 0.000000000123456786F - Const f_8 As Single = 1.23456783E-11F ' Change at -11 - Const f_9 As Single = 1.23456779E-12F + Const f_6 As Single = {(IsNetCoreApp ? "0.0000000012345678F" : "0.00000000123456778F")} + Const f_7 As Single = {(IsNetCoreApp ? "0.00000000012345679F" : "0.000000000123456786F")} + Const f_8 As Single = {(IsNetCoreApp ? "1.2345678E-11F" : "1.23456783E-11F")} ' Change at -11 + Const f_9 As Single = {(IsNetCoreApp ? "1.2345678E-12F" : "1.23456779E-12F")} Const d_1 As Single = 0.00000000000000123456789012345 Const d_2 As Single = 0.000000000000000123456789012345 Const d_3 As Single = 1.23456789012345E-17 ' Change at -17 Const d_4 As Single = 1.23456789012345E-18 - Const d_5 As Double = 0.000000000000000012345678901234561 + Const d_5 As Double = {(IsNetCoreApp ? "0.00000000000000001234567890123456" : "0.000000000000000012345678901234561")} Const d_6 As Double = 0.000000000000000001234567890123456 - Const d_7 As Double = 1.2345678901234561E-19 ' Change at -19 + Const d_7 As Double = {(IsNetCoreApp ? "1.234567890123456E-19" : "1.2345678901234561E-19")} ' Change at -19 Const d_8 As Double = 1.234567890123456E-20 End Sub End Module @@ -1585,7 +1591,7 @@ End Sub End Module |]"; - var expected = @" + var expected = $@" Module Program Sub Main(args As String()) Const f1 As Single = 3.011F ' Dev11 & Roslyn: 3.011F @@ -1595,9 +1601,9 @@ Sub Main(args As String()) Const f5 As Single = 3.0E+13! ' Dev11 & Roslyn: 3.0E+13! Const f6 As Single = 3.0E+13F ' Dev11 & Roslyn: 3.0E+13F Const f7 As Single = 30000.1F ' Dev11 & Roslyn: 30000.1F - Const f8 As Single = 3.00012337E+13! ' Dev11 & Roslyn: 3.00012337E+13! - Const f9 As Single = 3.00012337E+13F ' Dev11 & Roslyn: 3.00012337E+13F - Const f10 As Single = 3000.12354F ' Dev11 & Roslyn: 3000.12354F + Const f8 As Single = {(IsNetCoreApp ? "3.0001234E+13!" : "3.00012337E+13!")} ' Dev11 & Roslyn: 3.00012337E+13! + Const f9 As Single = {(IsNetCoreApp ? "3.0001234E+13F" : "3.00012337E+13F")} ' Dev11 & Roslyn: 3.00012337E+13F + Const f10 As Single = {(IsNetCoreApp ? "3000.1235F" : "3000.12354F")} ' Dev11 & Roslyn: 3000.12354F Const f11 As Single = 0.0000003! ' Dev11 & Roslyn: 0.0000003! Console.WriteLine(f1) @@ -2049,7 +2055,7 @@ private static async Task VerifyAsync(string codeWithMarker, string expectedResu var cleanDocument = await CodeCleaner.CleanupAsync(document, textSpans[0], codeCleanups); - Assert.Equal(expectedResult, (await cleanDocument.GetSyntaxRootAsync()).ToFullString()); + AssertEx.EqualOrDiff(expectedResult, (await cleanDocument.GetSyntaxRootAsync()).ToFullString()); } private static Document CreateDocument(string code, string language) diff --git a/src/Workspaces/CoreTest/Microsoft.CodeAnalysis.Workspaces.UnitTests.csproj b/src/Workspaces/CoreTest/Microsoft.CodeAnalysis.Workspaces.UnitTests.csproj index 397b41952a248..b424acfd40372 100644 --- a/src/Workspaces/CoreTest/Microsoft.CodeAnalysis.Workspaces.UnitTests.csproj +++ b/src/Workspaces/CoreTest/Microsoft.CodeAnalysis.Workspaces.UnitTests.csproj @@ -3,7 +3,7 @@ Library - net472 + netcoreapp3.1;net472 true Microsoft.CodeAnalysis.UnitTests @@ -30,7 +30,6 @@ - diff --git a/src/Workspaces/CoreTest/UtilityTest/ReferenceHolderTests.cs b/src/Workspaces/CoreTest/UtilityTest/ReferenceHolderTests.cs index ed94369ffbc11..1bd834e2c498c 100644 --- a/src/Workspaces/CoreTest/UtilityTest/ReferenceHolderTests.cs +++ b/src/Workspaces/CoreTest/UtilityTest/ReferenceHolderTests.cs @@ -60,7 +60,7 @@ public void ExpiredValueNotEqualToNull() { var strongNull = ReferenceHolder.Strong(null); var weakNull = ReferenceHolder.Weak(null); - var expired = ReferenceHolder.TestAccessor.ReleasedWeak(hashCode: EqualityComparer.Default.GetHashCode(null)); + var expired = ReferenceHolder.TestAccessor.ReleasedWeak(hashCode: EqualityComparer.Default.GetHashCode(null!)); Assert.Equal(strongNull.GetHashCode(), expired.GetHashCode()); VerifyNotEqual(strongNull, expired); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs index 7737be5daf0a3..9687b4d89b708 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs @@ -308,6 +308,24 @@ private static Option2 CreateOption(OptionGroup group, string name, T defa defaultValue: new CodeStyleOption2(UnusedValuePreference.DiscardVariable, NotificationOption2.Suggestion), s_allOptionsBuilder); + public static readonly Option2> ImplicitObjectCreationWhenTypeIsApparent = CreateOption( + CSharpCodeStyleOptionGroups.ExpressionLevelPreferences, nameof(ImplicitObjectCreationWhenTypeIsApparent), + defaultValue: s_trueWithSuggestionEnforcement, + storageLocations: new OptionStorageLocation2[] { + EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_style_implicit_object_creation_when_type_is_apparent"), + new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.ImplicitObjectCreationWhenTypeIsApparent")}); + +#if false + + public static readonly Option2> VarElsewhere = CreateOption( + CSharpCodeStyleOptionGroups.VarPreferences, nameof(VarElsewhere), + defaultValue: s_trueWithSuggestionEnforcement, + storageLocations: new OptionStorageLocation2[] { + EditorConfigStorageLocation.ForBoolCodeStyleOption("csharp_style_var_elsewhere"), + new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.UseImplicitTypeWherePossible")}); + +#endif + static CSharpCodeStyleOptions() { // Note that the static constructor executes after all the static field initializers for the options have executed, diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/TypeStyle/TypeStyleHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/TypeStyle/TypeStyleHelper.cs index bca7aef92d917..174d259c85103 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/TypeStyle/TypeStyleHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/TypeStyle/TypeStyleHelper.cs @@ -22,25 +22,6 @@ internal static class TypeStyleHelper public static bool IsBuiltInType(ITypeSymbol type) => type?.IsSpecialType() == true; - public static bool IsImplicitStylePreferred( - OptionSet optionSet, bool isBuiltInTypeContext, bool isTypeApparentContext) - { - return IsImplicitStylePreferred( - GetCurrentTypeStylePreferences(optionSet), - isBuiltInTypeContext, - isTypeApparentContext); - } - - private static bool IsImplicitStylePreferred( - UseVarPreference stylePreferences, bool isBuiltInTypeContext, bool isTypeApparentContext) - { - return isBuiltInTypeContext - ? stylePreferences.HasFlag(UseVarPreference.ForBuiltInTypes) - : isTypeApparentContext - ? stylePreferences.HasFlag(UseVarPreference.WhenTypeIsApparent) - : stylePreferences.HasFlag(UseVarPreference.Elsewhere); - } - /// /// Analyzes if type information is obvious to the reader by simply looking at the assignment expression. /// @@ -239,32 +220,6 @@ private static ExpressionSyntax GetRightmostInvocationExpression(ExpressionSynta return node; } - private static UseVarPreference GetCurrentTypeStylePreferences(OptionSet optionSet) - { - var stylePreferences = UseVarPreference.None; - - var styleForIntrinsicTypes = optionSet.GetOption(CSharpCodeStyleOptions.VarForBuiltInTypes); - var styleForApparent = optionSet.GetOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent); - var styleForElsewhere = optionSet.GetOption(CSharpCodeStyleOptions.VarElsewhere); - - if (styleForIntrinsicTypes.Value) - { - stylePreferences |= UseVarPreference.ForBuiltInTypes; - } - - if (styleForApparent.Value) - { - stylePreferences |= UseVarPreference.WhenTypeIsApparent; - } - - if (styleForElsewhere.Value) - { - stylePreferences |= UseVarPreference.Elsewhere; - } - - return stylePreferences; - } - public static bool IsPredefinedType(TypeSyntax type) { return type is PredefinedTypeSyntax predefinedType diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs index 71547bbfad5af..652aad5d5fff0 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs @@ -1244,7 +1244,7 @@ public SeparatedSyntaxList GetArgumentsOfInvocationExpression(Syntax => GetArgumentsOfArgumentList((invocationExpression as InvocationExpressionSyntax)?.ArgumentList); public SeparatedSyntaxList GetArgumentsOfObjectCreationExpression(SyntaxNode objectCreationExpression) - => GetArgumentsOfArgumentList((objectCreationExpression as ObjectCreationExpressionSyntax)?.ArgumentList); + => GetArgumentsOfArgumentList((objectCreationExpression as BaseObjectCreationExpressionSyntax)?.ArgumentList); public SeparatedSyntaxList GetArgumentsOfArgumentList(SyntaxNode argumentList) => (argumentList as BaseArgumentListSyntax)?.Arguments ?? default; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs index 042769695fb89..8862550a94c71 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Simplification/Simplifiers/CastSimplifier.cs @@ -43,13 +43,85 @@ private static bool IsCastSafeToRemove( if (speculationAnalyzer.SemanticRootOfOriginalExpression.ContainsDiagnostics) return false; - // Look for simple patterns that are known to be absolutely safe to always remove. - if (CastCanDefinitelyBeRemoved(castNode, castedExpressionNode, semanticModel, cancellationToken)) + // Now perform basic checks looking for a few things: + // + // 1. casts that must stay because removal will produce actually illegal code. + // 2. casts that must stay because they have runtime impact (i.e. could cause exceptions to be thrown). + // 3. casts that *seem* unnecessary because they don't violate the above, and the cast seems like it has no + // effect at runtime (i.e. casting a `string` to `object`). Note: just because the cast seems like it + // will have not runtime impact doesn't mean we can remove it. It still may be necessary to preserve the + // meaning of the code (for example for overload resolution). That check will occur after this. + // + // This is the fundamental separation between CastHasNoRuntimeImpact and + // speculationAnalyzer.ReplacementChangesSemantics. The former is simple and is only asking if the cast + // seems like it would have no impact *at runtime*. The latter ensures that the static meaning of the code + // is preserved. + // + // When adding/updating checks keep the above in mind to determine where the check should go. + var castHasRuntimeImpact = CastHasRuntimeImpact( + speculationAnalyzer, castNode, castedExpressionNode, semanticModel, cancellationToken); + if (castHasRuntimeImpact) + return false; + + // Cast has no runtime effect. But it may change static semantics. Only allow removal if static semantics + // don't change. + if (speculationAnalyzer.ReplacementChangesSemantics()) + return false; + + return true; + } + + private static bool CastHasRuntimeImpact( + SpeculationAnalyzer speculationAnalyzer, + ExpressionSyntax castNode, ExpressionSyntax castedExpressionNode, + SemanticModel semanticModel, CancellationToken cancellationToken) + { + // Look for simple patterns we know will never cause any runtime changes. + if (CastDefinitelyHasNoRuntimeImpact(castNode, castedExpressionNode, semanticModel, cancellationToken)) + return false; + + // Call into our legacy codepath that tries to make the same determination. + return !CastHasNoRuntimeImpact_Legacy(speculationAnalyzer, castNode, castedExpressionNode, semanticModel, cancellationToken); + } + + private static bool CastDefinitelyHasNoRuntimeImpact( + ExpressionSyntax castNode, + ExpressionSyntax castedExpressionNode, + SemanticModel semanticModel, + CancellationToken cancellationToken) + { + // NOTE: Keep this method simple. Each type of runtime impact check should just be a new check added + // independently from the rest. We want to make it very clear exactly which cases each check is covering. + + // castNode is: `(Type)expr` or `expr as Type`. + // castedExpressionnode is: `expr` + + // The type in `(Type)...` or `... as Type` + var castType = semanticModel.GetTypeInfo(castNode, cancellationToken).Type; + + // The type in `(...)expr` or `expr as ...` + var castedExpressionType = semanticModel.GetTypeInfo(castedExpressionNode, cancellationToken).Type; + + // $"x {(object)y} z" It's always safe to remove this `(object)` cast as this cast happens automatically. + if (IsObjectCastInInterpolation(castNode, castType)) return true; - // Then look for patterns for cases where we never want to remove casts. Note: we want these checks to be - // very fast, and to eliminate as many cases as necessary. Importantly, we want to be able to do these - // checks before calling into the speculation analyzer. + // if we have `(E)~(int)e` then the cast to (int) is not necessary as enums always support `~` + if (IsEnumToNumericCastThatCanDefinitelyBeRemoved(castNode, castType, castedExpressionType, semanticModel, cancellationToken)) + return true; + + return false; + } + + private static bool CastHasNoRuntimeImpact_Legacy( + SpeculationAnalyzer speculationAnalyzer, + ExpressionSyntax castNode, ExpressionSyntax castedExpressionNode, + SemanticModel semanticModel, CancellationToken cancellationToken) + { + // Note: Legacy codepaths for determining if a cast is removable. As much as possible we should attempt to + // extract simple and clearly defined checks from here and move to CastDefinitelyHasNoRuntimeImpact. + + // Then look for patterns for cases where we never want to remove casts. if (CastMustBePreserved(castNode, castedExpressionNode, semanticModel, cancellationToken)) return false; @@ -242,31 +314,6 @@ private static bool IsCastSafeToRemove( return false; } - private static bool CastCanDefinitelyBeRemoved( - ExpressionSyntax castNode, - ExpressionSyntax castedExpressionNode, - SemanticModel semanticModel, - CancellationToken cancellationToken) - { - // castNode is: `(Type)expr` or `expr as Type`. - // castedExpressionnode is: `expr` - - // The type in `(Type)...` or `... as Type` - var castType = semanticModel.GetTypeInfo(castNode, cancellationToken).Type; - - // The type in `(...)expr` or `expr as ...` - var castedExpressionType = semanticModel.GetTypeInfo(castedExpressionNode, cancellationToken).Type; - - // $"x {(object)y} z" It's always safe to remove this `(object)` cast. - if (IsObjectCastInInterpolation(castNode, castType)) - return true; - - if (IsEnumToNumericCastThatCanDefinitelyBeRemoved(castNode, castType, castedExpressionType, semanticModel, cancellationToken)) - return true; - - return false; - } - private static bool IsObjectCastInInterpolation(ExpressionSyntax castNode, ITypeSymbol castType) { // A casts to object can always be removed from an expression inside of an interpolation, since it'll be converted to object diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs index 780aa197854c2..8791de55bc586 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpTypeStyleHelper.cs @@ -91,7 +91,7 @@ internal TypeSyntax FindAnalyzableType(SyntaxNode node, SemanticModel semanticMo return node switch { - VariableDeclarationSyntax variableDeclaration => ShouldAnalyzeVariableDeclaration(variableDeclaration, semanticModel, cancellationToken) + VariableDeclarationSyntax variableDeclaration => ShouldAnalyzeVariableDeclaration(variableDeclaration, cancellationToken) ? variableDeclaration.Type : null, ForEachStatementSyntax forEachStatement => ShouldAnalyzeForEachStatement(forEachStatement, semanticModel, cancellationToken) @@ -104,7 +104,7 @@ internal TypeSyntax FindAnalyzableType(SyntaxNode node, SemanticModel semanticMo }; } - protected virtual bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken) + public virtual bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, CancellationToken cancellationToken) { // implicit type is applicable only for local variables and // such declarations cannot have multiple declarators and diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs index 6deca3a726737..53d1bbbb5a387 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseExplicitTypeHelper.cs @@ -43,7 +43,7 @@ protected override bool IsStylePreferred(in State state) } } - protected override bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken) + public override bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, CancellationToken cancellationToken) { if (!variableDeclaration.Type.StripRefIfNeeded().IsVar) { @@ -52,7 +52,7 @@ protected override bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSynt } // The base analyzer may impose further limitations - return base.ShouldAnalyzeVariableDeclaration(variableDeclaration, semanticModel, cancellationToken); + return base.ShouldAnalyzeVariableDeclaration(variableDeclaration, cancellationToken); } protected override bool ShouldAnalyzeForEachStatement(ForEachStatementSyntax forEachStatement, SemanticModel semanticModel, CancellationToken cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs index 24c6142cc3bf5..9cc41b8562bbf 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/TypeStyle/CSharpUseImplicitTypeHelper.cs @@ -51,7 +51,7 @@ public override TypeStyleResult AnalyzeTypeName( typeName, semanticModel, optionSet, cancellationToken); } - protected override bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken) + public override bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, CancellationToken cancellationToken) { var type = variableDeclaration.Type.StripRefIfNeeded(); if (type.IsVar) @@ -61,7 +61,7 @@ protected override bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSynt } // The base analyzer may impose further limitations - return base.ShouldAnalyzeVariableDeclaration(variableDeclaration, semanticModel, cancellationToken); + return base.ShouldAnalyzeVariableDeclaration(variableDeclaration, cancellationToken); } protected override bool ShouldAnalyzeForEachStatement(ForEachStatementSyntax forEachStatement, SemanticModel semanticModel, CancellationToken cancellationToken) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs index baab113802f7b..ffaf0e24e72ec 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/INamedTypeSymbolExtensions.cs @@ -551,30 +551,22 @@ private static void AddOverridableMembers( private static bool IsOverridable(ISymbol member, INamedTypeSymbol containingType) { - if (member.IsAbstract || member.IsVirtual || member.IsOverride) - { - if (member.IsSealed) - { - return false; - } + if (!member.IsAbstract && !member.IsVirtual && !member.IsOverride) + return false; - if (!member.IsAccessibleWithin(containingType)) - { - return false; - } + if (member.IsSealed) + return false; - switch (member.Kind) - { - case SymbolKind.Event: - return true; - case SymbolKind.Method: - return ((IMethodSymbol)member).MethodKind == MethodKind.Ordinary; - case SymbolKind.Property: - return !((IPropertySymbol)member).IsWithEvents; - } - } + if (!member.IsAccessibleWithin(containingType)) + return false; - return false; + return member switch + { + IEventSymbol => true, + IMethodSymbol { MethodKind: MethodKind.Ordinary, CanBeReferencedByName: true } => true, + IPropertySymbol { IsWithEvents: false } => true, + _ => false, + }; } private static void RemoveOverriddenMembers( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs index 087f204aa0a99..bf5b177433a56 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SyntaxNodeExtensions.cs @@ -833,6 +833,14 @@ public static SyntaxToken WithoutLeadingTrivia(this SyntaxToken token) return token.WithLeadingTrivia(default(SyntaxTriviaList)); } + /// + /// Creates a new token with the trailing trivia removed. + /// + public static SyntaxToken WithoutTrailingTrivia(this SyntaxToken token) + { + return token.WithTrailingTrivia(default(SyntaxTriviaList)); + } + // Copy of the same function in SyntaxNode.cs public static SyntaxNode? GetParent(this SyntaxNode node, bool ascendOutOfTrivia) { diff --git a/src/Workspaces/VisualBasicTest/Microsoft.CodeAnalysis.VisualBasic.Workspaces.UnitTests.vbproj b/src/Workspaces/VisualBasicTest/Microsoft.CodeAnalysis.VisualBasic.Workspaces.UnitTests.vbproj index 6e5c21b242473..d285e182a8b8c 100644 --- a/src/Workspaces/VisualBasicTest/Microsoft.CodeAnalysis.VisualBasic.Workspaces.UnitTests.vbproj +++ b/src/Workspaces/VisualBasicTest/Microsoft.CodeAnalysis.VisualBasic.Workspaces.UnitTests.vbproj @@ -4,8 +4,7 @@ Library Off - Default - net472 + netcoreapp3.1;net472 @@ -27,20 +26,8 @@ - - - - - - - - - - - - \ No newline at end of file