private void RegisterAnalysis(CompilationStartAnalysisContext context) { DependencyRegistry dependencyRegistry; if (!DependencyRegistry.TryCreateRegistry(context.Compilation, out dependencyRegistry)) { return; } if (!AnnotationsContext.TryCreate(context.Compilation, out AnnotationsContext annotationsContext)) { return; } var immutabilityCtx = ImmutabilityContext.Create(context.Compilation, annotationsContext); context.RegisterSyntaxNodeAction( ctx => AnalyzeInvocation(ctx, immutabilityCtx, dependencyRegistry), SyntaxKind.InvocationExpression ); }
private void AnalyzeInvocation( SyntaxNodeAnalysisContext context, ImmutabilityContext immutabilityCtx, DependencyRegistry registry ) { var root = context.Node as InvocationExpressionSyntax; if (root == null) { return; } var method = context.SemanticModel.GetSymbolInfo(root).Symbol as IMethodSymbol; if (method == null) { return; } if (!registry.IsRegistationMethod(method)) { return; } if (IsExpressionInClassInIgnoreList(root, context.SemanticModel)) { return; } DependencyRegistrationExpression dependencyRegistrationExpresion; if (!registry.TryMapRegistrationMethod( method, root.ArgumentList.Arguments, context.SemanticModel, out dependencyRegistrationExpresion )) { // this can happen where there's a new registration method // that we can't map to // so we fail var diagnostic = Diagnostic.Create( Diagnostics.RegistrationKindUnknown, root.GetLocation() ); context.ReportDiagnostic(diagnostic); return; } var dependencyRegistration = dependencyRegistrationExpresion.GetRegistration( method, root.ArgumentList.Arguments, context.SemanticModel ); if (dependencyRegistration == null) { /* This can happen in the following scenarios: * 1) ObjectScope is passed in as a variable and we can't extract it. * 2) Some require argument is missing (compile error). * We fail because we can't analyze it. */ var diagnostic = Diagnostic.Create( Diagnostics.RegistrationKindUnknown, root.GetLocation() ); context.ReportDiagnostic(diagnostic); return; } InspectRegistration(dependencyRegistration, immutabilityCtx, context); }
private void InspectRegistration( DependencyRegistration registration, ImmutabilityContext immutabilityCtx, SyntaxNodeAnalysisContext ctx ) { if (registration.ObjectScope == ObjectScope.Singleton) { var typesToInspect = GetTypesRequiredToBeImmutableForSingletonRegistration(registration); foreach (var type in typesToInspect) { if (type.IsNullOrErrorType()) { continue; } // We require full immutability here, // because we don't know if it's a concrete type // // TODO: could make this better by exposing the minimum // scope required for each type var query = new ImmutabilityQuery( ImmutableTypeKind.Total, type ); if (!immutabilityCtx.IsImmutable(query, () => null, out var _)) { var diagnostic = GetUnsafeSingletonDiagnostic( ctx.Compilation.Assembly, ctx.Node, type ); ctx.ReportDiagnostic(diagnostic); } } } // ensure webrequest isn't marked Singleton var isMarkedSingleton = registration.DependencyType.IsTypeMarkedSingleton(); if (isMarkedSingleton && registration.ObjectScope != ObjectScope.Singleton) { var diagnostic = Diagnostic.Create( Diagnostics.AttributeRegistrationMismatch, ctx.Node.GetLocation(), registration.DependencyType.GetFullTypeNameWithGenericArguments() ); ctx.ReportDiagnostic(diagnostic); } if (TryGetInstantiatedTypeForRegistration(registration, out ITypeSymbol instantiatedType)) { if (!TryGetInjectableConstructor(instantiatedType, out IMethodSymbol injectableConstructor)) { var diagnostic = Diagnostic.Create( Diagnostics.DependencyRegistraionMissingPublicConstructor, ctx.Node.GetLocation(), instantiatedType.GetFullTypeNameWithGenericArguments() ); ctx.ReportDiagnostic(diagnostic); } } }