// 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.Runtime.InteropServices; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols { /// /// Represents a parameter of a method or indexer. /// internal abstract partial class ParameterSymbol : Symbol, IParameterSymbol { internal const string ValueParameterName = "value"; internal ParameterSymbol() { } /// /// 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 ParameterSymbol OriginalDefinition { get { return this; } } protected override sealed Symbol OriginalSymbolDefinition { get { return this.OriginalDefinition; } } /// /// Gets the type of the parameter. /// public abstract TypeSymbol Type { get; } /// /// Determines if the parameter ref, out or neither. /// public abstract RefKind RefKind { get; } /// /// The list of custom modifiers, if any, associated with the parameter type. /// public abstract ImmutableArray CustomModifiers { get; } /// /// Custom modifiers associated with the ref modifier, or an empty array if there are none. /// public abstract ImmutableArray RefCustomModifiers { get; } /// /// Describes how the parameter is marshalled when passed to native code. /// Null if no specific marshalling information is available for the parameter. /// /// PE symbols don't provide this information and always return null. internal abstract MarshalPseudoCustomAttributeData MarshallingInformation { get; } /// /// Returns the marshalling type of this parameter, or 0 if marshalling information isn't available. /// /// /// By default this information is extracted from if available. /// Since the compiler does only need to know the marshalling type of symbols that aren't emitted /// PE symbols just decode the type from metadata and don't provide full marshalling information. /// internal virtual UnmanagedType MarshallingType { get { var info = MarshallingInformation; return info != null ? info.UnmanagedType : 0; } } internal bool IsMarshalAsObject { get { switch (this.MarshallingType) { case UnmanagedType.Interface: case UnmanagedType.IUnknown: case Cci.Constants.UnmanagedType_IDispatch: return true; } return false; } } /// /// Gets the ordinal position of the parameter. The first parameter has ordinal zero. /// The "'this' parameter has ordinal -1. /// public abstract int Ordinal { get; } /// /// Returns true if the parameter was declared as a parameter array. /// public abstract bool IsParams { get; } /// /// Returns true if the parameter is semantically optional. /// /// /// True iff the parameter has a default argument syntax, /// or the parameter is not a params-array and Optional metadata flag is set. /// public bool IsOptional { get { // DEV10 COMPATIBILITY: Special handling for ParameterArray params // // Ideally we should not need the additional "isParams" check below // as a ParameterArray param cannot have a default value. // However, for certain cases of overriding this is not true. // See test "CodeGenTests.NoDefaultForParams_Dev10781558" for an example. // See Roslyn bug 10753 and Dev10 bug 781558 for details. // // To maintain compatibility with Dev10, we allow such code to compile but explicitly // classify a ParameterArray param as a required parameter. // // Also when we call f() where signature of f is void([Optional]params int[] args) // an empty array is created and passed to f. // // We also do not consider ref/out parameters as optional, unless in COM interop scenarios // and only for ref. RefKind refKind; return !IsParams && IsMetadataOptional && ((refKind = RefKind) == RefKind.None || (refKind == RefKind.In) || (refKind == RefKind.Ref && ContainingSymbol.ContainingType.IsComImport)); } } /// /// True if Optional flag is set in metadata. /// internal abstract bool IsMetadataOptional { get; } /// /// True if In flag is set in metadata. /// internal abstract bool IsMetadataIn { get; } /// /// True if Out flag is set in metadata. /// internal abstract bool IsMetadataOut { get; } /// /// Returns true if the parameter explicitly specifies a default value to be passed /// when no value is provided as an argument to a call. /// /// /// True if the parameter has a default argument syntax, /// or the parameter is from source and is applied, /// or the parameter is from metadata and HasDefault metadata flag is set. See /// to determine if the parameter will be considered optional by /// overload resolution. /// /// The default value can be obtained with property. /// public bool HasExplicitDefaultValue { get { // In the symbol model, only optional parameters have default values. // Internally, however, non-optional parameters may also have default // values (accessible via DefaultConstantValue). For example, if the // DefaultParameterValue attribute is applied to a non-optional parameter // we still want to emit a default parameter value, even if it isn't // recognized by the language. // Special Case: params parameters are never optional, but can have // default values (e.g. if the params-ness is inherited from an // overridden method, but the current method declares the parameter // as optional). In such cases, dev11 emits the default value. return IsOptional && ExplicitDefaultConstantValue != null; } } /// /// Returns the default value of the parameter. If /// returns false then DefaultValue throws an InvalidOperationException. /// /// /// If the parameter type is a struct and the default value of the parameter /// is the default value of the struct type or of type parameter type which is /// not known to be a referenced type, then this property will return null. /// /// The parameter has no default value. [DebuggerBrowsable(DebuggerBrowsableState.Never)] public object ExplicitDefaultValue { get { if (HasExplicitDefaultValue) { return ExplicitDefaultConstantValue.Value; } throw new InvalidOperationException(); } } /// /// Returns the default value constant of the parameter, /// or null if the parameter doesn't have a default value or /// the parameter type is a struct and the default value of the parameter /// is the default value of the struct type or of type parameter type which is /// not known to be a referenced type. /// /// /// This is used for emitting. It does not reflect the language semantics /// (i.e. even non-optional parameters can have default values). /// internal abstract ConstantValue ExplicitDefaultConstantValue { get; } /// /// Gets the kind of this symbol. /// public sealed override SymbolKind Kind { get { return SymbolKind.Parameter; } } /// /// Implements visitor pattern. /// internal override TResult Accept(CSharpSymbolVisitor visitor, TArgument argument) { return visitor.VisitParameter(this, argument); } public override void Accept(CSharpSymbolVisitor visitor) { visitor.VisitParameter(this); } public override TResult Accept(CSharpSymbolVisitor visitor) { return visitor.VisitParameter(this); } /// /// Get this accessibility that was declared on this symbol. For symbols that do not have /// accessibility declared on them, returns NotApplicable. /// public override Accessibility DeclaredAccessibility { get { return Accessibility.NotApplicable; } } /// /// Returns true if this symbol was declared as requiring an override; i.e., declared with /// the "abstract" modifier. Also returns true on a type declared as "abstract", all /// interface types, and members of interface types. /// public override bool IsAbstract { get { return false; } } /// /// Returns true if this symbol was declared to override a base class member and was also /// sealed from further overriding; i.e., declared with the "sealed" modifier. Also set for /// types that do not allow a derived class (declared with "sealed" or "static" or "struct" /// or "enum" or "delegate"). /// public override bool IsSealed { get { return false; } } /// /// Returns true if this symbol is "virtual", has an implementation, and does not override a /// base class member; i.e., declared with the "virtual" modifier. Does not return true for /// members declared as abstract or override. /// public override bool IsVirtual { get { return false; } } /// /// Returns true if this symbol was declared to override a base class member; i.e., declared /// with the "override" modifier. Still returns true if member was declared to override /// something, but (erroneously) no member to override exists. /// public override bool IsOverride { get { return false; } } /// /// Returns true if this symbol is "static"; i.e., declared with the "static" modifier or /// implicitly static. /// public override bool IsStatic { get { return false; } } /// /// Returns true if this symbol has external implementation; i.e., declared with the /// "extern" modifier. /// public override bool IsExtern { get { return false; } } /// /// Returns true if the parameter is the hidden 'this' parameter. /// public virtual bool IsThis { get { return false; } } /// /// Returns data decoded from Obsolete attribute or null if there is no Obsolete attribute. /// This property returns ObsoleteAttributeData.Uninitialized if attribute arguments haven't been decoded yet. /// internal sealed override ObsoleteAttributeData ObsoleteAttributeData { get { return null; } } internal abstract bool IsIDispatchConstant { get; } internal abstract bool IsIUnknownConstant { get; } internal abstract bool IsCallerFilePath { get; } internal abstract bool IsCallerLineNumber { get; } internal abstract bool IsCallerMemberName { get; } protected sealed override int HighestPriorityUseSiteError { get { return (int)ErrorCode.ERR_BogusType; } } public sealed override bool HasUnsupportedMetadata { get { DiagnosticInfo info = null; DeriveUseSiteDiagnosticFromParameter(ref info, this); return (object)info != null && info.Code == (int)ErrorCode.ERR_BogusType; } } #region IParameterSymbol Members ITypeSymbol IParameterSymbol.Type { get { return this.Type; } } ImmutableArray IParameterSymbol.CustomModifiers { get { return this.CustomModifiers; } } ImmutableArray IParameterSymbol.RefCustomModifiers { get { return this.RefCustomModifiers; } } IParameterSymbol IParameterSymbol.OriginalDefinition { get { return this.OriginalDefinition; } } #endregion #region ISymbol Members public override void Accept(SymbolVisitor visitor) { visitor.VisitParameter(this); } public override TResult Accept(SymbolVisitor visitor) { return visitor.VisitParameter(this); } #endregion } }