/// <summary> /// Gets the <see cref="PropertyInfo"/> as a code gen member (<see cref="CgMember"/>) /// </summary> /// <param name="pi"></param> /// <param name="valueTypeOnly"></param> /// <param name="enumValueDictionary"></param> /// <returns></returns> public static CgMember GetAsCgMember(PropertyInfo pi, bool valueTypeOnly, Dictionary <string, string[]> enumValueDictionary) { if (pi == null) { return(null); } var piType = pi.NfPropertyType(); if (valueTypeOnly && piType.NfBaseType() != null && piType.NfBaseType().Name != VALUE_TYPE) { return(null); } var cgMem = new CgMember { TypeName = Settings.LangStyle.TransformClrTypeSyntax(piType), IsEnumerableType = NfReflect.IsEnumerableReturnType(piType), Name = pi.Name, MetadataToken = pi.MetadataToken }; if (pi.CanRead) { cgMem.HasGetter = true; if (pi.NfGetGetMethod() != null) { cgMem.IsStatic = pi.NfGetGetMethod().IsStatic; } } if (pi.CanWrite) { cgMem.HasSetter = true; if (pi.NfGetSetMethod() != null) { cgMem.IsStatic = pi.NfGetSetMethod().IsStatic; } } string[] enumVals; if (NfReflect.IsEnumType(piType, out enumVals) && enumValueDictionary != null) { cgMem.IsEnum = true; var clearName = NfReflect.GetLastTypeNameFromArrayAndGeneric(cgMem.TypeName, "<"); if (!enumValueDictionary.ContainsKey(clearName)) { enumValueDictionary.Add(clearName, enumVals); } } return(cgMem); }
/// <summary> /// Gets the <see cref="FieldInfo"/> as a code gen member (<see cref="CgMember"/>) /// </summary> /// <param name="fi"></param> /// <param name="valueTypeOnly"></param> /// <param name="enumValueDictionary"></param> /// <returns></returns> public static CgMember GetAsCgMember(FieldInfo fi, bool valueTypeOnly, Dictionary <string, string[]> enumValueDictionary) { if (fi == null) { return(null); } if (NfReflect.IsClrGeneratedType(fi.Name)) { return(null); } var fiType = fi.NfFieldType(); if (valueTypeOnly && fiType.NfBaseType() != null && fiType.NfBaseType().Name != VALUE_TYPE) { return(null); } var cgMem = new CgMember { TypeName = Settings.LangStyle.TransformClrTypeSyntax(fiType), IsEnumerableType = NfReflect.IsEnumerableReturnType(fiType), Name = fi.Name, IsStatic = fi.IsStatic, MetadataToken = fi.MetadataToken }; string[] enumVals; if (NfReflect.IsEnumType(fiType, out enumVals) && enumValueDictionary != null) { cgMem.IsEnum = true; var clearName = NfReflect.GetLastTypeNameFromArrayAndGeneric(cgMem.TypeName, "<"); if (!enumValueDictionary.ContainsKey(clearName)) { enumValueDictionary.Add(clearName, enumVals); } } return(cgMem); }
public AsmDiagram(Assembly asm, bool withNamespaceSubGraphs = false) { if (asm == null) { throw new ArgumentNullException(nameof(asm)); } _targetedNs = asm.GetName().Name; _withNsSubgraphs = withNamespaceSubGraphs; _asmName = NfString.SafeDotNetIdentifier(asm.GetName().Name); foreach ( var asmType in asm.NfGetExportedTypes() .Where(x => !string.IsNullOrWhiteSpace(x.Namespace) && AssemblyName.ReferenceMatchesDefinition(asm.GetName(), x.Assembly.GetName()))) { var item1 = new FlattenedItem(asmType) { FlName = asmType.Name }; if (item1.IsTerminalNode || NfReflect.IsEnumType(asmType)) { continue; } foreach ( var p in asmType.NfGetProperties(NfSettings.DefaultFlags, false) .Where( x => x != null && !string.IsNullOrWhiteSpace(x.NfPropertyType(false)?.Namespace) && AssemblyName.ReferenceMatchesDefinition(x.NfPropertyType(false)?.Assembly.GetName(), asm.GetName())) ) { if (NfReflect.IsEnumType(p.PropertyType)) { continue; } var item2 = new FlattenedItem(p.PropertyType) { FlName = p.Name }; if (item2.IsTerminalNode) { continue; } var tupleOfItems = new Tuple <FlattenedItem, FlattenedItem>(item1, item2); var itemEv = new AsmDiagramEdge(tupleOfItems); if (Edges.Any(x => x.AreSame(itemEv))) { continue; } Edges.Add(itemEv); } } Edges = RemoveDuplicates(Edges); var names = Edges.SelectMany(x => x.NodeName).ToList(); var uqNames = names.Distinct().OrderBy(x => x).ToList(); _nodes = uqNames.Select(x => new AsmDiagramNode(x, GetCountOfEdgesOn(x))).ToList(); if (_withNsSubgraphs) { var uqNamespaces = _nodes.Select(x => x.NodeNamespace).Distinct().ToList(); foreach (var ns in uqNamespaces) { _nsSubGraphs.Add(new AsmDiagramSubGraph(ns, _nodes)); } } }
//[EditorBrowsable(EditorBrowsableState.Never)] public static List <FlattenedLine> FlattenType(Assembly assembly, string typeFullName, ref int currentDepth, int maxDepth, string limitOnValueType, bool displayEnums, Stack <FlattenedItem> fiValueTypes, Stack typeStack) { var printList = new List <FlattenedLine>(); if (string.IsNullOrWhiteSpace(typeFullName)) { return(printList); } Func <PropertyInfo, string, bool> limitOnPi = (info, s) => string.IsNullOrWhiteSpace(s) || string.Equals($"{info.PropertyType}", s, StringComparison.OrdinalIgnoreCase) || string.Equals(NfReflect.GetLastTypeNameFromArrayAndGeneric(info.PropertyType), s, StringComparison.OrdinalIgnoreCase) || (s == Constants.ENUM && NfReflect.IsEnumType(info.PropertyType)); var currentType = assembly.NfGetType(typeFullName); if (currentType == null) { return(printList); } //top frame of recursive calls will perform this if (fiValueTypes == null) { if (maxDepth <= 0) { maxDepth = 16; } typeStack = new Stack(); typeStack.Push(typeFullName); fiValueTypes = new Stack <FlattenedItem>(); fiValueTypes.Push(new FlattenedItem(currentType) { FlName = NfReflect.GetTypeNameWithoutNamespace(typeFullName) }); } var typeNamesList = currentType.GetProperties(NfSettings.DefaultFlags) .Where( x => (NfReflect.IsValueTypeProperty(x) && limitOnPi(x, limitOnValueType) || (limitOnValueType == Constants.ENUM && limitOnPi(x, limitOnValueType))) //more limbo branching for enums ) .Select(p => new Tuple <Type, string>(p.PropertyType, p.Name)) .ToList(); foreach (var typeNamePair in typeNamesList) { var pVtype = typeNamePair.Item1; var pVname = typeNamePair.Item2; fiValueTypes.Push(new FlattenedItem(pVtype) { FlName = pVname }); var fiItems = fiValueTypes.ToList(); fiItems.Reverse(); printList.Add(new FlattenedLine(fiItems.Distinct(new FlattenedItemComparer()).ToList()) { ValueType = $"{typeNamePair.Item1}" }); fiValueTypes.Pop(); } //then recurse the object types foreach ( var p in currentType.GetProperties(NfSettings.DefaultFlags) .Where(x => !NfReflect.IsValueTypeProperty(x))) { currentDepth += 1; //time to go if (currentDepth >= maxDepth) { return(printList); } var typeIn = NfReflect.GetLastTypeNameFromArrayAndGeneric(p.PropertyType); if (typeIn == null || typeStack.Contains(typeIn)) { continue; } var fi = new FlattenedItem(p.PropertyType) { FlName = p.Name }; if (fiValueTypes.ToList().Any(x => x.FlType == p.PropertyType)) { continue; } fiValueTypes.Push(fi); typeStack.Push(typeIn); //enum types being handled as limbo between value type and ref type string[] enumVals; if (displayEnums && NfReflect.IsEnumType(p.PropertyType, out enumVals)) { foreach (var ev in enumVals) { fiValueTypes.Push(new FlattenedItem(typeof(Enum)) { FlName = ev }); var fiItems = fiValueTypes.ToList(); fiItems.Reverse(); printList.Add(new FlattenedLine(fiItems.Distinct(new FlattenedItemComparer()).ToList()) { ValueType = String.Empty }); fiValueTypes.Pop(); } } else { printList.AddRange(FlattenType(assembly, fi.TypeFullName, ref currentDepth, maxDepth, limitOnValueType, displayEnums, fiValueTypes, typeStack)); } fiValueTypes.Pop(); typeStack.Pop(); currentDepth -= 1; } return(printList); }
/// <summary> /// Converts the .NET type into the custom Code Gen type /// </summary> /// <param name="asmType"></param> /// <param name="valueTypeOnly"> /// Will only export Fields and Properties whose base type extends System.ValueType /// </param> /// <param name="resolveDependencies"> /// Switch to have the IL of the type parsed and all dependent calls Metadata tokens added. /// </param> /// <returns></returns> public static CgType GetCgOfType(this Type asmType, bool valueTypeOnly, bool resolveDependencies = false) { var cgType = new CgType(); if (asmType == null || NfReflect.IsIgnoreType(asmType) || NfReflect.IsClrGeneratedType(asmType)) { return(null); } //use the logic in TypeName to get the namespace and class name so its not tied to having the assembly var cgTypeName = new NfTypeName(asmType.AssemblyQualifiedName); //make sure there is always some kind of namespace cgType.Namespace = string.IsNullOrWhiteSpace(cgTypeName.Namespace) ? asmType.Assembly.GetName().Name : cgTypeName.Namespace; cgType.IsContrivedNamespace = string.IsNullOrWhiteSpace(cgTypeName.Namespace); cgType.Name = cgTypeName.ClassName; cgType.AssemblyQualifiedName = asmType.AssemblyQualifiedName; cgType.IsEnum = NfReflect.IsEnumType(asmType); var cgTypesInterfaces = asmType.GetInterfaces(); cgType.MetadataToken = asmType.MetadataToken; Func <CgType, string, bool> alreadyPresentHerein = (cg, nextName) => (cg.Properties.FirstOrDefault( cgP => string.Equals(cgP.Name, nextName, StringComparison.OrdinalIgnoreCase)) != null || cg.Fields.FirstOrDefault( cgF => string.Equals(cgF.Name, nextName, StringComparison.OrdinalIgnoreCase)) != null || cg.Events.FirstOrDefault( cgE => string.Equals(cgE.Name, nextName, StringComparison.OrdinalIgnoreCase)) != null) ; //have events go first since they tend to be speard across fields and properties foreach ( var evtInfo in asmType.GetEvents(Shared.Core.NfSettings.DefaultFlags)) { var evtHandlerType = evtInfo.NfEventHandlerType().ToString(); var cgMem = new CgMember { Name = evtInfo.Name, TypeName = evtHandlerType, MetadataToken = evtInfo.MetadataToken }; cgType.Events.Add(cgMem); } var asmMembers = asmType.GetMembers(Shared.Core.NfSettings.DefaultFlags); foreach (var mi in asmMembers) { if (alreadyPresentHerein(cgType, mi.Name)) { continue; } try { if (mi.MemberType == MemberTypes.Property) { var pi = mi as PropertyInfo; var cgm = GetAsCgMember(pi, valueTypeOnly, cgType.EnumValueDictionary); if (cgm == null) { continue; } if (resolveDependencies) { var propMi = NfReflect.GetMethodsForProperty(pi, asmType); foreach (var pim in propMi) { cgm.opCodeCallsAndCallvirtsMetadatTokens.AddRange(Asm.GetCallsMetadataTokens(pim)); } } cgType.Properties.Add(cgm); } } catch (Exception ex) { Asm.AddLoaderExceptionToLog(null, ex); if (!Settings.IgnoreReflectionMissingAsmError) { throw; } cgType.Properties.Add(new CgMember { Name = mi.Name, TypeName = DF_TYPE_NAME, HasGetter = true, HasSetter = true, SkipIt = true }); } try { if (mi.MemberType == MemberTypes.Event) { continue;//these have already been handled } } catch (Exception ex) { Asm.AddLoaderExceptionToLog(null, ex); continue; } try { if (mi.MemberType == MemberTypes.Field) { var fi = mi as FieldInfo; var cgm = GetAsCgMember(fi, valueTypeOnly, cgType.EnumValueDictionary); if (cgm == null) { continue; } cgType.Fields.Add(cgm); } } catch (Exception ex) { Asm.AddLoaderExceptionToLog(null, ex); if (!Settings.IgnoreReflectionMissingAsmError) { throw; } cgType.Fields.Add(new CgMember { Name = mi.Name, TypeName = DF_TYPE_NAME, SkipIt = true }); } try { if (!valueTypeOnly && mi.MemberType == MemberTypes.Method) { var mti = mi as MethodInfo; var cgm = GetAsCgMember(mti, resolveDependencies); if (cgm == null) { continue; } cgm.IsInterfaceImpl = IsInterfaceImpl(mti, cgTypesInterfaces); cgType.Methods.Add(cgm); } if (!valueTypeOnly && mi.MemberType == MemberTypes.Constructor) { var ci = mi as ConstructorInfo; var tn = (string.IsNullOrWhiteSpace(cgTypeName.Namespace) ? cgTypeName.ClassName : $"{cgTypeName.Namespace}.{cgTypeName.ClassName}"); var cgm = GetAsCgMember(ci, tn, resolveDependencies); if (cgm == null) { continue; } cgType.Methods.Add(cgm); } } catch (Exception ex) { Asm.AddLoaderExceptionToLog(null, ex); if (!Settings.IgnoreReflectionMissingAsmError) { throw; } cgType.Methods.Add(new CgMember { Name = mi.Name, TypeName = DF_TYPE_NAME, SkipIt = true }); } } if (resolveDependencies) { ResolveAllMetadataTokens(cgType, asmType.Assembly.ManifestModule); } return(cgType); }