protected override void Initialize(SonarAnalysisContext context) { context.RegisterCompilationStartAction( c => { // Collect potentially removable internal types from the project to evaluate when // the compilation is over, depending on whether InternalsVisibleTo attribute is present // or not. var removableInternalTypes = new ConcurrentBag <ISymbol>(); c.RegisterSymbolAction( cc => { var namedType = (INamedTypeSymbol)cc.Symbol; if (!namedType.IsClassOrStruct() || namedType.ContainingType != null || namedType.DerivesFromAny(IgnoredTypes)) { return; } // Collect symbols of private members that could potentially be removed var removableSymbolsCollector = new CSharpRemovableSymbolWalker(c.Compilation.GetSemanticModel); if (!VisitDeclaringReferences(namedType, removableSymbolsCollector)) { return; } // Keep the removable internal types for when the compilation ends foreach (var internalSymbol in removableSymbolsCollector.InternalSymbols.OfType <INamedTypeSymbol>()) { removableInternalTypes.Add(internalSymbol); } var usageCollector = new CSharpSymbolUsageCollector( c.Compilation.GetSemanticModel, removableSymbolsCollector.PrivateSymbols.Select(s => s.Name).ToHashSet()); if (!VisitDeclaringReferences(namedType, usageCollector)) { return; } var diagnostics = GetDiagnostics(usageCollector, removableSymbolsCollector.PrivateSymbols, "private", removableSymbolsCollector.FieldLikeSymbols); foreach (var diagnostic in diagnostics) { cc.ReportDiagnosticIfNonGenerated(diagnostic, cc.Compilation); } }, SymbolKind.NamedType); c.RegisterCompilationEndAction( cc => { var foundInternalsVisibleTo = cc.Compilation.Assembly .GetAttributes(KnownType.System_Runtime_CompilerServices_InternalsVisibleToAttribute) .Any(); if (foundInternalsVisibleTo || removableInternalTypes.Count == 0) { return; } var usageCollector = new CSharpSymbolUsageCollector( c.Compilation.GetSemanticModel, removableInternalTypes.Select(s => s.Name).ToHashSet()); foreach (var syntaxTree in c.Compilation.SyntaxTrees) { usageCollector.SafeVisit(syntaxTree.GetRoot()); } var diagnostics = GetDiagnostics(usageCollector, removableInternalTypes.ToHashSet(), "internal", new BidirectionalDictionary <ISymbol, SyntaxNode>()); foreach (var diagnostic in diagnostics) { cc.ReportDiagnosticIfNonGenerated(diagnostic, cc.Compilation); } }); }); }
protected override void Initialize(SonarAnalysisContext context) => context.RegisterCompilationStartAction( c => { // Collect potentially removable internal types from the project to evaluate when // the compilation is over, depending on whether InternalsVisibleTo attribute is present // or not. var removableInternalTypes = new ConcurrentBag <ISymbol>(); c.RegisterSymbolAction( cc => { var namedType = (INamedTypeSymbol)cc.Symbol; if (namedType.TypeKind != TypeKind.Struct && namedType.TypeKind != TypeKind.Class && namedType.TypeKind != TypeKind.Delegate && namedType.TypeKind != TypeKind.Enum && namedType.TypeKind != TypeKind.Interface) { return; } if (namedType.ContainingType != null || namedType.DerivesFromAny(IgnoredTypes)) { return; } // Collect symbols of private members that could potentially be removed var removableSymbolsCollector = new CSharpRemovableSymbolWalker(c.Compilation.GetSemanticModel); if (!VisitDeclaringReferences(namedType, removableSymbolsCollector, c.Compilation, includeGeneratedFile: false)) { return; } // Keep the removable internal types for when the compilation ends foreach (var internalSymbol in removableSymbolsCollector.InternalSymbols.OfType <INamedTypeSymbol>()) { removableInternalTypes.Add(internalSymbol); } var usageCollector = new CSharpSymbolUsageCollector(c.Compilation, removableSymbolsCollector.PrivateSymbols); if (!VisitDeclaringReferences(namedType, usageCollector, c.Compilation, includeGeneratedFile: true)) { return; } var diagnostics = GetDiagnosticsForUnusedPrivateMembers(usageCollector, removableSymbolsCollector.PrivateSymbols, "private", removableSymbolsCollector.FieldLikeSymbols) .Concat(GetDiagnosticsForUsedButUnreadFields(usageCollector, removableSymbolsCollector.PrivateSymbols)); foreach (var diagnostic in diagnostics) { cc.ReportDiagnosticIfNonGenerated(diagnostic); } }, SymbolKind.NamedType); c.RegisterCompilationEndAction( cc => { var foundInternalsVisibleTo = cc.Compilation.Assembly.HasAttribute(KnownType.System_Runtime_CompilerServices_InternalsVisibleToAttribute); if (foundInternalsVisibleTo || removableInternalTypes.Count == 0) { return; } var usageCollector = new CSharpSymbolUsageCollector(c.Compilation, removableInternalTypes.ToHashSet()); foreach (var syntaxTree in c.Compilation.SyntaxTrees.Where(tree => !tree.IsGenerated(CSharpGeneratedCodeRecognizer.Instance, c.Compilation))) { usageCollector.SafeVisit(syntaxTree.GetRoot()); } var diagnostics = GetDiagnosticsForUnusedPrivateMembers(usageCollector, removableInternalTypes.ToHashSet(), "internal", new BidirectionalDictionary <ISymbol, SyntaxNode>()); foreach (var diagnostic in diagnostics) { cc.ReportDiagnosticIfNonGenerated(diagnostic); } }); });