@@ -1367,4 +1367,79 @@ TEST(DIBuilder, DynamicOffsetAndSize) {
13671367 EXPECT_EQ (Field->getRawSizeInBits (), Len);
13681368}
13691369
1370+ TEST (DILocationTest, InlinedAtMethodsWithMultipleLevels) {
1371+ LLVMContext C;
1372+
1373+ // Create IR with 3 levels of inlining:
1374+ // main() calls inline1() which calls inline2() which calls inline3()
1375+ // We'll test from the perspective of code in inline3()
1376+ std::unique_ptr<Module> M = parseIR (C, R"(
1377+ define void @main() !dbg !10 {
1378+ ret void, !dbg !20
1379+ }
1380+
1381+ !llvm.dbg.cu = !{!0}
1382+ !llvm.module.flags = !{!2}
1383+
1384+ !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1)
1385+ !1 = !DIFile(filename: "test.c", directory: "/test")
1386+ !2 = !{i32 2, !"Debug Info Version", i32 3}
1387+
1388+ ; Subprograms for each function in the call chain
1389+ !10 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 100, unit: !0)
1390+ !11 = distinct !DISubprogram(name: "inline1", scope: !1, file: !1, line: 200, unit: !0)
1391+ !12 = distinct !DISubprogram(name: "inline2", scope: !1, file: !1, line: 300, unit: !0)
1392+ !13 = distinct !DISubprogram(name: "inline3", scope: !1, file: !1, line: 400, unit: !0)
1393+
1394+ ; Location in inline3 (line 401), inlined at location !21
1395+ !20 = !DILocation(line: 401, column: 5, scope: !13, inlinedAt: !21)
1396+
1397+ ; Location in inline2 (line 301) where inline3 was called, inlined at !22
1398+ !21 = !DILocation(line: 301, column: 10, scope: !12, inlinedAt: !22)
1399+
1400+ ; Location in inline1 (line 201) where inline2 was called, inlined at !23
1401+ !22 = !DILocation(line: 201, column: 15, scope: !11, inlinedAt: !23)
1402+
1403+ ; Location in main (line 101) where inline1 was called (no more inlinedAt)
1404+ !23 = !DILocation(line: 101, column: 3, scope: !10)
1405+ )" );
1406+
1407+ ASSERT_TRUE (M);
1408+
1409+ Function *MainFunc = M->getFunction (" main" );
1410+ ASSERT_TRUE (MainFunc);
1411+ Instruction &RetInst = MainFunc->getEntryBlock ().front ();
1412+
1413+ // Use getDebugLoc() to get the location from the ret instruction.
1414+ const DILocation *InnermostLoc = RetInst.getDebugLoc ().get ();
1415+ ASSERT_TRUE (InnermostLoc);
1416+
1417+ // Test getScope() - should return the immediate scope (inline3).
1418+ DILocalScope *ImmediateScope = InnermostLoc->getScope ();
1419+ ASSERT_TRUE (ImmediateScope);
1420+ EXPECT_TRUE (isa<DISubprogram>(ImmediateScope));
1421+ EXPECT_EQ (cast<DISubprogram>(ImmediateScope)->getName (), " inline3" );
1422+
1423+ // Test getInlinedAt() - should return the next level in the inlining chain.
1424+ const DILocation *NextLevel = InnermostLoc->getInlinedAt ();
1425+ ASSERT_TRUE (NextLevel);
1426+ EXPECT_EQ (NextLevel->getLine (), 301u );
1427+ EXPECT_EQ (cast<DISubprogram>(NextLevel->getScope ())->getName (), " inline2" );
1428+
1429+ // Test getInlinedAtLocation() - should return the outermost location.
1430+ const DILocation *OutermostLoc = InnermostLoc->getInlinedAtLocation ();
1431+ ASSERT_TRUE (OutermostLoc);
1432+ EXPECT_EQ (OutermostLoc->getLine (), 101u );
1433+ EXPECT_EQ (OutermostLoc->getColumn (), 3u );
1434+ EXPECT_EQ (OutermostLoc->getInlinedAt (), nullptr );
1435+ EXPECT_EQ (cast<DISubprogram>(OutermostLoc->getScope ())->getName (), " main" );
1436+
1437+ // Test getInlinedAtScope() - should return the scope of the outermost location.
1438+ DILocalScope *InlinedAtScope = InnermostLoc->getInlinedAtScope ();
1439+ ASSERT_TRUE (InlinedAtScope);
1440+ EXPECT_TRUE (isa<DISubprogram>(InlinedAtScope));
1441+ EXPECT_EQ (cast<DISubprogram>(InlinedAtScope)->getName (), " main" );
1442+ EXPECT_EQ (InlinedAtScope, OutermostLoc->getScope ());
1443+ }
1444+
13701445} // end namespace
0 commit comments