官术网_书友最值得收藏!

How it works...

Compilation analyzers register compilation actions to analyze symbols and/or syntax nodes in the compilation. You can register either a stateless CompilationAction or a stateful CompilationStartAction with nested actions to analyze symbols and/or syntax nodes within a compilation. Our analyzer registers a CompilationStartAction to perform stateful analysis.

context.RegisterCompilationStartAction(compilationContext =>
{
...
}

Analysis begins with a couple of early bail out checks: we are only interested in analyzing compilations which have source or metadata types by name MyNamespace.ISecureType and MyNamespace.InsecureMethodAttribute.

 // Check if the attribute type marking insecure methods is defined.
var insecureMethodAttributeType = compilationContext.Compilation.GetTypeByMetadataName("MyNamespace.InsecureMethodAttribute");
if (insecureMethodAttributeType == null)
{
return;
}

// Check if the interface type marking secure types is defined.
var secureTypeInterfaceType = compilationContext.Compilation.GetTypeByMetadataName("MyNamespace.ISecureType");
if (secureTypeInterfaceType == null)
{
return;
}

We allocate a new CompilationAnalyzer instance for compilations to be analyzed. A constructor of this type initializes the mutable and immutable state tracked for analysis (explained later).

// Initialize state in the start action.
var analyzer = new CompilationAnalyzer(insecureMethodAttributeType, secureTypeInterfaceType);

We then register a nested symbol action, CompilationAnalyzer.AnalyzeSymbol, on the given compilation start context for the given compilation. We register interest in analyzing type and method symbols within the compilation.

// Register an intermediate non-end action that accesses and modifies the state. compilationContext.RegisterSymbolAction(analyzer.AnalyzeSymbol, SymbolKind.NamedType, SymbolKind.Method);

Finally, we register a nested CompilationEndAction to be executed on the instance of CompilationAnalyzer at the end of the compilation analysis.

// Register an end action to report diagnostics based on the final state. compilationContext.RegisterCompilationEndAction(analyzer.CompilationEndAction);
Nested compilation end actions are always guaranteed to be executed after all the nested non-end actions registered on the same analysis context have finished executing.

Let's now understand the working of the core CompilationAnalyzer type to analyze a specific compilation. This analyzer defines an immutable state for type symbols corresponding to the secure interface and insecure method attribute. It also defines mutable state fields to track the set of types defined in the compilation that implement the secure interface and a set of interfaces defined in the compilation that have methods with an insecure method attribute.

#region Per-Compilation immutable state
private readonly INamedTypeSymbol _insecureMethodAttributeType;
private readonly INamedTypeSymbol _secureTypeInterfaceType;
#endregion

#region Per-Compilation mutable state
/// <summary>
/// List of secure types in the compilation implementing secure interface.
/// </summary>
private List<INamedTypeSymbol> _secureTypes;

/// <summary>
/// Set of insecure interface types in the compilation that have methods with an insecure method attribute.
/// </summary>
private HashSet<INamedTypeSymbol> _interfacesWithInsecureMethods;
#endregion

At the start of the analysis, we initialize the set of secure types and interfaces with insecure methods to be empty.

#region State intialization
public CompilationAnalyzer(INamedTypeSymbol insecureMethodAttributeType, INamedTypeSymbol secureTypeInterfaceType)
{
_insecureMethodAttributeType = insecureMethodAttributeType;
_secureTypeInterfaceType = secureTypeInterfaceType;

_secureTypes = null;
_interfacesWithInsecureMethods = null;
}
#endregion

AnalyzeSymbol is registered as a nested symbol action to analyze all types and methods within the compilation. For every type declaration in the compilation, we check whether it implements the secure interface, and if so, add it to our set of secure types. For every method declaration in the compilation, we check whether its containing type is an interface and the method has the insecure method attribute, and if so, add the containing interface type to our set of interface types with insecure methods.

  #region Intermediate actions
public void AnalyzeSymbol(SymbolAnalysisContext context)
{
switch (context.Symbol.Kind)
{
case SymbolKind.NamedType:
// Check if the symbol implements "_secureTypeInterfaceType".
var namedType = (INamedTypeSymbol)context.Symbol;
if (namedType.AllInterfaces.Contains(_secureTypeInterfaceType))
{
_secureTypes = _secureTypes ?? new List<INamedTypeSymbol>();
_secureTypes.Add(namedType);
}

break;

case SymbolKind.Method:
// Check if this is an interface method with "_insecureMethodAttributeType" attribute.
var method = (IMethodSymbol)context.Symbol;
if (method.ContainingType.TypeKind == TypeKind.Interface && method.GetAttributes().Any(a => a.AttributeClass.Equals(_insecureMethodAttributeType)))
{
_interfacesWithInsecureMethods = _interfacesWithInsecureMethods ?? new HashSet<INamedTypeSymbol>();
_interfacesWithInsecureMethods.Add(method.ContainingType);
}

break;
}
}
#endregion

Finally, the registered the compilation end action uses the final state at the end of compilation analysis to report diagnostics. Analysis in this action starts by bailing out early if we either have no secure types or no interfaces with insecure methods. Then, we walk through all secure types and all interfaces with insecure methods, and for every pair. check whether the secure type or any of its base types implements the insecure interface. If so, we report a diagnostic on the secure type.

   #region End action
public void CompilationEndAction(CompilationAnalysisContext context)
{
if (_interfacesWithInsecureMethods == null || _secureTypes == null)
{
// No violating types.
return;
}

// Report diagnostic for violating named types.
foreach (var secureType in _secureTypes)
{
foreach (var insecureInterface in _interfacesWithInsecureMethods)
{
if (secureType.AllInterfaces.Contains(insecureInterface))
{
var diagnostic = Diagnostic.Create(Rule, secureType.Locations[0], secureType.Name, "MyNamespace.ISecureType", insecureInterface.Name);
context.ReportDiagnostic(diagnostic);

break;
}
}
}
}
#endregion
主站蜘蛛池模板: 靖边县| 伊金霍洛旗| 大英县| 合江县| 吉水县| 玉田县| 渑池县| 陕西省| 舟山市| 自治县| 三亚市| 阿图什市| 平原县| 嘉禾县| 乃东县| 平谷区| 富阳市| 射阳县| 铁岭市| 扬中市| 团风县| 江陵县| 德清县| 滨海县| 秦皇岛市| 新乐市| 延长县| 贞丰县| 嘉荫县| 房产| 丹巴县| 三台县| 舞阳县| 高清| 海丰县| 七台河市| 蒲城县| 荆州市| 康保县| 都江堰市| 丰顺县|