// 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;
using Nova.Resolving;
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 /* 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)
{
// Unresolve instead of resolving if the flag is specified
TypeRefBase typeRefBase;
if (flags.HasFlag(ResolveFlags.Unresolve))
typeRefBase = new UnresolvedRef(this, resolveCategory, false);
else
typeRefBase = this;
// Ignore any TypeArguments - don't attempt to resolve or unresolve, since they're actually
// part of the Alias definition, not the AliasRef.
return typeRefBase;
}
/// <summary>
/// Resolve child code objects that match the specified name.
/// </summary>
public override void ResolveRef(string name, Resolver resolver)
{
if (HasArrayRanks)
ResolveRef(ArrayRef, name, resolver);
else
((Alias)_reference).ResolveRef(name, 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()
{
return ((Alias)_reference).HasUnresolvedRef();
}
// Don't override EvaluateType() - we want to treat a type alias like a new type, displaying it as
// the new type, but making it synonymous with the aliased type.
/// <summary>
/// Find a type argument for the specified type parameter.
/// </summary>
public override TypeRefBase FindTypeArgument(TypeParameterRef typeParameterRef, CodeObject originatingChild)
{
TypeRefBase typeRefBase = Type;
return (typeRefBase != null ? typeRefBase.FindTypeArgument(typeParameterRef, originatingChild) : null);
}
#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
}
}