public TypeCollection ReflectOnAssembly(Assembly assembly, IncludeKind includeKind) { TypeCollection typeCollection = new TypeCollection(); Type[] types = assembly.GetTypes(); foreach (Type type in types) { // Skip any classes they don't want us to include. IncludeKind currentIncludeKind = type.IsPublic ? IncludeKind.Public : IncludeKind.Internal; if ((currentIncludeKind & includeKind) == 0) { continue; } // Skip compiler-generated classes, which are invisible to both // consumers of the assembly and to the assembly's creator. if (type.Name.StartsWith("<")) { continue; } TypeDoc typeDoc = ConvertTypeToDocForm(type, includeKind); typeCollection = typeCollection.AddType(typeDoc.Name, typeDoc); } return(typeCollection); }
private TypeDoc ConvertTypeToDocForm(Type type, IncludeKind includeKind) { NameInfo typeName = ConvertTypeToNameInfo(type); IEnumerable <TypeParameterDoc> typeParameters = ExtractTypeParameters(type); ImmutableDictionary <string, FieldDoc> fields = ExtractFields(type, typeName, includeKind); ImmutableDictionary <string, PropertyDoc> properties = ExtractProperties(type, typeName, includeKind); ImmutableDictionary <string, EventDoc> events = ExtractEvents(type, typeName, includeKind); ImmutableDictionary <string, MethodDoc> methods = ExtractMethods(type, typeName, includeKind); ImmutableDictionary <string, MethodDoc> constructors = ExtractConstructors(type, typeName, includeKind); methods = methods.AddRange(constructors); TypeDoc typeDoc = new TypeDoc(typeName, null, typeParameters, fields, properties, events, methods); return(typeDoc); }
private Options( IEnumerable <string> filenames, OutputKind outputKind, SplitKind splitKind, IncludeKind includeKind, string templatePath, string outputPath, bool verbose, bool success ) { Filenames = new ReadOnlyCollection <string>(filenames.ToArray()); OutputKind = outputKind; SplitKind = splitKind; IncludeKind = includeKind; TemplatePath = templatePath; OutputPath = outputPath; Verbose = verbose; Success = success; }
public static Options Parse(string[] args) { List <string> filenames = new List <string>(); bool lastOption = false; OutputKind outputKind = default; SplitKind splitKind = default; IncludeKind includeKind = default; string templatePath = null; string outputPath = null; bool verbose = false; bool success = false; for (int i = 0; i < args.Length; i++) { if (args[i][0] == '-' && !lastOption) { if (args[i] == "--") { lastOption = true; continue; } switch (args[i].Length > 1 ? args[i][1] : '-') { case '-': switch (args[i].Substring(2)) { case "html": outputKind = OutputKind.Html; break; case "internal": includeKind |= IncludeKind.Internal; break; case "md": case "markdown": outputKind = OutputKind.Markdown; break; case "output": if (i >= args.Length) { Console.Error.WriteLine($"Missing pathname after {args[i]}"); Environment.Exit(-1); break; } outputPath = args[++i]; break; case "private": includeKind |= IncludeKind.Private; break; case "protected": includeKind |= IncludeKind.Protected; break; case "public": includeKind |= IncludeKind.Public; break; case "split": case "split-types": splitKind = SplitKind.SplitByNamespaceAndType; break; case "split-namespace": splitKind = SplitKind.SplitByNamespace; break; case "template": if (i >= args.Length) { Console.Error.WriteLine($"Missing pathname after {args[i]}"); Environment.Exit(-1); break; } templatePath = args[++i]; break; case "verbose": verbose = true; break; default: Console.Error.WriteLine($"Unknown option: {args[i]}"); Environment.Exit(-1); break; } break; case 'm': outputKind = OutputKind.Markdown; break; case 's': splitKind = SplitKind.SplitByNamespaceAndType; break; case 't': if (args[i].Length > 2) { templatePath = args[i].Substring(2); } else { if (i >= args.Length) { Console.Error.WriteLine($"Missing pathname after {args[i]}"); Environment.Exit(-1); break; } templatePath = args[++i]; } break; case 'o': if (args[i].Length > 2) { outputPath = args[i].Substring(2); } else { if (i >= args.Length) { Console.Error.WriteLine($"Missing pathname after {args[i]}"); Environment.Exit(-1); break; } outputPath = args[++i]; } break; case 'v': verbose = true; break; case '?': case 'h': case 'H': Console.Error.WriteLine( @"Usage: crossdox [options] assembly.dll assembly2.xml ... Crossdox reads XML documentation output from the C# compiler and any given compiled DLLs or EXEs, and generates cross-referenced, pretty Markdown or HTML documentation websites from them. Selection options: --public Include public (exclude private/protected) --internal Include internal (exclude private/protected) --protected Include protected (exclude private) --private Include private Website options: --html Output is HTML website -m --md --markdown Output is Markdown (default) --summary Output a summary of what does & doesn't have docs -t path --template path Use custom HTML/Markdown template(s) from here Output options: -s --split --split-types Output separate files by namespace and type --split-namespace Output separate files only by namespace -o path --output path Specify output file/folder (default is '.') -v --verbose Emit verbose debugging information to stderr "); success = false; break; default: Console.Error.WriteLine($"Unknown option: {args[i]}"); success = false; break; } } else { filenames.Add(args[i]); } } if (includeKind == default) { includeKind = IncludeKind.All; } return(new Options( filenames: filenames, outputKind: outputKind, splitKind: splitKind, includeKind: includeKind, templatePath: templatePath, outputPath: outputPath, verbose: verbose, success: success )); }
private ImmutableDictionary <string, PropertyDoc> ExtractProperties(Type type, NameInfo typeName, IncludeKind includeKind) { PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); ImmutableDictionary <string, PropertyDoc> dictionary = ImmutableDictionary <string, PropertyDoc> .Empty; IEnumerable <ClassInfo> classes = typeName.AsClass; foreach (PropertyInfo property in properties) { // Don't emit properties that were just inherited. if (property.DeclaringType != type) { continue; } // Skip compiler-generated properties, which are invisible to both // consumers of the assembly and to the assembly's creator. if (type.Name.StartsWith("<")) { continue; } NameFlags getterFlags = GetVisibilityNameFlags(property.GetGetMethod()); NameFlags setterFlags = GetVisibilityNameFlags(property.GetSetMethod()); NameFlags nameFlags = (getterFlags | setterFlags) & (NameFlags.Static | NameFlags.Abstract | NameFlags.Virtual | NameFlags.New); if (property.Name.StartsWith("#")) { nameFlags |= NameFlags.SpecialName; } else if (property.Name.Contains("#")) { nameFlags |= NameFlags.ExplicitInterfaceImplementation; } if (((getterFlags | setterFlags) & NameFlags.AllVisibilities) >= NameFlags.Public) { nameFlags |= NameFlags.Public; } else if (((getterFlags | setterFlags) & NameFlags.AllVisibilities) >= NameFlags.Internal) { nameFlags |= NameFlags.Internal; } else if (((getterFlags | setterFlags) & NameFlags.AllVisibilities) >= NameFlags.Protected) { nameFlags |= NameFlags.Protected; } else if (((getterFlags | setterFlags) & NameFlags.AllVisibilities) >= NameFlags.Private) { nameFlags |= NameFlags.Private; } NameInfo propertyName = new NameInfo(classes, property.Name, null, null, nameFlags); dictionary = dictionary.Add(property.Name, new PropertyDoc(propertyName, getterFlags: getterFlags, setterFlags: setterFlags)); } return(dictionary); }
private ImmutableDictionary <string, FieldDoc> ExtractFields(Type type, NameInfo typeName, IncludeKind includeKind) { FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); ImmutableDictionary <string, FieldDoc> dictionary = ImmutableDictionary <string, FieldDoc> .Empty; IEnumerable <ClassInfo> classes = typeName.AsClass; foreach (FieldInfo field in fields) { // Don't emit fields that were just inherited. if (field.DeclaringType != type) { continue; } // Skip compiler-generated fields, which are invisible to both // consumers of the assembly and to the assembly's creator. if (type.Name.StartsWith("<")) { continue; } NameFlags nameFlags = GetVisibilityNameFlags(field); NameInfo fieldName = new NameInfo(classes, field.Name, null, null, nameFlags); dictionary = dictionary.Add(field.Name, new FieldDoc(fieldName)); } return(dictionary); }
private ImmutableDictionary <string, MethodDoc> ExtractConstructors(Type type, NameInfo typeName, IncludeKind includeKind) { ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); ImmutableDictionary <string, MethodDoc> dictionary = ImmutableDictionary <string, MethodDoc> .Empty; IEnumerable <ClassInfo> classes = typeName.AsClass; foreach (ConstructorInfo constructor in constructors) { // Don't emit constructors that were just inherited. if (constructor.DeclaringType != type) { continue; } // Skip compiler-generated constructors, which are invisible to both // consumers of the assembly and to the assembly's creator. if (constructor.Name.StartsWith("<")) { continue; } NameFlags nameFlags = GetVisibilityNameFlags(constructor); List <TypeParameterDoc> typeParameters = null; string effectiveMethodName = constructor.Name; int backtickIndex = effectiveMethodName.IndexOf('`'); if (backtickIndex >= 0) { effectiveMethodName = effectiveMethodName.Substring(0, backtickIndex); } List <Tuple <ParamInfo, ParameterDoc> > parameters = GetParameters(constructor.GetParameters()); NameInfo methodName = new NameInfo(classes, effectiveMethodName, typeParameters?.Select(t => t.Name), parameters.Select(p => p.Item1), nameFlags); List <ParameterDoc> parameterDocs = parameters.Select(p => p.Item2).ToList(); dictionary = dictionary.Add(methodName.NameWithParameters, new MethodDoc(methodName, null, typeParameters, parameterDocs, null)); } return(dictionary); }
private ImmutableDictionary <string, MethodDoc> ExtractMethods(Type type, NameInfo typeName, IncludeKind includeKind) { MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); ImmutableDictionary <string, MethodDoc> dictionary = ImmutableDictionary <string, MethodDoc> .Empty; IEnumerable <ClassInfo> classes = typeName.AsClass; foreach (MethodInfo method in methods) { // Don't emit methods that were just inherited. if (method.DeclaringType != type) { continue; } // Skip compiler-generated methods, which are invisible to both // consumers of the assembly and to the assembly's creator. if (method.Name.StartsWith("<")) { continue; } if (method.IsSpecialName) { continue; } NameFlags nameFlags = GetVisibilityNameFlags(method); List <TypeParameterDoc> typeParameters = null; if (method.IsGenericMethodDefinition) { Type[] genericArgs = method.GetGenericArguments(); typeParameters = genericArgs.Select(t => new TypeParameterDoc(t.Name, null)).ToList(); } string effectiveMethodName = method.Name; List <Tuple <ParamInfo, ParameterDoc> > parameters = GetParameters(method.GetParameters()); NameInfo methodName = new NameInfo(classes, method.Name, typeParameters?.Select(t => t.Name), parameters.Select(p => p.Item1), nameFlags); List <ParameterDoc> parameterDocs = parameters.Select(p => p.Item2).ToList(); dictionary = dictionary.Add(methodName.NameWithParameters, new MethodDoc(methodName, null, typeParameters, parameterDocs, null)); } return(dictionary); }
private ImmutableDictionary <string, EventDoc> ExtractEvents(Type type, NameInfo typeName, IncludeKind includeKind) { EventInfo[] events = type.GetEvents(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); ImmutableDictionary <string, EventDoc> dictionary = ImmutableDictionary <string, EventDoc> .Empty; IEnumerable <ClassInfo> classes = typeName.AsClass; foreach (EventInfo @event in events) { // Don't emit events that were just inherited. if (@event.DeclaringType != type) { continue; } // Skip compiler-generated events, which are invisible to both // consumers of the assembly and to the assembly's creator. if (type.Name.StartsWith("<")) { continue; } NameFlags adderFlags = GetVisibilityNameFlags(@event.GetAddMethod()); NameFlags removerFlags = GetVisibilityNameFlags(@event.GetRemoveMethod()); NameFlags nameFlags = (adderFlags | removerFlags) & (NameFlags.Static | NameFlags.Abstract | NameFlags.Virtual | NameFlags.New); if (@event.Name.StartsWith("#")) { nameFlags |= NameFlags.SpecialName; } else if (@event.Name.Contains("#")) { nameFlags |= NameFlags.ExplicitInterfaceImplementation; } if (((adderFlags | removerFlags) & NameFlags.AllVisibilities) >= NameFlags.Public) { nameFlags |= NameFlags.Public; } else if (((adderFlags | removerFlags) & NameFlags.AllVisibilities) >= NameFlags.Internal) { nameFlags |= NameFlags.Internal; } else if (((adderFlags | removerFlags) & NameFlags.AllVisibilities) >= NameFlags.Protected) { nameFlags |= NameFlags.Protected; } else if (((adderFlags | removerFlags) & NameFlags.AllVisibilities) >= NameFlags.Private) { nameFlags |= NameFlags.Private; } NameInfo eventName = new NameInfo(classes, @event.Name, null, null, nameFlags); dictionary = dictionary.Add(@event.Name, new EventDoc(eventName, adderFlags: adderFlags, removerFlags: removerFlags)); } return(dictionary); }