Find Step Usages command results in doubled list of steps

#163 ยท open ยท 12 comments

View on GitHub โ†—

clrudolphi

### Used Visual Studio Visual Studio 2026 ### Are the latest Visual Studio updates installed? Yes ### Content of reqnroll.json (if present) none ### Issue Description The `Find Step Usages` command results in a double listing of steps. <img width="1920" height="1032" alt="Image" src="https://github.com/user-attachments/assets/ac586352-8724-4111-9a10-90eab63e4be9" /> ### Steps to Reproduce Create a new VS Reqnroll project using the VS Extension wizard. Upgrade the Reqnroll package to latest. Compile. Navigate to the example calculator step definitions. Right click a step definition method and select `Find Step Definition Usages` ### Link to a project repository that reproduces the issue _No response_

Comments

clrudolphi

It seems to me that the issue was introduced with Reqnroll release 3.3.0.

clrudolphi

Further investigation: Added a line of logging to the FindStepUsages command code: ```c# private async Task FindUsagesInternalAsync(IProjectScope[] reqnrollTestProjects, string fileName, SnapshotPoint triggerPoint, IAsyncContextMenu asyncContextMenu, CancellationToken cancellationToken, FindUsagesSummary summary) { foreach (var project in reqnrollTestProjects) { if (cancellationToken.IsCancellationRequested) break; var stepDefinitions = await GetStepDefinitionsAsync(project, fileName, triggerPoint); summary.FoundStepDefinitions += stepDefinitions.Length; if (stepDefinitions.Length == 0) continue; var featureFiles = project.GetProjectFiles(".feature"); foreach (var featureFile in featureFiles) { Logger.LogInfo($"Found feature file: {project.ProjectFullName} {featureFile}."); } var configuration = project.GetDeveroomConfiguration(); var projectUsages = _stepDefinitionUsageFinder.FindUsages(stepDefinitions, featureFiles, configuration); foreach (var usage in projectUsages) { if (cancellationToken.IsCancellationRequested) break; //await Task.Delay(500); asyncContextMenu.AddItems(CreateMenuItem(usage, project)); summary.UsagesFound++; } summary.ScannedFeatureFiles += featureFiles.Length; } } ``` When the above is run on a sample project that has three feature files, it reports **six** feature files found, each repeated twice. ``` Info: OnActivityStarted: Starting Visual Studio Extension... Info: CreateProjectScope: Initializing project: Repro_FindStepDefUsages_doubled Info: OnSettingsInitialized: Project settings initialized: .NETCoreApp,Version=v8.0,Reqnroll:3.3.0 Info: GetDotNetExecCommand: Invoking 'Reqnroll-Generic-net8.0\reqnroll-vs.dll'... Info: ThenImportBindings: 4 step definitions and 0 hooks discovered for project Repro_FindStepDefUsages_doubled Info: FindUsagesInternalAsync: Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Calculator.feature. Info: FindUsagesInternalAsync: Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Calculator.feature. Info: FindUsagesInternalAsync: Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Second.feature. Info: FindUsagesInternalAsync: Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Second.feature. Info: FindUsagesInternalAsync: Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Third.feature. Info: FindUsagesInternalAsync: Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Third.feature. Info: FindUsagesInProjectsAsync: Found 6 usages in 6 feature files ``` This is not specific to NUnit (same behavior with MsTest as the test framework). It does seem that the `IProjectScope` has been populated with each feature twice. I haven't yet found the root cause. I also remained completely stumped by the observation that this problem does not occur prior to v3.3.0 of Reqnroll - I'm not understanding how the version would influence how the VisualStudio project system would be influenced by that.

304NotModified

Is it really the v3.3 update? Or could it be a VS update? Or maybe a sln+slnx (just a guess) Maybe also add some logging to vsutils , for example this method: https://github.com/reqnroll/Reqnroll.VisualStudio/blob/b80f37cdac6a234a42093932f63db01ac44c2591/Reqnroll.VisualStudio.Package/VsUtils.cs#L492

clrudolphi

> Is it really the v3.3 update? Or could it be a VS update? V3.3 is at least part of it. When I downgrade to v3.2.1 the problem goes away. Would you mind trying to reproduce this? Just to confirm that it is not just my VS instance?

clrudolphi

> Maybe also add some logging to vsutils Here is result of logging the Name and Kind of the `ProjectItems` as they are enumerated by the `VsUtils.GetProjectItems()` method: ``` ReqnrollVs: Verbose: PreExec:Find Step Definition Usages ReqnrollVs: Verbose: PreExec:Find Step Definition Usages:PreExec: project loaded Found project item: Features; Kind: {6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C} Found project item: Calculator.feature; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} ReqnrollVs: Verbose: ShowContextMenu:Caret screen position: 409:440 ReqnrollVs: Verbose: Exec:00:00:00.0889065 PreExec FindStepDefinitionUsagesCommand handled:True in C:\Users\clrud\source\repos\Reqnroll.VisualStudio\Reqnroll.VisualStudio\Editor\Commands\Infrastructure\DeveroomEditorCommandBroker.cs: line 128 ReqnrollVs: Verbose: Exec:00:00:00.0907329 PostExec FindStepDefinitionUsagesCommand handled:False in C:\Users\clrud\source\repos\Reqnroll.VisualStudio\Reqnroll.VisualStudio\Editor\Commands\Infrastructure\DeveroomEditorCommandBroker.cs: line 140 Found project item: Features; Kind: {6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C} Found project item: Calculator.feature; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: Calculator.feature; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: Calculator.feature.cs; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: Second.feature; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: Second.feature; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: Second.feature.cs; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: Third.feature; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: Third.feature; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: Third.feature.cs; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: StepDefinitions; Kind: {6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C} Found project item: CalculatorStepDefinitions.cs; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: .gitignore; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: nunit.engine.api.dll; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: nunit.engine.core.dll; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: nunit.engine.dll; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: NUnit3.TestAdapter.dll; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: NUnit3.TestAdapter.pdb; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: testcentric.engine.metadata.dll; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: testhost.dll; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} Found project item: testhost.exe; Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C} ReqnrollVs: Info: FindUsagesInternalAsync:Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Calculator.feature. ReqnrollVs: Info: FindUsagesInternalAsync:Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Calculator.feature. ReqnrollVs: Info: FindUsagesInternalAsync:Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Second.feature. ReqnrollVs: Info: FindUsagesInternalAsync:Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Second.feature. ReqnrollVs: Info: FindUsagesInternalAsync:Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Third.feature. ReqnrollVs: Info: FindUsagesInternalAsync:Found feature file: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled.csproj C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Third.feature. The thread 53604 has exited with code 0 (0x0). The thread 59156 has exited with code 0 (0x0). The thread 75176 has exited with code 0 (0x0). The thread 57148 has exited with code 0 (0x0). The thread 60980 has exited with code 0 (0x0). The thread 58372 has exited with code 0 (0x0). The thread 70388 has exited with code 0 (0x0). The thread 69456 has exited with code 0 (0x0). ReqnrollVs: Info: FindUsagesInProjectsAsync:Found 6 usages in 6 feature files ``` It reconfirms that the VS project system thinks they are duplicated. It doesn't help me explain why. Would there be any other property of each `ProjectItem` that I should be logging that would help?

clrudolphi

After a bit more digging, I think have a proximate cause, but not root cause. The feature file items are included in the `ProjectItems` collection twice, each with a different 'parent': ``` Name: Calculator.feature, Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}, File: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Calculator.feature, Parent: Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAFolderItem Name: Calculator.feature, Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}, File: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Calculator.feature, Parent: Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProjectItem Name: Second.feature, Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}, File: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Second.feature, Parent: Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAFolderItem Name: Second.feature, Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}, File: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Second.feature, Parent: Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProjectItem Name: Third.feature, Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}, File: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Third.feature, Parent: Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAFolderItem Name: Third.feature, Kind: {6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}, File: C:\Users\clrud\source\repos\repros\Repro_FindStepDefUsages_doubled\Repro_FindStepDefUsages_doubled\Features\Third.feature, Parent: Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProjectItem ``` Once as belonging to the 'Features' folder and once belonging to the project directly. It's possible that the changes we made in Reqnroll v3.3.0 (perhaps in the MsBuild Generator) changed the population of an `<ItemGroup>` or a logical link got created/changed with the wrong parent. Continuing the investigation there.

clrudolphi

When I switch between v3.2.1 and v3.3.0 and use the MSBuild Structured Log Viewer to see how Item groups were resolved, the big difference between them is that with the v3.3.0 release there is a `<None>` group present that includes all the feature files. This item group is not present under v3.2.1. When I modify a .csproj file that is using v3.3.0 to explicitly eliminate the feature files from the `None` group, such as with: ```html <ItemGroup> <None Remove="**\*.feature" /> </ItemGroup> ``` The problem is no longer present. Adding an exclusion pattern like this to the `Reqnroll.Tools.MsBuild.Generation.targets` file also solves the problem. I haven't found a specific change yet that would have caused this. Still looking.

clrudolphi

I think I have a root cause. In PR#[941](https://github.com/reqnroll/Reqnroll/pull/941) the `Reqnroll.Tools.MSBuild.Generation.prpps` file was changed and line 51 was [removed](https://github.com/reqnroll/Reqnroll/pull/941/changes#diff-c6a29c09f2929c0623998786724b8cb5b75395d0723ecc0af3d8cda372381a66L51): ```xml <DefaultItemExcludes>$(DefaultItemExcludes);**/*.feature</DefaultItemExcludes> ``` When I add that back into the props file, my example project no longer exhibits the problem of duplicate feature files. @gasparnagy What do you think? Is that line safe to add back in to the props file? Will that interfere with the build in other ways?

gasparnagy

> I think I have a root cause. > > In PR#[941](https://github.com/reqnroll/Reqnroll/pull/941) the `Reqnroll.Tools.MSBuild.Generation.prpps` file was changed and line 51 was [removed](https://github.com/reqnroll/Reqnroll/pull/941/changes#diff-c6a29c09f2929c0623998786724b8cb5b75395d0723ecc0af3d8cda372381a66L51): > > <DefaultItemExcludes>$(DefaultItemExcludes);**/*.feature</DefaultItemExcludes> > When I add that back into the props file, my example project no longer exhibits the problem of duplicate feature files. > > [@gasparnagy](https://github.com/gasparnagy) What do you think? Is that line safe to add back in to the props file? Will that interfere with the build in other ways? Thanks for the intensive analysis on this. I have removed this line as part of the cleanup process of the MsBuild settings. The [`<DefaultItemExcludes>` setting](https://learn.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#defaultitemexcludes) should contain things that are generally not belonging to the project (similar to .gitignore), the default value excludes `./bin` and `./obj` folders. So "by design" of MsBuild (if I understand MsBuild docs correctly), feature files should not be listed there. I think what the problem might be is that we add the feature files to multiple groups (like `None`, but maybe some other too), and remove them from one of these. But this needs further analysis (and a very extensive testing, including up-to-date checks). MsBuild settings are pretty magical. I know that it is the harder and maybe not the nicest way ๐Ÿ™, but could we just de-duplicate them in the VS extension command?

clrudolphi

> I know that it is the harder and maybe not the nicest way ๐Ÿ™, but could we just de-duplicate them in the VS extension command? Yes, we can do this. It's not ideal IMO; treating a symptom rather than the root cause. But as a temporary measure it will be effective. I'll add that logic and we can remove it in a subsequent release when we've had time to do the thorough analysis needed.

gasparnagy

> > I know that it is the harder and maybe not the nicest way ๐Ÿ™, but could we just de-duplicate them in the VS extension command? > > Yes, we can do this. It's not ideal IMO; treating a symptom rather than the root cause. But as a temporary measure it will be effective. I'll add that logic and we can remove it in a subsequent release when we've had time to do the thorough analysis needed. I have reviewed the MsBuild stuff and we do not include the feature files to any other collections. It is only in the `<ReqnrollFeatureFile>`... So I have no idea why they are listed twice and why `<DefaultItemExcludes>` would fix this. One more: Could you please try what happens if you enable `ReqnrollUseIntermediateOutputPathForCodeBehind`? (After enable, make sure you rebuild and then restart VS before you test)

jrod567

> > I know that it is the harder and maybe not the nicest way ๐Ÿ™, but could we just de-duplicate them in the VS extension command? > > Yes, we can do this. It's not ideal IMO; treating a symptom rather than the root cause. But as a temporary measure it will be effective. I'll add that logic and we can remove it in a subsequent release when we've had time to do the thorough analysis needed. @clrudolphi Curious if you were still planning on implementing this stop gap? We've been seeing this one for quite a while as well.