private static void CheckClassWithOnlyUnusedPrivateConstructors(SymbolAnalysisContext context) { var namedType = context.Symbol as INamedTypeSymbol; if (!namedType.IsClass() || namedType.IsStatic) { return; } var members = namedType.GetMembers(); var constructors = GetConstructors(members).ToList(); if (!constructors.Any() || HasNonPrivateConstructor(constructors) || HasOnlyStaticMembers(members.Except(constructors).ToList())) { return; } var classDeclarations = new RemovableDeclarationCollector(namedType, context.Compilation).ClassDeclarations; if (!IsAnyConstructorCalled(namedType, classDeclarations)) { var message = constructors.Count > 1 ? "at least one of its constructors" : "its constructor"; foreach (var classDeclaration in classDeclarations) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(Rule, classDeclaration.SyntaxNode.Identifier.GetLocation(), message)); } } }
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 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); }
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); }
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 declaredPrivateMethodsWithReturn = CollectRemovableMethods(removableDeclarationCollector).ToList(); if (!declaredPrivateMethodsWithReturn.Any()) { return; } var invocations = CollectInvocations(removableDeclarationCollector.ClassDeclarations).ToList(); foreach (var declaredPrivateMethodWithReturn in declaredPrivateMethodsWithReturn) { var matchingInvocations = invocations .Where(inv => object.Equals(inv.Symbol.OriginalDefinition, declaredPrivateMethodWithReturn.Symbol)) .ToList(); if (!matchingInvocations.Any()) { /// this is handled by S1144 <see cref="UnusedPrivateMember"/> continue; } if (!IsReturnValueUsed(matchingInvocations)) { c.ReportDiagnostic(Diagnostic.Create(Rule, declaredPrivateMethodWithReturn.SyntaxNode.ReturnType.GetLocation())); } } }, SymbolKind.NamedType); }
protected override void Initialize(SonarAnalysisContext context) { context.RegisterSymbolAction( c => { var namedType = (INamedTypeSymbol)c.Symbol; if (!namedType.IsClassOrStruct() || namedType.ContainingType != null) { return; } var declarationCollector = new RemovableDeclarationCollector(namedType, c.Compilation); var declaredPrivateSymbols = new HashSet<ISymbol>(); var fieldLikeSymbols = new BidirectionalDictionary<ISymbol, SyntaxNode>(); CollectRemovableNamedTypes(declarationCollector, declaredPrivateSymbols); CollectRemovableFieldLikeDeclarations(declarationCollector, declaredPrivateSymbols, fieldLikeSymbols); CollectRemovableEventsAndProperties(declarationCollector, declaredPrivateSymbols); CollectRemovableMethods(declarationCollector, declaredPrivateSymbols); if (!declaredPrivateSymbols.Any()) { return; } var usedSymbols = new HashSet<ISymbol>(); var emptyConstructors = new HashSet<ISymbol>(); CollectUsedSymbols(declarationCollector, usedSymbols, declaredPrivateSymbols); CollectUsedSymbolsFromCtorInitializerAndCollectEmptyCtors(declarationCollector, usedSymbols, emptyConstructors); ReportIssues(c, usedSymbols, declaredPrivateSymbols, emptyConstructors, fieldLikeSymbols); }, SymbolKind.NamedType); }
private static IList<MemberUsage> GetMemberUsages(RemovableDeclarationCollector removableDeclarationCollector, HashSet<ISymbol> declaredPrivateSymbols) { var symbolNames = declaredPrivateSymbols.Select(s => s.Name).ToImmutableHashSet(); var identifiers = removableDeclarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.IdentifierName)) .Cast<IdentifierNameSyntax>() .Where(node => symbolNames.Contains(node.Identifier.ValueText)) .Select(node => new MemberUsage { SyntaxNode = node, SemanticModel = container.SemanticModel, Symbol = container.SemanticModel.GetSymbolInfo(node).Symbol })); var generic = removableDeclarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.GenericName)) .Cast<GenericNameSyntax>() .Where(node => symbolNames.Contains(node.Identifier.ValueText)) .Select(node => new MemberUsage { SyntaxNode = node, SemanticModel = container.SemanticModel, Symbol = container.SemanticModel.GetSymbolInfo(node).Symbol })); return identifiers.Concat(generic) .Where(tuple => tuple.Symbol is IFieldSymbol || tuple.Symbol is IPropertySymbol) .ToList(); }
private static ISet<ISymbol> GetPossiblyCopiedSymbols(RemovableDeclarationCollector removableDeclarationCollector) { var usedSymbols = new HashSet<ISymbol>(); var arguments = removableDeclarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.Argument)) .Cast<ArgumentSyntax>() .Select(node => new SyntaxNodeSemanticModelTuple<SyntaxNode> { SyntaxNode = node.Expression, SemanticModel = container.SemanticModel })); var equalsValue = removableDeclarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .OfType<EqualsValueClauseSyntax>() .Select(node => new SyntaxNodeSemanticModelTuple<SyntaxNode> { SyntaxNode = node.Value, SemanticModel = container.SemanticModel })); var assignment = removableDeclarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.SimpleAssignmentExpression)) .Cast<AssignmentExpressionSyntax>() .Select(node => new SyntaxNodeSemanticModelTuple<SyntaxNode> { SyntaxNode = node.Right, SemanticModel = container.SemanticModel })); var allNodes = arguments .Concat(equalsValue) .Concat(assignment); foreach (var node in allNodes) { var symbol = node.SemanticModel.GetSymbolInfo(node.SyntaxNode).Symbol as IEventSymbol; if (symbol != null) { usedSymbols.Add(symbol.OriginalDefinition); } } return usedSymbols; }
private static ISet<ISymbol> GetInvokedEventSymbols(RemovableDeclarationCollector removableDeclarationCollector) { var delegateInvocations = removableDeclarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.InvocationExpression)) .Cast<InvocationExpressionSyntax>() .Select(node => new SyntaxNodeSymbolSemanticModelTuple<InvocationExpressionSyntax, IMethodSymbol> { SyntaxNode = node, SemanticModel = container.SemanticModel, Symbol = container.SemanticModel.GetSymbolInfo(node).Symbol as IMethodSymbol })) .Where(tuple => tuple.Symbol != null && tuple.Symbol.MethodKind == MethodKind.DelegateInvoke); var invokedEventSymbols = delegateInvocations .Select(tuple => new SyntaxNodeSemanticModelTuple<ExpressionSyntax> { SyntaxNode = GetEventExpressionFromInvocation(tuple.SyntaxNode, tuple.Symbol), SemanticModel = tuple.SemanticModel }) .Select(tuple => new SyntaxNodeSymbolSemanticModelTuple<ExpressionSyntax, IEventSymbol> { SyntaxNode = tuple.SyntaxNode, SemanticModel = tuple.SemanticModel, Symbol = tuple.SemanticModel.GetSymbolInfo(tuple.SyntaxNode).Symbol as IEventSymbol }) .Where(tuple => tuple.Symbol != null) .Select(tuple => tuple.Symbol.OriginalDefinition); return new HashSet<ISymbol>(invokedEventSymbols); }
private static ISet<ISymbol> GetReferencedSymbolsWithMatchingNames(RemovableDeclarationCollector removableDeclarationCollector, ISet<string> symbolNames) { var usedSymbols = new HashSet<ISymbol>(); var identifiers = removableDeclarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.IdentifierName)) .Cast<IdentifierNameSyntax>() .Where(node => symbolNames.Contains(node.Identifier.ValueText)) .Select(node => new SyntaxNodeSemanticModelTuple<SyntaxNode> { SyntaxNode = node, SemanticModel = container.SemanticModel })); var generic = removableDeclarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.GenericName)) .Cast<GenericNameSyntax>() .Where(node => symbolNames.Contains(node.Identifier.ValueText)) .Select(node => new SyntaxNodeSemanticModelTuple<SyntaxNode> { SyntaxNode = node, SemanticModel = container.SemanticModel })); var allNodes = identifiers.Concat(generic); foreach (var node in allNodes) { var symbol = node.SemanticModel.GetSymbolInfo(node.SyntaxNode).Symbol; if (symbol != null) { usedSymbols.Add(symbol.OriginalDefinition); } } return usedSymbols; }
private static void CollectUsedSymbols(RemovableDeclarationCollector declarationCollector, HashSet<ISymbol> usedSymbols, HashSet<ISymbol> declaredPrivateSymbols) { var symbolNames = declaredPrivateSymbols.Select(s => s.Name).ToImmutableHashSet(); var anyRemovableIndexers = declaredPrivateSymbols .OfType<IPropertySymbol>() .Any(p => p.IsIndexer); var anyRemovableCtors = declaredPrivateSymbols .OfType<IMethodSymbol>() .Any(m => m.MethodKind == MethodKind.Constructor); var identifiers = declarationCollector.ClassDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.IdentifierName)) .Cast<IdentifierNameSyntax>() .Where(node => symbolNames.Contains(node.Identifier.ValueText)) .Select(node => new SyntaxNodeSemanticModelTuple<SyntaxNode> { SyntaxNode = node, SemanticModel = container.SemanticModel })); var generic = declarationCollector.ClassDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.GenericName)) .Cast<GenericNameSyntax>() .Where(node => symbolNames.Contains(node.Identifier.ValueText)) .Select(node => new SyntaxNodeSemanticModelTuple<SyntaxNode> { SyntaxNode = node, SemanticModel = container.SemanticModel })); var allNodes = identifiers.Concat(generic); if (anyRemovableIndexers) { var nodes = declarationCollector.ClassDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.ElementAccessExpression)) .Select(node => new SyntaxNodeSemanticModelTuple<SyntaxNode> { SyntaxNode = node, SemanticModel = container.SemanticModel })); allNodes = allNodes.Concat(nodes); } if (anyRemovableCtors) { var nodes = declarationCollector.ClassDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.ObjectCreationExpression)) .Select(node => new SyntaxNodeSemanticModelTuple<SyntaxNode> { SyntaxNode = node, SemanticModel = container.SemanticModel })); allNodes = allNodes.Concat(nodes); } foreach (var node in allNodes) { var symbol = node.SemanticModel.GetSymbolInfo(node.SyntaxNode).Symbol; var methodSymbol = symbol as IMethodSymbol; if (methodSymbol != null && methodSymbol.MethodKind == MethodKind.ReducedExtension) { symbol = methodSymbol.ReducedFrom; } if (symbol != null) { usedSymbols.Add(symbol.OriginalDefinition); } } }
private static void CollectUsedSymbolsFromCtorInitializerAndCollectEmptyCtors( RemovableDeclarationCollector declarationCollector, HashSet<ISymbol> usedSymbols, HashSet<ISymbol> emptyConstructors) { var ctors = declarationCollector.ClassDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes(RemovableDeclarationCollector.IsNodeStructOrClassDeclaration) .Where(node => node.IsKind(SyntaxKind.ConstructorDeclaration)) .Select(node => new SyntaxNodeSemanticModelTuple<ConstructorDeclarationSyntax> { SyntaxNode = (ConstructorDeclarationSyntax)node, SemanticModel = container.SemanticModel })); foreach (var ctor in ctors) { if (ctor.SyntaxNode.Body == null || !ctor.SyntaxNode.Body.Statements.Any()) { var ctorSymbol = ctor.SemanticModel.GetDeclaredSymbol(ctor.SyntaxNode); if (ctorSymbol != null && !ctorSymbol.Parameters.Any()) { emptyConstructors.Add(ctorSymbol.OriginalDefinition); } } if (ctor.SyntaxNode.Initializer == null) { continue; } var baseCtor = ctor.SemanticModel.GetSymbolInfo(ctor.SyntaxNode.Initializer).Symbol; if (baseCtor != null) { usedSymbols.Add(baseCtor); } } }
private static void CollectRemovableNamedTypes(RemovableDeclarationCollector declarationCollector, HashSet<ISymbol> declaredPrivateSymbols) { var symbols = declarationCollector.ClassDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes(RemovableDeclarationCollector.IsNodeContainerTypeDeclaration) .Where(node => node.IsKind(SyntaxKind.ClassDeclaration) || node.IsKind(SyntaxKind.InterfaceDeclaration) || node.IsKind(SyntaxKind.StructDeclaration) || node.IsKind(SyntaxKind.DelegateDeclaration)) .Select(node => new SyntaxNodeSemanticModelTuple<SyntaxNode> { SyntaxNode = node, SemanticModel = container.SemanticModel })) .Select(node => node.SemanticModel.GetDeclaredSymbol(node.SyntaxNode)) .Where(symbol => RemovableDeclarationCollector.IsRemovable(symbol, maxAccessibility)); declaredPrivateSymbols.UnionWith(symbols); }
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); } }
private static void CollectRemovableEventsAndProperties(RemovableDeclarationCollector helper, HashSet<ISymbol> declaredPrivateSymbols) { var declarationKinds = ImmutableHashSet.Create(SyntaxKind.EventDeclaration, SyntaxKind.PropertyDeclaration, SyntaxKind.IndexerDeclaration); var declarations = helper.GetRemovableDeclarations(declarationKinds, maxAccessibility); declaredPrivateSymbols.UnionWith(declarations.Select(d => d.Symbol)); }
private static void CollectRemovableMethods(RemovableDeclarationCollector declarationCollector, HashSet<ISymbol> declaredPrivateSymbols) { var methodSymbols = declarationCollector.ClassDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes(RemovableDeclarationCollector.IsNodeContainerTypeDeclaration) .Where(node => node.IsKind(SyntaxKind.MethodDeclaration) || node.IsKind(SyntaxKind.ConstructorDeclaration)) .Select(node => new SyntaxNodeSemanticModelTuple<SyntaxNode> { SyntaxNode = node, SemanticModel = container.SemanticModel })) .Select(node => node.SemanticModel.GetDeclaredSymbol(node.SyntaxNode) as IMethodSymbol) .Where(method => RemovableDeclarationCollector.IsRemovable(method, maxAccessibility)); declaredPrivateSymbols.UnionWith(methodSymbols); }
private static IEnumerable<SyntaxNodeSymbolSemanticModelTuple<MethodDeclarationSyntax, IMethodSymbol>> CollectRemovableMethods( RemovableDeclarationCollector removableDeclarationCollector) { return removableDeclarationCollector.ClassDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes(RemovableDeclarationCollector.IsNodeContainerTypeDeclaration) .OfType<MethodDeclarationSyntax>() .Select(node => new SyntaxNodeSymbolSemanticModelTuple<MethodDeclarationSyntax, IMethodSymbol> { SyntaxNode = node, SemanticModel = container.SemanticModel, Symbol = container.SemanticModel.GetDeclaredSymbol(node) })) .Where(node => node.Symbol != null && !node.Symbol.ReturnsVoid && RemovableDeclarationCollector.IsRemovable(node.Symbol, Accessibility.Private)); }