/// <summary> /// Walks through the Roslyn symbols hierarchy and prepares the member builders hierarchy into the given <paramref name="root"/> builder. /// </summary> /// <param name="symbol">Symbol to process</param> /// <param name="root">Root builder</param> /// <param name="assembly">Containing assembly builder</param> /// <param name="ns">Containing namespace builder</param> /// <param name="type">Containing type builder (used for nested types)</param> /// <param name="level">Hierarchy level (used to indent the console output)</param> private static void Build(ISymbol symbol, RootMemberBuilder root, AssemblyMemberBuilder assembly, NamespaceMemberBuilder ns, TypeMemberBuilder type, int level) { Console.WriteLine($"{new string(' ', level)}Checking the {symbol.Kind}: {symbol.Name}"); try { switch (symbol) { case IAssemblySymbol assemblySymbol: BuildAssembly(assemblySymbol, root, level); break; case INamespaceSymbol namespaceSymbol: BuildNamespace(namespaceSymbol, root, assembly, level); break; case INamedTypeSymbol typeSymbol: BuildType(typeSymbol, root, assembly, ns, type, level); break; case IFieldSymbol fieldSymbol: BuildField(fieldSymbol, root, type, level); break; case IPropertySymbol propertySymbol: BuildProperty(propertySymbol, root, type, level); break; case IMethodSymbol methodSymbol: BuildMethod(methodSymbol, root, type, level); break; case IEventSymbol eventSymbol: BuildEvent(eventSymbol, root, type, level); break; } } catch (Exception exception) { ConsoleUtils.WriteErr($"{new string(' ', level)}Exception '{exception.Message}' while processing {symbol.Kind}: {symbol.Name}"); throw; } }
/// <summary> /// Prepares the <see cref="EventMemberBuilder"/> from the <paramref name="symbol"/> /// and adds it to <see cref="TypeMemberBuilder.ContentMembers"/> /// </summary> /// <param name="symbol">Source <see cref="INamedTypeSymbol"/></param> /// <param name="root">Builder root</param> /// <param name="type">Parent <see cref="TypeMemberBuilder"/></param> /// <param name="level">Hierarchy level (used to indent the console output)</param> private static void BuildEvent(IEventSymbol symbol, RootMemberBuilder root, TypeMemberBuilder type, int level) { if (symbol.IsImplicitlyDeclared) { return; } if (symbol.GetAttributes().Any(a => a.AttributeClassString() == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")) { return; } var e = new EventMemberBuilder { Name = symbol.Name, NameBase = symbol.Name, Symbol = symbol, SourceFiles = symbol.DeclaringSyntaxReferences.Select(dsr => dsr.SyntaxTree.FilePath).ToList(), DocumentationId = symbol.GetDocumentationCommentId(), DocumentationXml = symbol.GetDocumentationCommentXml(), Documentation = Documentation.Read(symbol.GetDocumentationCommentXml()), Modifier = ModifierEnumExtensions.Modifier(symbol.DeclaredAccessibility), IsAbstract = symbol.IsAbstract, IsExtern = symbol.IsExtern, IsSealed = symbol.IsSealed, IsStatic = symbol.IsStatic, IsOverride = symbol.IsOverride, IsVirtual = symbol.IsVirtual, HasExplicitAddAndRemove = !symbol.AddMethod.IsImplicitlyDeclared && !symbol.RemoveMethod.IsImplicitlyDeclared, TypeRef = TypeRef.GetOrCreate(symbol.Type, root), IsNew = symbol.GetIsNew(), OverridesSymbol = symbol.OverriddenEvent, ExplicitInterfaceImplementationMemberSymbol = symbol.ExplicitInterfaceImplementations != null && symbol.ExplicitInterfaceImplementations.Length > 0 ? symbol.ExplicitInterfaceImplementations[0] : null }; e.SetAttributes(root); type.ContentMembers.Add(e); Console.WriteLine($"{new string(' ', level)} read as {e}"); }
/// <summary> /// Prepares the <see cref="FieldMemberBuilder"/> from the <paramref name="symbol"/> /// and adds it to <see cref="TypeMemberBuilder.ContentMembers"/> /// </summary> /// <param name="symbol">Source <see cref="INamedTypeSymbol"/></param> /// <param name="root">Builder root</param> /// <param name="type">Parent <see cref="TypeMemberBuilder"/></param> /// <param name="level">Hierarchy level (used to indent the console output)</param> private static void BuildField(IFieldSymbol symbol, RootMemberBuilder root, TypeMemberBuilder type, int level) { if (symbol.IsImplicitlyDeclared) { return; } if (symbol.GetAttributes().Any(a => a.AttributeClassString() == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")) { return; } var f = new FieldMemberBuilder() { Name = symbol.Name, NameBase = symbol.Name, Symbol = symbol, SourceFiles = symbol.DeclaringSyntaxReferences.Select(dsr => dsr.SyntaxTree.FilePath).ToList(), DocumentationId = symbol.GetDocumentationCommentId(), DocumentationXml = symbol.GetDocumentationCommentXml(), Documentation = Documentation.Read(symbol.GetDocumentationCommentXml()), Modifier = ModifierEnumExtensions.Modifier(symbol.DeclaredAccessibility), IsAbstract = symbol.IsAbstract, IsExtern = symbol.IsExtern, IsSealed = symbol.IsSealed, IsStatic = symbol.IsStatic, IsOverride = symbol.IsOverride, IsVirtual = symbol.IsVirtual, IsConst = symbol.IsConst, IsReadOnly = symbol.IsReadOnly, IsVolatile = symbol.IsVolatile, ConstantValue = symbol.ConstantValue, TypeRef = TypeRef.GetOrCreate(symbol.Type, root), IsNew = symbol.GetIsNew() }; f.SetAttributes(root); type.ContentMembers.Add(f); Console.WriteLine($"{new string(' ', level)} read as {f}"); }
/// <summary> /// Prepares the <see cref="MethodMemberBuilder"/> from the <paramref name="symbol"/> /// and adds it to <see cref="TypeMemberBuilder.ContentMembers"/> /// </summary> /// <param name="symbol">Source <see cref="INamedTypeSymbol"/></param> /// <param name="root">Builder root</param> /// <param name="type">Parent <see cref="TypeMemberBuilder"/></param> /// <param name="level">Hierarchy level (used to indent the console output)</param> private static void BuildMethod(IMethodSymbol symbol, RootMemberBuilder root, TypeMemberBuilder type, int level) { if (symbol.IsImplicitlyDeclared || symbol.MethodKind == MethodKind.AnonymousFunction || symbol.MethodKind == MethodKind.BuiltinOperator || symbol.MethodKind == MethodKind.LambdaMethod || symbol.MethodKind == MethodKind.LocalFunction || symbol.MethodKind == MethodKind.PropertyGet || symbol.MethodKind == MethodKind.PropertySet || symbol.MethodKind == MethodKind.EventAdd || symbol.MethodKind == MethodKind.EventRemove) { return; } if (symbol.GetAttributes().Any(a => a.AttributeClassString() == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")) { return; } var m = new MethodMemberBuilder() { Name = symbol.GetOperatorMethodAliasOrOriginalName(), NameBase = symbol.Name, OperatorCSharpSymbol = symbol.GetOperatorCSharpSymbol(), Symbol = symbol, SourceFiles = symbol.DeclaringSyntaxReferences.Select(dsr => dsr.SyntaxTree.FilePath).ToList(), DocumentationId = symbol.GetDocumentationCommentId(), DocumentationXml = symbol.GetDocumentationCommentXml(), Documentation = Documentation.Read(symbol.GetDocumentationCommentXml()), Modifier = ModifierEnumExtensions.Modifier(symbol.DeclaredAccessibility), IsAbstract = symbol.IsAbstract, IsExtern = symbol.IsExtern, IsSealed = symbol.IsSealed, IsStatic = symbol.IsStatic, IsOverride = symbol.IsOverride, IsVirtual = symbol.IsVirtual, IsAsync = symbol.IsAsync, IsExtensionMethod = symbol.IsExtensionMethod, IsGeneric = symbol.IsGenericMethod && symbol.TypeParameters != null && symbol.TypeParameters.Length > 0, ReturnsVoid = symbol.ReturnsVoid, ReturnsByRef = symbol.ReturnsByRef, ReturnsByRefReadonly = symbol.ReturnsByRefReadonly, RefKind = (RefKindEnum)symbol.RefKind, ReturnTypeRef = TypeRef.GetOrCreate(symbol.ReturnType, root), MethodKind = (MethodKindEnum)symbol.MethodKind, IsNew = symbol.GetIsNew(), OverridesSymbol = symbol.OverriddenMethod, ExplicitInterfaceImplementationMemberSymbol = symbol.ExplicitInterfaceImplementations != null && symbol.ExplicitInterfaceImplementations.Length > 0 ?symbol.ExplicitInterfaceImplementations[0] :null }; if (m.IsConstructor || m.IsDestructor) { m.Name = $"{(m.IsDestructor ? "~" : "")}{type.Name}"; m.NameBase = m.Name; } if (m.IsGeneric) { //Process the type parameters m.TypeParameters = GetTypeParameters(symbol.TypeParameters, root); m.Name += $"<{string.Join(",", m.TypeParameters.Select(tp => tp.Name))}>"; // add types to name } if (symbol.Parameters != null && symbol.Parameters.Length > 0) { //Process the method parameters m.Parameters = GetMethodParameters(symbol.Parameters, root, m.IsExtensionMethod); m.Name += $"({string.Join(", ", m.Parameters.Select(p => p.TypeRef.ApplySpecialName(false)))})"; } else { m.Name += "()"; } m.SetAttributes(root); type.ContentMembers.Add(m); Console.WriteLine($"{new string(' ', level)} read as {m}"); }
/// <summary> /// Prepares the <see cref="PropertyMemberBuilder"/> from the <paramref name="symbol"/> /// and adds it to <see cref="TypeMemberBuilder.ContentMembers"/> /// </summary> /// <param name="symbol">Source <see cref="INamedTypeSymbol"/></param> /// <param name="root">Builder root</param> /// <param name="type">Parent <see cref="TypeMemberBuilder"/></param> /// <param name="level">Hierarchy level (used to indent the console output)</param> private static void BuildProperty(IPropertySymbol symbol, RootMemberBuilder root, TypeMemberBuilder type, int level) { if (symbol.IsImplicitlyDeclared) { return; } if (symbol.GetAttributes().Any(a => a.AttributeClassString() == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")) { return; } var p = new PropertyMemberBuilder() { Name = symbol.Name, NameBase = symbol.Name.Replace("[]", ""), Symbol = symbol, SourceFiles = symbol.DeclaringSyntaxReferences.Select(dsr => dsr.SyntaxTree.FilePath).ToList(), DocumentationId = symbol.GetDocumentationCommentId(), DocumentationXml = symbol.GetDocumentationCommentXml(), Documentation = Documentation.Read(symbol.GetDocumentationCommentXml()), Modifier = ModifierEnumExtensions.Modifier(symbol.DeclaredAccessibility), IsAbstract = symbol.IsAbstract, IsExtern = symbol.IsExtern, IsSealed = symbol.IsSealed, IsStatic = symbol.IsStatic, IsOverride = symbol.IsOverride, IsVirtual = symbol.IsVirtual, IsReadOnly = symbol.IsReadOnly, IsWriteOnly = symbol.IsWriteOnly, IsIndexer = symbol.IsIndexer, TypeRef = TypeRef.GetOrCreate(symbol.Type, root), IsNew = symbol.GetIsNew(), OverridesSymbol = symbol.OverriddenProperty, ExplicitInterfaceImplementationMemberSymbol = symbol.ExplicitInterfaceImplementations != null && symbol.ExplicitInterfaceImplementations.Length > 0 ? symbol.ExplicitInterfaceImplementations[0] : null }; var propertyModifier = ModifierEnumExtensions.Modifier(symbol.DeclaredAccessibility); var getterModifier = ModifierEnumExtensions.Modifier(symbol.GetMethod?.DeclaredAccessibility ?? symbol.DeclaredAccessibility); var setterModifier = ModifierEnumExtensions.Modifier(symbol.SetMethod?.DeclaredAccessibility ?? symbol.DeclaredAccessibility); if (getterModifier != propertyModifier) { p.GetterModifier = getterModifier.ToModifierString(); } if (setterModifier != propertyModifier) { p.SetterModifier = setterModifier.ToModifierString(); } if (symbol.Parameters != null && symbol.Parameters.Length > 0) { //Process the indexer parameters (the only property kind with parameters p.Parameters = GetMethodParameters(symbol.Parameters, root); p.Name = p.Name.Replace("[]", $"[{string.Join(", ", p.Parameters.Select(param => param.TypeRef.ApplySpecialName(false)))}]"); } p.SetAttributes(root); type.ContentMembers.Add(p); Console.WriteLine($"{new string(' ', level)} read as {p}"); }
/// <summary> /// Prepares the <see cref="TypeMemberBuilder"/> from the <paramref name="symbol"/> /// and adds it to <see cref="NamespaceMemberBuilder.Types"/> /// </summary> /// <param name="symbol">Source <see cref="INamedTypeSymbol"/></param> /// <param name="root">Builder root</param> /// <param name="assembly">Containing <see cref="AssemblyMemberBuilder"/></param> /// <param name="ns">Parent <see cref="NamespaceMemberBuilder"/></param> /// <param name="type">Parent <see cref="TypeMemberBuilder"/> for nested types</param> /// <param name="level">Hierarchy level (used to indent the console output)</param> // ReSharper disable once SuggestBaseTypeForParameter private static void BuildType(INamedTypeSymbol symbol, RootMemberBuilder root, AssemblyMemberBuilder assembly, NamespaceMemberBuilder ns, TypeMemberBuilder type, int level) { if (symbol.IsImplicitlyDeclared) { return; } if (symbol.GetAttributes().Any(a => a.AttributeClassString() == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")) { return; } if (symbol.Name.Contains("NuProps")) { } var t = new TypeMemberBuilder() { Name = type == null ? symbol.Name : $"{type.Name}.{symbol.Name}", Symbol = symbol, SourceFiles = symbol.DeclaringSyntaxReferences.Select(dsr => dsr.SyntaxTree.FilePath).ToList(), DocumentationId = symbol.GetDocumentationCommentId(), DocumentationXml = symbol.GetDocumentationCommentXml(), Documentation = Documentation.Read(symbol.GetDocumentationCommentXml()), TypeKind = symbol.TypeKind.ToTypeKindEnum(), TypeRef = TypeRef.GetOrCreate(symbol, root), Modifier = ModifierEnumExtensions.Modifier(symbol.DeclaredAccessibility), IsAbstract = symbol.IsAbstract, IsExtern = symbol.IsExtern, IsSealed = symbol.IsSealed, IsStatic = symbol.IsStatic, IsNew = symbol.GetIsNew(), IsGeneric = symbol.IsGenericType && symbol.TypeParameters != null && symbol.TypeParameters.Length > 0 }; t.NameBase = t.Name; //Get the implemented interfaces var typeInterfaces = symbol.Interfaces; if (typeInterfaces != null && typeInterfaces.Length > 0) { //directly implemented t.InterfacesTypeRefs = typeInterfaces.Select(i => TypeRef.GetOrCreate(i, root)).ToList(); } var typeAllInterfaces = symbol.AllInterfaces; if (typeAllInterfaces != null && typeAllInterfaces.Length > 0) { //includes the inherited t.AllInterfacesTypeRefs = typeAllInterfaces.Select(i => TypeRef.GetOrCreate(i, root)).ToList(); foreach (var implementedInterface in typeAllInterfaces) { var interfaceMembers = implementedInterface.GetMembers(); if (interfaceMembers == null) { continue; } foreach (var interfaceMember in interfaceMembers.Where( im => im.Kind == SymbolKind.Event || im.Kind == SymbolKind.Property || im.Kind == SymbolKind.Method)) { var implementationMember = symbol.FindImplementationForInterfaceMember(interfaceMember); if (implementationMember == null) { continue; } t.InterfaceImplementationsByInterfaceMember.Add(interfaceMember, implementationMember); if (!t.InterfaceMembersByInterfaceImplementation.TryGetValue(implementationMember, out var interfaceMemberList)) { interfaceMemberList = new List <ISymbol>(); t.InterfaceMembersByInterfaceImplementation.Add(implementationMember, interfaceMemberList); } ((List <ISymbol>)interfaceMemberList).Add(interfaceMember); } } } //Get the attributes t.SetAttributes(root); if (t.IsGeneric) { //Process the type parameters t.TypeParameters = GetTypeParameters(symbol.TypeParameters, root); t.Name += $"<{string.Join(",", t.TypeParameters.Select(tp => tp.Name))}>"; // add types to name } if (t.TypeKind == TypeKindEnum.Delegate) { //Process delegate - delegates only have parameters and return value t.DelegateReturnType = TypeRef.GetOrCreate(symbol.DelegateInvokeMethod.ReturnType, root); t.DelegateParameters = GetMethodParameters(symbol.DelegateInvokeMethod.Parameters, root); } ns.Types.Add(t); Console.WriteLine($"{new string(' ', level)} read as {t}"); foreach (var subType in symbol.GetMembers()) { if (!subType.IsImplicitlyDeclared) { Build(subType, root, assembly, ns, t, level + 1); } } }