// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Nova.Rendering;
using Nova.Utilities;
namespace Nova.CodeDOM
{
/// <summary>
/// Represents a reference to a <see cref="ParameterDecl"/> or a <see cref="ParameterInfo"/>.
/// Similar to a <see cref="LocalRef"/>, but represents a parameter passed to the current method.
/// </summary>
/// <remarks>
/// Although references to <see cref="ParameterInfo"/>s aren't common, they might occur in some special circumstances.
/// </remarks>
public class ParameterRef : VariableRef
{
#region /* CONSTRUCTORS */
/// <summary>
/// Create a <see cref="ParameterRef"/>.
/// </summary>
public ParameterRef(ParameterDecl parameterDecl, bool isFirstOnLine)
: base(parameterDecl, isFirstOnLine)
{ }
/// <summary>
/// Create a <see cref="ParameterRef"/>.
/// </summary>
public ParameterRef(ParameterDecl parameterDecl)
: base(parameterDecl, false)
{ }
/// <summary>
/// Create a <see cref="ParameterRef"/>.
/// </summary>
public ParameterRef(ParameterInfo parameterInfo, bool isFirstOnLine)
: base(parameterInfo, isFirstOnLine)
{ }
/// <summary>
/// Create a <see cref="ParameterRef"/>.
/// </summary>
public ParameterRef(ParameterInfo parameterInfo)
: base(parameterInfo, false)
{ }
#endregion
#region /* PROPERTIES */
/// <summary>
/// The name of the <see cref="SymbolicRef"/>.
/// </summary>
public override string Name
{
get
{
if (_reference is ParameterDecl)
return ((ParameterDecl)_reference).Name;
return ((ParameterInfo)_reference).Name;
}
}
/// <summary>
/// True if the referenced parameter is a 'params' parameter.
/// </summary>
public bool IsParams
{
get
{
if (_reference is ParameterDecl)
return ((ParameterDecl)_reference).IsParams;
return ParameterInfoUtil.IsParams((ParameterInfo)_reference);
}
}
/// <summary>
/// True if the referenced parameter is a 'ref' parameter.
/// </summary>
public bool IsRef
{
get
{
if (_reference is ParameterDecl)
return ((ParameterDecl)_reference).IsRef;
return ParameterInfoUtil.IsRef((ParameterInfo)_reference);
}
}
/// <summary>
/// True if the referenced parameter is an 'out' parameter.
/// </summary>
public bool IsOut
{
get
{
if (_reference is ParameterDecl)
return ((ParameterDecl)_reference).IsOut;
return ParameterInfoUtil.IsOut((ParameterInfo)_reference);
}
}
#endregion
#region /* STATIC METHODS */
/// <summary>
/// Find the parameter on the specified <see cref="MethodDeclBase"/> with the specified name.
/// </summary>
/// <returns>A <see cref="ParameterRef"/> to the parameter, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(MethodDeclBase methodDeclBase, string name, bool isFirstOnLine)
{
if (methodDeclBase != null)
{
ParameterRef parameterRef = methodDeclBase.GetParameter(name);
if (parameterRef != null)
{
parameterRef.IsFirstOnLine = isFirstOnLine;
return parameterRef;
}
}
return new UnresolvedRef(name, isFirstOnLine);
}
/// <summary>
/// Find the parameter on the specified <see cref="MethodDeclBase"/> with the specified name.
/// </summary>
/// <returns>A <see cref="ParameterRef"/> to the parameter, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(MethodDeclBase methodDeclBase, string name)
{
return Find(methodDeclBase, name, false);
}
/// <summary>
/// Find the parameter of the specified <see cref="MethodInfo"/> with the specified name.
/// </summary>
/// <returns>A <see cref="ParameterRef"/> to the parameter, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(MethodInfo methodInfo, string name, bool isFirstOnLine)
{
if (methodInfo != null)
{
ParameterInfo parameterInfo = MethodInfoUtil.GetParameter(methodInfo, name);
if (parameterInfo != null)
return new ParameterRef(parameterInfo, isFirstOnLine);
}
return new UnresolvedRef(name, isFirstOnLine);
}
/// <summary>
/// Find the parameter of the specified <see cref="MethodInfo"/> with the specified name.
/// </summary>
/// <returns>A <see cref="ParameterRef"/> to the parameter, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(MethodInfo methodInfo, string name)
{
return Find(methodInfo, name, false);
}
/// <summary>
/// Find the parameter on the specified <see cref="TypeRefBase"/> with the specified name.
/// </summary>
/// <returns>A <see cref="ParameterRef"/> to the parameter, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(TypeRefBase typeRefBase, string name, bool isFirstOnLine)
{
if (typeRefBase is MethodRef)
{
ParameterRef parameterRef = ((MethodRef)typeRefBase).GetParameter(name);
if (parameterRef != null)
{
parameterRef.IsFirstOnLine = isFirstOnLine;
return parameterRef;
}
}
return new UnresolvedRef(name, isFirstOnLine);
}
/// <summary>
/// Find the parameter on the specified <see cref="TypeRefBase"/> with the specified name.
/// </summary>
/// <returns>A <see cref="ParameterRef"/> to the parameter, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(TypeRefBase typeRefBase, string name)
{
return Find(typeRefBase, name, false);
}
#endregion
#region /* METHODS */
/// <summary>
/// Get the <see cref="ParameterModifier"/> for the specified <see cref="ParameterInfo"/>.
/// </summary>
public static ParameterModifier GetParameterModifier(ParameterInfo parameterInfo)
{
ParameterModifier modifier = ParameterModifier.None;
if (ParameterInfoUtil.IsParams(parameterInfo))
modifier = ParameterModifier.Params;
else if (ParameterInfoUtil.IsRef(parameterInfo))
modifier = ParameterModifier.Ref;
else if (ParameterInfoUtil.IsOut(parameterInfo))
modifier = ParameterModifier.Out;
return modifier;
}
/// <summary>
/// Determine if the parameter in the collection with the specified index is a 'params' parameter.
/// </summary>
public static bool ParameterIsParams(ICollection parameters, int index)
{
bool isParams;
if (parameters is List<ParameterDecl>)
isParams = (((List<ParameterDecl>)parameters)[index].IsParams);
else //if (parameters is ParameterInfo[])
isParams = ParameterInfoUtil.IsParams(((ParameterInfo[])parameters)[index]);
return isParams;
}
/// <summary>
/// Get the type of the parameter in the collection with the specified index, using the specified parent expression to evaluate any type argument types.
/// </summary>
public static TypeRefBase GetParameterType(ICollection parameters, int index, Expression parentExpression)
{
TypeRefBase parameterTypeRef;
if (parameters is List<ParameterDecl>)
parameterTypeRef = ((List<ParameterDecl>)parameters)[index].Type.SkipPrefixes() as TypeRefBase;
else //if (parameters is ParameterInfo[])
parameterTypeRef = TypeRef.Create(((ParameterInfo[])parameters)[index].ParameterType);
return parameterTypeRef;
}
#endregion
#region /* RENDERING */
public static void AsTextParameterInfo(CodeWriter writer, ParameterInfo parameterInfo, RenderFlags flags)
{
RenderFlags passFlags = flags & ~RenderFlags.Description;
Attribute.AsTextAttributes(writer, parameterInfo);
ParameterModifier modifier = GetParameterModifier(parameterInfo);
if (modifier != ParameterModifier.None)
writer.Write(ParameterDecl.ParameterModifierToString(modifier) + " ");
Type parameterType = parameterInfo.ParameterType;
if (parameterType.IsByRef)
{
// Dereference (remove the trailing '&') if it's a reference type
parameterType = parameterType.GetElementType();
}
TypeRefBase.AsTextType(writer, parameterType, passFlags);
writer.Write(" " + parameterInfo.Name);
}
#endregion
}
}