void Add(Dictionary <string, HierarchyElement> index, string indexName, string typeName, HierarchyElement type) { if (String.IsNullOrEmpty(typeName)) { throw new ArgumentException("must not be null or empty", nameof(typeName)); } if (String.Compare("java.lang.Comparable", typeName, StringComparison.OrdinalIgnoreCase) == 0) { Logger.Debug($"java.lang.Comparable being added: {type} ({type.FullName})"); } //Logger.Verbose ($"Index: trying to add '{typeName}' ({type.GetType ().FullName}), parent: {type.ParentElement?.FullName} ({type.ParentElement?.GetType ()?.FullName})"); HierarchyElement t; if (index.TryGetValue(typeName, out t) && t != null) { // if (t.GetType () == type.GetType ()) // TODO: implement IEquatable<T> on namespaces, // // classes and indexes and don't throw if the two // // objects have actually equal contents // throw new InvalidOperationException ($"Duplicate type entry for type '{typeName}' ({type.GetType ().FullName})' in {indexName} index"); string prefix = TypeToPrefix(type); Logger.Warning($"Duplicate type name '{typeName}' in {indexName} index. Existing entry is of type {t.GetType ().FullName}, new entry of type {type.GetType ().FullName}"); Logger.Debug($"Prefixing new type entry with '{prefix}:'"); // This is necessary because Xamarin.Android adds invoker classes for deprecated // interfaces and, initially, the class has exactly the same Java name as the interface // and only later in the process the interface name is prefixed with 'I' creating a // unique managed type name typeName = $"{prefix}:{typeName}"; } index [typeName] = type; }
protected virtual void GenerateNamespaceMember(HierarchyNamespace ns, HierarchyElement element, string outputDirectory) { FilesystemPath path = Context.OutputPathProvider.GetPathFor(outputDirectory, element); if (String.IsNullOrEmpty(path?.FullPath)) { Logger.Warning($"Unable to generate output for element {element.GetType ().FullName} ({element.GetManagedName (true) ?? element.FullName}) since no full path was given (at {element.GetLocation ()})"); return; } if (path.IsDirectory) { throw new InvalidOperationException($"Namespace member must be written to a file ({ns.FullName})"); } EnsureDirectory(Path.GetDirectoryName(path.FullPath)); CheckOverwrite(path.FullPath); using (Stream fs = File.Open(path.FullPath, FileMode.Create)) { using (StreamWriter writer = new StreamWriter(fs, Context.FileEncoding)) { WriteFileHeader(ns, writer); OutputNamespaceMember(element, writer, path.FullPath); WriteFileFooter(ns, writer); } } }
// Walks up the parent chain and calculates the namespace based on the parent types instead of just // reading the full managed name which can lead to invalid results public virtual string GetNamespace() { if (Parent == null) { return(null); } HierarchyElement parent = ParentElement; HierarchyBase previousParent = parent; var segments = new List <string> (); while (parent != null) { var ns = parent as HierarchyNamespace; if (ns != null) { if (!(previousParent is HierarchyNamespace)) { throw new InvalidOperationException("Parent namespaces must not be interlaced with other types"); } segments.Add(ns.GetManagedName()); } previousParent = parent; parent = parent.ParentElement; } if (segments.Count == 0) { throw new InvalidOperationException($"A type must be a child of at least one namespace"); } return(String.Join(".", segments)); }
public void ResolveBaseTypes(HierarchyIndex typeIndex) { if (DoNotAddBaseTypes || baseTypes != null) { return; } if (typeIndex == null) { throw new ArgumentNullException(nameof(typeIndex)); } if (baseTypeNames != null && baseTypeNames.Count > 0) { string kindHint = HierarchyIndex.TypeToPrefix <HierarchyInterface> (); foreach (string typeName in baseTypeNames) { HierarchyElement e = typeIndex.Lookup(typeName, kindHint, this); } } AddBaseTypes(typeIndex); if (baseTypes == null) { AddDefaultBaseType(typeIndex); } }
// Builds, possibly nested, type name excluding any and all namespaces. Nested type name will have its // parent class names separated with dots. public virtual string GetNameWithoutNamespace() { if (Parent == null) { return(GetManagedName()); } HierarchyElement parent = ParentElement; var segments = new List <string> { GetManagedName() }; while (parent != null) { if (parent is HierarchyNamespace) { break; } segments.Add(parent.GetManagedName()); parent = parent.ParentElement; } return(String.Join(".", segments)); }
protected void NestElements(Action <Dictionary <HierarchyElement, HierarchyElement> > looper) { if (looper == null) { throw new ArgumentNullException(nameof(looper)); } var toReparent = new Dictionary <HierarchyElement, HierarchyElement> (); looper(toReparent); if (toReparent.Count == 0) { return; } foreach (var kvp in toReparent) { HierarchyElement element = kvp.Key; HierarchyElement newParent = kvp.Value; element.ParentElement?.RemoveMember(element); newParent.AddMember(element); } }
protected FilesystemPath GetPathFor_Single(string rootDirectory, HierarchyElement element) { if (element is HierarchyNamespace) { return(null); } throw new NotImplementedException(); }
public void AddNative(HierarchyElement type) { if (type == null) { throw new ArgumentNullException(nameof(type)); } Add(nativeIndex, "native", type.FullName, type); }
public void AddMember(HierarchyElement member) { if (member == null) { throw new ArgumentNullException(nameof(member)); } Helpers.AddToList(member, ref members); member.Parent = this; MemberAdded(member); }
public void RemoveMember(HierarchyElement member) { if (member == null) { throw new ArgumentNullException(nameof(member)); } if (members == null || members.Count == 0) { return; } members.Remove(member); }
public void AddManaged(HierarchyElement type) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (!String.IsNullOrEmpty(type.FullManagedName)) { Add(managedIndex, "managed", type.FullManagedName, type); } }
public HierarchyElement Lookup(string typeName, string kindHint = null, HierarchyElement context = null) { HierarchyElement ret = Lookup(nativeIndex, "native", typeName, kindHint, context); if (ret == null) { ret = Lookup(managedIndex, "managed", typeName, kindHint, context); } if (ret == null) { throw new InvalidOperationException($"Type '{typeName}' not found in index.{GetContextLocation (context)}"); } return(ret); }
protected virtual T SelectNewParent <T> (HierarchyElement element) where T : HierarchyElement { if (element == null) { return(null); } if (String.IsNullOrEmpty(element.FullName)) { throw new InvalidOperationException("Each element must have a full name"); } if (TypeIndex.Count == 0) { Logger.Warning($"Unable to select new parent for element {element.Name}, type index does not exist"); return(null); } // The way API description is constructed we can check whether a class/interface/enum is nested // by simply looking at its "namespace" name and checking whether it corresponds to another // class or interfaces string nsOrTypeName = Helpers.GetTypeNamespace(element.FullName); if (String.IsNullOrEmpty(nsOrTypeName)) { return(null); } try { HierarchyElement maybeParent = TypeIndex.Lookup(nsOrTypeName); if (maybeParent == null) { return(null); } var ret = maybeParent as T; if (ret == null) { return(null); } return(ret); } catch { Logger.Fatal($"Error selecting new parent for element '{element.FullName}' ({element.GetLocation ()})"); throw; } }
static string GetContextLocation(HierarchyElement context) { if (context == null) { return(String.Empty); } string ret = $" Called on behalf of: {context.FullName}"; string location = context.GetLocation(); if (!String.IsNullOrEmpty(location)) { ret += $" at {location}"; } return(ret); }
protected void GenerateManagedNames(HierarchyElement root) { if (root == null) { return; } root.SetManagedNames(); if (root is HierarchyObject || root is HierarchyNamespace) { TypeIndex.AddManaged(root); } if (!root.HasMembers) { return; } Helpers.ForEachNotNull(root.Members, (HierarchyElement element) => GenerateManagedNames(element)); }
void AddLocationComment(ApiElement element, HierarchyElement hierarchyElement) { if (String.IsNullOrEmpty(element.DocumentPath) || element.SourceLine < 0) { return; } var sb = new StringBuilder(); sb.Append(element.DocumentPath); if (element.SourceColumn > 0) { sb.Append($" [{element.SourceLine}:{element.SourceColumn}]"); } else { sb.Append($":{element.SourceLine}"); } hierarchyElement.AddComment(sb.ToString()); }
protected virtual void GenerateNamespaceMember(HierarchyElement element, TextWriter writer, string outputFileName) { Logger.Debug($"Generating {element.GetManagedName (true)} in namespace output file: {outputFileName}"); OutputNamespaceMember(element, writer, outputFileName); }
protected FilesystemPath GetPathFor_Deep(string rootDirectory, HierarchyElement element) { throw new NotImplementedException(); }
protected FilesystemPath GetPathFor_FirstLevelThenFullShallow(string rootDirectory, HierarchyElement element) { string fullManagedName = element.GetManagedName(true); bool isDirectory; string path = GetFirstNameSegment(fullManagedName); Logger.Debug($"Element: {element.FullName} (managed: {fullManagedName})"); Logger.Debug($"Initial path: {path}"); if (element is HierarchyNamespace) { Logger.Debug("Is namespace"); isDirectory = true; path = Path.Combine(path, fullManagedName); } else { var obj = element as HierarchyObject; if (obj == null) { throw new InvalidOperationException("Only HierarchyObject and HierarchyNamespace instances can be used to compute output file name"); } Logger.Debug("Is type"); isDirectory = false; path = Path.Combine(path, obj.GetNamespace(), obj.GetNameWithoutNamespace()); } Logger.Debug($"Final relative path: {path}"); Logger.Debug(String.Empty); return(GetFilePath(rootDirectory, path, isDirectory)); }
public HierarchyInterface(GeneratorContext context, HierarchyElement parent) : base(context, parent) { }
protected FilesystemPath GetPathFor_FirstLevelThenShortSingle(string rootDirectory, HierarchyElement element) { throw new NotImplementedException(); }
protected virtual void MemberAdded(HierarchyElement member) { }
public override FilesystemPath GetPathFor(string rootDirectory, HierarchyElement element) { if (String.IsNullOrEmpty(rootDirectory)) { throw new ArgumentException("Must not be null or empty", nameof(rootDirectory)); } if (element == null) { throw new ArgumentNullException(nameof(element)); } switch (element) { case HierarchyNamespace ns: case HierarchyClass klass: case HierarchyInterface iface: case HierarchyEnum enm: break; default: throw new InvalidOperationException($"Unsupported hierarchy type '{element.GetType ()}'"); } Func <string, HierarchyElement, FilesystemPath> getter = null; switch (TreeLayout.NamespaceTreeStyle) { case OutputNamespaceTreeStyle.Single: getter = GetPathFor_Single; break; case OutputNamespaceTreeStyle.Shallow: getter = GetPathFor_Shallow; break; case OutputNamespaceTreeStyle.Deep: getter = GetPathFor_Deep; break; case OutputNamespaceTreeStyle.FirstLevelThenFullShallow: getter = GetPathFor_FirstLevelThenFullShallow; break; case OutputNamespaceTreeStyle.FirstLevelThenFullSingle: getter = GetPathFor_FirstLevelThenFullSingle; break; case OutputNamespaceTreeStyle.FirstLevelThenShortShallow: getter = GetPathFor_FirstLevelThenShortShallow; break; case OutputNamespaceTreeStyle.FirstLevelThenShortSingle: getter = GetPathFor_FirstLevelThenShortSingle; break; default: throw new InvalidOperationException($"Unsupported namespace tree style {TreeLayout.NamespaceTreeStyle}"); } return(getter(rootDirectory, element)); }
HierarchyElement Lookup(Dictionary <string, HierarchyElement> index, string indexName, string typeName, string kindHint, HierarchyElement context) { if (!index.TryGetValue(typeName, out HierarchyElement ret)) { string caller = GetContextLocation(context); Logger.Debug($"Type '{typeName}' not found in {indexName} index.{caller}"); if (!String.IsNullOrEmpty(kindHint)) { typeName = $"{kindHint}:{typeName}"; Logger.Debug($"Trying to look up using prefixed name: '{typeName}'.{caller}"); if (!index.TryGetValue(typeName, out ret)) { Logger.Debug($"Prefixed type name not found in {indexName} index either.{caller}"); } } } return(ret); }
public abstract FilesystemPath GetPathFor(string rootDirectory, HierarchyElement element);
protected virtual void OutputNamespaceMember(HierarchyElement element, TextWriter writer, string fileName) { }
public void Add(HierarchyElement type) { AddNative(type); AddManaged(type); }
public HierarchyInterfaceInvoker(GeneratorContext context, HierarchyElement parent, HierarchyInterface invokedInterface) : base(context, parent) { InvokedInterface = invokedInterface ?? throw new ArgumentNullException(nameof(invokedInterface)); Visibility = ApiVisibility.Internal; }
public HierarchyClass(GeneratorContext context, HierarchyElement parent) : base(context, parent) { }