我写一个罗斯林分析仪来执行一些文档的规则。该规则规定,需要记录仅领域和类型的组件外部可见。这使我找出一个字段或类型是否清晰可见,可以申报组件之外使用的问题。
鉴于此声明:
namespace TestApp {
internal class InternalClass {
public class InnerClass {
public int PublicFieldInInternal;
}
}
}
我想知道是否PublicFieldInInternal
是申报装配外部可见。我用下面的代码来确定可访问性:
private bool IsNonPrivateMemberDeclaration(SyntaxNodeAnalysisContext context, SyntaxNode node)
{
if (node is BaseFieldDeclarationSyntax fieldDeclaration)
{
var firstField = fieldDeclaration.Declaration.Variables.First();
var fieldAccessibility = context.SemanticModel.GetDeclaredSymbol(firstField).DeclaredAccessibility;
return ConstructVisibleFromOtherAssemblies(fieldAccessibility);
}
var accessibility = context.SemanticModel.GetDeclaredSymbol(node)?.DeclaredAccessibility;
if (accessibility != null)
{
return ConstructVisibleFromOtherAssemblies(accessibility.Value);
}
Debug.Assert(true, "This code should be unreachable as one of the two cases above will catch all calls");
return false;
}
private static bool ConstructVisibleFromOtherAssemblies(Accessibility accessibility) =>
accessibility == Accessibility.Public ||
accessibility == Accessibility.Protected ||
accessibility == Accessibility.ProtectedOrInternal;
然而,它没有考虑父类型考虑的可访问性,因此对应于DeclaredAccessibility
回报PublicFieldInInternal
符号的Accessibility.Public
财产。有没有一种方法直接查询语义模型,以获得有效的可访问性,或者我需要递归看含类型?
我结束了这种方法,并通过所有的单元测试:
private bool IsVisibleFromOtherAssemblies(SyntaxNodeAnalysisContext context, SyntaxNode node)
{
ISymbol declaredSymbol = GetDeclaredSymbol(context, node);
var accessibility = declaredSymbol.DeclaredAccessibility;
var visibility = ConstructVisibleFromOtherAssemblies(accessibility);
var containingType = declaredSymbol.ContainingType;
return IsSymbolAndContainingTypeVisible(visibility, containingType);
}
private static ISymbol GetDeclaredSymbol(SyntaxNodeAnalysisContext context, SyntaxNode node)
{
if (node is BaseFieldDeclarationSyntax fieldDeclaration)
{
var firstField = fieldDeclaration.Declaration.Variables.First();
return context.SemanticModel.GetDeclaredSymbol(firstField);
}
return context.SemanticModel.GetDeclaredSymbol(node);
}
private bool IsSymbolAndContainingTypeVisible(bool visibility, INamedTypeSymbol containingType)
{
if (containingType == null)
{
return visibility;
}
return visibility && IsSymbolAndContainingTypeVisible(
ConstructVisibleFromOtherAssemblies(containingType.DeclaredAccessibility),
containingType.ContainingType);
}
private static bool ConstructVisibleFromOtherAssemblies(Accessibility accessibility) =>
accessibility == Accessibility.Public ||
accessibility == Accessibility.Protected ||
accessibility == Accessibility.ProtectedOrInternal;