public static void HandleSyntaxTree(SyntaxTreeAnalysisContext context, StyleCopSettings settings) { var syntaxRoot = context.Tree.GetRoot(context.CancellationToken); var firstTypeDeclaration = GetFirstTypeDeclaration(syntaxRoot); if (firstTypeDeclaration == null) { return; } if (firstTypeDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword)) { return; } string suffix; var fileName = FileNameHelpers.GetFileNameAndSuffix(context.Tree.FilePath, out suffix); var expectedFileName = FileNameHelpers.GetConventionalFileName(firstTypeDeclaration, settings.DocumentationRules.FileNamingConvention); if (string.Compare(fileName, expectedFileName, StringComparison.OrdinalIgnoreCase) != 0) { if (settings.DocumentationRules.FileNamingConvention == FileNamingConvention.StyleCop && string.Compare(fileName, FileNameHelpers.GetSimpleFileName(firstTypeDeclaration), StringComparison.OrdinalIgnoreCase) == 0) { return; } var properties = ImmutableDictionary.Create<string, string>() .Add(ExpectedFileNameKey, expectedFileName + suffix); context.ReportDiagnostic(Diagnostic.Create(Descriptor, firstTypeDeclaration.Identifier.GetLocation(), properties)); } }
private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context, StyleCopSettings settings) { SyntaxNode root = context.Tree.GetCompilationUnitRoot(context.CancellationToken); ImmutableArray<TextSpan> excludedSpans; if (!LocateExcludedSpans(root, out excludedSpans)) { return; } ReportIncorrectTabUsage(context, settings.Indentation, excludedSpans); }
private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings) { var elementOrder = settings.OrderingRules.ElementOrder; int staticIndex = elementOrder.IndexOf(OrderingTrait.Static); if (staticIndex < 0) { return; } var compilationUnit = (NamespaceDeclarationSyntax)context.Node; HandleMemberList(context, elementOrder, staticIndex, compilationUnit.Members); }
private static void HandleCompilationUnit(SyntaxNodeAnalysisContext context, StyleCopSettings settings) { if (!settings.OrderingRules.SystemUsingDirectivesFirst) { return; } var compilationUnit = context.Node as CompilationUnitSyntax; var usings = compilationUnit.Usings; ProcessUsingsAndReportDiagnostic(usings, context); }
private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings) { if (!settings.OrderingRules.SystemUsingDirectivesFirst) { return; } var namespaceDeclaration = context.Node as NamespaceDeclarationSyntax; var usings = namespaceDeclaration.Usings; ProcessUsingsAndReportDiagnostic(usings, context); }
private static SyntaxNode ReplaceHeader(Document document, SyntaxNode root, StyleCopSettings settings) { // Skip single line comments, whitespace, and end of line trivia until a blank line is encountered. SyntaxTriviaList trivia = root.GetLeadingTrivia(); bool onBlankLine = false; while (trivia.Any()) { bool done = false; switch (trivia[0].Kind()) { case SyntaxKind.SingleLineCommentTrivia: trivia = trivia.RemoveAt(0); onBlankLine = false; break; case SyntaxKind.WhitespaceTrivia: trivia = trivia.RemoveAt(0); break; case SyntaxKind.EndOfLineTrivia: trivia = trivia.RemoveAt(0); if (onBlankLine) { done = true; } else { onBlankLine = true; } break; default: done = true; break; } if (done) { break; } } string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); return root.WithLeadingTrivia(CreateNewHeader(document.Name, settings, newLineText).Add(SyntaxFactory.CarriageReturnLineFeed).Add(SyntaxFactory.CarriageReturnLineFeed).AddRange(trivia)); }
public static void HandleEnumMemberDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings) { if (context.GetDocumentationMode() != DocumentationMode.Diagnose) { return; } EnumMemberDeclarationSyntax declaration = (EnumMemberDeclarationSyntax)context.Node; Accessibility declaredAccessibility = declaration.GetDeclaredAccessibility(); Accessibility effectiveAccessibility = declaration.GetEffectiveAccessibility(context.SemanticModel, context.CancellationToken); if (NeedsComment(settings.DocumentationRules, declaration.Kind(), declaration.Parent.Kind(), declaredAccessibility, effectiveAccessibility)) { if (!XmlCommentHelper.HasDocumentation(declaration)) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, declaration.Identifier.GetLocation())); } } }
private static void CheckCopyrightHeader(SyntaxTreeAnalysisContext context, Compilation compilation, StyleCopSettings settings, XmlFileHeader fileHeader) { var copyrightElement = fileHeader.GetElement("copyright"); if (copyrightElement == null) { context.ReportDiagnostic(Diagnostic.Create(SA1634Descriptor, fileHeader.GetLocation(context.Tree))); return; } if (!compilation.IsAnalyzerSuppressed(SA1637Identifier)) { CheckFile(context, compilation, fileHeader, copyrightElement, settings); } if (!compilation.IsAnalyzerSuppressed(SA1640Identifier)) { CheckCompanyName(context, compilation, fileHeader, copyrightElement, settings); } if (!compilation.IsAnalyzerSuppressed(SA1635Identifier)) { CheckCopyrightText(context, compilation, fileHeader, copyrightElement, settings); } }
private static void CheckFile(SyntaxTreeAnalysisContext context, Compilation compilation, XmlFileHeader fileHeader, XElement copyrightElement, StyleCopSettings settings) { var fileAttribute = copyrightElement.Attribute("file"); if (fileAttribute == null) { var location = fileHeader.GetElementLocation(context.Tree, copyrightElement); context.ReportDiagnostic(Diagnostic.Create(SA1637Descriptor, location)); return; } if (compilation.IsAnalyzerSuppressed(SA1638Identifier)) { return; } var fileName = Path.GetFileName(context.Tree.FilePath); if (string.CompareOrdinal(fileAttribute.Value, fileName) != 0) { var location = fileHeader.GetElementLocation(context.Tree, copyrightElement); context.ReportDiagnostic(Diagnostic.Create(SA1638Descriptor, location)); } }
private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context, StyleCopSettings settings) { var endOfFileToken = context.Tree.GetRoot().GetLastToken(includeZeroWidth: true); TextSpan reportedSpan = new TextSpan(endOfFileToken.SpanStart, 0); SyntaxTrivia precedingTrivia = default(SyntaxTrivia); bool checkPrecedingToken; if (endOfFileToken.HasLeadingTrivia) { var leadingTrivia = endOfFileToken.LeadingTrivia; var trailingWhitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(leadingTrivia); if (trailingWhitespaceIndex > 0) { checkPrecedingToken = false; reportedSpan = TextSpan.FromBounds(leadingTrivia[trailingWhitespaceIndex].SpanStart, reportedSpan.End); precedingTrivia = leadingTrivia[trailingWhitespaceIndex - 1]; } else if (trailingWhitespaceIndex == 0) { checkPrecedingToken = true; reportedSpan = TextSpan.FromBounds(leadingTrivia[trailingWhitespaceIndex].SpanStart, reportedSpan.End); } else { checkPrecedingToken = false; precedingTrivia = leadingTrivia.Last(); } } else { checkPrecedingToken = true; } if (checkPrecedingToken) { var previousToken = endOfFileToken.GetPreviousToken(includeZeroWidth: true, includeSkipped: true, includeDirectives: true, includeDocumentationComments: true); var trailingWhitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(previousToken.TrailingTrivia); if (trailingWhitespaceIndex > 0) { reportedSpan = TextSpan.FromBounds(previousToken.TrailingTrivia[trailingWhitespaceIndex].SpanStart, reportedSpan.End); precedingTrivia = previousToken.TrailingTrivia[trailingWhitespaceIndex - 1]; } else if (trailingWhitespaceIndex == 0) { reportedSpan = TextSpan.FromBounds(previousToken.TrailingTrivia[trailingWhitespaceIndex].SpanStart, reportedSpan.End); precedingTrivia = default(SyntaxTrivia); } else { if (previousToken.TrailingTrivia.Count > 0) { precedingTrivia = previousToken.TrailingTrivia.Last(); } } } if (precedingTrivia.IsDirective) { DirectiveTriviaSyntax directiveTriviaSyntax = precedingTrivia.GetStructure() as DirectiveTriviaSyntax; if (directiveTriviaSyntax != null && directiveTriviaSyntax.EndOfDirectiveToken.HasTrailingTrivia) { var trailingWhitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(directiveTriviaSyntax.EndOfDirectiveToken.TrailingTrivia); if (trailingWhitespaceIndex >= 0) { reportedSpan = TextSpan.FromBounds(directiveTriviaSyntax.EndOfDirectiveToken.TrailingTrivia[trailingWhitespaceIndex].SpanStart, reportedSpan.End); } } } else if (precedingTrivia.IsKind(SyntaxKind.EndOfLineTrivia)) { reportedSpan = TextSpan.FromBounds(precedingTrivia.SpanStart, reportedSpan.End); } SourceText sourceText = context.Tree.GetText(context.CancellationToken); string trailingWhitespaceText = sourceText.ToString(reportedSpan); int firstNewline = trailingWhitespaceText.IndexOf('\n'); int secondNewline = firstNewline >= 0 ? trailingWhitespaceText.IndexOf('\n', firstNewline + 1) : -1; DiagnosticDescriptor descriptorToReport; switch (settings.LayoutRules.NewlineAtEndOfFile) { case EndOfFileHandling.Omit: if (firstNewline < 0) { return; } descriptorToReport = DescriptorOmit; break; case EndOfFileHandling.Require: if (firstNewline >= 0 && firstNewline == trailingWhitespaceText.Length - 1) { return; } descriptorToReport = DescriptorRequire; break; case EndOfFileHandling.Allow: default: if (secondNewline < 0) { // 1. A newline is allowed but not required // 2. If a newline is included, it cannot be followed by whitespace if (firstNewline < 0 || firstNewline == trailingWhitespaceText.Length - 1) { return; } } descriptorToReport = DescriptorAllow; break; } context.ReportDiagnostic(Diagnostic.Create(descriptorToReport, Location.Create(context.Tree, reportedSpan))); }
private static void CheckCopyrightText(SyntaxTreeAnalysisContext context, Compilation compilation, XmlFileHeader fileHeader, XElement copyrightElement, StyleCopSettings settings) { var copyrightText = copyrightElement.Value; if (string.IsNullOrWhiteSpace(copyrightText)) { var location = fileHeader.GetElementLocation(context.Tree, copyrightElement); context.ReportDiagnostic(Diagnostic.Create(SA1635Descriptor, location)); return; } if (compilation.IsAnalyzerSuppressed(SA1636Identifier)) { return; } if (string.Equals(settings.DocumentationRules.CopyrightText, DocumentationSettings.DefaultCopyrightText, StringComparison.OrdinalIgnoreCase)) { // The copyright text is meaningless until the company name is configured by the user. return; } if (string.CompareOrdinal(copyrightText.Trim(' ', '\r', '\n'), settings.DocumentationRules.CopyrightText) != 0) { var location = fileHeader.GetElementLocation(context.Tree, copyrightElement); context.ReportDiagnostic(Diagnostic.Create(SA1636Descriptor, location)); } }
private static void HandleCompilationUnit(SyntaxNodeAnalysisContext context, StyleCopSettings settings) { var compilationUnit = (CompilationUnitSyntax)context.Node; ProcessUsings(context, settings.OrderingRules, compilationUnit.Usings); }
private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings) { var namespaceDeclaration = (NamespaceDeclarationSyntax)context.Node; ProcessUsings(context, settings.OrderingRules, namespaceDeclaration.Usings); }
private static string WrapInXmlComment(string prefixWithLeadingSpaces, string copyrightText, string filename, StyleCopSettings settings, string newLineText) { string encodedFilename = new XAttribute("t", filename).ToString().Substring(2).Trim('"'); string encodedCompanyName = new XAttribute("t", settings.DocumentationRules.CompanyName).ToString().Substring(2).Trim('"'); string encodedCopyrightText = new XText(copyrightText).ToString(); return $"{prefixWithLeadingSpaces} <copyright file=\"{encodedFilename}\" company=\"{encodedCompanyName}\">" + newLineText + encodedCopyrightText + newLineText + prefixWithLeadingSpaces + " </copyright>"; }
private static string WrapInXmlComment(string copyrightText, string filename, StyleCopSettings settings) { return $@"// <copyright file=""{filename}"" company=""{settings.DocumentationRules.CompanyName}""> {copyrightText} // </copyright>"; }
protected SettingsFile() { this.settings = new StyleCopSettings(); }
private static SyntaxNode AddHeader(Document document, SyntaxNode root, string name, StyleCopSettings settings) { string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); var newLineTrivia = SyntaxFactory.EndOfLine(newLineText); var newTrivia = CreateNewHeader("//", name, settings, newLineText).Add(newLineTrivia).Add(newLineTrivia); newTrivia = newTrivia.AddRange(root.GetLeadingTrivia()); return root.WithLeadingTrivia(newTrivia); }
private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context, StyleCopSettings settings) { if (settings.Indentation.UseTabs) { return; } SyntaxNode root = context.Tree.GetCompilationUnitRoot(context.CancellationToken); foreach (var trivia in root.DescendantTrivia(descendIntoTrivia: true)) { switch (trivia.Kind()) { case SyntaxKind.WhitespaceTrivia: case SyntaxKind.DocumentationCommentExteriorTrivia: case SyntaxKind.SingleLineCommentTrivia: case SyntaxKind.MultiLineCommentTrivia: HandleWhitespaceTrivia(context, trivia); break; case SyntaxKind.SingleLineDocumentationCommentTrivia: case SyntaxKind.MultiLineDocumentationCommentTrivia: HandleDocumentationCommentTrivia(context, trivia); break; default: break; } } }
/// <summary> /// Creates a solution that will be used as parent for the sources that need to be checked. /// </summary> /// <param name="projectId">The project identifier to use.</param> /// <param name="language">The language for which the solution is being created.</param> /// <returns>The created solution.</returns> protected virtual Solution CreateSolution(ProjectId projectId, string language) { var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true); Solution solution = new AdhocWorkspace() .CurrentSolution .AddProject(projectId, TestProjectName, TestProjectName, language) .WithProjectCompilationOptions(projectId, compilationOptions) .AddMetadataReference(projectId, MetadataReferences.CorlibReference) .AddMetadataReference(projectId, MetadataReferences.SystemReference) .AddMetadataReference(projectId, MetadataReferences.SystemCoreReference) .AddMetadataReference(projectId, MetadataReferences.CSharpSymbolsReference) .AddMetadataReference(projectId, MetadataReferences.CodeAnalysisReference); solution.Workspace.Options = solution.Workspace.Options .WithChangedOption(FormattingOptions.IndentationSize, language, this.IndentationSize) .WithChangedOption(FormattingOptions.TabSize, language, this.TabSize) .WithChangedOption(FormattingOptions.UseTabs, language, this.UseTabs); var settings = this.GetSettings(); StyleCopSettings defaultSettings = new StyleCopSettings(); if (this.IndentationSize != defaultSettings.Indentation.IndentationSize || this.UseTabs != defaultSettings.Indentation.UseTabs || this.TabSize != defaultSettings.Indentation.TabSize) { var indentationSettings = $@" {{ ""settings"": {{ ""indentation"": {{ ""indentationSize"": {this.IndentationSize}, ""useTabs"": {this.UseTabs.ToString().ToLowerInvariant()}, ""tabSize"": {this.TabSize} }} }} }} "; if (string.IsNullOrEmpty(settings)) { settings = indentationSettings; } else { JObject mergedSettings = JsonConvert.DeserializeObject<JObject>(settings); mergedSettings.Merge(JsonConvert.DeserializeObject<JObject>(indentationSettings)); settings = JsonConvert.SerializeObject(mergedSettings); } } if (!string.IsNullOrEmpty(settings)) { var documentId = DocumentId.CreateNewId(projectId); solution = solution.AddAdditionalDocument(documentId, SettingsHelper.SettingsFileName, settings); } ParseOptions parseOptions = solution.GetProject(projectId).ParseOptions; return solution.WithProjectParseOptions(projectId, parseOptions.WithDocumentationMode(DocumentationMode.Diagnose)); }
private static SyntaxTriviaList CreateNewHeader(string filename, StyleCopSettings settings) { var copyrightText = "// " + GetCopyrightText(settings.DocumentationRules.CopyrightText); var newHeader = settings.DocumentationRules.XmlHeader ? WrapInXmlComment(copyrightText, filename, settings) : copyrightText; return SyntaxFactory.ParseLeadingTrivia(newHeader); }
private static void CheckCompanyName(SyntaxTreeAnalysisContext context, Compilation compilation, XmlFileHeader fileHeader, XElement copyrightElement, StyleCopSettings settings) { var companyName = copyrightElement.Attribute("company")?.Value; if (string.IsNullOrWhiteSpace(companyName)) { var location = fileHeader.GetElementLocation(context.Tree, copyrightElement); context.ReportDiagnostic(Diagnostic.Create(SA1640Descriptor, location)); return; } if (compilation.IsAnalyzerSuppressed(SA1641Identifier)) { return; } if (string.CompareOrdinal(companyName, settings.DocumentationRules.CompanyName) != 0) { var location = fileHeader.GetElementLocation(context.Tree, copyrightElement); context.ReportDiagnostic(Diagnostic.Create(SA1641Descriptor, location)); } }
private static SyntaxNode AddHeader(SyntaxNode root, string name, StyleCopSettings settings) { var newTrivia = CreateNewHeader(name, settings).Add(SyntaxFactory.CarriageReturnLineFeed).Add(SyntaxFactory.CarriageReturnLineFeed); newTrivia = newTrivia.AddRange(root.GetLeadingTrivia()); return root.WithLeadingTrivia(newTrivia); }
private static void HandleTypeDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings) { var elementOrder = settings.OrderingRules.ElementOrder; int accessibilityIndex = elementOrder.IndexOf(OrderingTrait.Accessibility); if (accessibilityIndex < 0) { return; } var typeDeclaration = (TypeDeclarationSyntax)context.Node; HandleMemberList(context, elementOrder, accessibilityIndex, typeDeclaration.Members, AccessLevel.Private); }
private static string WrapInXmlComment(string copyrightText, string filename, StyleCopSettings settings, string newLineText) { return $"// <copyright file=\"{filename}\" company=\"{settings.DocumentationRules.CompanyName}\">" + newLineText + copyrightText + newLineText + "// </copyright>"; }
private static SyntaxNode ReplaceHeader(Document document, SyntaxNode root, StyleCopSettings settings, bool isMalformedHeader) { // If the header is well formed Xml then we parse out the copyright otherwise // Skip single line comments, whitespace, and end of line trivia until a blank line is encountered. SyntaxTriviaList trivia = root.GetLeadingTrivia(); bool onBlankLine = false; bool inCopyright = isMalformedHeader; int? copyrightTriviaIndex = null; var removalList = new System.Collections.Generic.List<int>(); var leadingSpaces = string.Empty; string possibleLeadingSpaces = string.Empty; // Need to do this with index so we get the line endings correct. for (int i = 0; i < trivia.Count; i++) { var triviaLine = trivia[i]; bool done = false; switch (triviaLine.Kind()) { case SyntaxKind.SingleLineCommentTrivia: if (possibleLeadingSpaces != string.Empty) { leadingSpaces = possibleLeadingSpaces; } if (!isMalformedHeader) { var openingTag = triviaLine.ToFullString().Contains("<copyright "); var closingTag = triviaLine.ToFullString().Contains("</copyright>") || (openingTag && triviaLine.ToFullString().Trim().EndsWith("/>")); if (openingTag) { inCopyright = !closingTag; copyrightTriviaIndex = i; } else if (inCopyright) { removalList.Add(i); inCopyright = !closingTag; } } else { removalList.Add(i); } onBlankLine = false; break; case SyntaxKind.WhitespaceTrivia: if (leadingSpaces == string.Empty) { possibleLeadingSpaces = triviaLine.ToFullString(); } if (inCopyright) { removalList.Add(i); } break; case SyntaxKind.EndOfLineTrivia: if (inCopyright) { removalList.Add(i); } if (onBlankLine) { done = true; } else { onBlankLine = true; } break; default: done = true; break; } if (done) { break; } } // Remove copyright lines in reverse order. for (int i = removalList.Count - 1; i >= 0; i--) { trivia = trivia.RemoveAt(removalList[i]); } string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); var newLineTrivia = SyntaxFactory.EndOfLine(newLineText); var newHeaderTrivia = CreateNewHeader(leadingSpaces + "//", document.Name, settings, newLineText); if (!isMalformedHeader && copyrightTriviaIndex.HasValue) { // Does the copyright element have leading whitespace? If so remove it. if ((copyrightTriviaIndex.Value > 0) && trivia[copyrightTriviaIndex.Value - 1].IsKind(SyntaxKind.WhitespaceTrivia)) { copyrightTriviaIndex = copyrightTriviaIndex - 1; trivia = trivia.RemoveAt(copyrightTriviaIndex.Value); } // Replace copyright element in place. return root.WithLeadingTrivia(trivia.ReplaceRange(trivia[copyrightTriviaIndex.Value], newHeaderTrivia)); } else { // Add blank line if we don't already have comments at top of file. if (!FirstLineIsComment(trivia)) { newHeaderTrivia = newHeaderTrivia.Add(newLineTrivia); } // Insert header at top of the file. return root.WithLeadingTrivia(newHeaderTrivia.Add(newLineTrivia).AddRange(trivia)); } }
private static void HandleCompilationUnit(SyntaxNodeAnalysisContext context, StyleCopSettings settings) { var elementOrder = settings.OrderingRules.ElementOrder; int accessibilityIndex = elementOrder.IndexOf(OrderingTrait.Accessibility); if (accessibilityIndex < 0) { return; } var compilationUnit = (CompilationUnitSyntax)context.Node; HandleMemberList(context, elementOrder, accessibilityIndex, compilationUnit.Members, AccessLevel.Internal); }
private static SyntaxTriviaList CreateNewHeader(string prefixWithLeadingSpaces, string filename, StyleCopSettings settings, string newLineText) { var copyrightText = prefixWithLeadingSpaces + " " + GetCopyrightText(prefixWithLeadingSpaces, settings.DocumentationRules.CopyrightText, newLineText); var newHeader = settings.DocumentationRules.XmlHeader ? WrapInXmlComment(prefixWithLeadingSpaces, copyrightText, filename, settings, newLineText) : copyrightText; return SyntaxFactory.ParseLeadingTrivia(newHeader); }
private static bool CompareCopyrightText(string copyrightText, StyleCopSettings settings) { // make sure that both \n and \r\n are accepted from the settings. var reformattedCopyrightTextParts = settings.DocumentationRules.CopyrightText.Replace("\r\n", "\n").Split('\n'); var fileHeaderCopyrightTextParts = copyrightText.Replace("\r\n", "\n").Split('\n'); if (reformattedCopyrightTextParts.Length != fileHeaderCopyrightTextParts.Length) { return false; } // compare line by line, ignoring leading and trailing whitespace on each line. for (var i = 0; i < reformattedCopyrightTextParts.Length; i++) { if (string.CompareOrdinal(reformattedCopyrightTextParts[i].Trim(), fileHeaderCopyrightTextParts[i].Trim()) != 0) { return false; } } return true; }
private static SyntaxNode ReplaceWellFormedMultiLineCommentHeader(Document document, SyntaxNode root, StyleCopSettings settings, int commentIndex, XmlFileHeader header) { SyntaxTriviaList trivia = root.GetLeadingTrivia(); var commentTrivia = trivia[commentIndex]; // Is the comment pushed in by a prefix? var commentIndentation = string.Empty; if (commentIndex > 0) { var prefixTrivia = trivia[commentIndex - 1]; if (prefixTrivia.IsKind(SyntaxKind.WhitespaceTrivia)) { commentIndentation = prefixTrivia.ToFullString(); } } var triviaString = commentTrivia.ToFullString(); var startIndex = triviaString.IndexOf("/*", StringComparison.Ordinal) + 2; var endIndex = triviaString.LastIndexOf("*/", StringComparison.Ordinal); var commentContext = triviaString.Substring(startIndex, endIndex - startIndex).Trim(' ', '\t').TrimEnd(); var triviaStringParts = commentContext.Replace("\r\n", "\n").Split('\n'); // Assume we have comments that have a leading * string interlinePadding = " *"; int minExpectedLength = (commentIndentation + interlinePadding).Length; string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp); // Examine second line to see if we should have stars or not if it's blank // set the interline padding to be blank also. if ((triviaStringParts.Length > 2) && (triviaStringParts[1].Length > minExpectedLength) && string.IsNullOrWhiteSpace(triviaStringParts[1].Substring(0, minExpectedLength))) { interlinePadding = " "; } // Pad line that used to be next to a /* triviaStringParts[0] = commentIndentation + interlinePadding + " " + triviaStringParts[0]; StringBuilder sb = StringBuilderPool.Allocate(); var copyrightText = commentIndentation + interlinePadding + " " + GetCopyrightText(commentIndentation + interlinePadding, settings.DocumentationRules.CopyrightText, newLineText); var newHeader = WrapInXmlComment(commentIndentation + interlinePadding, copyrightText, document.Name, settings, newLineText); sb.Append(commentIndentation); sb.Append("/*"); if (header.GetElement("copyright") == null) { // No copyright element at the moment so add us. sb.Append(newHeader.Substring(minExpectedLength)); sb.Append(newLineText); // Append the original stuff foreach (var oldLine in triviaStringParts) { sb.Append(oldLine.TrimEnd()); sb.Append(newLineText); } } else { bool firstLine = true; bool inCopyright = false; foreach (var oldLine in triviaStringParts) { var openingTag = oldLine.Contains("<copyright "); var closingTag = oldLine.Contains("</copyright>") || (openingTag && oldLine.Trim().EndsWith("/>")); if (openingTag) { inCopyright = !closingTag; sb.Append(newHeader.Substring(firstLine ? minExpectedLength : 0)); sb.Append(newLineText); } if (inCopyright) { inCopyright = !closingTag; } else { sb.Append(oldLine.Substring(firstLine ? minExpectedLength : 0)); sb.Append(newLineText); } firstLine = false; } } sb.Append(commentIndentation); sb.Append(" */"); // Get rid of any trailing spaces. var lines = sb.ToString().Split(new string[] { newLineText }, StringSplitOptions.None); sb.Clear(); for (int i = 0; i < lines.Length; i++) { sb.Append((i == 0 ? string.Empty : newLineText) + lines[i].TrimEnd()); } var newTrivia = SyntaxFactory.SyntaxTrivia(SyntaxKind.MultiLineCommentTrivia, StringBuilderPool.ReturnAndFree(sb)); return root.WithLeadingTrivia(trivia.Replace(commentTrivia, newTrivia)); }
public static void HandleSyntaxTree(SyntaxTreeAnalysisContext context, StyleCopSettings settings, Compilation compilation) { var root = context.Tree.GetRoot(context.CancellationToken); // don't process empty files if (root.FullSpan.IsEmpty) { return; } if (settings.DocumentationRules.XmlHeader) { var fileHeader = FileHeaderHelpers.ParseXmlFileHeader(root); if (fileHeader.IsMissing) { context.ReportDiagnostic(Diagnostic.Create(SA1633DescriptorMissing, fileHeader.GetLocation(context.Tree))); return; } if (fileHeader.IsMalformed) { context.ReportDiagnostic(Diagnostic.Create(SA1633DescriptorMalformed, fileHeader.GetLocation(context.Tree))); return; } if (!compilation.IsAnalyzerSuppressed(SA1634Identifier)) { CheckCopyrightHeader(context, settings.DocumentationRules, compilation, fileHeader); } if (!compilation.IsAnalyzerSuppressed(SA1639Identifier)) { CheckSummaryHeader(context, compilation, fileHeader); } } else { var fileHeader = FileHeaderHelpers.ParseFileHeader(root); if (fileHeader.IsMissing) { context.ReportDiagnostic(Diagnostic.Create(SA1633DescriptorMissing, fileHeader.GetLocation(context.Tree))); return; } if (!compilation.IsAnalyzerSuppressed(SA1635Identifier)) { if (string.IsNullOrWhiteSpace(fileHeader.CopyrightText)) { context.ReportDiagnostic(Diagnostic.Create(SA1635Descriptor, fileHeader.GetLocation(context.Tree))); return; } if (compilation.IsAnalyzerSuppressed(SA1636Identifier)) { return; } if (!CompareCopyrightText(settings.DocumentationRules, fileHeader.CopyrightText)) { context.ReportDiagnostic(Diagnostic.Create(SA1636Descriptor, fileHeader.GetLocation(context.Tree))); return; } } } }