From 3facb050df0fb68338aa07374a70398e434123bd Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 13 Mar 2020 20:54:54 -0700 Subject: [PATCH] Infer base type better when generating a type --- .../GenerateType/GenerateTypeTests.cs | 52 ++++++++++++------- .../GenerateTypeWithUnboundAnalyzerTests.cs | 46 ++++++++++++++++ .../AbstractGenerateTypeService.State.cs | 24 ++++----- 3 files changed, 89 insertions(+), 33 deletions(-) create mode 100644 src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeWithUnboundAnalyzerTests.cs diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs index 34c6e894a9a..5e94bf1c71a 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeTests.cs @@ -7,9 +7,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateType; -using Microsoft.CodeAnalysis.CSharp.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Test.Utilities; @@ -5355,32 +5353,50 @@ public Class(global::System.Object method) }}", index: 1); } - } - - public partial class GenerateTypeWithUnboundAnalyzerTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest - { - internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) - => (new CSharpUnboundIdentifiersDiagnosticAnalyzer(), new GenerateTypeCodeFixProvider()); - - protected override ImmutableArray MassageActions(ImmutableArray codeActions) - => FlattenActions(codeActions); [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateType)] - [WorkItem(13211, "https://github.com/dotnet/roslyn/issues/13211")] - public async Task TestGenerateOffOfIncompleteMember() + [WorkItem(270, "https://github.com/dotnet/roslyn/issues/270")] + public async Task TestGenerateInIsExpression() { await TestInRegularAndScriptAsync( -@"class Class +@"using System; + +class Program { - public [|Goo|] + static void Main(Exception p) + { + bool result = p is [|SampleType|]; + } }", -@"class Class +@"using System; +using System.Runtime.Serialization; + +class Program { - public Goo + static void Main(Exception p) + { + bool result = p is SampleType; + } } -internal class Goo +[Serializable] +internal class SampleType : Exception { + public SampleType() + { + } + + public SampleType(string message) : base(message) + { + } + + public SampleType(string message, Exception innerException) : base(message, innerException) + { + } + + protected SampleType(SerializationInfo info, StreamingContext context) : base(info, context) + { + } }", index: 1); } diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeWithUnboundAnalyzerTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeWithUnboundAnalyzerTests.cs new file mode 100644 index 00000000000..7d182a4868b --- /dev/null +++ b/src/EditorFeatures/CSharpTest/Diagnostics/GenerateType/GenerateTypeWithUnboundAnalyzerTests.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.CodeFixes.GenerateType; +using Microsoft.CodeAnalysis.CSharp.Diagnostics; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.GenerateTypeTests +{ + public partial class GenerateTypeWithUnboundAnalyzerTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest + { + internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace) + => (new CSharpUnboundIdentifiersDiagnosticAnalyzer(), new GenerateTypeCodeFixProvider()); + + protected override ImmutableArray MassageActions(ImmutableArray codeActions) + => FlattenActions(codeActions); + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateType)] + [WorkItem(13211, "https://github.com/dotnet/roslyn/issues/13211")] + public async Task TestGenerateOffOfIncompleteMember() + { + await TestInRegularAndScriptAsync( +@"class Class +{ + public [|Goo|] +}", +@"class Class +{ + public Goo +} + +internal class Goo +{ +}", +index: 1); + } + } +} diff --git a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs index 9f1484e5161..06312984287 100644 --- a/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs +++ b/src/Features/Core/Portable/GenerateType/AbstractGenerateTypeService.State.cs @@ -210,42 +210,36 @@ private State(Compilation compilation) var syntaxFacts = document.Document.GetLanguageService(); if (service.IsInCatchDeclaration(NameOrMemberAccessExpression)) { - BaseTypeOrInterfaceOpt = document.SemanticModel.Compilation.ExceptionType(); + SetBaseType(document.SemanticModel.Compilation.ExceptionType()); } else if (syntaxFacts.IsAttributeName(NameOrMemberAccessExpression)) { - BaseTypeOrInterfaceOpt = document.SemanticModel.Compilation.AttributeType(); + SetBaseType(document.SemanticModel.Compilation.AttributeType()); } - else if ( - service.IsArrayElementType(NameOrMemberAccessExpression) || - service.IsInVariableTypeContext(NameOrMemberAccessExpression) || - ObjectCreationExpressionOpt != null) + else { var expr = ObjectCreationExpressionOpt ?? NameOrMemberAccessExpression; - var typeInference = document.Document.GetLanguageService(); - var baseType = typeInference.InferType(document.SemanticModel, expr, objectAsDefault: true, cancellationToken: cancellationToken) as INamedTypeSymbol; - SetBaseType(baseType); + if (expr != null) + { + var typeInference = document.Document.GetLanguageService(); + var baseType = typeInference.InferType(document.SemanticModel, expr, objectAsDefault: true, cancellationToken: cancellationToken) as INamedTypeSymbol; + SetBaseType(baseType); + } } } private void SetBaseType(INamedTypeSymbol baseType) { if (baseType == null) - { return; - } // A base type need to be non class or interface type. Also, being 'object' is // redundant as the base type. if (baseType.IsSealed || baseType.IsStatic || baseType.SpecialType == SpecialType.System_Object) - { return; - } if (baseType.TypeKind != TypeKind.Class && baseType.TypeKind != TypeKind.Interface) - { return; - } // Strip off top-level nullability since we can't put top-level nullability into the base list. We will still include nested nullability // if you're deriving some interface like IEnumerable. -- GitLab