private static void BuildReplaceMapForConditionalDirectives(UsingsHelper usingsHelper, Dictionary <UsingDirectiveSyntax, UsingDirectiveSyntax> replaceMap, IndentationOptions indentationOptions, DirectiveSpan rootSpan) { foreach (var childSpan in rootSpan.Children) { var originalUsings = usingsHelper.GetContainedUsings(childSpan); if (originalUsings.Count > 0) { // sort the original using declarations on Span.Start, in order to have the correct replace mapping. originalUsings.Sort(CompareSpanStart); var indentationSteps = IndentationHelper.GetIndentationSteps(indentationOptions, originalUsings[0].Parent); if (originalUsings[0].Parent is NamespaceDeclarationSyntax) { indentationSteps++; } var indentation = IndentationHelper.GenerateIndentationString(indentationOptions, indentationSteps); var modifiedUsings = usingsHelper.GenerateGroupedUsings(childSpan, indentation, false, qualifyNames: false); for (var i = 0; i < originalUsings.Count; i++) { replaceMap.Add(originalUsings[i], modifiedUsings[i]); } } BuildReplaceMapForConditionalDirectives(usingsHelper, replaceMap, indentationOptions, childSpan); } }
public ITextOutput Generate(ICodeSetup codeSetup, ICodeGeneratorSetup codeGeneratorSetup, IProject target, IQuantityModel model, ICodeRun run, long index) { return(new TextOutput($@" // -------------------------------------------------------------------------------------------------------------------- // <copyright file=""{run.FileName}"" company=""Hukano""> // Copyright (c) Hukano. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // </copyright> // -------------------------------------------------------------------------------------------------------------------- // <auto-generated /> namespace {NamespaceHelper.CombineNamespaces(target.RootNamespace, run.Namespace)} {{ {UsingsHelper.GetUsings(codeSetup.UseGlobalUsings | codeGeneratorSetup.UseGlobalUsings, 4, codeSetup.Usings, codeGeneratorSetup.Usings)} /// <summary> /// Interface for <see cref=""{model.Name}""/> unit selector. /// </summary> [GeneratedCode(""{this.GetType().FullName}"", ""{this.GetType().Assembly.GetName().Version}"")] public interface I{model.Name}UnitSelector : IUnitSelector {{ {this.GetUnits(model)} }} }} ")); }
private static void BuildReplaceMapForNamespaces(UsingsHelper usingsHelper, Dictionary <UsingDirectiveSyntax, UsingDirectiveSyntax> replaceMap, IndentationOptions indentationOptions, bool qualifyNames) { var usingsPerNamespace = usingsHelper .GetContainedUsings(usingsHelper.RootSpan) .GroupBy(ud => ud.Parent) .Select(gr => gr.ToList()); foreach (var usingList in usingsPerNamespace) { if (usingList.Count > 0) { // sort the original using declarations on Span.Start, in order to have the correct replace mapping. usingList.Sort(CompareSpanStart); var indentationSteps = IndentationHelper.GetIndentationSteps(indentationOptions, usingList[0].Parent); if (usingList[0].Parent is NamespaceDeclarationSyntax) { indentationSteps++; } var indentation = IndentationHelper.GenerateIndentationString(indentationOptions, indentationSteps); var modifiedUsings = usingsHelper.GenerateGroupedUsings(usingList, indentation, false, qualifyNames); for (var i = 0; i < usingList.Count; i++) { replaceMap.Add(usingList[i], modifiedUsings[i]); } } } }
private static SyntaxNode AddUsingsToNamespace(SyntaxNode newSyntaxRoot, UsingsHelper usingsHelper, string usingsIndentation, bool hasConditionalDirectives) { var rootNamespace = ((CompilationUnitSyntax)newSyntaxRoot).Members.OfType <NamespaceDeclarationSyntax>().First(); var withTrailingBlankLine = hasConditionalDirectives || rootNamespace.Members.Any() || rootNamespace.Externs.Any(); var groupedUsings = usingsHelper.GenerateGroupedUsings(usingsHelper.RootSpan, usingsIndentation, withTrailingBlankLine); groupedUsings = groupedUsings.AddRange(rootNamespace.Usings); var newRootNamespace = rootNamespace.WithUsings(groupedUsings); newSyntaxRoot = newSyntaxRoot.ReplaceNode(rootNamespace, newRootNamespace); return(newSyntaxRoot); }
public void GetUsings_Then_ResultShouldBeExpectedResult() { var usings1 = new[] { "Microsoft.Windows", "System.Collections", "Microsoft.Windows" }; var usings2 = new[] { "Microsoft.Win32", "System" }; const string expectedResult = @"using System; using System.Collections; using Microsoft.Win32; using Microsoft.Windows;"; var result = UsingsHelper.GetUsings(false, 0, true, usings1, usings2); result.Should().Be(expectedResult); }
private static SyntaxNode ReAddFileHeader(SyntaxNode syntaxRoot, SyntaxNode newSyntaxRoot) { var oldFirstToken = syntaxRoot.GetFirstToken(); if (!oldFirstToken.HasLeadingTrivia) { return(newSyntaxRoot); } var fileHeader = UsingsHelper.GetFileHeader(oldFirstToken.LeadingTrivia.ToList()); if (!fileHeader.Any()) { return(newSyntaxRoot); } var newFirstToken = newSyntaxRoot.GetFirstToken(); return(newSyntaxRoot.ReplaceToken(newFirstToken, newFirstToken.WithLeadingTrivia(fileHeader))); }
private static async Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode syntaxRoot, CancellationToken cancellationToken) { var fileHeader = GetFileHeader(syntaxRoot); var compilationUnit = (CompilationUnitSyntax)syntaxRoot; var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, cancellationToken); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var usingsHelper = new UsingsHelper(settings, semanticModel, compilationUnit, fileHeader); var namespaceCount = CountNamespaces(compilationUnit.Members); // Only move using declarations inside the namespace when // - There are no global attributes // - There is only a single namespace declared at the top level // - OrderingSettings.UsingDirectivesPlacement is set to InsideNamespace UsingDirectivesPlacement usingDirectivesPlacement; switch (settings.OrderingRules.UsingDirectivesPlacement) { case UsingDirectivesPlacement.InsideNamespace: if (compilationUnit.AttributeLists.Any() || compilationUnit.Members.Count > 1 || namespaceCount > 1) { // Override the user's setting with a more conservative one usingDirectivesPlacement = UsingDirectivesPlacement.Preserve; } else if (namespaceCount == 0) { usingDirectivesPlacement = UsingDirectivesPlacement.OutsideNamespace; } else { usingDirectivesPlacement = UsingDirectivesPlacement.InsideNamespace; } break; case UsingDirectivesPlacement.OutsideNamespace: usingDirectivesPlacement = UsingDirectivesPlacement.OutsideNamespace; break; case UsingDirectivesPlacement.Preserve: default: usingDirectivesPlacement = UsingDirectivesPlacement.Preserve; break; } string usingsIndentation; if (usingDirectivesPlacement == UsingDirectivesPlacement.InsideNamespace) { var rootNamespace = compilationUnit.Members.OfType<NamespaceDeclarationSyntax>().First(); var indentationLevel = IndentationHelper.GetIndentationSteps(settings.Indentation, rootNamespace); usingsIndentation = IndentationHelper.GenerateIndentationString(settings.Indentation, indentationLevel + 1); } else { usingsIndentation = string.Empty; } // - The strategy is to strip all using directive that are not inside a conditional directive and replace them later with a sorted list at the correct spot // - The using directives that are inside a conditional directive are replaced (in sorted order) on the spot. // - Conditional directives are not moved, as correctly parsing them is too tricky // - No using directives will be stripped when there are multiple namespaces. In that case everything is replaced on the spot. List<UsingDirectiveSyntax> stripList; var replaceMap = new Dictionary<UsingDirectiveSyntax, UsingDirectiveSyntax>(); // When there are multiple namespaces, do not move using statements outside of them, only sort. if (usingDirectivesPlacement == UsingDirectivesPlacement.Preserve) { BuildReplaceMapForNamespaces(usingsHelper, replaceMap, settings.Indentation, false); stripList = new List<UsingDirectiveSyntax>(); } else { stripList = usingsHelper.GetContainedUsings(usingsHelper.RootSpan); } BuildReplaceMapForConditionalDirectives(usingsHelper, replaceMap, settings.Indentation, usingsHelper.RootSpan); var usingSyntaxRewriter = new UsingSyntaxRewriter(stripList, replaceMap, fileHeader); var newSyntaxRoot = usingSyntaxRewriter.Visit(syntaxRoot); if (usingDirectivesPlacement == UsingDirectivesPlacement.InsideNamespace) { newSyntaxRoot = AddUsingsToNamespace(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } else if (usingDirectivesPlacement == UsingDirectivesPlacement.OutsideNamespace) { newSyntaxRoot = AddUsingsToCompilationRoot(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } // Final cleanup newSyntaxRoot = StripMultipleBlankLines(newSyntaxRoot); newSyntaxRoot = ReAddFileHeader(newSyntaxRoot, fileHeader); var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting()); return newDocument; }
private static SyntaxNode AddUsingsToCompilationRoot(SyntaxNode newSyntaxRoot, UsingsHelper usingsHelper, string usingsIndentation, bool hasConditionalDirectives) { var newCompilationUnit = (CompilationUnitSyntax)newSyntaxRoot; var withTrailingBlankLine = hasConditionalDirectives || newCompilationUnit.AttributeLists.Any() || newCompilationUnit.Members.Any() || newCompilationUnit.Externs.Any(); var groupedUsings = usingsHelper.GenerateGroupedUsings(usingsHelper.RootSpan, usingsIndentation, withTrailingBlankLine, qualifyNames: true); groupedUsings = groupedUsings.AddRange(newCompilationUnit.Usings); newSyntaxRoot = newCompilationUnit.WithUsings(groupedUsings); return newSyntaxRoot; }
private static SyntaxNode AddUsingsToNamespace(SyntaxNode newSyntaxRoot, UsingsHelper usingsHelper, string usingsIndentation, bool hasConditionalDirectives) { var rootNamespace = ((CompilationUnitSyntax)newSyntaxRoot).Members.OfType<NamespaceDeclarationSyntax>().First(); var withTrailingBlankLine = hasConditionalDirectives || rootNamespace.Members.Any() || rootNamespace.Externs.Any(); var groupedUsings = usingsHelper.GenerateGroupedUsings(usingsHelper.RootSpan, usingsIndentation, withTrailingBlankLine, qualifyNames: false); groupedUsings = groupedUsings.AddRange(rootNamespace.Usings); var newRootNamespace = rootNamespace.WithUsings(groupedUsings); newSyntaxRoot = newSyntaxRoot.ReplaceNode(rootNamespace, newRootNamespace); return newSyntaxRoot; }
private static void BuildReplaceMapForConditionalDirectives(UsingsHelper usingsHelper, Dictionary<UsingDirectiveSyntax, UsingDirectiveSyntax> replaceMap, IndentationSettings indentationSettings, DirectiveSpan rootSpan) { foreach (var childSpan in rootSpan.Children) { var originalUsings = usingsHelper.GetContainedUsings(childSpan); if (originalUsings.Count > 0) { // sort the original using declarations on Span.Start, in order to have the correct replace mapping. originalUsings.Sort(CompareSpanStart); var indentationSteps = IndentationHelper.GetIndentationSteps(indentationSettings, originalUsings[0].Parent); if (originalUsings[0].Parent is NamespaceDeclarationSyntax) { indentationSteps++; } var indentation = IndentationHelper.GenerateIndentationString(indentationSettings, indentationSteps); var modifiedUsings = usingsHelper.GenerateGroupedUsings(childSpan, indentation, false, qualifyNames: false); for (var i = 0; i < originalUsings.Count; i++) { replaceMap.Add(originalUsings[i], modifiedUsings[i]); } } BuildReplaceMapForConditionalDirectives(usingsHelper, replaceMap, indentationSettings, childSpan); } }
public ITextOutput Generate(ICodeSetup codeSetup, ICodeGeneratorSetup codeGeneratorSetup, IProject target, IQuantityModel model, ICodeRun run, long index) { return(new TextOutput( $@" // -------------------------------------------------------------------------------------------------------------------- // <copyright file=""{run.FileName}"" company=""Hukano""> // Copyright (c) Hukano. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // </copyright> // -------------------------------------------------------------------------------------------------------------------- // <auto-generated /> namespace {NamespaceHelper.CombineNamespaces(target.RootNamespace, run.Namespace)} {{ {UsingsHelper.GetUsings(codeSetup.UseGlobalUsings || codeGeneratorSetup.UseGlobalUsings, 4, codeSetup.Usings, codeGeneratorSetup.Usings)} [GeneratedCode(""{this.GetType().FullName}"", ""{this.GetType().Assembly.GetName().Version}"")] public partial struct {model.Name} : IQuantity<{model.Name}, {model.Name}UnitSelector> {{ private readonly double value; {ConstructorsHelper.GetConstructors(model)} /// <summary> /// Gets the value. /// </summary> /// <value> /// The value. /// </value> double IQuantity.Value => this.value; /// <summary> /// Gets the unit. /// </summary> /// <value> /// The unit. /// </value> public IUnit Unit {{ get; }} {StandardOperationsHelper.GetStandardOperations(model)} {ConversionOperationsHelper.GetConversionOperations(model)} {EqualityOperationsHelper.GetEqualityOperations(model)} {FormattingOperationsHelper.GetToStringOperations(model)} /// <summary> /// Creates the quantity. /// </summary> /// <param name=""value"">The quantity value.</param> /// <param name=""unit"">The quantity unit.</param> /// <returns> /// A <see cref=""{model.Name}"" />. /// </returns> public {model.Name} CreateQuantity(double value, IUnit unit) {{ return new {model.Name}(value, unit); }} /// <summary> /// Gets the result. /// </summary> /// <returns> /// An <see cref=""IQuantity"" />. /// </returns> IQuantity IDeferredQuantity.GetResult() {{ return this; }} /// <summary> /// Creates the unit selector. /// </summary> /// <returns> /// A unit selector. /// </returns> {model.Name}UnitSelector IQuantity<{model.Name}, {model.Name}UnitSelector>.CreateUnitSelector() {{ return new {model.Name}UnitSelector(); }} }} }} ")); }
public ITextOutput Generate(ICodeSetup codeSetup, ICodeGeneratorSetup codeGeneratorSetup, IProject target, IQuantityModel model, ICodeRun run, long index) { return(new TextOutput(new IndentedString($@" // -------------------------------------------------------------------------------------------------------------------- // <copyright file=""{run.FileName}"" company=""Hukano""> // Copyright (c) Hukano. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // </copyright> // -------------------------------------------------------------------------------------------------------------------- // <auto-generated /> namespace {NamespaceHelper.CombineNamespaces(target.RootNamespace, run.Namespace)} {{ {UsingsHelper.GetUsings(codeSetup.UseGlobalUsings | codeGeneratorSetup.UseGlobalUsings, 4, codeSetup.Usings, codeGeneratorSetup.Usings)} /// <summary> /// UnitSelector for <see cref=""{model.Name}""/>. /// </summary> [GeneratedCode(""{this.GetType().FullName}"", ""{this.GetType().Assembly.GetName().Version}"")] public class {model.Name}UnitSelector : IExponentSelector<{PrefixesHelper.GetPrefixesAndUnitsInterface(model)}>, {PrefixesHelper.GetPrefixesAndUnitsInterface(model)} {{ private int actualExponent = 1; private Prefix actualPrefix; /// <summary> /// Gets the base unit. /// </summary> /// <value> /// The base unit. /// </value> public Expression BaseUnit => UnitDefinitions.{model.BaseUnit}; /// <summary> /// Gets the default units. /// </summary> /// <returns> /// An <see cref=""IEnumerable{{IUnit}}"" />. /// </returns> public IEnumerable<IUnit> GetDefaultUnits() {{ {this.GetDefaultUnits(model.DefaultUnits)} }} {ExponentsHelper.GetExponents(model)} {PrefixesHelper.GetPrefixes(model)} {UnitsHelper.GetUnits(model)} /// <summary> /// Specifies the prefix by the specified factor. /// </summary> /// <param name=""factor"">The factor.</param> /// <returns>The available units.</returns> public {PrefixesHelper.GetUnitsInterface(model)} By(double factor) {{ return this.GetUnits(new FactoredPrefix(factor)); }} /// <summary> /// Specifies the exponent. /// </summary> /// <param name=""exponent"">The exponent.</param> public void SpecifyExponent(int exponent) {{ this.actualExponent = exponent; }} /// <summary> /// Specifies the prefix. /// </summary> /// <param name=""prefix"">The prefix.</param> public void SpecifyPrefix(Prefix prefix) {{ this.actualPrefix = prefix; }} /// <summary> /// Selects the unit based on the specified magnitude, prefix and base unit. /// </summary> /// <param name=""unit"">The unit.</param> /// <returns> /// An <see cref=""Expression""/>. /// </returns> public Expression SpecifyUnit(IUnit unit) {{ return UnitSelectorHelper.CreateExpression(ref this.actualExponent, ref this.actualPrefix, unit); }} /// <summary> /// Gets the prefixes and unit selector. /// </summary> /// <param name=""exponent"">The exponent.</param> /// <returns> /// The available prefixes and units. /// </returns> private {PrefixesHelper.GetPrefixesAndUnitsInterface(model)} GetPrefixesAndUnits(int exponent) {{ this.SpecifyExponent(exponent); return this; }} /// <summary> /// Gets the unit selector. /// </summary> /// <param name=""prefix"">The prefix.</param> /// <returns>The available units.</returns> private {PrefixesHelper.GetUnitsInterface(model)} GetUnits(Prefix prefix) {{ this.SpecifyPrefix(prefix); return this; }} }} }} "))); }
private static async Task ParseCsharpFiles(string solutionFullPath, bool previewOnly, string tfsExePath) { foreach (var item in await GetUnitTestItems(solutionFullPath)) { var stub2Moq = new MsTestStub2Moq(item.Workspace, item.File, item.SemanticModel); var rewriter = new MsTestStubRewriter(stub2Moq); var newTestFile = rewriter.Visit(item.Root); if (newTestFile != item.Root) { var root = newTestFile.SyntaxTree.GetRoot(); var compilationUnitSyntax = root as CompilationUnitSyntax; if (compilationUnitSyntax != null) { bool hasMoqUsing = compilationUnitSyntax.Usings .Select(u => u.Name) .OfType <IdentifierNameSyntax>() .Any(u => u.Identifier.ValueText.Equals("Moq", StringComparison.InvariantCulture)); if (!hasMoqUsing) { var moq = SyntaxFactory.ParseName("Moq"); var moqUsing = SyntaxFactory.UsingDirective(moq).NormalizeWhitespace().WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed); root = compilationUnitSyntax.AddUsings(moqUsing); } } var newDoc = item.File.WithSyntaxRoot(root); var newSemanticModel = await newDoc.GetSemanticModelAsync().ConfigureAwait(false); root = await newDoc.GetSyntaxRootAsync(); // remove useless usings (.Fakes and others) root = UsingsHelper.RemoveUnusedImportDirectives(newSemanticModel, root, CancellationToken.None, (r, usingNode) => { if (usingNode.ToString().Contains("Moq")) { return(!r.ToString().Contains("Mock")); } else { return(true); } }); if (previewOnly) { Console.WriteLine(newTestFile.ToFullString()); } else { if (!string.IsNullOrEmpty(tfsExePath)) { TfsCheckOut(tfsExePath, item.File.FilePath); } using (var writer = new StreamWriter(item.File.FilePath, false, System.Text.UTF8Encoding.UTF8)) { root.WriteTo(writer); } } } } }
private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode syntaxRoot, CancellationToken cancellationToken) { var compilationUnit = (CompilationUnitSyntax)syntaxRoot; var indentationOptions = IndentationOptions.FromDocument(document); var usingsHelper = new UsingsHelper(document, compilationUnit); var namespaceCount = CountNamespaces(compilationUnit.Members); // Only move using declarations inside the namespace when // - SA1200 is enabled // - There are no global attributes // - There is only a single namespace declared at the top level var moveInsideNamespace = !document.Project.CompilationOptions.IsAnalyzerSuppressed(SA1200UsingDirectivesMustBePlacedWithinNamespace.DiagnosticId) && !compilationUnit.AttributeLists.Any() && compilationUnit.Members.Count == 1 && namespaceCount == 1; string usingsIndentation; if (moveInsideNamespace) { var rootNamespace = compilationUnit.Members.OfType<NamespaceDeclarationSyntax>().First(); var indentationLevel = IndentationHelper.GetIndentationSteps(indentationOptions, rootNamespace); usingsIndentation = IndentationHelper.GenerateIndentationString(indentationOptions, indentationLevel + 1); } else { usingsIndentation = string.Empty; } // - The strategy is to strip all using directive that are not inside a conditional directive and replace them later with a sorted list at the correct spot // - The using directives that are inside a conditional directive are replaced (in sorted order) on the spot. // - Conditional directives are not moved, as correctly parsing them is too tricky // - No using directives will be stripped when there are multiple namespaces. In that case everything is replaced on the spot. List<UsingDirectiveSyntax> stripList; var replaceMap = new Dictionary<UsingDirectiveSyntax, UsingDirectiveSyntax>(); // When there are multiple namespaces, do not move using statements outside of them, only sort. if (namespaceCount > 1) { BuildReplaceMapForNamespaces(usingsHelper, replaceMap, indentationOptions); stripList = new List<UsingDirectiveSyntax>(); } else { stripList = usingsHelper.GetContainedUsings(usingsHelper.RootSpan); } BuildReplaceMapForConditionalDirectives(usingsHelper, replaceMap, indentationOptions, usingsHelper.RootSpan); var usingSyntaxRewriter = new UsingSyntaxRewriter(stripList, replaceMap); var newSyntaxRoot = usingSyntaxRewriter.Visit(syntaxRoot); if (moveInsideNamespace) { newSyntaxRoot = AddUsingsToNamespace(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } else if (namespaceCount <= 1) { newSyntaxRoot = AddUsingsToCompilationRoot(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } newSyntaxRoot = ReAddFileHeader(syntaxRoot, newSyntaxRoot); var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting()); return Task.FromResult(newDocument); }
private static Task <Document> GetTransformedDocumentAsync(Document document, SyntaxNode syntaxRoot, CancellationToken cancellationToken) { var compilationUnit = (CompilationUnitSyntax)syntaxRoot; var indentationOptions = IndentationOptions.FromDocument(document); var usingsHelper = new UsingsHelper(document, compilationUnit); var namespaceCount = CountNamespaces(compilationUnit.Members); // Only move using declarations inside the namespace when // - SA1200 is enabled // - There are no global attributes // - There is only a single namespace declared at the top level var moveInsideNamespace = !document.Project.CompilationOptions.IsAnalyzerSuppressed(SA1200UsingDirectivesMustBePlacedWithinNamespace.DiagnosticId) && !compilationUnit.AttributeLists.Any() && compilationUnit.Members.Count == 1 && namespaceCount == 1; string usingsIndentation; if (moveInsideNamespace) { var rootNamespace = compilationUnit.Members.OfType <NamespaceDeclarationSyntax>().First(); var indentationLevel = IndentationHelper.GetIndentationSteps(indentationOptions, rootNamespace); usingsIndentation = IndentationHelper.GenerateIndentationString(indentationOptions, indentationLevel + 1); } else { usingsIndentation = string.Empty; } // - The strategy is to strip all using directive that are not inside a conditional directive and replace them later with a sorted list at the correct spot // - The using directives that are inside a conditional directive are replaced (in sorted order) on the spot. // - Conditional directives are not moved, as correctly parsing them is too tricky // - No using directives will be stripped when there are multiple namespaces. In that case everything is replaced on the spot. List <UsingDirectiveSyntax> stripList; var replaceMap = new Dictionary <UsingDirectiveSyntax, UsingDirectiveSyntax>(); // When there are multiple namespaces, do not move using statements outside of them, only sort. if (namespaceCount > 1) { BuildReplaceMapForNamespaces(usingsHelper, replaceMap, indentationOptions); stripList = new List <UsingDirectiveSyntax>(); } else { stripList = usingsHelper.GetContainedUsings(usingsHelper.RootSpan); } BuildReplaceMapForConditionalDirectives(usingsHelper, replaceMap, indentationOptions, usingsHelper.RootSpan); var usingSyntaxRewriter = new UsingSyntaxRewriter(stripList, replaceMap); var newSyntaxRoot = usingSyntaxRewriter.Visit(syntaxRoot); if (moveInsideNamespace) { newSyntaxRoot = AddUsingsToNamespace(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } else if (namespaceCount <= 1) { newSyntaxRoot = AddUsingsToCompilationRoot(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } newSyntaxRoot = ReAddFileHeader(syntaxRoot, newSyntaxRoot); var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting()); return(Task.FromResult(newDocument)); }
private static SyntaxNode AddUsingsToCompilationRoot(SyntaxNode newSyntaxRoot, UsingsHelper usingsHelper, string usingsIndentation, bool hasConditionalDirectives) { var newCompilationUnit = (CompilationUnitSyntax)newSyntaxRoot; var withTrailingBlankLine = hasConditionalDirectives || newCompilationUnit.AttributeLists.Any() || newCompilationUnit.Members.Any() || newCompilationUnit.Externs.Any(); var groupedUsings = usingsHelper.GenerateGroupedUsings(usingsHelper.RootSpan, usingsIndentation, withTrailingBlankLine, qualifyNames: true); groupedUsings = groupedUsings.AddRange(newCompilationUnit.Usings); newSyntaxRoot = newCompilationUnit.WithUsings(groupedUsings); return(newSyntaxRoot); }
private static async Task <Document> GetTransformedDocumentAsync(Document document, SyntaxNode syntaxRoot, CancellationToken cancellationToken) { var fileHeader = GetFileHeader(syntaxRoot); var compilationUnit = (CompilationUnitSyntax)syntaxRoot; var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, cancellationToken); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var indentationOptions = IndentationOptions.FromDocument(document); var usingsHelper = new UsingsHelper(settings, semanticModel, compilationUnit, fileHeader); var namespaceCount = CountNamespaces(compilationUnit.Members); // Only move using declarations inside the namespace when // - There are no global attributes // - There is only a single namespace declared at the top level // - OrderingSettings.UsingDirectivesPlacement is set to InsideNamespace UsingDirectivesPlacement usingDirectivesPlacement; switch (settings.OrderingRules.UsingDirectivesPlacement) { case UsingDirectivesPlacement.InsideNamespace: if (compilationUnit.AttributeLists.Any() || compilationUnit.Members.Count > 1 || namespaceCount > 1) { // Override the user's setting with a more conservative one usingDirectivesPlacement = UsingDirectivesPlacement.Preserve; } else if (namespaceCount == 0) { usingDirectivesPlacement = UsingDirectivesPlacement.OutsideNamespace; } else { usingDirectivesPlacement = UsingDirectivesPlacement.InsideNamespace; } break; case UsingDirectivesPlacement.OutsideNamespace: usingDirectivesPlacement = UsingDirectivesPlacement.OutsideNamespace; break; case UsingDirectivesPlacement.Preserve: default: usingDirectivesPlacement = UsingDirectivesPlacement.Preserve; break; } string usingsIndentation; if (usingDirectivesPlacement == UsingDirectivesPlacement.InsideNamespace) { var rootNamespace = compilationUnit.Members.OfType <NamespaceDeclarationSyntax>().First(); var indentationLevel = IndentationHelper.GetIndentationSteps(indentationOptions, rootNamespace); usingsIndentation = IndentationHelper.GenerateIndentationString(indentationOptions, indentationLevel + 1); } else { usingsIndentation = string.Empty; } // - The strategy is to strip all using directive that are not inside a conditional directive and replace them later with a sorted list at the correct spot // - The using directives that are inside a conditional directive are replaced (in sorted order) on the spot. // - Conditional directives are not moved, as correctly parsing them is too tricky // - No using directives will be stripped when there are multiple namespaces. In that case everything is replaced on the spot. List <UsingDirectiveSyntax> stripList; var replaceMap = new Dictionary <UsingDirectiveSyntax, UsingDirectiveSyntax>(); // When there are multiple namespaces, do not move using statements outside of them, only sort. if (usingDirectivesPlacement == UsingDirectivesPlacement.Preserve) { BuildReplaceMapForNamespaces(usingsHelper, replaceMap, indentationOptions, false); stripList = new List <UsingDirectiveSyntax>(); } else { stripList = usingsHelper.GetContainedUsings(usingsHelper.RootSpan); } BuildReplaceMapForConditionalDirectives(usingsHelper, replaceMap, indentationOptions, usingsHelper.RootSpan); var usingSyntaxRewriter = new UsingSyntaxRewriter(stripList, replaceMap, fileHeader); var newSyntaxRoot = usingSyntaxRewriter.Visit(syntaxRoot); if (usingDirectivesPlacement == UsingDirectivesPlacement.InsideNamespace) { newSyntaxRoot = AddUsingsToNamespace(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } else if (usingDirectivesPlacement == UsingDirectivesPlacement.OutsideNamespace) { newSyntaxRoot = AddUsingsToCompilationRoot(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } // Final cleanup newSyntaxRoot = StripMultipleBlankLines(newSyntaxRoot); newSyntaxRoot = ReAddFileHeader(newSyntaxRoot, fileHeader); var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting()); return(newDocument); }
private static void BuildReplaceMapForNamespaces(UsingsHelper usingsHelper, Dictionary<UsingDirectiveSyntax, UsingDirectiveSyntax> replaceMap, IndentationSettings indentationSettings, bool qualifyNames) { var usingsPerNamespace = usingsHelper .GetContainedUsings(usingsHelper.RootSpan) .GroupBy(ud => ud.Parent) .Select(gr => gr.ToList()); foreach (var usingList in usingsPerNamespace) { if (usingList.Count > 0) { // sort the original using declarations on Span.Start, in order to have the correct replace mapping. usingList.Sort(CompareSpanStart); var indentationSteps = IndentationHelper.GetIndentationSteps(indentationSettings, usingList[0].Parent); if (usingList[0].Parent is NamespaceDeclarationSyntax) { indentationSteps++; } var indentation = IndentationHelper.GenerateIndentationString(indentationSettings, indentationSteps); var modifiedUsings = usingsHelper.GenerateGroupedUsings(usingList, indentation, false, qualifyNames); for (var i = 0; i < usingList.Count; i++) { replaceMap.Add(usingList[i], modifiedUsings[i]); } } } }