private bool AnalyzeMemberWithinContext(ITypeSymbol type, ISymbol?symbol, SyntaxNodeAnalysisContext context, Location?focusDiagnosticOn = null)
            {
                if (type is null)
                {
                    throw new ArgumentNullException(nameof(type));
                }

                bool requiresUIThread = (type.TypeKind == TypeKind.Interface || type.TypeKind == TypeKind.Class || type.TypeKind == TypeKind.Struct) &&
                                        this.MembersRequiringMainThread.Contains(type, symbol);

                if (requiresUIThread)
                {
                    ThreadingContext threadingContext  = ThreadingContext.Unknown;
                    SyntaxNode?      methodDeclaration = context.Node.FirstAncestorOrSelf <SyntaxNode>(n => CSharpCommonInterest.MethodSyntaxKinds.Contains(n.Kind()));
                    if (methodDeclaration is object)
                    {
                        threadingContext = this.methodDeclarationNodes.GetValueOrDefault(methodDeclaration);
                    }

                    if (threadingContext != ThreadingContext.MainThread)
                    {
                        CSharpUtils.ContainingFunctionData function = CSharpUtils.GetContainingFunction((CSharpSyntaxNode)context.Node);
                        Location             location   = focusDiagnosticOn ?? context.Node.GetLocation();
                        DiagnosticDescriptor?descriptor = function.IsAsync ? DescriptorAsync : DescriptorSync;
                        var formattingArgs = function.IsAsync ? new object[] { type.Name } : new object[] { type.Name, this.MainThreadAssertingMethods.FirstOrDefault() };
                        context.ReportDiagnostic(Diagnostic.Create(descriptor, location, this.DiagnosticProperties, formattingArgs));
                        return(true);
                    }
                }

                return(false);
            }
        private static void CheckArgument(
            ISymbol targetSymbol,
            IObjectCreationOperation creation,
            IParameterSymbol parameter,
            string stringArgument,
            OperationAnalysisContext context)
        {
            bool matchesParameter     = MatchesParameter(targetSymbol, creation, stringArgument);
            DiagnosticDescriptor?rule = null;

            if (IsMessage(parameter) && matchesParameter)
            {
                rule = RuleIncorrectMessage;
            }
            else if (IsParameterName(parameter) && !matchesParameter)
            {
                // Allow argument exceptions in accessors to use the associated property symbol name.
                if (MatchesAssociatedSymbol(targetSymbol, stringArgument))
                {
                    return;
                }

                rule = RuleIncorrectParameterName;
            }

            if (rule != null)
            {
                context.ReportDiagnostic(context.Operation.Syntax.CreateDiagnostic(rule, targetSymbol.Name, stringArgument, parameter.Name, creation.Type.Name));
            }
        }
예제 #3
0
        public bool Equals(DiagnosticDescriptor?x, DiagnosticDescriptor?y)
        {
            if (ReferenceEquals(x, y))
            {
                return(true);
            }

            if (x is null || y is null)
            {
                return(false);
            }

            // The properties are guaranteed to be non-null by DiagnosticDescriptor invariants.
            Debug.Assert(x.Description != null && x.Title != null && x.CustomTags != null);
            Debug.Assert(y.Description != null && y.Title != null && y.CustomTags != null);

            return(x.Category == y.Category &&
                   x.DefaultSeverity == y.DefaultSeverity &&
                   x.Description !.Equals(y.Description) &&
                   x.HelpLinkUri == y.HelpLinkUri &&
                   x.Id == y.Id &&
                   x.IsEnabledByDefault == y.IsEnabledByDefault &&
                   x.Title !.Equals(y.Title) &&
                   x.CustomTags.SequenceEqual(y.CustomTags));
        }
        /// <inheritdoc/>
        protected override bool ValidateTargetType(
            GeneratorExecutionContext context,
            AttributeData attributeData,
            ClassDeclarationSyntax classDeclaration,
            INamedTypeSymbol classDeclarationSymbol,
            [NotNullWhen(false)] out DiagnosticDescriptor?descriptor)
        {
            INamedTypeSymbol
                iNotifyPropertyChangedSymbol  = context.Compilation.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged") !,
                iNotifyPropertyChangingSymbol = context.Compilation.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanging") !;

            // Check if the type already implements INotifyPropertyChanged...
            if (classDeclarationSymbol.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, iNotifyPropertyChangedSymbol)))
            {
                descriptor = DuplicateINotifyPropertyChangedInterfaceForObservableObjectAttributeError;

                return(false);
            }

            // ...or INotifyPropertyChanging
            if (classDeclarationSymbol.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, iNotifyPropertyChangingSymbol)))
            {
                descriptor = DuplicateINotifyPropertyChangingInterfaceForObservableObjectAttributeError;

                return(false);
            }

            descriptor = null;

            return(true);
        }
예제 #5
0
        /// <summary>
        /// Processes the markup syntax for this <see cref="SolutionState"/> according to the current
        /// <see cref="MarkupHandling"/>, and returns a new <see cref="SolutionState"/> with the
        /// <see cref="ProjectState.Sources"/>, <see cref="ProjectState.GeneratedSources"/>,
        /// <see cref="ProjectState.AdditionalFiles"/>, <see cref="ProjectState.AnalyzerConfigFiles"/>, and
        /// <see cref="ExpectedDiagnostics"/> updated accordingly.
        /// </summary>
        /// <param name="markupOptions">Additional options to apply during markup processing.</param>
        /// <param name="defaultDiagnostic">The diagnostic descriptor to use for markup spans without an explicit name,
        /// or <see langword="null"/> if no such default exists.</param>
        /// <param name="supportedDiagnostics">The diagnostics supported by analyzers used by the test.</param>
        /// <param name="fixableDiagnostics">The set of diagnostic IDs to treat as fixable. This value is only used when
        /// <see cref="MarkupHandling"/> is <see cref="MarkupMode.IgnoreFixable"/>.</param>
        /// <param name="defaultPath">The default file path for diagnostics reported in source code.</param>
        /// <returns>A new <see cref="SolutionState"/> with all markup processing completed according to the current
        /// <see cref="MarkupHandling"/>. The <see cref="MarkupHandling"/> of the returned instance is
        /// <see cref="MarkupMode.None"/>.</returns>
        /// <exception cref="InvalidOperationException">If <see cref="InheritanceMode"/> is not
        /// <see cref="StateInheritanceMode.Explicit"/>.</exception>
        public SolutionState WithProcessedMarkup(MarkupOptions markupOptions, DiagnosticDescriptor?defaultDiagnostic, ImmutableArray <DiagnosticDescriptor> supportedDiagnostics, ImmutableArray <string> fixableDiagnostics, string defaultPath)
        {
            if (InheritanceMode != StateInheritanceMode.Explicit)
            {
                throw new InvalidOperationException("Inheritance processing must complete before markup processing.");
            }

            var markupLocations = ImmutableDictionary <string, FileLinePositionSpan> .Empty;

            (var expected, var testSources) = ProcessMarkupSources(Sources, ExpectedDiagnostics, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath);
            var(additionalExpected2, testGeneratedSources) = ProcessMarkupSources(GeneratedSources, expected, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath);
            var(additionalExpected1, additionalFiles)      = ProcessMarkupSources(AdditionalFiles.Concat(AdditionalFilesFactories.SelectMany(factory => factory())), additionalExpected2, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath);
            var(additionalExpected, analyzerConfigFiles)   = ProcessMarkupSources(AnalyzerConfigFiles, additionalExpected1, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath);

            var result = new SolutionState(Name, Language, DefaultPrefix, DefaultExtension);

            result.MarkupHandling      = MarkupMode.None;
            result.InheritanceMode     = StateInheritanceMode.Explicit;
            result.ReferenceAssemblies = ReferenceAssemblies;
            result.OutputKind          = OutputKind;
            result.DocumentationMode   = DocumentationMode;
            result.Sources.AddRange(testSources);
            result.GeneratedSources.AddRange(testGeneratedSources);
            result.AdditionalFiles.AddRange(additionalFiles);
            result.AnalyzerConfigFiles.AddRange(analyzerConfigFiles);

            foreach (var(projectName, projectState) in AdditionalProjects)
            {
                var(correctedIntermediateDiagnostics, additionalProjectSources) = ProcessMarkupSources(projectState.Sources, additionalExpected, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath);
                var(correctedDiagnostics2, additionalProjectGeneratedSources)   = ProcessMarkupSources(projectState.GeneratedSources, correctedIntermediateDiagnostics, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath);
                var(correctedDiagnostics1, additionalProjectAdditionalFiles)    = ProcessMarkupSources(projectState.AdditionalFiles.Concat(projectState.AdditionalFilesFactories.SelectMany(factory => factory())), correctedDiagnostics2, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath);
                var(correctedDiagnostics, additionalProjectAnalyzerConfigFiles) = ProcessMarkupSources(projectState.AnalyzerConfigFiles, correctedDiagnostics1, ref markupLocations, markupOptions, defaultDiagnostic, supportedDiagnostics, fixableDiagnostics, defaultPath);

                var processedProjectState = new ProjectState(projectState);
                processedProjectState.Sources.Clear();
                processedProjectState.Sources.AddRange(additionalProjectSources);
                processedProjectState.GeneratedSources.Clear();
                processedProjectState.GeneratedSources.AddRange(additionalProjectGeneratedSources);
                processedProjectState.AdditionalFiles.Clear();
                processedProjectState.AdditionalFilesFactories.Clear();
                processedProjectState.AdditionalFiles.AddRange(additionalProjectAdditionalFiles);
                processedProjectState.AnalyzerConfigFiles.Clear();
                processedProjectState.AnalyzerConfigFiles.AddRange(additionalProjectAnalyzerConfigFiles);

                result.AdditionalProjects.Add(projectName, processedProjectState);
                additionalExpected = correctedDiagnostics;
            }

            for (var i = 0; i < additionalExpected.Length; i++)
            {
                additionalExpected[i] = additionalExpected[i].WithAppliedMarkupLocations(markupLocations);
            }

            result.AdditionalProjectReferences.AddRange(AdditionalProjectReferences);
            result.AdditionalReferences.AddRange(AdditionalReferences);
            result.ExpectedDiagnostics.AddRange(additionalExpected);
            return(result);
        }
예제 #6
0
            public int Compare(DiagnosticDescriptor?x, DiagnosticDescriptor?y)
            {
                // Sort null as less than non-null.
                if (x is null)
                {
                    return(y is null ? 0 : -1);
                }
                if (y is null)
                {
                    return(1);
                }

                return(GetOrderIndexFromDescriptor(x) - GetOrderIndexFromDescriptor(y));
            }
        protected AbstractCodeStyleDiagnosticAnalyzer(
            string descriptorId, LocalizableString title,
            LocalizableString?messageFormat = null,
            bool configurable = true)
        {
            DescriptorId              = descriptorId;
            _localizableTitle         = title;
            _localizableMessageFormat = messageFormat ?? title;

            Descriptor = CreateDescriptorWithId(DescriptorId, _localizableTitle, _localizableMessageFormat, isConfigurable: configurable);
            UnnecessaryWithSuggestionDescriptor    = CreateUnnecessaryDescriptor(DescriptorId, configurable);
            UnnecessaryWithoutSuggestionDescriptor = CreateUnnecessaryDescriptor(descriptorId + "WithoutSuggestion", configurable);

            SupportedDiagnostics = ImmutableArray.Create(
                Descriptor, UnnecessaryWithoutSuggestionDescriptor, UnnecessaryWithSuggestionDescriptor);
        }
    /// <summary>
    ///     Helper method to format a Diagnostic into an easily readable string
    /// </summary>
    /// <param name="analyzer">The analyzer that this verifier tests</param>
    /// <param name="diagnostics">The Diagnostics to be formatted</param>
    /// <returns>The Diagnostics formatted as a string</returns>
    private static string FormatDiagnostics(DiagnosticAnalyzer analyzer, params Diagnostic[] diagnostics)
    {
        StringBuilder builder = new();

        foreach (Diagnostic diagnostic in diagnostics)
        {
            builder = builder.Append("// ")
                      .AppendLine(diagnostic.ToString());

            Type analyzerType = analyzer.GetType();
            ImmutableArray <DiagnosticDescriptor> rules = analyzer.SupportedDiagnostics;

            DiagnosticDescriptor?rule = rules.FirstOrDefault(rule => rule.Id == diagnostic.Id);

            if (rule == null)
            {
                continue;
            }

            Location location = diagnostic.Location;

            if (location == Location.None)
            {
                builder = builder.Append(provider: CultureInfo.InvariantCulture, $"GetGlobalResult({analyzerType.Name}.{rule.Id})");
            }
            else
            {
                Assert.True(condition: location.IsInSource, $"Test base does not currently handle diagnostics in metadata locations. Diagnostic in metadata: {diagnostic}\r\n");

                string       resultMethodName = GetResultMethodName(diagnostic);
                LinePosition linePosition     = diagnostic.Location.GetLineSpan()
                                                .StartLinePosition;

                builder = builder.Append(provider: CultureInfo.InvariantCulture,
                                         $"{resultMethodName}({linePosition.Line + 1}, {linePosition.Character + 1}, {analyzerType.Name}.{rule.Id})");
            }

            builder = builder.Append(value: ',')
                      .AppendLine();
        }

        return(builder.ToString()
               .TrimEnd()
               .TrimEnd(',') + Environment.NewLine);
    }
예제 #9
0
        /// <nodoc />
        protected DiagnosticAnalyzerBase(
            bool supportFading,
            params DiagnosticDescriptor[] diagnostics)
        {
            Contract.Requires(diagnostics.Length != 0);

            Descriptor   = diagnostics[0];
            DescriptorId = Descriptor.Id;
            var supportedDiagnostics = diagnostics.ToImmutableArray();

            if (supportFading)
            {
                UnnecessaryWithSuggestionDescriptor    = CreateUnnecessaryDescriptor();
                UnnecessaryWithoutSuggestionDescriptor = CreateUnnecessaryDescriptor(DescriptorId + "WithoutSuggestion");
                supportedDiagnostics = supportedDiagnostics.Add(UnnecessaryWithoutSuggestionDescriptor).Add(UnnecessaryWithSuggestionDescriptor);
            }

            SupportedDiagnostics = supportedDiagnostics;
        }
예제 #10
0
        public bool Equals(DiagnosticDescriptor?x, DiagnosticDescriptor?y)
        {
            if (ReferenceEquals(x, y))
            {
                return(true);
            }

            if (x is null || y is null)
            {
                return(false);
            }

            return(x.Category == y.Category &&
                   x.DefaultSeverity == y.DefaultSeverity &&
                   x.Description.Equals(y.Description) &&
                   x.HelpLinkUri == y.HelpLinkUri &&
                   x.Id == y.Id &&
                   x.IsEnabledByDefault == y.IsEnabledByDefault &&
                   x.Title.Equals(y.Title) &&
                   x.ImmutableCustomTags.SequenceEqual(y.ImmutableCustomTags));
        }
        /// <inheritdoc/>
        protected override bool ValidateTargetType(
            GeneratorExecutionContext context,
            AttributeData attributeData,
            ClassDeclarationSyntax classDeclaration,
            INamedTypeSymbol classDeclarationSymbol,
            [NotNullWhen(false)] out DiagnosticDescriptor?descriptor)
        {
            INamedTypeSymbol
                observableRecipientSymbol       = context.Compilation.GetTypeByMetadataName("Microsoft.Toolkit.Mvvm.ComponentModel.ObservableRecipient") !,
                observableObjectSymbol          = context.Compilation.GetTypeByMetadataName("Microsoft.Toolkit.Mvvm.ComponentModel.ObservableObject") !,
                observableObjectAttributeSymbol = context.Compilation.GetTypeByMetadataName("Microsoft.Toolkit.Mvvm.ComponentModel.ObservableObjectAttribute") !,
                iNotifyPropertyChangedSymbol    = context.Compilation.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged") !;

            // Check if the type already inherits from ObservableRecipient
            if (classDeclarationSymbol.InheritsFrom(observableRecipientSymbol))
            {
                descriptor = DuplicateObservableRecipientError;

                return(false);
            }

            // In order to use [ObservableRecipient], the target type needs to inherit from ObservableObject,
            // or be annotated with [ObservableObject] or [INotifyPropertyChanged] (with additional helpers).
            if (!classDeclarationSymbol.InheritsFrom(observableObjectSymbol) &&
                !classDeclarationSymbol.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, observableObjectAttributeSymbol)) &&
                !classDeclarationSymbol.GetAttributes().Any(a =>
                                                            SymbolEqualityComparer.Default.Equals(a.AttributeClass, iNotifyPropertyChangedSymbol) &&
                                                            !a.HasNamedArgument("IncludeAdditionalHelperMethods", false)))
            {
                descriptor = MissingBaseObservableObjectFunctionalityError;

                return(false);
            }

            descriptor = null;

            return(true);
        }
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterCompilationStartAction(compilationContext =>
            {
                INamedTypeSymbol?expectedExceptionType = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftVisualStudioTestToolsUnitTestingExpectedExceptionAttribute);
                INamedTypeSymbol?nunitAssertType       = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.NUnitFrameworkAssert);
                INamedTypeSymbol?xunitAssertType       = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.XunitAssert);
                INamedTypeSymbol?linqEnumerableType    = compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemLinqEnumerable);

                compilationContext.RegisterOperationBlockStartAction(osContext =>
                {
                    if (osContext.OwningSymbol is not IMethodSymbol method)
                    {
                        return;
                    }

                    osContext.RegisterOperationAction(opContext =>
                    {
                        IOperation expression = ((IExpressionStatementOperation)opContext.Operation).Operation;

                        var userDefinedMethods = compilationContext.Options.GetAdditionalUseResultsMethodsOption(UserDefinedMethodRule, expression.Syntax.SyntaxTree, compilationContext.Compilation, compilationContext.CancellationToken);

                        DiagnosticDescriptor?rule = null;
                        string targetMethodName   = "";
                        switch (expression.Kind)
                        {
                        case OperationKind.ObjectCreation:
                            IMethodSymbol ctor = ((IObjectCreationOperation)expression).Constructor;
                            if (ctor != null)
                            {
                                rule             = ObjectCreationRule;
                                targetMethodName = ctor.ContainingType.Name;
                            }
                            break;

                        case OperationKind.Invocation:
                            IInvocationOperation invocationExpression = (IInvocationOperation)expression;
                            IMethodSymbol targetMethod = invocationExpression.TargetMethod;
                            if (targetMethod.ReturnsVoid)
                            {
                                break;
                            }

                            if (IsStringCreatingMethod(targetMethod))
                            {
                                rule = StringCreationRule;
                            }
                            else if (IsTryParseMethod(targetMethod))
                            {
                                rule = TryParseRule;
                            }
                            else if (IsHResultOrErrorCodeReturningMethod(targetMethod))
                            {
                                rule = HResultOrErrorCodeRule;
                            }
                            else if (IsPureMethod(targetMethod, opContext.Compilation))
                            {
                                rule = PureMethodRule;
                            }
                            else if (targetMethod.ContainingType.Equals(linqEnumerableType))
                            {
                                rule = LinqMethodRule;
                            }
                            else if (userDefinedMethods.Contains(targetMethod.OriginalDefinition))
                            {
                                rule = UserDefinedMethodRule;
                            }

                            targetMethodName = targetMethod.Name;
                            break;
                        }

                        if (rule != null)
                        {
                            if (ShouldSkipAnalyzing(opContext, expectedExceptionType, xunitAssertType, nunitAssertType))
                            {
                                return;
                            }

                            Diagnostic diagnostic = expression.CreateDiagnostic(rule, method.Name, targetMethodName);
                            opContext.ReportDiagnostic(diagnostic);
                        }
                    }, OperationKind.ExpressionStatement);
                });
            });
        }
        /// <inheritdoc />
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze);

            context.RegisterCompilationStartAction(compilationStartContext =>
            {
                var mainThreadAssertingMethods = CommonInterest.ReadMethods(compilationStartContext.Options, CommonInterest.FileNamePatternForMethodsThatAssertMainThread, compilationStartContext.CancellationToken).ToImmutableArray();
                var mainThreadSwitchingMethods = CommonInterest.ReadMethods(compilationStartContext.Options, CommonInterest.FileNamePatternForMethodsThatSwitchToMainThread, compilationStartContext.CancellationToken).ToImmutableArray();
                var membersRequiringMainThread = CommonInterest.ReadTypesAndMembers(compilationStartContext.Options, CommonInterest.FileNamePatternForMembersRequiringMainThread, compilationStartContext.CancellationToken).ToImmutableArray();
                ImmutableDictionary <string, string>?diagnosticProperties = ImmutableDictionary <string, string> .Empty
                                                                            .Add(CommonInterest.FileNamePatternForMethodsThatAssertMainThread.ToString(), string.Join("\n", mainThreadAssertingMethods))
                                                                            .Add(CommonInterest.FileNamePatternForMethodsThatSwitchToMainThread.ToString(), string.Join("\n", mainThreadSwitchingMethods));

                var methodsDeclaringUIThreadRequirement = new HashSet <IMethodSymbol>();
                var methodsAssertingUIThreadRequirement = new HashSet <IMethodSymbol>();
                var callerToCalleeMap = new Dictionary <IMethodSymbol, List <CallInfo> >();

                compilationStartContext.RegisterCodeBlockStartAction <SyntaxKind>(codeBlockStartContext =>
                {
                    var methodAnalyzer = new MethodAnalyzer(
                        mainThreadAssertingMethods: mainThreadAssertingMethods,
                        mainThreadSwitchingMethods: mainThreadSwitchingMethods,
                        membersRequiringMainThread: membersRequiringMainThread,
                        methodsDeclaringUIThreadRequirement: methodsDeclaringUIThreadRequirement,
                        methodsAssertingUIThreadRequirement: methodsAssertingUIThreadRequirement,
                        diagnosticProperties: diagnosticProperties);
                    codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeInvocation), SyntaxKind.InvocationExpression);
                    codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeMemberAccess), SyntaxKind.SimpleMemberAccessExpression);
                    codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeCast), SyntaxKind.CastExpression);
                    codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeAs), SyntaxKind.AsExpression);
                    codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeAs), SyntaxKind.IsExpression);
                    codeBlockStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(methodAnalyzer.AnalyzeIsPattern), SyntaxKind.IsPatternExpression);
                });

                compilationStartContext.RegisterOperationAction(Utils.DebuggableWrapper(c => this.AddToCallerCalleeMap(c, callerToCalleeMap)), OperationKind.Invocation);
                compilationStartContext.RegisterOperationAction(Utils.DebuggableWrapper(c => this.AddToCallerCalleeMap(c, callerToCalleeMap)), OperationKind.PropertyReference);

                compilationStartContext.RegisterCompilationEndAction(compilationEndContext =>
                {
                    Dictionary <IMethodSymbol, List <CallInfo> >?calleeToCallerMap        = CreateCalleeToCallerMap(callerToCalleeMap);
                    HashSet <IMethodSymbol>?transitiveClosureOfMainThreadRequiringMethods = GetTransitiveClosureOfMainThreadRequiringMethods(methodsAssertingUIThreadRequirement, calleeToCallerMap);
                    foreach (IMethodSymbol?implicitUserMethod in transitiveClosureOfMainThreadRequiringMethods.Except(methodsDeclaringUIThreadRequirement))
                    {
                        var reportSites = from info in callerToCalleeMap[implicitUserMethod]
                                          where transitiveClosureOfMainThreadRequiringMethods.Contains(info.MethodSymbol)
                                          group info by info.MethodSymbol into bySymbol
                                          select new { Location = bySymbol.First().InvocationSyntax.GetLocation(), CalleeMethod = bySymbol.Key };
                        foreach (var site in reportSites)
                        {
                            bool isAsync = Utils.IsAsyncReady(implicitUserMethod);
                            DiagnosticDescriptor?descriptor = isAsync ? DescriptorAsync : DescriptorSync;
                            string calleeName     = Utils.GetFullName(site.CalleeMethod);
                            var formattingArgs    = isAsync ? new object[] { calleeName } : new object[] { calleeName, mainThreadAssertingMethods.FirstOrDefault() };
                            Diagnostic diagnostic = Diagnostic.Create(
                                descriptor,
                                site.Location,
                                diagnosticProperties,
                                formattingArgs);
                            compilationEndContext.ReportDiagnostic(diagnostic);
                        }
                    }
                });
            });
        }
        public sealed override void Initialize(AnalysisContext context)
        {
            ImmutableHashSet <string> cachedDeserializationMethodNames = this.DeserializationMethodNames;

            Debug.Assert(!cachedDeserializationMethodNames.IsEmpty);

            context.EnableConcurrentExecution();

            // Security analyzer - analyze and report diagnostics on generated code.
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartAnalysisContext) =>
            {
                WellKnownTypeProvider wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(
                    compilationStartAnalysisContext.Compilation);
                INamedTypeSymbol?deserializerTypeSymbol =
                    wellKnownTypeProvider.GetOrCreateTypeByMetadataName(this.DeserializerTypeMetadataName);
                if (deserializerTypeSymbol == null)
                {
                    return;
                }

                compilationStartAnalysisContext.RegisterOperationAction(
                    (OperationAnalysisContext operationAnalysisContext) =>
                {
                    IInvocationOperation invocationOperation =
                        (IInvocationOperation)operationAnalysisContext.Operation;
                    if (invocationOperation.Instance?.Type?.DerivesFrom(deserializerTypeSymbol) == true &&
                        cachedDeserializationMethodNames.Contains(invocationOperation.TargetMethod.MetadataName))
                    {
                        DiagnosticDescriptor?chosenDiagnostic =
                            this.ChooseDiagnosticDescriptor(operationAnalysisContext, wellKnownTypeProvider);
                        if (chosenDiagnostic != null)
                        {
                            operationAnalysisContext.ReportDiagnostic(
                                invocationOperation.CreateDiagnostic(
                                    chosenDiagnostic,
                                    invocationOperation.TargetMethod.ToDisplayString(
                                        SymbolDisplayFormat.MinimallyQualifiedFormat)));
                        }
                    }
                },
                    OperationKind.Invocation);

                compilationStartAnalysisContext.RegisterOperationAction(
                    (OperationAnalysisContext operationAnalysisContext) =>
                {
                    IMethodReferenceOperation methodReferenceOperation =
                        (IMethodReferenceOperation)operationAnalysisContext.Operation;
                    if (methodReferenceOperation.Instance?.Type?.DerivesFrom(deserializerTypeSymbol) == true &&
                        cachedDeserializationMethodNames.Contains(methodReferenceOperation.Method.MetadataName))
                    {
                        DiagnosticDescriptor?chosenDiagnostic =
                            this.ChooseDiagnosticDescriptor(operationAnalysisContext, wellKnownTypeProvider);
                        if (chosenDiagnostic != null)
                        {
                            operationAnalysisContext.ReportDiagnostic(
                                methodReferenceOperation.CreateDiagnostic(
                                    chosenDiagnostic,
                                    methodReferenceOperation.Method.ToDisplayString(
                                        SymbolDisplayFormat.MinimallyQualifiedFormat)));
                        }
                    }
                },
                    OperationKind.MethodReference);
            });
        }
        private static void AnalyzeMethodSignature(AutoLayoutTypeCache autoLayoutCache, Action <Diagnostic> reportDiagnostic, IMethodSymbol method, ImmutableArray <Location> locationsOverride = default, DiagnosticDescriptor?descriptorOverride = null)
        {
            AnalyzeSignatureType(locationsOverride.IsDefaultOrEmpty ? method.Locations : locationsOverride, method.ReturnType);
            foreach (var param in method.Parameters)
            {
                var paramLocation = locationsOverride.IsDefaultOrEmpty ? param.Locations : locationsOverride;
                if (param.RefKind != RefKind.None)
                {
                    reportDiagnostic(paramLocation.CreateDiagnostic(descriptorOverride ?? FeatureUnsupportedWhenRuntimeMarshallingDisabledByRefParameters));
                }
                AnalyzeSignatureType(paramLocation, param.Type);
            }

            void AnalyzeSignatureType(ImmutableArray <Location> locations, ITypeSymbol type)
            {
                if (type.SpecialType == SpecialType.System_Void)
                {
                    return;
                }

                if (type.Language == LanguageNames.CSharp)
                {
                    if (!type.IsUnmanagedType)
                    {
                        reportDiagnostic(locations.CreateDiagnostic(descriptorOverride ?? FeatureUnsupportedWhenRuntimeMarshallingDisabledManagedParameterOrReturnTypes));
                    }
                }
                // For non-C# languages, we'll do a quick check to catch simple cases
                // since IsUnmanagedType only works in languages that support unmanaged types
                // and non-C# languages that might not support is (such as VB) aren't a big focus of the attribute
                // this analyzer validates.
                else if (type.IsReferenceType || type.GetMembers().Any(m => m is IFieldSymbol {
                    IsStatic: false, Type.IsReferenceType: true
                }))
                {
                    reportDiagnostic(locations.CreateDiagnostic(descriptorOverride ?? FeatureUnsupportedWhenRuntimeMarshallingDisabledManagedParameterOrReturnTypes));
                }

                if (type.IsValueType && autoLayoutCache.TypeIsAutoLayoutOrContainsAutoLayout(type))
                {
                    reportDiagnostic(locations.CreateDiagnostic(descriptorOverride ?? FeatureUnsupportedWhenRuntimeMarshallingDisabledAutoLayoutTypes));
                }
            }