Click here to Skip to main content
15,898,010 members
Articles / Programming Languages / C#

Creating a CodeDOM: Modeling the Semantics of Code (Part 2)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (17 votes)
9 Nov 2012CDDL24 min read 41.3K   757   33  
Creating a CodeDOM for C#
// 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
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)


Written By
Software Developer (Senior)
United States United States
I've been writing software since the late 70's, currently focusing mainly on C#.NET. I also like to travel around the world, and I own a Chocolate Factory (sadly, none of my employees are oompa loompas).

Comments and Discussions