|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
/// <summary>
/// A <see cref="MissingMetadataTypeSymbol"/> is a special kind of <see cref="ErrorTypeSymbol"/> that represents
/// a type symbol that was attempted to be read from metadata, but couldn't be
/// found, because:
/// a) The metadata file it lives in wasn't referenced
/// b) The metadata file was referenced, but didn't contain the type
/// c) The metadata file was referenced, contained the correct outer type, but
/// didn't contains a nested type in that outer type.
/// </summary>
internal abstract class MissingMetadataTypeSymbol : ErrorTypeSymbol
{
protected readonly string name;
protected readonly int arity;
protected readonly bool mangleName;
private MissingMetadataTypeSymbol(string name, int arity, bool mangleName, TupleExtraData? tupleData = null)
: base(tupleData)
{
RoslynDebug.Assert(name != null);
this.name = name;
this.arity = arity;
this.mangleName = (mangleName && arity > 0);
}
public override string Name
{
get { return name; }
}
internal override bool MangleName
{
get
{
return mangleName;
}
}
internal sealed override bool IsFileLocal => false;
internal sealed override FileIdentifier? AssociatedFileIdentifier => null;
/// <summary>
/// Get the arity of the missing type.
/// </summary>
public override int Arity
{
get { return arity; }
}
internal override DiagnosticInfo ErrorInfo
{
get
{
AssemblySymbol containingAssembly = this.ContainingAssembly;
// The Dev10 C# compiler produces errors based on what it was trying to do when
// the type could not be found. For example, if it could not resolve a base class
// then it would report:
//
// error CS1714: The base class or interface of 'C' could not be resolved or is invalid
//
// Since we do not know what task was being performed, for now we just report a generic
// "you must add a reference" error.
if (containingAssembly?.IsMissing == true)
{
// error CS0012: The type 'Blah' is defined in an assembly that is not referenced. You must add a reference to assembly 'Goo'.
return new CSDiagnosticInfo(ErrorCode.ERR_NoTypeDef, this, containingAssembly.Identity);
}
else
{
ModuleSymbol containingModule = this.ContainingModule;
if (containingModule?.IsMissing == true)
{
// It looks like required module wasn't added to the compilation.
return new CSDiagnosticInfo(ErrorCode.ERR_NoTypeDefFromModule, this, containingModule.Name);
}
// Both the containing assembly and the module were resolved, but the type isn't.
//
// These are warnings in the native compiler, but they seem to always
// be accompanied by an error. It seems strange to make these warnings; something is
// seriously wrong in the program and it is unlikely that we'll be able to correctly
// generate metadata.
// NOTE: this is another case where we would like to base our decision on which compilation
// is the "current" compilation, but we don't want to force consumers of the API to specify.
if (containingAssembly is object)
{
if (containingAssembly.Dangerous_IsFromSomeCompilation)
{
// This scenario is quite tricky and involves a circular reference. Suppose we have
// assembly Alpha that has a type C. Assembly Beta refers to Alpha and uses type C.
// Now we create a new source assembly that replaces Alpha, and refers to Beta.
// The usage of C in Beta will be redirected to refer to the source assembly.
// If C is not in that source assembly then we give the following warning:
// CS7068: Reference to type 'C' claims it is defined in this assembly, but it is not defined in source or any added modules
return new CSDiagnosticInfo(ErrorCode.ERR_MissingTypeInSource, this);
}
else
{
// The more straightforward scenario is that we compiled Beta against a version of Alpha
// that had C, and then added a reference to a different version of Alpha that
// lacks the type C:
// error CS7069: Reference to type 'C' claims it is defined in 'Alpha', but it could not be found
return new CSDiagnosticInfo(ErrorCode.ERR_MissingTypeInAssembly, this, containingAssembly.Name);
}
}
else if (ContainingType is ErrorTypeSymbol { ErrorInfo: { } info })
{
return info;
}
else
{
// This is the best we can do at this point
return new CSDiagnosticInfo(ErrorCode.ERR_BogusType, string.Empty);
}
}
}
}
/// <summary>
/// Represents not nested missing type.
/// </summary>
internal sealed class TopLevel : MissingMetadataTypeSymbol
{
private readonly string _namespaceName;
private readonly ModuleSymbol _containingModule;
private readonly bool _isNativeInt;
private DiagnosticInfo? _lazyErrorInfo;
private NamespaceSymbol? _lazyContainingNamespace;
/// <summary>
/// Either <see cref="SpecialType"/>, <see cref="InternalSpecialType"/>, <see cref="WellKnownType"/>, or -1 if not initialized.
/// </summary>
private int _lazyTypeId;
public TopLevel(ModuleSymbol module, string @namespace, string name, int arity, bool mangleName)
: this(module, @namespace, name, arity, mangleName, errorInfo: null, isNativeInt: false, containingNamespace: null, typeId: -1, tupleData: null)
{
}
public TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, DiagnosticInfo? errorInfo = null)
: this(module, ref fullName, -1, errorInfo)
{
}
public TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, ExtendedSpecialType specialType, DiagnosticInfo? errorInfo = null)
: this(module, ref fullName, (int)specialType, errorInfo)
{
}
public TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, WellKnownType wellKnownType, DiagnosticInfo? errorInfo = null)
: this(module, ref fullName, (int)wellKnownType, errorInfo)
{
}
private TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, int typeId, DiagnosticInfo? errorInfo)
: this(module, ref fullName, fullName.ForcedArity == -1 || fullName.ForcedArity == fullName.InferredArity, errorInfo, typeId)
{
}
private TopLevel(ModuleSymbol module, ref MetadataTypeName fullName, bool mangleName, DiagnosticInfo? errorInfo, int typeId)
: this(module, fullName.NamespaceName,
mangleName ? fullName.UnmangledTypeName : fullName.TypeName,
mangleName ? fullName.InferredArity : fullName.ForcedArity,
mangleName,
isNativeInt: false,
errorInfo,
containingNamespace: null,
typeId,
tupleData: null)
{
}
private TopLevel(ModuleSymbol module, string @namespace, string name, int arity, bool mangleName, bool isNativeInt, DiagnosticInfo? errorInfo, NamespaceSymbol? containingNamespace, int typeId, TupleExtraData? tupleData)
: base(name, arity, mangleName, tupleData)
{
RoslynDebug.Assert((object)module != null);
RoslynDebug.Assert(@namespace != null);
RoslynDebug.Assert(typeId == -1 || typeId == (int)SpecialType.None || arity == 0 || mangleName);
_namespaceName = @namespace;
_containingModule = module;
_isNativeInt = isNativeInt;
_lazyErrorInfo = errorInfo;
_lazyContainingNamespace = containingNamespace;
_lazyTypeId = typeId;
}
protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData)
{
return new TopLevel(_containingModule, _namespaceName, name, arity, mangleName, _isNativeInt, _lazyErrorInfo, _lazyContainingNamespace, _lazyTypeId, newData);
}
/// <summary>
/// This is the FULL namespace name (e.g., "System.Collections.Generic")
/// of the type that couldn't be found.
/// </summary>
public string NamespaceName
{
get { return _namespaceName; }
}
internal override ModuleSymbol ContainingModule
{
get
{
return _containingModule;
}
}
public override AssemblySymbol ContainingAssembly
{
get
{
return _containingModule.ContainingAssembly;
}
}
public override Symbol ContainingSymbol
{
get
{
if ((object?)_lazyContainingNamespace == null)
{
NamespaceSymbol container = _containingModule.GlobalNamespace;
if (_namespaceName.Length > 0)
{
var namespaces = MetadataHelpers.SplitQualifiedName(_namespaceName);
int i;
for (i = 0; i < namespaces.Length; i++)
{
NamespaceSymbol? newContainer = null;
foreach (NamespaceOrTypeSymbol symbol in container.GetMembers(namespaces[i]))
{
if (symbol.Kind == SymbolKind.Namespace) // VB should also check name casing.
{
newContainer = (NamespaceSymbol)symbol;
break;
}
}
if ((object?)newContainer == null)
{
break;
}
container = newContainer;
}
// now create symbols we couldn't find.
for (; i < namespaces.Length; i++)
{
container = new MissingNamespaceSymbol(container, namespaces[i]);
}
}
Interlocked.CompareExchange(ref _lazyContainingNamespace, container, null);
}
return _lazyContainingNamespace;
}
}
private int TypeId
{
get
{
if (_lazyTypeId == -1)
{
ExtendedSpecialType typeId = default;
AssemblySymbol containingAssembly = _containingModule.ContainingAssembly;
if ((Arity == 0 || MangleName) && (object)containingAssembly != null && ReferenceEquals(containingAssembly, containingAssembly.CorLibrary) && _containingModule.Ordinal == 0)
{
// Check the name
string emittedName = MetadataHelpers.BuildQualifiedName(_namespaceName, MetadataName);
typeId = SpecialTypes.GetTypeFromMetadataName(emittedName);
}
Interlocked.CompareExchange(ref _lazyTypeId, (int)typeId, -1);
}
return _lazyTypeId;
}
}
public override ExtendedSpecialType ExtendedSpecialType
{
get
{
int typeId = TypeId;
return (typeId >= (int)WellKnownType.First) ? SpecialType.None : (ExtendedSpecialType)typeId;
}
}
internal override DiagnosticInfo ErrorInfo
{
get
{
if (_lazyErrorInfo == null)
{
var errorInfo = this.TypeId != (int)SpecialType.None ?
new CSDiagnosticInfo(ErrorCode.ERR_PredefinedTypeNotFound, MetadataHelpers.BuildQualifiedName(_namespaceName, MetadataName)) :
base.ErrorInfo;
Interlocked.CompareExchange(ref _lazyErrorInfo, errorInfo, null);
}
return _lazyErrorInfo;
}
}
public override int GetHashCode()
{
// Inherit special behavior for the object type from NamedTypeSymbol.
if (this.SpecialType == Microsoft.CodeAnalysis.SpecialType.System_Object)
{
return (int)Microsoft.CodeAnalysis.SpecialType.System_Object;
}
return Hash.Combine(MetadataName, Hash.Combine(_containingModule, Hash.Combine(_namespaceName, arity)));
}
internal sealed override NamedTypeSymbol AsNativeInteger() => AsNativeInteger(asNativeInt: true);
private TopLevel AsNativeInteger(bool asNativeInt)
{
Debug.Assert(this.SpecialType == SpecialType.System_IntPtr || this.SpecialType == SpecialType.System_UIntPtr);
if (asNativeInt == _isNativeInt)
{
return this;
}
var other = new TopLevel(_containingModule, _namespaceName, name, arity, mangleName, isNativeInt: asNativeInt, _lazyErrorInfo, _lazyContainingNamespace, _lazyTypeId, TupleData);
NativeIntegerTypeSymbol.VerifyEquality(this, other);
Debug.Assert(other.SpecialType == this.SpecialType);
return other;
}
internal sealed override bool IsNativeIntegerWrapperType => _isNativeInt;
internal sealed override NamedTypeSymbol? NativeIntegerUnderlyingType => _isNativeInt ? AsNativeInteger(asNativeInt: false) : null;
internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison)
{
if (ReferenceEquals(this, t2))
{
return true;
}
// if ignoring dynamic, then treat dynamic the same as the type 'object'
if ((comparison & TypeCompareKind.IgnoreDynamic) != 0 &&
(object)t2 != null &&
t2.TypeKind == TypeKind.Dynamic &&
this.SpecialType == Microsoft.CodeAnalysis.SpecialType.System_Object)
{
return true;
}
var other = t2 as TopLevel;
if (other is null)
{
return false;
}
if ((comparison & TypeCompareKind.IgnoreNativeIntegers) == 0 &&
_isNativeInt != other._isNativeInt)
{
return false;
}
return string.Equals(MetadataName, other.MetadataName, StringComparison.Ordinal) &&
arity == other.arity &&
string.Equals(_namespaceName, other.NamespaceName, StringComparison.Ordinal) &&
_containingModule.Equals(other._containingModule);
}
}
/// <summary>
/// Represents nested missing type.
/// </summary>
internal sealed class Nested : MissingMetadataTypeSymbol
{
private readonly NamedTypeSymbol _containingType;
public Nested(NamedTypeSymbol containingType, string name, int arity, bool mangleName)
: base(name, arity, mangleName)
{
RoslynDebug.Assert((object)containingType != null);
_containingType = containingType;
}
public Nested(NamedTypeSymbol containingType, ref MetadataTypeName emittedName)
: this(containingType, ref emittedName, emittedName.ForcedArity == -1 || emittedName.ForcedArity == emittedName.InferredArity)
{
}
private Nested(NamedTypeSymbol containingType, ref MetadataTypeName emittedName, bool mangleName)
: this(containingType,
mangleName ? emittedName.UnmangledTypeName : emittedName.TypeName,
mangleName ? emittedName.InferredArity : emittedName.ForcedArity,
mangleName)
{
}
public override Symbol ContainingSymbol
{
get
{
return _containingType;
}
}
public override ExtendedSpecialType ExtendedSpecialType
{
get
{
return default; // do not have nested types among CORE types yet.
}
}
protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData)
{
throw ExceptionUtilities.Unreachable();
}
public override int GetHashCode()
{
return Hash.Combine(_containingType, Hash.Combine(MetadataName, arity));
}
internal override bool Equals(TypeSymbol t2, TypeCompareKind comparison)
{
if (ReferenceEquals(this, t2))
{
return true;
}
var other = t2 as Nested;
return (object?)other != null && string.Equals(MetadataName, other.MetadataName, StringComparison.Ordinal) &&
arity == other.arity &&
_containingType.Equals(other._containingType, comparison);
}
}
}
}
|