Comments (17)
Also, as 17.10 preview 4 just came out, can you give it a spin. There have been lots of changes in this area, so it's possible this was fixed (or got worse =-o). Would be good to know if it still repros to you on that build. Thanks!
Will give it a go when I get home and update
from roslyn.
My only downside I can think of is I want to generate source code for tests which might be defined in a base class, and there's no easy way to view inherited classes without searching through the entire compilation, right?
Correct, there is absolutely no efficient way to do that. Our strong recommendation is that you not design your domain space in this fashion. We ourselves never do this. The runtime team never does this. Exactly because it just cannot be done 'incrementally' (today at least). So far, all of our first party consumers are good with this, and the 3rd party ecosystem has been doing the same.
It might seem unfortunate, but if you can't model the domain around what ISGs can actually provide well, we recommend not using SGs as the tool here, and you should use something else instead.
from roslyn.
That's this line:
Which is... bad.
That's being called here:
So we're asking for the doc state for a generated document, and we're finding that it no longer exists. Thsi sholud not be possible in our snapshot model. I will try to repro this with the provided branch tomorrow.
from roslyn.
Note: i did'nt look deeply (about to go to bed), but your generators are not properly written:
This captures IMethodSymbols in the incremental pipeline adn will never be incremental. Your generator will run virtuall on every node in the entire compilation virtually on every keystroke.
from roslyn.
I thought the idea is it'd just run on edited nodes, so keystrokes on methods? What do I need to do if this is incorrect?
from roslyn.
I thought the idea is it'd just run on edited nodes, so keystrokes on methods? What do I need to do if this is incorrect?
The problem is related to the identification of "edited nodes". The IMethodSymbol
implementation captures all context about a method, including large amounts of context that is unrelated to your source generator. If any of this context changes, it will be treated as "edited" and cause those nodes to run again through the source generator. In practice, any edit anywhere in the project causes one or more changes to every IMethodSymbol
in the project.
The solution to this is to create a custom data structure, e.g. MyMethodData
, which contains properties for only the aspect of IMethodSymbol
you need in your source generator. This data object should be equatable, either as a record, or by implementing IEquatable<T>
, or by providing an IEqualityComparer<MyMethodData>
to the portions of the source generator pipeline that produce it. Using a custom data model will allow the incrementality to take effect by only running steps in the pipeline when the symbol changes as it relates to what you are using from it.
I generally recommend users start at the end of the pipeline for defining the data models, and then work backwards towards the beginning to create steps that generate them.
from roslyn.
I thought the idea is it'd just run on edited nodes, so keystrokes on methods? What do I need to do if this is incorrect?
The problem is related to the identification of "edited nodes". The
IMethodSymbol
implementation captures all context about a method, including large amounts of context that is unrelated to your source generator. If any of this context changes, it will be treated as "edited" and cause those nodes to run again through the source generator. In practice, any edit anywhere in the project causes one or more changes to everyIMethodSymbol
in the project.The solution to this is to create a custom data structure, e.g.
MyMethodData
, which contains properties for only the aspect ofIMethodSymbol
you need in your source generator. This data object should be equatable, either as a record, or by implementingIEquatable<T>
, or by providing anIEqualityComparer<MyMethodData>
to the portions of the source generator pipeline that produce it. Using a custom data model will allow the incrementality to take effect by only running steps in the pipeline when the symbol changes as it relates to what you are using from it.I generally recommend users start at the end of the pipeline for defining the data models, and then work backwards towards the beginning to create steps that generate them.
Ah I did not know that! Thanks for the information, I'll try and make it more efficient!
from roslyn.
@thomhurst I highly recommend https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.cookbook.md. note that the use of var testMethods = context.SyntaxProvider.CreateSyntaxProvider
is high discouraged as it has no incrementality and will on every node on ever edit. Our recommended pattern is to use the ForAttributeWithMetadataName
to register pipeline steps to run on symbols that have a particular attribute on it that you decide. This is (no exaggeration), generally around 1000x faster than .CreateSyntaxProvider
and can often take around 1000x less memory (depending on what the callbacks passed into CreateSyntaxProvider do).
This is the only pattern we now use in the runtime itself for our own generators as it's the only system we've found fast enough, with a good balance of expressivity, and reasonableness around user experiences (for people directly using teh generator, or indirectly using it when they pull it in through a package).
from roslyn.
@thomhurst Having a little trouble repro'ing this. When i try, all the steps work up to the last step Right click TUnit.TestProject inside VS. Click run tests
. When i do that, test-explorer gives me the following message:
========== Starting test discovery ==========
Microsoft.VisualStudio.TestPlatform.ObjectModel.TestPlatformException: Could not find testhost
at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting.DotnetTestHostManager.GetTestHostProcessStartInfo(IEnumerable`1 sources, IDictionary`2 environmentVariables, TestRunnerConnectionInfo connectionInfo) in /_/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs:line 410
at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.ProxyOperationManager.SetupChannel(IEnumerable`1 sources, String runSettings) in /_/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs:line 223
at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.ProxyDiscoveryManager.InitializeDiscovery(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEventsHandler2 eventHandler, Boolean skipDefaultAdapters) in /_/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs:line 149
========== Test discovery aborted: 0 Tests found in 1.3 sec ==========
Executing all tests in project: TUnit.TestProject
Is there some prereq/dependency i need here? Thanks!
from roslyn.
Also, as 17.10 preview 4 just came out, can you give it a spin. There have been lots of changes in this area, so it's possible this was fixed (or got worse =-o). Would be good to know if it still repros to you on that build. Thanks!
from roslyn.
@thomhurst Having a little trouble repro'ing this. When i try, all the steps work up to the last step
Right click TUnit.TestProject inside VS. Click run tests
. When i do that, test-explorer gives me the following message:========== Starting test discovery ========== Microsoft.VisualStudio.TestPlatform.ObjectModel.TestPlatformException: Could not find testhost at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting.DotnetTestHostManager.GetTestHostProcessStartInfo(IEnumerable`1 sources, IDictionary`2 environmentVariables, TestRunnerConnectionInfo connectionInfo) in /_/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs:line 410 at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.ProxyOperationManager.SetupChannel(IEnumerable`1 sources, String runSettings) in /_/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyOperationManager.cs:line 223 at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.ProxyDiscoveryManager.InitializeDiscovery(DiscoveryCriteria discoveryCriteria, ITestDiscoveryEventsHandler2 eventHandler, Boolean skipDefaultAdapters) in /_/src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs:line 149 ========== Test discovery aborted: 0 Tests found in 1.3 sec ========== Executing all tests in project: TUnit.TestProject
Is there some prereq/dependency i need here? Thanks!
Sorry you have to go into the Visual Studio experimental features and switch it on
tools -> options -> preview features -> testing platform server
from roslyn.
Sorry you have to go into the Visual Studio experimental features and switch it on
Thanks!
from roslyn.
@thomhurst I highly recommend https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.cookbook.md. note that the use of
var testMethods = context.SyntaxProvider.CreateSyntaxProvider
is high discouraged as it has no incrementality and will on every node on ever edit. Our recommended pattern is to use theForAttributeWithMetadataName
to register pipeline steps to run on symbols that have a particular attribute on it that you decide. This is (no exaggeration), generally around 1000x faster than.CreateSyntaxProvider
and can often take around 1000x less memory (depending on what the callbacks passed into CreateSyntaxProvider do).This is the only pattern we now use in the runtime itself for our own generators as it's the only system we've found fast enough, with a good balance of expressivity, and reasonableness around user experiences (for people directly using teh generator, or indirectly using it when they pull it in through a package).
This is very useful, thank you!
My only downside I can think of is I want to generate source code for tests which might be defined in a base class, and there's no easy way to view inherited classes without searching through the entire compilation, right?
So even if I found my test with an attribute marker, I can't easily find inherited members.
Because of this I'm having to search through ClassDeclarationSyntaxes and INamedTypeSymbols and iterate through it's methods and then check for my test markers which I know is going to be crazy heavy work
from roslyn.
Ok. Now i get:
Log level is set to Informational (Default).
Connected to test environment '< Local Windows Environment >'
Test data store opened in 0.109 sec.
Building Test Projects
Starting test discovery for requested test run
========== Starting test discovery ==========
Starting server mode
Telemetry collector provider: 'Microsoft.Testing.Platform.Telemetry.NopTelemetryService'
Telemetry is 'ENABLED'
DOTNET_NOLOGO environment variable: ''
TESTINGPLATFORM_NOBANNER environment variable: ''
DOTNET_CLI_TELEMETRY_OPTOUT environment variable: ''
TESTINGPLATFORM_TELEMETRY_OPTOUT environment variable: '0'
TestApplicationOptions.EnableTelemetry: True
Received initialize request
Connection established with 'Microsoft Visual Studio Testing Platform Client', protocol version 1.0.0
Received testing/discoverTests request
TestFrameworkAdapter UID: 'TUnitExtension' Version: '1.0.0.0' DisplayName: 'TUnit' Description: 'TUnit Framework for Microsoft Testing Platform'
Time elapsed: 00:00:00
Server requested to shutdown
========== Test discovery finished: 0 Tests found in 747.5 ms ==========
Executing all tests in project: TUnit.TestProject
========== Starting test run ==========
========== Test run aborted: 0 Tests (0 Passed, 0 Failed, 0 Skipped) run in < 1 ms ==========
========== Starting test discovery ==========
========== Test discovery skipped: All test containers are up to date ==========
But no yellowbars. LMK what you run into.
from roslyn.
My only downside I can think of is I want to generate source code for tests which might be defined in a base class, and there's no easy way to view inherited classes without searching through the entire compilation, right?
Correct, there is absolutely no efficient way to do that. Our strong recommendation is that you not design your domain space in this fashion. We ourselves never do this. The runtime team never does this. Exactly because it just cannot be done 'incrementally' (today at least). So far, all of our first party consumers are good with this, and the 3rd party ecosystem has been doing the same.
It might seem unfortunate, but if you can't model the domain around what ISGs can actually provide well, we recommend not using SGs as the tool here, and you should use something else instead.
Thanks! I might have to settle from some marker attributes then. Not what I wanted ideally but if it's a necessary evil then so be it. Really appreciate you explaining these to me. I feel a bit more clued up about source generators now 😄
from roslyn.
Ok. Now i get:
Log level is set to Informational (Default). Connected to test environment '< Local Windows Environment >' Test data store opened in 0.109 sec. Building Test Projects Starting test discovery for requested test run ========== Starting test discovery ========== Starting server mode Telemetry collector provider: 'Microsoft.Testing.Platform.Telemetry.NopTelemetryService' Telemetry is 'ENABLED' DOTNET_NOLOGO environment variable: '' TESTINGPLATFORM_NOBANNER environment variable: '' DOTNET_CLI_TELEMETRY_OPTOUT environment variable: '' TESTINGPLATFORM_TELEMETRY_OPTOUT environment variable: '0' TestApplicationOptions.EnableTelemetry: True Received initialize request Connection established with 'Microsoft Visual Studio Testing Platform Client', protocol version 1.0.0 Received testing/discoverTests request TestFrameworkAdapter UID: 'TUnitExtension' Version: '1.0.0.0' DisplayName: 'TUnit' Description: 'TUnit Framework for Microsoft Testing Platform' Time elapsed: 00:00:00 Server requested to shutdown ========== Test discovery finished: 0 Tests found in 747.5 ms ========== Executing all tests in project: TUnit.TestProject ========== Starting test run ========== ========== Test run aborted: 0 Tests (0 Passed, 0 Failed, 0 Skipped) run in < 1 ms ========== ========== Starting test discovery ========== ========== Test discovery skipped: All test containers are up to date ==========
But no yellowbars. LMK what you run into.
Just tried on Preview 4 and got the same as you. The source generation error seems to have disappeared.
Although I'm not sure why the test run is aborted. It doesn't seem to give any more information to try and tell why. Weird seeing as it runs via dotnet run
or dotnet test
from roslyn.
Goign to close out for now. Please let us know if you run into this again. We can reopen if there's a repro. Tnx.
from roslyn.
Related Issues (20)
- False positive CS8618 null reference type warning when using required members and [SetsRequiredMembers] in derived class HOT 2
- C# rename default constructor argument which is used as a property HOT 1
- Replacing using System with #include <stdio.h> in Roslyn C# Syntax Tree Rewriter HOT 3
- Debug assert triggered for interpolated string convserion
- "dotnet build-server shutdown" warning for missing dll HOT 3
- Enabling latest-All analyzers hangs build
- TestCode classification breaks in LSP for lines that begin with whitespace
- See squigglies in #if'd code but Quick Actions don't work. HOT 1
- Method name style is not consistent along the code HOT 1
- EnC: Emit System.Runtime.CompilerServices.HotReloadException
- Go to definition is not consistent with C# compilation when a symbol is missing HOT 8
- Auto-indent doesn't work in inline diff mode HOT 1
- $$ in source code causes test always to fail
- Nonsense identifier expected error depending on how you edit unrelated code HOT 1
- [Automated] PRs inserted in VS build feature.debugger.main-35118.200
- [Automated] PRs inserted in VS build main-35118.130
- IDE0270 creates invalid code HOT 2
- NuGet packages need to include a README.md HOT 2
- Code action "Allow unsafe code in this project" has no effect HOT 2
- Adding `_` (discard) in front of evaluation auto-completes to first symbol name match for `_` (underscore) HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from roslyn.