private static async Task <Document> GetTransformedDocumentAsync(Document document, SyntaxNode syntaxRoot, bool forcePreservePlacement, 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 usingDirectivesPlacement = forcePreservePlacement ? UsingDirectivesPlacement.Preserve : DeterminePlacement(compilationUnit, settings); var usingsHelper = new UsingsSorter(settings, semanticModel, compilationUnit, fileHeader); var usingsIndentation = DetermineIndentation(compilationUnit, settings.Indentation, usingDirectivesPlacement); // - 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 = BuildStripList(usingsHelper); } BuildReplaceMapForConditionalDirectives(usingsHelper, replaceMap, settings.Indentation, usingsHelper.ConditionalRoot); 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 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 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 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 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)); }