// 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;
using System.Collections.Generic;
using Nova.Rendering;
namespace Nova.CodeDOM
{
/// <summary>
/// Represents a type parameter of a generic type or method declaration.
/// </summary>
public class TypeParameter : CodeObject, ITypeDecl
{
#region /* FIELDS */
protected string _name;
#endregion
#region /* CONSTRUCTORS */
/// <summary>
/// Create a <see cref="TypeParameter"/> with the specified name.
/// </summary>
public TypeParameter(string name)
{
_name = name;
}
#endregion
#region /* PROPERTIES */
/// <summary>
/// The name of the <see cref="TypeParameter"/>.
/// </summary>
public string Name
{
get { return _name; }
set { _name = value; }
}
/// <summary>
/// The descriptive category of the code object.
/// </summary>
public string Category
{
get { return "type parameter"; }
}
/// <summary>
/// Always <c>0</c>.
/// </summary>
public int TypeParameterCount
{
get { return 0; }
}
/// <summary>
/// Always <c>false</c>.
/// </summary>
public bool IsAbstract
{
get { return false; }
}
/// <summary>
/// Always <c>false</c>.
/// </summary>
public bool IsClass
{
get { return false; }
}
/// <summary>
/// True if the <see cref="TypeParameter"/> has a delegate type.
/// </summary>
public bool IsDelegateType
{
get { return GetTypeConstraint().IsDelegateType; }
}
/// <summary>
/// Always <c>false</c>.
/// </summary>
public bool IsEnum
{
get { return false; }
}
/// <summary>
/// Always <c>true</c>.
/// </summary>
public bool IsGenericParameter
{
get { return true; }
}
/// <summary>
/// Always <c>false</c>.
/// </summary>
public bool IsGenericType
{
get { return false; }
}
/// <summary>
/// Always <c>false</c>.
/// </summary>
public bool IsInterface
{
get { return false; }
}
/// <summary>
/// Always <c>true</c>.
/// </summary>
public bool IsNested
{
// TypeParameters are considered nested types (including in .NET reflection)
get { return true; }
}
/// <summary>
/// Always <c>false</c>.
/// </summary>
public bool IsNullableType
{
get { return false; }
}
/// <summary>
/// Always <c>false</c>.
/// </summary>
public bool IsPartial
{
get { return false; }
}
/// <summary>
/// Always <c>false</c>.
/// </summary>
public bool IsStruct
{
get { return false; }
}
/// <summary>
/// Always <c>false</c>.
/// </summary>
public bool IsValueType
{
get { return false; }
}
#endregion
#region /* METHODS */
/// <summary>
/// Create a reference to the <see cref="TypeParameter"/>.
/// </summary>
/// <param name="isFirstOnLine">True if the reference should be displayed on a new line.</param>
/// <returns>A <see cref="TypeParameterRef"/>.</returns>
public override SymbolicRef CreateRef(bool isFirstOnLine)
{
return new TypeParameterRef(this, isFirstOnLine);
}
/// <summary>
/// Create a reference to the <see cref="TypeParameter"/>.
/// </summary>
/// <returns>A <see cref="TypeParameterRef"/>.</returns>
public TypeRef CreateRef(bool isFirstOnLine, ChildList<Expression> typeArguments, List<int> arrayRanks)
{
// Ignore any type arguments - a TypeParameterRef can't have any
return new TypeParameterRef(this, isFirstOnLine, arrayRanks);
}
/// <summary>
/// Create a reference to the <see cref="TypeParameter"/>.
/// </summary>
/// <returns>A <see cref="TypeParameterRef"/>.</returns>
public TypeRef CreateRef(bool isFirstOnLine, ChildList<Expression> typeArguments)
{
// Ignore any type arguments - a TypeParameterRef can't have any
return new TypeParameterRef(this, isFirstOnLine);
}
/// <summary>
/// Create a reference to the <see cref="TypeParameter"/>.
/// </summary>
/// <returns>A <see cref="TypeParameterRef"/>.</returns>
public TypeRef CreateRef(ChildList<Expression> typeArguments, List<int> arrayRanks)
{
// Ignore any type arguments - a TypeParameterRef can't have any
return new TypeParameterRef(this, false, arrayRanks);
}
/// <summary>
/// Create a reference to the <see cref="TypeParameter"/>.
/// </summary>
/// <returns>A <see cref="TypeParameterRef"/>.</returns>
public TypeRef CreateRef(ChildList<Expression> typeArguments)
{
// Ignore any type arguments - a TypeParameterRef can't have any
return new TypeParameterRef(this, false);
}
/// <summary>
/// Create an array reference to this <see cref="TypeParameter"/>.
/// </summary>
/// <returns>A <see cref="TypeParameterRef"/>.</returns>
public TypeRef CreateArrayRef(bool isFirstOnLine, params int[] ranks)
{
return new TypeParameterRef(this, isFirstOnLine, ranks);
}
/// <summary>
/// Create an array reference to this <see cref="TypeParameter"/>.
/// </summary>
/// <returns>A <see cref="TypeParameterRef"/>.</returns>
public TypeRef CreateArrayRef(params int[] ranks)
{
return new TypeParameterRef(this, false, ranks);
}
/// <summary>
/// Create a nullable reference to this <see cref="TypeParameter"/>.
/// </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="TypeParameter"/>.
/// </summary>
/// <returns>A <see cref="TypeRef"/>.</returns>
public TypeRef CreateNullableRef()
{
return TypeRef.CreateNullable(CreateRef());
}
/// <summary>
/// Get any constraints for this <see cref="TypeParameter"/> from the parent type or generic method.
/// </summary>
public List<TypeParameterConstraint> GetConstraints()
{
return ((ITypeParameters)_parent).GetTypeParameterConstraints(this);
}
/// <summary>
/// Get the main constraining type (if any - not including interfaces).
/// </summary>
public TypeRef GetTypeConstraint()
{
List<TypeParameterConstraint> constraints = GetConstraints();
if (constraints != null)
{
foreach (TypeParameterConstraint constraint in constraints)
{
if (constraint is TypeConstraint)
{
// Ignore if an UnresolvedRef, because we can't distinguish class vs interface
TypeRef typeRef = ((TypeConstraint)constraint).Type.SkipPrefixes() as TypeRef;
if (typeRef != null && typeRef.IsClass)
return typeRef;
}
else if (constraint is ClassConstraint)
return TypeRef.ObjectRef;
else if (constraint is StructConstraint)
return TypeRef.ValueTypeRef;
}
}
return TypeRef.ObjectRef;
}
/// <summary>
/// Get the base type - always a <see cref="TypeRef"/> to the 'object' type.
/// </summary>
public TypeRef GetBaseType()
{
return TypeRef.ObjectRef;
}
/// <summary>
/// Always returns <c>null</c>.
/// </summary>
public ConstructorRef GetConstructor(params TypeRefBase[] parameterTypes)
{
return null;
}
/// <summary>
/// Get all non-static constructors for this type.
/// </summary>
public NamedCodeObjectGroup GetConstructors(bool currentPartOnly)
{
return null;
}
/// <summary>
/// Get all non-static constructors for this type.
/// </summary>
public NamedCodeObjectGroup GetConstructors()
{
return null;
}
/// <summary>
/// Always returns <c>null</c>.
/// </summary>
public MethodRef GetMethod(string name, params TypeRefBase[] parameterTypes)
{
return null;
}
/// <summary>
/// Does nothing.
/// </summary>
public void GetMethods(string name, bool searchBaseClasses, NamedCodeObjectGroup results)
{ }
/// <summary>
/// Always returns <c>null</c> for this type.
/// </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)
{
return null;
}
/// <summary>
/// Always returns <c>null</c> for this type.
/// </summary>
/// <param name="name">The method name.</param>
public List<MethodRef> GetMethods(string name)
{
return null;
}
/// <summary>
/// Always returns <c>null</c>.
/// </summary>
public PropertyRef GetProperty(string name)
{
return null;
}
/// <summary>
/// Always returns <c>null</c>.
/// </summary>
public FieldRef GetField(string name)
{
return null;
}
/// <summary>
/// Always returns <c>null</c>.
/// </summary>
public TypeRef GetNestedType(string name)
{
return null;
}
/// <summary>
/// Get the delegate parameters of the constraining type (if any).
/// </summary>
public ICollection GetDelegateParameters()
{
return GetTypeConstraint().GetDelegateParameters();
}
/// <summary>
/// Get the delegate return type of the constraining type (if any).
/// </summary>
public TypeRefBase GetDelegateReturnType()
{
return GetTypeConstraint().GetDelegateReturnType();
}
/// <summary>
/// Determine if the constraining type is assignable from the specified type.
/// </summary>
public bool IsAssignableFrom(TypeRef typeRef)
{
return GetTypeConstraint().IsAssignableFrom(typeRef);
}
/// <summary>
/// Determine if the constraining type is a subclass of the specified type.
/// </summary>
public bool IsSubclassOf(TypeRef classTypeRef)
{
return GetTypeConstraint().IsSubclassOf(classTypeRef);
}
/// <summary>
/// Determine if the constraining type implements the specified interface type.
/// </summary>
public bool IsImplementationOf(TypeRef interfaceTypeRef)
{
return GetTypeConstraint().IsImplementationOf(interfaceTypeRef);
}
/// <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>
/// Get the full name of the <see cref="INamedCodeObject"/>, including any namespace name.
/// </summary>
/// <param name="descriptive">True to display type parameters and method parameters, otherwise false.</param>
public string GetFullName(bool descriptive)
{
if (Parent is TypeDecl)
return ((TypeDecl)Parent).GetFullName(descriptive) + "." + _name;
if (Parent is GenericMethodDecl)
return ((GenericMethodDecl)Parent).GetFullName(descriptive) + "." + _name;
return _name;
}
/// <summary>
/// Get the full name of the <see cref="INamedCodeObject"/>, including any namespace name.
/// </summary>
public string GetFullName()
{
return GetFullName(false);
}
#endregion
#region /* FORMATTING */
/// <summary>
/// True if the code object defaults to starting on a new line.
/// </summary>
public override bool IsFirstOnLineDefault
{
get { return false; }
}
/// <summary>
/// The number of newlines preceeding the object (0 to N).
/// </summary>
public override int NewLines
{
get { return base.NewLines; }
set
{
// If we're changing to zero, also change all prefix attributes to zero
bool isFirstOnLine = (value != 0);
if (_annotations != null && !isFirstOnLine && IsFirstOnLine)
{
foreach (Annotation annotation in _annotations)
{
if (annotation is Attribute)
annotation.IsFirstOnLine = false;
}
}
base.NewLines = value;
}
}
#endregion
#region /* RENDERING */
public override void AsText(CodeWriter writer, RenderFlags flags)
{
RenderFlags passFlags = (flags & RenderFlags.PassMask);
if (flags.HasFlag(RenderFlags.PrefixSpace))
writer.Write(" ");
AsTextAnnotations(writer, passFlags);
UpdateLineCol(writer, flags);
writer.WriteIdentifier(_name, flags);
}
public static void AsTextTypeParameters(CodeWriter writer, ChildList<TypeParameter> typeParameters, RenderFlags flags)
{
RenderFlags passFlags = (flags & RenderFlags.PassMask);
// Render the angle brackets as braces if we're inside a documentation comment
writer.Write(flags.HasFlag(RenderFlags.InDocComment) ? "{" : "<");
writer.WriteList(typeParameters, passFlags, typeParameters.Parent);
writer.Write(flags.HasFlag(RenderFlags.InDocComment) ? "}" : ">");
}
#endregion
}
}