Skip to content

Conversation

@heejaechang
Copy link
Contributor

@heejaechang heejaechang commented Feb 6, 2018

Customer scenario

Users that use F# or Typescript should see errors that are considered cheaper to calculate much faster than before.

Bugs this fixes

#20390 (for F#)

Workarounds, if any

each have put their own workaround for it which they want to remove.

Risk

I don't see any risk

Performance impact

time to run all analyzers are same. just order of they run can be changed. but for users, since they will see the first error faster than before if there is one, perception-wise, it could feel faster.

Is this a regression from a previous update?

No

Root cause analysis

Roslyn analyzer engine doesn't allow diagnostic author to specific order of analyzers since it is open platform (third party analyzers). otherwise, there can be an abuser that think theirs are most important and put theirs at the head. so we don't give this control to author. for built in analyzers, we do have control over the order. for example, we run compiler analyzers first so not a problem.

Issue occurred once partner team start to adapt Roslyn for diagnostics (typescript, F#). they want to control order of their builtin analyzers (like running their compiler analyzers run first), but to us, they are still not first party, so they don't have such control. this expose a way for them to control their analyzers order. but for now, this is specific to vsix installed analyzers and only for partner team (Document/ProjectDiagnosticAnalyzers). we still don't give it to pure third party.

How was the bug found?

Dogfooding

this is to let partner team such as typescript and F# to be able to order their analyzers
@heejaechang heejaechang requested a review from a team as a code owner February 6, 2018 19:32
@heejaechang
Copy link
Contributor Author

@dsyme @amcasey can you take a look? I added a way to priority DocumentAnalyzers so that you guys can run compiler analyzers first and make slow analyzers last.

@heejaechang
Copy link
Contributor Author

@jinujoseph @Pilchie approval for 15.7?

@heejaechang
Copy link
Contributor Author

tagging @minestarks as well.

@sharwell sharwell self-requested a review February 6, 2018 20:14
/// Priority is ascending order and this only works on HostDiagnosticAnalyzer meaning Vsix installed analyzers in VS.
/// This is to support partner teams (such as typescript and F#) who want to order their analyzer's execution order.
/// </summary>
public virtual int Priority { get; } = DefaultPriority;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 The second backing field here isn't needed. You can use => instead of { get; } =.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@heejaechang
Copy link
Contributor Author

ping? can I get a code review?

return Math.Max(0, analyzer.Priority);
default:
// regular analyzer get next priority
return -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ This means all user analyzers will have priority over all DocumentDiagnosticAnalyzer and ProjectDiagnosticAnalyzer instances. Is this the intent?

Copy link
Contributor Author

@heejaechang heejaechang Feb 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document/ProjectDiagnosticAnalyzer will come after all other kinds of analyzers. Document/ProjectDiagnosticAnalyzer is special kind of analyzers that want to use Workspace not compilation for diagnostics. I dont see any issue it being last. and no third party can use it.

return Owner.GetOnAnalyzerException(projectId, DiagnosticLogAggregator);
}

internal IEnumerable<DiagnosticAnalyzer> GetAnalyzersTestOnly(Project project)
Copy link
Contributor

@sharwell sharwell Feb 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 It would be good to create an enforced [TestOnly] attribute. Outside the scope of this pull request, but something to think about if this is a common pattern.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. we could create enforcer once we have call graph I believe with attribute.

_compilerAnalyzer = analyzerManager.GetCompilerDiagnosticAnalyzer(language);
_map = analyzerMap;

var compilerAnalyzer = analyzerManager.GetCompilerDiagnosticAnalyzer(language);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't like that we are tracking four different things now for analyzer prioritization.

  • The compiler analyzers
  • Implementations of DocumentDiagnosticAnalyzer
  • Implementations of ProjectDiagnosticAnalyzer
  • Everything else

Each of these four uses a different prioritization mechanism, and none of them leverage the functionality which users come to expect with MEF/VS (OrderAttribute / ExtensionOrderAttribute).

❓ What are our alternatives to unify and simplify this behavior?

Copy link
Contributor Author

@heejaechang heejaechang Feb 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DiagnosticAnalyzer doesn't use MEF. and I dont like OrderAttribute which require one to explicitly specify what comes before and after. that is just overkill for what is asked and get pretty complex fast. we used them and probably still use in some cases such as command handler, but we just hated them I believe. since whenever new one is added, one had to change multiple ones to adjust order. it is only suitable for ones that order must be declared quite clearly. this is not the case.

...

we have 4 different groups of analyzers (C#/VB compiler analyzer which is special, regular diagnostic analyzer, Document/ProjectDiagnosticAnalyzer, analyzer that implements IBuiltInAnalyzer). Engine treats them differently. reason is simple. since we want to allow special ability third party analyzer (regular diagnostic analyzer) can't use.

sure, we can have an issue tracking whether we should expose this special ability to third party or not. but that is not something this PR is about.

@sharwell
Copy link
Contributor

sharwell commented Feb 7, 2018

otherwise, there can be an abuser that think theirs are most important and put theirs at the head. so we don't give this control to author.

This is not a reason¹ to avoid allowing users to prioritize analyzers. Historically, the members working on dotnet/roslyn are just as likely, if not more so, to implement analyzers that are slower than third-party analyzers.

¹ To clarify, this is not even a weak reason. If anything, this serves as a reason to allow third-party analyzers to declare priorities because it explicitly acknowledges the user benefits of running analyzers in specified orders.

💡 If you ever find yourself thinking "people maybe shouldn't do this", it's almost certainly the case that 'people' includes our own team. 😄

@heejaechang
Copy link
Contributor Author

heejaechang commented Feb 7, 2018

letting users set priority is I believe what we want. not authors. we currently disallow author from setting it.
we want to have a way for users to set them, and Blame is to get to that ability. asking users without any data to set priority is, I think, as bad as just not providing the ability. Blame + other data such as how often you used, how many errors shown and etc will help users to make informed decision on priority. but again, that is not this PR is for.

..
¹ To clarify, this is not even a weak reason. If anything, this serves as a reason to allow third-party analyzers to declare priorities because it explicitly acknowledges the user benefits of running analyzers in specified orders.

yep, we should allow users to set priority. BUT NEVER let author to set it. (sure, except first party including F# and typescript. especially F# and typescript since they don't have concept of third party analyzers)
..
" it's almost certainly the case that 'people' includes our own team"

I don't agree we should be treated exactly same as third party. if we don't have requirement to maintain API backward compatibility/perf or quality, then sure. we can innovate/experiment and breaks people as we go along. but since we need to maintain all those, I don't see anyway we expose everything we do to third party such as supporting special treatment on compiler diagnostic analyzers which get participate in build/live error duplication, Document/ProjectDiagnosticAnalyzer that use Solution directly rather than compilation.

we do have something we try to expose to third-party such as Options (currently only first party can use options) through editorconfig.

there are some we want to expose such as IBuiltInAnalyzer.GetAnalyzerCategory which can improve perf on demand analysis on span.

also there are something we want to get rid of "OpenFlieOnly".

all these, I dont think we can expose them as we introduce before we internally playing with them. once we have such thing, engine must treat first party special.

@heejaechang
Copy link
Contributor Author

@sharwell not sure which you want to change.

@heejaechang
Copy link
Contributor Author

ping? @sharwell and @Pilchie @jinujoseph ?

@sharwell
Copy link
Contributor

sharwell commented Feb 8, 2018

not authors.

I did mean I believe authors should be able to control it.

Copy link
Contributor

@sharwell sharwell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accepting as an interim solution while we work on blame and overall driver performance. With additional work going into the analyzer driver for performance, expect two things to occur in the future:

  1. The current API to change
  2. The eventual API to expose the final option uniformly, allowing for reordering by analyzer authors and/or users without limitations to origin

@heejaechang
Copy link
Contributor Author

I am against letting author to set priority so I guess that is design question? tagging @jinujoseph and @dotnet/roslyn-analysis @dotnet/roslyn-ide

if (state == _compilerStateSet)
{
return _compilerStateSet;
return -2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we extract these into constant fields?

@mavasani
Copy link
Contributor

mavasani commented Feb 8, 2018

I am against exposing any analyzer priority based public API or mechanism, until there is strong request from community (analyzer authors or users) with a valid reason how this will help them.

  1. It is difficult to rationalize priorities for diagnostic analyzers coming from different analyzer assemblies/packages.
  2. A common end user would not know about performance characteristics of each diagnostic analyzer to be able decide how to order the execution.

I think ordering comes into picture only when we start putting expensive/slow analyzers into the pool of analyzers getting executed. Instead of enabling users/authors to push these analyzers to the end of the queue, we should instead focus on a better blame story so end users can disable expensive analyzers and help analyzer authors improve their analyzers.

@heejaechang
Copy link
Contributor Author

retest windows_debug_unit64_prtest please

@heejaechang
Copy link
Contributor Author

@Pilchie can you take a look?

@Pilchie
Copy link
Member

Pilchie commented Feb 9, 2018

I approve of the scenario, but I'd like confirmation from at least one of F#/TS that this is sufficient to alleviate their issues. @dsyme or @minestarks - how can we work to validate that this will be enough for your use cases?

@Pilchie
Copy link
Member

Pilchie commented Feb 9, 2018

Also tagging @brettfo - maybe we could create a VAL build containing this change and a corresponding change to F# to supply priorities and let people try that out?

@dsyme
Copy link

dsyme commented Feb 9, 2018

cc @TIHan

@Pilchie I looked at the code and it appears to be exactly what Visual F# Tools need. It would be good to do a validation via an evaluation build though.

To do that we'd need to

  1. co-build Visual F# Tools and Roslyn (they use the same RoslynDev hive)
  2. set the priority of the document analyzers in Visual F# Tools
  3. trial to check errors are being shown faster

@heejaechang
Copy link
Contributor Author

@dsyme @TIHan let me know once you guys are done testing.

@minestarks
Copy link

@Pilchie I can't recall whether we had a specific demand around this. We did have broad discussions about priority in the past, so I checked to see whether this change would help. In our case, we have a mechanism to prioritize by document type (library files vs. user files) rather than analyzer type. I don't think this change directly allows us to control that, but I can see us maybe splitting our current DocumentDiagnosticAnalyzer into two different analyzers (one that only handles library files, and another that handles user files) with different priorities.

So yes, potentially helpful, but I don't think we'll be consuming this immediately.

@dsyme
Copy link

dsyme commented Feb 12, 2018

@heejaechang Ugh, I'm having trouble building the dev15.7.x branch.

image

@sharwell
Copy link
Contributor

/cc @jaredpar for error ⬆️

@dsyme
Copy link

dsyme commented Feb 12, 2018

In a normal directory I get this:

>     C:\GitHub\dsyme>dotnet --version
      2.1.4

I get this in the roslyn directory:

C:\GitHub\dsyme\roslyn>dotnet --version
The specified SDK version [2.2.0-preview1-007622] from global.json [C:\GitHub\dsyme\roslyn\global.json] not found; install specified SDK version
Did you mean to run dotnet SDK commands? Please install dotnet SDK from:
  http://go.microsoft.com/fwlink/?LinkID=798306&clcid=0x409

@dsyme
Copy link

dsyme commented Feb 12, 2018

Trying a

git clean -xfd

@dsyme
Copy link

dsyme commented Feb 12, 2018

Same problem

@sharwell
Copy link
Contributor

@dsyme The Roslyn repository is locked to a specific version of the dotnet tool and the .NET SDK. The former is automatically installed by the Restore script in the repository, but the latter requires manual installation. If the correct version of the SDK isn't already located on the system (e.g. as part of a prior Visual Studio install that uses the same version), you'll have to follow the link provided in the error to install the specific version. The error will then be resolved until the next time we need to upgrade our SDK reference.

@dsyme
Copy link

dsyme commented Feb 12, 2018

OK, but it downloaded and installed the dotnet SDK pre-release version during restore. But then fails to detect it during build. Also the offered link http://go.microsoft.com/fwlink/?LinkID=798306&clcid=0x409 doesn't give me an option to manually install the specific pre-release 2.2.0 version requested

The log for the Restore & build after a git clean is below:

C:\GitHub\dsyme\roslyn>Restore.cmd
Repo Dir C:\GitHub\dsyme\roslyn
Binaries Dir C:\GitHub\dsyme\roslyn\Binaries
Downloading CLI 2.2.0-preview1-007622
dotnet-install: Downloading link: https://dotnetcli.azureedge.net/dotnet/Sdk/2.2.0-preview1-007622/dotnet-sdk-2.2.0-preview1-007622-win-x64.zip
dotnet-install: Extracting zip from https://dotnetcli.azureedge.net/dotnet/Sdk/2.2.0-preview1-007622/dotnet-sdk-2.2.0-preview1-007622-win-x64.zip
dotnet-install: Adding to current process PATH: "C:\GitHub\dsyme\roslyn\Binaries\Tools\dotnet\". Note: This change will not be visible if PowerShell was run as a child process.
dotnet-install: Installation finished
dotnet-install: Downloading link: https://dotnetcli.azureedge.net/dotnet/Runtime/2.0.0/dotnet-runtime-2.0.0-win-x64.zip
dotnet-install: Extracting zip from https://dotnetcli.azureedge.net/dotnet/Runtime/2.0.0/dotnet-runtime-2.0.0-win-x64.zip
dotnet-install: Adding to current process PATH: "C:\GitHub\dsyme\roslyn\Binaries\Tools\dotnet\". Note: This change will not be visible if PowerShell was run as a child process.
dotnet-install: Installation finished
Running restore
Restore using dotnet at C:\GitHub\dsyme\roslyn\Binaries\Tools\dotnet\dotnet.exe
Restoring Roslyn Toolset

Configuring...
--------------
A command is running to populate your local package cache to improve restore speed and enable offline access. This command takes up to one minute to complete and only runs once.
Decompressing 100% 8521 ms
Expanding 100% 29369 ms
Restoring Roslyn
Restoring DevDivInsertionFiles
C:\GitHub\dsyme\roslyn>.\build
Repo Dir C:\GitHub\dsyme\roslyn
Binaries Dir C:\GitHub\dsyme\roslyn\Binaries
The specified SDK version [2.2.0-preview1-007622] from global.json [C:\GitHub\dsyme\roslyn\global.json] not found; install specified SDK version
The specified SDK version [2.2.0-preview1-007622] from global.json [C:\GitHub\dsyme\roslyn\global.json] not found; install specified SDK version
C:\GitHub\dsyme\roslyn\build\Targets\Imports.targets(422,5): error : The 2.2.0 SDK is required to build this repo. It can be insta
ll here https://dotnetcli.blob.core.windows.net/dotnet/Sdk/2.2.0-preview1-007622/dotnet-sdk-2.2.0-preview1-007622-win-x64.exe [C:\
GitHub\dsyme\roslyn\src\Compilers\Core\CodeAnalysisTest\CodeAnalysisTest.csproj]
The specified SDK version [2.2.0-preview1-007622] from global.json [C:\GitHub\dsyme\roslyn\global.json] not found; install specified SDK version
The specified SDK version [2.2.0-preview1-007622] from global.json [C:\GitHub\dsyme\roslyn\global.json] not found; install specified SDK version

@sharwell
Copy link
Contributor

@dsyme A direct link is given in the red text from your error screenshot:

https://dotnetcli.blob.core.windows.net/dotnet/Sdk/2.2.0-preview1-007622/dotnet-sdk-2.2.0-preview1-007622-win-x64.exe

@dsyme
Copy link

dsyme commented Feb 12, 2018

AH thanks, didn't see that one

@dsyme
Copy link

dsyme commented Feb 12, 2018

Quick question: which Roslyn.sln startup project should I use to F5 debug into a new RoslynDev-hive (in order to exercise the new code above)?

@sharwell
Copy link
Contributor

which Roslyn.sln startup project should I use to F5 debug into a new RoslynDev-hive

VisualStudioSetup.Next

@dsyme
Copy link

dsyme commented Feb 12, 2018

@sharwell To pick up the new Roslyn binaries do I have to HintPath to

 \GitHub\dsyme\roslyn\Binaries\Release\Dlls\...

binary-by-binary from the VIsualFSharp.sln? If so, which specific binaries are affected by the above fix?

@dsyme
Copy link

dsyme commented Feb 12, 2018

@sharwell

which Roslyn.sln startup project should I use to F5 debug into a new RoslynDev-hive

VisualStudioSetup.Next

Quick question: how do I confirm if this is running in a RoslynDev registry hive? It seems to know all my settings history when I launch which surprises me (e.g. different to when I launch into using "Roslyn" project as the startup project)

@sharwell
Copy link
Contributor

To pick up the new Roslyn binaries do I have to HintPath ...

I'm not sure on this one (new area for me).

Quick question: how do I confirm if this is running in a RoslynDev registry hive?

If you used F5 (or Ctrl+F5), it's almost certainly in the RoslynDev hive. You can use Process Explorer to see the command line arguments passed to the process if you want to conficb.

@dsyme
Copy link

dsyme commented Feb 12, 2018

Looks like only Microsoft.CodeAnalysis.Features.dll

@mavasani
Copy link
Contributor

Quick question: how do I confirm if this is running in a RoslynDev registry hive?

You can also verify the location of the loaded Microsoft.CodeAnalysis assemblies using the debugger modules window.

@dsyme
Copy link

dsyme commented Feb 12, 2018

@heejaechang Just to check - Priority 1 = go first, Priority 1000 = go last? The docs just say "in ascending order" which I'm still not clear about

@sharwell
Copy link
Contributor

sharwell commented Feb 12, 2018

Just to check - Priority 1 = go first, Priority 1000 = go last?

Yes, priority 1 goes first for the configurable analyzers. The default value is 50.

@dsyme
Copy link

dsyme commented Feb 12, 2018

OK, I confirm this works! See the notes on the corresponding Visual F# pull request dotnet/fsharp#4341

@Pilchie
Copy link
Member

Pilchie commented Feb 12, 2018

Thanks for the confirmation @dsyme. @heejaechang Approved to merge for 15.7.

@jaredpar
Copy link
Member

@dsyme, @sharwell

That's really odd. From the command line Restore and Build should always work. We bootstrap everything. Indeed it is going through the bootstrap phase for CLI here but the latter msbuild call is not picking up the installation. That's pretty straight forward as all we need to do is manipulate %PATH% to see the download.

@dsyme is this a simple cmd window (not a developer command prompt)? Can you run :set and paste the output. Want to see what could be interfering here.

@heejaechang
Copy link
Contributor Author

VS roams setting between hives as well. if you don't want that, you need to turn this off

image

@heejaechang heejaechang merged commit 66de1a9 into dotnet:dev15.7.x Feb 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants