protected sealed override void Initialize(SonarAnalysisContext context) { context.RegisterSymbolAction( c => { var namedType = (INamedTypeSymbol)c.Symbol; if (!namedType.IsClassOrStruct() || namedType.GetAttributes().Any(IsStructLayoutAttribute) || namedType.ContainingType != null) { return; } var removableDeclarationCollector = new RemovableDeclarationCollector(namedType, c.Compilation); var candidateFields = removableDeclarationCollector.GetRemovableFieldLikeDeclarations( ImmutableHashSet.Create(SyntaxKind.FieldDeclaration), maxAccessibility) .Where(tuple => !IsInitializedOrFixed(((VariableDeclaratorSyntax)tuple.SyntaxNode))); var candidateProperties = removableDeclarationCollector.GetRemovableDeclarations( ImmutableHashSet.Create(SyntaxKind.PropertyDeclaration), maxAccessibility) .Where(tuple => IsAutoPropertyWithNoInitializer((PropertyDeclarationSyntax)tuple.SyntaxNode)); var allCandidateMembers = candidateFields.Concat(candidateProperties).ToList(); if (!allCandidateMembers.Any()) { return; } var usedMembers = GetMemberUsages(removableDeclarationCollector, new HashSet <ISymbol>(allCandidateMembers.Select(t => t.Symbol))); var usedMemberSymbols = new HashSet <ISymbol>(usedMembers.Select(tuple => tuple.Symbol)); var assignedMemberSymbols = GetAssignedMemberSymbols(usedMembers); foreach (var candidateMember in allCandidateMembers) { if (!usedMemberSymbols.Contains(candidateMember.Symbol)) { /// reported by <see cref="UnusedPrivateMember"/> continue; } if (!assignedMemberSymbols.Contains(candidateMember.Symbol)) { var field = candidateMember.SyntaxNode as VariableDeclaratorSyntax; var property = candidateMember.SyntaxNode as PropertyDeclarationSyntax; var memberType = field != null ? "field" : "auto-property"; var location = field != null ? field.Identifier.GetLocation() : property.Identifier.GetLocation(); c.ReportDiagnosticIfNonGenerated(Diagnostic.Create(rule, location, memberType, candidateMember.Symbol.Name)); } } }, SymbolKind.NamedType); }
private static void CollectRemovableFieldLikeDeclarations(RemovableDeclarationCollector declarationCollector, HashSet <ISymbol> declaredPrivateSymbols, BidirectionalDictionary <ISymbol, SyntaxNode> fieldLikeSymbols) { var declarationKinds = ImmutableHashSet.Create(SyntaxKind.FieldDeclaration, SyntaxKind.EventFieldDeclaration); var removableFieldsDefinitions = declarationCollector.GetRemovableFieldLikeDeclarations(declarationKinds, maxAccessibility); foreach (var fieldsDefinitions in removableFieldsDefinitions) { declaredPrivateSymbols.Add(fieldsDefinitions.Symbol); fieldLikeSymbols.Add(fieldsDefinitions.Symbol, fieldsDefinitions.SyntaxNode); } }
protected override void Initialize(SonarAnalysisContext context) { context.RegisterSymbolAction( c => { var namedType = (INamedTypeSymbol)c.Symbol; if (!namedType.IsClassOrStruct() || namedType.ContainingType != null) { return; } var removableDeclarationCollector = new RemovableDeclarationCollector(namedType, c.Compilation); var removableEvents = removableDeclarationCollector.GetRemovableDeclarations( ImmutableHashSet.Create(SyntaxKind.EventDeclaration), maxAccessibility); var removableEventFields = removableDeclarationCollector.GetRemovableFieldLikeDeclarations( ImmutableHashSet.Create(SyntaxKind.EventFieldDeclaration), maxAccessibility); var allRemovableEvents = removableEvents.Concat(removableEventFields).ToList(); if (!allRemovableEvents.Any()) { return; } var symbolNames = allRemovableEvents.Select(t => t.Symbol.Name).ToImmutableHashSet(); var usedSymbols = GetReferencedSymbolsWithMatchingNames(removableDeclarationCollector, symbolNames); var invokedSymbols = GetInvokedEventSymbols(removableDeclarationCollector); var possiblyCopiedSymbols = GetPossiblyCopiedSymbols(removableDeclarationCollector); foreach (var removableEvent in allRemovableEvents) { if (!usedSymbols.Contains(removableEvent.Symbol)) { /// reported by <see cref="UnusedPrivateMember"/> continue; } if (!invokedSymbols.Contains(removableEvent.Symbol) && !possiblyCopiedSymbols.Contains(removableEvent.Symbol)) { var eventField = removableEvent.SyntaxNode as VariableDeclaratorSyntax; var location = eventField != null ? eventField.Identifier.GetLocation() : ((EventDeclarationSyntax)removableEvent.SyntaxNode).Identifier.GetLocation(); c.ReportDiagnosticIfNonGenerated(Diagnostic.Create(Rule, location)); } } }, SymbolKind.NamedType); }
private void RaiseOnUninvokedEventDeclaration(SymbolAnalysisContext context) { var namedType = (INamedTypeSymbol)context.Symbol; if (!namedType.IsClassOrStruct() || namedType.ContainingType != null) { return; } var removableDeclarationCollector = new RemovableDeclarationCollector(namedType, context.Compilation); var removableEventFields = removableDeclarationCollector .GetRemovableFieldLikeDeclarations(eventSyntax, maxAccessibility) .ToList(); if (!removableEventFields.Any()) { return; } var symbolNames = removableEventFields.Select(t => t.Symbol.Name).ToHashSet(); var usedSymbols = GetReferencedSymbolsWithMatchingNames(removableDeclarationCollector, symbolNames); var invokedSymbols = GetInvokedEventSymbols(removableDeclarationCollector); var possiblyCopiedSymbols = GetPossiblyCopiedSymbols(removableDeclarationCollector); removableEventFields .Where(IsNotInvoked) .Where(IsNotCopied) .ToList() .ForEach(x => context.ReportDiagnosticIfNonGenerated( Diagnostic.Create(rule, GetLocation(x.SyntaxNode), x.Symbol.Name))); Location GetLocation(SyntaxNode node) => node is VariableDeclaratorSyntax variableDeclarator ? variableDeclarator.Identifier.GetLocation() : ((EventDeclarationSyntax)node).Identifier.GetLocation(); bool IsNotInvoked(SyntaxNodeSymbolSemanticModelTuple <SyntaxNode, ISymbol> tuple) => !invokedSymbols.Contains(tuple.Symbol); bool IsNotCopied(SyntaxNodeSymbolSemanticModelTuple <SyntaxNode, ISymbol> tuple) => !possiblyCopiedSymbols.Contains(tuple.Symbol); bool IsUsed(SyntaxNodeSymbolSemanticModelTuple <SyntaxNode, ISymbol> tuple) => usedSymbols.Contains(tuple.Symbol); }