{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/6324","labels_url":"https://api.github.com/repos/dotnet/roslyn/issues/6324/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/6324/comments","events_url":"https://api.github.com/repos/dotnet/roslyn/issues/6324/events","html_url":"https://github.com/dotnet/roslyn/issues/6324","id":113415760,"number":6324,"title":"Add support for sharing per-compilation state across analyzer instances","user":{"login":"mavasani","id":10605811,"avatar_url":"https://avatars.githubusercontent.com/u/10605811?v=3","gravatar_id":"","url":"https://api.github.com/users/mavasani","html_url":"https://github.com/mavasani","followers_url":"https://api.github.com/users/mavasani/followers","following_url":"https://api.github.com/users/mavasani/following{/other_user}","gists_url":"https://api.github.com/users/mavasani/gists{/gist_id}","starred_url":"https://api.github.com/users/mavasani/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mavasani/subscriptions","organizations_url":"https://api.github.com/users/mavasani/orgs","repos_url":"https://api.github.com/users/mavasani/repos","events_url":"https://api.github.com/users/mavasani/events{/privacy}","received_events_url":"https://api.github.com/users/mavasani/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/dotnet/roslyn/labels/API","name":"API","color":"fc2929"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Area-Analyzers","name":"Area-Analyzers","color":"5319e7"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Feature%20Request","name":"Feature Request","color":"fc2929"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":18,"created_at":"2015-10-26T18:05:52Z","updated_at":"2015-10-26T19:07:49Z","closed_at":null,"body":"Currently, our diagnostic analyzer API provides no support for sharing any state between diagnostic analyzers. This causes extreme pain or performance issues for our customers when they have some expensive computation and/or large data to share across analyzer instances. For example:\r\n\r\n  1. Group of analyzers that need identical configuration settings from an additional file - they have identical computation logic and resulting data, and would get a real performance benefit if they can share this data across analyzer instances without doing any complicated lifetime management.\r\n\r\n  2. StyleCop analyzers want to walk through all trees in a compilation and identify generated files - they want to do it just once per compilation across all analyzer instances. In absence of any API support, they ended up creating a static conditional weak table keyed on compilation, which caused GC related perf problems when executing in the IDE. See https://github.com/DotNetAnalyzers/StyleCopAnalyzers/pull/1671 for the workaround they put to avoid CWT.\r\n\r\nAn ideal solution here is to provide an analyzer API to share per-compilation data across analyzer instances, so that analyzer authors don't have to explicitly deal with lifetime management for such state. I am going to propose an initial API for this feature, and we can iterate over the best design for it.\r\n\r\n**Principles:**\r\n1. API should guarantee easy state access/manipulation within all analyzer callbacks. However, analyzer author needs to handle concurrent access/update to shared state instance.\r\n2. [Implementation] No conditional weak tables for storing share state: CWT are evil in most instances, the shared state should be strongly referenced within CompilationWithAnalyzers/AnalyzerDriver instance.\r\n\r\n**Proposed API:**\r\nAdd the below APIs to each [DiagnosticAnalysisContext](http://source.roslyn.io/#Microsoft.CodeAnalysis/DiagnosticAnalyzer/DiagnosticAnalysisContext.cs) parameter type for analyzer callbacks:\r\n\r\n```C#\r\nTState GetOrCreateSharedState<TState>(object key, Func<object, TState> createSharedState) where TState: object\r\n\r\nbool TryGetSharedState<TState>(object key, out TState value) where TState: object\r\n```"},"comment":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/comments/151252442","html_url":"https://github.com/dotnet/roslyn/issues/6324#issuecomment-151252442","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/6324","id":151252442,"user":{"login":"heejaechang","id":1333179,"avatar_url":"https://avatars.githubusercontent.com/u/1333179?v=3","gravatar_id":"","url":"https://api.github.com/users/heejaechang","html_url":"https://github.com/heejaechang","followers_url":"https://api.github.com/users/heejaechang/followers","following_url":"https://api.github.com/users/heejaechang/following{/other_user}","gists_url":"https://api.github.com/users/heejaechang/gists{/gist_id}","starred_url":"https://api.github.com/users/heejaechang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/heejaechang/subscriptions","organizations_url":"https://api.github.com/users/heejaechang/orgs","repos_url":"https://api.github.com/users/heejaechang/repos","events_url":"https://api.github.com/users/heejaechang/events{/privacy}","received_events_url":"https://api.github.com/users/heejaechang/received_events","type":"User","site_admin":false},"created_at":"2015-10-26T19:07:49Z","updated_at":"2015-10-26T19:07:49Z","body":"@mavasani also, can we remove \"State\" from the API and rather put \"Cache\" in them. so that people doesn't use it as a state but use as a \"Cache\". implication is, \"state\" can break functionality but cache can't. this also remove assumption on dependency and also, we don't need to re-think our statefull and stateless analyzer story."}}