diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 59bdf21d2b36f..100a6fd5751fb 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -54,6 +54,10 @@ var symbolInfo = semanticModel.GetSymbolInfo(expression); - Test utilities in `Microsoft.CodeAnalysis.Test.Utilities` - Language-specific test bases: `CSharpTestBase`, `VisualBasicTestBase` - Add `[WorkItem("https://github.com/dotnet/roslyn/issues/issueNumber")]` attribute to tests that fix specific GitHub issues +- Prefer raw string literals (`"""..."""`) over verbatim strings (`@"..."`) when creating test source code +- Avoid unnecessary intermediary assertions - tests should do the minimal amount of work to validate just the core issue being addressed + - In tests, use concise methods like `.Single()` instead of asserting count and extracting elements + - For compiler tests, validate diagnostics (e.g., `comp.VerifyEmitDiagnostics()`) so reviewers can easily see if the code is in error or represents something legal ## Critical Integration Points diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs index 0aa92b3c636cb..53cbd4f9c6d23 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/GenericConstraintTests.cs @@ -7460,5 +7460,88 @@ interface Base : Base, ISetup where N : Base.Nest { } Assert.Null(model.GetAliasInfo(nest)); Assert.Equal("Base.Nest", model.GetTypeInfo(nest).Type.ToDisplayString()); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41733")] + public void TypeParameter_BaseType_ReturnsNull() + { + var source = """ + abstract class Base + { + public abstract void Method(); + } + + class Derived where T : Base + { + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var typeParameter = (ITypeParameterSymbol)comp.GetTypeByMetadataName("Derived`1").TypeParameters[0].GetPublicSymbol(); + Assert.Null(typeParameter.BaseType); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41733")] + public void MethodTypeParameter_BaseType_ReturnsNull() + { + var source = """ + class C + { + void M() where T : class + { + } + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var typeParameter = (ITypeParameterSymbol)comp.GetTypeByMetadataName("C").GetMethod("M").TypeParameters[0].GetPublicSymbol(); + Assert.Null(typeParameter.BaseType); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41733")] + public void ObjectType_BaseType_ReturnsNull() + { + var comp = CreateCompilation(""); + comp.VerifyDiagnostics(); + + var objectType = (INamedTypeSymbol)comp.GetSpecialType(SpecialType.System_Object).GetPublicSymbol(); + Assert.Null(objectType.BaseType); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41733")] + public void InterfaceType_BaseType_ReturnsNull() + { + var source = """ + interface IMyInterface + { + void Method(); + } + """; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var interfaceType = (INamedTypeSymbol)comp.GetTypeByMetadataName("IMyInterface").GetPublicSymbol(); + Assert.Null(interfaceType.BaseType); + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41733")] + public void PointerType_BaseType_ReturnsNull() + { + var source = """ + unsafe class C + { + int* ptr; + } + """; + var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); + comp.VerifyDiagnostics( + // (3,10): warning CS0169: The field 'C.ptr' is never used + // int* ptr; + Diagnostic(ErrorCode.WRN_UnreferencedField, "ptr").WithArguments("C.ptr").WithLocation(3, 10)); + + var pointerType = (IPointerTypeSymbol)comp.GetTypeByMetadataName("C").GetField("ptr").Type.GetPublicSymbol(); + Assert.Null(pointerType.BaseType); + } } } diff --git a/src/Compilers/Core/Portable/Symbols/ITypeSymbol.cs b/src/Compilers/Core/Portable/Symbols/ITypeSymbol.cs index 85bb9c9c39df6..e51c27f69b692 100644 --- a/src/Compilers/Core/Portable/Symbols/ITypeSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/ITypeSymbol.cs @@ -26,8 +26,7 @@ public interface ITypeSymbol : INamespaceOrTypeSymbol /// /// The declared base type of this type, or null. The object type, interface types, - /// and pointer types do not have a base type. The base type of a type parameter - /// is its effective base class. + /// pointer types, and type parameters do not have a base type. /// INamedTypeSymbol? BaseType { get; }