using System; using System.Collections.Generic; using System.Linq; using Mono.Cecil; using Mono.Cecil.Rocks; namespace Mono.Documentation.Updater.Frameworks { public class FrameworkEntry { SortedSet types = new SortedSet (); IList allcachedframeworks; IList allframeworks; ISet allAssemblies = new SortedSet (); public int Index = 0; int _fxCount; public int FrameworksCount { get => _fxCount < 1 ? allframeworks.Count : _fxCount; } public FrameworkEntry (IList frameworks, IList cachedfx) : this(frameworks, -1, cachedfx) {} public FrameworkEntry (IList frameworks, int fxCount, IList cachedFx) { allframeworks = frameworks; if (allframeworks == null) { allframeworks = new List (1); allframeworks.Add (this); Index = 0; allcachedframeworks = allframeworks; } else { Index = allframeworks.Count; allcachedframeworks = cachedFx; } _fxCount = fxCount; } public string Name { get; set; } public string Version { get; set; } public string Id { get; set; } /// Gets a value indicating whether this is last framework being processed. public bool IsLastFramework { get => Index == FrameworksCount - 1; } /// should be the assembly name (without version and file extension) public bool IsLastFrameworkForAssembly(string assemblyName) { if (this == Empty) return true; var retval = this.allcachedframeworks .Where(f => f.AllProcessedAssemblies .Any(ass => ass.Assemblies .Any(a => a.Name.Name.Equals(assemblyName, StringComparison.OrdinalIgnoreCase)))) .ToArray(); if (!retval.Any ()) return false; var lastListed = retval.Last (); return lastListed.Name == this.Name; } public bool IsLastFrameworkForType(FrameworkTypeEntry typeEntry) { if (this == Empty) return true; var fxlist = this.allcachedframeworks.Where (f => f.FindTypeEntry (typeEntry) != null).ToArray(); if (!fxlist.Any ()) return false; var lastListed = fxlist.Last (); return lastListed.Name == this.Name; } public string AllFrameworksWithAssembly(string assemblyName) { if (this == Empty) return this.Name; var fxlist = this.allcachedframeworks.Where (f => f.allAssemblies.Any (ass => ass.Assemblies.Any (a => a.Name.Name.Equals (assemblyName, StringComparison.OrdinalIgnoreCase)))); return string.Join (";", fxlist.Select (f => f.Name).ToArray ()); } public string AllFrameworksWithType(FrameworkTypeEntry typeEntry) { if (this == Empty) return this.Name; var fxlist = this.allcachedframeworks.Where (f => f.FindTypeEntry (typeEntry) != null); return string.Join (";", fxlist.Select (f => f.Name).ToArray ()); } string _allFxString = ""; public string AllFrameworksString { get { Lazy fxString = new Lazy(() => string.Join (";", allcachedframeworks.Select (f => f.Name).ToArray ())); if (!this.IsLastFramework) return fxString.Value; if (string.IsNullOrWhiteSpace(_allFxString)) { _allFxString = fxString.Value; } return _allFxString; } } public readonly List> AssemblyNames = new List> (); public void AddProcessedAssembly (AssemblyDefinition assembly) { AssemblyNames.Add (new Tuple(assembly.Name.Name, assembly.Name.Version.ToString())); } public IEnumerable PreviousFrameworks { get => allframeworks.Where (f => f.Index < this.Index); } public ISet AllProcessedAssemblies { get => allAssemblies; } public void AddAssemblySet (AssemblySet assemblySet) { allAssemblies.Add (assemblySet); } /// Gets a value indicating whether this is first framework being processed. public bool IsFirstFramework { get => this.Index == 0; } public bool IsFirstFrameworkForType(FrameworkTypeEntry typeEntry) { if (this == Empty) return true; var firstFx = this.allcachedframeworks.FirstOrDefault(f => f.FindTypeEntry(typeEntry) != null); return firstFx == null || firstFx.Name == this.Name; } /// Only Use in Unit Tests public string Replace=""; /// Only Use in Unit Tests public string With =""; public IEnumerable Importers { get; set; } public ISet Types { get { return this.types; } } Dictionary typeMap = new Dictionary (); public FrameworkTypeEntry FindTypeEntry (FrameworkTypeEntry type) { return FindTypeEntry (Str(type.Name)); } /// The value from . public FrameworkTypeEntry FindTypeEntry (string name) { FrameworkTypeEntry entry; typeMap.TryGetValue (Str(name), out entry); return entry; } public IEnumerable Frameworks { get { return this.allframeworks; } } public static readonly FrameworkEntry Empty = new EmptyFrameworkEntry () { Name = "Empty" }; public virtual FrameworkTypeEntry ProcessType (TypeDefinition type) { FrameworkTypeEntry entry; if (!typeMap.TryGetValue (Str(type.FullName), out entry)) { var docid = DocCommentId.GetDocCommentId (type); string nstouse = GetNamespace (type); entry = new FrameworkTypeEntry (this) { Id = Str (docid), Name = Str (type.FullName), Namespace = nstouse }; types.Add (entry); typeMap.Add (Str (entry.Name), entry); } return entry; } private string GetNamespace (TypeDefinition type) { var nstouse = Str (type.Namespace); if (string.IsNullOrWhiteSpace (nstouse) && type.DeclaringType != null) { return GetNamespace(type.DeclaringType); } return nstouse; } string Str(string value) { if (!string.IsNullOrWhiteSpace (Replace)) return value.Replace (Replace, With); return value; } public override string ToString () => Str(this.Name); class EmptyFrameworkEntry : FrameworkEntry { public EmptyFrameworkEntry () : base (null, 1, null) { } public override FrameworkTypeEntry ProcessType (TypeDefinition type) { return FrameworkTypeEntry.Empty; } } } }