/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using dnlib.DotNet; using dnSpy.Contracts.Text; namespace dnSpy.Contracts.Decompiler { /// /// Provides text colors /// public abstract class MetadataTextColorProvider { /// /// Gets a type color /// /// Type /// public virtual object GetColor(TypeDef? type) { if (type is null) return BoxedTextColor.Text; if (type.IsInterface) return BoxedTextColor.Interface; if (type.IsEnum) return BoxedTextColor.Enum; if (type.IsValueType) return BoxedTextColor.ValueType; if (type.IsDelegate) return BoxedTextColor.Delegate; if (type.IsSealed && type.IsAbstract) { var bt = type.BaseType; if (bt is not null && bt.DefinitionAssembly.IsCorLib()) { if (bt is TypeRef baseTr) { if (baseTr.Namespace == systemString && baseTr.Name == objectString) return BoxedTextColor.StaticType; } else { var baseTd = bt as TypeDef; if (baseTd is not null && baseTd.Namespace == systemString && baseTd.Name == objectString) return BoxedTextColor.StaticType; } } } if (type.IsSealed) return BoxedTextColor.SealedType; return BoxedTextColor.Type; } static readonly UTF8String systemString = new UTF8String("System"); static readonly UTF8String objectString = new UTF8String("Object"); /// /// Gets a type color /// /// Type /// public virtual object GetColor(TypeRef? type) { if (type is null) return BoxedTextColor.Text; var td = type.Resolve(); if (td is not null) return GetColor(td); return BoxedTextColor.Type; } static readonly UTF8String systemRuntimeCompilerServicesString = new UTF8String("System.Runtime.CompilerServices"); static readonly UTF8String extensionAttributeString = new UTF8String("ExtensionAttribute"); /// /// Gets a member color /// /// Member /// public virtual object GetColor(IMemberRef? memberRef) { if (memberRef is null) return BoxedTextColor.Text; if (memberRef.IsField) { var fd = ((IField)memberRef).ResolveFieldDef(); if (fd is null) return BoxedTextColor.InstanceField; if (fd.DeclaringType?.IsEnum == true) return BoxedTextColor.EnumField; if (fd.IsLiteral) return BoxedTextColor.LiteralField; if (fd.IsStatic) return BoxedTextColor.StaticField; return BoxedTextColor.InstanceField; } if (memberRef.IsMethod) { var mr = (IMethod)memberRef; if (mr.MethodSig is null) return BoxedTextColor.InstanceMethod; var md = mr.ResolveMethodDef(); if (md is not null && md.IsConstructor) return GetColor(md.DeclaringType); if (!mr.MethodSig.HasThis) { if (md is not null && md.IsDefined(systemRuntimeCompilerServicesString, extensionAttributeString)) return BoxedTextColor.ExtensionMethod; return BoxedTextColor.StaticMethod; } return BoxedTextColor.InstanceMethod; } if (memberRef.IsPropertyDef) { var p = (PropertyDef)memberRef; return GetColor(p.GetMethod ?? p.SetMethod, BoxedTextColor.StaticProperty, BoxedTextColor.InstanceProperty); } if (memberRef.IsEventDef) { var e = (EventDef)memberRef; return GetColor(e.AddMethod ?? e.RemoveMethod ?? e.InvokeMethod, BoxedTextColor.StaticEvent, BoxedTextColor.InstanceEvent); } if (memberRef is TypeDef td) return GetColor(td); if (memberRef is TypeRef tr) return GetColor(tr); if (memberRef is TypeSpec ts) { if (ts.TypeSig is GenericSig gsig) return GetColor(gsig); return BoxedTextColor.Type; } if (memberRef is GenericParam gp) return GetColor(gp); // It can be a MemberRef if it doesn't have a field or method sig (invalid metadata) if (memberRef.IsMemberRef) return BoxedTextColor.Text; return BoxedTextColor.Text; } /// /// Gets a generic signature color /// /// Generic signature /// public virtual object GetColor(GenericSig? genericSig) { if (genericSig is null) return BoxedTextColor.Text; return genericSig.IsMethodVar ? BoxedTextColor.MethodGenericParameter : BoxedTextColor.TypeGenericParameter; } /// /// Gets a generic parameter color /// /// Generic parameter /// public virtual object GetColor(GenericParam? genericParam) { if (genericParam is null) return BoxedTextColor.Text; if (genericParam.DeclaringType is not null) return BoxedTextColor.TypeGenericParameter; if (genericParam.DeclaringMethod is not null) return BoxedTextColor.MethodGenericParameter; return BoxedTextColor.TypeGenericParameter; } static object GetColor(MethodDef method, object staticValue, object instanceValue) { if (method is null) return instanceValue; if (method.IsStatic) return staticValue; return instanceValue; } /// /// Gets an exported type color /// /// Exported type /// public virtual object GetColor(ExportedType? exportedType) { if (exportedType is null) return BoxedTextColor.Text; return GetColor(exportedType.ToTypeRef()); } /// /// Gets a type signature color /// /// Type signature /// public virtual object GetColor(TypeSig? typeSig) { typeSig = typeSig.RemovePinnedAndModifiers(); if (typeSig is null) return BoxedTextColor.Text; if (typeSig is TypeDefOrRefSig tdr) return GetColor(tdr.TypeDefOrRef); if (typeSig is GenericSig gsig) return GetColor(gsig); return BoxedTextColor.Text; } /// /// Gets a color /// /// Object, eg. an instruction operand /// public virtual object GetColor(object? obj) { if (obj is null) return BoxedTextColor.Text; if (obj is byte || obj is sbyte || obj is ushort || obj is short || obj is uint || obj is int || obj is ulong || obj is long || obj is UIntPtr || obj is IntPtr) return BoxedTextColor.Number; if (obj is IMemberRef r) return GetColor(r); if (obj is ExportedType et) return GetColor(et); if (obj is TypeSig ts) return GetColor(ts); if (obj is GenericParam gp) return GetColor(gp); if (obj is TextColor) return obj; if (obj is Parameter) return BoxedTextColor.Parameter; if (obj is dnlib.DotNet.Emit.Local) return BoxedTextColor.Local; if (obj is MethodSig) return BoxedTextColor.Text;//TODO: if (obj is string) return BoxedTextColor.String; return BoxedTextColor.Text; } } /// /// C# provider /// public sealed class CSharpMetadataTextColorProvider : MetadataTextColorProvider { /// /// Gets the instance /// public static readonly CSharpMetadataTextColorProvider Instance = new CSharpMetadataTextColorProvider(); CSharpMetadataTextColorProvider() { } } /// /// Visual Basic provider /// public sealed class VisualBasicMetadataTextColorProvider : MetadataTextColorProvider { /// /// Gets the instance /// public static readonly VisualBasicMetadataTextColorProvider Instance = new VisualBasicMetadataTextColorProvider(); VisualBasicMetadataTextColorProvider() { } /// /// Gets a type color /// /// Type /// public override object GetColor(TypeDef? type) { if (IsModule(type)) return BoxedTextColor.Module; return base.GetColor(type); } static bool IsModule(TypeDef? type) => type is not null && type.DeclaringType is null && type.IsSealed && type.IsDefined(stringMicrosoftVisualBasicCompilerServices, stringStandardModuleAttribute); static readonly UTF8String stringMicrosoftVisualBasicCompilerServices = new UTF8String("Microsoft.VisualBasic.CompilerServices"); static readonly UTF8String stringStandardModuleAttribute = new UTF8String("StandardModuleAttribute"); } }