Skip to content

Commit 6d6b60c

Browse files
committed
Improve handling of relative file paths in report files
- Up to know we were stating in our [Wiki](https://github.com/SonarOpenCommunity/sonar-cxx/wiki/Troubleshooting-Reports): Relative paths in report files are always relative to the project base directory. Start relative paths always with .\ on Windows or ./ on Linux. - relative paths starting with '..' were resolved to null in the past. "No file" results in adding an issue on project level (project issue). In such a case we replace null with the filename. This leads at least to an error message an that and the issue is not added to the project because typically no such indexed file exists. - The real problem is that tools generate reports with relative paths without defining which base directory is referred to. This problem remains and must be solved via the CI/CD and tool configuration. - close #2741
1 parent 95ea2ae commit 6d6b60c

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

cxx-squid/src/main/java/org/sonar/cxx/utils/CxxReportLocation.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
package org.sonar.cxx.utils;
2121

22+
import java.nio.file.Paths;
2223
import java.util.Objects;
2324
import javax.annotation.Nullable;
2425
import org.sonar.api.utils.PathUtils;
@@ -35,8 +36,19 @@ public class CxxReportLocation {
3536

3637
public CxxReportLocation(@Nullable String file, @Nullable String line, @Nullable String column, String info) {
3738
super();
38-
// normalize file, removing double and single dot path steps => avoids duplicates
39-
this.file = PathUtils.sanitize(file);
39+
40+
// Normalize file using separators in UNIX format, removing double and single dot path steps. This is to avoid
41+
// duplicates in the issue containers because they are using the file as key. PathUtils.sanitize uses
42+
// FilenameUtils.normalize internally, relative paths starting with a double dot will cause that path segment
43+
// and the one before to be removed. If the double dot has no parent path segment to work with, null is returned.
44+
// null would mean 'project issue' which is wrong in this context. To avoid this we extract the filename to
45+
// generate at least a meningful error message.
46+
var normalized = PathUtils.sanitize(file);
47+
if (normalized == null && (file != null && !file.isBlank())) {
48+
normalized = Paths.get(file).getFileName().toString();
49+
}
50+
51+
this.file = normalized;
4052
this.line = line;
4153
this.column = column;
4254
this.info = info;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* C++ Community Plugin (cxx plugin)
3+
* Copyright (C) 2010-2023 SonarOpenCommunity
4+
* http://github.com/SonarOpenCommunity/sonar-cxx
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
package org.sonar.cxx.utils;
21+
22+
import static org.assertj.core.api.Assertions.*;
23+
import org.junit.jupiter.api.Test;
24+
25+
public class CxxReportLocationTest {
26+
27+
@Test
28+
void testConstructor() {
29+
var loc0 = new CxxReportLocation(null, null, null, "info");
30+
assertThat(loc0.getFile()).isNull();
31+
assertThat(loc0.getLine()).isNull();
32+
assertThat(loc0.getColumn()).isNull();
33+
assertThat(loc0.getInfo()).isEqualTo("info");
34+
assertThat(loc0.toString()).isEqualTo("CxxReportLocation [file=null, line=null, column=null, info=info]");
35+
36+
var loc1 = new CxxReportLocation("file", "line", "column", "info");
37+
assertThat(loc1.getFile()).isEqualTo("file");
38+
assertThat(loc1.getLine()).isEqualTo("line");
39+
assertThat(loc1.getColumn()).isEqualTo("column");
40+
assertThat(loc1.getInfo()).isEqualTo("info");
41+
assertThat(loc1.toString()).isEqualTo("CxxReportLocation [file=file, line=line, column=column, info=info]");
42+
}
43+
44+
@Test
45+
void testPathSanitize() {
46+
var loc = new CxxReportLocation("file", null, null, "");
47+
48+
loc = new CxxReportLocation("/dir/File", null, null, "");
49+
assertThat(loc.getFile()).isEqualTo("/dir/File");
50+
loc = new CxxReportLocation("/dir/./File", null, null, "");
51+
assertThat(loc.getFile()).isEqualTo("/dir/File");
52+
loc = new CxxReportLocation("/dir/../File", null, null, "");
53+
assertThat(loc.getFile()).isEqualTo("/File");
54+
loc = new CxxReportLocation("dir/File", null, null, "");
55+
assertThat(loc.getFile()).isEqualTo("dir/File");
56+
loc = new CxxReportLocation("./dir/File", null, null, "");
57+
assertThat(loc.getFile()).isEqualTo("dir/File");
58+
loc = new CxxReportLocation("../dir/File", null, null, "");
59+
assertThat(loc.getFile()).isEqualTo("File");
60+
loc = new CxxReportLocation("../../File", null, null, "");
61+
assertThat(loc.getFile()).isEqualTo("File");
62+
63+
loc = new CxxReportLocation("c:\\dir\\file.ext", null, null, "");
64+
assertThat(loc.getFile()).isEqualTo("c:/dir/file.ext");
65+
loc = new CxxReportLocation("C:\\dir\\.\\file.ext", null, null, "");
66+
assertThat(loc.getFile()).isEqualTo("C:/dir/file.ext");
67+
loc = new CxxReportLocation("c:\\dir\\..\\file.ext", null, null, "");
68+
assertThat(loc.getFile()).isEqualTo("c:/file.ext");
69+
loc = new CxxReportLocation("dir\\file.ext", null, null, "");
70+
assertThat(loc.getFile()).isEqualTo("dir/file.ext");
71+
loc = new CxxReportLocation(".\\dir\\file.ext", null, null, "");
72+
assertThat(loc.getFile()).isEqualTo("dir/file.ext");
73+
loc = new CxxReportLocation("..\\dir\\file.ext", null, null, "");
74+
assertThat(loc.getFile()).isEqualTo("file.ext");
75+
loc = new CxxReportLocation("..\\..\\file.ext", null, null, "");
76+
assertThat(loc.getFile()).isEqualTo("file.ext");
77+
}
78+
}

0 commit comments

Comments
 (0)