//Prevent static usage of OldAndBrokenServiceLocator //For example, OldAndBrokenServiceLocator.Instance.Get<IFoo>() private void PreventOldAndBrokenUsage( SyntaxNodeAnalysisContext context, ImmutableArray <INamedTypeSymbol> disallowedTypes, AllowedTypeList allowedTypeList ) { if (!(context.Node is IdentifierNameSyntax syntax)) { return; } if (!IdentifierIsOfDisallowedType(context.SemanticModel, disallowedTypes, syntax)) { return; } var parentClasses = context.Node.Ancestors().OfType <TypeDeclarationSyntax>(); var parentSymbols = parentClasses.Select(c => context.SemanticModel.GetDeclaredSymbol(c)).ToImmutableArray(); if (parentSymbols.Any(s => Attributes.DIFramework.IsDefined(s))) { //Classes in the DI Framework are allowed to use locators and activators return; } if (_excludeKnownProblems && parentSymbols.Any(allowedTypeList.Contains)) { return; } context.ReportDiagnostic( Diagnostic.Create(Diagnostics.OldAndBrokenLocatorIsObsolete, syntax.GetLocation()) ); }
private void RegisterAnalysis(CompilationStartAnalysisContext context) { var attributeType = context.Compilation.GetTypeByMetadataName("D2L.LP.Web.Rest.Attributes.JsonParamBinder"); if (attributeType == null) { // Attribute is presumably not being used, so no need to register our analyzer return; } AllowedTypeList allowedTypeList = AllowedTypeList.CreateFromAnalyzerOptions( allowedListFileName: "LegacyJsonParamBinderAllowedList.txt", analyzerOptions: context.Options ); context.RegisterSyntaxNodeAction( ctx => AnalyzeAttribute(ctx, attributeType, allowedTypeList), SyntaxKind.Attribute ); context.RegisterSymbolAction( ctx => PreventUnnecessaryAllowedListing( ctx, attributeType, allowedTypeList ), SymbolKind.NamedType ); }
public void RegisterServiceLocatorAnalyzer(CompilationStartAnalysisContext context) { // Cache some important type lookups var locatorType = context.Compilation.GetTypeByMetadataName("D2L.LP.Extensibility.Activation.Domain.OldAndBrokenServiceLocator"); var factoryType = context.Compilation.GetTypeByMetadataName("D2L.LP.Extensibility.Activation.Domain.OldAndBrokenServiceLocatorFactory"); var activatorType = context.Compilation.GetTypeByMetadataName("D2L.LP.Extensibility.Activation.Domain.IObjectActivator"); var customActivatorType = context.Compilation.GetTypeByMetadataName("D2L.LP.Extensibility.Activation.Domain.ICustomObjectActivator"); var staticDILocatorType = context.Compilation.GetTypeByMetadataName("D2L.LP.Extensibility.Activation.Domain.Default.StaticDI.Current"); // If those type lookups failed then OldAndBrokenServiceLocator // cannot resolve and we don't need to register our analyzer. if (locatorType == null || locatorType.Kind == SymbolKind.ErrorType) { return; } if (factoryType == null || factoryType.Kind == SymbolKind.ErrorType) { return; } ImmutableArray <INamedTypeSymbol> disallowedTypes = ImmutableArray.Create( locatorType, factoryType, activatorType, customActivatorType, staticDILocatorType ); AllowedTypeList allowedTypeList = AllowedTypeList.CreateFromAnalyzerOptions( allowedListFileName: "OldAndBrokenServiceLocatorAllowedList.txt", analyzerOptions: context.Options ); //Prevent static usage of OldAndBrokenServiceLocator //For example, OldAndBrokenServiceLocator.Instance.Get<IFoo>() context.RegisterSyntaxNodeAction( ctx => PreventOldAndBrokenUsage( ctx, disallowedTypes, allowedTypeList ), SyntaxKind.IdentifierName ); context.RegisterSymbolAction( ctx => PreventUnnecessaryAllowedListing( ctx, disallowedTypes, allowedTypeList ), SymbolKind.NamedType ); }
private void PreventUnnecessaryAllowedListing( SymbolAnalysisContext context, ImmutableArray <INamedTypeSymbol> disallowedTypes, AllowedTypeList allowedTypeList ) { if (!(context.Symbol is INamedTypeSymbol namedType)) { return; } if (!allowedTypeList.Contains(namedType)) { return; } Location diagnosticLocation = null; foreach (var syntaxRef in namedType.DeclaringSyntaxReferences) { var typeSyntax = syntaxRef.GetSyntax(context.CancellationToken) as TypeDeclarationSyntax; diagnosticLocation = diagnosticLocation ?? typeSyntax.Identifier.GetLocation(); SemanticModel model = context.Compilation.GetSemanticModel(typeSyntax.SyntaxTree); bool usesDisallowedTypes = typeSyntax .DescendantNodes() .OfType <IdentifierNameSyntax>() .Any(syntax => IdentifierIsOfDisallowedType(model, disallowedTypes, syntax)); if (usesDisallowedTypes) { return; } } if (diagnosticLocation != null) { allowedTypeList.ReportEntryAsUnnecesary( entry: namedType, location: diagnosticLocation, report: context.ReportDiagnostic ); } }
private void AnalyzeAttribute( SyntaxNodeAnalysisContext context, INamedTypeSymbol jsonParamBinderT, AllowedTypeList allowedList ) { if (!(context.Node is AttributeSyntax attribute)) { return; } if (!AttributeIsOfDisallowedType(context.SemanticModel, jsonParamBinderT, attribute)) { return; } ISymbol methodSymbol = context.ContainingSymbol; if (methodSymbol.Kind != SymbolKind.Method) { return; } if (!(methodSymbol.ContainingType is INamedTypeSymbol classSymbol)) { return; } if (allowedList.Contains(classSymbol)) { return; } Location location = attribute.GetLocation(); Diagnostic diagnostic = Diagnostic.Create( Diagnostics.ObsoleteJsonParamBinder, location ); context.ReportDiagnostic(diagnostic); }