-
Notifications
You must be signed in to change notification settings - Fork 239
Don't fail for Razor: SymbolReference locations for @typeparam are misplaced #8424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7010dca
6a5d29b
1efc0f1
7d13a76
bd48e09
8bf0fcc
e09eb21
2fc10fd
8610ce4
d88d8bb
442cdfb
7eee3d8
52b2d83
6667539
d5bcf35
3fd86f5
1f45892
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| /* | ||
| * SonarSource :: .NET :: Shared library | ||
| * Copyright (C) 2014-2023 SonarSource SA | ||
| * mailto:info AT sonarsource DOT com | ||
| * | ||
| * This program is free software; you can redistribute it and/or | ||
| * modify it under the terms of the GNU Lesser General Public | ||
| * License as published by the Free Software Foundation; either | ||
| * version 3 of the License, or (at your option) any later version. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| * Lesser General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public License | ||
| * along with this program; if not, write to the Free Software Foundation, | ||
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| */ | ||
| package org.sonarsource.dotnet.shared.plugins.protobuf; | ||
|
|
||
| import java.io.File; | ||
| import java.io.FileNotFoundException; | ||
| import java.io.FileReader; | ||
| import java.nio.file.Paths; | ||
| import org.junit.Before; | ||
| import org.junit.Rule; | ||
| import org.slf4j.event.Level; | ||
| import org.sonar.api.batch.fs.internal.DefaultInputFile; | ||
| import org.sonar.api.batch.fs.internal.FileMetadata; | ||
| import org.sonar.api.batch.fs.internal.TestInputFileBuilder; | ||
| import org.sonar.api.batch.sensor.internal.SensorContextTester; | ||
| import org.sonar.api.notifications.AnalysisWarnings; | ||
| import org.sonar.api.testfixtures.log.LogTester; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.mockito.Mockito.mock; | ||
|
|
||
| public class RazorImporterTestBase { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New base class for all tests that interact with "src/test/resources/RazorProtobufImporter" files. |
||
| protected final static File TEST_DATA_DIR = new File("src/test/resources/RazorProtobufImporter"); | ||
| protected final SensorContextTester sensorContext = SensorContextTester.create(TEST_DATA_DIR); | ||
| @Rule | ||
| public LogTester logTester = new LogTester(); | ||
| protected DefaultInputFile CasesInputFile; | ||
| protected DefaultInputFile OverlapSymbolReferencesInputFile; | ||
| protected DefaultInputFile ProgramInputFile; | ||
|
|
||
| protected static String fileName(String filePath) { | ||
| return Paths.get(filePath).getFileName().toString(); | ||
| } | ||
|
|
||
| @Before | ||
| public void setUp() throws FileNotFoundException { | ||
| logTester.setLevel(Level.TRACE); | ||
| CasesInputFile = addTestFileToContext("Cases.razor"); | ||
| OverlapSymbolReferencesInputFile = addTestFileToContext("OverlapSymbolReferences.razor"); | ||
| ProgramInputFile = addTestFileToContext("Program.cs"); | ||
| } | ||
|
|
||
| private DefaultInputFile addTestFileToContext(String testFilePath) throws FileNotFoundException { | ||
| var testFile = new File(TEST_DATA_DIR, testFilePath); | ||
| assertThat(testFile).withFailMessage("no such file: " + testFilePath).isFile(); | ||
| var inputFile = new TestInputFileBuilder("dummyKey", testFilePath) | ||
| .setMetadata(new FileMetadata(mock(AnalysisWarnings.class)).readMetadata(new FileReader(testFile))) | ||
| .build(); | ||
| sensorContext.fileSystem().add(inputFile); | ||
| return inputFile; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,69 +19,58 @@ | |
| */ | ||
| package org.sonarsource.dotnet.shared.plugins.protobuf; | ||
|
|
||
| import java.io.File; | ||
| import java.io.FileNotFoundException; | ||
| import java.util.Collections; | ||
| import org.assertj.core.groups.Tuple; | ||
| import org.junit.Before; | ||
| import org.junit.Test; | ||
| import org.sonar.api.batch.fs.InputFile; | ||
| import org.sonar.api.batch.fs.internal.FileMetadata; | ||
| import org.sonar.api.batch.fs.internal.TestInputFileBuilder; | ||
| import org.sonar.api.batch.sensor.internal.SensorContextTester; | ||
| import org.sonar.api.issue.NoSonarFilter; | ||
| import org.sonar.api.measures.CoreMetrics; | ||
| import org.sonar.api.measures.FileLinesContext; | ||
| import org.sonar.api.measures.FileLinesContextFactory; | ||
| import org.sonar.api.notifications.AnalysisWarnings; | ||
|
|
||
| import java.io.File; | ||
| import java.io.FileNotFoundException; | ||
| import java.io.FileReader; | ||
| import java.util.Collections; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.mockito.ArgumentMatchers.any; | ||
| import static org.mockito.Mockito.*; | ||
| import static org.mockito.Mockito.mock; | ||
| import static org.mockito.Mockito.times; | ||
| import static org.mockito.Mockito.verify; | ||
| import static org.mockito.Mockito.when; | ||
| import static org.sonarsource.dotnet.shared.plugins.ProtobufDataImporter.METRICS_FILENAME; | ||
|
|
||
| public class RoslynMetricsImporterTest { | ||
| private static final File TEST_DATA_DIR = new File("src/test/resources/RazorProtobufImporter"); | ||
| private static final String TEST_FILE_PATH = "Cases.razor"; | ||
| private static final File TEST_FILE = new File(TEST_DATA_DIR, TEST_FILE_PATH); | ||
| public class RazorMetricsImporterTest extends RazorImporterTestBase { | ||
| private static final File PROTOBUF_FILE = new File(TEST_DATA_DIR, METRICS_FILENAME); | ||
|
|
||
| @Before | ||
| public void before() { | ||
| assertThat(TEST_FILE).withFailMessage("no such file: " + TEST_FILE).isFile(); | ||
| @Override | ||
| public void setUp() throws FileNotFoundException { | ||
| super.setUp(); | ||
| assertThat(PROTOBUF_FILE).withFailMessage("no such file: " + PROTOBUF_FILE).isFile(); | ||
| } | ||
|
|
||
| @Test | ||
| public void roslyn_metrics_are_imported() throws FileNotFoundException { | ||
| var inputFile = new TestInputFileBuilder("dummyKey", TEST_FILE_PATH) | ||
| .setMetadata(new FileMetadata(mock(AnalysisWarnings.class)).readMetadata(new FileReader(TEST_FILE))) | ||
| .build(); | ||
|
|
||
| var sensorContext = SensorContextTester.create(TEST_FILE); | ||
| sensorContext.fileSystem().add(inputFile); | ||
|
|
||
| public void roslyn_metrics_are_imported() { | ||
| var inputFile = CasesInputFile; | ||
| var noSonarFilter = mock(NoSonarFilter.class); | ||
| var fileLinesContext = mock(FileLinesContext.class); | ||
| var fileLinesContextFactory = mock(FileLinesContextFactory.class); | ||
| when(fileLinesContextFactory.createFor(any(InputFile.class))).thenReturn(fileLinesContext); | ||
|
|
||
| new MetricsImporter(sensorContext, fileLinesContextFactory, noSonarFilter, String::toString).accept(PROTOBUF_FILE.toPath()); | ||
| new MetricsImporter(sensorContext, fileLinesContextFactory, noSonarFilter, RazorImporterTestBase::fileName).accept(PROTOBUF_FILE.toPath()); | ||
|
|
||
| var measures = sensorContext.measures(inputFile.key()); | ||
| assertThat(measures).hasSize(7); | ||
|
|
||
| assertThat(measures).extracting("metric", "value") | ||
| .containsOnly( | ||
| Tuple.tuple(CoreMetrics.CLASSES, 1), | ||
| Tuple.tuple(CoreMetrics.STATEMENTS, 15), | ||
| Tuple.tuple(CoreMetrics.FUNCTIONS, 4), | ||
| Tuple.tuple(CoreMetrics.COMPLEXITY, 5), | ||
| Tuple.tuple(CoreMetrics.FUNCTIONS, 3), | ||
| Tuple.tuple(CoreMetrics.COMMENT_LINES, 0), | ||
| Tuple.tuple(CoreMetrics.COGNITIVE_COMPLEXITY, 1), | ||
| Tuple.tuple(CoreMetrics.NCLOC, 14)); | ||
| Tuple.tuple(CoreMetrics.CLASSES, 0), | ||
| Tuple.tuple(CoreMetrics.NCLOC, 13), | ||
| Tuple.tuple(CoreMetrics.STATEMENTS, 6)); | ||
|
Comment on lines
-78
to
+73
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some values changed, likely because the pd files were created new, and the old ones didn't fit "Cases.razor" or because the old ones were created with .Net 7 SDK and the new ones with .Net 8 SDK. |
||
|
|
||
| verify(noSonarFilter).noSonarInFile(inputFile, Collections.emptySet()); | ||
|
|
||
|
|
@@ -92,11 +81,10 @@ public void roslyn_metrics_are_imported() throws FileNotFoundException { | |
| verify(fileLinesContext).setIntValue(CoreMetrics.EXECUTABLE_LINES_DATA_KEY, 23, 1); | ||
| verify(fileLinesContext).setIntValue(CoreMetrics.EXECUTABLE_LINES_DATA_KEY, 24, 1); | ||
|
|
||
| verify(fileLinesContext).setIntValue(CoreMetrics.NCLOC_DATA_KEY, 3, 1); | ||
| verify(fileLinesContext).setIntValue(CoreMetrics.NCLOC_DATA_KEY, 5, 1); | ||
| verify(fileLinesContext, times(2)).setIntValue(CoreMetrics.NCLOC_DATA_KEY, 3, 1); | ||
| verify(fileLinesContext, times(2)).setIntValue(CoreMetrics.NCLOC_DATA_KEY, 5, 1); | ||
| verify(fileLinesContext).setIntValue(CoreMetrics.NCLOC_DATA_KEY, 8, 1); | ||
| verify(fileLinesContext).setIntValue(CoreMetrics.NCLOC_DATA_KEY, 9, 1); | ||
| verify(fileLinesContext).setIntValue(CoreMetrics.NCLOC_DATA_KEY, 11, 1); | ||
| verify(fileLinesContext).setIntValue(CoreMetrics.NCLOC_DATA_KEY, 13, 1); | ||
| verify(fileLinesContext).setIntValue(CoreMetrics.NCLOC_DATA_KEY, 16, 1); | ||
| verify(fileLinesContext).setIntValue(CoreMetrics.NCLOC_DATA_KEY, 18, 1); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,61 +19,60 @@ | |
| */ | ||
| package org.sonarsource.dotnet.shared.plugins.protobuf; | ||
|
|
||
| import java.io.File; | ||
| import java.io.FileNotFoundException; | ||
| import java.nio.file.Paths; | ||
| import org.junit.Before; | ||
| import org.junit.Rule; | ||
| import org.junit.Test; | ||
| import org.slf4j.event.Level; | ||
| import org.sonar.api.batch.fs.internal.FileMetadata; | ||
| import org.sonar.api.batch.fs.internal.TestInputFileBuilder; | ||
| import org.sonar.api.batch.sensor.internal.SensorContextTester; | ||
| import org.sonar.api.notifications.AnalysisWarnings; | ||
| import org.sonar.api.testfixtures.log.LogTester; | ||
|
|
||
| import java.io.File; | ||
| import java.io.FileNotFoundException; | ||
| import java.io.FileReader; | ||
|
|
||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.mockito.Mockito.mock; | ||
| import static org.sonarsource.dotnet.shared.plugins.ProtobufDataImporter.SYMBOLREFS_FILENAME; | ||
|
|
||
| public class RoslynSymbolRefsImporterTest { | ||
|
|
||
| private static final File TEST_DATA_DIR = new File("src/test/resources/RazorProtobufImporter"); | ||
| private static final String TEST_FILE_PATH = "Cases.razor"; | ||
| private static final File TEST_FILE = new File(TEST_DATA_DIR, TEST_FILE_PATH); | ||
|
|
||
| private final SensorContextTester sensorContext = SensorContextTester.create(TEST_DATA_DIR); | ||
| public class RazorSymbolRefsImporterTest extends RazorImporterTestBase { | ||
| private final File protobuf = new File(TEST_DATA_DIR, SYMBOLREFS_FILENAME); | ||
|
|
||
| @Rule | ||
| public LogTester logTester = new LogTester(); | ||
|
|
||
| @Override | ||
| @Before | ||
| public void setUp() { | ||
| logTester.setLevel(Level.TRACE); | ||
| public void setUp() throws FileNotFoundException { | ||
| super.setUp(); | ||
| assertThat(protobuf).withFailMessage("no such file: " + protobuf).isFile(); | ||
| } | ||
|
|
||
| @Test | ||
| public void test_symbol_refs_get_imported() throws FileNotFoundException { | ||
| var inputFile = new TestInputFileBuilder("dummyKey", TEST_FILE_PATH) | ||
| .setMetadata(new FileMetadata(mock(AnalysisWarnings.class)).readMetadata(new FileReader(TEST_FILE))) | ||
| .build(); | ||
| sensorContext.fileSystem().add(inputFile); | ||
| public void test_symbol_refs_get_imported_cases() { | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pedantic: there is an empty line at the beginning of the tests that is not needed |
||
| var sut = new SymbolRefsImporter(sensorContext, String::toString); | ||
| var inputFile = CasesInputFile; | ||
| var sut = new SymbolRefsImporter(sensorContext, RazorImporterTestBase::fileName); | ||
| sut.accept(protobuf.toPath()); | ||
| sut.save(); | ||
|
Comment on lines
+46
to
48
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Creating the |
||
|
|
||
| // a symbol is defined at this location, and referenced at 3 other locations | ||
| assertThat(sensorContext.referencesForSymbolAt(inputFile.key(), 8, 30)).hasSize(1); | ||
| assertThat(sensorContext.referencesForSymbolAt(inputFile.key(), 8, 15)).hasSize(2); | ||
|
|
||
| // ... other similar examples ... | ||
| assertThat(sensorContext.referencesForSymbolAt(inputFile.key(), 16, 16)).hasSize(4); | ||
| assertThat(sensorContext.referencesForSymbolAt(inputFile.key(), 21, 17)).hasSize(1); | ||
| assertThat(sensorContext.referencesForSymbolAt(inputFile.key(), 19, 15)).hasSize(3); | ||
| assertThat(sensorContext.referencesForSymbolAt(inputFile.key(), 21, 17)).isEmpty(); | ||
|
|
||
| assertThat(logTester.logs(Level.DEBUG)).containsExactly( | ||
| "The declaration token at Range[from [line=1, lineOffset=0] to [line=1, lineOffset=17]] overlaps with the referencing token Range[from [line=1, lineOffset=6] to [line=1, lineOffset=23]] in file OverlapSymbolReferences.razor"); | ||
| } | ||
|
|
||
| @Test | ||
| public void test_symbol_refs_get_imported_overlapSymbolReferences() { | ||
|
|
||
| var inputFile = OverlapSymbolReferencesInputFile; | ||
| var sut = new SymbolRefsImporter(sensorContext, s -> Paths.get(s).getFileName().toString()); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| sut.accept(protobuf.toPath()); | ||
| sut.save(); | ||
|
|
||
| var references = sensorContext.referencesForSymbolAt(inputFile.key(), 1, 1); | ||
| assertThat(references) | ||
| .isNotNull() // The symbol declaration can be found, | ||
| .isEmpty(); // but there are no references, due to the overlap. | ||
|
|
||
| assertThat(logTester.logs(Level.DEBUG).get(0)).startsWith("The reported token was out of the range. File Cases.razor, Range start_line: 8"); | ||
| assertThat(logTester.logs(Level.DEBUG)).containsExactly( | ||
| "The declaration token at Range[from [line=1, lineOffset=0] to [line=1, lineOffset=17]] overlaps with the referencing token Range[from [line=1, lineOffset=6] to [line=1, lineOffset=23]] in file OverlapSymbolReferences.razor"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"> | ||
| <PropertyGroup> | ||
| <ProjectGuid>{1250CC30-A343-4A10-A1DE-B1792ADB6244}</ProjectGuid> | ||
| <TargetFramework>net8.0</TargetFramework> | ||
| <RuntimeIdentifier>browser-wasm</RuntimeIdentifier> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" /> | ||
| <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0" PrivateAssets="all" /> | ||
| <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.0" /> | ||
| </ItemGroup> | ||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| @typeparam TSomeVeryLongName where TSomeVeryLongName : class |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| namespace WebAss; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The first chars look strange. Is the encoding set correctly on the file? |
||
|
|
||
| public class Program | ||
| { | ||
| public static void Main() { } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| Please see the ReadMe.md file from `ProtobufImporterTest` folder that explains how to use the `ProtobufFilterTool`. | ||
| ### How to re-create the pb files | ||
|
|
||
| Before running the tool please update the following fields in the `ProtobufFilterTool`: | ||
| - TEST_DATA_DIR should point to `"sonar-dotnet-shared-library/src/test/resources/RazorProtobufImporter"` | ||
| - TEST_FILENAME should point to `"Cases.razor"` | ||
| - Create a Project in SonarQube (manual setup) | ||
| - Open a console in this directory | ||
| - Run the "Start" and the "Build" step as given by SonarQube | ||
| - Copy the pb files from `.sonarqube\out\0\output-cs` here |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,4 @@ | ||
| m | ||
| bC:\src\work\sonar-dotnet\its\projects\RazorMetrics\obj\Debug\net7.0\RazorMetrics.GlobalUsings.g.csutf-8} | ||
| rC:\src\work\sonar-dotnet\its\projects\RazorMetrics\obj\Debug\net7.0\.NETCoreApp,Version=v7.0.AssemblyAttributes.csutf-8k | ||
| `C:\src\work\sonar-dotnet\its\projects\RazorMetrics\obj\Debug\net7.0\RazorMetrics.AssemblyInfo.csutf-8� | ||
| wMicrosoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\Cases_razor.g.csutf-8� | ||
| zMicrosoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\_Imports_razor.g.csutf-8 | ||
| ; | ||
| 2C:\Users\martin.strecker\Desktop\WebAss\Program.csutf-8Z | ||
| OC:\Users\martin.strecker\Desktop\WebAss\obj\Debug\net8.0\WebAss.AssemblyInfo.csutf-8r | ||
| gC:\Users\martin.strecker\Desktop\WebAss\obj\Debug\net8.0\.NETCoreApp,Version=v8.0.AssemblyAttributes.csutf-8 |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -1 +1 @@ | ||||
| Roslyn version: 4.6.0.0Language version: CSharp11!Concurrent execution: enabled��File 'C:\src\work\sonar-dotnet\its\projects\RazorMetrics\obj\Debug\net7.0\RazorMetrics.GlobalUsings.g.cs' was recognized as generated��File 'C:\src\work\sonar-dotnet\its\projects\RazorMetrics\obj\Debug\net7.0\.NETCoreApp,Version=v7.0.AssemblyAttributes.cs' was recognized as generated��File 'C:\src\work\sonar-dotnet\its\projects\RazorMetrics\obj\Debug\net7.0\RazorMetrics.AssemblyInfo.cs' was recognized as generated��File 'Microsoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\Cases_razor.g.cs' was recognized as generated��File 'Microsoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\_Imports_razor.g.cs' was recognized as generated | ||||
| Roslyn version: 4.8.0.0Language version: CSharp12!Concurrent execution: enabled��File 'Microsoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\OverlapSymbolReferences_razor.g.cs' was recognized as razor generated��File 'Microsoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\Cases_razor.g.cs' was recognized as razor generatedvrFile 'C:\Users\martin.strecker\Desktop\WebAss\obj\Debug\net8.0\WebAss.AssemblyInfo.cs' was recognized as generated��File 'C:\Users\martin.strecker\Desktop\WebAss\obj\Debug\net8.0\.NETCoreApp,Version=v8.0.AssemblyAttributes.cs' was recognized as generated | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. double check I understand well: did you recreate these PB files with .NET 8 @martin-strecker-sonarsource ?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. I also added the csproj as part of the PR, so it is more easy to recreate the pb files (before, the csproj was missing): Line 4 in 1f45892
|
||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We lost coverage for that line because in the new pb, there is not "out of range" anymore (either fixed in .Net 8 SDK or fixed somewhere else).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They fixed the tab problem and we used tabs to reproduce that out-of-range issue.