private WellKnownTypeProvider(Compilation compilation) { Compilation = compilation; Exception = WellKnownTypes.Exception(compilation); Contract = WellKnownTypes.SystemDiagnosticContractsContract(compilation); IDisposable = WellKnownTypes.IDisposable(compilation); Task = WellKnownTypes.Task(compilation); CollectionTypes = GetWellKnownCollectionTypes(compilation); SerializationInfo = WellKnownTypes.SerializationInfo(compilation); }
public override void Initialize(AnalysisContext analysisContext) { analysisContext.EnableConcurrentExecution(); analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); analysisContext.RegisterCompilationStartAction(compilationStartContext => { Compilation compilation = compilationStartContext.Compilation; INamedTypeSymbol exceptionType = WellKnownTypes.Exception(compilation); if (exceptionType == null) { return; } // Get a list of interesting categories of methods to analyze. List <MethodCategory> methodCategories = GetMethodCategories(compilation); compilationStartContext.RegisterOperationBlockStartAction(operationBlockContext => { var methodSymbol = operationBlockContext.OwningSymbol as IMethodSymbol; if (methodSymbol == null) { return; } // Find out if this given method is one of the interesting categories of methods. // For eg: certain Equals methods or certain accessors etc. MethodCategory methodCategory = methodCategories.FirstOrDefault(l => l.IsMatch(methodSymbol, compilation)); if (methodCategory == null) { return; } // For the interesting methods, register an operation action to catch all // Throw statements. operationBlockContext.RegisterOperationAction(operationContext => { // Get ThrowOperation's ExceptionType var thrownExceptionType = ((IThrowOperation)operationContext.Operation).Exception?.Type as INamedTypeSymbol; if (thrownExceptionType != null && thrownExceptionType.DerivesFrom(exceptionType)) { // If no exceptions are allowed or if the thrown exceptions is not an allowed one.. if (methodCategory.AllowedExceptions.IsEmpty || !methodCategory.AllowedExceptions.Contains(thrownExceptionType)) { operationContext.ReportDiagnostic( operationContext.Operation.Syntax.CreateDiagnostic(methodCategory.Rule, methodSymbol.Name, thrownExceptionType.Name)); } } }, OperationKind.Throw); }); }); }
private static async Task <Document> AddConstructorsAsync(Document document, IEnumerable <Diagnostic> diagnostics, SyntaxNode root, CancellationToken cancellationToken) { DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); SyntaxGenerator generator = editor.Generator; SemanticModel model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); CodeAnalysis.Text.TextSpan diagnosticSpan = diagnostics.First().Location.SourceSpan; // All the diagnostics are reported at the same location -- the name of the declared class -- so it doesn't matter which one we pick SyntaxNode node = root.FindNode(diagnosticSpan); SyntaxNode targetNode = editor.Generator.GetDeclaration(node, DeclarationKind.Class); var typeSymbol = model.GetDeclaredSymbol(targetNode) as INamedTypeSymbol; foreach (Diagnostic diagnostic in diagnostics) { var missingCtorSignature = (ImplementStandardExceptionConstructorsAnalyzer.MissingCtorSignature)Enum.Parse(typeof(ImplementStandardExceptionConstructorsAnalyzer.MissingCtorSignature), diagnostic.Properties["Signature"]); switch (missingCtorSignature) { case ImplementStandardExceptionConstructorsAnalyzer.MissingCtorSignature.CtorWithNoParameter: // Add missing CtorWithNoParameter SyntaxNode newConstructorNode1 = generator.ConstructorDeclaration(typeSymbol.Name, accessibility: Accessibility.Public); editor.AddMember(targetNode, newConstructorNode1); break; case ImplementStandardExceptionConstructorsAnalyzer.MissingCtorSignature.CtorWithStringParameter: // Add missing CtorWithStringParameter SyntaxNode newConstructorNode2 = generator.ConstructorDeclaration( containingTypeName: typeSymbol.Name, parameters: new[] { generator.ParameterDeclaration("message", generator.TypeExpression(WellKnownTypes.String(editor.SemanticModel.Compilation))) }, accessibility: Accessibility.Public, baseConstructorArguments: new[] { generator.Argument(generator.IdentifierName("message")) }); editor.AddMember(targetNode, newConstructorNode2); break; case ImplementStandardExceptionConstructorsAnalyzer.MissingCtorSignature.CtorWithStringAndExceptionParameters: // Add missing CtorWithStringAndExceptionParameters SyntaxNode newConstructorNode3 = generator.ConstructorDeclaration( containingTypeName: typeSymbol.Name, parameters: new[] { generator.ParameterDeclaration("message", generator.TypeExpression(WellKnownTypes.String(editor.SemanticModel.Compilation))), generator.ParameterDeclaration("innerException", generator.TypeExpression(WellKnownTypes.Exception(editor.SemanticModel.Compilation))) }, accessibility: Accessibility.Public, baseConstructorArguments: new[] { generator.Argument(generator.IdentifierName("message")), generator.Argument(generator.IdentifierName("innerException")) }); editor.AddMember(targetNode, newConstructorNode3); break; } } return(editor.GetChangedDocument()); }