Compilation_WellKnownMembers.cs 43.8 KB
Newer Older
1
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
P
Pilchie 已提交
2 3 4 5 6

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
7
using System.Linq;
P
Pilchie 已提交
8 9
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
T
Tomas Matousek 已提交
10
using Microsoft.CodeAnalysis.PooledObjects;
P
Pilchie 已提交
11 12 13 14 15 16 17 18
using Microsoft.CodeAnalysis.RuntimeMembers;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp
{
    // TODO: (tomat) translated 1:1 from VB, might need adjustments
    // TODO: (tomat) can we share more with VB?

19
    public partial class CSharpCompilation
P
Pilchie 已提交
20
    {
21
        internal readonly WellKnownMembersSignatureComparer WellKnownMemberSignatureComparer;
P
Pilchie 已提交
22 23 24 25 26

        /// <summary>
        /// An array of cached well known types available for use in this Compilation.
        /// Lazily filled by GetWellKnownType method.
        /// </summary>
27
        private NamedTypeSymbol[] _lazyWellKnownTypes;
P
Pilchie 已提交
28 29 30 31 32

        /// <summary>
        /// Lazy cache of well known members.
        /// Not yet known value is represented by ErrorTypeSymbol.UnknownResultType
        /// </summary>
33
        private Symbol[] _lazyWellKnownTypeMembers;
P
Pilchie 已提交
34

35
        private bool _needsGeneratedIsReadOnlyAttribute_Value;
V
vsadov 已提交
36 37
        private bool _needsGeneratedIsByRefLikeAttribute_Value;

38
        private bool _needsGeneratedAttributes_IsFrozen;
39 40 41 42 43 44 45 46 47 48

        /// <summary>
        /// Returns a value indicating whether this compilation has a member that needs IsReadOnlyAttribute to be generated during emit phase.
        /// The value is set during binding the symbols that need that attribute, and is frozen on first trial to get it.
        /// Freezing is needed to make sure that nothing tries to modify the value after the value is read.
        /// </summary>
        internal bool NeedsGeneratedIsReadOnlyAttribute
        {
            get
            {
49
                _needsGeneratedAttributes_IsFrozen = true;
50 51 52 53
                return _needsGeneratedIsReadOnlyAttribute_Value;
            }
        }

V
vsadov 已提交
54 55 56 57 58 59 60 61 62
        /// <summary>
        /// Returns a value indicating whether this compilation has a member that needs IsIsByRefLikeAttribute to be generated during emit phase.
        /// The value is set during binding the symbols that need that attribute, and is frozen on first trial to get it.
        /// Freezing is needed to make sure that nothing tries to modify the value after the value is read.
        /// </summary>
        internal bool NeedsGeneratedIsByRefLikeAttribute
        {
            get
            {
63
                _needsGeneratedAttributes_IsFrozen = true;
V
vsadov 已提交
64 65 66 67
                return _needsGeneratedIsByRefLikeAttribute_Value;
            }
        }

P
Pilchie 已提交
68 69 70 71 72 73 74 75 76 77 78
        /// <summary>
        /// Lookup member declaration in well known type used by this Compilation.
        /// </summary>
        /// <remarks>
        /// If a well-known member of a generic type instantiation is needed use this method to get the corresponding generic definition and 
        /// <see cref="MethodSymbol.AsMember"/> to construct an instantiation.
        /// </remarks>
        internal Symbol GetWellKnownTypeMember(WellKnownMember member)
        {
            Debug.Assert(member >= 0 && member < WellKnownMember.Count);

79
            // Test hook: if a member is marked missing, then return null.
80
            if (IsMemberMissing(member)) return null;
P
Pilchie 已提交
81

82
            if (_lazyWellKnownTypeMembers == null || ReferenceEquals(_lazyWellKnownTypeMembers[(int)member], ErrorTypeSymbol.UnknownResultType))
P
Pilchie 已提交
83
            {
84
                if (_lazyWellKnownTypeMembers == null)
P
Pilchie 已提交
85 86 87 88 89 90 91 92
                {
                    var wellKnownTypeMembers = new Symbol[(int)WellKnownMember.Count];

                    for (int i = 0; i < wellKnownTypeMembers.Length; i++)
                    {
                        wellKnownTypeMembers[i] = ErrorTypeSymbol.UnknownResultType;
                    }

93
                    Interlocked.CompareExchange(ref _lazyWellKnownTypeMembers, wellKnownTypeMembers, null);
P
Pilchie 已提交
94 95 96 97 98 99 100 101 102 103
                }

                MemberDescriptor descriptor = WellKnownMembers.GetDescriptor(member);
                NamedTypeSymbol type = descriptor.DeclaringTypeId <= (int)SpecialType.Count
                                            ? this.GetSpecialType((SpecialType)descriptor.DeclaringTypeId)
                                            : this.GetWellKnownType((WellKnownType)descriptor.DeclaringTypeId);
                Symbol result = null;

                if (!type.IsErrorType())
                {
104
                    result = GetRuntimeMember(type, ref descriptor, WellKnownMemberSignatureComparer, accessWithinOpt: this.Assembly);
P
Pilchie 已提交
105 106
                }

107
                Interlocked.CompareExchange(ref _lazyWellKnownTypeMembers[(int)member], result, ErrorTypeSymbol.UnknownResultType);
P
Pilchie 已提交
108 109
            }

110
            return _lazyWellKnownTypeMembers[(int)member];
P
Pilchie 已提交
111 112
        }

113 114 115 116 117 118
        /// <summary>
        /// This method handles duplicate types in a few different ways:
        /// - for types before C# 7, the first candidate is returned with a warning
        /// - for types after C# 7, the type is considered missing
        /// - in both cases, when BinderFlags.IgnoreCorLibraryDuplicatedTypes is set, any duplicate coming from corlib will be ignored (ie not count as a duplicate)
        /// </summary>
P
Pilchie 已提交
119 120
        internal NamedTypeSymbol GetWellKnownType(WellKnownType type)
        {
C
Charles Stoner 已提交
121
            Debug.Assert(type.IsValid());
P
Pilchie 已提交
122

123 124
            bool ignoreCorLibraryDuplicatedTypes = this.Options.TopLevelBinderFlags.Includes(BinderFlags.IgnoreCorLibraryDuplicatedTypes);

P
Pilchie 已提交
125
            int index = (int)type - (int)WellKnownType.First;
126
            if (_lazyWellKnownTypes == null || (object)_lazyWellKnownTypes[index] == null)
P
Pilchie 已提交
127
            {
128
                if (_lazyWellKnownTypes == null)
P
Pilchie 已提交
129
                {
130
                    Interlocked.CompareExchange(ref _lazyWellKnownTypes, new NamedTypeSymbol[(int)WellKnownTypes.Count], null);
P
Pilchie 已提交
131 132 133 134
                }

                string mdName = type.GetMetadataName();
                var warnings = DiagnosticBag.GetInstance();
135
                NamedTypeSymbol result;
136
                (AssemblySymbol, AssemblySymbol) conflicts = default;
137 138 139 140 141 142 143

                if (IsTypeMissing(type))
                {
                    result = null;
                }
                else
                {
144 145
                    // well-known types introduced before CSharp7 allow lookup ambiguity and report a warning
                    DiagnosticBag legacyWarnings = (type <= WellKnownType.CSharp7Sentinel) ? warnings : null;
146
                    result = this.Assembly.GetTypeByMetadataName(
147
                        mdName, includeReferences: true, useCLSCompliantNameArityEncoding: true, isWellKnownType: true, conflicts: out conflicts,
148
                        warnings: legacyWarnings, ignoreCorLibraryDuplicatedTypes: ignoreCorLibraryDuplicatedTypes);
149
                }
P
Pilchie 已提交
150 151 152 153 154

                if ((object)result == null)
                {
                    // TODO: should GetTypeByMetadataName rather return a missing symbol?
                    MetadataTypeName emittedName = MetadataTypeName.FromFullName(mdName, useCLSCompliantNameArityEncoding: true);
155 156
                    if (type.IsValueTupleType())
                    {
157 158 159 160 161 162 163 164 165 166 167 168
                        CSDiagnosticInfo errorInfo;
                        if (conflicts.Item1 is null)
                        {
                            Debug.Assert(conflicts.Item2 is null);
                            errorInfo = new CSDiagnosticInfo(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, emittedName.FullName);
                        }
                        else
                        {
                            errorInfo = new CSDiagnosticInfo(ErrorCode.ERR_PredefinedValueTupleTypeAmbiguous3, emittedName.FullName, conflicts.Item1, conflicts.Item2);
                        }

                        result = new MissingMetadataTypeSymbol.TopLevelWithCustomErrorInfo(this.Assembly.Modules[0], ref emittedName, errorInfo, type);
169 170 171 172 173
                    }
                    else
                    {
                        result = new MissingMetadataTypeSymbol.TopLevel(this.Assembly.Modules[0], ref emittedName, type);
                    }
P
Pilchie 已提交
174 175
                }

176
                if ((object)Interlocked.CompareExchange(ref _lazyWellKnownTypes[index], result, null) != null)
P
Pilchie 已提交
177 178
                {
                    Debug.Assert(
179
                        result == _lazyWellKnownTypes[index] || (_lazyWellKnownTypes[index].IsErrorType() && result.IsErrorType())
P
Pilchie 已提交
180 181 182 183 184 185 186 187 188 189
                    );
                }
                else
                {
                    AdditionalCodegenWarnings.AddRange(warnings);
                }

                warnings.Free();
            }

190
            return _lazyWellKnownTypes[index];
P
Pilchie 已提交
191 192 193 194 195 196 197 198 199 200 201 202 203
        }

        internal bool IsAttributeType(TypeSymbol type)
        {
            HashSet<DiagnosticInfo> useSiteDiagnostics = null;
            return IsEqualOrDerivedFromWellKnownClass(type, WellKnownType.System_Attribute, ref useSiteDiagnostics);
        }

        internal override bool IsAttributeType(ITypeSymbol type)
        {
            return IsAttributeType((TypeSymbol)type);
        }

204
        internal bool IsExceptionType(TypeSymbol type, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
P
Pilchie 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
        {
            return IsEqualOrDerivedFromWellKnownClass(type, WellKnownType.System_Exception, ref useSiteDiagnostics);
        }

        internal bool IsEqualOrDerivedFromWellKnownClass(TypeSymbol type, WellKnownType wellKnownType, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(wellKnownType == WellKnownType.System_Attribute ||
                         wellKnownType == WellKnownType.System_Exception);

            if (type.Kind != SymbolKind.NamedType || type.TypeKind != TypeKind.Class)
            {
                return false;
            }

            var wkType = GetWellKnownType(wellKnownType);
220
            return type.Equals(wkType, TypeCompareKind.ConsiderEverything) || type.IsDerivedFrom(wkType, TypeCompareKind.ConsiderEverything, useSiteDiagnostics: ref useSiteDiagnostics);
P
Pilchie 已提交
221 222 223 224 225 226 227 228 229 230 231 232
        }

        internal override bool IsSystemTypeReference(ITypeSymbol type)
        {
            return (TypeSymbol)type == GetWellKnownType(WellKnownType.System_Type);
        }

        internal override ISymbol CommonGetWellKnownTypeMember(WellKnownMember member)
        {
            return GetWellKnownTypeMember(member);
        }

233
        internal static Symbol GetRuntimeMember(NamedTypeSymbol declaringType, ref MemberDescriptor descriptor, SignatureComparer<MethodSymbol, FieldSymbol, PropertySymbol, TypeSymbol, ParameterSymbol> comparer, AssemblySymbol accessWithinOpt)
P
Pilchie 已提交
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
        {
            Symbol result = null;
            SymbolKind targetSymbolKind;
            MethodKind targetMethodKind = MethodKind.Ordinary;
            bool isStatic = (descriptor.Flags & MemberFlags.Static) != 0;

            switch (descriptor.Flags & MemberFlags.KindMask)
            {
                case MemberFlags.Constructor:
                    targetSymbolKind = SymbolKind.Method;
                    targetMethodKind = MethodKind.Constructor;
                    //  static constructors are never called explicitly
                    Debug.Assert(!isStatic);
                    break;

                case MemberFlags.Method:
                    targetSymbolKind = SymbolKind.Method;
                    break;

                case MemberFlags.PropertyGet:
                    targetSymbolKind = SymbolKind.Method;
                    targetMethodKind = MethodKind.PropertyGet;
                    break;

                case MemberFlags.Field:
                    targetSymbolKind = SymbolKind.Field;
                    break;

                case MemberFlags.Property:
                    targetSymbolKind = SymbolKind.Property;
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(descriptor.Flags);
            }

            foreach (var member in declaringType.GetMembers(descriptor.Name))
            {
                Debug.Assert(member.Name.Equals(descriptor.Name));

274
                if (member.Kind != targetSymbolKind || member.IsStatic != isStatic ||
275
                    !(member.DeclaredAccessibility == Accessibility.Public || ((object)accessWithinOpt != null && Symbol.IsSymbolAccessible(member, accessWithinOpt))))
P
Pilchie 已提交
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
                {
                    continue;
                }

                switch (targetSymbolKind)
                {
                    case SymbolKind.Method:
                        {
                            MethodSymbol method = (MethodSymbol)member;
                            MethodKind methodKind = method.MethodKind;
                            // Treat user-defined conversions and operators as ordinary methods for the purpose
                            // of matching them here.
                            if (methodKind == MethodKind.Conversion || methodKind == MethodKind.UserDefinedOperator)
                            {
                                methodKind = MethodKind.Ordinary;
                            }

                            if (method.Arity != descriptor.Arity || methodKind != targetMethodKind ||
                                ((descriptor.Flags & MemberFlags.Virtual) != 0) != (method.IsVirtual || method.IsOverride || method.IsAbstract))
                            {
                                continue;
                            }

                            if (!comparer.MatchMethodSignature(method, descriptor.Signature))
                            {
                                continue;
                            }
                        }

                        break;

                    case SymbolKind.Property:
                        {
                            PropertySymbol property = (PropertySymbol)member;
                            if (((descriptor.Flags & MemberFlags.Virtual) != 0) != (property.IsVirtual || property.IsOverride || property.IsAbstract))
                            {
                                continue;
                            }

                            if (!comparer.MatchPropertySignature(property, descriptor.Signature))
                            {
                                continue;
                            }
                        }

                        break;

                    case SymbolKind.Field:
                        if (!comparer.MatchFieldSignature((FieldSymbol)member, descriptor.Signature))
                        {
                            continue;
                        }

                        break;

                    default:
                        throw ExceptionUtilities.UnexpectedValue(targetSymbolKind);
                }

                // ambiguity
                if ((object)result != null)
                {
                    result = null;
                    break;
                }

                result = member;
            }
            return result;
        }

        /// <summary>
        /// Synthesizes a custom attribute. 
A
angocke 已提交
349 350 351
        /// Returns null if the <paramref name="constructor"/> symbol is missing,
        /// or any of the members in <paramref name="namedArguments" /> are missing.
        /// The attribute is synthesized only if present.
P
Pilchie 已提交
352
        /// </summary>
A
angocke 已提交
353 354 355 356 357 358 359 360 361 362
        /// <param name="constructor">
        /// Constructor of the attribute. If it doesn't exist, the attribute is not created.
        /// </param>
        /// <param name="arguments">Arguments to the attribute constructor.</param>
        /// <param name="namedArguments">
        /// Takes a list of pairs of well-known members and constants. The constants
        /// will be passed to the field/property referenced by the well-known member.
        /// If the well-known member does not exist in the compilation then no attribute
        /// will be synthesized.
        /// </param>
363 364 365
        /// <param name="isOptionalUse">
        /// Indicates if this particular attribute application should be considered optional.
        /// </param>
A
angocke 已提交
366
        internal SynthesizedAttributeData TrySynthesizeAttribute(
P
Pilchie 已提交
367 368
            WellKnownMember constructor,
            ImmutableArray<TypedConstant> arguments = default(ImmutableArray<TypedConstant>),
369 370
            ImmutableArray<KeyValuePair<WellKnownMember, TypedConstant>> namedArguments = default(ImmutableArray<KeyValuePair<WellKnownMember, TypedConstant>>),
            bool isOptionalUse = false)
P
Pilchie 已提交
371
        {
372 373 374
            DiagnosticInfo diagnosticInfo;
            var ctorSymbol = (MethodSymbol)Binder.GetWellKnownTypeMember(this, constructor, out diagnosticInfo, isOptional: true);

P
Pilchie 已提交
375 376 377
            if ((object)ctorSymbol == null)
            {
                // if this assert fails, UseSiteErrors for "member" have not been checked before emitting ...
378
                Debug.Assert(isOptionalUse || WellKnownMembers.IsSynthesizedAttributeOptional(constructor));
P
Pilchie 已提交
379 380 381 382 383 384 385 386
                return null;
            }

            if (arguments.IsDefault)
            {
                arguments = ImmutableArray<TypedConstant>.Empty;
            }

A
angocke 已提交
387
            ImmutableArray<KeyValuePair<string, TypedConstant>> namedStringArguments;
P
Pilchie 已提交
388 389
            if (namedArguments.IsDefault)
            {
A
angocke 已提交
390 391 392 393 394 395 396
                namedStringArguments = ImmutableArray<KeyValuePair<string, TypedConstant>>.Empty;
            }
            else
            {
                var builder = new ArrayBuilder<KeyValuePair<string, TypedConstant>>(namedArguments.Length);
                foreach (var arg in namedArguments)
                {
397
                    var wellKnownMember = Binder.GetWellKnownTypeMember(this, arg.Key, out diagnosticInfo, isOptional: true);
A
angocke 已提交
398 399 400 401 402 403 404 405 406 407 408 409 410
                    if (wellKnownMember == null || wellKnownMember is ErrorTypeSymbol)
                    {
                        // if this assert fails, UseSiteErrors for "member" have not been checked before emitting ...
                        Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(constructor));
                        return null;
                    }
                    else
                    {
                        builder.Add(new KeyValuePair<string, TypedConstant>(
                            wellKnownMember.Name, arg.Value));
                    }
                }
                namedStringArguments = builder.ToImmutableAndFree();
P
Pilchie 已提交
411 412
            }

A
angocke 已提交
413
            return new SynthesizedAttributeData(ctorSymbol, arguments, namedStringArguments);
P
Pilchie 已提交
414 415 416 417
        }

        internal SynthesizedAttributeData SynthesizeDecimalConstantAttribute(decimal value)
        {
T
tmat 已提交
418 419 420 421
            bool isNegative;
            byte scale;
            uint low, mid, high;
            value.GetBits(out isNegative, out scale, out low, out mid, out high);
P
Pilchie 已提交
422 423 424 425 426 427
            var systemByte = GetSpecialType(SpecialType.System_Byte);
            Debug.Assert(!systemByte.HasUseSiteError);

            var systemUnit32 = GetSpecialType(SpecialType.System_UInt32);
            Debug.Assert(!systemUnit32.HasUseSiteError);

A
angocke 已提交
428
            return TrySynthesizeAttribute(
P
Pilchie 已提交
429 430
                WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor,
                ImmutableArray.Create(
T
tmat 已提交
431 432 433 434 435
                    new TypedConstant(systemByte, TypedConstantKind.Primitive, scale),
                    new TypedConstant(systemByte, TypedConstantKind.Primitive, (byte)(isNegative ? 128 : 0)),
                    new TypedConstant(systemUnit32, TypedConstantKind.Primitive, high),
                    new TypedConstant(systemUnit32, TypedConstantKind.Primitive, mid),
                    new TypedConstant(systemUnit32, TypedConstantKind.Primitive, low)
P
Pilchie 已提交
436 437 438 439 440
                ));
        }

        internal SynthesizedAttributeData SynthesizeDebuggerBrowsableNeverAttribute()
        {
441
            if (Options.OptimizationLevel != OptimizationLevel.Debug)
P
Pilchie 已提交
442 443 444 445
            {
                return null;
            }

A
angocke 已提交
446
            return TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_DebuggerBrowsableAttribute__ctor,
P
Pilchie 已提交
447 448 449 450 451 452
                   ImmutableArray.Create(new TypedConstant(
                       GetWellKnownType(WellKnownType.System_Diagnostics_DebuggerBrowsableState),
                       TypedConstantKind.Enum,
                       DebuggerBrowsableState.Never)));
        }

453 454 455 456 457 458 459 460 461 462
        internal SynthesizedAttributeData SynthesizeDebuggerStepThroughAttribute()
        {
            if (Options.OptimizationLevel != OptimizationLevel.Debug)
            {
                return null;
            }

            return TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_DebuggerStepThroughAttribute__ctor);
        }

463 464
        internal void EnsureIsReadOnlyAttributeExists(DiagnosticBag diagnostics, Location location, bool modifyCompilationForRefReadOnly)
        {
465
            Debug.Assert(!modifyCompilationForRefReadOnly || !_needsGeneratedAttributes_IsFrozen);
V
vsadov 已提交
466

467 468 469 470 471 472 473 474
            var isNeeded = CheckIfIsReadOnlyAttributeShouldBeEmbedded(diagnostics, location);

            if (isNeeded && modifyCompilationForRefReadOnly)
            {
                _needsGeneratedIsReadOnlyAttribute_Value = true;
            }
        }

V
vsadov 已提交
475 476
        internal void EnsureIsByRefLikeAttributeExists(DiagnosticBag diagnostics, Location location, bool modifyCompilationForIsByRefLike)
        {
477
            Debug.Assert(!modifyCompilationForIsByRefLike || !_needsGeneratedAttributes_IsFrozen);
V
vsadov 已提交
478 479 480 481 482 483 484 485 486

            var isNeeded = CheckIfIsByRefLikeAttributeShouldBeEmbedded(diagnostics, location);

            if (isNeeded && modifyCompilationForIsByRefLike)
            {
                _needsGeneratedIsByRefLikeAttribute_Value = true;
            }
        }

487
        internal bool CheckIfIsReadOnlyAttributeShouldBeEmbedded(DiagnosticBag diagnosticsOpt, Location locationOpt)
488
        {
V
vsadov 已提交
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
            return CheckIfAttributeShouldBeEmbedded(
                diagnosticsOpt, 
                locationOpt, 
                WellKnownType.System_Runtime_CompilerServices_IsReadOnlyAttribute, 
                WellKnownMember.System_Runtime_CompilerServices_IsReadOnlyAttribute__ctor);
        }

        internal bool CheckIfIsByRefLikeAttributeShouldBeEmbedded(DiagnosticBag diagnosticsOpt, Location locationOpt)
        {
            return CheckIfAttributeShouldBeEmbedded(
                diagnosticsOpt, 
                locationOpt, 
                WellKnownType.System_Runtime_CompilerServices_IsByRefLikeAttribute, 
                WellKnownMember.System_Runtime_CompilerServices_IsByRefLikeAttribute__ctor);
        }

        private bool CheckIfAttributeShouldBeEmbedded(DiagnosticBag diagnosticsOpt, Location locationOpt, WellKnownType attributeType, WellKnownMember attributeCtor)
        {
            var userDefinedAttribute = GetWellKnownType(attributeType);
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526

            if (userDefinedAttribute is MissingMetadataTypeSymbol)
            {
                if (Options.OutputKind == OutputKind.NetModule)
                {
                    if (diagnosticsOpt != null)
                    {
                        var errorReported = Binder.ReportUseSiteDiagnostics(userDefinedAttribute, diagnosticsOpt, locationOpt);
                        Debug.Assert(errorReported);
                    }
                }
                else
                {
                    return true;
                }
            }
            else if (diagnosticsOpt != null)
            {
                // This should produce diagnostics if the member is missing or bad
V
vsadov 已提交
527
                Binder.GetWellKnownTypeMember(this, attributeCtor, diagnosticsOpt, locationOpt);
528 529 530
            }

            return false;
531 532
        }

P
Pilchie 已提交
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
        internal SynthesizedAttributeData SynthesizeDebuggableAttribute()
        {
            TypeSymbol debuggableAttribute = GetWellKnownType(WellKnownType.System_Diagnostics_DebuggableAttribute);
            Debug.Assert((object)debuggableAttribute != null, "GetWellKnownType unexpectedly returned null");
            if (debuggableAttribute is MissingMetadataTypeSymbol)
            {
                return null;
            }

            TypeSymbol debuggingModesType = GetWellKnownType(WellKnownType.System_Diagnostics_DebuggableAttribute__DebuggingModes);
            Debug.Assert((object)debuggingModesType != null, "GetWellKnownType unexpectedly returned null");
            if (debuggingModesType is MissingMetadataTypeSymbol)
            {
                return null;
            }

549 550 551 552 553 554
            // IgnoreSymbolStoreDebuggingMode flag is checked by the CLR, it is not referred to by the debugger.
            // It tells the JIT that it doesn't need to load the PDB at the time it generates jitted code. 
            // The PDB would still be used by a debugger, or even by the runtime for putting source line information 
            // on exception stack traces. We always set this flag to avoid overhead of JIT loading the PDB. 
            // The theoretical scenario for not setting it would be a language compiler that wants their sequence points 
            // at specific places, but those places don't match what CLR's heuristics calculate when scanning the IL.
555 556
            var ignoreSymbolStoreDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__IgnoreSymbolStoreSequencePoints);
            if ((object)ignoreSymbolStoreDebuggingMode == null || !ignoreSymbolStoreDebuggingMode.HasConstantValue)
P
Pilchie 已提交
557 558 559 560
            {
                return null;
            }

561
            int constantVal = ignoreSymbolStoreDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value;
P
Pilchie 已提交
562

563 564 565 566 567 568
            // Since .NET 2.0 the combinations of None, Default and DisableOptimizations have the following effect:
            // 
            // None                                         JIT optimizations enabled
            // Default                                      JIT optimizations enabled
            // DisableOptimizations                         JIT optimizations enabled
            // Default | DisableOptimizations               JIT optimizations disabled
569
            if (_options.OptimizationLevel == OptimizationLevel.Debug)
P
Pilchie 已提交
570
            {
571 572 573 574 575
                var defaultDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__Default);
                if ((object)defaultDebuggingMode == null || !defaultDebuggingMode.HasConstantValue)
                {
                    return null;
                }
P
Pilchie 已提交
576

577 578 579 580 581
                var disableOptimizationsDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__DisableOptimizations);
                if ((object)disableOptimizationsDebuggingMode == null || !disableOptimizationsDebuggingMode.HasConstantValue)
                {
                    return null;
                }
P
Pilchie 已提交
582

583 584
                constantVal |= defaultDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value;
                constantVal |= disableOptimizationsDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value;
585
            }
P
Pilchie 已提交
586

587
            if (_options.EnableEditAndContinue)
588
            {
589 590 591 592 593 594 595
                var enableEncDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__EnableEditAndContinue);
                if ((object)enableEncDebuggingMode == null || !enableEncDebuggingMode.HasConstantValue)
                {
                    return null;
                }

                constantVal |= enableEncDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value;
P
Pilchie 已提交
596 597 598 599
            }

            var typedConstantDebugMode = new TypedConstant(debuggingModesType, TypedConstantKind.Enum, constantVal);

A
angocke 已提交
600
            return TrySynthesizeAttribute(
P
Pilchie 已提交
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
                WellKnownMember.System_Diagnostics_DebuggableAttribute__ctorDebuggingModes,
                ImmutableArray.Create(typedConstantDebugMode));
        }

        /// <summary>
        /// Given a type <paramref name="type"/>, which is either dynamic type OR is a constructed type with dynamic type present in it's type argument tree,
        /// returns a synthesized DynamicAttribute with encoded dynamic transforms array.
        /// </summary>
        /// <remarks>This method is port of AttrBind::CompileDynamicAttr from the native C# compiler.</remarks>
        internal SynthesizedAttributeData SynthesizeDynamicAttribute(TypeSymbol type, int customModifiersCount, RefKind refKindOpt = RefKind.None)
        {
            Debug.Assert((object)type != null);
            Debug.Assert(type.ContainsDynamic());

            if (type.IsDynamic() && refKindOpt == RefKind.None && customModifiersCount == 0)
            {
A
angocke 已提交
617
                return TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_DynamicAttribute__ctor);
P
Pilchie 已提交
618 619 620 621 622
            }
            else
            {
                NamedTypeSymbol booleanType = GetSpecialType(SpecialType.System_Boolean);
                Debug.Assert((object)booleanType != null);
623
                var transformFlags = DynamicTransformsEncoder.Encode(type, refKindOpt, customModifiersCount, booleanType);
624
                var boolArray = ArrayTypeSymbol.CreateSZArray(booleanType.ContainingAssembly, booleanType, customModifiers: ImmutableArray<CustomModifier>.Empty);
P
Pilchie 已提交
625
                var arguments = ImmutableArray.Create<TypedConstant>(new TypedConstant(boolArray, transformFlags));
A
angocke 已提交
626
                return TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_DynamicAttribute__ctorTransformFlags, arguments);
P
Pilchie 已提交
627 628 629
            }
        }

630
        internal SynthesizedAttributeData SynthesizeTupleNamesAttribute(TypeSymbol type)
631 632 633 634 635 636 637
        {
            Debug.Assert((object)type != null);
            Debug.Assert(type.ContainsTuple());

            var stringType = GetSpecialType(SpecialType.System_String);
            Debug.Assert((object)stringType != null);
            var names = TupleNamesEncoder.Encode(type, stringType);
638

V
VSadov 已提交
639
            Debug.Assert(!names.IsDefault, "should not need the attribute when no tuple names");
640

641 642 643 644 645
            var stringArray = ArrayTypeSymbol.CreateSZArray(stringType.ContainingAssembly, stringType, customModifiers: ImmutableArray<CustomModifier>.Empty);
            var args = ImmutableArray.Create(new TypedConstant(stringArray, names));
            return TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_TupleElementNamesAttribute__ctorTransformNames, args);
        }

646
        internal static class TupleNamesEncoder
647
        {
648 649 650 651 652 653 654 655 656 657 658 659 660
            public static ImmutableArray<string> Encode(TypeSymbol type)
            {
                var namesBuilder = ArrayBuilder<string>.GetInstance();

                if (!TryGetNames(type, namesBuilder))
                {
                    namesBuilder.Free();
                    return default(ImmutableArray<string>);
                }

                return namesBuilder.ToImmutableAndFree();
            }

661 662 663 664
            public static ImmutableArray<TypedConstant> Encode(TypeSymbol type, TypeSymbol stringType)
            {
                var namesBuilder = ArrayBuilder<string>.GetInstance();

665
                if (!TryGetNames(type, namesBuilder))
666 667 668 669 670
                {
                    namesBuilder.Free();
                    return default(ImmutableArray<TypedConstant>);
                }

671 672 673 674 675 676
                var names = namesBuilder.SelectAsArray((name, constantType) =>
                    new TypedConstant(constantType, TypedConstantKind.Primitive, name), stringType);
                namesBuilder.Free();
                return names;
            }

677
            internal static bool TryGetNames(TypeSymbol type, ArrayBuilder<string> namesBuilder)
678 679 680 681 682
            {
                type.VisitType((t, builder, _ignore) => AddNames(t, builder), namesBuilder);
                return namesBuilder.Any(name => name != null);
            }

683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
            private static bool AddNames(TypeSymbol type, ArrayBuilder<string> namesBuilder)
            {
                if (type.IsTupleType)
                {
                    if (type.TupleElementNames.IsDefaultOrEmpty)
                    {
                        // If none of the tuple elements have names, put
                        // null placeholders in.
                        // TODO(https://github.com/dotnet/roslyn/issues/12347):
                        // A possible optimization could be to emit an empty attribute
                        // if all the names are missing, but that has to be true
                        // recursively.
                        namesBuilder.AddMany(null, type.TupleElementTypes.Length);
                    }
                    else
                    {
                        namesBuilder.AddRange(type.TupleElementNames);
                    }
                }
                // Always recur into nested types
                return false;
            }
        }

P
Pilchie 已提交
707 708 709 710 711
        /// <summary>
        /// Used to generate the dynamic attributes for the required typesymbol.
        /// </summary>
        internal static class DynamicTransformsEncoder
        {
712
            internal static ImmutableArray<TypedConstant> Encode(TypeSymbol type, RefKind refKind, int customModifiersCount, TypeSymbol booleanType)
P
Pilchie 已提交
713 714
            {
                var flagsBuilder = ArrayBuilder<bool>.GetInstance();
715
                Encode(type, customModifiersCount, refKind, flagsBuilder, addCustomModifierFlags: true);
P
Pilchie 已提交
716 717 718
                Debug.Assert(flagsBuilder.Any());
                Debug.Assert(flagsBuilder.Contains(true));

719
                var result = flagsBuilder.SelectAsArray((flag, constantType) => new TypedConstant(constantType, TypedConstantKind.Primitive, flag), booleanType);
P
Pilchie 已提交
720
                flagsBuilder.Free();
721 722 723 724 725 726 727 728
                return result;
            }

            internal static ImmutableArray<bool> Encode(TypeSymbol type, RefKind refKind, int customModifiersCount)
            {
                var builder = ArrayBuilder<bool>.GetInstance();
                Encode(type, customModifiersCount, refKind, builder, addCustomModifierFlags: true);
                return builder.ToImmutableAndFree();
P
Pilchie 已提交
729 730
            }

731 732
            internal static ImmutableArray<bool> EncodeWithoutCustomModifierFlags(TypeSymbol type, RefKind refKind)
            {
733 734 735
                var builder = ArrayBuilder<bool>.GetInstance();
                Encode(type, -1, refKind, builder, addCustomModifierFlags: false);
                return builder.ToImmutableAndFree();
736 737
            }

738
            internal static void Encode(TypeSymbol type, int customModifiersCount, RefKind refKind, ArrayBuilder<bool> transformFlagsBuilder, bool addCustomModifierFlags)
P
Pilchie 已提交
739 740 741 742 743 744 745 746 747
            {
                Debug.Assert(!transformFlagsBuilder.Any());

                if (refKind != RefKind.None)
                {
                    // Native compiler encodes an extra transform flag, always false, for ref/out parameters.
                    transformFlagsBuilder.Add(false);
                }

748 749 750 751
                if (addCustomModifierFlags)
                {
                    // Native compiler encodes an extra transform flag, always false, for each custom modifier.
                    HandleCustomModifiers(customModifiersCount, transformFlagsBuilder);
752
                    type.VisitType((typeSymbol, builder, isNested) => AddFlags(typeSymbol, builder, isNested, addCustomModifierFlags: true), transformFlagsBuilder);
753 754 755
                }
                else
                {
756
                    type.VisitType((typeSymbol, builder, isNested) => AddFlags(typeSymbol, builder, isNested, addCustomModifierFlags: false), transformFlagsBuilder);
757
                }
P
Pilchie 已提交
758 759
            }

760
            private static bool AddFlags(TypeSymbol type, ArrayBuilder<bool> transformFlagsBuilder, bool isNestedNamedType, bool addCustomModifierFlags)
P
Pilchie 已提交
761 762 763 764
            {
                // Encode transforms flag for this type and it's custom modifiers (if any).
                switch (type.TypeKind)
                {
765
                    case TypeKind.Dynamic:
P
Pilchie 已提交
766 767 768
                        transformFlagsBuilder.Add(true);
                        break;

769
                    case TypeKind.Array:
770 771 772 773 774
                        if (addCustomModifierFlags)
                        {
                            HandleCustomModifiers(((ArrayTypeSymbol)type).CustomModifiers.Length, transformFlagsBuilder);
                        }

P
Pilchie 已提交
775 776 777
                        transformFlagsBuilder.Add(false);
                        break;

778
                    case TypeKind.Pointer:
779 780 781 782 783
                        if (addCustomModifierFlags)
                        {
                            HandleCustomModifiers(((PointerTypeSymbol)type).CustomModifiers.Length, transformFlagsBuilder);
                        }

P
Pilchie 已提交
784 785 786 787 788 789 790 791 792 793
                        transformFlagsBuilder.Add(false);
                        break;

                    default:
                        // Encode transforms flag for this type.
                        // For nested named types, a single flag (false) is encoded for the entire type name, followed by flags for all of the type arguments.
                        // For example, for type "A<T>.B<dynamic>", encoded transform flags are:
                        //      {
                        //          false,  // Type "A.B"
                        //          false,  // Type parameter "T"
C
Charles Stoner 已提交
794
                        //          true,   // Type parameter "dynamic"
P
Pilchie 已提交
795 796 797 798 799 800 801 802 803 804 805
                        //      }

                        if (!isNestedNamedType)
                        {
                            transformFlagsBuilder.Add(false);
                        }
                        break;
                }

                // Continue walking types
                return false;
806
            }
P
Pilchie 已提交
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827

            private static void HandleCustomModifiers(int customModifiersCount, ArrayBuilder<bool> transformFlagsBuilder)
            {
                for (int i = 0; i < customModifiersCount; i++)
                {
                    // Native compiler encodes an extra transforms flag, always false, for each custom modifier.
                    transformFlagsBuilder.Add(false);
                }
            }
        }

        internal class SpecialMembersSignatureComparer : SignatureComparer<MethodSymbol, FieldSymbol, PropertySymbol, TypeSymbol, ParameterSymbol>
        {
            // Fields
            public static readonly SpecialMembersSignatureComparer Instance = new SpecialMembersSignatureComparer();

            // Methods
            protected SpecialMembersSignatureComparer()
            {
            }

828
            protected override TypeSymbol GetMDArrayElementType(TypeSymbol type)
P
Pilchie 已提交
829 830 831 832 833 834
            {
                if (type.Kind != SymbolKind.ArrayType)
                {
                    return null;
                }
                ArrayTypeSymbol array = (ArrayTypeSymbol)type;
835
                if (array.IsSZArray)
P
Pilchie 已提交
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
                {
                    return null;
                }
                return array.ElementType;
            }

            protected override TypeSymbol GetFieldType(FieldSymbol field)
            {
                return field.Type;
            }

            protected override TypeSymbol GetPropertyType(PropertySymbol property)
            {
                return property.Type;
            }

            protected override TypeSymbol GetGenericTypeArgument(TypeSymbol type, int argumentIndex)
            {
                if (type.Kind != SymbolKind.NamedType)
                {
                    return null;
                }
                NamedTypeSymbol named = (NamedTypeSymbol)type;
                if (named.Arity <= argumentIndex)
                {
                    return null;
                }
                if ((object)named.ContainingType != null)
                {
                    return null;
                }
                return named.TypeArgumentsNoUseSiteDiagnostics[argumentIndex];
            }

            protected override TypeSymbol GetGenericTypeDefinition(TypeSymbol type)
            {
                if (type.Kind != SymbolKind.NamedType)
                {
                    return null;
                }
                NamedTypeSymbol named = (NamedTypeSymbol)type;
                if ((object)named.ContainingType != null)
                {
                    return null;
                }
                if (named.Arity == 0)
                {
                    return null;
                }
                return (NamedTypeSymbol)named.OriginalDefinition;
            }

            protected override ImmutableArray<ParameterSymbol> GetParameters(MethodSymbol method)
            {
                return method.Parameters;
            }

            protected override ImmutableArray<ParameterSymbol> GetParameters(PropertySymbol property)
            {
                return property.Parameters;
            }

            protected override TypeSymbol GetParamType(ParameterSymbol parameter)
            {
                return parameter.Type;
            }

            protected override TypeSymbol GetPointedToType(TypeSymbol type)
            {
                return type.Kind == SymbolKind.PointerType ? ((PointerTypeSymbol)type).PointedAtType : null;
            }

            protected override TypeSymbol GetReturnType(MethodSymbol method)
            {
                return method.ReturnType;
            }

            protected override TypeSymbol GetSZArrayElementType(TypeSymbol type)
            {
                if (type.Kind != SymbolKind.ArrayType)
                {
                    return null;
                }
                ArrayTypeSymbol array = (ArrayTypeSymbol)type;
920
                if (!array.IsSZArray)
P
Pilchie 已提交
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
                {
                    return null;
                }
                return array.ElementType;
            }

            protected override bool IsByRefParam(ParameterSymbol parameter)
            {
                return parameter.RefKind != RefKind.None;
            }

            protected override bool IsGenericMethodTypeParam(TypeSymbol type, int paramPosition)
            {
                if (type.Kind != SymbolKind.TypeParameter)
                {
                    return false;
                }
                TypeParameterSymbol typeParam = (TypeParameterSymbol)type;
                if (typeParam.ContainingSymbol.Kind != SymbolKind.Method)
                {
                    return false;
                }
                return (typeParam.Ordinal == paramPosition);
            }

            protected override bool IsGenericTypeParam(TypeSymbol type, int paramPosition)
            {
                if (type.Kind != SymbolKind.TypeParameter)
                {
                    return false;
                }
                TypeParameterSymbol typeParam = (TypeParameterSymbol)type;
                if (typeParam.ContainingSymbol.Kind != SymbolKind.NamedType)
                {
                    return false;
                }
                return (typeParam.Ordinal == paramPosition);
            }

            protected override bool MatchArrayRank(TypeSymbol type, int countOfDimensions)
            {
                if (type.Kind != SymbolKind.ArrayType)
                {
                    return false;
                }
966

P
Pilchie 已提交
967 968 969 970 971 972 973 974 975 976
                ArrayTypeSymbol array = (ArrayTypeSymbol)type;
                return (array.Rank == countOfDimensions);
            }

            protected override bool MatchTypeToTypeId(TypeSymbol type, int typeId)
            {
                return (int)type.SpecialType == typeId;
            }
        }

977
        internal sealed class WellKnownMembersSignatureComparer : SpecialMembersSignatureComparer
P
Pilchie 已提交
978
        {
979
            private readonly CSharpCompilation _compilation;
P
Pilchie 已提交
980 981 982

            public WellKnownMembersSignatureComparer(CSharpCompilation compilation)
            {
983
                _compilation = compilation;
P
Pilchie 已提交
984 985 986 987 988
            }

            protected override bool MatchTypeToTypeId(TypeSymbol type, int typeId)
            {
                WellKnownType wellKnownId = (WellKnownType)typeId;
C
Charles Stoner 已提交
989
                if (wellKnownId.IsWellKnownType())
P
Pilchie 已提交
990
                {
991
                    return (type == _compilation.GetWellKnownType(wellKnownId));
P
Pilchie 已提交
992 993 994 995 996 997 998
                }

                return base.MatchTypeToTypeId(type, typeId);
            }
        }
    }
}