Skip to content

Commit 1fbf60f

Browse files
authored
Fix Kotlin fake source mapping (#10880)
Fix Kotlin fake source mapping When there is no mapping to original source code, Kotlin SMAP use the fake.kt file inside the SoruceDebugExtenstion. Need to support this to avoid having line not correctly mapped and that are beyond the end of the file fix unit test fix spotless Co-authored-by: jean-philippe.bempel <jean-philippe.bempel@datadoghq.com>
1 parent 954fe13 commit 1fbf60f

File tree

7 files changed

+83
-25
lines changed

7 files changed

+83
-25
lines changed

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SourceRemapper.java

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,18 @@ static SourceRemapper getSourceRemapper(String sourceFile, SourceMap sourceMap)
1313
JvmLanguage jvmLanguage = JvmLanguage.of(sourceFile);
1414
switch (jvmLanguage) {
1515
case KOTLIN:
16-
StratumExt stratum = sourceMap.getStratum("KotlinDebug");
17-
if (stratum == null) {
18-
throw new IllegalArgumentException("No stratum found for KotlinDebug");
16+
StratumExt stratumMain = sourceMap.getStratum("Kotlin");
17+
if (stratumMain == null) {
18+
stratumMain = sourceMap.getStratum(sourceMap.getDefaultStratumName());
19+
if (stratumMain == null) {
20+
throw new IllegalArgumentException("No default stratum found");
21+
}
1922
}
20-
return new KotlinSourceRemapper(stratum);
23+
StratumExt stratumDebug = sourceMap.getStratum("KotlinDebug");
24+
if (stratumDebug == null) {
25+
throw new IllegalArgumentException("No stratumDebug found for KotlinDebug");
26+
}
27+
return new KotlinSourceRemapper(stratumMain, stratumDebug);
2128
default:
2229
return NOOP_REMAPPER;
2330
}
@@ -33,19 +40,33 @@ public int remapSourceLine(int line) {
3340
}
3441

3542
class KotlinSourceRemapper implements SourceRemapper {
36-
private final StratumExt stratum;
43+
private final StratumExt stratumMain;
44+
private final StratumExt stratumDebug;
3745

38-
public KotlinSourceRemapper(StratumExt stratum) {
39-
this.stratum = stratum;
46+
public KotlinSourceRemapper(StratumExt stratumMain, StratumExt stratumDebug) {
47+
this.stratumMain = stratumMain;
48+
this.stratumDebug = stratumDebug;
4049
}
4150

4251
@Override
4352
public int remapSourceLine(int line) {
44-
Pair<String, Integer> pair = stratum.getInputLine(line);
45-
if (pair == null || pair.getRight() == null) {
46-
return line;
53+
Pair<String, Integer> pairDebug = stratumDebug.getInputLine(line);
54+
if (pairDebug == null || pairDebug.getRight() == null) {
55+
Pair<String, Integer> pairMain = stratumMain.getInputLine(line);
56+
if (pairMain == null || pairMain.getRight() == null) {
57+
return line;
58+
}
59+
String fileId = pairMain.getLeft();
60+
String sourceFileName = stratumMain.getSourceFileName(fileId);
61+
if (sourceFileName == null) {
62+
throw new IllegalArgumentException("Cannot find source filename for fileid=" + fileId);
63+
}
64+
if (sourceFileName.equals("fake.kt")) {
65+
return -1; // no mapping possible
66+
}
67+
return pairMain.getRight();
4768
}
48-
return pair.getRight();
69+
return pairDebug.getRight();
4970
}
5071
}
5172
}

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymbolExtractor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ private static MethodLineInfo extractMethodLineInfo(
506506
if (node.getType() == AbstractInsnNode.LINE) {
507507
LineNumberNode lineNumberNode = (LineNumberNode) node;
508508
int newLine = sourceRemapper.remapSourceLine(lineNumberNode.line);
509-
if (dedupSet.add(newLine)) {
509+
if (newLine > 0 && dedupSet.add(newLine)) {
510510
lineNo.add(newLine);
511511
}
512512
maxLine = Math.max(newLine, maxLine);

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SourceRemapperTest.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ public void noopSourceRemapper() {
2121
@Test
2222
public void kotlinSourceRemapper() {
2323
SourceMap sourceMapMock = mock(SourceMap.class);
24-
StratumExt stratumMock = mock(StratumExt.class);
25-
when(sourceMapMock.getStratum(eq("KotlinDebug"))).thenReturn(stratumMock);
26-
when(stratumMock.getInputLine(eq(42))).thenReturn(Pair.of("", 24));
24+
StratumExt stratumMainMock = mock(StratumExt.class);
25+
StratumExt stratumDebugMock = mock(StratumExt.class);
26+
when(sourceMapMock.getStratum(eq("Kotlin"))).thenReturn(stratumMainMock);
27+
when(sourceMapMock.getStratum(eq("KotlinDebug"))).thenReturn(stratumDebugMock);
28+
when(stratumDebugMock.getInputLine(eq(42))).thenReturn(Pair.of("", 24));
2729
SourceRemapper sourceRemapper = SourceRemapper.getSourceRemapper("foo.kt", sourceMapMock);
2830
assertTrue(sourceRemapper instanceof SourceRemapper.KotlinSourceRemapper);
2931
assertEquals(24, sourceRemapper.remapSourceLine(42));

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymbolExtractionTransformerTest.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,7 @@ public void symbolExtraction16() throws IOException, URISyntaxException {
10021002
}
10031003
assertEquals(2, symbolSinkMock.jarScopes.size());
10041004
Scope classScope = symbolSinkMock.jarScopes.get(0).getScopes().get(0);
1005-
assertScope(classScope, ScopeType.CLASS, CLASS_NAME, 6, 17, SOURCE_FILE, 4, 1);
1005+
assertScope(classScope, ScopeType.CLASS, CLASS_NAME, 6, 23, SOURCE_FILE, 5, 1);
10061006
assertLangSpecifics(
10071007
classScope.getLanguageSpecifics(),
10081008
asList("public", "final"),
@@ -1024,12 +1024,15 @@ public void symbolExtraction16() throws IOException, URISyntaxException {
10241024
Scope f2MethodScope = classScope.getScopes().get(2);
10251025
assertScope(f2MethodScope, ScopeType.METHOD, "f2", 10, 17, SOURCE_FILE, 3, 1);
10261026
assertLineRanges(f2MethodScope, "10-10", "12-12", "14-14", "16-17");
1027+
Scope f3MethodScope = classScope.getScopes().get(3);
1028+
assertScope(f3MethodScope, ScopeType.METHOD, "f3", 21, 23, SOURCE_FILE, 1, 1);
1029+
assertLineRanges(f3MethodScope, "21-23");
10271030
assertScope(
1028-
classScope.getScopes().get(3), ScopeType.METHOD, "<clinit>", 0, 0, SOURCE_FILE, 0, 0);
1031+
classScope.getScopes().get(4), ScopeType.METHOD, "<clinit>", 0, 0, SOURCE_FILE, 0, 0);
10291032

10301033
Scope companionClassScope = symbolSinkMock.jarScopes.get(1).getScopes().get(0);
10311034
assertScope(
1032-
companionClassScope, ScopeType.CLASS, CLASS_NAME + "$Companion", 22, 23, SOURCE_FILE, 3, 0);
1035+
companionClassScope, ScopeType.CLASS, CLASS_NAME + "$Companion", 28, 29, SOURCE_FILE, 3, 0);
10331036
assertLangSpecifics(
10341037
classScope.getLanguageSpecifics(),
10351038
asList("public", "final"),
@@ -1047,8 +1050,8 @@ public void symbolExtraction16() throws IOException, URISyntaxException {
10471050
0,
10481051
0);
10491052
Scope mainMethodScope = companionClassScope.getScopes().get(1);
1050-
assertScope(mainMethodScope, ScopeType.METHOD, "main", 22, 23, SOURCE_FILE, 1, 1);
1051-
assertLineRanges(mainMethodScope, "22-23");
1053+
assertScope(mainMethodScope, ScopeType.METHOD, "main", 28, 29, SOURCE_FILE, 1, 1);
1054+
assertLineRanges(mainMethodScope, "28-29");
10521055
}
10531056

10541057
@Test

dd-java-agent/agent-debugger/src/test/resources/CapturedSnapshot301.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ class CapturedSnapshot301 {
1515
return value
1616
}
1717

18+
fun f3(value: Int): Int {
19+
val list = listOf(value, 2, 3)
20+
val max = list.maxOf { it -> it > 0 }
21+
return value
22+
}
23+
1824
companion object {
1925
fun main(arg: String): Int {
2026
val c = CapturedSnapshot301()

dd-java-agent/agent-debugger/src/test/resources/com/datadog/debugger/symboltest/SymbolExtraction16.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ class SymbolExtraction16 {
1717
return value
1818
}
1919

20+
fun f3(value: Int): Int {
21+
val list = listOf(value, 2, 3)
22+
val max = list.maxOf { it -> it > 0 }
23+
return value
24+
}
25+
2026
companion object {
2127
fun main(arg: String): Int {
2228
val c = SymbolExtraction16()

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/stratum/StratumExt.java

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
import java.util.ArrayList;
55
import java.util.Arrays;
66
import java.util.Comparator;
7+
import java.util.HashMap;
78
import java.util.List;
9+
import java.util.Map;
810
import org.slf4j.Logger;
911
import org.slf4j.LoggerFactory;
1012

1113
public class StratumExt extends AbstractStratum implements Stratum {
1214
private final List<FileInfo> fileInfo = new ArrayList<>();
15+
private Map<String, FileInfo> fileInfoMap;
1316

1417
private int[] lineStart = null;
1518

@@ -57,11 +60,28 @@ public String getSourceFile(String fileId) {
5760
if (fileInfo.isEmpty()) {
5861
return null;
5962
}
60-
return fileInfo.stream()
61-
.filter(f -> f.getFileId().equals(fileId))
62-
.findFirst()
63-
.map(FileInfo::getInputFilePath)
64-
.orElse(null);
63+
populateFileInfoMap();
64+
FileInfo fileInfo = fileInfoMap.get(fileId);
65+
return fileInfo != null ? fileInfo.getInputFilePath() : null;
66+
}
67+
68+
public String getSourceFileName(String fileId) {
69+
if (fileInfo.isEmpty()) {
70+
return null;
71+
}
72+
populateFileInfoMap();
73+
FileInfo fileInfo = fileInfoMap.get(fileId);
74+
return fileInfo != null ? fileInfo.getInputFileName() : null;
75+
}
76+
77+
private void populateFileInfoMap() {
78+
if (fileInfoMap != null) {
79+
return;
80+
}
81+
fileInfoMap = new HashMap<>();
82+
for (FileInfo fileInfo : fileInfo) {
83+
fileInfoMap.put(fileInfo.getFileId(), fileInfo);
84+
}
6585
}
6686

6787
public List<FileInfo> getFileInfo() {

0 commit comments

Comments
 (0)