private static void CheckClassWithOnlyUnusedPrivateConstructors(SymbolAnalysisContext context) { var namedType = context.Symbol as INamedTypeSymbol; if (!IsNonStaticClassWithNoAttributes(namedType) || DerivesFromSafeHandle(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)); } } }
public static void ReportDiagnosticIfNonGenerated( this SymbolAnalysisContext context, Diagnostic diagnostic) { context.ReportDiagnosticIfNonGenerated(VisualBasic.VisualBasicGeneratedCodeRecognizer.Instance, diagnostic, context.Compilation); }
public static void ReportDiagnosticIfNonGenerated( this SymbolAnalysisContext context, Diagnostic diagnostic, Compilation compilation) { context.ReportDiagnosticIfNonGenerated(CSharp.CSharpGeneratedCodeRecognizer.Instance, diagnostic, compilation); }
private static void CheckConstructors(INamedTypeSymbol utilityClass, SymbolAnalysisContext context) { if (!ClassQualifiesForIssue(utilityClass) || !HasMembersAndAllAreStaticExceptConstructors(utilityClass)) { return; } var reportMessage = string.Format(MessageFormatConstructor, utilityClass.IsSealed ? "private" : "protected"); foreach (var constructor in utilityClass.GetMembers() .Where(IsConstructor) .Where(symbol => ProblematicConstructorAccessibility.Contains(symbol.DeclaredAccessibility))) { var syntaxReferences = constructor.DeclaringSyntaxReferences; foreach (var syntaxReference in syntaxReferences) { var constructorDeclaration = syntaxReference.GetSyntax() as ConstructorDeclarationSyntax; if (constructorDeclaration != null) { context.ReportDiagnosticIfNonGenerated( Diagnostic.Create(rule, constructorDeclaration.Identifier.GetLocation(), reportMessage), context.Compilation); } } } }
public static void ReportDiagnosticIfNonGenerated( this SymbolAnalysisContext context, GeneratedCodeRecognizer generatedCodeRecognizer, Diagnostic diagnostic) { context.ReportDiagnosticIfNonGenerated(generatedCodeRecognizer, diagnostic, context.Compilation); }
private static void Report(INamedTypeSymbol symbol, string message, SymbolAnalysisContext context) { foreach (var declaringSyntaxReference in symbol.DeclaringSyntaxReferences) { var node = declaringSyntaxReference.GetSyntax(); if (node is ClassDeclarationSyntax classDeclaration) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(Rule, classDeclaration.Identifier.GetLocation(), "class", message)); } if (RecordDeclarationSyntaxWrapper.IsInstance(node)) { var wrapper = (RecordDeclarationSyntaxWrapper)node; context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(Rule, wrapper.Identifier.GetLocation(), "record", message)); } } }
private static void ReportDisposeMethods(IEnumerable <IMethodSymbol> disposeMethods, SymbolAnalysisContext context) { foreach (var location in disposeMethods.SelectMany(m => m.Locations)) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create( rule, location)); } }
private static void ReportIssues(SymbolAnalysisContext context, HashSet <ISymbol> usedSymbols, HashSet <ISymbol> declaredPrivateSymbols, HashSet <ISymbol> emptyConstructors, BidirectionalDictionary <ISymbol, SyntaxNode> fieldLikeSymbols) { var unusedSymbols = declaredPrivateSymbols .Except(usedSymbols.Union(emptyConstructors)) .ToList(); var alreadyReportedFieldLikeSymbols = new HashSet <ISymbol>(); var unusedSymbolSyntaxPairs = unusedSymbols .SelectMany(unusedSymbol => unusedSymbol.DeclaringSyntaxReferences .Select(r => new { Syntax = r.GetSyntax(), Symbol = unusedSymbol })); foreach (var unused in unusedSymbolSyntaxPairs) { var location = unused.Syntax.GetLocation(); var canBeFieldLike = unused.Symbol is IFieldSymbol || unused.Symbol is IEventSymbol; if (canBeFieldLike) { if (alreadyReportedFieldLikeSymbols.Contains(unused.Symbol)) { continue; } var variableDeclaration = GetVariableDeclaration(unused.Syntax); if (variableDeclaration == null) { continue; } var declarations = variableDeclaration.Variables .Select(v => fieldLikeSymbols.GetByB(v)) .ToList(); if (declarations.All(d => unusedSymbols.Contains(d))) { location = unused.Syntax.Parent.Parent.GetLocation(); alreadyReportedFieldLikeSymbols.UnionWith(declarations); } } var memberKind = GetMemberType(unused.Symbol); var memberName = GetMemberName(unused.Symbol); context.ReportDiagnosticIfNonGenerated( Diagnostic.Create(rule, location, memberKind, memberName), context.Compilation); } }
private static void ReportClass(INamedTypeSymbol symbol, string message, SymbolAnalysisContext context) { foreach (var declaringSyntaxReference in symbol.DeclaringSyntaxReferences) { if (declaringSyntaxReference.GetSyntax() is ClassDeclarationSyntax classDeclaration) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(rule, classDeclaration.Identifier.GetLocation(), message)); } } }
private static void ReportClass(INamedTypeSymbol symbol, string message, SymbolAnalysisContext c) { foreach (var declaringSyntaxReference in symbol.DeclaringSyntaxReferences) { var classDeclaration = declaringSyntaxReference.GetSyntax() as ClassDeclarationSyntax; if (classDeclaration != null) { c.ReportDiagnosticIfNonGenerated( Diagnostic.Create(Rule, classDeclaration.Identifier.GetLocation(), message), c.Compilation); } } }
private static void ReportUnusedPropertyAccessors(SymbolAnalysisContext context, HashSet <ISymbol> usedSymbols, HashSet <ISymbol> declaredPrivateSymbols, Dictionary <IPropertySymbol, AccessorAccess> propertyAccessorAccess) { var usedPrivatePropertis = declaredPrivateSymbols.Intersect(usedSymbols).OfType <IPropertySymbol>(); var onlyOneAccessorAccessed = usedPrivatePropertis.Where(p => propertyAccessorAccess.ContainsKey(p)); foreach (var property in onlyOneAccessorAccessed) { var access = propertyAccessorAccess[property]; if (access == AccessorAccess.None || access == AccessorAccess.Both) { continue; } if (access == AccessorAccess.Get && property.SetMethod != null) { var accessorSyntax = GetAccessorSyntax(property.SetMethod); if (accessorSyntax != null) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(rule, accessorSyntax.GetLocation(), "private", "set accessor in property", property.Name), context.Compilation); } continue; } if (access == AccessorAccess.Set && property.GetMethod != null) { var accessorSyntax = GetAccessorSyntax(property.GetMethod); if (accessorSyntax != null && accessorSyntax.Body != null) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(rule, accessorSyntax.GetLocation(), "private", "get accessor in property", property.Name), context.Compilation); } } } }
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 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(); context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(rule, location)); } } }
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 void CheckClasses(INamedTypeSymbol utilityClass, SymbolAnalysisContext context) { if (!ClassIsRelevant(utilityClass)) { return; } var reportMessage = string.Format(MessageFormatStaticClass, utilityClass.IsSealed ? "private" : "protected"); foreach (var syntaxReference in utilityClass.DeclaringSyntaxReferences) { if (syntaxReference.GetSyntax() is ClassDeclarationSyntax classDeclarationSyntax) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(rule, classDeclarationSyntax.Identifier.GetLocation(), reportMessage)); } } }
private static void CheckFieldOrProperty <T>(T propertyOrField, INamedTypeSymbol containerClassSymbol, SymbolAnalysisContext context, Func <T, Location> locationSelector, string memberType) where T : ISymbol { var shadowsProperty = GetSelfAndOuterClasses(containerClassSymbol) .SelectMany(c => c.GetMembers(propertyOrField.Name)) .OfType <IPropertySymbol>() .Any(prop => prop.IsStatic); var shadowsField = GetSelfAndOuterClasses(containerClassSymbol) .SelectMany(c => c.GetMembers(propertyOrField.Name)) .OfType <IFieldSymbol>() .Any(field => field.IsStatic || field.IsConst); if (shadowsProperty || shadowsField) { var location = locationSelector(propertyOrField); if (location != null) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(rule, location, memberType)); } } }
private static void CheckEventOrMethod <T>(T eventOrMethod, INamedTypeSymbol containerClassSymbol, SymbolAnalysisContext context, Func <T, Location> locationSelector, string memberType) where T : ISymbol { var shadowsMethod = GetSelfAndOuterClasses(containerClassSymbol) .SelectMany(c => c.GetMembers(eventOrMethod.Name)) .OfType <IMethodSymbol>() .Any(method => method.IsStatic); var shadowsEvent = GetSelfAndOuterClasses(containerClassSymbol) .SelectMany(c => c.GetMembers(eventOrMethod.Name)) .OfType <IEventSymbol>() .Any(@event => @event.IsStatic); if (shadowsMethod || shadowsEvent) { var location = locationSelector(eventOrMethod); if (location != null) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(rule, location, memberType)); } } }
private void ReportIssues(SymbolAnalysisContext context, HashSet <ISymbol> usedSymbols, HashSet <ISymbol> declaredPrivateSymbols, HashSet <ISymbol> emptyConstructors, BidirectionalDictionary <ISymbol, SyntaxNode> fieldLikeSymbols) { var unusedSymbols = declaredPrivateSymbols .Except(usedSymbols.Union(emptyConstructors)) .ToList(); var alreadyReportedFieldLikeSymbols = new HashSet <ISymbol>(); var unusedSymbolSyntaxPairs = unusedSymbols .SelectMany(unusedSymbol => unusedSymbol.DeclaringSyntaxReferences .Select(r => new { Syntax = r.GetSyntax(), Symbol = unusedSymbol })); foreach (var unused in unusedSymbolSyntaxPairs) { var location = unused.Syntax.GetLocation(); var canBeFieldLike = unused.Symbol is IFieldSymbol || unused.Symbol is IEventSymbol; if (canBeFieldLike) { if (alreadyReportedFieldLikeSymbols.Contains(unused.Symbol)) { continue; } var variableDeclaration = GetVariableDeclaration(unused.Syntax); if (variableDeclaration == null) { continue; } var declarations = variableDeclaration.Variables .Select(v => fieldLikeSymbols.GetByB(v)) .ToList(); if (declarations.All(d => unusedSymbols.Contains(d))) { location = unused.Syntax.Parent.Parent.GetLocation(); alreadyReportedFieldLikeSymbols.UnionWith(declarations); } } var memberKind = GetMemberType(unused.Symbol); var memberName = GetMemberName(unused.Symbol); var effectiveAccessibility = unused.Symbol.GetEffectiveAccessibility(); if (effectiveAccessibility == Accessibility.Internal) { // We can't report internal members directly because they might be used through another assembly. possibleUnusedInternalMembers.Add( Diagnostic.Create(rule, location, "internal", memberKind, memberName)); continue; } if (effectiveAccessibility == Accessibility.Private) { context.ReportDiagnosticIfNonGenerated( Diagnostic.Create(rule, location, "private", memberKind, memberName), context.Compilation); } } }
private static void CheckConstructors(INamedTypeSymbol utilityClass, SymbolAnalysisContext c) { if (!ClassQualifiesForIssue(utilityClass) || !HasMembersAndAllAreStaticExceptConstructors(utilityClass)) { return; } var reportMessage = string.Format(MessageFormatConstructor, utilityClass.IsSealed ? "private" : "protected"); foreach (var constructor in utilityClass.GetMembers() .Where(IsConstructor) .Where(symbol => ProblematicConstructorAccessibility.Contains(symbol.DeclaredAccessibility))) { var syntaxReferences = constructor.DeclaringSyntaxReferences; foreach (var syntaxReference in syntaxReferences) { var constructorDeclaration = syntaxReference.GetSyntax() as ConstructorDeclarationSyntax; if (constructorDeclaration != null) { c.ReportDiagnosticIfNonGenerated( Diagnostic.Create(Rule, constructorDeclaration.Identifier.GetLocation(), reportMessage), c.Compilation); } } } }
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)); } } }
private static void ReportDisposeMethods(IEnumerable<IMethodSymbol> disposeMethods, SymbolAnalysisContext context) { foreach (var location in disposeMethods.SelectMany(m => m.Locations)) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create( Rule, location)); } }
private static void ReportClass(INamedTypeSymbol symbol, string message, SymbolAnalysisContext c) { foreach (var declaringSyntaxReference in symbol.DeclaringSyntaxReferences) { var classDeclaration = declaringSyntaxReference.GetSyntax() as ClassDeclarationSyntax; if (classDeclaration != null) { c.ReportDiagnosticIfNonGenerated(Diagnostic.Create(Rule, classDeclaration.Identifier.GetLocation(), message)); } } }
private static void ReportIssues(SymbolAnalysisContext context, HashSet<ISymbol> usedSymbols, HashSet<ISymbol> declaredPrivateSymbols, HashSet<ISymbol> emptyConstructors, BidirectionalDictionary<ISymbol, SyntaxNode> fieldLikeSymbols) { var unusedSymbols = declaredPrivateSymbols .Except(usedSymbols.Union(emptyConstructors)) .ToList(); var alreadyReportedFieldLikeSymbols = new HashSet<ISymbol>(); var unusedSymbolSyntaxPairs = unusedSymbols .SelectMany(unusedSymbol => unusedSymbol.DeclaringSyntaxReferences .Select(r => new { Syntax = r.GetSyntax(), Symbol = unusedSymbol })); foreach (var unused in unusedSymbolSyntaxPairs) { var location = unused.Syntax.GetLocation(); var canBeFieldLike = unused.Symbol is IFieldSymbol || unused.Symbol is IEventSymbol; if (canBeFieldLike) { if (alreadyReportedFieldLikeSymbols.Contains(unused.Symbol)) { continue; } var variableDeclaration = GetVariableDeclaration(unused.Syntax); if (variableDeclaration == null) { continue; } var declarations = variableDeclaration.Variables .Select(v => fieldLikeSymbols.GetByB(v)) .ToList(); if (declarations.All(d => unusedSymbols.Contains(d))) { location = unused.Syntax.Parent.Parent.GetLocation(); alreadyReportedFieldLikeSymbols.UnionWith(declarations); } } context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(Rule, location), context.Compilation); } }
private static void ReportUnusedParametersOnMethod(IMethodSymbol methodSymbol, SymbolAnalysisContext context) { if (!MethodCanBeSafelyChanged(methodSymbol)) { return; } var unusedParameters = GetUnusedParameters(methodSymbol, context.Compilation); if (!unusedParameters.Any() || IsUsedAsEventHandlerFunctionOrAction(methodSymbol, context.Compilation)) { return; } foreach (var unusedParameter in unusedParameters) { foreach (var unusedParameterDeclaration in unusedParameter.DeclaringSyntaxReferences.Select(r => r.GetSyntax())) { context.ReportDiagnosticIfNonGenerated(Diagnostic.Create(Rule, unusedParameterDeclaration.GetLocation(), unusedParameter.Name)); } } }
private static void CheckClasses(INamedTypeSymbol utilityClass, SymbolAnalysisContext c) { if (!ClassIsRelevant(utilityClass)) { return; } var reportMessage = string.Format(MessageFormatStaticClass, utilityClass.IsSealed ? "private" : "protected"); foreach (var syntaxReference in utilityClass.DeclaringSyntaxReferences) { var classDeclarationSyntax = syntaxReference.GetSyntax() as ClassDeclarationSyntax; if (classDeclarationSyntax != null) { c.ReportDiagnosticIfNonGenerated( Diagnostic.Create(Rule, classDeclarationSyntax.Identifier.GetLocation(), reportMessage), c.Compilation); } } }
public static void ReportDiagnosticIfNonGenerated(this SymbolAnalysisContext context, Diagnostic diagnostic) => context.ReportDiagnosticIfNonGenerated(CSharpGeneratedCodeRecognizer.Instance, diagnostic);