// 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.Collections.Generic;
using Nova.Rendering;
namespace Nova.CodeDOM
{
/// <summary>
/// Represents a reference to an <see cref="Alias"/>, which can in turn refer to a <see cref="NamespaceRef"/>
/// or a <see cref="TypeRef"/> (or an <see cref="UnresolvedRef"/>).
/// </summary>
/// <remarks>
/// <see cref="AliasRef"/> subclasses <see cref="TypeRef"/> so that it can have array ranks just like a <see cref="TypeRef"/>
/// if it's a type alias. The aliased type can be an instance of a generic type (with type arguments), but the <see cref="AliasRef"/>
/// itself can't have any type arguments. In such a case, the HasTypeArguments and TypeArguments
/// properties will return the values of the aliased type, so that the AliasRef may be used synonymously
/// with the generic aliased type (but the type arguments will not be displayed on the AliasRef).
/// An AliasRef can have array ranks regardless of whether or not the aliased type has any.
/// </remarks>
public class AliasRef : TypeRef
{
#region /* CONSTRUCTORS */
/// <summary>
/// Create an <see cref="AliasRef"/> from an <see cref="Alias"/>.
/// </summary>
public AliasRef(Alias aliasDecl, bool isFirstOnLine)
: base(aliasDecl, isFirstOnLine)
{ }
/// <summary>
/// Create an <see cref="AliasRef"/> from an <see cref="Alias"/>.
/// </summary>
public AliasRef(Alias aliasDecl)
: base(aliasDecl, false)
{ }
/// <summary>
/// Create an <see cref="AliasRef"/> from an <see cref="Alias"/>.
/// </summary>
public AliasRef(Alias aliasDecl, bool isFirstOnLine, List<int> arrayRanks)
: base(aliasDecl, isFirstOnLine, null, arrayRanks)
{ }
/// <summary>
/// Create an <see cref="AliasRef"/> from an <see cref="Alias"/>.
/// </summary>
public AliasRef(Alias aliasDecl, bool isFirstOnLine, params int[] arrayRanks)
: this(aliasDecl, isFirstOnLine, ((arrayRanks != null && arrayRanks.Length > 0) ? new List<int>(arrayRanks) : null))
{ }
/// <summary>
/// Create an <see cref="AliasRef"/> from an <see cref="Alias"/>.
/// </summary>
public AliasRef(Alias aliasDecl, params int[] arrayRanks)
: this(aliasDecl, false, ((arrayRanks != null && arrayRanks.Length > 0) ? new List<int>(arrayRanks) : null))
{ }
#endregion
#region /* PROPERTIES */
// NOTE: We can't just override the Reference property, and have it refer to what the alias refers
// to, because we want to treat the alias as a new type that can have array indexes, etc.
/// <summary>
/// The name of the <see cref="AliasRef"/>.
/// </summary>
public override string Name
{
get { return ((Alias)_reference).Name; }
}
/// <summary>
/// Get the referenced <see cref="Alias"/> object.
/// </summary>
public Alias Alias
{
get { return (Alias)_reference; }
}
/// <summary>
/// True if the referenced <see cref="Alias"/> is a namespace alias.
/// </summary>
public bool IsNamespace
{
get { return ((Alias)_reference).IsNamespace; }
}
/// <summary>
/// The <see cref="Namespace"/> of the referenced alias if it's a namespace alias (otherwise null).
/// </summary>
public NamespaceRef Namespace
{
get { return ((Alias)_reference).Namespace; }
}
/// <summary>
/// True if the referenced <see cref="Alias"/> is a type alias.
/// </summary>
public bool IsType
{
get { return ((Alias)_reference).IsType; }
}
/// <summary>
/// The <see cref="Type"/> of the referenced alias if it's a type alias (otherwise null).
/// </summary>
public TypeRef Type
{
get { return ((Alias)_reference).Type; }
}
/// <summary>
/// The type argument <see cref="Expression"/>s of the reference (if any).
/// </summary>
public override ChildList<Expression> TypeArguments
{
get { return (IsType ? Type.TypeArguments : null); }
}
#endregion
#region /* METHODS */
/// <summary>
/// Get the actual type reference.
/// </summary>
/// <returns>The <see cref="ITypeDecl"/> (<see cref="TypeDecl"/> or <see cref="TypeParameter"/>, but NOT <see cref="Alias"/>)
/// or <see cref="Type"/> (or null if the type is unresolved or if the <see cref="Alias"/> is to a <see cref="NamespaceRef"/>).</returns>
public override object GetReferencedType()
{
TypeRefBase typeRefBase = Type;
return (typeRefBase != null ? typeRefBase.GetReferencedType() : null);
}
/// <summary>
/// Determine if the current reference refers to the same code object as the specified reference.
/// </summary>
public override bool IsSameRef(SymbolicRef symbolicRef)
{
return (base.IsSameRef(symbolicRef) || (IsType && Type.IsSameRef(symbolicRef)) || (IsNamespace && Namespace.IsSameRef(symbolicRef)));
}
/// <summary>
/// Determine if the specified <see cref="TypeRefBase"/> refers to the same generic type, regardless of actual type arguments.
/// </summary>
public override bool IsSameGenericType(TypeRefBase typeRefBase)
{
TypeRefBase typeRef = Type;
return (typeRef != null && typeRef.IsSameGenericType(typeRefBase));
}
#endregion
#region /* RENDERING */
public override void AsTextExpression(CodeWriter writer, RenderFlags flags)
{
UpdateLineCol(writer, flags);
writer.WriteIdentifier(Name, flags);
AsTextTypeArguments(writer, _typeArguments, flags);
AsTextArrayRanks(writer, flags);
}
#endregion
}
}