예제 #1
0
        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));
            }
        }
예제 #2
0
        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));
            }
        }
예제 #6
0
        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));
            }
        }
예제 #7
0
        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));
            }
        }
예제 #10
0
        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;
            }
        }
예제 #11
0
        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));
                    }
                }
            }
        }