// 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
}
}