Skip to content

Instantly share code, notes, and snippets.

@bricelam
Created January 28, 2014 18:20
Show Gist options
  • Save bricelam/8673172 to your computer and use it in GitHub Desktop.
Save bricelam/8673172 to your computer and use it in GitHub Desktop.
Roslyn syntax rewriter to remove internal doc comments
namespace RemoveInternalDocComments
{
using System;
using System.IO;
using System.Linq;
using Roslyn.Compilers.CSharp;
class Program
{
static void Main()
{
var path = @"C:\Path\to\src";
foreach (var file in Directory.EnumerateFiles(path, "*.cs", SearchOption.AllDirectories))
{
// TODO: Exclude all auto-generated files
if (file.EndsWith(".designer.cs", StringComparison.OrdinalIgnoreCase))
{
continue;
}
var rewriter = new Rewriter();
var newRoot = rewriter.Visit(SyntaxTree.ParseFile(file).GetRoot());
if (rewriter.ReplacedAnything)
{
// TODO: Use original encoding
File.WriteAllText(file, newRoot.ToFullString());
Console.Write("X");
}
else
{
Console.Write(".");
}
}
Console.WriteLine();
Console.WriteLine();
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
class Rewriter : SyntaxRewriter
{
public bool ReplacedAnything { get; set; }
public override SyntaxTrivia VisitTrivia(SyntaxTrivia trivia)
{
if (trivia.Kind == SyntaxKind.DocumentationCommentTrivia
&& !IsPublic(trivia.Token.Parent))
{
ReplacedAnything = true;
return Syntax.Comment(trivia.ToFullString().Replace("///", "//"));
}
return base.VisitTrivia(trivia);
}
private bool IsPublic(SyntaxNode node)
{
if (node is MemberDeclarationSyntax)
{
if (node.Parent is BaseTypeDeclarationSyntax && !IsPublic(node.Parent))
{
return false;
}
if (node.Parent is InterfaceDeclarationSyntax || node.Parent is EnumDeclarationSyntax)
{
return true;
}
var baseTypeDeclaration = node as BaseTypeDeclarationSyntax;
var baseFieldDeclaration = node as BaseFieldDeclarationSyntax;
var delegateDeclaration = node as DelegateDeclarationSyntax;
var baseMethodDeclaration = node as BaseMethodDeclarationSyntax;
var basePropertyDeclaration = node as BasePropertyDeclarationSyntax;
if (baseTypeDeclaration != null)
{
if (!IsPublic(baseTypeDeclaration.Modifiers))
{
return false;
}
}
else if (baseFieldDeclaration != null)
{
if (!IsPublic(baseFieldDeclaration.Modifiers))
{
return false;
}
}
else if (delegateDeclaration != null)
{
if (!IsPublic(delegateDeclaration.Modifiers))
{
return false;
}
}
else if (baseMethodDeclaration != null)
{
if (baseMethodDeclaration is DestructorDeclarationSyntax)
{
return true;
}
var methodDeclaration = baseMethodDeclaration as MethodDeclarationSyntax;
if (methodDeclaration != null && methodDeclaration.ExplicitInterfaceSpecifier != null)
{
// TODO: Only if interface is public
return true;
}
if (!IsPublic(baseMethodDeclaration.Modifiers))
{
return false;
}
}
else if (basePropertyDeclaration != null)
{
var propertyDeclaration = basePropertyDeclaration as PropertyDeclarationSyntax;
if (propertyDeclaration != null && propertyDeclaration.ExplicitInterfaceSpecifier != null)
{
// TODO: Only if interface is public
return true;
}
if (!IsPublic(basePropertyDeclaration.Modifiers))
{
return false;
}
}
else
{
throw new Exception("Unexpected node.");
}
}
else if (node is AttributeListSyntax || node is TypeSyntax)
{
return IsPublic(node.Parent);
}
else if (node is ExpressionSyntax || node is StatementSyntax || node is VariableDeclarationSyntax)
{
return false;
}
else
{
throw new Exception("Unexpected node.");
}
return true;
}
private static bool IsPublic(SyntaxTokenList modifiers)
{
return modifiers.Any(m => m.Kind == SyntaxKind.PublicKeyword || m.Kind == SyntaxKind.ProtectedKeyword);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment