patterncsharpMinor
Tool to Add Access Modifiers to Code
Viewed 0 times
modifierstoolcodeaccessadd
Problem
Working on VSDiagnostics, I implemented a tool that adds the default access modifiers to C# code. An example use would be starting with this:
And ending with this:
This is the analyzer:
```
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeSymbol,
SyntaxKind.ClassDeclaration,
SyntaxKind.ConstructorDeclaration,
SyntaxKind.DelegateDeclaration,
SyntaxKind.EnumDeclaration,
SyntaxKind.EventDeclaration,
SyntaxKind.EventFieldDeclaration,
SyntaxKind.FieldDeclaration,
SyntaxKind.IndexerDeclaration,
SyntaxKind.InterfaceDeclaration,
SyntaxKind.MethodDeclaration,
SyntaxKind.PropertyDeclaration,
SyntaxKind.StructDeclaration);
}
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
if (context.Node is ClassDeclarationSyntax)
{
var declarationExpression = (ClassDeclarationSyntax) context.Node;
if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
{
var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
accessibility.ToString().ToLower()));
}
}
if (context.Node is StructDeclarationSyntax)
{
var declarationExpression = (StructDeclarationSyntax)context.Node;
if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
{
var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
accessibility.ToString().ToLower()));
}
}
if (context.Node is EnumDeclarationSynt
static class Foo { }And ending with this:
internal static class Foo { }This is the analyzer:
```
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeSymbol,
SyntaxKind.ClassDeclaration,
SyntaxKind.ConstructorDeclaration,
SyntaxKind.DelegateDeclaration,
SyntaxKind.EnumDeclaration,
SyntaxKind.EventDeclaration,
SyntaxKind.EventFieldDeclaration,
SyntaxKind.FieldDeclaration,
SyntaxKind.IndexerDeclaration,
SyntaxKind.InterfaceDeclaration,
SyntaxKind.MethodDeclaration,
SyntaxKind.PropertyDeclaration,
SyntaxKind.StructDeclaration);
}
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
if (context.Node is ClassDeclarationSyntax)
{
var declarationExpression = (ClassDeclarationSyntax) context.Node;
if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
{
var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
accessibility.ToString().ToLower()));
}
}
if (context.Node is StructDeclarationSyntax)
{
var declarationExpression = (StructDeclarationSyntax)context.Node;
if (!declarationExpression.Modifiers.Any(m => _accessModifierKinds.Contains(m.Kind())))
{
var accessibility = context.SemanticModel.GetDeclaredSymbol(declarationExpression).DeclaredAccessibility;
context.ReportDiagnostic(Diagnostic.Create(Rule, declarationExpression.GetLocation(),
accessibility.ToString().ToLower()));
}
}
if (context.Node is EnumDeclarationSynt
Solution
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
This method is quite large and could at least be improved for readability and performance. Right now you are checking for each expected type although if a previous check had been successful. It would better return early.
That beeing said let us see what the different "DeclarationSyntax"'s have in common.
By checking the rosaly source we see the following inheritance tree
ClassDeclarationSyntax -> TypeDeclarationSyntax -> BaseTypeDeclarationSyntax
StructDeclarationSyntax -> TypeDeclarationSyntax -> BaseTypeDeclarationSyntax
EnumDeclarationSyntax -> BaseTypeDeclarationSyntax
InterfaceDeclarationSyntax -> TypeDeclarationSyntax -> BaseTypeDeclarationSyntax
DelegateDeclarationSyntax -> MemberDeclarationSyntax
EventFieldDeclarationSyntax -> BaseFieldDeclarationSyntax
FieldDeclarationSyntax -> BaseFieldDeclarationSyntax
PropertyDeclarationSyntax -> BasePropertyDeclarationSyntax
EventDeclarationSyntax -> BasePropertyDeclarationSyntax
IndexerDeclarationSyntax -> BasePropertyDeclarationSyntax
MethodDeclarationSyntax -> BaseMethodDeclarationSyntax
ConstructorDeclarationSyntax -> BaseMethodDeclarationSyntax
and expect for
If we then add a class
We can add methods for processing the separate base classes in a
By adding generic methods for processing the extending classes in the same fashion like so
which are called from here
We have a clear chain of execution for each class which extends
For completeness all these
```
private bool IsContainedInDeclaredModifiers(SyntaxTokenList modifiers)
{
return modifiers.Any(m => _accessModifierKinds.Contains(m.Kind()));
}
private bool TryAnalyzeBaseTypeSymbol(SyntaxNodeAnalysisContext context, out AnalyzeResult result)
{
result = null;
var declarationSyntax = context.Node as BaseTypeDeclarationSyntax;
if (declarationSyntax == null)
{
return false;
}
if (IsContainedInDeclaredModifiers(declarationSyntax.Modifiers))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol(context, out result))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol(context, out result))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol(context, out result))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol(context, out result))
{
return true;
}
return false;
}
private bool TryAnalyzeBaseTypeSymbol(SyntaxNodeAnalysisContext context, out AnalyzeResult value) where T : BaseTypeDeclarationSyntax
{
value = null;
var declaration = context.Node as T;
if (declaration == null) { return false; }
var accessibility = context.SemanticModel.GetDeclaredSymbol(declaration).DeclaredAccessibility.ToString().ToLower();
value = new AnalyzeResult(declaration.GetLocation(), accessibility);
return true;
}
private bool TryAnalyzeBasePropertySymbol(SyntaxNodeAnalysisContext context, out AnalyzeResult result)
{
result = null;
var declarationSyntax = context.Node as BasePropertyDeclaration
This method is quite large and could at least be improved for readability and performance. Right now you are checking for each expected type although if a previous check had been successful. It would better return early.
That beeing said let us see what the different "DeclarationSyntax"'s have in common.
By checking the rosaly source we see the following inheritance tree
ClassDeclarationSyntax -> TypeDeclarationSyntax -> BaseTypeDeclarationSyntax
StructDeclarationSyntax -> TypeDeclarationSyntax -> BaseTypeDeclarationSyntax
EnumDeclarationSyntax -> BaseTypeDeclarationSyntax
InterfaceDeclarationSyntax -> TypeDeclarationSyntax -> BaseTypeDeclarationSyntax
DelegateDeclarationSyntax -> MemberDeclarationSyntax
EventFieldDeclarationSyntax -> BaseFieldDeclarationSyntax
FieldDeclarationSyntax -> BaseFieldDeclarationSyntax
PropertyDeclarationSyntax -> BasePropertyDeclarationSyntax
EventDeclarationSyntax -> BasePropertyDeclarationSyntax
IndexerDeclarationSyntax -> BasePropertyDeclarationSyntax
MethodDeclarationSyntax -> BaseMethodDeclarationSyntax
ConstructorDeclarationSyntax -> BaseMethodDeclarationSyntax
and expect for
DelegateDeclarationSyntax -> MemberDeclarationSyntax each of these base classes share a SyntaxTokenList Modifiers property. If we then add a class
AnalyzeResult like so private class AnalyzeResult
{
public Location NodeLocion { get; private set; }
public string Accessibility { get; private set; }
public AnalyzeResult(Location location, string accessibility)
{
NodeLocion = location;
Accessibility = accessibility;
}
}We can add methods for processing the separate base classes in a
bool TryGetValue(SyntaxNodeAnalysisContext, out AnalyzeResult) fashion. By adding generic methods for processing the extending classes in the same fashion like so
private bool TryAnalyzeBaseType(SyntaxNodeAnalysisContext context, out AnalyzeResult value) where T : BaseTypeDeclarationSyntax
{
value = null;
var declaration = context.Node as T;
if (declaration == null) { return false; }
var accessibility = context.SemanticModel.GetDeclaredSymbol(declaration).DeclaredAccessibility.ToString().ToLower();
value = new AnalyzeResult(declaration.GetLocation(), accessibility);
return true;
}which are called from here
private bool TryAnalyzeBaseTypeSymbol(SyntaxNodeAnalysisContext context, out AnalyzeResult result)
{
result = null;
var declarationSyntax = context.Node as BaseTypeDeclarationSyntax;
if (declarationSyntax == null)
{
return false;
}
if (IsContainedInDeclaredModifiers(declarationSyntax.Modifiers))
{
return true;
}
if (TryAnalyzeBaseType(context, out result))
{
return true;
}
if (TryAnalyzeBaseType(context, out result))
{
return true;
}
if (TryAnalyzeBaseType(context, out result))
{
return true;
}
if (TryAnalyzeBaseType(context, out result))
{
return true;
}
return false;
}
private bool IsContainedInDeclaredModifiers(SyntaxTokenList modifiers)
{
return modifiers.Any(m => _accessModifierKinds.Contains(m.Kind()));
}We have a clear chain of execution for each class which extends
BaseTypeDeclarationSyntax. For completeness all these
TryX..() and their generic methods ```
private bool IsContainedInDeclaredModifiers(SyntaxTokenList modifiers)
{
return modifiers.Any(m => _accessModifierKinds.Contains(m.Kind()));
}
private bool TryAnalyzeBaseTypeSymbol(SyntaxNodeAnalysisContext context, out AnalyzeResult result)
{
result = null;
var declarationSyntax = context.Node as BaseTypeDeclarationSyntax;
if (declarationSyntax == null)
{
return false;
}
if (IsContainedInDeclaredModifiers(declarationSyntax.Modifiers))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol(context, out result))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol(context, out result))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol(context, out result))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol(context, out result))
{
return true;
}
return false;
}
private bool TryAnalyzeBaseTypeSymbol(SyntaxNodeAnalysisContext context, out AnalyzeResult value) where T : BaseTypeDeclarationSyntax
{
value = null;
var declaration = context.Node as T;
if (declaration == null) { return false; }
var accessibility = context.SemanticModel.GetDeclaredSymbol(declaration).DeclaredAccessibility.ToString().ToLower();
value = new AnalyzeResult(declaration.GetLocation(), accessibility);
return true;
}
private bool TryAnalyzeBasePropertySymbol(SyntaxNodeAnalysisContext context, out AnalyzeResult result)
{
result = null;
var declarationSyntax = context.Node as BasePropertyDeclaration
Code Snippets
private class AnalyzeResult
{
public Location NodeLocion { get; private set; }
public string Accessibility { get; private set; }
public AnalyzeResult(Location location, string accessibility)
{
NodeLocion = location;
Accessibility = accessibility;
}
}private bool TryAnalyzeBaseType<T>(SyntaxNodeAnalysisContext context, out AnalyzeResult value) where T : BaseTypeDeclarationSyntax
{
value = null;
var declaration = context.Node as T;
if (declaration == null) { return false; }
var accessibility = context.SemanticModel.GetDeclaredSymbol(declaration).DeclaredAccessibility.ToString().ToLower();
value = new AnalyzeResult(declaration.GetLocation(), accessibility);
return true;
}private bool TryAnalyzeBaseTypeSymbol(SyntaxNodeAnalysisContext context, out AnalyzeResult result)
{
result = null;
var declarationSyntax = context.Node as BaseTypeDeclarationSyntax;
if (declarationSyntax == null)
{
return false;
}
if (IsContainedInDeclaredModifiers(declarationSyntax.Modifiers))
{
return true;
}
if (TryAnalyzeBaseType<ClassDeclarationSyntax>(context, out result))
{
return true;
}
if (TryAnalyzeBaseType<StructDeclarationSyntax>(context, out result))
{
return true;
}
if (TryAnalyzeBaseType<EnumDeclarationSyntax>(context, out result))
{
return true;
}
if (TryAnalyzeBaseType<InterfaceDeclarationSyntax>(context, out result))
{
return true;
}
return false;
}
private bool IsContainedInDeclaredModifiers(SyntaxTokenList modifiers)
{
return modifiers.Any(m => _accessModifierKinds.Contains(m.Kind()));
}private bool IsContainedInDeclaredModifiers(SyntaxTokenList modifiers)
{
return modifiers.Any(m => _accessModifierKinds.Contains(m.Kind()));
}
private bool TryAnalyzeBaseTypeSymbol(SyntaxNodeAnalysisContext context, out AnalyzeResult result)
{
result = null;
var declarationSyntax = context.Node as BaseTypeDeclarationSyntax;
if (declarationSyntax == null)
{
return false;
}
if (IsContainedInDeclaredModifiers(declarationSyntax.Modifiers))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol<ClassDeclarationSyntax>(context, out result))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol<StructDeclarationSyntax>(context, out result))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol<EnumDeclarationSyntax>(context, out result))
{
return true;
}
if (TryAnalyzeBaseTypeSymbol<InterfaceDeclarationSyntax>(context, out result))
{
return true;
}
return false;
}
private bool TryAnalyzeBaseTypeSymbol<T>(SyntaxNodeAnalysisContext context, out AnalyzeResult value) where T : BaseTypeDeclarationSyntax
{
value = null;
var declaration = context.Node as T;
if (declaration == null) { return false; }
var accessibility = context.SemanticModel.GetDeclaredSymbol(declaration).DeclaredAccessibility.ToString().ToLower();
value = new AnalyzeResult(declaration.GetLocation(), accessibility);
return true;
}
private bool TryAnalyzeBasePropertySymbol(SyntaxNodeAnalysisContext context, out AnalyzeResult result)
{
result = null;
var declarationSyntax = context.Node as BasePropertyDeclarationSyntax;
if (declarationSyntax == null)
{
return false;
}
if (IsContainedInDeclaredModifiers(declarationSyntax.Modifiers))
{
return true;
}
if (TryAnalyzeBasePropertySymbol<PropertyDeclarationSyntax>(context,out result))
{
return true;
}
if (TryAnalyzeBasePropertySymbol<EventDeclarationSyntax>(context, out result))
{
return true;
}
if (TryAnalyzeBasePropertySymbol<IndexerDeclarationSyntax>(context, out result))
{
return true;
}
return false;
}
private bool TryAnalyzeBasePropertySymbol<T>(SyntaxNodeAnalysisContext context, out AnalyzeResult value) where T : BasePropertyDeclarationSyntax
{
value = null;
var declaration = context.Node as T;
if (declaration == null) { return false; }
var accessibility = context.SemanticModel.GetDeclaredSymbol(declaration).DeclaredAccessibility.ToString().ToLower();
value = new AnalyzeResult(declaration.GetLocation(), accessibility);
return true;
}
private bool TryAnalyzeBaseMethodSymbol(SyntaxNodeAnalysisContext context, out AnalyzeResult result)
{
result = null;
var declarationSyntax = context.Node as BaseMethodDeclarationSyntax;
if (declarationSyntax == null)
{
return false;
}
if (IsContainedInDeclaredModifiers(declarationSyntax.Modifiers))
private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
AnalyzeResult result;
if (TryAnalyzeBaseTypeSymbol(context, out result))
{
if (result == null) { return; }
}
else if (TryAnalyzeBaseFieldSymbol(context, out result))
{
if (result == null) { return; }
} else if(TryAnalyzeBasePropertySymbol(context,out result))
{
if (result == null) { return; }
} else if (TryAnalyzeBaseMethodSymbol(context,out result))
{
if (result == null) { return; }
} else if(TryAnalyzeDelegateSymbol(context,out result))
{
if (result == null) { return; }
}
else
{
return;
}
context.ReportDiagnostic(Diagnostic.Create(Rule, result.NodeLocion,
result.Accessibility));
}Context
StackExchange Code Review Q#100601, answer score: 3
Revisions (0)
No revisions yet.