private static void AnalyzeDiagnostic(Diagnostic diagnostic, SuppressionAnalysisContext context) { var sourceTree = diagnostic.Location.SourceTree; var root = sourceTree.GetRoot(context.CancellationToken); var node = root.FindNode(diagnostic.Location.SourceSpan); if (!(node is MethodDeclarationSyntax method)) { return; } var model = context.GetSemanticModel(diagnostic.Location.SourceTree); if (!(model.GetDeclaredSymbol(method) is IMethodSymbol methodSymbol)) { return; } var typeSymbol = methodSymbol.ContainingType; if (!typeSymbol.Extends(typeof(UnityEngine.MonoBehaviour))) { return; } while (typeSymbol.ContainingType != null && typeSymbol.ContainingType.Extends(typeof(UnityEngine.MonoBehaviour))) { typeSymbol = typeSymbol.ContainingType; } var references = new List <InvocationExpressionSyntax>(); foreach (var typeNode in typeSymbol.Locations.Select(location => root.FindNode(location.SourceSpan))) { references.AddRange(typeNode.DescendantNodes() .OfType <InvocationExpressionSyntax>() .Where(e => MethodInvocationAnalyzer.InvocationMatches(e, out string argument) && argument == methodSymbol.Name)); } if (references.Any()) { context.ReportSuppression(Suppression.Create(Rule, diagnostic)); } }
public override void ReportSuppressions(SuppressionAnalysisContext context) { foreach (var diagnostic in context.ReportedDiagnostics) { var root = diagnostic.Location.SourceTree.GetRoot(); var location = root?.FindNode(diagnostic.Location.SourceSpan); var classDeclaration = location?.FirstAncestorOrSelf <ClassDeclarationSyntax>(); if (classDeclaration is null) { continue; } var model = context.GetSemanticModel(diagnostic.Location.SourceTree); var symbol = model?.GetDeclaredSymbol(classDeclaration); if (symbol is null) { continue; } var scriptInfo = new ScriptInfo(symbol); if (!scriptInfo.HasMessages) { continue; } var propertyDeclaration = location.FirstAncestorOrSelf <PropertyDeclarationSyntax>(); //handle properties before fields to minimize double checking of potential backing fields if (!(propertyDeclaration is null)) { AnalyzeProperties(propertyDeclaration, diagnostic, context, root); continue; } if (location is VariableDeclaratorSyntax fieldDeclaration) { AnalyzeFields(fieldDeclaration, diagnostic, context, root); } //TODO handle nullable warnings for constructors => diagnostic location is now on constructor //TODO handle other Unity objects that cannot be initialized => e.g. Unity's new Input system } }
private static void SuppressMarkMethodsAsStaticDiagnosticIfNeeded(SuppressionAnalysisContext context, Diagnostic diagnostic) { SemanticModel model = context.GetSemanticModel(diagnostic.Location.SourceTree); ISymbol diagnosedSymbol = model.GetDeclaredSymbol(diagnostic.Location.SourceTree.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan), context.CancellationToken); if (diagnosedSymbol.Kind != SymbolKind.Method) { return; } if (FindContainingEntryPointTypeAndManagedType(diagnosedSymbol.ContainingType) is (INamedTypeSymbol entryPointMarshallerType, INamedTypeSymbol managedType)) { bool isLinearCollectionMarshaller = ManualTypeMarshallingHelper.IsLinearCollectionEntryPoint(entryPointMarshallerType); (MarshallerShape _, StatefulMarshallerShapeHelper.MarshallerMethods methods) = StatefulMarshallerShapeHelper.GetShapeForType(diagnosedSymbol.ContainingType, managedType, isLinearCollectionMarshaller, context.Compilation); if (methods.IsShapeMethod((IMethodSymbol)diagnosedSymbol)) { // If we are a method of the shape on the stateful marshaller shape, then we need to be our current shape. // So, suppress the diagnostic to make this method static, as that would break the shape. context.ReportSuppression(Suppression.Create(MarkMethodsAsStaticSuppression, diagnostic)); } } }
private void AnalyzeDiagnostic(Diagnostic diagnostic, SuppressionAnalysisContext context) { var node = context.GetSuppressibleNode <SyntaxNode>(diagnostic, n => n is ParameterSyntax || n is MethodDeclarationSyntax); if (node is ParameterSyntax) { node = node .Ancestors() .OfType <MethodDeclarationSyntax>() .FirstOrDefault(); } if (node == null) { return; } var model = context.GetSemanticModel(diagnostic.Location.SourceTree); if (!(model.GetDeclaredSymbol(node) is IMethodSymbol methodSymbol)) { return; } var scriptInfo = new ScriptInfo(methodSymbol.ContainingType); if (!scriptInfo.IsMessage(methodSymbol)) { return; } foreach (var suppression in SupportedSuppressions) { if (suppression.SuppressedDiagnosticId == diagnostic.Id) { context.ReportSuppression(Suppression.Create(suppression, diagnostic)); } } }
private static void AnalyzeDiagnostic(Diagnostic diagnostic, SuppressionAnalysisContext context) { var sourceTree = diagnostic.Location.SourceTree; var root = sourceTree.GetRoot(context.CancellationToken); var node = root.FindNode(diagnostic.Location.SourceSpan); if (!(node is MethodDeclarationSyntax method)) { return; } var model = context.GetSemanticModel(diagnostic.Location.SourceTree); if (!(model.GetDeclaredSymbol(method) is IMethodSymbol methodSymbol)) { return; } if (IsSuppressable(methodSymbol)) { context.ReportSuppression(Suppression.Create(Rule, diagnostic)); } }
private static void AnalyzeDiagnostic(Diagnostic diagnostic, SuppressionAnalysisContext context) { var sourceTree = diagnostic.Location.SourceTree; var root = sourceTree.GetRoot(context.CancellationToken); var node = root.FindNode(diagnostic.Location.SourceSpan); if (!(node is MethodDeclarationSyntax method)) { return; } var model = context.GetSemanticModel(diagnostic.Location.SourceTree); if (!(model.GetDeclaredSymbol(method) is IMethodSymbol methodSymbol)) { return; } var typeSymbol = methodSymbol.ContainingType; if (!typeSymbol.Extends(typeof(UnityEngine.MonoBehaviour))) { return; } var references = root .DescendantNodes() .OfType <InvocationExpressionSyntax>() .Where(e => IsMatchingArgument(e, methodSymbol.Name)) .Where(e => IsMatchingIdentifier(e.Expression)); if (references.Any()) { context.ReportSuppression(Suppression.Create(Rule, diagnostic)); } }
public override void ReportSuppressions(SuppressionAnalysisContext context) { foreach (var diagnostic in context.ReportedDiagnostics) { var root = diagnostic.Location.SourceTree.GetRoot(context.CancellationToken); if (root.FindNode(diagnostic.Location.SourceSpan) is { } node&& node.TryFirstAncestorOrSelf(out IdentifierNameSyntax? identifierName) && context.GetSemanticModel(identifierName.SyntaxTree) is { } semanticModel) { if (semanticModel.TryGetSymbol(identifierName, context.CancellationToken, out var symbol) && FieldOrProperty.TryCreate(symbol, out var fieldOrProperty) && fieldOrProperty.Type == KnownSymbols.DependencyPropertyKey) { context.ReportSuppression(Suppression.Create(Descriptor, diagnostic)); } if (identifierName.Parent is MethodDeclarationSyntax method && ClrMethod.IsAttachedSet(method, semanticModel, context.CancellationToken, out _, out _)) { context.ReportSuppression(Suppression.Create(Descriptor, diagnostic)); } } } }
private static ITypeSymbol GetSymbol(CodeAnalysis.SyntaxTree tree, TypeSyntax type, SuppressionAnalysisContext context) { var model = context.GetSemanticModel(tree); return((ITypeSymbol)model.GetSymbolInfo(type).Symbol); }
private static void AnalyzeDiagnostic(Diagnostic diagnostic, SuppressionAnalysisContext context) { var node = diagnostic.Location.SourceTree.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan); if (node == null) { return; } if (!node.IsKind(SyntaxKind.ConditionalExpression)) { return; } var cond = (ConditionalExpressionSyntax)node; switch (cond.Condition.Kind()) { case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: break; default: return; } var binary = (BinaryExpressionSyntax)cond.Condition; if (!binary.Right.IsKind(SyntaxKind.NullLiteralExpression)) { return; } var model = context.GetSemanticModel(node.SyntaxTree); if (model == null) { return; } var type = model.GetTypeInfo(binary.Left); if (type.Type == null) { return; } if (!type.Type.Extends(typeof(UnityEngine.Object))) { return; } if (diagnostic.Id == NullCoalescingRule.SuppressedDiagnosticId) { context.ReportSuppression(Suppression.Create(NullCoalescingRule, diagnostic)); } else if (diagnostic.Id == NullPropagationRule.SuppressedDiagnosticId) { context.ReportSuppression(Suppression.Create(NullPropagationRule, diagnostic)); } }
public override void ReportSuppressions(SuppressionAnalysisContext context) { try { // Get expose attribute instance and check Catel.Fody assembly var exposeAttributeType = context.Compilation.GetTypeByMetadataName("Catel.Fody.ExposeAttribute"); if (exposeAttributeType is null) { return; } var supresssionDescriptor = SupportedSuppressions.FirstOrDefault(); foreach (var diagnostic in context.ReportedDiagnostics) { if (context.CancellationToken.IsCancellationRequested) { return; } var diagnosticSourceSyntaxTree = diagnostic.Location.SourceTree; if (diagnosticSourceSyntaxTree is null || !diagnostic.Location.IsInSource) { continue; } var rootSyntax = diagnosticSourceSyntaxTree.GetRoot(context.CancellationToken); var targetSyntax = rootSyntax.FindNode(diagnostic.Location.SourceSpan, false, true); // Look is class weaved by Fody var containerClassSyntax = targetSyntax.FirstAncestor <ClassDeclarationSyntax>(); if (containerClassSyntax is null) { continue; } if (context.CancellationToken.IsCancellationRequested) { return; } var rootSemantic = context.GetSemanticModel(diagnosticSourceSyntaxTree); var containerClassSymbol = (rootSemantic.GetDeclaredSymbol(containerClassSyntax, context.CancellationToken) as ITypeSymbol); if (containerClassSymbol is null) { // Wrong class declaration continue; } if (context.CancellationToken.IsCancellationRequested) { return; } if (!containerClassSymbol.InheritsFrom(CatelBaseClassLookupName)) { continue; } var targetSymbol = rootSemantic.GetDeclaredSymbol(targetSyntax, context.CancellationToken); if (context.CancellationToken.IsCancellationRequested) { return; } var accessModifierNode = targetSyntax.ChildTokens().FirstOrDefault(x => x.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PrivateKeyword)); // Check agains "None" kine empty token if (!accessModifierNode.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PrivateKeyword)) { // Skip non-private continue; } if (!(targetSymbol is IMethodSymbol method) || !method.Name.StartsWith("On") || !method.Name.EndsWith("Changed")) { continue; } var propertyName = method.Name.ReplaceFirst("On", string.Empty).ReplaceLast("Changed", string.Empty); // Search for property // Step 1: Search by property name through class properties // Step 2: Try to check Expose attributes: // - arguments passed to ctor // - named arguments // This call is more expensive than queries on syntax tree if (containerClassSymbol.TryFindProperty(propertyName, out var weavedPropertySymbol)) { context.ReportSuppression(Suppression.Create(supresssionDescriptor, diagnostic)); return; } var exposedMarkedDeclarations = from descendantNode in containerClassSyntax.DescendantNodes(x => x is ClassDeclarationSyntax || x is PropertyDeclarationSyntax || x is AttributeListSyntax) where descendantNode is AttributeSyntax && string.Equals(descendantNode.GetIdentifier(), CatelFodyAttributeLookupName) select descendantNode.FirstAncestor <PropertyDeclarationSyntax>(); if (IsAnyExposedPropertyDeclarationMatch(exposedMarkedDeclarations, exposeAttributeType, propertyName, rootSemantic, context.CancellationToken)) { context.ReportSuppression(Suppression.Create(supresssionDescriptor, diagnostic)); } } } catch (Exception ex) { throw ex; } }
public override void ReportSuppressions(SuppressionAnalysisContext context) { foreach (var diagnostic in context.ReportedDiagnostics) { var methodSourceTree = diagnostic.Location.SourceTree; if (methodSourceTree == null) { continue; } var methodNode = methodSourceTree.GetRoot(context.CancellationToken).FindNode(diagnostic.Location.SourceSpan); if (methodNode == null || !(methodNode is MethodDeclarationSyntax methodDec)) { continue; } // Ensure the method has no parameters if (methodDec.ParameterList.Parameters.Count != 0) { continue; } // Determine if the method matches On_PropertyName_Changed pattern var matches = OnChangedPattern.Matches(methodDec.Identifier.Text); if (matches.Count == 0 || matches.Count > 1) { continue; } var expectedPropertyName = matches[0].Groups[1].Value; var classNode = methodDec.Parent; if (classNode == null) { continue; } var classModel = context.GetSemanticModel(classNode.SyntaxTree); var classDeclaredSymbol = classModel.GetDeclaredSymbol(classNode, context.CancellationToken); if (!(classDeclaredSymbol is INamedTypeSymbol classDeclaringSymbol)) { continue; } var isINotifyPropertyChanged = IsDerivedFromInterface(classDeclaringSymbol, "INotifyPropertyChanged"); // Check if parent class has AddINotifyPropertyChangedInterfaceAttribute bool hasAddINotifyPropertyChangedInterface = classDeclaringSymbol.GetAttributes() .Any(a => a.AttributeClass.Name.Equals("AddINotifyPropertyChangedInterfaceAttribute", StringComparison.InvariantCulture)); if (!hasAddINotifyPropertyChangedInterface && !isINotifyPropertyChanged) { continue; } var relatedPropertyFound = false; // Iterate through all locations (possible partial classes) foreach (var loc in classDeclaringSymbol.Locations) { var locSourceTree = loc.SourceTree; if (locSourceTree == null) { continue; } var locnode = locSourceTree.GetRoot(context.CancellationToken).FindNode(loc.SourceSpan); SyntaxList <MemberDeclarationSyntax> members; if (locnode is ClassDeclarationSyntax declaringClass) { members = declaringClass.Members; } else if (locnode is StructDeclarationSyntax declaringStruct) { members = declaringStruct.Members; } else { continue; } // Iterate through member of (partial) class foreach (var member in members) { // Bail out if not a property if (!(member is PropertyDeclarationSyntax property)) { continue; } // Check to see if property name is what's between On and Changed if (property.Identifier.Text.Equals(expectedPropertyName, StringComparison.InvariantCulture)) { relatedPropertyFound = true; } } if (relatedPropertyFound) { context.ReportSuppression(Suppression.Create(SupportedSuppressions[0], diagnostic)); } } } }