提交 077d536b 编写于 作者: J Jason Malinowski

Add a set of wrapper ITypeSymbols that carry nullability along

Currently, the APIs for nullable reference types take a model that
instead of the top level nullability of a named type being on the
INamedTypeSymbol, it's carried along as a separate piece of information.
This causes a lot of churn for code that is used to passing along
ITypeSymbols today; one way to ease this is simply create a set of
wrapper types which carry it along for us but still implement
ITypeSymbol.
上级 fb1fdf34
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Text;
namespace Microsoft.CodeAnalysis
{
internal static partial class NullableExtensions
{
private sealed class ArrayTypeSymbolWithNullableAnnotation : TypeSymbolWithNullableAnnotation, IArrayTypeSymbol
{
public ArrayTypeSymbolWithNullableAnnotation(ITypeSymbol wrappedSymbol, NullableAnnotation nullability) : base(wrappedSymbol, nullability)
{
}
private new IArrayTypeSymbol WrappedSymbol => (IArrayTypeSymbol)base.WrappedSymbol;
public override void Accept(SymbolVisitor visitor)
{
visitor.VisitArrayType(this);
}
public override TResult Accept<TResult>(SymbolVisitor<TResult> visitor)
{
return visitor.VisitArrayType(this);
}
#region IArrayTypeSymbol Implementation Forwards
public int Rank => WrappedSymbol.Rank;
public bool IsSZArray => WrappedSymbol.IsSZArray;
public ImmutableArray<int> LowerBounds => WrappedSymbol.LowerBounds;
public ImmutableArray<int> Sizes => WrappedSymbol.Sizes;
public ITypeSymbol ElementType => WrappedSymbol.ElementType;
public NullableAnnotation ElementNullableAnnotation => WrappedSymbol.ElementNullableAnnotation;
public ImmutableArray<CustomModifier> CustomModifiers => WrappedSymbol.CustomModifiers;
public bool Equals(IArrayTypeSymbol other)
{
return WrappedSymbol.Equals(other);
}
#endregion
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Text;
namespace Microsoft.CodeAnalysis
{
internal static partial class NullableExtensions
{
private sealed class DynamicTypeSymbolWithNullableAnnotation : TypeSymbolWithNullableAnnotation, IDynamicTypeSymbol
{
public DynamicTypeSymbolWithNullableAnnotation(ITypeSymbol wrappedSymbol, NullableAnnotation nullability) : base(wrappedSymbol, nullability)
{
}
private new IDynamicTypeSymbol WrappedSymbol => (IDynamicTypeSymbol)base.WrappedSymbol;
public override void Accept(SymbolVisitor visitor)
{
visitor.VisitDynamicType(this);
}
public override TResult Accept<TResult>(SymbolVisitor<TResult> visitor)
{
return visitor.VisitDynamicType(this);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Text;
namespace Microsoft.CodeAnalysis
{
internal static partial class NullableExtensions
{
private sealed class NamedTypeSymbolWithNullableAnnotation : TypeSymbolWithNullableAnnotation, INamedTypeSymbol
{
public NamedTypeSymbolWithNullableAnnotation(INamedTypeSymbol wrappedSymbol, NullableAnnotation nullability) : base(wrappedSymbol, nullability)
{
}
private new INamedTypeSymbol WrappedSymbol => (INamedTypeSymbol)base.WrappedSymbol;
public override void Accept(SymbolVisitor visitor)
{
visitor.VisitNamedType(this);
}
public override TResult Accept<TResult>(SymbolVisitor<TResult> visitor)
{
return visitor.VisitNamedType(this);
}
#region INamedTypeSymbol Implementation Forwards
public int Arity => WrappedSymbol.Arity;
public bool IsGenericType => WrappedSymbol.IsGenericType;
public bool IsUnboundGenericType => WrappedSymbol.IsUnboundGenericType;
public bool IsScriptClass => WrappedSymbol.IsScriptClass;
public bool IsImplicitClass => WrappedSymbol.IsImplicitClass;
public bool IsComImport => WrappedSymbol.IsComImport;
public IEnumerable<string> MemberNames => WrappedSymbol.MemberNames;
public ImmutableArray<ITypeParameterSymbol> TypeParameters => WrappedSymbol.TypeParameters;
public ImmutableArray<ITypeSymbol> TypeArguments => WrappedSymbol.TypeArguments;
public ImmutableArray<NullableAnnotation> TypeArgumentsNullableAnnotations => WrappedSymbol.TypeArgumentsNullableAnnotations;
public IMethodSymbol DelegateInvokeMethod => WrappedSymbol.DelegateInvokeMethod;
public INamedTypeSymbol EnumUnderlyingType => WrappedSymbol.EnumUnderlyingType;
public INamedTypeSymbol ConstructedFrom => WrappedSymbol.ConstructedFrom;
public ImmutableArray<IMethodSymbol> InstanceConstructors => WrappedSymbol.InstanceConstructors;
public ImmutableArray<IMethodSymbol> StaticConstructors => WrappedSymbol.StaticConstructors;
public ImmutableArray<IMethodSymbol> Constructors => WrappedSymbol.Constructors;
public ISymbol AssociatedSymbol => WrappedSymbol.AssociatedSymbol;
public bool MightContainExtensionMethods => WrappedSymbol.MightContainExtensionMethods;
public INamedTypeSymbol TupleUnderlyingType => WrappedSymbol.TupleUnderlyingType;
public ImmutableArray<IFieldSymbol> TupleElements => WrappedSymbol.TupleElements;
public bool IsSerializable => WrappedSymbol.IsSerializable;
INamedTypeSymbol INamedTypeSymbol.OriginalDefinition => WrappedSymbol.OriginalDefinition;
public INamedTypeSymbol Construct(params ITypeSymbol[] typeArguments)
{
return WrappedSymbol.Construct(typeArguments);
}
public INamedTypeSymbol ConstructUnboundGenericType()
{
return WrappedSymbol.ConstructUnboundGenericType();
}
public ImmutableArray<CustomModifier> GetTypeArgumentCustomModifiers(int ordinal)
{
return WrappedSymbol.GetTypeArgumentCustomModifiers(ordinal);
}
#endregion
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
internal static partial class NullableExtensions
{
public static T WithNullability<T>(this T typeSymbol, NullableAnnotation nullability) where T : class, ITypeSymbol
{
if (typeSymbol == null)
{
return null;
}
// No reason to wrap a wrapper, so unwrap it
if (typeSymbol is TypeSymbolWithNullableAnnotation typeSymbolWithNullability)
{
typeSymbol = (T)typeSymbolWithNullability.WrappedSymbol;
}
return typeSymbol switch
{
IArrayTypeSymbol arrayTypeSymbol => (ITypeSymbol)new ArrayTypeSymbolWithNullableAnnotation(arrayTypeSymbol, nullability),
IDynamicTypeSymbol dynamicTypeSymbol => (ITypeSymbol)new DynamicTypeSymbolWithNullableAnnotation(dynamicTypeSymbol, nullability),
INamedTypeSymbol namedTypeSymbol => (ITypeSymbol)new NamedTypeSymbolWithNullableAnnotation(namedTypeSymbol, nullability),
IPointerTypeSymbol pointerType => (ITypeSymbol)new PointerTypeSymbolWithNullableAnnotation(pointerType, nullability),
ITypeParameterSymbol typeParameterSymbol => (ITypeSymbol)new TypeParameterSymbolWithNullableAnnotation(typeParameterSymbol, nullability),
_ => throw ExceptionUtilities.UnexpectedValue(typeSymbol)
} as T;
}
public static T WithNullability<T>(this T typeSymbol, NullableFlowState flowState) where T : class, ITypeSymbol
{
// TODO: call the compiler API once it's available
switch (flowState)
{
case NullableFlowState.NotApplicable:
return typeSymbol.WithNullability(NullableAnnotation.NotApplicable);
case NullableFlowState.NotNull:
return typeSymbol.WithNullability(NullableAnnotation.NotAnnotated);
case NullableFlowState.MaybeNull:
return typeSymbol.WithNullability(NullableAnnotation.Annotated);
default:
throw ExceptionUtilities.UnexpectedValue(typeSymbol);
}
}
public static NullableAnnotation GetNullability(this ITypeSymbol typeSymbol)
{
if (typeSymbol is TypeSymbolWithNullableAnnotation typeSymbolWithNullability)
{
return typeSymbolWithNullability.Nullability;
}
else
{
// For now, we'll return this while we transition the codebase over to these helpers. Eventually this should throw, since it means somebody got a type from
// the compiler API and didn't wrap it properly.
return NullableAnnotation.NotApplicable;
}
}
public static T UnwrapNullabilitySymbol<T>(this T typeSymbol) where T : ITypeSymbol
{
if (typeSymbol is TypeSymbolWithNullableAnnotation typeSymbolWithNullability)
{
return (T)typeSymbolWithNullability.WrappedSymbol;
}
else
{
return typeSymbol;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Text;
namespace Microsoft.CodeAnalysis
{
internal static partial class NullableExtensions
{
private sealed class PointerTypeSymbolWithNullableAnnotation : TypeSymbolWithNullableAnnotation, IPointerTypeSymbol
{
public PointerTypeSymbolWithNullableAnnotation(ITypeSymbol wrappedSymbol, NullableAnnotation nullability) : base(wrappedSymbol, nullability)
{
}
private new IPointerTypeSymbol WrappedSymbol => (IPointerTypeSymbol)base.WrappedSymbol;
public override void Accept(SymbolVisitor visitor)
{
visitor.VisitPointerType(this);
}
public override TResult Accept<TResult>(SymbolVisitor<TResult> visitor)
{
return visitor.VisitPointerType(this);
}
#region IPointerTypeSymbol Implementation Forwards
public ITypeSymbol PointedAtType => WrappedSymbol.PointedAtType;
public ImmutableArray<CustomModifier> CustomModifiers => WrappedSymbol.CustomModifiers;
#endregion
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Text;
namespace Microsoft.CodeAnalysis
{
internal static partial class NullableExtensions
{
private sealed class TypeParameterSymbolWithNullableAnnotation : TypeSymbolWithNullableAnnotation, ITypeParameterSymbol
{
public TypeParameterSymbolWithNullableAnnotation(ITypeSymbol wrappedSymbol, NullableAnnotation nullability) : base(wrappedSymbol, nullability)
{
}
private new ITypeParameterSymbol WrappedSymbol => (ITypeParameterSymbol)base.WrappedSymbol;
ITypeParameterSymbol ITypeParameterSymbol.OriginalDefinition => WrappedSymbol.OriginalDefinition;
public override void Accept(SymbolVisitor visitor)
{
visitor.VisitTypeParameter(this);
}
public override TResult Accept<TResult>(SymbolVisitor<TResult> visitor)
{
return visitor.VisitTypeParameter(this);
}
#region ITypeParameterSymbol Implementation Forwards
public int Ordinal => WrappedSymbol.Ordinal;
public VarianceKind Variance => WrappedSymbol.Variance;
public TypeParameterKind TypeParameterKind => WrappedSymbol.TypeParameterKind;
public IMethodSymbol DeclaringMethod => WrappedSymbol.DeclaringMethod;
public INamedTypeSymbol DeclaringType => WrappedSymbol.DeclaringType;
public bool HasReferenceTypeConstraint => WrappedSymbol.HasReferenceTypeConstraint;
public NullableAnnotation ReferenceTypeConstraintNullableAnnotation => WrappedSymbol.ReferenceTypeConstraintNullableAnnotation;
public bool HasValueTypeConstraint => WrappedSymbol.HasValueTypeConstraint;
public bool HasUnmanagedTypeConstraint => WrappedSymbol.HasUnmanagedTypeConstraint;
public bool HasConstructorConstraint => WrappedSymbol.HasConstructorConstraint;
public ImmutableArray<ITypeSymbol> ConstraintTypes => WrappedSymbol.ConstraintTypes;
public ImmutableArray<NullableAnnotation> ConstraintNullableAnnotations => WrappedSymbol.ConstraintNullableAnnotations;
public ITypeParameterSymbol ReducedFrom => WrappedSymbol.ReducedFrom;
#endregion
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Threading;
namespace Microsoft.CodeAnalysis
{
internal static partial class NullableExtensions
{
[DebuggerDisplay("{WrappedSymbol,nq}, Nullability = {Nullability,nq}")]
private abstract class TypeSymbolWithNullableAnnotation : ITypeSymbol
{
internal ITypeSymbol WrappedSymbol { get; }
internal NullableAnnotation Nullability { get; }
protected TypeSymbolWithNullableAnnotation(ITypeSymbol wrappedSymbol, NullableAnnotation nullability)
{
Debug.Assert(!(wrappedSymbol is TypeSymbolWithNullableAnnotation));
WrappedSymbol = wrappedSymbol;
Nullability = nullability;
}
public bool Equals(ISymbol other)
{
if (other is TypeSymbolWithNullableAnnotation otherWrappingSymbol)
{
return this.Nullability == otherWrappingSymbol.Nullability &&
this.WrappedSymbol.Equals(otherWrappingSymbol.WrappedSymbol);
}
else if (other is ITypeSymbol)
{
// Somebody is trying to compare a nullable-wrapped symbol with a regular compiler symbol. By rule Equals must be reflexive,
// and since the compiler's Equals won't respect us as being equal, we can't return anything other than false. Flagging this with an assert
// is helpful while moving features over, because this comparison might be the reason a feature isn't working right. However, for now disabling
// the assert is easiest because we can't update the whole codebase at once. Enabling the assert is tracked in https://github.com/dotnet/roslyn/issues/36045.
// Debug.Fail($"A {nameof(TypeSymbolWithNullableAnnotation)} was compared to a regular symbol. This comparison is disallowed.");
// We are also going to cheat further: for now, we'll just throw away nullability and compare, because if a core feature (like the type inferrerr) is updated
// but other features aren't, we want to keep those working.
return this.WrappedSymbol.Equals(other);
}
else
{
return false;
}
}
public override bool Equals(object obj)
{
return this.Equals(obj as ISymbol);
}
public override int GetHashCode()
{
// As a transition mechanism, we allow ourselves to be compared to non-wrapped
// symbols and we compare with the existing compiler equality and just throw away our
// top-level nullability. Because of that, we can't incorporate the top-level nullability
// into our hash code, because if we did we couldn't be both simultaneously equal to
// something that has top level nullability and something that doesn't.
return this.WrappedSymbol.GetHashCode();
}
#region ITypeSymbol Implementation Forwards
public TypeKind TypeKind => WrappedSymbol.TypeKind;
public INamedTypeSymbol BaseType => WrappedSymbol.BaseType;
public ImmutableArray<INamedTypeSymbol> Interfaces => WrappedSymbol.Interfaces;
public ImmutableArray<INamedTypeSymbol> AllInterfaces => WrappedSymbol.AllInterfaces;
public bool IsReferenceType => WrappedSymbol.IsReferenceType;
public bool IsValueType => WrappedSymbol.IsValueType;
public bool IsAnonymousType => WrappedSymbol.IsAnonymousType;
public bool IsTupleType => WrappedSymbol.IsTupleType;
public ITypeSymbol OriginalDefinition => WrappedSymbol.OriginalDefinition;
public SpecialType SpecialType => WrappedSymbol.SpecialType;
public bool IsRefLikeType => WrappedSymbol.IsRefLikeType;
public bool IsUnmanagedType => WrappedSymbol.IsUnmanagedType;
public bool IsReadOnly => WrappedSymbol.IsReadOnly;
public bool IsNamespace => WrappedSymbol.IsNamespace;
public bool IsType => WrappedSymbol.IsType;
public SymbolKind Kind => WrappedSymbol.Kind;
public string Language => WrappedSymbol.Language;
public string Name => WrappedSymbol.Name;
public string MetadataName => WrappedSymbol.MetadataName;
public ISymbol ContainingSymbol => WrappedSymbol.ContainingSymbol;
public IAssemblySymbol ContainingAssembly => WrappedSymbol.ContainingAssembly;
public IModuleSymbol ContainingModule => WrappedSymbol.ContainingModule;
public INamedTypeSymbol ContainingType => WrappedSymbol.ContainingType;
public INamespaceSymbol ContainingNamespace => WrappedSymbol.ContainingNamespace;
public bool IsDefinition => WrappedSymbol.IsDefinition;
public bool IsStatic => WrappedSymbol.IsStatic;
public bool IsVirtual => WrappedSymbol.IsVirtual;
public bool IsOverride => WrappedSymbol.IsOverride;
public bool IsAbstract => WrappedSymbol.IsAbstract;
public bool IsSealed => WrappedSymbol.IsSealed;
public bool IsExtern => WrappedSymbol.IsExtern;
public bool IsImplicitlyDeclared => WrappedSymbol.IsImplicitlyDeclared;
public bool CanBeReferencedByName => WrappedSymbol.CanBeReferencedByName;
public ImmutableArray<Location> Locations => WrappedSymbol.Locations;
public ImmutableArray<SyntaxReference> DeclaringSyntaxReferences => WrappedSymbol.DeclaringSyntaxReferences;
public Accessibility DeclaredAccessibility => WrappedSymbol.DeclaredAccessibility;
public bool HasUnsupportedMetadata => WrappedSymbol.HasUnsupportedMetadata;
ISymbol ISymbol.OriginalDefinition => WrappedSymbol.OriginalDefinition;
public abstract void Accept(SymbolVisitor visitor);
public abstract TResult Accept<TResult>(SymbolVisitor<TResult> visitor);
public ISymbol FindImplementationForInterfaceMember(ISymbol interfaceMember)
{
return WrappedSymbol.FindImplementationForInterfaceMember(interfaceMember);
}
public ImmutableArray<AttributeData> GetAttributes()
{
return WrappedSymbol.GetAttributes();
}
public string GetDocumentationCommentId()
{
return WrappedSymbol.GetDocumentationCommentId();
}
public string GetDocumentationCommentXml(CultureInfo preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default)
{
return WrappedSymbol.GetDocumentationCommentXml(preferredCulture, expandIncludes, cancellationToken);
}
public ImmutableArray<ISymbol> GetMembers()
{
return WrappedSymbol.GetMembers();
}
public ImmutableArray<ISymbol> GetMembers(string name)
{
return WrappedSymbol.GetMembers(name);
}
public ImmutableArray<INamedTypeSymbol> GetTypeMembers()
{
return WrappedSymbol.GetTypeMembers();
}
public ImmutableArray<INamedTypeSymbol> GetTypeMembers(string name)
{
return WrappedSymbol.GetTypeMembers(name);
}
public ImmutableArray<INamedTypeSymbol> GetTypeMembers(string name, int arity)
{
return WrappedSymbol.GetTypeMembers(name, arity);
}
public ImmutableArray<SymbolDisplayPart> ToDisplayParts(NullableFlowState topLevelNullability, SymbolDisplayFormat format = null)
{
return WrappedSymbol.ToDisplayParts(topLevelNullability, format);
}
public ImmutableArray<SymbolDisplayPart> ToDisplayParts(SymbolDisplayFormat format = null)
{
return WrappedSymbol.ToDisplayParts(format);
}
public string ToDisplayString(NullableFlowState topLevelNullability, SymbolDisplayFormat format = null)
{
return WrappedSymbol.ToDisplayString(topLevelNullability, format);
}
public string ToDisplayString(SymbolDisplayFormat format = null)
{
return WrappedSymbol.ToDisplayString(format);
}
public ImmutableArray<SymbolDisplayPart> ToMinimalDisplayParts(SemanticModel semanticModel, NullableFlowState topLevelNullability, int position, SymbolDisplayFormat format = null)
{
return WrappedSymbol.ToMinimalDisplayParts(semanticModel, topLevelNullability, position, format);
}
public ImmutableArray<SymbolDisplayPart> ToMinimalDisplayParts(SemanticModel semanticModel, int position, SymbolDisplayFormat format = null)
{
return WrappedSymbol.ToMinimalDisplayParts(semanticModel, position, format);
}
public string ToMinimalDisplayString(SemanticModel semanticModel, NullableFlowState topLevelNullability, int position, SymbolDisplayFormat format = null)
{
return WrappedSymbol.ToMinimalDisplayString(semanticModel, topLevelNullability, position, format);
}
public string ToMinimalDisplayString(SemanticModel semanticModel, int position, SymbolDisplayFormat format = null)
{
return WrappedSymbol.ToMinimalDisplayString(semanticModel, position, format);
}
#endregion
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册