Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.function.UnaryOperator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.TextRange;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.symbol.NewSymbol;
import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
Expand All @@ -48,6 +49,33 @@ public SymbolRefsImporter(SensorContext context, UnaryOperator<String> toRealPat
this.context = context;
}

private static void addReferences(InputFile file, SymbolReferenceInfo.SymbolReference tokenInfo, NewSymbolTable symbolTable) {
var declarationRange = toTextRange(file, tokenInfo.getDeclaration());
if (declarationRange.isPresent()) {
NewSymbol symbol = symbolTable.newSymbol(declarationRange.get());
for (SonarAnalyzer.TextRange refTextRange : tokenInfo.getReferenceList()) {
var validatedReference = validatedReference(file, refTextRange, declarationRange.get());
validatedReference.ifPresent(symbol::newReference);
}
}
}

private static Optional<TextRange> validatedReference(InputFile file, SonarAnalyzer.TextRange refTextRange, TextRange declarationRange) {
var referenceRange = toTextRange(file, refTextRange);
if (referenceRange.isEmpty()) {
if (LOG.isDebugEnabled()) {
LOG.debug("The reported token was out of the range. File {}, Range {}", file.filename(), refTextRange);
Copy link
Contributor Author

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).

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.

}
return Optional.empty();
} else if (declarationRange.overlap(referenceRange.get())) {
if (LOG.isDebugEnabled()) {
LOG.debug("The declaration token at {} overlaps with the referencing token {} in file {}", declarationRange, referenceRange.get(), file.filename());
}
return Optional.empty();
}
return referenceRange;
}

@Override
void consumeFor(InputFile inputFile, SymbolReferenceInfo message) {
for (SonarAnalyzer.SymbolReferenceInfo.SymbolReference tokenInfo : message.getReferenceList()) {
Expand All @@ -73,21 +101,4 @@ boolean isProcessed(InputFile inputFile) {
// we aggregate all symbol reference information, no need to process only the first protobuf file
return false;
}

private static void addReferences(InputFile file, SymbolReferenceInfo.SymbolReference tokenInfo, NewSymbolTable symbolTable) {
var declarationRange = toTextRange(file, tokenInfo.getDeclaration());
if (declarationRange.isPresent()) {
NewSymbol symbol = symbolTable.newSymbol(declarationRange.get());
for (SonarAnalyzer.TextRange refTextRange : tokenInfo.getReferenceList()) {
var referenceRange = toTextRange(file, refTextRange);
if (referenceRange.isPresent()) {
symbol.newReference(referenceRange.get());
} else if (LOG.isDebugEnabled()) {
LOG.debug("The reported token was out of the range. File {}, Range {}", file.filename(), refTextRange);
}
}
} else if (LOG.isDebugEnabled()) {
LOG.debug("The reported token was out of the range. File {}, Range {}", file.filename(), tokenInfo.getDeclaration());
}
}
}
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 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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
Expand Up @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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());

Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {

Choose a reason for hiding this comment

The 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

Choose a reason for hiding this comment

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

Creating the sut is duplicated (but slightly different), we should extract a function to create it.


// 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());

Choose a reason for hiding this comment

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

    var sut = new SymbolRefsImporter(sensorContext, RazorImporterTestBase::fileName);

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;

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The 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 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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):

Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
0
Cases.razor 8r x�
L
EC:\Users\martin.strecker\Desktop\WebAss\OverlapSymbolReferences.razor8rU
3C:\Users\martin.strecker\Desktop\WebAss\Cases.razor 8r x�A
2C:\Users\martin.strecker\Desktop\WebAss\Program.cs 8r
Expand Down
Loading