Click here to Skip to main content
15,886,026 members
Articles / Programming Languages / C#

Resolving Symbolic References in a CodeDOM (Part 7)

Rate me:
Please Sign up or sign in to vote.
4.75/5 (6 votes)
2 Dec 2012CDDL12 min read 19.4K   509   14  
Resolving symbolic references in a CodeDOM.
// 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 Mono.Cecil;

using Nova.Parsing;
using Nova.Rendering;
using Nova.Resolving;

namespace Nova.CodeDOM
{
    /// <summary>
    /// Represents an alias to a <see cref="Namespace"/> or a type (<see cref="TypeDecl"/>, or <see cref="TypeDefinition"/>/<see cref="Type"/>).
    /// </summary>
    /// <remarks>
    /// An alias can only be defined at the <see cref="CodeUnit"/> or <see cref="NamespaceDecl"/> level, and it can only
    /// be used within that scope.  The syntax is "using aliasname = expression;" where the expression evaluates to either
    /// a <see cref="NamespaceRef"/> or a <see cref="TypeRef"/>.
    /// </remarks>
    public class Alias : Statement, INamedCodeObject, ITypeDecl, INamespace
    {
        #region /* FIELDS */

        protected string _name;

        /// <summary>
        /// The expression should be a <see cref="NamespaceRef"/>, <see cref="TypeRef"/>, or a <see cref="Dot"/> operator
        /// whose right-most operand evaluates to a <see cref="NamespaceRef"/> or <see cref="TypeRef"/>.  It can also be
        /// an <see cref="UnresolvedRef"/>.
        /// </summary>
        protected Expression _expression;

        #endregion

        #region /* CONSTRUCTORS */

        /// <summary>
        /// Create an <see cref="Alias"/> with the specified name to the specified <see cref="Expression"/>.
        /// </summary>
        public Alias(string name, Expression expression)
        {
            _name = name;
            Expression = expression;
        }

        #endregion

        #region /* PROPERTIES */

        /// <summary>
        /// The name of the <see cref="Alias"/>.
        /// </summary>
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// The descriptive category of the code object.
        /// </summary>
        public string Category
        {
            get
            {
                Expression expression = _expression.SkipPrefixes();
                string category;
                if (expression is NamespaceRef)
                    category = "namespace";
                else if (expression is TypeRef)
                    category = "type";
                else
                    category = "unknown";
                return category + " alias";
            }
        }

        /// <summary>
        /// The aliased <see cref="Expression"/>.
        /// </summary>
        public Expression Expression
        {
            get { return _expression; }
            set { SetField(ref _expression, value, true); }
        }

        /// <summary>
        /// The keyword associated with the <see cref="Statement"/>.
        /// </summary>
        public override string Keyword
        {
            get { return ParseToken; }
        }

        /// <summary>
        /// True if this is a namespace alias.
        /// </summary>
        public bool IsNamespace
        {
            get { return _expression.SkipPrefixes() is NamespaceRef; }
        }

        /// <summary>
        /// The namespace that this alias refers to (null if not a namespace alias).
        /// </summary>
        public NamespaceRef Namespace
        {
            get { return _expression.SkipPrefixes() as NamespaceRef; }
        }

        /// <summary>
        /// True if this is a type alias.
        /// </summary>
        public bool IsType
        {
            get { return _expression.SkipPrefixes() is TypeRef; }
        }

        /// <summary>
        /// The type that this alias refers to (null if not a type alias).
        /// </summary>
        public TypeRef Type
        {
            get { return _expression.EvaluateType() as TypeRef; }
        }

        #region /* ITYPEDECL PROPERTIES */

        /// <summary>
        /// Get the number of <see cref="TypeParameter"/>s in the aliased type (if any).
        /// </summary>
        public int TypeParameterCount
        {
            get
            {
                TypeRef typeRefBase = Type;
                return (typeRefBase != null ? typeRefBase.TypeArgumentCount : 0);
            }
        }

        /// <summary>
        /// True if the aliased type is abstract.
        /// </summary>
        public bool IsAbstract
        {
            get
            {
                TypeRef typeRef = Type;
                return (typeRef != null && typeRef.IsAbstract);
            }
        }

        /// <summary>
        /// True if the aliased type is a class.
        /// </summary>
        public bool IsClass
        {
            get
            {
                TypeRef typeRef = Type;
                return (typeRef != null && typeRef.IsClass);
            }
        }

        /// <summary>
        /// True if the aliased type is a delegate type.
        /// </summary>
        public bool IsDelegateType
        {
            get
            {
                TypeRef typeRef = Type;
                return (typeRef != null && typeRef.IsDelegateType);
            }
        }

        /// <summary>
        /// True if the aliased type is an enum.
        /// </summary>
        public bool IsEnum
        {
            get
            {
                TypeRef typeRef = Type;
                return (typeRef != null && typeRef.IsEnum);
            }
        }

        /// <summary>
        /// Always <c>false</c>.
        /// </summary>
        public bool IsGenericParameter
        {
            get { return false; }
        }

        /// <summary>
        /// True if the aliased type is a generic type.
        /// </summary>
        public bool IsGenericType
        {
            get
            {
                TypeRef typeRef = Type;
                return (typeRef != null && typeRef.IsGenericType);
            }
        }

        /// <summary>
        /// True if the aliased type is an interface.
        /// </summary>
        public bool IsInterface
        {
            get
            {
                TypeRef typeRef = Type;
                return (typeRef != null && typeRef.IsInterface);
            }
        }

        /// <summary>
        /// True if the aliased type is a nested type.
        /// </summary>
        public bool IsNested
        {
            get
            {
                TypeRef typeRef = Type;
                return (typeRef != null && typeRef.IsNested);
            }
        }

        /// <summary>
        /// True if the aliased type is a nullable type.
        /// </summary>
        public bool IsNullableType
        {
            get
            {
                TypeRef typeRef = Type;
                return (typeRef != null && typeRef.IsNullableType);
            }
        }

        /// <summary>
        /// True if the aliased type is a partial type.
        /// </summary>
        public bool IsPartial
        {
            get
            {
                TypeRef typeRef = Type;
                return (typeRef != null && typeRef.IsPartial);
            }
        }

        /// <summary>
        /// True if the aliased type is a struct.
        /// </summary>
        public bool IsStruct
        {
            get
            {
                TypeRef typeRef = Type;
                return (typeRef != null && typeRef.IsUserStruct);
            }
        }

        /// <summary>
        /// True if the aliased type is a value type.
        /// </summary>
        public bool IsValueType
        {
            get
            {
                TypeRef typeRef = Type;
                return (typeRef != null && typeRef.IsValueType);
            }
        }

        #endregion

        #region /* INAMESPACE PROPERTIES */

        /// <summary>
        /// The full name of the referenced <see cref="Namespace"/>, including any parent namespaces.
        /// </summary>
        public string FullName
        {
            get
            {
                NamespaceRef namespaceRef = Namespace;
                return (namespaceRef != null ? namespaceRef.FullName : null);
            }
        }

        /// <summary>
        /// The dictionary of child objects in the referenced <see cref="Namespace"/>.
        /// </summary>
        public NamespaceTypeDictionary Children
        {
            get
            {
                NamespaceRef namespaceRef = Namespace;
                return (namespaceRef != null ? namespaceRef.Children : null);
            }
        }

        /// <summary>
        /// Determines if the referenced <see cref="Namespace"/> is root-level (global or extern alias).
        /// </summary>
        public bool IsRootLevel
        {
            get
            {
                NamespaceRef namespaceRef = Namespace;
                return (namespaceRef != null && namespaceRef.IsRootLevel);
            }
        }

        /// <summary>
        /// Determines if the referenced <see cref="Namespace"/> is the project-global namespace.
        /// </summary>
        public bool IsGlobal
        {
            get
            {
                NamespaceRef namespaceRef = Namespace;
                return (namespaceRef != null && namespaceRef.IsGlobal);
            }
        }

        /// <summary>
        /// True if the referenced <see cref="Namespace"/> has <see cref="NamespaceDecl"/> declarations in the current
        /// project, otherwise false (meaning items in the namespace exist only in imported assemblies and projects).
        /// </summary>
        public bool HasDeclarationsInProject
        {
            get
            {
                NamespaceRef namespaceRef = Namespace;
                return (namespaceRef != null && namespaceRef.HasDeclarationsInProject);
            }
        }

        #endregion

        #endregion

        #region /* METHODS */

        /// <summary>
        /// Create a reference to the <see cref="Alias"/>.
        /// </summary>
        /// <param name="isFirstOnLine">True if the reference should be displayed on a new line.</param>
        /// <returns>An <see cref="AliasRef"/>.</returns>
        public override SymbolicRef CreateRef(bool isFirstOnLine)
        {
            return new AliasRef(this, isFirstOnLine);
        }

        /// <summary>
        /// Create a reference to the <see cref="Alias"/>.
        /// </summary>
        /// <returns>An <see cref="AliasRef"/>.</returns>
        public TypeRef CreateRef(bool isFirstOnLine, ChildList<Expression> typeArguments, List<int> arrayRanks)
        {
            // Ignore any type arguments - an AliasRef can't have any
            return new AliasRef(this, isFirstOnLine, arrayRanks);
        }

        /// <summary>
        /// Create a reference to the <see cref="Alias"/>.
        /// </summary>
        /// <returns>An <see cref="AliasRef"/>.</returns>
        public TypeRef CreateRef(bool isFirstOnLine, ChildList<Expression> typeArguments)
        {
            // Ignore any type arguments - an AliasRef can't have any
            return new AliasRef(this, isFirstOnLine);
        }

        /// <summary>
        /// Create a reference to the <see cref="Alias"/>.
        /// </summary>
        /// <returns>An <see cref="AliasRef"/>.</returns>
        public TypeRef CreateRef(ChildList<Expression> typeArguments, List<int> arrayRanks)
        {
            // Ignore any type arguments - an AliasRef can't have any
            return new AliasRef(this, false, arrayRanks);
        }

        /// <summary>
        /// Create a reference to the <see cref="Alias"/>.
        /// </summary>
        /// <returns>An <see cref="AliasRef"/>.</returns>
        public TypeRef CreateRef(ChildList<Expression> typeArguments)
        {
            // Ignore any type arguments - an AliasRef can't have any
            return new AliasRef(this, false);
        }

        /// <summary>
        /// Create an array reference to this <see cref="Alias"/>.
        /// </summary>
        /// <returns>An <see cref="AliasRef"/>.</returns>
        public TypeRef CreateArrayRef(bool isFirstOnLine, params int[] ranks)
        {
            return new AliasRef(this, isFirstOnLine, ranks);
        }

        /// <summary>
        /// Create an array reference to this <see cref="Alias"/>.
        /// </summary>
        /// <returns>An <see cref="AliasRef"/>.</returns>
        public TypeRef CreateArrayRef(params int[] ranks)
        {
            return new AliasRef(this, false, ranks);
        }

        /// <summary>
        /// Create a nullable reference to this <see cref="Alias"/>.
        /// </summary>
        /// <returns>A <see cref="TypeRef"/>.</returns>
        public TypeRef CreateNullableRef(bool isFirstOnLine)
        {
            return TypeRef.CreateNullable(CreateRef(), isFirstOnLine);
        }

        /// <summary>
        /// Create a nullable reference to this <see cref="Alias"/>.
        /// </summary>
        /// <returns>A <see cref="TypeRef"/>.</returns>
        public TypeRef CreateNullableRef()
        {
            return TypeRef.CreateNullable(CreateRef());
        }

        #region /* ITYPEDECL METHODS */

        /// <summary>
        /// Get the base type of the aliased type.
        /// </summary>
        public TypeRef GetBaseType()
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetBaseType() as TypeRef : null);
        }

        /// <summary>
        /// Get the non-static constructor of the aliased type with the specified parameters.
        /// </summary>
        public ConstructorRef GetConstructor(params TypeRefBase[] parameterTypes)
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetConstructor(parameterTypes) : null);
        }

        /// <summary>
        /// Get all non-static constructors of the aliased type.
        /// </summary>
        public NamedCodeObjectGroup GetConstructors(bool currentPartOnly)
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetConstructors(currentPartOnly) : null);
        }

        /// <summary>
        /// Get all non-static constructors of the aliased type.
        /// </summary>
        public NamedCodeObjectGroup GetConstructors()
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetConstructors(false) : null);
        }

        /// <summary>
        /// Get the method of the aliased type with the specified name and parameter types.
        /// </summary>
        public MethodRef GetMethod(string name, params TypeRefBase[] parameterTypes)
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetMethod(name, parameterTypes) : null);
        }

        /// <summary>
        /// Get all methods of the aliased type with the specified name.
        /// </summary>
        public void GetMethods(string name, bool searchBaseClasses, NamedCodeObjectGroup results)
        {
            TypeRef typeRef = Type;
            if (typeRef != null)
                typeRef.GetMethods(name, searchBaseClasses, results);
        }

        /// <summary>
        /// Get all methods with the specified name.
        /// </summary>
        /// <param name="name">The method name.</param>
        /// <param name="searchBaseClasses">Pass <c>false</c> to NOT search base classes.</param>
        public List<MethodRef> GetMethods(string name, bool searchBaseClasses)
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetMethods(name, searchBaseClasses) : null);
        }

        /// <summary>
        /// Get all methods with the specified name.
        /// </summary>
        /// <param name="name">The method name.</param>
        public List<MethodRef> GetMethods(string name)
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetMethods(name, false) : null);
        }

        /// <summary>
        /// Get the property of the aliased type with the specified name.
        /// </summary>
        public PropertyRef GetProperty(string name)
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetProperty(name) : null);
        }

        /// <summary>
        /// Get the field of the aliased type with the specified name.
        /// </summary>
        public FieldRef GetField(string name)
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetField(name) : null);
        }

        /// <summary>
        /// Get the nested type of the aliased type with the specified name.
        /// </summary>
        public TypeRef GetNestedType(string name)
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetNestedType(name) : null);
        }

        /// <summary>
        /// Get the delegate parameters (if any) of the aliased type.
        /// </summary>
        public ICollection GetDelegateParameters()
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetDelegateParameters() : null);
        }

        /// <summary>
        /// Get the delegate return type (if any) of the aliased type.
        /// </summary>
        public TypeRefBase GetDelegateReturnType()
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.GetDelegateReturnType() : null);
        }

        /// <summary>
        /// Determine if the aliased type is assignable from the specified type.
        /// </summary>
        public bool IsAssignableFrom(TypeRef fromTypeRef)
        {
            TypeRef typeRef = Type;
            return (typeRef != null && typeRef.IsAssignableFrom(fromTypeRef));
        }

        /// <summary>
        /// Determine if the aliased type is a subclass of the specified type.
        /// </summary>
        public bool IsSubclassOf(TypeRef classTypeRef)
        {
            TypeRef typeRef = Type;
            return (typeRef != null && typeRef.IsSubclassOf(classTypeRef));
        }

        /// <summary>
        /// Determine if the aliased type implements the specified interface type.
        /// </summary>
        public bool IsImplementationOf(TypeRef interfaceTypeRef)
        {
            TypeRef typeRef = Type;
            return (typeRef != null && typeRef.IsImplementationOf(interfaceTypeRef));
        }

        #endregion

        #region /* INAMESPACE METHODS */

        /// <summary>
        /// Add a child <see cref="Namespace"/> to the referenced <see cref="Namespace"/>.
        /// </summary>
        public void Add(Namespace @namespace)
        {
            NamespaceRef namespaceRef = Namespace;
            if (namespaceRef != null)
                namespaceRef.Add(@namespace);
        }

        /// <summary>
        /// Add a <see cref="TypeDecl"/> to the referenced <see cref="Namespace"/>.
        /// </summary>
        public void Add(TypeDecl typeDecl)
        {
            NamespaceRef namespaceRef = Namespace;
            if (namespaceRef != null)
                namespaceRef.Add(typeDecl);
        }

        /// <summary>
        /// Add a <see cref="TypeDefinition"/> to the referenced <see cref="Namespace"/>.
        /// </summary>
        public void Add(TypeDefinition typeDefinition)
        {
            NamespaceRef namespaceRef = Namespace;
            if (namespaceRef != null)
                namespaceRef.Add(typeDefinition);
        }

        /// <summary>
        /// Add a <see cref="Type"/> to the referenced <see cref="Namespace"/>.
        /// </summary>
        public void Add(Type type)
        {
            NamespaceRef namespaceRef = Namespace;
            if (namespaceRef != null)
                namespaceRef.Add(type);
        }

        /// <summary>
        /// Remove a child <see cref="Namespace"/> from the referenced <see cref="Namespace"/>.
        /// </summary>
        public void Remove(Namespace @namespace)
        {
            NamespaceRef namespaceRef = Namespace;
            if (namespaceRef != null)
                namespaceRef.Remove(@namespace);
        }

        /// <summary>
        /// Remove a <see cref="TypeDecl"/> from the referenced <see cref="Namespace"/>.
        /// </summary>
        public void Remove(TypeDecl typeDecl)
        {
            NamespaceRef namespaceRef = Namespace;
            if (namespaceRef != null)
                namespaceRef.Remove(typeDecl);
        }

        /// <summary>
        /// Remove a <see cref="TypeDefinition"/> from the referenced <see cref="Namespace"/>.
        /// </summary>
        public void Remove(TypeDefinition typeDefinition)
        {
            NamespaceRef namespaceRef = Namespace;
            if (namespaceRef != null)
                namespaceRef.Remove(typeDefinition);
        }

        /// <summary>
        /// Remove a <see cref="Type"/> from the referenced <see cref="Namespace"/>.
        /// </summary>
        public void Remove(Type type)
        {
            NamespaceRef namespaceRef = Namespace;
            if (namespaceRef != null)
                namespaceRef.Remove(type);
        }

        /// <summary>
        /// Remove all items from the referenced <see cref="Namespace"/>.
        /// </summary>
        public void RemoveAll()
        {
            NamespaceRef namespaceRef = Namespace;
            if (namespaceRef != null)
                namespaceRef.RemoveAll();
        }

        /// <summary>
        /// Find or create a child <see cref="Namespace"/>, including any missing parent namespaces.
        /// </summary>
        public Namespace FindOrCreateChildNamespace(string namespaceName)
        {
            NamespaceRef namespaceRef = Namespace;
            return (namespaceRef != null ? namespaceRef.FindOrCreateChildNamespace(namespaceName) : null);
        }

        /// <summary>
        /// Parse the specified name into a child <see cref="NamespaceRef"/> or <see cref="TypeRef"/> on the referenced namespace,
        /// or a <see cref="Dot"/> expression that evaluates to one.
        /// </summary>
        public Expression ParseName(string name)
        {
            NamespaceRef namespaceRef = Namespace;
            return (namespaceRef != null ? namespaceRef.ParseName(name) : null);
        }

        #endregion

        /// <summary>
        /// Find a child <see cref="Namespace"/>, <see cref="TypeDecl"/>, or <see cref="TypeDefinition"/>/<see cref="Type"/> with
        /// the specified name.
        /// </summary>
        /// <returns>The child object if found, otherwise null.</returns>
        public object Find(string name)
        {
            if (IsNamespace)
                return Namespace.Find(name);
            if (IsType)
                return Type.GetNestedType(name).Reference;
            return null;
        }

        /// <summary>
        /// Add the <see cref="CodeObject"/> to the specified dictionary.
        /// </summary>
        public virtual void AddToDictionary(NamedCodeObjectDictionary dictionary)
        {
            dictionary.Add(Name, this);
        }

        /// <summary>
        /// Remove the <see cref="CodeObject"/> from the specified dictionary.
        /// </summary>
        public virtual void RemoveFromDictionary(NamedCodeObjectDictionary dictionary)
        {
            dictionary.Remove(Name, this);
        }

        /// <summary>
        /// Deep-clone the code object.
        /// </summary>
        public override CodeObject Clone()
        {
            Alias clone = (Alias)base.Clone();
            clone.CloneField(ref clone._expression, _expression);
            return clone;
        }

        /// <summary>
        /// Get the full name of the <see cref="INamedCodeObject"/>, including any namespace name.
        /// </summary>
        public string GetFullName(bool descriptive)
        {
            return _name;
        }

        /// <summary>
        /// Get the full name of the <see cref="INamedCodeObject"/>, including any namespace name.
        /// </summary>
        public string GetFullName()
        {
            return _name;
        }

        #endregion

        #region /* PARSING */

        /// <summary>
        /// The token used to parse the code object.
        /// </summary>
        public const string ParseToken = "using";

        /// <summary>
        /// The token used to parse between the alias name and expression.
        /// </summary>
        public const string ParseTokenSeparator = "=";

        internal static void AddParsePoints()
        {
            // Use a parse-priority of 0 (UsingDirective uses 100, Using uses 200)
            Parser.AddParsePoint(ParseToken, Parse, typeof(NamespaceDecl));
        }

        /// <summary>
        /// Parse an <see cref="Alias"/>.
        /// </summary>
        public static Alias Parse(Parser parser, CodeObject parent, ParseFlags flags)
        {
            // Continue only if it looks like an alias assignment instead of a UsingDirective
            if (parser.PeekNextTokenText() == ParseTokenSeparator || parser.PeekNextTokenText() == ParseTokenSeparator)
                return new Alias(parser, parent);
            return null;
        }

        protected Alias(Parser parser, CodeObject parent)
            : base(parser, parent)
        {
            parser.NextToken();                  // Move past 'using'
            _name = parser.GetIdentifierText();  // Parse the name
            parser.NextToken();                  // Move past '='
            SetField(ref _expression, Expression.Parse(parser, this, true), false);
            ParseTerminator(parser);
        }

        #endregion

        #region /* RESOLVING */

        /// <summary>
        /// Resolve all child symbolic references, using the specified <see cref="ResolveCategory"/> and <see cref="ResolveFlags"/>.
        /// </summary>
        public override CodeObject Resolve(ResolveCategory resolveCategory, ResolveFlags flags)
        {
            _expression = (Expression)_expression.Resolve(ResolveCategory.NamespaceOrType, flags);
            return this;
        }

        /// <summary>
        /// Resolve child code objects that match the specified name.
        /// </summary>
        public void ResolveRef(string name, Resolver resolver)
        {
            Expression expression = _expression.SkipPrefixes();
            if (expression is NamespaceRef)
                ((NamespaceRef)expression).Namespace.ResolveRef(name, resolver, false);
            else if (expression is TypeRef)
                ((TypeRef)expression).ResolveRef(name, resolver);
        }

        /// <summary>
        /// Resolve indexers.
        /// </summary>
        public void ResolveIndexerRef(Resolver resolver)
        {
            TypeRef typeRef = Type;
            if (typeRef != null)
                typeRef.ResolveIndexerRef(resolver);
        }

        /// <summary>
        /// Returns true if the code object is an <see cref="UnresolvedRef"/> or has any <see cref="UnresolvedRef"/> children.
        /// </summary>
        public override bool HasUnresolvedRef()
        {
            if (_expression != null && _expression.HasUnresolvedRef())
                return true;
            return base.HasUnresolvedRef();
        }

        /// <summary>
        /// Find a type argument in a base class for the specified type parameter.
        /// </summary>
        public TypeRefBase FindTypeArgumentInBase(TypeParameterRef typeParameterRef)
        {
            TypeRef typeRef = Type;
            return (typeRef != null ? typeRef.FindTypeArgumentInBase(typeParameterRef) : null);
        }

        #endregion

        #region /* FORMATTING */

        /// <summary>
        /// True if the <see cref="Statement"/> has parens around its argument.
        /// </summary>
        public override bool HasArgumentParens
        {
            get { return false; }
        }

        /// <summary>
        /// True if the <see cref="Statement"/> has a terminator character by default.
        /// </summary>
        public override bool HasTerminatorDefault
        {
            get { return true; }
        }

        /// <summary>
        /// Determine a default of 1 or 2 newlines when adding items to a <see cref="Block"/>.
        /// </summary>
        public override int DefaultNewLines(CodeObject previous)
        {
            // Default to a preceeding blank line if the object has first-on-line annotations
            if (HasFirstOnLineAnnotations)
                return 2;

            // Default to a preceeding blank line if the previous object was another alias directive
            // with a different root namespace, otherwise use a single newline.
            if (previous is Alias)
            {
                SymbolicRef symbolicRef = ((Alias)previous).Expression.FirstPrefix() as SymbolicRef;
                if (symbolicRef != null && !symbolicRef.IsSameRef(Expression.FirstPrefix() as SymbolicRef))
                    return 2;
                return 1;
            }

            // Default to no preceeding blank line if the previous object was a using directive with
            // the same root namespace, otherwise use a preceeding blank line.
            if (previous is UsingDirective)
            {
                SymbolicRef symbolicRef = ((UsingDirective)previous).Namespace.FirstPrefix() as SymbolicRef;
                if (symbolicRef != null && symbolicRef.IsSameRef(Expression.FirstPrefix() as SymbolicRef))
                    return 1;
                return 2;
            }

            // Default to a preceeding blank line if the object is a different type than the previous one
            if (previous.GetType() != GetType())
                return 2;
            return 1;
        }

        /// <summary>
        /// Determines if the code object only requires a single line for display.
        /// </summary>
        public override bool IsSingleLine
        {
            get { return (base.IsSingleLine && (_expression == null || (!_expression.IsFirstOnLine && _expression.IsSingleLine))); }
            set
            {
                base.IsSingleLine = value;
                if (value && _expression != null)
                {
                    _expression.IsFirstOnLine = false;
                    _expression.IsSingleLine = true;
                }
            }
        }

        #endregion

        #region /* RENDERING */

        protected override void AsTextArgument(CodeWriter writer, RenderFlags flags)
        {
            writer.WriteIdentifier(_name, flags);
            writer.Write(" " + ParseTokenSeparator);
            if (_expression != null)
                _expression.AsText(writer, flags | RenderFlags.PrefixSpace);
        }

        #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