// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Symbols;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
///
/// Represents a method or method-like symbol (including constructor,
/// destructor, operator, or property/event accessor).
///
internal abstract partial class MethodSymbol : Symbol, IMethodSymbolInternal
{
internal const MethodSymbol None = null;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Changes to the public interface of this class should remain synchronized with the VB version.
// Do not make any changes to the public interface without making the corresponding change
// to the VB version.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
protected MethodSymbol()
{
}
///
/// The original definition of this symbol. If this symbol is constructed from another
/// symbol by type substitution then OriginalDefinition gets the original symbol as it was defined in
/// source or metadata.
///
public new virtual MethodSymbol OriginalDefinition
{
get
{
return this;
}
}
protected override sealed Symbol OriginalSymbolDefinition
{
get
{
return this.OriginalDefinition;
}
}
///
/// Gets what kind of method this is. There are several different kinds of things in the
/// C# language that are represented as methods. This property allow distinguishing those things
/// without having to decode the name of the method.
///
public abstract MethodKind MethodKind
{
get;
}
///
/// Returns the arity of this method, or the number of type parameters it takes.
/// A non-generic method has zero arity.
///
public abstract int Arity { get; }
///
/// Returns whether this method is generic; i.e., does it have any type parameters?
///
public virtual bool IsGenericMethod
{
get
{
return this.Arity != 0;
}
}
///
/// True if the method itself is excluded from code coverage instrumentation.
/// True for source methods marked with .
///
internal virtual bool IsDirectlyExcludedFromCodeCoverage { get => false; }
///
/// Returns true if this method is an extension method.
///
public abstract bool IsExtensionMethod { get; }
///
/// True if this symbol has a special name (metadata flag SpecialName is set).
///
internal abstract bool HasSpecialName { get; }
///
/// Misc implementation metadata flags (ImplFlags in metadata).
///
internal abstract System.Reflection.MethodImplAttributes ImplementationAttributes { get; }
///
/// True if the type has declarative security information (HasSecurity flags).
///
internal abstract bool HasDeclarativeSecurity { get; }
///
/// Platform invoke information, or null if the method isn't a P/Invoke.
///
public abstract DllImportData GetDllImportData();
///
/// Declaration security information associated with this type, or null if there is none.
///
internal abstract IEnumerable GetSecurityInformation();
///
/// Marshalling information for return value (FieldMarshal in metadata).
///
internal abstract MarshalPseudoCustomAttributeData ReturnValueMarshallingInformation { get; }
///
/// True if the method calls another method containing security code (metadata flag RequiresSecurityObject is set).
///
///
/// A method can me marked as RequiresSecurityObject by applying the DynamicSecurityMethodAttribute in source.
/// DynamicSecurityMethodAttribute is a pseudo custom attribute defined as an internal class in System.Security namespace.
/// This attribute is set on certain security methods defined within mscorlib.
///
internal abstract bool RequiresSecurityObject { get; }
// Note: This is no public "IsNew". This is intentional, because new has no syntactic meaning.
///
/// Returns true if this method hides base methods by name. This cannot be specified directly
/// in the C# language, but can be true for methods defined in other languages imported from
/// metadata. The equivalent of the "hidebyname" flag in metadata.
///
public abstract bool HidesBaseMethodsByName { get; }
///
/// Returns whether this method is using CLI VARARG calling convention. This is used for C-style variable
/// argument lists. This is used extremely rarely in C# code and is represented using the undocumented "__arglist" keyword.
///
/// Note that methods with "params" on the last parameter are indicated with the "IsParams" property on ParameterSymbol, and
/// are not represented with this property.
///
public abstract bool IsVararg { get; }
///
/// Returns whether this built-in operator checks for integer overflow.
///
public virtual bool IsCheckedBuiltin
{
get
{
return false;
}
}
///
/// Returns true if this method has no return type; i.e., returns "void".
///
public abstract bool ReturnsVoid { get; }
///
/// Source: Returns whether this method is async; i.e., does it have the async modifier?
/// Metadata: Returns false; methods from metadata cannot be async.
///
public abstract bool IsAsync { get; }
///
/// Indicates whether or not the method returns by reference
///
public bool ReturnsByRef
{
get
{
return this.RefKind == RefKind.Ref;
}
}
///
/// Indicates whether or not the method returns by ref readonly
///
public bool ReturnsByRefReadonly
{
get
{
Debug.Assert(this.RefKind != RefKind.Out);
return this.RefKind == RefKind.RefReadOnly;
}
}
///
/// Gets the ref kind of the method's return value
///
public abstract RefKind RefKind { get; }
///
/// Gets the return type of the method
///
public abstract TypeSymbolWithAnnotations ReturnType { get; }
///
/// Returns the type arguments that have been substituted for the type parameters.
/// If nothing has been substituted for a given type parameter,
/// then the type parameter itself is consider the type argument.
///
public abstract ImmutableArray TypeArguments { get; }
///
/// Get the type parameters on this method. If the method has not generic,
/// returns an empty list.
///
public abstract ImmutableArray TypeParameters { get; }
internal ImmutableArray GetTypeParametersAsTypeArguments()
{
// Resolving [NonNullTypes] only makes sense within the definition of the generic type or method.
// If this is a substituted symbol, we use a dummy NonNullTypes context.
var definition = OriginalDefinition;
INonNullTypesContext nonNullTypesContext = (object)this == definition ? definition : NonNullTypesFalseContext.Instance;
return GetTypeParametersAsTypeArguments(nonNullTypesContext);
}
internal ImmutableArray GetTypeParametersAsTypeArguments(INonNullTypesContext nonNullTypesContext) =>
TypeMap.TypeParametersAsTypeSymbolsWithAnnotations(nonNullTypesContext, TypeParameters);
///
/// Call and throw if it returns false.
///
internal ParameterSymbol ThisParameter
{
get
{
ParameterSymbol thisParameter;
if (!TryGetThisParameter(out thisParameter))
{
throw ExceptionUtilities.Unreachable;
}
return thisParameter;
}
}
///
/// True if this type supports retrieving the this parameter
/// and false otherwise. Note that a return value of true does not guarantee a non-null
/// (e.g. fails for static methods).
///
internal virtual bool TryGetThisParameter(out ParameterSymbol thisParameter)
{
thisParameter = null;
return false;
}
///
/// Optimization: in many cases, the parameter count (fast) is sufficient and we
/// don't need the actual parameter symbols (slow).
///
///
/// The default implementation is always correct, but may be unnecessarily slow.
///
internal virtual int ParameterCount
{
get
{
return this.Parameters.Length;
}
}
///
/// Gets the parameters of this method. If this method has no parameters, returns
/// an empty list.
///
public abstract ImmutableArray Parameters { get; }
///
/// Returns the method symbol that this method was constructed from. The resulting
/// method symbol
/// has the same containing type (if any), but has type arguments that are the same
/// as the type parameters (although its containing type might not).
///
public virtual MethodSymbol ConstructedFrom
{
get
{
return this;
}
}
///
/// Source: Was the member name qualified with a type name?
/// Metadata: Is the member an explicit implementation?
///
///
/// Will not always agree with ExplicitInterfaceImplementations.Any()
/// (e.g. if binding of the type part of the name fails).
///
internal virtual bool IsExplicitInterfaceImplementation
{
get { return ExplicitInterfaceImplementations.Any(); }
}
///
/// Returns interface methods explicitly implemented by this method.
///
///
/// Methods imported from metadata can explicitly implement more than one method,
/// that is why return type is ImmutableArray.
///
public abstract ImmutableArray ExplicitInterfaceImplementations { get; }
///
/// Custom modifiers associated with the ref modifier, or an empty array if there are none.
///
public abstract ImmutableArray RefCustomModifiers { get; }
///
/// Gets the attributes on method's return type.
/// Returns an empty array if there are no attributes.
///
public virtual ImmutableArray GetReturnTypeAttributes()
{
Debug.Assert(!(this is IAttributeTargetSymbol)); //such types must override
// Return an empty array by default.
// Sub-classes that can have return type attributes must
// override this method
return ImmutableArray.Empty;
}
///
/// If this method has MethodKind of MethodKind.PropertyGet or MethodKind.PropertySet,
/// returns the property that this method is the getter or setter for.
/// If this method has MethodKind of MethodKind.EventAdd or MethodKind.EventRemove,
/// returns the event that this method is the adder or remover for.
/// Note, the set of possible associated symbols might be expanded in the future to
/// reflect changes in the languages.
///
public abstract Symbol AssociatedSymbol { get; }
///
/// Returns the original virtual or abstract method which a given method symbol overrides,
/// ignoring any other overriding methods in base classes.
///
/// The search must respect accessibility from this type.
internal MethodSymbol GetLeastOverriddenMethod(NamedTypeSymbol accessingTypeOpt)
{
var accessingType = ((object)accessingTypeOpt == null ? this.ContainingType : accessingTypeOpt).OriginalDefinition;
MethodSymbol m = this;
while (m.IsOverride && !m.HidesBaseMethodsByName)
{
// We might not be able to access the overridden method. For example,
//
// .assembly A
// {
// InternalsVisibleTo("B")
// public class A { internal virtual void M() { } }
// }
//
// .assembly B
// {
// InternalsVisibleTo("C")
// public class B : A { internal override void M() { } }
// }
//
// .assembly C
// {
// public class C : B { ... new B().M ... } // A.M is not accessible from here
// }
//
// See InternalsVisibleToAndStrongNameTests: IvtVirtualCall1, IvtVirtualCall2, IvtVirtual_ParamsAndDynamic.
MethodSymbol overridden = m.OverriddenMethod;
HashSet useSiteDiagnostics = null;
if ((object)overridden == null || !AccessCheck.IsSymbolAccessible(overridden, accessingType, ref useSiteDiagnostics))
{
break;
}
m = overridden;
}
return m;
}
///
/// Returns the original virtual or abstract method which a given method symbol overrides,
/// ignoring any other overriding methods in base classes.
/// Also, if the given method symbol is generic then the resulting virtual or abstract method is constructed with the
/// same type arguments as the given method.
///
internal MethodSymbol GetConstructedLeastOverriddenMethod(NamedTypeSymbol accessingTypeOpt)
{
var m = this.ConstructedFrom.GetLeastOverriddenMethod(accessingTypeOpt);
return m.IsGenericMethod ? m.Construct(this.TypeArguments) : m;
}
///
/// If this method overrides another method (because it both had the override modifier
/// and there correctly was a method to override), returns the overridden method.
/// Note that if an overriding method D.M overrides C.M, which in turn overrides
/// virtual method A.M, the "overridden method" of D.M is C.M, not the original virtual
/// method A.M. Note also that constructed generic methods are not considered to
/// override anything.
///
public MethodSymbol OverriddenMethod
{
get
{
if (this.IsOverride && ReferenceEquals(this.ConstructedFrom, this))
{
if (IsDefinition)
{
return (MethodSymbol)OverriddenOrHiddenMembers.GetOverriddenMember();
}
return (MethodSymbol)OverriddenOrHiddenMembersResult.GetOverriddenMember(this, OriginalDefinition.OverriddenMethod);
}
return null;
}
}
///
/// Returns true if calls to this method are omitted in this syntax tree. Calls are omitted
/// when the called method is a partial method with no implementation part, or when the
/// called method is a conditional method whose condition is not true in the source file
/// corresponding to the given syntax tree.
///
internal virtual bool CallsAreOmitted(SyntaxTree syntaxTree)
{
return syntaxTree != null && this.CallsAreConditionallyOmitted(syntaxTree);
}
///
/// Calls are conditionally omitted if both the following requirements are true:
/// (a) IsConditional == true, i.e. it has at least one applied/inherited conditional attribute AND
/// (b) None of conditional symbols corresponding to these conditional attributes are defined in the given syntaxTree.
///
///
/// Forces binding and decoding of attributes.
///
private bool CallsAreConditionallyOmitted(SyntaxTree syntaxTree)
{
if (this.IsConditional)
{
ImmutableArray conditionalSymbols = this.GetAppliedConditionalSymbols();
Debug.Assert(conditionalSymbols != null);
if (syntaxTree.IsAnyPreprocessorSymbolDefined(conditionalSymbols))
{
return false;
}
if (this.IsOverride)
{
var overriddenMethod = this.OverriddenMethod;
if ((object)overriddenMethod != null && overriddenMethod.IsConditional)
{
return overriddenMethod.CallsAreConditionallyOmitted(syntaxTree);
}
}
return true;
}
else
{
return false;
}
}
///
/// Returns a sequence of preprocessor symbols specified in applied on this symbol, or null if there are none.
///
internal abstract ImmutableArray GetAppliedConditionalSymbols();
///
/// Returns a flag indicating whether this symbol has at least one applied/inherited conditional attribute.
///
///
/// Forces binding and decoding of attributes.
///
internal bool IsConditional
{
get
{
if (this.GetAppliedConditionalSymbols().Any())
{
return true;
}
// Conditional attributes are inherited by overriding methods.
if (this.IsOverride)
{
var overriddenMethod = this.OverriddenMethod;
if ((object)overriddenMethod != null)
{
return overriddenMethod.IsConditional;
}
}
return false;
}
}
///
/// Some method kinds do not participate in overriding/hiding (e.g. constructors).
///
internal static bool CanOverrideOrHide(MethodKind kind)
{
switch (kind)
{
case MethodKind.AnonymousFunction:
case MethodKind.Constructor:
case MethodKind.Destructor:
case MethodKind.ExplicitInterfaceImplementation:
case MethodKind.StaticConstructor:
case MethodKind.ReducedExtension:
return false;
case MethodKind.Conversion:
case MethodKind.DelegateInvoke:
case MethodKind.EventAdd:
case MethodKind.EventRemove:
case MethodKind.LocalFunction:
case MethodKind.UserDefinedOperator:
case MethodKind.Ordinary:
case MethodKind.PropertyGet:
case MethodKind.PropertySet:
return true;
default:
throw ExceptionUtilities.UnexpectedValue(kind);
}
}
internal virtual OverriddenOrHiddenMembersResult OverriddenOrHiddenMembers
{
get
{
// To save space, the default implementation does not cache its result. We expect there to
// be a very large number of MethodSymbols and we expect that a large percentage of them will
// obviously not override anything (e.g. static methods, constructors, destructors, etc).
return this.MakeOverriddenOrHiddenMembers();
}
}
///
/// Returns value 'Method' of the
///
public sealed override SymbolKind Kind
{
get
{
return SymbolKind.Method;
}
}
///
/// Returns true if this symbol represents a constructor of a script class.
///
internal bool IsScriptConstructor
{
get
{
return MethodKind == MethodKind.Constructor && ContainingType.IsScriptClass;
}
}
internal virtual bool IsScriptInitializer
{
get { return false; }
}
///
/// Returns if the method is implicit constructor (normal and static)
///
internal bool IsImplicitConstructor
{
get
{
return ((MethodKind == MethodKind.Constructor || MethodKind == MethodKind.StaticConstructor) && IsImplicitlyDeclared);
}
}
///
/// Returns if the method is implicit instance constructor
///
internal bool IsImplicitInstanceConstructor
{
get
{
return MethodKind == MethodKind.Constructor && IsImplicitlyDeclared;
}
}
///
/// Returns true if this symbol represents a constructor of an interactive submission class.
///
internal bool IsSubmissionConstructor
{
get
{
return IsScriptConstructor && ContainingAssembly.IsInteractive;
}
}
internal bool IsSubmissionInitializer
{
get
{
return IsScriptInitializer && ContainingAssembly.IsInteractive;
}
}
///
/// Determines whether this method is a candidate for a default assembly entry point
/// (i.e. it is a static method called "Main").
///
internal bool IsEntryPointCandidate
{
get
{
if (this.IsPartialDefinition() &&
this.PartialImplementationPart is null)
{
return false;
}
return IsStatic && Name == WellKnownMemberNames.EntryPointMethodName;
}
}
internal override TResult Accept(CSharpSymbolVisitor visitor, TArgument argument)
{
return visitor.VisitMethod(this, argument);
}
public override void Accept(CSharpSymbolVisitor visitor)
{
visitor.VisitMethod(this);
}
public override TResult Accept(CSharpSymbolVisitor visitor)
{
return visitor.VisitMethod(this);
}
///
/// If this is an extension method that can be applied to a receiver of the given type,
/// returns a reduced extension method symbol thus formed. Otherwise, returns null.
///
public MethodSymbol ReduceExtensionMethod(TypeSymbol receiverType)
{
if ((object)receiverType == null)
{
throw new ArgumentNullException(nameof(receiverType));
}
if (!this.IsExtensionMethod || this.MethodKind == MethodKind.ReducedExtension)
{
return null;
}
// To give optimal diagnostics, we should really pass the "current" compilation.
// However, this is never used in batch scenarios, so it doesn't matter
// (modulo future changes to the API).
return ReducedExtensionMethodSymbol.Create(this, receiverType, compilation: null);
}
///
/// If this is an extension method, returns a reduced extension method
/// symbol representing the method. Otherwise, returns null.
///
public MethodSymbol ReduceExtensionMethod()
{
return (this.IsExtensionMethod && this.MethodKind != MethodKind.ReducedExtension) ? ReducedExtensionMethodSymbol.Create(this) : null;
}
///
/// If this method is a reduced extension method, returns the extension method that
/// should be used at call site during ILGen. Otherwise, returns null.
///
internal virtual MethodSymbol CallsiteReducedFromMethod
{
get { return null; }
}
///
/// If this is a partial method declaration without a body, and the method also
/// has a part that implements it with a body, returns that implementing
/// definition. Otherwise null.
///
public virtual MethodSymbol PartialImplementationPart
{
get { return null; }
}
///
/// If this is a partial method with a body, returns the corresponding
/// definition part (without a body). Otherwise null.
///
public virtual MethodSymbol PartialDefinitionPart
{
get { return null; }
}
///
/// If this method is a reduced extension method, gets the extension method definition that
/// this method was reduced from. Otherwise, returns null.
///
public virtual MethodSymbol ReducedFrom
{
get { return null; }
}
///
/// If this method can be applied to an object, returns the type of object it is applied to.
///
public virtual TypeSymbol ReceiverType
{
get
{
return this.ContainingType;
}
}
///
/// If this method is a reduced extension method, returns a type inferred during reduction process for the type parameter.
///
/// Type parameter of the corresponding method.
/// Inferred type or Nothing if nothing was inferred.
/// If this is not a reduced extension method.
/// If is null.
/// If doesn't belong to the corresponding method.
public virtual TypeSymbol GetTypeInferredDuringReduction(TypeParameterSymbol reducedFromTypeParameter)
{
throw new InvalidOperationException();
}
///
/// Apply type substitution to a generic method to create an method symbol with the given type parameters supplied.
///
///
///
public MethodSymbol Construct(params TypeSymbol[] typeArguments)
{
return this.Construct(ImmutableArray.Create(typeArguments));
}
///
/// Apply type substitution to a generic method to create an method symbol with the given type parameters supplied.
///
///
///
public MethodSymbol Construct(ImmutableArray typeArguments)
{
return Construct(typeArguments.SelectAsArray(a => TypeSymbolWithAnnotations.Create(a)));
}
internal MethodSymbol Construct(ImmutableArray typeArguments)
{
if (!ReferenceEquals(this, ConstructedFrom) || this.Arity == 0)
{
throw new InvalidOperationException();
}
if (typeArguments.IsDefault)
{
throw new ArgumentNullException(nameof(typeArguments));
}
if (typeArguments.Any(NamedTypeSymbol.TypeSymbolIsNullFunction))
{
throw new ArgumentException(CSharpResources.TypeArgumentCannotBeNull, nameof(typeArguments));
}
if (typeArguments.Length != this.Arity)
{
throw new ArgumentException(CSharpResources.WrongNumberOfTypeArguments, nameof(typeArguments));
}
if (ConstructedNamedTypeSymbol.TypeParametersMatchTypeArguments(this.TypeParameters, typeArguments))
{
return this;
}
return new ConstructedMethodSymbol(this, typeArguments);
}
internal MethodSymbol AsMember(NamedTypeSymbol newOwner)
{
Debug.Assert(this.IsDefinition);
Debug.Assert(ReferenceEquals(newOwner.OriginalDefinition, this.ContainingSymbol.OriginalDefinition));
return (newOwner == this.ContainingSymbol) ? this : new SubstitutedMethodSymbol(newOwner, this);
}
///
/// As a performance optimization, cache parameter types and refkinds - overload resolution uses them a lot.
///
private ParameterSignature _lazyParameterSignature;
internal ImmutableArray ParameterTypes
{
get
{
ParameterSignature.PopulateParameterSignature(this.Parameters, ref _lazyParameterSignature);
return _lazyParameterSignature.parameterTypes;
}
}
///
/// Null if no parameter is ref/out. Otherwise the RefKind for each parameter.
///
internal ImmutableArray ParameterRefKinds
{
get
{
ParameterSignature.PopulateParameterSignature(this.Parameters, ref _lazyParameterSignature);
return _lazyParameterSignature.parameterRefKinds;
}
}
internal abstract Microsoft.Cci.CallingConvention CallingConvention
{
get;
}
///
/// Returns the map from type parameters to type arguments.
/// If this is not a generic method instantiation, returns null.
/// The map targets the original definition of the method.
///
internal virtual TypeMap TypeSubstitution
{
get { return null; }
}
#region Use-Site Diagnostics
internal override DiagnosticInfo GetUseSiteDiagnostic()
{
if (this.IsDefinition)
{
return base.GetUseSiteDiagnostic();
}
// There is no reason to specially check type arguments because
// constructed members are never imported.
return this.OriginalDefinition.GetUseSiteDiagnostic();
}
internal bool CalculateUseSiteDiagnostic(ref DiagnosticInfo result)
{
Debug.Assert(this.IsDefinition);
// Check return type, custom modifiers, parameters
if (DeriveUseSiteDiagnosticFromType(ref result, this.ReturnType) ||
DeriveUseSiteDiagnosticFromCustomModifiers(ref result, this.RefCustomModifiers) ||
DeriveUseSiteDiagnosticFromParameters(ref result, this.Parameters))
{
return true;
}
// If the member is in an assembly with unified references,
// we check if its definition depends on a type from a unified reference.
if (this.ContainingModule.HasUnifiedReferences)
{
HashSet unificationCheckedTypes = null;
if (this.ReturnType.GetUnificationUseSiteDiagnosticRecursive(ref result, this, ref unificationCheckedTypes) ||
GetUnificationUseSiteDiagnosticRecursive(ref result, this.RefCustomModifiers, this, ref unificationCheckedTypes) ||
GetUnificationUseSiteDiagnosticRecursive(ref result, this.Parameters, this, ref unificationCheckedTypes) ||
GetUnificationUseSiteDiagnosticRecursive(ref result, this.TypeParameters, this, ref unificationCheckedTypes))
{
return true;
}
}
return false;
}
///
/// Return error code that has highest priority while calculating use site error for this symbol.
///
protected override int HighestPriorityUseSiteError
{
get
{
return (int)ErrorCode.ERR_BindToBogus;
}
}
public sealed override bool HasUnsupportedMetadata
{
get
{
DiagnosticInfo info = GetUseSiteDiagnostic();
return (object)info != null && (info.Code == (int)ErrorCode.ERR_BindToBogus || info.Code == (int)ErrorCode.ERR_ByRefReturnUnsupported);
}
}
#endregion
internal bool IsIterator
{
get
{
return (object)IteratorElementType != null;
}
}
///
/// If the method was written as an iterator method (i.e. with yield statements in its body) returns the
/// element type of the iterator. Otherwise returns null.
///
internal virtual TypeSymbol IteratorElementType
{
get { return null; }
set { throw ExceptionUtilities.Unreachable; }
}
///
/// Generates bound block representing method's body for methods in lowered form and adds it to
/// a collection of method bodies of the current module. This method is supposed to only be
/// called for method symbols which return SynthesizesLoweredBoundBody == true.
///
internal virtual void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
{
throw ExceptionUtilities.Unreachable;
}
///
/// Returns true for synthesized symbols which generate synthesized body in lowered form
///
internal virtual bool SynthesizesLoweredBoundBody
{
get
{
return false;
}
}
///
/// Return true iff the method contains user code.
///
internal abstract bool GenerateDebugInfo { get; }
///
/// Calculates a syntax offset for a local (user-defined or long-lived synthesized) declared at .
/// Must be implemented by all methods that may contain user code.
///
///
/// Syntax offset is a unique identifier for the local within the emitted method body.
/// It's based on position of the local declarator. In single-part method bodies it's simply the distance
/// from the start of the method body syntax span. If a method body has multiple parts (such as a constructor
/// comprising of code for member initializers and constructor initializer calls) the offset is calculated
/// as if all source these parts were concatenated together and prepended to the constructor body.
/// The resulting syntax offset is then negative for locals defined outside of the constructor body.
///
internal abstract int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree);
public override bool? NonNullTypes
{
get
{
return (AssociatedSymbol ?? ContainingSymbol)?.NonNullTypes;
}
}
#region IMethodSymbol Members
MethodKind IMethodSymbol.MethodKind
{
get
{
switch (this.MethodKind)
{
case MethodKind.AnonymousFunction:
return MethodKind.AnonymousFunction;
case MethodKind.Constructor:
return MethodKind.Constructor;
case MethodKind.Conversion:
return MethodKind.Conversion;
case MethodKind.DelegateInvoke:
return MethodKind.DelegateInvoke;
case MethodKind.Destructor:
return MethodKind.Destructor;
case MethodKind.EventAdd:
return MethodKind.EventAdd;
case MethodKind.EventRemove:
return MethodKind.EventRemove;
case MethodKind.ExplicitInterfaceImplementation:
return MethodKind.ExplicitInterfaceImplementation;
case MethodKind.UserDefinedOperator:
return MethodKind.UserDefinedOperator;
case MethodKind.BuiltinOperator:
return MethodKind.BuiltinOperator;
case MethodKind.Ordinary:
return MethodKind.Ordinary;
case MethodKind.PropertyGet:
return MethodKind.PropertyGet;
case MethodKind.PropertySet:
return MethodKind.PropertySet;
case MethodKind.ReducedExtension:
return MethodKind.ReducedExtension;
case MethodKind.StaticConstructor:
return MethodKind.StaticConstructor;
case MethodKind.LocalFunction:
return MethodKind.LocalFunction;
default:
throw ExceptionUtilities.UnexpectedValue(this.MethodKind);
}
}
}
ITypeSymbol IMethodSymbol.ReturnType
{
get
{
return this.ReturnType.TypeSymbol;
}
}
ImmutableArray IMethodSymbol.TypeArguments
{
get
{
return this.TypeArguments.SelectAsArray(a => (ITypeSymbol)a.TypeSymbol);
}
}
ImmutableArray IMethodSymbol.TypeParameters
{
get
{
return StaticCast.From(this.TypeParameters);
}
}
ImmutableArray IMethodSymbol.Parameters
{
get
{
return StaticCast.From(this.Parameters);
}
}
IMethodSymbol IMethodSymbol.ConstructedFrom
{
get
{
return this.ConstructedFrom;
}
}
IMethodSymbol IMethodSymbol.OriginalDefinition
{
get
{
return this.OriginalDefinition;
}
}
IMethodSymbol IMethodSymbol.OverriddenMethod
{
get
{
return this.OverriddenMethod;
}
}
ITypeSymbol IMethodSymbol.ReceiverType
{
get
{
return this.ReceiverType;
}
}
IMethodSymbol IMethodSymbol.ReducedFrom
{
get
{
return this.ReducedFrom;
}
}
ITypeSymbol IMethodSymbol.GetTypeInferredDuringReduction(ITypeParameterSymbol reducedFromTypeParameter)
{
return this.GetTypeInferredDuringReduction(reducedFromTypeParameter.EnsureCSharpSymbolOrNull(nameof(reducedFromTypeParameter)));
}
IMethodSymbol IMethodSymbol.ReduceExtensionMethod(ITypeSymbol receiverType)
{
return this.ReduceExtensionMethod(receiverType.EnsureCSharpSymbolOrNull(nameof(receiverType)));
}
ImmutableArray IMethodSymbol.ExplicitInterfaceImplementations
{
get
{
return this.ExplicitInterfaceImplementations.Cast();
}
}
ISymbol IMethodSymbol.AssociatedSymbol
{
get
{
return this.AssociatedSymbol;
}
}
bool IMethodSymbol.IsGenericMethod
{
get
{
return this.IsGenericMethod;
}
}
bool IMethodSymbol.IsAsync
{
get
{
return this.IsAsync;
}
}
bool IMethodSymbol.HidesBaseMethodsByName
{
get
{
return this.HidesBaseMethodsByName;
}
}
ImmutableArray IMethodSymbol.ReturnTypeCustomModifiers
{
get
{
return this.ReturnType.CustomModifiers;
}
}
ImmutableArray IMethodSymbol.RefCustomModifiers
{
get
{
return this.RefCustomModifiers;
}
}
ImmutableArray IMethodSymbol.GetReturnTypeAttributes()
{
return this.GetReturnTypeAttributes().Cast();
}
///
/// Build and add synthesized return type attributes for this method symbol.
///
internal virtual void AddSynthesizedReturnTypeAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes)
{
if (this.ReturnsByRefReadonly)
{
AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeIsReadOnlyAttribute(this));
}
var compilation = this.DeclaringCompilation;
var type = this.ReturnType;
if (type.TypeSymbol.ContainsDynamic() && compilation.HasDynamicEmitAttributes())
{
AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(type.TypeSymbol, type.CustomModifiers.Length + this.RefCustomModifiers.Length, this.RefKind));
}
if (type.TypeSymbol.ContainsTupleNames() && compilation.HasTupleNamesAttributes)
{
AddSynthesizedAttribute(ref attributes, compilation.SynthesizeTupleNamesAttribute(type.TypeSymbol));
}
// PROTOTYPE(NullableReferenceTypes): type.ReportAnnotatedUnconstrainedTypeParameterIfAny()
if (type.ContainsNullableReferenceTypes())
{
AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeNullableAttribute(this, type));
}
}
IMethodSymbol IMethodSymbol.Construct(params ITypeSymbol[] arguments)
{
foreach (var arg in arguments)
{
arg.EnsureCSharpSymbolOrNull("typeArguments");
}
return this.Construct(arguments.Cast().AsImmutable());
}
IMethodSymbol IMethodSymbol.PartialImplementationPart
{
get
{
return PartialImplementationPart;
}
}
IMethodSymbol IMethodSymbol.PartialDefinitionPart
{
get
{
return PartialDefinitionPart;
}
}
INamedTypeSymbol IMethodSymbol.AssociatedAnonymousDelegate
{
get
{
return null;
}
}
#endregion
///
/// Is this a method of a tuple type?
///
public virtual bool IsTupleMethod
{
get
{
return false;
}
}
///
/// If this is a method of a tuple type, return corresponding underlying method from the
/// tuple underlying type. Otherwise, null.
///
public virtual MethodSymbol TupleUnderlyingMethod
{
get
{
return null;
}
}
#region IMethodSymbolInternal
bool IMethodSymbolInternal.IsIterator => IsIterator;
int IMethodSymbolInternal.CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) => CalculateLocalSyntaxOffset(localPosition, localTree);
#endregion
#region ISymbol Members
public override void Accept(SymbolVisitor visitor)
{
visitor.VisitMethod(this);
}
public override TResult Accept(SymbolVisitor visitor)
{
return visitor.VisitMethod(this);
}
#endregion
}
}