// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGeneration { /// /// Options for controlling the code produced by the . /// internal class CodeGenerationOptions { public static readonly CodeGenerationOptions Default = new CodeGenerationOptions(); /// /// A location used to determine the best place to generate a member. This is only used for /// determining which part of a partial type to generate in. If a type only has one part, or /// an API is used that specifies the type, then this is not used. A part is preferred if /// it surrounds this context location. If no part surrounds this location then a part is /// preferred if it comes from the same SyntaxTree as this location. If there is no /// such part, then any part may be used for generation. /// /// This option is not necessary if or are /// provided. /// public Location ContextLocation { get; } /// /// A hint to the code generation service to specify where the generated code should be /// placed. Code will be generated after this location if the location is valid in the type /// or symbol being generated into, and it is possible to generate the code after it. /// /// If this option is provided, neither nor are /// needed. /// public Location AfterThisLocation { get; } /// /// A hint to the code generation service to specify where the generated code should be /// placed. Code will be generated before this location if the location is valid in the type /// or symbol being generated into, and it is possible to generate the code after it. /// /// If this option is provided, neither nor are /// needed. /// public Location BeforeThisLocation { get; } /// /// True if the code generation service should add , /// and when not generating directly into a declaration, should try to automatically add imports to the file /// for any generated code. /// Defaults to true. /// public bool AddImports { get; } /// /// True if, when adding a System import, the import should be placed above non-System /// imports. Defaults to true. Only used if is true. /// public bool PlaceSystemNamespaceFirst { get; } /// /// Contains additional imports to be automatically added. This is useful for adding /// imports that are part of a list of statements. /// public IEnumerable AdditionalImports { get; } /// /// True if members of a symbol should also be generated along with the declaration. If /// false, only the symbol's declaration will be generated. /// public bool GenerateMembers { get; } /// /// True if the code generator should merge namespaces which only contain other namespaces /// into a single declaration with a dotted name. False if the nesting should be preserved /// and each namespace declaration should be nested and should only have a single non-dotted /// name. /// /// Merging can only occur if the namespace only contains a single member that is also a /// namespace. /// public bool MergeNestedNamespaces { get; } /// /// True if the code generation should put multiple attributes in a single attribute /// declaration, or if should have a separate attribute declaration for each attribute. For /// example, in C# setting this to True this would produce "[Goo, Bar]" while setting it to /// False would produce "[Goo][Bar]" /// public bool MergeAttributes { get; } /// /// True if the code generator should always generate accessibility modifiers, even if they /// are the same as the defaults for that symbol. For example, a private field in C# does /// not need its accessibility specified as it will be private by default. However, if this /// option is set to true 'private' will still be generated. /// public bool GenerateDefaultAccessibility { get; } /// /// True if the code generator should generate empty bodies for methods along with the /// method declaration. If false, only method declarations will be generated. /// public bool GenerateMethodBodies { get; } /// /// True if the code generator should generate documentation comments where available /// public bool GenerateDocumentationComments { get; } /// /// True if the code generator should automatically attempt to choose the appropriate location /// to insert members. If false and a generation location is not specified by AfterThisLocation, /// or BeforeThisLocation, members will be inserted at the end of the destination definition. /// public bool AutoInsertionLocation { get; } /// /// If is , determines if members will be /// sorted before being added to the end of the list of members. /// public bool SortMembers { get; } /// /// True if the code generator should attempt to reuse the syntax of the constituent entities, such as members, access modifier tokens, etc. while attempting to generate code. /// If any of the member symbols have zero declaring syntax references (non-source symbols) OR two or more declaring syntax references (partial definitions), then syntax is not reused. /// If false, then the code generator will always synthesize a new syntax node and ignore the declaring syntax references. /// public bool ReuseSyntax { get; } public ParseOptions ParseOptions { get; } public CodeGenerationOptions( Location contextLocation = null, Location afterThisLocation = null, Location beforeThisLocation = null, bool addImports = true, bool placeSystemNamespaceFirst = true, IEnumerable additionalImports = null, bool generateMembers = true, bool mergeNestedNamespaces = true, bool mergeAttributes = true, bool generateDefaultAccessibility = true, bool generateMethodBodies = true, bool generateDocumentationComments = false, bool autoInsertionLocation = true, bool sortMembers = true, bool reuseSyntax = false, ParseOptions parseOptions = null) { CheckLocation(contextLocation, nameof(contextLocation)); CheckLocation(afterThisLocation, nameof(afterThisLocation)); CheckLocation(beforeThisLocation, nameof(beforeThisLocation)); this.ContextLocation = contextLocation; this.AfterThisLocation = afterThisLocation; this.BeforeThisLocation = beforeThisLocation; this.AddImports = addImports; this.PlaceSystemNamespaceFirst = placeSystemNamespaceFirst; this.AdditionalImports = additionalImports ?? SpecializedCollections.EmptyEnumerable(); this.GenerateMembers = generateMembers; this.MergeNestedNamespaces = mergeNestedNamespaces; this.MergeAttributes = mergeAttributes; this.GenerateDefaultAccessibility = generateDefaultAccessibility; this.GenerateMethodBodies = generateMethodBodies; this.GenerateDocumentationComments = generateDocumentationComments; this.AutoInsertionLocation = autoInsertionLocation; this.SortMembers = sortMembers; this.ReuseSyntax = reuseSyntax; this.ParseOptions = parseOptions ?? this.BestLocation?.SourceTree.Options; } private void CheckLocation(Location location, string name) { if (location != null && !location.IsInSource) { throw new ArgumentException(WorkspacesResources.Location_must_be_null_or_from_source, name); } } internal Location BestLocation { get { return this.AfterThisLocation != null ? this.AfterThisLocation : this.BeforeThisLocation != null ? this.BeforeThisLocation : this.ContextLocation; } } public CodeGenerationOptions With( Optional contextLocation = default, Optional afterThisLocation = default, Optional beforeThisLocation = default, Optional addImports = default, Optional placeSystemNamespaceFirst = default, Optional> additionalImports = default, Optional generateMembers = default, Optional mergeNestedNamespaces = default, Optional mergeAttributes = default, Optional generateDefaultAccessibility = default, Optional generateMethodBodies = default, Optional generateDocumentationComments = default, Optional autoInsertionLocation = default, Optional sortMembers = default, Optional reuseSyntax = default, Optional parseOptions = default) { var newContextLocation = contextLocation.HasValue ? contextLocation.Value : this.ContextLocation; var newAfterThisLocation = afterThisLocation.HasValue ? afterThisLocation.Value : this.AfterThisLocation; var newBeforeThisLocation = beforeThisLocation.HasValue ? beforeThisLocation.Value : this.BeforeThisLocation; var newAddImports = addImports.HasValue ? addImports.Value : this.AddImports; var newPlaceSystemNamespaceFirst = placeSystemNamespaceFirst.HasValue ? placeSystemNamespaceFirst.Value : this.PlaceSystemNamespaceFirst; var newAdditionalImports = additionalImports.HasValue ? additionalImports.Value : this.AdditionalImports; var newGenerateMembers = generateMembers.HasValue ? generateMembers.Value : this.GenerateMembers; var newMergeNestedNamespaces = mergeNestedNamespaces.HasValue ? mergeNestedNamespaces.Value : this.MergeNestedNamespaces; var newMergeAttributes = mergeAttributes.HasValue ? mergeAttributes.Value : this.MergeAttributes; var newGenerateDefaultAccessibility = generateDefaultAccessibility.HasValue ? generateDefaultAccessibility.Value : this.GenerateDefaultAccessibility; var newGenerateMethodBodies = generateMethodBodies.HasValue ? generateMethodBodies.Value : this.GenerateMethodBodies; var newGenerateDocumentationComments = generateDocumentationComments.HasValue ? generateDocumentationComments.Value : this.GenerateDocumentationComments; var newAutoInsertionLocation = autoInsertionLocation.HasValue ? autoInsertionLocation.Value : this.AutoInsertionLocation; var newSortMembers = sortMembers.HasValue ? sortMembers.Value : this.SortMembers; var newReuseSyntax = reuseSyntax.HasValue ? reuseSyntax.Value : this.ReuseSyntax; var newParseOptions = parseOptions.HasValue ? parseOptions.Value : this.ParseOptions; return new CodeGenerationOptions( newContextLocation, newAfterThisLocation, newBeforeThisLocation, newAddImports, newPlaceSystemNamespaceFirst, newAdditionalImports, newGenerateMembers, newMergeNestedNamespaces, newMergeAttributes, newGenerateDefaultAccessibility, newGenerateMethodBodies, newGenerateDocumentationComments, newAutoInsertionLocation, newSortMembers, newReuseSyntax, newParseOptions); } } }