// 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.Reflection;
using Nova.Rendering;
namespace Nova.CodeDOM
{
/// <summary>
/// Represents a reference to a <see cref="FieldDecl"/> or a <see cref="FieldInfo"/>.
/// </summary>
public class FieldRef : VariableRef
{
#region /* CONSTRUCTORS */
/// <summary>
/// Create a <see cref="FieldRef"/>.
/// </summary>
public FieldRef(FieldDecl declaration, bool isFirstOnLine)
: base(declaration, isFirstOnLine)
{ }
/// <summary>
/// Create a <see cref="FieldRef"/>.
/// </summary>
public FieldRef(FieldDecl declaration)
: base(declaration, false)
{ }
/// <summary>
/// Create a <see cref="FieldRef"/>.
/// </summary>
public FieldRef(FieldInfo fieldInfo, bool isFirstOnLine)
: base(fieldInfo, isFirstOnLine)
{ }
/// <summary>
/// Create a <see cref="FieldRef"/>.
/// </summary>
public FieldRef(FieldInfo fieldInfo)
: base(fieldInfo, false)
{ }
#endregion
#region /* PROPERTIES */
/// <summary>
/// True if the referenced field is const.
/// </summary>
public override bool IsConst
{
get
{
if (_reference is FieldDecl)
return ((FieldDecl)_reference).IsConst;
return ((FieldInfo)_reference).IsLiteral;
}
}
/// <summary>
/// True if the referenced field is static.
/// </summary>
public override bool IsStatic
{
get
{
if (_reference is FieldDecl)
return ((FieldDecl)_reference).IsStatic;
return ((FieldInfo)_reference).IsStatic;
}
}
/// <summary>
/// True if the referenced field has public access.
/// </summary>
public bool IsPublic
{
get
{
if (_reference is FieldDecl)
return ((FieldDecl)_reference).IsPublic;
return ((FieldInfo)_reference).IsPublic;
}
}
/// <summary>
/// True if the referenced field has private access.
/// </summary>
public bool IsPrivate
{
get
{
if (_reference is FieldDecl)
return ((FieldDecl)_reference).IsPrivate;
return ((FieldInfo)_reference).IsPrivate;
}
}
/// <summary>
/// True if the referenced field has protected access.
/// </summary>
public bool IsProtected
{
get
{
if (_reference is FieldDecl)
return ((FieldDecl)_reference).IsProtected;
return ((FieldInfo)_reference).IsFamily;
}
}
/// <summary>
/// True if the referenced field has internal access.
/// </summary>
public bool IsInternal
{
get
{
if (_reference is FieldDecl)
return ((FieldDecl)_reference).IsInternal;
return ((FieldInfo)_reference).IsAssembly;
}
}
#endregion
#region /* STATIC METHODS */
/// <summary>
/// Find a field on the specified <see cref="TypeDecl"/> with the specified name.
/// </summary>
/// <returns>A <see cref="FieldRef"/> to the field, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(TypeDecl typeDecl, string name, bool isFirstOnLine)
{
if (typeDecl != null)
{
FieldRef fieldRef = typeDecl.GetField(name);
if (fieldRef != null)
{
fieldRef.IsFirstOnLine = isFirstOnLine;
return fieldRef;
}
}
return new UnresolvedRef(name, isFirstOnLine);
}
/// <summary>
/// Find a field on the specified <see cref="TypeDecl"/> with the specified name.
/// </summary>
/// <returns>A <see cref="FieldRef"/> to the field, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(TypeDecl typeDecl, string name)
{
return Find(typeDecl, name, false);
}
/// <summary>
/// Find a field on the specified type <see cref="Alias"/> with the specified name.
/// </summary>
/// <returns>A <see cref="FieldRef"/> to the field, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(Alias typeAlias, string name, bool isFirstOnLine)
{
if (typeAlias != null)
{
FieldRef fieldRef = typeAlias.GetField(name);
if (fieldRef != null)
{
fieldRef.IsFirstOnLine = isFirstOnLine;
return fieldRef;
}
}
return new UnresolvedRef(name, isFirstOnLine);
}
/// <summary>
/// Find a field on the specified type <see cref="Alias"/> with the specified name.
/// </summary>
/// <returns>A <see cref="FieldRef"/> to the field, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(Alias typeAlias, string name)
{
return Find(typeAlias, name, false);
}
/// <summary>
/// Find the field in the specified <see cref="Type"/> with the specified name.
/// </summary>
/// <returns>A <see cref="FieldRef"/> to the field, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(Type type, string name, bool isFirstOnLine)
{
if (type != null)
{
FieldInfo fieldInfo = type.GetField(name);
if (fieldInfo != null)
return new FieldRef(fieldInfo, isFirstOnLine);
}
return new UnresolvedRef(name, isFirstOnLine);
}
/// <summary>
/// Find the field in the specified <see cref="Type"/> with the specified name.
/// </summary>
/// <returns>A <see cref="FieldRef"/> to the field, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(Type type, string name)
{
return Find(type, name, false);
}
/// <summary>
/// Find a field on the specified <see cref="TypeRefBase"/> with the specified name.
/// </summary>
/// <returns>A <see cref="FieldRef"/> to the field, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(TypeRefBase typeRefBase, string name, bool isFirstOnLine)
{
if (typeRefBase is TypeRef)
{
FieldRef fieldRef = ((TypeRef)typeRefBase).GetField(name);
if (fieldRef != null)
{
fieldRef.IsFirstOnLine = isFirstOnLine;
return fieldRef;
}
}
return new UnresolvedRef(name, isFirstOnLine);
}
/// <summary>
/// Find a field on the specified <see cref="TypeRefBase"/> with the specified name.
/// </summary>
/// <returns>A <see cref="FieldRef"/> to the field, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static SymbolicRef Find(TypeRefBase typeRefBase, string name)
{
return Find(typeRefBase, name, false);
}
/// <summary>
/// Get any modifiers from the specified <see cref="FieldInfo"/>.
/// </summary>
public static Modifiers GetFieldModifiers(FieldInfo fieldInfo)
{
Modifiers modifiers = 0;
if (fieldInfo.IsPublic)
modifiers |= Modifiers.Public;
if (fieldInfo.IsFamily || fieldInfo.IsFamilyOrAssembly)
modifiers |= Modifiers.Protected;
if (fieldInfo.IsAssembly || fieldInfo.IsFamilyOrAssembly)
modifiers |= Modifiers.Internal;
if (fieldInfo.IsPrivate)
modifiers |= Modifiers.Private;
if (fieldInfo.IsLiteral)
modifiers |= Modifiers.Const;
else if (fieldInfo.IsStatic) // Ignore static if const
modifiers |= Modifiers.Static;
if (fieldInfo.IsInitOnly)
modifiers |= Modifiers.ReadOnly;
// 'new' isn't relevant to external users, so don't bother figuring it out (we could look
// at IsHideBySig, but we'd have to further determine if it's the hide-er or the hide-e).
// 'volatile' would be nice to know, but there isn't any attribute or any other way to figure it out.
return modifiers;
}
#endregion
#region /* METHODS */
/// <summary>
/// Get the declaring type of the referenced field.
/// </summary>
public override TypeRefBase GetDeclaringType()
{
TypeRefBase declaringTypeRef = GetDeclaringType(_reference);
// A field reference doesn't store any type arguments for a parent type instance, so any
// type arguments in any generic declaring type or its parent types will always default to
// the declared type arguments. Convert them from OpenTypeParameterRefs to TypeParameterRefs
// so that they don't show up as Red in the GUI.
if (declaringTypeRef != null && declaringTypeRef.HasTypeArguments)
declaringTypeRef.ConvertOpenTypeParameters();
return declaringTypeRef;
}
/// <summary>
/// Get the declaring type of the specified field object.
/// </summary>
/// <param name="fieldObj">The field object (a <see cref="FieldDecl"/> or <see cref="FieldInfo"/>).</param>
/// <returns>The <see cref="TypeRef"/> of the declaring type, or null if it can't be determined.</returns>
public static TypeRefBase GetDeclaringType(object fieldObj)
{
TypeRefBase declaringTypeRef;
if (fieldObj is FieldDecl)
{
TypeDecl declaringTypeDecl = ((FieldDecl)fieldObj).DeclaringType;
declaringTypeRef = (declaringTypeDecl != null ? declaringTypeDecl.CreateRef() : null);
}
else //if (fieldObj is FieldInfo)
declaringTypeRef = TypeRef.Create(((FieldInfo)fieldObj).DeclaringType);
return declaringTypeRef;
}
#endregion
#region /* RENDERING */
public static void AsTextFieldInfo(CodeWriter writer, FieldInfo fieldInfo, RenderFlags flags)
{
RenderFlags passFlags = flags & ~RenderFlags.Description;
// Skip all details for enum members, including the declaring type since it will always be on the left of the dot
if (!(fieldInfo.IsLiteral && fieldInfo.FieldType.IsEnum))
{
if (!flags.HasFlag(RenderFlags.NoPreAnnotations))
Attribute.AsTextAttributes(writer, fieldInfo);
writer.Write(ModifiersHelpers.AsString(GetFieldModifiers(fieldInfo)));
Type fieldType = fieldInfo.FieldType;
TypeRefBase.AsTextType(writer, fieldType, passFlags);
writer.Write(" ");
TypeRefBase.AsTextType(writer, fieldInfo.DeclaringType, passFlags);
Dot.AsTextDot(writer);
}
writer.Write(fieldInfo.Name);
}
#endregion
}
}