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 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 void CollectUsedSymbolsFromCtorInitializerAndCollectEmptyCtors( RemovableDeclarationCollector declarationCollector, HashSet <ISymbol> usedSymbols, HashSet <ISymbol> emptyConstructors) { var ctors = declarationCollector.TypeDeclarations .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; } usedSymbols.UnionWith(GetAllCandidateSymbols(ctor.SemanticModel.GetSymbolInfo(ctor.SyntaxNode.Initializer))); } }
private static void CheckClassWithOnlyUnusedPrivateConstructors(SymbolAnalysisContext context) { var namedType = context.Symbol as INamedTypeSymbol; if (!IsNonStaticClassWithNoAttributes(namedType)) { return; } var members = namedType.GetMembers(); var constructors = GetConstructors(members).ToList(); if (!HasOnlyCandidateConstructors(constructors) || HasOnlyStaticMembers(members.Except(constructors).ToList())) { return; } var typeDeclarations = new RemovableDeclarationCollector(namedType, context.Compilation).TypeDeclarations; if (!IsAnyConstructorCalled(namedType, typeDeclarations)) { var message = constructors.Count > 1 ? "at least one of its constructors" : "its constructor"; foreach (var classDeclaration in typeDeclarations) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(Rule, classDeclaration.SyntaxNode.Identifier.GetLocation(), message)); } } }
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 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.TypeDeclarations .SelectMany(GetMethodsNodesAndModels) .Select(node => node.SemanticModel.GetDeclaredSymbol(node.SyntaxNode) as IMethodSymbol) .Select(symbol => symbol.PartialDefinitionPart ?? symbol) .Where(method => RemovableDeclarationCollector.IsRemovable(method, maxAccessibility)); declaredPrivateSymbols.UnionWith(methodSymbols); }
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 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); }
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 IEnumerable <SyntaxNodeSymbolSemanticModelTuple <MethodDeclarationSyntax, IMethodSymbol> > CollectRemovableMethods( RemovableDeclarationCollector removableDeclarationCollector) { return(removableDeclarationCollector.TypeDeclarations .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))); }
private static void CollectRemovableMethods(RemovableDeclarationCollector declarationCollector, HashSet <ISymbol> declaredPrivateSymbols) { var methodSymbols = declarationCollector.TypeDeclarations .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); }
protected sealed 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.TypeDeclarations).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 sealed 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>(); var propertyAccessorAccess = new Dictionary <IPropertySymbol, AccessorAccess>(); CollectUsedSymbols(declarationCollector, usedSymbols, declaredPrivateSymbols, propertyAccessorAccess); CollectUsedSymbolsFromCtorInitializerAndCollectEmptyCtors(declarationCollector, usedSymbols, emptyConstructors); ReportIssues(c, usedSymbols, declaredPrivateSymbols, emptyConstructors, fieldLikeSymbols); ReportUnusedPropertyAccessors(c, usedSymbols, declaredPrivateSymbols, propertyAccessorAccess); }, SymbolKind.NamedType); }
private static void CollectRemovableNamedTypes(RemovableDeclarationCollector declarationCollector, HashSet <ISymbol> declaredPrivateSymbols) { var symbols = declarationCollector.TypeDeclarations .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, Accessibility.Internal)); declaredPrivateSymbols.UnionWith(symbols); }
protected override void Initialize(SonarAnalysisContext context) { context.RegisterSymbolAction( analysisContext => { var namedType = analysisContext.Symbol as INamedTypeSymbol; if (!namedType.IsClass() || namedType.Implements(KnownType.System_IDisposable)) { return; } var disposableFields = namedType.GetMembers().OfType <IFieldSymbol>() .Where(IsNonStaticNonPublicDisposableField).ToHashSet(); var disposableFieldsWithInitializer = disposableFields .Where(f => IsOwnerSinceDeclaration(f)); var otherInitializationsOfFields = namedType.GetMembers().OfType <IMethodSymbol>(). SelectMany(m => GetAssignementsToFieldsIn(m, analysisContext.Compilation)). Where(f => disposableFields.Contains(f)); var message = string.Join(", ", disposableFieldsWithInitializer. Union(otherInitializationsOfFields). Distinct(). Select(symbol => $"'{symbol.Name}'"). OrderBy(s => s)); if (!string.IsNullOrEmpty(message)) { var typeDeclarations = new RemovableDeclarationCollector(namedType, analysisContext.Compilation).TypeDeclarations; foreach (var classDeclaration in typeDeclarations) { analysisContext.ReportDiagnosticIfNonGenerated( Diagnostic.Create(rule, classDeclaration.SyntaxNode.Identifier.GetLocation(), message)); } } }, SymbolKind.NamedType); }
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.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 = declarationCollector.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); if (anyRemovableIndexers) { var nodes = declarationCollector.TypeDeclarations .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.TypeDeclarations .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); } var candidateSymbols = allNodes .Select(n => n.SemanticModel.GetSymbolInfo(n.SyntaxNode)) .SelectMany(s => GetAllCandidateSymbols(s)) .Select(s => GetOriginalSymbol(s)) .Where(s => s != null); usedSymbols.UnionWith(candidateSymbols); }
protected sealed override void Initialize(SonarAnalysisContext context) { context.RegisterCompilationStartAction( c => { var shouldRaise = true; possibleUnusedInternalMembers = new ConcurrentBag <Diagnostic>(); c.RegisterSemanticModelAction( cc => { var isInternalsVisibleToAttributeFound = cc.SemanticModel.SyntaxTree.GetRoot() .DescendantNodes() .OfType <AttributeListSyntax>() .SelectMany(list => list.Attributes) .Any(a => IsInternalVisibleToAttribute(a, cc.SemanticModel)); if (isInternalsVisibleToAttributeFound) { shouldRaise = false; } }); c.RegisterSymbolAction( cc => { var namedType = (INamedTypeSymbol)cc.Symbol; if (!namedType.IsClassOrStruct() || namedType.ContainingType != null) { return; } var declarationCollector = new RemovableDeclarationCollector(namedType, cc.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>(); var propertyAccessorAccess = new Dictionary <IPropertySymbol, AccessorAccess>(); CollectUsedSymbols(declarationCollector, usedSymbols, declaredPrivateSymbols, propertyAccessorAccess); CollectUsedSymbolsFromCtorInitializerAndCollectEmptyCtors(declarationCollector, usedSymbols, emptyConstructors); ReportIssues(cc, usedSymbols, declaredPrivateSymbols, emptyConstructors, fieldLikeSymbols); ReportUnusedPropertyAccessors(cc, usedSymbols, declaredPrivateSymbols, propertyAccessorAccess); }, SymbolKind.NamedType); c.RegisterCompilationEndAction( cc => { if (!shouldRaise) { return; } foreach (var diagnostic in possibleUnusedInternalMembers) { cc.ReportDiagnosticIfNonGenerated(diagnostic, cc.Compilation); } }); }); }
private static void CollectUsedSymbols(RemovableDeclarationCollector declarationCollector, HashSet <ISymbol> usedSymbols, HashSet <ISymbol> declaredPrivateSymbols, Dictionary <IPropertySymbol, AccessorAccess> propertyAccessorAccess) { var symbolNames = declaredPrivateSymbols.Select(s => s.Name).ToHashSet(); var anyRemovableIndexers = declaredPrivateSymbols .OfType <IPropertySymbol>() .Any(p => p.IsIndexer); var anyRemovableCtors = declaredPrivateSymbols .OfType <IMethodSymbol>() .Any(m => m.MethodKind == MethodKind.Constructor); var identifiers = declarationCollector.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 <ExpressionSyntax> { SyntaxNode = node, SemanticModel = container.SemanticModel })); var generic = declarationCollector.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 <ExpressionSyntax> { SyntaxNode = node, SemanticModel = container.SemanticModel })); var allNodes = identifiers.Concat(generic); if (anyRemovableIndexers) { var nodes = declarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.ElementAccessExpression)) .Cast <ElementAccessExpressionSyntax>() .Select(node => new SyntaxNodeSemanticModelTuple <ExpressionSyntax> { SyntaxNode = node, SemanticModel = container.SemanticModel })); allNodes = allNodes.Concat(nodes); } if (anyRemovableCtors) { var nodes = declarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .Where(node => node.IsKind(SyntaxKind.ObjectCreationExpression)) .Cast <ObjectCreationExpressionSyntax>() .Select(node => new SyntaxNodeSemanticModelTuple <ExpressionSyntax> { SyntaxNode = node, SemanticModel = container.SemanticModel })); allNodes = allNodes.Concat(nodes); } var candidateSymbols = allNodes .Select(n => new { Syntax = n.SyntaxNode, SemanticModel = n.SemanticModel, Symbol = n.SemanticModel.GetSymbolInfo(n.SyntaxNode) }) .Select(n => new { Syntax = n.Syntax, SemanticModel = n.SemanticModel, Symbols = GetAllCandidateSymbols(n.Symbol) .Select(s => GetOriginalSymbol(s)) .Where(s => s != null) }); foreach (var candidateSymbol in candidateSymbols) { usedSymbols.UnionWith(candidateSymbol.Symbols); var accessorKind = GetAccessorAccessKind(candidateSymbol.Syntax, candidateSymbol.SemanticModel); foreach (var propertySymbol in candidateSymbol.Symbols.OfType <IPropertySymbol>()) { if (propertyAccessorAccess.ContainsKey(propertySymbol)) { propertyAccessorAccess[propertySymbol] |= accessorKind; } else { propertyAccessorAccess[propertySymbol] = accessorKind; } } } }
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.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 = declarationCollector.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); if (anyRemovableIndexers) { var nodes = declarationCollector.TypeDeclarations .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.TypeDeclarations .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?.MethodKind == MethodKind.ReducedExtension) { symbol = methodSymbol.ReducedFrom; } if (symbol != null) { usedSymbols.Add(symbol.OriginalDefinition); } } }