private static void AnalyzeNamedTypes(SymbolAnalysisContext context) { var namedType = (INamedTypeSymbol)context.Symbol; if (!namedType.IsClassOrStruct() || namedType.ContainingType != null) { return; } var removableDeclarationCollector = new CSharpRemovableDeclarationCollector(namedType, context.Compilation); var declaredPrivateMethodsWithReturn = CollectRemovableMethods(removableDeclarationCollector).ToList(); if (!declaredPrivateMethodsWithReturn.Any()) { return; } var invocations = removableDeclarationCollector.TypeDeclarations.SelectMany(x => FilterInvocations(x)).ToList(); foreach (var declaredPrivateMethodWithReturn in declaredPrivateMethodsWithReturn) { var matchingInvocations = invocations .Where(invocation => invocation.Symbol.OriginalDefinition.Equals(declaredPrivateMethodWithReturn.Symbol)) .ToList(); // Method invocation is noncompliant when there is at least 1 invocation of the method, and no invocation is using the return value. The case of 0 invocation is handled by S1144. if (matchingInvocations.Any() && !matchingInvocations.Any(x => IsReturnValueUsed(x))) { context.ReportDiagnosticWhenActive(Diagnostic.Create(Rule, declaredPrivateMethodWithReturn.SyntaxNode.ReturnType.GetLocation())); } } }
private static IList <MemberUsage> GetMemberUsages(CSharpRemovableDeclarationCollector removableDeclarationCollector, HashSet <ISymbol> declaredPrivateSymbols) { var symbolNames = declaredPrivateSymbols.Select(s => s.Name).ToHashSet(); 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 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 CSharpRemovableDeclarationCollector(namedType, context.Compilation).TypeDeclarations; if (!IsAnyConstructorCalled <BaseTypeDeclarationSyntax, ObjectCreationExpressionSyntax, ClassDeclarationSyntax> (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)); } } }
private void CheckClassWithOnlyUnusedPrivateConstructors(SymbolAnalysisContext context) { var namedType = (INamedTypeSymbol)context.Symbol; if (!IsNonStaticClassWithNoAttributes(namedType) || DerivesFromSafeHandle(namedType)) { return; } var members = namedType.GetMembers(); var constructors = GetConstructors(members).Where(x => !x.IsImplicitlyDeclared).ToList(); if (!HasOnlyCandidateConstructors(constructors) || HasOnlyStaticMembers(members.Except(constructors).ToList())) { return; } var typeDeclarations = new CSharpRemovableDeclarationCollector(namedType, context.Compilation).TypeDeclarations; if (!IsAnyConstructorCalled <BaseTypeDeclarationSyntax, ObjectCreationExpressionSyntax>(namedType, typeDeclarations)) { var message = constructors.Count > 1 ? "at least one of its constructors" : "its constructor"; foreach (var typeDeclaration in typeDeclarations) { var declarationKind = typeDeclaration.SyntaxNode.IsKind(SyntaxKind.ClassDeclaration) ? "class" : "record"; context.ReportDiagnosticIfNonGenerated( Diagnostic.Create(Rule, typeDeclaration.SyntaxNode.Identifier.GetLocation(), declarationKind, 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 CSharpRemovableDeclarationCollector(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(invocation => invocation.Symbol.OriginalDefinition.Equals(declaredPrivateMethodWithReturn.Symbol)) .ToList(); if (IsNoncompliant(matchingInvocations)) { c.ReportDiagnosticWhenActive(Diagnostic.Create(rule, declaredPrivateMethodWithReturn.SyntaxNode.ReturnType.GetLocation())); } } }, SymbolKind.NamedType); context.RegisterSyntaxNodeActionInNonGenerated( c => { var localFunctionSyntax = (LocalFunctionStatementSyntaxWrapper)c.Node; var localFunctionSymbol = c.SemanticModel.GetDeclaredSymbol(localFunctionSyntax) as IMethodSymbol; var topmostContainingMethod = c.Node.GetTopMostContainingMethod(); if (localFunctionSymbol == null || localFunctionSymbol.ReturnsVoid || topmostContainingMethod == null) { return; } var matchingInvocations = GetLocalMatchingInvocations(topmostContainingMethod, localFunctionSymbol, c.SemanticModel); if (IsNoncompliant(matchingInvocations)) { c.ReportDiagnosticWhenActive(Diagnostic.Create(rule, localFunctionSyntax.ReturnType.GetLocation())); } }, SyntaxKindEx.LocalFunctionStatement); }
private static ISet <ISymbol> GetPossiblyCopiedSymbols(CSharpRemovableDeclarationCollector 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 SyntaxNodeAndSemanticModel <SyntaxNode> { SyntaxNode = node.Expression, SemanticModel = container.SemanticModel })); var equalsValue = removableDeclarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes() .OfType <EqualsValueClauseSyntax>() .Select(node => new SyntaxNodeAndSemanticModel <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 SyntaxNodeAndSemanticModel <SyntaxNode> { SyntaxNode = node.Right, SemanticModel = container.SemanticModel })); var allNodes = arguments .Concat(equalsValue) .Concat(assignment); foreach (var node in allNodes) { if (node.SemanticModel.GetSymbolInfo(node.SyntaxNode).Symbol is IEventSymbol symbol) { usedSymbols.Add(symbol.OriginalDefinition); } } return(usedSymbols); }
private static IEnumerable <SyntaxNodeSymbolSemanticModelTuple <MethodDeclarationSyntax, IMethodSymbol> > CollectRemovableMethods( CSharpRemovableDeclarationCollector removableDeclarationCollector) { return(removableDeclarationCollector.TypeDeclarations .SelectMany(container => container.SyntaxNode.DescendantNodes(CSharpRemovableDeclarationCollector.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 && CSharpRemovableDeclarationCollector.IsRemovable(node.Symbol, Accessibility.Private))); }
private void RaiseOnUninvokedEventDeclaration(SymbolAnalysisContext context) { var namedType = (INamedTypeSymbol)context.Symbol; if (!namedType.IsClassOrStruct() || namedType.ContainingType != null) { return; } var removableDeclarationCollector = new CSharpRemovableDeclarationCollector(namedType, context.Compilation); var removableEventFields = removableDeclarationCollector .GetRemovableFieldLikeDeclarations(eventSyntax, maxAccessibility) .ToList(); if (!removableEventFields.Any()) { return; } 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); }
protected override void Initialize(SonarAnalysisContext context) { context.RegisterSymbolAction( c => { var namedType = (INamedTypeSymbol)c.Symbol; if (!namedType.IsClassOrStruct() || namedType.ContainingType != null) { return; } var removableDeclarationCollector = new CSharpRemovableDeclarationCollector(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.ReportDiagnosticWhenActive(Diagnostic.Create(rule, declaredPrivateMethodWithReturn.SyntaxNode.ReturnType.GetLocation())); } } }, SymbolKind.NamedType); }
protected override void Initialize(SonarAnalysisContext context) => context.RegisterSymbolAction( c => { var namedType = (INamedTypeSymbol)c.Symbol; if (TypeDefinitionShouldBeSkipped(namedType)) { return; } var removableDeclarationCollector = new CSharpRemovableDeclarationCollector(namedType, c.Compilation); var allCandidateMembers = GetCandidateDeclarations(removableDeclarationCollector); 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); var unassignedUsedMemberSymbols = allCandidateMembers.Where(x => usedMemberSymbols.Contains(x.Symbol) && !assignedMemberSymbols.Contains(x.Symbol)); foreach (var candidateMember in unassignedUsedMemberSymbols) { var field = candidateMember.SyntaxNode as VariableDeclaratorSyntax; var property = candidateMember.SyntaxNode as PropertyDeclarationSyntax; var memberType = field == null ? "auto-property" : "field"; var location = field == null ? property.Identifier.GetLocation() : field.Identifier.GetLocation(); c.ReportDiagnosticIfNonGenerated(Diagnostic.Create(Rule, location, memberType, candidateMember.Symbol.Name)); } }, SymbolKind.NamedType);
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 CSharpRemovableDeclarationCollector(namedType, analysisContext.Compilation).TypeDeclarations; foreach (var classDeclaration in typeDeclarations) { analysisContext.ReportDiagnosticIfNonGenerated( Diagnostic.Create(rule, classDeclaration.SyntaxNode.Identifier.GetLocation(), message)); } } }, SymbolKind.NamedType); }
protected override void Initialize(SonarAnalysisContext context) => context.RegisterSymbolAction( analysisContext => { var namedType = (INamedTypeSymbol)analysisContext.Symbol; if (ShouldExclude(namedType)) { return; } var message = GetMessage(namedType, analysisContext); if (string.IsNullOrEmpty(message)) { return; } var typeDeclarations = new CSharpRemovableDeclarationCollector(namedType, analysisContext.Compilation).TypeDeclarations; foreach (var classDeclaration in typeDeclarations) { analysisContext.ReportDiagnosticIfNonGenerated(Diagnostic.Create(rule, classDeclaration.SyntaxNode.Identifier.GetLocation(), message)); } }, SymbolKind.NamedType);
private static ISet <ISymbol> GetInvokedEventSymbols(CSharpRemovableDeclarationCollector 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 && IsDelegateInvocation(tuple.Symbol)); var invokedEventSymbols = delegateInvocations .Select(tuple => new SyntaxNodeAndSemanticModel <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 List <SyntaxNodeSymbolSemanticModelTuple <SyntaxNode, ISymbol> > GetCandidateDeclarations(CSharpRemovableDeclarationCollector removableDeclarationCollector) { var candidateFields = removableDeclarationCollector.GetRemovableFieldLikeDeclarations(new HashSet <SyntaxKind> { SyntaxKind.FieldDeclaration }, MaxAccessibility) .Where(tuple => !IsInitializedOrFixed((VariableDeclaratorSyntax)tuple.SyntaxNode) && !HasStructLayoutAttribute(tuple.Symbol.ContainingType)); var candidateProperties = removableDeclarationCollector.GetRemovableDeclarations(new HashSet <SyntaxKind> { SyntaxKind.PropertyDeclaration }, MaxAccessibility) .Where(tuple => IsAutoPropertyWithNoInitializer((PropertyDeclarationSyntax)tuple.SyntaxNode) && !HasStructLayoutAttribute(tuple.Symbol.ContainingType)); return(candidateFields.Concat(candidateProperties).ToList()); }
protected override void Initialize(SonarAnalysisContext context) { context.RegisterSymbolAction( c => { var namedType = (INamedTypeSymbol)c.Symbol; if (!namedType.IsClassOrStruct() || namedType.GetAttributes(KnownType.System_Runtime_InteropServices_StructLayoutAttribute).Any() || namedType.ContainingType != null) { return; } var removableDeclarationCollector = new CSharpRemovableDeclarationCollector(namedType, c.Compilation); var candidateFields = removableDeclarationCollector.GetRemovableFieldLikeDeclarations( new HashSet <SyntaxKind> { SyntaxKind.FieldDeclaration }, maxAccessibility) .Where(tuple => !IsInitializedOrFixed(((VariableDeclaratorSyntax)tuple.SyntaxNode))); var candidateProperties = removableDeclarationCollector.GetRemovableDeclarations( new HashSet <SyntaxKind> { 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); }