Skip to content

Commit 9a02676

Browse files
committed
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
1 parent 3ff081c commit 9a02676

File tree

6 files changed

+79
-22
lines changed

6 files changed

+79
-22
lines changed

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

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.datadog.debugger.symbol;
22

33
import com.datadog.debugger.util.JvmLanguage;
4+
import datadog.trace.agent.tooling.stratum.FileInfo;
45
import datadog.trace.agent.tooling.stratum.SourceMap;
56
import datadog.trace.agent.tooling.stratum.StratumExt;
67
import datadog.trace.api.Pair;
@@ -13,11 +14,18 @@ static SourceRemapper getSourceRemapper(String sourceFile, SourceMap sourceMap)
1314
JvmLanguage jvmLanguage = JvmLanguage.of(sourceFile);
1415
switch (jvmLanguage) {
1516
case KOTLIN:
16-
StratumExt stratum = sourceMap.getStratum("KotlinDebug");
17-
if (stratum == null) {
18-
throw new IllegalArgumentException("No stratum found for KotlinDebug");
17+
StratumExt stratumMain = sourceMap.getStratum("Kotlin");
18+
if (stratumMain == null) {
19+
stratumMain = sourceMap.getStratum(sourceMap.getDefaultStratumName());
20+
if (stratumMain == null) {
21+
throw new IllegalArgumentException("No default stratum found");
22+
}
1923
}
20-
return new KotlinSourceRemapper(stratum);
24+
StratumExt stratumDebug = sourceMap.getStratum("KotlinDebug");
25+
if (stratumDebug == null) {
26+
throw new IllegalArgumentException("No stratumDebug found for KotlinDebug");
27+
}
28+
return new KotlinSourceRemapper(stratumMain, stratumDebug);
2129
default:
2230
return NOOP_REMAPPER;
2331
}
@@ -33,19 +41,33 @@ public int remapSourceLine(int line) {
3341
}
3442

3543
class KotlinSourceRemapper implements SourceRemapper {
36-
private final StratumExt stratum;
44+
private final StratumExt stratumMain;
45+
private final StratumExt stratumDebug;
3746

38-
public KotlinSourceRemapper(StratumExt stratum) {
39-
this.stratum = stratum;
47+
public KotlinSourceRemapper(StratumExt stratumMain, StratumExt stratumDebug) {
48+
this.stratumMain = stratumMain;
49+
this.stratumDebug = stratumDebug;
4050
}
4151

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

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