// 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 System.Reflection;
using Mono.Cecil;
using Mono.Collections.Generic;
using Nova.CodeDOM;
using Nova.Utilities;
namespace Nova.UI
{
/// <summary>
/// The view model for a <see cref="CodeDOM.MethodRef"/>.
/// </summary>
public class MethodRefVM : TypeRefBaseVM
{
#region /* STATICS */
internal static void AddViewModelMapping()
{
CreateViewModel.Add(typeof(MethodRef),
delegate(CodeObject codeObject, bool isDescription, Dictionary<CodeObject, CodeObjectVM> dictionary) { return new MethodRefVM((MethodRef)codeObject, dictionary); });
}
#endregion
#region /* CONSTRUCTORS */
/// <summary>
/// Create a view model instance for the specified <see cref="CodeDOM.MethodRef"/>.
/// </summary>
public MethodRefVM(MethodRef methodRef, Dictionary<CodeObject, CodeObjectVM> dictionary)
: base(methodRef, true, dictionary)
{ }
#endregion
#region /* PROPERTIES */
/// <summary>
/// The underlying <see cref="CodeDOM.MethodRef"/> model.
/// </summary>
public MethodRef MethodRef
{
get { return (MethodRef)CodeObject; }
}
#endregion
#region /* METHODS */
#endregion
#region /* RENDERING */
public override void RenderExpression(CodeRenderer renderer, RenderFlags flags)
{
MethodRef methodRef = MethodRef;
// If we have no dot prefix, and the ShowParentTypes flag is set, then render all parent types
// (this shouldn't occur in display of code, but only when displaying an evaluated type reference,
// such as in a tooltip). Generic methods won't include type arguments for enclosing types, so
// we don't have to worry about them.
if (!flags.HasFlag(RenderFlags.HasDotPrefix) && flags.HasFlag(RenderFlags.ShowParentTypes))
{
TypeRefBase typeRef = methodRef.GetDeclaringType();
if (typeRef != null)
{
CreateVM(typeRef).Render(renderer, flags);
renderer.RenderText(Dot.ParseToken, PUNC_BRUSH, this);
flags |= RenderFlags.HasDotPrefix;
}
}
object reference = methodRef.Reference;
if (reference is MethodDeclBase)
renderer.RenderText(((MethodDeclBase)reference).Name, IDENTIFIER_BRUSH, this);
else if (reference is MethodDefinition)
renderer.RenderText(((MethodDefinition)reference).Name, IDENTIFIER_BRUSH, this);
else if (reference is MethodInfo)
renderer.RenderText(((MethodInfo)reference).Name, IDENTIFIER_BRUSH, this);
if (!methodRef.HasInferredTypeArguments || flags.HasFlag(RenderFlags.Description))
RenderTypeArguments(renderer, _typeArgumentVMs, flags, this);
}
public static void RenderMethodDefinition(CodeRenderer renderer, MethodDefinition methodDefinition, RenderFlags flags, CodeObjectVM tag)
{
RenderFlags passFlags = flags & ~RenderFlags.Description;
bool hasBorder = flags.HasFlag(RenderFlags.ForceBorder);
if (hasBorder)
renderer.CreateBorder(MethodDeclBaseVM.StaticBorderBrush, MethodDeclBaseVM.StaticBackgroundBrush, tag);
if (!flags.HasFlag(RenderFlags.NoPreAnnotations))
{
AttributeVM.RenderAttributes(renderer, methodDefinition, tag);
AttributeVM.RenderAttributes(renderer, methodDefinition.MethodReturnType, tag, AttributeTarget.Return);
}
Modifiers modifiers = MethodRef.GetMethodModifiers(methodDefinition);
renderer.RenderText(ModifiersHelpers.AsString(modifiers), KEYWORD_BRUSH, tag);
bool isConversionOperator = (modifiers.HasFlag(Modifiers.Explicit) || modifiers.HasFlag(Modifiers.Implicit));
if (!methodDefinition.IsConstructor && !isConversionOperator)
{
TypeReference returnType = methodDefinition.ReturnType;
RenderTypeReferenceAsTypeRefVM(renderer, returnType, passFlags, tag); // Render as TypeRefVM for nested tooltips
renderer.RenderText(" ", PUNC_BRUSH, tag);
}
TypeReference declaringType = methodDefinition.DeclaringType;
RenderTypeReferenceAsTypeRefVM(renderer, declaringType, passFlags, tag); // Render as TypeRefVM for nested tooltips
DotVM.RenderDot(renderer, tag);
if (methodDefinition.IsConstructor)
renderer.RenderName(declaringType.HasGenericParameters ? TypeDefinitionUtil.NonGenericName(declaringType) : declaringType.Name, TYPE_BRUSH, tag, passFlags);
else if (methodDefinition.HasGenericParameters)
RenderGenericMember(renderer, methodDefinition.Name, (IEnumerable<TypeReference>)methodDefinition.GenericParameters, passFlags, IDENTIFIER_BRUSH, tag);
else if (methodDefinition.Name.StartsWith(Operator.NamePrefix))
{
// Convert the internal name into the appropriate symbol
renderer.RenderText(OperatorDecl.ParseToken, KEYWORD_BRUSH, tag);
renderer.RenderText(" ", PUNC_BRUSH, tag);
if (isConversionOperator)
RenderTypeReferenceAsTypeRefVM(renderer, methodDefinition.ReturnType, passFlags, tag); // Render as TypeRefVM for nested tooltips
else
renderer.RenderText(OperatorDecl.GetOperatorSymbol(methodDefinition.Name), IDENTIFIER_BRUSH, tag);
}
else
renderer.RenderText(methodDefinition.Name, IDENTIFIER_BRUSH, tag);
RenderMethodParameters(renderer, methodDefinition, passFlags, tag);
// Render type constraints (if any)
if (methodDefinition.HasGenericParameters)
RenderConstraints(renderer, methodDefinition.GenericParameters, passFlags, tag);
// If we have a border, return to the previous one
if (hasBorder)
renderer.ReturnToBorderParent(tag);
}
public static void RenderMethodParameters(CodeRenderer renderer, MethodDefinition methodDefinition, RenderFlags flags, CodeObjectVM tag)
{
renderer.RenderText(MethodDeclBase.ParseTokenStart, PUNC_BRUSH, tag);
ICollection parameters = MethodRef.GetMethodParameters(methodDefinition);
if (parameters is ChildList<ParameterDecl>)
{
ChildListVM<ParameterDeclVM> parameterVMs = CreateListVM<ParameterDecl, ParameterDeclVM>((ChildList<ParameterDecl>)parameters, tag);
renderer.RenderList(parameterVMs, flags, null);
}
else if (parameters is Collection<ParameterDefinition>)
RenderParameters(renderer, (Collection<ParameterDefinition>)parameters, flags, tag);
else //if (parameters is ParameterInfo[])
RenderParameters(renderer, (ParameterInfo[])parameters, flags, tag);
renderer.RenderText(MethodDeclBase.ParseTokenEnd, PUNC_BRUSH, tag);
}
public static void RenderParameters(CodeRenderer renderer, Collection<ParameterDefinition> parameters, RenderFlags flags, CodeObjectVM tag)
{
for (int i = 0; i < parameters.Count; ++i)
{
ParameterDefinition parameterDefinition = parameters[i];
if (i > 0)
renderer.RenderText(ParameterDecl.ParseTokenSeparator + " ", PUNC_BRUSH, tag);
bool hasBorder = !flags.HasFlag(RenderFlags.NoBorder);
if (hasBorder)
renderer.CreateBorder(VariableDeclVM.StaticBorderBrush, VariableDeclVM.StaticBackgroundBrush, tag);
ParameterRefVM.RenderParameterDefinition(renderer, parameterDefinition, flags, tag);
// If we have a border, return to the previous one);
if (hasBorder)
renderer.ReturnToBorderParent(tag);
}
}
/// <summary>
/// Render a MethodDefinition as a MethodRefVM for nested tooltips.
/// </summary>
public static void RenderMethodDefinitionAsMethodRefVM(CodeRenderer renderer, MethodDefinition methodDefinition, RenderFlags flags, CodeObjectVM parentVM)
{
// Use parentVM to render if possible, but it can be null if we're inside a tooltip
CodeObjectVM codeObjectVM;
MethodRef methodRef = MethodRef.Create(methodDefinition);
if (parentVM != null)
codeObjectVM = parentVM.CreateVM(methodRef, true);
else
codeObjectVM = CreateVM(methodRef, null, true);
codeObjectVM.Render(renderer, flags | RenderFlags.NoBorder);
}
public static void RenderMethodInfo(CodeRenderer renderer, MethodInfo methodInfo, RenderFlags flags, CodeObjectVM tag)
{
RenderFlags passFlags = flags & ~RenderFlags.Description;
bool hasBorder = flags.HasFlag(RenderFlags.ForceBorder);
if (hasBorder)
renderer.CreateBorder(MethodDeclBaseVM.StaticBorderBrush, MethodDeclBaseVM.StaticBackgroundBrush, tag);
if (!flags.HasFlag(RenderFlags.NoPreAnnotations))
{
AttributeVM.RenderAttributes(renderer, methodInfo, tag);
AttributeVM.RenderAttributes(renderer, methodInfo.ReturnParameter, tag, AttributeTarget.Return);
}
Modifiers modifiers = MethodRef.GetMethodModifiers(methodInfo);
renderer.RenderText(ModifiersHelpers.AsString(modifiers), KEYWORD_BRUSH, tag);
bool isConversionOperator = (modifiers.HasFlag(Modifiers.Explicit) || modifiers.HasFlag(Modifiers.Implicit));
if (!isConversionOperator)
{
Type returnType = methodInfo.ReturnType;
RenderTypeAsTypeRefVM(renderer, returnType, passFlags, tag); // Render as TypeRefVM for nested tooltips
renderer.RenderText(" ", PUNC_BRUSH, tag);
}
Type declaringType = methodInfo.DeclaringType;
RenderTypeAsTypeRefVM(renderer, declaringType, passFlags, tag); // Render as TypeRefVM for nested tooltips
DotVM.RenderDot(renderer, tag);
if (methodInfo.IsGenericMethod)
RenderGenericMember(renderer, methodInfo.Name, methodInfo.GetGenericArguments(), passFlags, IDENTIFIER_BRUSH, tag);
else if (methodInfo.Name.StartsWith(Operator.NamePrefix))
{
// Convert the internal name into the appropriate symbol
renderer.RenderText(OperatorDecl.ParseToken, KEYWORD_BRUSH, tag);
renderer.RenderText(" ", PUNC_BRUSH, tag);
if (isConversionOperator)
RenderTypeAsTypeRefVM(renderer, methodInfo.ReturnType, passFlags, tag); // Render as TypeRefVM for nested tooltips
else
renderer.RenderText(OperatorDecl.GetOperatorSymbol(methodInfo.Name), IDENTIFIER_BRUSH, tag);
}
else
renderer.RenderText(methodInfo.Name, IDENTIFIER_BRUSH, tag);
RenderMethodParameters(renderer, methodInfo, passFlags, tag);
// Render type constraints (if any)
if (methodInfo.IsGenericMethod)
RenderConstraints(renderer, methodInfo.GetGenericMethodDefinition().GetGenericArguments(), passFlags, tag);
// If we have a border, return to the previous one
if (hasBorder)
renderer.ReturnToBorderParent(tag);
}
public static void RenderMethodParameters(CodeRenderer renderer, MethodBase methodBase, RenderFlags flags, CodeObjectVM tag)
{
renderer.RenderText(MethodDeclBase.ParseTokenStart, PUNC_BRUSH, tag);
ICollection parameters = MethodRef.GetMethodParameters(methodBase);
if (parameters is ParameterInfo[])
RenderParameters(renderer, (ParameterInfo[])parameters, flags, tag);
else
{
ChildListVM<ParameterDeclVM> parameterVMs = CreateListVM<ParameterDecl, ParameterDeclVM>((ChildList<ParameterDecl>)parameters, tag);
renderer.RenderList(parameterVMs, flags, null);
}
renderer.RenderText(MethodDeclBase.ParseTokenEnd, PUNC_BRUSH, tag);
}
public static void RenderParameters(CodeRenderer renderer, ParameterInfo[] parameters, RenderFlags flags, CodeObjectVM tag)
{
for (int i = 0; i < parameters.Length; ++i)
{
ParameterInfo parameterInfo = parameters[i];
if (i > 0)
renderer.RenderText(ParameterDecl.ParseTokenSeparator + " ", PUNC_BRUSH, tag);
bool hasBorder = !flags.HasFlag(RenderFlags.NoBorder);
if (hasBorder)
renderer.CreateBorder(VariableDeclVM.StaticBorderBrush, VariableDeclVM.StaticBackgroundBrush, tag);
ParameterRefVM.RenderParameterInfo(renderer, parameterInfo, flags, tag);
// If we have a border, return to the previous one);
if (hasBorder)
renderer.ReturnToBorderParent(tag);
}
}
#endregion
}
}