/// <summary> /// Extract the data that will be needed for source generation from the syntax tree provided /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary data</param> /// <returns>ExtractedTypeDefinition containing the data extracted from the syntax tree</returns> public static ExtractedTypeDefinition ExtractTypeDefinition(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { ExtractedTypeDefinition definition = new ExtractedTypeDefinition(); StringBuilder fullyQualifiedNameBuilder = new StringBuilder(); definition.TypeName = GetTypeName(extractionContext, targetTypeDeclaration); definition.TypeKind = GetTypeKind(extractionContext, targetTypeDeclaration); definition.Namespace = GetNamespace(extractionContext, targetTypeDeclaration); definition.Scope = GetScopeDefinition(extractionContext, targetTypeDeclaration); foreach (ExtractedContainerDefinition containerDefinition in ContainerDefinitionsExtractor.GetContainerDefinitions(extractionContext, targetTypeDeclaration)) { definition.ContainerDefinitions.Add(containerDefinition); fullyQualifiedNameBuilder.Append(containerDefinition.Name); fullyQualifiedNameBuilder.Append("."); } foreach (ExtractedPropertyDefinition propertyDefinition in PropertyDefinitionsExtractor.ExtractPropertyDefinitions(extractionContext, targetTypeDeclaration)) { definition.Properties.Add(propertyDefinition); } foreach (ExtractedFieldDefinition fieldDefinition in FieldDefinitionsExtractor.ExtractFieldDefinitions(extractionContext, targetTypeDeclaration)) { definition.Fields.Add(fieldDefinition); } fullyQualifiedNameBuilder.Append(definition.TypeName); definition.FullyQualifiedName = fullyQualifiedNameBuilder.ToString(); return(definition); }
/// <summary> /// Extract the scope of the type for which we will be generating code /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary information</param> /// <returns>The scope of the type for which generation is being performed</returns> private static string GetScopeDefinition(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { StringBuilder scopeNameBuilder = new StringBuilder(); foreach (SyntaxToken modifier in targetTypeDeclaration.Modifiers) { if (modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PublicKeyword)) { AppendScopeName(scopeNameBuilder, modifier.ValueText); continue; } if (modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.InternalKeyword)) { AppendScopeName(scopeNameBuilder, modifier.ValueText); continue; } if (modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.ProtectedKeyword)) { AppendScopeName(scopeNameBuilder, modifier.ValueText); continue; } if (modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PrivateKeyword)) { AppendScopeName(scopeNameBuilder, modifier.ValueText); continue; } } if (scopeNameBuilder.Length < 1) { scopeNameBuilder.Append("internal"); } return(scopeNameBuilder.ToString().Trim()); }
/// <summary> /// Determine if a property has one of the scopes requested by a caller /// </summary> /// <param name="context">The definition extraction context for this extraction</param> /// <param name="propertyDeclaration">The declaration of the property being tested</param> /// <param name="scopes">The list of scopes in which the caller is interested</param> /// <returns>Boolean true if the property has one of the scopes requested by the caller, else false</returns> private static bool HasOneOfScopes(DefinitionExtractionContext context, PropertyDeclarationSyntax propertyDeclaration, params string[] scopes) { foreach (string scope in scopes) { if (propertyDeclaration.Modifiers.Any(m => m.ValueText.Equals(scope, StringComparison.InvariantCultureIgnoreCase))) { return(true); } } return(false); }
/// <summary> /// Extract information about a single property from its declaration in the syntax tree /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The PropertyDeclarationSyntax from which to extract the necessary data</param> /// <returns>A readonly list of ExtractedPropertyDefinition containing the data extracted from the syntax tree</returns> public static ExtractedPropertyDefinition ExtractPropertyDefinition(DefinitionExtractionContext extractionContext, PropertyDeclarationSyntax propertyDeclaration) { ExtractedPropertyDefinition propertyDefinition = new ExtractedPropertyDefinition(); propertyDefinition.PropertyName = GetPropertyName(extractionContext, propertyDeclaration); propertyDefinition.TypeDefinition.TypeName = GetPropertyTypeName(extractionContext, propertyDeclaration); propertyDefinition.TypeDefinition.TypeNamespace = extractionContext.GetTypeNamespace(propertyDeclaration.Type); propertyDefinition.TypeDefinition.IsAutoSerializable = extractionContext.IsTypeAutoSerializable(propertyDeclaration.Type); propertyDefinition.TypeDefinition.ImplementsIMobileObject = extractionContext.DoesTypeImplementIMobileObject(propertyDeclaration.Type); return(propertyDefinition); }
/// <summary> /// Extract information about a single field from its declaration in the syntax tree /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="fieldDeclaration">The FieldDeclarationSyntax from which to extract the necessary data</param> /// <returns>A readonly list of ExtractedFieldDefinition containing the data extracted from the syntax tree</returns> public static ExtractedFieldDefinition ExtractFieldDefinition(DefinitionExtractionContext extractionContext, FieldDeclarationSyntax fieldDeclaration) { ExtractedFieldDefinition fieldDefinition = new ExtractedFieldDefinition(); fieldDefinition.FieldName = GetFieldName(extractionContext, fieldDeclaration); fieldDefinition.TypeDefinition.TypeName = GetFieldTypeName(extractionContext, fieldDeclaration); fieldDefinition.TypeDefinition.TypeNamespace = extractionContext.GetTypeNamespace(fieldDeclaration.Declaration.Type); fieldDefinition.TypeDefinition.IsAutoSerializable = extractionContext.IsTypeAutoSerializable(fieldDeclaration.Declaration.Type); fieldDefinition.TypeDefinition.ImplementsIMobileObject = extractionContext.DoesTypeImplementIMobileObject(fieldDeclaration.Declaration.Type); return(fieldDefinition); }
/// <summary> /// Get the field declarations for all fields which have been explicitly included in serialization /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary data</param> /// <returns>A readonly list of field declarations to be included in serialization</returns> private static List <FieldDeclarationSyntax> GetAllIncludedFields(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { List <FieldDeclarationSyntax> serializableFields; // Get any private or protected fields that are opted in with the use of the [AutoSerialized] attribute serializableFields = targetTypeDeclaration.Members.Where( m => m is FieldDeclarationSyntax fieldDeclaration && extractionContext.IsFieldDecoratedWithAutoSerialized(fieldDeclaration)) .Cast <FieldDeclarationSyntax>() .ToList(); return(serializableFields); }
/// <summary> /// Get the field declarations for all public fields which are not explicitly excluded from serialization /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary data</param> /// <returns>A readonly list of field declarations to be included in serialization</returns> private static List <FieldDeclarationSyntax> GetPublicNonExcludedFields(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { List <FieldDeclarationSyntax> serializableFields; // Get all fields that are not specifically opted out with the [AutoNonSerialized] attribute serializableFields = targetTypeDeclaration.Members.Where( m => m is FieldDeclarationSyntax fieldDeclaration && HasOneOfScopes(extractionContext, fieldDeclaration, "public") && !extractionContext.IsFieldDecoratedWithAutoNonSerialized(fieldDeclaration)) .Cast <FieldDeclarationSyntax>() .ToList(); return(serializableFields); }
/// <summary> /// Extract the namespace of the type for which we will be generating code /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary information</param> /// <returns>The namespace of the type for which generation is being performed</returns> private static string GetNamespace(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { string namespaceName = string.Empty; NamespaceDeclarationSyntax namespaceDeclaration; TypeDeclarationSyntax containingTypeDeclaration; // Iterate through the containing types should the target type be nested inside other types containingTypeDeclaration = targetTypeDeclaration; while (containingTypeDeclaration.Parent is TypeDeclarationSyntax) { containingTypeDeclaration = (TypeDeclarationSyntax)containingTypeDeclaration.Parent; } namespaceDeclaration = containingTypeDeclaration.Parent as NamespaceDeclarationSyntax; if (namespaceDeclaration is not null) { namespaceName = namespaceDeclaration.Name.ToString(); } return(namespaceName); }
/// <summary> /// Test syntax nodes to see if they represent a type for which we must generate code /// </summary> /// <param name="context">The generator context supplied by Roslyn</param> public void OnVisitSyntaxNode(GeneratorSyntaxContext generatorSyntaxContext) { SyntaxNode syntaxNode; SemanticModel model; DefinitionExtractionContext context; ExtractedTypeDefinition typeDefinition; syntaxNode = generatorSyntaxContext.Node; model = generatorSyntaxContext.SemanticModel; if (syntaxNode is not TypeDeclarationSyntax typeDeclarationSyntax) { return; } context = new DefinitionExtractionContext(generatorSyntaxContext); if (context.IsTypeAutoSerializable(typeDeclarationSyntax)) { typeDefinition = TypeDefinitionExtractor.ExtractTypeDefinition(context, typeDeclarationSyntax); Targets.Add(typeDefinition); } }
private static ExtractedContainerDefinition GetContainerDefinition(DefinitionExtractionContext extractionContext, NamespaceDeclarationSyntax namespaceDeclarationSyntax) { StringBuilder containerDefinitionBuilder = new StringBuilder(); ExtractedContainerDefinition containerDefinition; foreach (SyntaxToken modifier in namespaceDeclarationSyntax.Modifiers) { containerDefinitionBuilder.Append(modifier.ToString()); containerDefinitionBuilder.Append(" "); } containerDefinitionBuilder.Append("namespace "); containerDefinitionBuilder.Append(namespaceDeclarationSyntax.Name.ToString()); containerDefinition = new ExtractedContainerDefinition() { Name = namespaceDeclarationSyntax.Name.ToString(), FullDefinition = containerDefinitionBuilder.ToString() }; return(containerDefinition); }
private static ExtractedContainerDefinition GetContainerDefinition(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax typeDeclarationSyntax) { StringBuilder containerDefinitionBuilder = new StringBuilder(); ExtractedContainerDefinition containerDefinition; foreach (SyntaxToken modifier in typeDeclarationSyntax.Modifiers) { containerDefinitionBuilder.Append(modifier.ToString()); containerDefinitionBuilder.Append(" "); } containerDefinitionBuilder.Append(typeDeclarationSyntax.Keyword.ToString()); containerDefinitionBuilder.Append(" "); containerDefinitionBuilder.Append(typeDeclarationSyntax.Identifier.ToString()); containerDefinition = new ExtractedContainerDefinition() { Name = typeDeclarationSyntax.Identifier.ToString(), FullDefinition = containerDefinitionBuilder.ToString() }; return(containerDefinition); }
/// <summary> /// Determine if a property has both a getter and a setter /// </summary> /// <param name="context">The definition extraction context for this extraction</param> /// <param name="propertyDeclaration">The declaration of the property being tested</param> /// <returns>Boolean true if the property has both a getter and setter (of any scope), else false</returns> private static bool HasGetterAndSetter(DefinitionExtractionContext context, PropertyDeclarationSyntax propertyDeclaration) { bool hasGetter = false; bool hasSetter = false; if (propertyDeclaration.AccessorList is null) { return(false); } foreach (AccessorDeclarationSyntax accessorDeclaration in propertyDeclaration.AccessorList.Accessors) { if (accessorDeclaration.Kind() == Microsoft.CodeAnalysis.CSharp.SyntaxKind.GetAccessorDeclaration) { hasGetter = true; } if (accessorDeclaration.Kind() == Microsoft.CodeAnalysis.CSharp.SyntaxKind.SetAccessorDeclaration) { hasSetter = true; } } return(hasGetter && hasSetter); }
/// <summary> /// Get the property declarations for all fields which are to be serialized /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary data</param> /// <returns>A readonly list of field declarations to be included in serialization</returns> private static IReadOnlyList <FieldDeclarationSyntax> GetSerializableFieldDeclarations(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { List <FieldDeclarationSyntax> serializableFields; List <FieldDeclarationSyntax> optedInSerializableFields; // Get all fields that are not specifically opted out with the [AutoNonSerialized] attribute serializableFields = GetPublicNonExcludedFields(extractionContext, targetTypeDeclaration); // Add any pfields that are opted in with the use of the [AutoSerialized] attribute optedInSerializableFields = GetNonPublicIncludedFields(extractionContext, targetTypeDeclaration); serializableFields.AddRange(optedInSerializableFields); // serializableFields = GetAllIncludedFields(extractionContext, targetTypeDeclaration); return(serializableFields); }
/// <summary> /// Extract the textual definition of the kind that this type represents /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary information</param> /// <returns>The kind of the type for which generation is being performed</returns> private static string GetTypeKind(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { return(targetTypeDeclaration.Keyword.ToString()); }
/// <summary> /// Extract the name of the type for which we will be generating code /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary information</param> /// <returns>The name of the type for which generation is being performed</returns> private static string GetTypeName(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { return(targetTypeDeclaration.Identifier.ToString()); }
/// <summary> /// Extract the type name of the property for which we are building information /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The PropertyDeclarationSyntax from which to extract the necessary information</param> /// <returns>The type name of the property for which we are extracting information</returns> private static string GetPropertyTypeName(DefinitionExtractionContext extractionContext, PropertyDeclarationSyntax propertyDeclaration) { return(propertyDeclaration.Type.ToString()); }
/// <summary> /// Extract the name of the property for which we are building information /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The PropertyDeclarationSyntax from which to extract the necessary information</param> /// <returns>The name of the property for which we are extracting information</returns> private static string GetPropertyName(DefinitionExtractionContext extractionContext, PropertyDeclarationSyntax propertyDeclaration) { return(propertyDeclaration.Identifier.ValueText); }
/// <summary> /// Get the property declarations for all properties which are to be serialized /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary data</param> /// <returns>A readonly list of property declarations to be included in serialization</returns> private static IReadOnlyList <PropertyDeclarationSyntax> GetSerializablePropertyDeclarations(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { List <PropertyDeclarationSyntax> serializableProperties; List <PropertyDeclarationSyntax> optedInSerializableProperties; // Get public or internal properties that are not specifically opted out with the [AutoNonSerialized] attribute serializableProperties = GetPublicNonExcludedProperties(extractionContext, targetTypeDeclaration); // Add any private or protected properties that are opted in with the use of the [AutoSerialized] attribute optedInSerializableProperties = GetNonPublicIncludedProperties(extractionContext, targetTypeDeclaration); serializableProperties.AddRange(optedInSerializableProperties); return(serializableProperties); }
/// <summary> /// Extract the name of the field for which we are building information /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The FieldDeclarationSyntax from which to extract the necessary information</param> /// <returns>The name of the field for which we are extracting information</returns> private static string GetFieldName(DefinitionExtractionContext extractionContext, FieldDeclarationSyntax fieldDeclaration) { return(fieldDeclaration.Declaration.Variables[0].Identifier.ToString()); }
/// <summary> /// Extract information about the fields which must be serialized from a part of the syntax tree /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary data</param> /// <returns>A readonly list of ExtractedFieldDefinition containing the data extracted from the syntax tree</returns> public static IReadOnlyList <ExtractedFieldDefinition> ExtractFieldDefinitions(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { List <ExtractedFieldDefinition> propertyDefinitions = new List <ExtractedFieldDefinition>(); ExtractedFieldDefinition fieldDefinition; IReadOnlyList <FieldDeclarationSyntax> serializableFields; serializableFields = GetSerializableFieldDeclarations(extractionContext, targetTypeDeclaration); foreach (FieldDeclarationSyntax fieldDeclaration in serializableFields) { fieldDefinition = FieldDefinitionExtractor.ExtractFieldDefinition(extractionContext, fieldDeclaration); propertyDefinitions.Add(fieldDefinition); } return(propertyDefinitions); }
/// <summary> /// Extract the definitions of the containers of the type for which we will be generating code /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary information</param> /// <returns>The definitions of all of the containers of the type for which generation is being performed</returns> public static IReadOnlyList <ExtractedContainerDefinition> GetContainerDefinitions(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { NamespaceDeclarationSyntax namespaceDeclaration; TypeDeclarationSyntax containingTypeDeclaration; List <ExtractedContainerDefinition> containers = new List <ExtractedContainerDefinition>(); // Iterate through the containing types should the target type be nested inside other types containingTypeDeclaration = targetTypeDeclaration; while (containingTypeDeclaration.Parent is TypeDeclarationSyntax) { containingTypeDeclaration = (TypeDeclarationSyntax)containingTypeDeclaration.Parent; containers.Add(GetContainerDefinition(extractionContext, containingTypeDeclaration)); } namespaceDeclaration = containingTypeDeclaration.Parent as NamespaceDeclarationSyntax; if (namespaceDeclaration is not null) { containers.Add(GetContainerDefinition(extractionContext, namespaceDeclaration)); } containers.Reverse(); return(containers); }
/// <summary> /// Get the property declarations for all non-public properties which have been explicitly included in serialization /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary data</param> /// <returns>A readonly list of property declarations to be included in serialization</returns> private static List <PropertyDeclarationSyntax> GetNonPublicIncludedProperties(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { List <PropertyDeclarationSyntax> serializableProperties; // Get private or protected properties that are specifically opted in with the [AutoSerialized] attribute serializableProperties = targetTypeDeclaration.Members.Where( m => m is PropertyDeclarationSyntax propertyDeclaration && !HasOneOfScopes(extractionContext, propertyDeclaration, "public") && HasGetterAndSetter(extractionContext, propertyDeclaration) && extractionContext.IsPropertyDecoratedWithAutoSerialized(propertyDeclaration)) .Cast <PropertyDeclarationSyntax>() .ToList(); return(serializableProperties); }
/// <summary> /// Extract the type name of the field for which we are building information /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The FieldDeclarationSyntax from which to extract the necessary information</param> /// <returns>The type name of the field for which we are extracting information</returns> private static string GetFieldTypeName(DefinitionExtractionContext extractionContext, FieldDeclarationSyntax fieldDeclaration) { return(fieldDeclaration.Declaration.Type.ToString()); }
/// <summary> /// Extract information about the properties which must be serialized from a part of the syntax tree /// </summary> /// <param name="extractionContext">The definition extraction context in which the extraction is being performed</param> /// <param name="targetTypeDeclaration">The TypeDeclarationSyntax from which to extract the necessary data</param> /// <returns>A readonly list of ExtractedPropertyDefinition containing the data extracted from the syntax tree</returns> public static IReadOnlyList <ExtractedPropertyDefinition> ExtractPropertyDefinitions(DefinitionExtractionContext extractionContext, TypeDeclarationSyntax targetTypeDeclaration) { List <ExtractedPropertyDefinition> propertyDefinitions = new List <ExtractedPropertyDefinition>(); ExtractedPropertyDefinition propertyDefinition; IReadOnlyList <PropertyDeclarationSyntax> serializableProperties; serializableProperties = GetSerializablePropertyDeclarations(extractionContext, targetTypeDeclaration); foreach (PropertyDeclarationSyntax propertyDeclaration in serializableProperties) { propertyDefinition = PropertyDefinitionExtractor.ExtractPropertyDefinition(extractionContext, propertyDeclaration); propertyDefinitions.Add(propertyDefinition); } return(propertyDefinitions); }