/// <inheritdoc /> public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze); context.RegisterCompilationStartAction(ctxt => { var mainThreadAssertingMethods = CommonInterest.ReadMethods(ctxt.Options, CommonInterest.FileNamePatternForMethodsThatAssertMainThread, ctxt.CancellationToken).ToImmutableArray(); ctxt.RegisterOperationAction(Utils.DebuggableWrapper(c => this.AnalyzeInvocation(c, mainThreadAssertingMethods)), OperationKind.Invocation); }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze); context.RegisterCompilationStartAction(compilationStartContext => { var legacyThreadSwitchingMembers = CommonInterest.ReadMethods(compilationStartContext.Options, CommonInterest.FileNamePatternForLegacyThreadSwitchingMembers, compilationStartContext.CancellationToken).ToImmutableArray(); var analyzer = new Analyzer(this.LanguageUtils, legacyThreadSwitchingMembers); compilationStartContext.RegisterOperationAction(Utils.DebuggableWrapper(analyzer.AnalyzeInvocation), OperationKind.Invocation); }); }
/// <inheritdoc /> public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze); context.RegisterCompilationStartAction(ctxt => { var mainThreadAssertingMethods = CommonInterest.ReadMethods(ctxt, CommonInterest.FileNamePatternForMethodsThatAssertMainThread).ToImmutableArray(); ctxt.RegisterCodeBlockStartAction <SyntaxKind>(ctxt2 => { ctxt2.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => this.AnalyzeInvocation(c, mainThreadAssertingMethods)), SyntaxKind.InvocationExpression); }); }); }
/// <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(); var 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); }); compilationStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => AddToCallerCalleeMap(c, callerToCalleeMap)), SyntaxKind.InvocationExpression); compilationStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => AddToCallerCalleeMap(c, callerToCalleeMap)), SyntaxKind.SimpleMemberAccessExpression); compilationStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => AddToCallerCalleeMap(c, callerToCalleeMap)), SyntaxKind.IdentifierName); compilationStartContext.RegisterCompilationEndAction(compilationEndContext => { var calleeToCallerMap = CreateCalleeToCallerMap(callerToCalleeMap); var transitiveClosureOfMainThreadRequiringMethods = GetTransitiveClosureOfMainThreadRequiringMethods(methodsAssertingUIThreadRequirement, calleeToCallerMap); foreach (var 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); var 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); } } }); }); }
/// <inheritdoc /> public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze); context.RegisterCompilationStartAction(compilationStartContext => { var mainThreadAssertingMethods = CommonInterest.ReadMethods(compilationStartContext, CommonInterest.FileNamePatternForMethodsThatAssertMainThread).ToImmutableArray(); var mainThreadSwitchingMethods = CommonInterest.ReadMethods(compilationStartContext, CommonInterest.FileNamePatternForMethodsThatSwitchToMainThread).ToImmutableArray(); var typesRequiringMainThread = CommonInterest.ReadTypes(compilationStartContext, CommonInterest.FileNamePatternForTypesRequiringMainThread).ToImmutableArray(); var methodsDeclaringUIThreadRequirement = new HashSet <IMethodSymbol>(); var callerToCalleeMap = new Dictionary <IMethodSymbol, HashSet <IMethodSymbol> >(); compilationStartContext.RegisterCodeBlockStartAction <SyntaxKind>(codeBlockStartContext => { var methodAnalyzer = new MethodAnalyzer { MainThreadAssertingMethods = mainThreadAssertingMethods, MainThreadSwitchingMethods = mainThreadSwitchingMethods, TypesRequiringMainThread = typesRequiringMainThread, MethodsDeclaringUIThreadRequirement = methodsDeclaringUIThreadRequirement, }; 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); }); compilationStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => AddToCallerCalleeMap(c, callerToCalleeMap)), SyntaxKind.InvocationExpression); compilationStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => AddToCallerCalleeMap(c, callerToCalleeMap)), SyntaxKind.SimpleMemberAccessExpression); compilationStartContext.RegisterSyntaxNodeAction(Utils.DebuggableWrapper(c => AddToCallerCalleeMap(c, callerToCalleeMap)), SyntaxKind.IdentifierName); compilationStartContext.RegisterCompilationEndAction(compilationEndContext => { var calleeToCallerMap = CreateCalleeToCallerMap(callerToCalleeMap); var transitiveClosureOfMainThreadRequiringMethods = GetTransitiveClosureOfMainThreadRequiringMethods(methodsDeclaringUIThreadRequirement, calleeToCallerMap); foreach (var implicitUserMethod in transitiveClosureOfMainThreadRequiringMethods.Except(methodsDeclaringUIThreadRequirement)) { var declarationSyntax = implicitUserMethod.DeclaringSyntaxReferences.FirstOrDefault()?.GetSyntax(compilationEndContext.CancellationToken); SyntaxToken memberNameSyntax = default(SyntaxToken); switch (declarationSyntax) { case MethodDeclarationSyntax methodDeclarationSyntax: memberNameSyntax = methodDeclarationSyntax.Identifier; break; case AccessorDeclarationSyntax accessorDeclarationSyntax: memberNameSyntax = accessorDeclarationSyntax.Keyword; break; } var location = memberNameSyntax.GetLocation(); if (location != null) { var exampleAssertingMethod = mainThreadAssertingMethods.FirstOrDefault(); compilationEndContext.ReportDiagnostic(Diagnostic.Create(DescriptorTransitiveMainThreadUser, location, exampleAssertingMethod)); } } }); }); }