private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context) { var typeDeclaration = (TypeDeclarationSyntax)context.Node; if (typeDeclaration.Modifiers.Contains(SyntaxKind.PartialKeyword)) return; SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; INamedTypeSymbol declarationSymbol = null; ImmutableArray<AttributeData> attributes = default; if (typeDeclaration.IsKind(SyntaxKind.StructDeclaration)) { declarationSymbol = semanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken); attributes = declarationSymbol.GetAttributes(); if (attributes.Any(f => f.AttributeClass.HasMetadataName(MetadataNames.System_Runtime_InteropServices_StructLayoutAttribute))) return; } bool? canContainUnityScriptMethods = null; SyntaxList<MemberDeclarationSyntax> members = typeDeclaration.Members; UnusedMemberWalker walker = null; foreach (MemberDeclarationSyntax member in members) { if (member.ContainsDiagnostics) continue; if (member.ContainsUnbalancedIfElseDirectives(member.Span)) continue; switch (member.Kind()) { case SyntaxKind.DelegateDeclaration: { var declaration = (DelegateDeclarationSyntax)member; if (SyntaxAccessibility<DelegateDeclarationSyntax>.Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) walker = UnusedMemberWalker.GetInstance(); walker.AddDelegate(declaration.Identifier.ValueText, declaration); } break; } case SyntaxKind.EventDeclaration: { var declaration = (EventDeclarationSyntax)member; if (declaration.ExplicitInterfaceSpecifier == null && SyntaxAccessibility<EventDeclarationSyntax>.Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) walker = UnusedMemberWalker.GetInstance(); walker.AddNode(declaration.Identifier.ValueText, declaration); } break; } case SyntaxKind.EventFieldDeclaration: { var declaration = (EventFieldDeclarationSyntax)member; if (SyntaxAccessibility<EventFieldDeclarationSyntax>.Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) walker = UnusedMemberWalker.GetInstance(); walker.AddNodes(declaration.Declaration); } break; } case SyntaxKind.FieldDeclaration: { var declaration = (FieldDeclarationSyntax)member; SyntaxTokenList modifiers = declaration.Modifiers; if (SyntaxAccessibility<FieldDeclarationSyntax>.Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) walker = UnusedMemberWalker.GetInstance(); walker.AddNodes(declaration.Declaration, isConst: modifiers.Contains(SyntaxKind.ConstKeyword)); } break; } case SyntaxKind.MethodDeclaration: { var declaration = (MethodDeclarationSyntax)member; SyntaxTokenList modifiers = declaration.Modifiers; if (declaration.ExplicitInterfaceSpecifier != null || declaration.AttributeLists.Any() || SyntaxAccessibility<MethodDeclarationSyntax>.Instance.GetAccessibility(declaration) != Accessibility.Private) { break; } string methodName = declaration.Identifier.ValueText; if (IsMainMethod(declaration, modifiers, methodName)) break; if (declaration.ReturnsVoid() && AnalyzerOptions.SuppressUnityScriptMethods.IsEnabled(context)) { if (canContainUnityScriptMethods == null) { if (declarationSymbol == null) declarationSymbol = semanticModel.GetDeclaredSymbol(typeDeclaration, context.CancellationToken); canContainUnityScriptMethods = declarationSymbol.InheritsFrom(UnityScriptMethods.MonoBehaviourClassName); } if (canContainUnityScriptMethods == true && UnityScriptMethods.MethodNames.Contains(methodName)) { break; } } if (walker == null) walker = UnusedMemberWalker.GetInstance(); walker.AddNode(methodName, declaration); break; } case SyntaxKind.PropertyDeclaration: { var declaration = (PropertyDeclarationSyntax)member; if (declaration.ExplicitInterfaceSpecifier == null && SyntaxAccessibility<PropertyDeclarationSyntax>.Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) walker = UnusedMemberWalker.GetInstance(); walker.AddNode(declaration.Identifier.ValueText, declaration); } break; } } } if (walker == null) return; try { Collection<NodeSymbolInfo> nodes = walker.Nodes; if (ShouldAnalyzeDebuggerDisplayAttribute() && nodes.Any(f => f.CanBeInDebuggerDisplayAttribute)) { if (attributes.IsDefault) attributes = semanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken).GetAttributes(); string value = attributes .FirstOrDefault(f => f.AttributeClass.HasMetadataName(MetadataNames.System_Diagnostics_DebuggerDisplayAttribute))? .ConstructorArguments .SingleOrDefault(shouldThrow: false) .Value? .ToString(); if (value != null) RemoveMethodsAndPropertiesThatAreInDebuggerDisplayAttributeValue(value, ref nodes); } if (nodes.Count > 0) { walker.SemanticModel = semanticModel; walker.CancellationToken = cancellationToken; walker.Visit(typeDeclaration); foreach (NodeSymbolInfo node in nodes) ReportDiagnostic(context, node.Node); } } finally { UnusedMemberWalker.Free(walker); } bool ShouldAnalyzeDebuggerDisplayAttribute() { foreach (AttributeListSyntax attributeList in typeDeclaration.AttributeLists) { foreach (AttributeSyntax attribute in attributeList.Attributes) { if (attribute.ArgumentList?.Arguments.Count(f => f.NameEquals == null) == 1) return true; } } return false; } }
private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context, TypeDeclarationSyntax typeDeclaration) { if (typeDeclaration.Modifiers.Contains(SyntaxKind.PartialKeyword)) { return; } SyntaxList <MemberDeclarationSyntax> members = typeDeclaration.Members; UnusedMemberWalker walker = null; SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; foreach (MemberDeclarationSyntax member in members) { if (member.ContainsDiagnostics) { continue; } if (member.ContainsUnbalancedIfElseDirectives(member.Span)) { continue; } switch (member.Kind()) { case SyntaxKind.DelegateDeclaration: { var declaration = (DelegateDeclarationSyntax)member; if (SyntaxAccessibility <DelegateDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddDelegate(declaration.Identifier.ValueText, declaration); } break; } case SyntaxKind.EventDeclaration: { var declaration = (EventDeclarationSyntax)member; if (declaration.ExplicitInterfaceSpecifier == null && SyntaxAccessibility <EventDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddNode(declaration.Identifier.ValueText, declaration); } break; } case SyntaxKind.EventFieldDeclaration: { var declaration = (EventFieldDeclarationSyntax)member; if (SyntaxAccessibility <EventFieldDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddNodes(declaration.Declaration); } break; } case SyntaxKind.FieldDeclaration: { var declaration = (FieldDeclarationSyntax)member; SyntaxTokenList modifiers = declaration.Modifiers; if (SyntaxAccessibility <FieldDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddNodes(declaration.Declaration, isConst: modifiers.Contains(SyntaxKind.ConstKeyword)); } break; } case SyntaxKind.MethodDeclaration: { var declaration = (MethodDeclarationSyntax)member; SyntaxTokenList modifiers = declaration.Modifiers; if (declaration.ExplicitInterfaceSpecifier == null && !declaration.AttributeLists.Any() && SyntaxAccessibility <MethodDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { string methodName = declaration.Identifier.ValueText; if (!IsMainMethod(declaration, modifiers, methodName)) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddNode(methodName, declaration); } } break; } case SyntaxKind.PropertyDeclaration: { var declaration = (PropertyDeclarationSyntax)member; if (declaration.ExplicitInterfaceSpecifier == null && SyntaxAccessibility <PropertyDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private) { if (walker == null) { walker = UnusedMemberWalkerCache.GetInstance(); } walker.AddNode(declaration.Identifier.ValueText, declaration); } break; } } } if (walker == null) { return; } Collection <NodeSymbolInfo> nodes = walker.Nodes; if (ShouldAnalyzeDebuggerDisplayAttribute() && nodes.Any(f => f.CanBeInDebuggerDisplayAttribute)) { string value = semanticModel .GetDeclaredSymbol(typeDeclaration, cancellationToken) .GetAttribute(MetadataNames.System_Diagnostics_DebuggerDisplayAttribute)? .ConstructorArguments .SingleOrDefault(shouldThrow: false) .Value? .ToString(); if (value != null) { RemoveMethodsAndPropertiesThatAreInDebuggerDisplayAttributeValue(value, ref nodes); } if (nodes.Count == 0) { UnusedMemberWalkerCache.Free(walker); return; } } walker.SemanticModel = semanticModel; walker.CancellationToken = cancellationToken; walker.Visit(typeDeclaration); foreach (NodeSymbolInfo info in nodes) { SyntaxNode node = info.Node; if (node is VariableDeclaratorSyntax variableDeclarator) { var variableDeclaration = (VariableDeclarationSyntax)variableDeclarator.Parent; if (variableDeclaration.Variables.Count == 1) { ReportDiagnostic(context, variableDeclaration.Parent, CSharpFacts.GetTitle(variableDeclaration.Parent)); } else { ReportDiagnostic(context, variableDeclarator, CSharpFacts.GetTitle(variableDeclaration.Parent)); } } else { ReportDiagnostic(context, node, CSharpFacts.GetTitle(node)); } } UnusedMemberWalkerCache.Free(walker); bool ShouldAnalyzeDebuggerDisplayAttribute() { foreach (AttributeListSyntax attributeList in typeDeclaration.AttributeLists) { foreach (AttributeSyntax attribute in attributeList.Attributes) { if (attribute.ArgumentList?.Arguments.Count(f => f.NameEquals == null) == 1) { return(true); } } } return(false); } }