Skip to content

Commit 312f1fa

Browse files
authored
[llvm][DebugInfo][test] DwarfTest: parameterize LanguageDescription tests (llvm#162863)
Better test coverage. The round-tripping test makes sure that if we ever change `llvm::dwarf::toDW_Lang` or `llvm::dwarf::toDW_LName`, we don't break the `LanguageDescription` API. The round-tripping test found an incorrect version check in `llvm::dwarf::toDW_Lang`, which I corrected as part of this PR (see the table at the bottom of https://dwarfstd.org/languages-v6.html for reference).
1 parent 24feeb2 commit 312f1fa

File tree

2 files changed

+182
-37
lines changed

2 files changed

+182
-37
lines changed

llvm/include/llvm/BinaryFormat/Dwarf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ toDW_LNAME(SourceLanguage language) {
390390
case DW_LANG_C11:
391391
return {{DW_LNAME_C, 201112}};
392392
case DW_LANG_C17:
393-
return {{DW_LNAME_C, 201712}};
393+
return {{DW_LNAME_C, 201710}};
394394
case DW_LANG_C_plus_plus:
395395
return {{DW_LNAME_C_plus_plus, 0}};
396396
case DW_LANG_C_plus_plus_03:

llvm/unittests/BinaryFormat/DwarfTest.cpp

Lines changed: 181 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -255,41 +255,186 @@ TEST(DwarfTest, lname_SourceLanguageNameString) {
255255
#include "llvm/BinaryFormat/Dwarf.def"
256256
}
257257

258-
TEST(DWARFDebugInfo, TestLanguageDescription_Versioned) {
259-
// Tests for the llvm::dwarf::LanguageDescription API that
260-
// takes a name *and* a version.
261-
262-
// Unknown language.
263-
EXPECT_EQ(
264-
llvm::dwarf::LanguageDescription(static_cast<SourceLanguageName>(0)),
265-
"Unknown");
266-
267-
EXPECT_EQ(
268-
llvm::dwarf::LanguageDescription(static_cast<SourceLanguageName>(0), 0),
269-
"Unknown");
270-
271-
// Test that specifying an invalid version falls back to a valid language name
272-
// regardless.
273-
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_ObjC, 0), "Objective C");
274-
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_Julia, 0), "Julia");
275-
276-
// Check some versions.
277-
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 199711),
278-
"C++98");
279-
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 201402),
280-
"C++14");
281-
282-
// Versions round up.
283-
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 201400),
284-
"C++14");
285-
286-
// Version 0 for C and C++ is an unversioned name.
287-
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C, 0), "C (K&R and ISO)");
288-
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 0),
289-
"ISO C++");
290-
291-
// Version 0 for other versioned languages may not be the unversioned name.
292-
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_Fortran, 0),
293-
"FORTRAN 77");
258+
struct LanguageDescriptionTestCase {
259+
llvm::dwarf::SourceLanguageName LName;
260+
uint32_t LVersion;
261+
llvm::StringRef ExpectedDescription;
262+
};
263+
264+
LanguageDescriptionTestCase LanguageDescriptionTestCases[] = {
265+
{static_cast<SourceLanguageName>(0), 0, "Unknown"},
266+
{static_cast<SourceLanguageName>(0), 1, "Unknown"},
267+
{DW_LNAME_Ada, 0, "Ada 83"},
268+
{DW_LNAME_Ada, 1982, "Ada 83"},
269+
{DW_LNAME_Ada, 1983, "Ada 83"},
270+
{DW_LNAME_Ada, 1994, "Ada 95"},
271+
{DW_LNAME_Ada, 1995, "Ada 95"},
272+
{DW_LNAME_Ada, 2004, "Ada 2005"},
273+
{DW_LNAME_Ada, 2005, "Ada 2005"},
274+
{DW_LNAME_Ada, 2011, "Ada 2012"},
275+
{DW_LNAME_Ada, 2012, "Ada 2012"},
276+
{DW_LNAME_Ada, 2013, "ISO Ada"},
277+
{DW_LNAME_Cobol, 0, "COBOL-74"},
278+
{DW_LNAME_Cobol, 1973, "COBOL-74"},
279+
{DW_LNAME_Cobol, 1974, "COBOL-74"},
280+
{DW_LNAME_Cobol, 1984, "COBOL-85"},
281+
{DW_LNAME_Cobol, 1985, "COBOL-85"},
282+
{DW_LNAME_Cobol, 1986, "ISO Cobol"},
283+
{DW_LNAME_Fortran, 0, "FORTRAN 77"},
284+
{DW_LNAME_Fortran, 1976, "FORTRAN 77"},
285+
{DW_LNAME_Fortran, 1977, "FORTRAN 77"},
286+
{DW_LNAME_Fortran, 1989, "FORTRAN 90"},
287+
{DW_LNAME_Fortran, 1990, "FORTRAN 90"},
288+
{DW_LNAME_Fortran, 1994, "Fortran 95"},
289+
{DW_LNAME_Fortran, 1995, "Fortran 95"},
290+
{DW_LNAME_Fortran, 2002, "Fortran 2003"},
291+
{DW_LNAME_Fortran, 2003, "Fortran 2003"},
292+
{DW_LNAME_Fortran, 2007, "Fortran 2008"},
293+
{DW_LNAME_Fortran, 2008, "Fortran 2008"},
294+
{DW_LNAME_Fortran, 2017, "Fortran 2018"},
295+
{DW_LNAME_Fortran, 2018, "Fortran 2018"},
296+
{DW_LNAME_Fortran, 2019, "ISO Fortran"},
297+
{DW_LNAME_C, 0, "C (K&R and ISO)"},
298+
{DW_LNAME_C, 198911, "C89"},
299+
{DW_LNAME_C, 198912, "C89"},
300+
{DW_LNAME_C, 199901, "C99"},
301+
{DW_LNAME_C, 199902, "C11"},
302+
{DW_LNAME_C, 201111, "C11"},
303+
{DW_LNAME_C, 201112, "C11"},
304+
{DW_LNAME_C, 201201, "C17"},
305+
{DW_LNAME_C, 201709, "C17"},
306+
{DW_LNAME_C, 201710, "C17"},
307+
{DW_LNAME_C, 201711, "C (K&R and ISO)"},
308+
{DW_LNAME_C_plus_plus, 0, "ISO C++"},
309+
{DW_LNAME_C_plus_plus, 199710, "C++98"},
310+
{DW_LNAME_C_plus_plus, 199711, "C++98"},
311+
{DW_LNAME_C_plus_plus, 199712, "C++03"},
312+
{DW_LNAME_C_plus_plus, 200310, "C++03"},
313+
{DW_LNAME_C_plus_plus, 200311, "C++11"},
314+
{DW_LNAME_C_plus_plus, 201102, "C++11"},
315+
{DW_LNAME_C_plus_plus, 201103, "C++11"},
316+
{DW_LNAME_C_plus_plus, 201104, "C++14"},
317+
{DW_LNAME_C_plus_plus, 201401, "C++14"},
318+
{DW_LNAME_C_plus_plus, 201402, "C++14"},
319+
{DW_LNAME_C_plus_plus, 201403, "C++17"},
320+
{DW_LNAME_C_plus_plus, 201702, "C++17"},
321+
{DW_LNAME_C_plus_plus, 201703, "C++17"},
322+
{DW_LNAME_C_plus_plus, 201704, "C++20"},
323+
{DW_LNAME_C_plus_plus, 202001, "C++20"},
324+
{DW_LNAME_C_plus_plus, 202002, "C++20"},
325+
{DW_LNAME_C_plus_plus, 202003, "ISO C++"},
326+
{DW_LNAME_ObjC_plus_plus, 0, LanguageDescription(DW_LNAME_ObjC_plus_plus)},
327+
{DW_LNAME_ObjC_plus_plus, 1, LanguageDescription(DW_LNAME_ObjC_plus_plus)},
328+
{DW_LNAME_ObjC, 0, LanguageDescription(DW_LNAME_ObjC)},
329+
{DW_LNAME_ObjC, 1, LanguageDescription(DW_LNAME_ObjC)},
330+
{DW_LNAME_Move, 0, LanguageDescription(DW_LNAME_Move)},
331+
{DW_LNAME_Move, 1, LanguageDescription(DW_LNAME_Move)},
332+
{DW_LNAME_SYCL, 0, LanguageDescription(DW_LNAME_SYCL)},
333+
{DW_LNAME_SYCL, 1, LanguageDescription(DW_LNAME_SYCL)},
334+
{DW_LNAME_BLISS, 0, LanguageDescription(DW_LNAME_BLISS)},
335+
{DW_LNAME_BLISS, 1, LanguageDescription(DW_LNAME_BLISS)},
336+
{DW_LNAME_Crystal, 0, LanguageDescription(DW_LNAME_Crystal)},
337+
{DW_LNAME_Crystal, 1, LanguageDescription(DW_LNAME_Crystal)},
338+
{DW_LNAME_D, 0, LanguageDescription(DW_LNAME_D)},
339+
{DW_LNAME_D, 1, LanguageDescription(DW_LNAME_D)},
340+
{DW_LNAME_Dylan, 0, LanguageDescription(DW_LNAME_Dylan)},
341+
{DW_LNAME_Dylan, 1, LanguageDescription(DW_LNAME_Dylan)},
342+
{DW_LNAME_Go, 0, LanguageDescription(DW_LNAME_Go)},
343+
{DW_LNAME_Go, 1, LanguageDescription(DW_LNAME_Go)},
344+
{DW_LNAME_Haskell, 0, LanguageDescription(DW_LNAME_Haskell)},
345+
{DW_LNAME_Haskell, 1, LanguageDescription(DW_LNAME_Haskell)},
346+
{DW_LNAME_HLSL, 0, LanguageDescription(DW_LNAME_HLSL)},
347+
{DW_LNAME_HLSL, 1, LanguageDescription(DW_LNAME_HLSL)},
348+
{DW_LNAME_Java, 0, LanguageDescription(DW_LNAME_Java)},
349+
{DW_LNAME_Java, 1, LanguageDescription(DW_LNAME_Java)},
350+
{DW_LNAME_Julia, 0, LanguageDescription(DW_LNAME_Julia)},
351+
{DW_LNAME_Julia, 1, LanguageDescription(DW_LNAME_Julia)},
352+
{DW_LNAME_Kotlin, 0, LanguageDescription(DW_LNAME_Kotlin)},
353+
{DW_LNAME_Kotlin, 1, LanguageDescription(DW_LNAME_Kotlin)},
354+
{DW_LNAME_Modula2, 0, LanguageDescription(DW_LNAME_Modula2)},
355+
{DW_LNAME_Modula2, 1, LanguageDescription(DW_LNAME_Modula2)},
356+
{DW_LNAME_Modula3, 0, LanguageDescription(DW_LNAME_Modula3)},
357+
{DW_LNAME_Modula3, 1, LanguageDescription(DW_LNAME_Modula3)},
358+
{DW_LNAME_OCaml, 0, LanguageDescription(DW_LNAME_OCaml)},
359+
{DW_LNAME_OCaml, 1, LanguageDescription(DW_LNAME_OCaml)},
360+
{DW_LNAME_OpenCL_C, 0, LanguageDescription(DW_LNAME_OpenCL_C)},
361+
{DW_LNAME_OpenCL_C, 1, LanguageDescription(DW_LNAME_OpenCL_C)},
362+
{DW_LNAME_Pascal, 0, LanguageDescription(DW_LNAME_Pascal)},
363+
{DW_LNAME_Pascal, 1, LanguageDescription(DW_LNAME_Pascal)},
364+
{DW_LNAME_PLI, 0, LanguageDescription(DW_LNAME_PLI)},
365+
{DW_LNAME_PLI, 1, LanguageDescription(DW_LNAME_PLI)},
366+
{DW_LNAME_Python, 0, LanguageDescription(DW_LNAME_Python)},
367+
{DW_LNAME_Python, 1, LanguageDescription(DW_LNAME_Python)},
368+
{DW_LNAME_RenderScript, 0, LanguageDescription(DW_LNAME_RenderScript)},
369+
{DW_LNAME_RenderScript, 1, LanguageDescription(DW_LNAME_RenderScript)},
370+
{DW_LNAME_Rust, 0, LanguageDescription(DW_LNAME_Rust)},
371+
{DW_LNAME_Rust, 1, LanguageDescription(DW_LNAME_Rust)},
372+
{DW_LNAME_Swift, 0, LanguageDescription(DW_LNAME_Swift)},
373+
{DW_LNAME_Swift, 1, LanguageDescription(DW_LNAME_Swift)},
374+
{DW_LNAME_UPC, 0, LanguageDescription(DW_LNAME_UPC)},
375+
{DW_LNAME_UPC, 1, LanguageDescription(DW_LNAME_UPC)},
376+
{DW_LNAME_Zig, 0, LanguageDescription(DW_LNAME_Zig)},
377+
{DW_LNAME_Zig, 1, LanguageDescription(DW_LNAME_Zig)},
378+
{DW_LNAME_Assembly, 0, LanguageDescription(DW_LNAME_Assembly)},
379+
{DW_LNAME_Assembly, 1, LanguageDescription(DW_LNAME_Assembly)},
380+
{DW_LNAME_C_sharp, 0, LanguageDescription(DW_LNAME_C_sharp)},
381+
{DW_LNAME_C_sharp, 1, LanguageDescription(DW_LNAME_C_sharp)},
382+
{DW_LNAME_Mojo, 0, LanguageDescription(DW_LNAME_Mojo)},
383+
{DW_LNAME_Mojo, 1, LanguageDescription(DW_LNAME_Mojo)},
384+
{DW_LNAME_GLSL, 0, LanguageDescription(DW_LNAME_GLSL)},
385+
{DW_LNAME_GLSL, 1, LanguageDescription(DW_LNAME_GLSL)},
386+
{DW_LNAME_GLSL_ES, 0, LanguageDescription(DW_LNAME_GLSL_ES)},
387+
{DW_LNAME_GLSL_ES, 1, LanguageDescription(DW_LNAME_GLSL_ES)},
388+
{DW_LNAME_OpenCL_CPP, 0, LanguageDescription(DW_LNAME_OpenCL_CPP)},
389+
{DW_LNAME_OpenCL_CPP, 1, LanguageDescription(DW_LNAME_OpenCL_CPP)},
390+
{DW_LNAME_CPP_for_OpenCL, 0, LanguageDescription(DW_LNAME_CPP_for_OpenCL)},
391+
{DW_LNAME_CPP_for_OpenCL, 1, LanguageDescription(DW_LNAME_CPP_for_OpenCL)},
392+
{DW_LNAME_Ruby, 0, LanguageDescription(DW_LNAME_Ruby)},
393+
{DW_LNAME_Ruby, 1, LanguageDescription(DW_LNAME_Ruby)},
394+
{DW_LNAME_Hylo, 0, LanguageDescription(DW_LNAME_Hylo)},
395+
{DW_LNAME_Hylo, 1, LanguageDescription(DW_LNAME_Hylo)},
396+
{DW_LNAME_Metal, 0, LanguageDescription(DW_LNAME_Metal)},
397+
{DW_LNAME_Metal, 1, LanguageDescription(DW_LNAME_Metal)}};
398+
399+
struct LanguageDescriptionTestFixture
400+
: public testing::Test,
401+
public testing::WithParamInterface<LanguageDescriptionTestCase> {};
402+
403+
TEST_P(LanguageDescriptionTestFixture, TestLanguageDescription) {
404+
auto [LName, LVersion, ExpectedDescription] = GetParam();
405+
406+
// Basic test.
407+
EXPECT_EQ(llvm::dwarf::LanguageDescription(LName, LVersion),
408+
ExpectedDescription);
409+
410+
// Now do the same test but roundtrip through the DW_LANG_ <-> DW_LNAME_
411+
// conversion APIs first.
412+
413+
auto DWLang = llvm::dwarf::toDW_LANG(LName, LVersion);
414+
// Some languages are not 1-to-1 mapped. In which case there's nothing else
415+
// to test.
416+
if (!DWLang)
417+
return;
418+
419+
std::optional<std::pair<SourceLanguageName, uint32_t>> DWLName =
420+
llvm::dwarf::toDW_LNAME(*DWLang);
421+
422+
// We are roundtripping, so there definitely should be a mapping back to
423+
// DW_LNAME_.
424+
ASSERT_TRUE(DWLName);
425+
426+
// There is no official DW_LANG_ code for C++98. So the roundtripping turns it
427+
// into a plain DW_LANG_C_plus_plus.
428+
if (DWLang == DW_LANG_C_plus_plus && LVersion <= 199711)
429+
EXPECT_EQ(llvm::dwarf::LanguageDescription(DWLName->first, DWLName->second),
430+
"ISO C++");
431+
else
432+
EXPECT_EQ(llvm::dwarf::LanguageDescription(DWLName->first, DWLName->second),
433+
ExpectedDescription);
294434
}
435+
436+
INSTANTIATE_TEST_SUITE_P(LanguageDescriptionTests,
437+
LanguageDescriptionTestFixture,
438+
::testing::ValuesIn(LanguageDescriptionTestCases));
439+
295440
} // end namespace

0 commit comments

Comments
 (0)