/// <summary> /// Let the add-on to prepare it's own data as a part of <see cref="RootMember"/> constructor. /// </summary> /// <remarks> /// The add-on checks all compilation files for the <NuProp.xxx> comments with source-only package metadata /// and builds the list of source-only packages and the indexes between the packages and code model members. /// </remarks> /// <param name="root">Code model root</param> /// <param name="builder">Code model buildel root</param> public void ProcessRootData(RootMember root, RootMemberBuilder builder) { ConsoleUtils.WriteInfo("SourceOnlyPackagesAddOn preparing data..."); //Get source-only packages info var packages = new List <NuProps>(); SourceOnlyPackages = packages; var sourceOnlyPackagesByMember = new Dictionary <Member, List <NuProps> >(); SourceOnlyPackagesByMember = sourceOnlyPackagesByMember; var membersBySourceOnlyPackage = new Dictionary <NuProps, List <Member> >(); MembersBySourceOnlyPackage = membersBySourceOnlyPackage; foreach (var compilationFile in builder.CompilationFiles) { var nuProps = new NuProps(compilationFile, builder.CompilationFiles); if (!nuProps.HasNuProps) { continue; } packages.Add(nuProps); //add members to indexes foreach (var packageFile in nuProps.PackageFiles) { if (!root.AllMembersBySourceFile.TryGetValue(packageFile, out var packageMembers)) { continue; } foreach (var packageMember in packageMembers) { if (!sourceOnlyPackagesByMember.TryGetValue(packageMember, out var packagesForMember)) { packagesForMember = new List <NuProps>(); sourceOnlyPackagesByMember.Add(packageMember, packagesForMember); } packagesForMember.Add(nuProps); if (!membersBySourceOnlyPackage.TryGetValue(nuProps, out var membersForPackage)) { membersForPackage = new List <Member>(); membersBySourceOnlyPackage.Add(nuProps, membersForPackage); } membersForPackage.Add(packageMember); } } } ConsoleUtils.WriteInfo($"SourceOnlyPackagesAddOn finished preparing data - {packages.Count} source only packages found"); }
/// <summary> /// Gets the <see cref="TypeRef"/> from the <see cref="ITypeSymbol"/>. When such TypeRef doesn't exist yet, it's created. /// </summary> /// <remarks>The list of existing type references is held by <see cref="RootMemberBuilder"/>.</remarks> /// <param name="symbol">Type symbol to get the TypeRef for</param> /// <param name="root">Root builder keeping the list of all type references</param> /// <returns><see cref="TypeRef"/> corresponding to the <paramref name="symbol"/></returns> public static TypeRef GetOrCreate(ITypeSymbol symbol, RootMemberBuilder root) { var ns = symbol.ContainingNamespace?.ToDisplayString(); var name = symbol.ContainingType == null ? symbol.Name : GetOrCreate(symbol.ContainingType, root).Name + "." + symbol.Name; var namedTypeSymbol = symbol as INamedTypeSymbol; //Arrays TypeRef arrayElementType = null; if (symbol is IArrayTypeSymbol arrayTypeSymbol) { var element = arrayTypeSymbol.ElementType; var nameExt = $"[{(arrayTypeSymbol.Rank > 1 ? new string(',', arrayTypeSymbol.Rank - 1) : "")}]"; //multi array while (element is IArrayTypeSymbol elementArray) //array of arrays { nameExt += $"[{(arrayTypeSymbol.Rank > 1 ? new string(',', arrayTypeSymbol.Rank - 1) : "")}]"; element = elementArray.ElementType; } arrayElementType = GetOrCreate(element, root); ns = arrayElementType.Namespace; name = arrayElementType.Name + nameExt; } //Tuples if (symbol.IsTupleType && namedTypeSymbol != null) { var tupleElements = namedTypeSymbol.TupleElements; var tupleUnderlyingType = namedTypeSymbol.TupleUnderlyingType; var parts = new List <string>(); for (var i = 0; i < tupleUnderlyingType.TypeArguments.Length; i++) { var itemTypeName = GetOrCreate(tupleUnderlyingType.TypeArguments[i], root).ApplySpecialName(); var itemName = tupleElements[i].Name; parts.Add($"{itemTypeName} {itemName}"); } name = $"({string.Join(", ", parts)})"; ns = ""; } //Generics var needsGenericDefinition = false; var genericBaseName = name; TypeRef genericDefinition = null; if (namedTypeSymbol != null && namedTypeSymbol.IsGenericType && namedTypeSymbol.TypeParameters != null && namedTypeSymbol.TypeParameters.Length > 0) { //generic, add types to name var paramListApplied = new List <string>(); for (var i = 0; i < namedTypeSymbol.TypeParameters.Length; i++) { var arg = namedTypeSymbol.TypeArguments[i]; switch (arg) { case ITypeParameterSymbol p: { //for base class A<T> is class B<T>:A<T> or B<U>:A<U> (rename) paramListApplied.Add(p.Name); if (arg.Name != namedTypeSymbol.TypeParameters[i].Name) { needsGenericDefinition = true; //rename } break; } case IArrayTypeSymbol argArray: { //for base class A<T> is class B<U>:A<U[]>or class B:A<some type[]> if (argArray.ElementType is ITypeParameterSymbol argArrayElementParam) { //for base class A<T> is class B<U>:A<U[]> paramListApplied.Add(argArrayElementParam.Name + "[]"); } else { //for base class A<T> is class B:A<some type[]> { paramListApplied.Add(GetOrCreate(argArray.ElementType, root) + "[]"); } needsGenericDefinition = true; break; } default: //for base class A<T> is class B<U>:A<U> or class B:A<some type> paramListApplied.Add(GetOrCreate(arg, root).ToString()); needsGenericDefinition = true; break; } } name += $"<{string.Join(",", paramListApplied)}>"; if (needsGenericDefinition) { genericDefinition = GetOrCreate(namedTypeSymbol.ConstructedFrom, root); } } //End of special cases //Try to get existing item var existingItem = root.AllTypeRefs.FirstOrDefault(tr => tr.Namespace == ns && tr.Name == name); if (existingItem != null) { return(existingItem); } //Create a new TypeRef var retVal = new TypeRef { Namespace = ns ?? "", Name = name, DocumentationId = namedTypeSymbol?.GetDocumentationCommentId(), GenericBaseName = genericBaseName, GenericArity = namedTypeSymbol?.Arity ?? 0, EnumValueType = ApplySpecialName(namedTypeSymbol?.EnumUnderlyingType?.ContainingNamespace.Name, namedTypeSymbol?.EnumUnderlyingType?.Name, false), ArrayElementType = arrayElementType }; root.AllTypeRefs.Add(retVal); if (symbol.BaseType != null) { retVal.Base = GetOrCreate(symbol.BaseType, root); } if (needsGenericDefinition) { retVal.GenericDefinition = genericDefinition; } return(retVal); }