|  | //===- unittest/BinaryFormat/DwarfTest.cpp - Dwarf support tests ----------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/BinaryFormat/Dwarf.h" | 
|  | #include "llvm/ADT/StringRef.h" | 
|  | #include "llvm/Support/FormatVariadic.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace llvm::dwarf; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | TEST(DwarfTest, TagStringOnInvalid) { | 
|  | // This is invalid, so it shouldn't be stringified. | 
|  | EXPECT_EQ(StringRef(), TagString(DW_TAG_invalid)); | 
|  |  | 
|  | // These aren't really tags: they describe ranges within tags.  They | 
|  | // shouldn't be stringified either. | 
|  | EXPECT_EQ(StringRef(), TagString(DW_TAG_lo_user)); | 
|  | EXPECT_EQ(StringRef(), TagString(DW_TAG_hi_user)); | 
|  | EXPECT_EQ(StringRef(), TagString(DW_TAG_user_base)); | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, getTag) { | 
|  | // A couple of valid tags. | 
|  | EXPECT_EQ(DW_TAG_array_type, getTag("DW_TAG_array_type")); | 
|  | EXPECT_EQ(DW_TAG_module, getTag("DW_TAG_module")); | 
|  |  | 
|  | // Invalid tags. | 
|  | EXPECT_EQ(DW_TAG_invalid, getTag("DW_TAG_invalid")); | 
|  | EXPECT_EQ(DW_TAG_invalid, getTag("DW_TAG_madeuptag")); | 
|  | EXPECT_EQ(DW_TAG_invalid, getTag("something else")); | 
|  |  | 
|  | // Tag range markers should not be recognized. | 
|  | EXPECT_EQ(DW_TAG_invalid, getTag("DW_TAG_lo_user")); | 
|  | EXPECT_EQ(DW_TAG_invalid, getTag("DW_TAG_hi_user")); | 
|  | EXPECT_EQ(DW_TAG_invalid, getTag("DW_TAG_user_base")); | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, getOperationEncoding) { | 
|  | // Some valid ops. | 
|  | EXPECT_EQ(DW_OP_deref, getOperationEncoding("DW_OP_deref")); | 
|  | EXPECT_EQ(DW_OP_bit_piece, getOperationEncoding("DW_OP_bit_piece")); | 
|  |  | 
|  | // Invalid ops. | 
|  | EXPECT_EQ(0u, getOperationEncoding("DW_OP_otherthings")); | 
|  | EXPECT_EQ(0u, getOperationEncoding("other")); | 
|  |  | 
|  | // Markers shouldn't be recognized. | 
|  | EXPECT_EQ(0u, getOperationEncoding("DW_OP_lo_user")); | 
|  | EXPECT_EQ(0u, getOperationEncoding("DW_OP_hi_user")); | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, LanguageStringOnInvalid) { | 
|  | // This is invalid, so it shouldn't be stringified. | 
|  | EXPECT_EQ(StringRef(), LanguageString(0)); | 
|  |  | 
|  | // These aren't really tags: they describe ranges within tags.  They | 
|  | // shouldn't be stringified either. | 
|  | EXPECT_EQ(StringRef(), LanguageString(DW_LANG_lo_user)); | 
|  | EXPECT_EQ(StringRef(), LanguageString(DW_LANG_hi_user)); | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, getLanguage) { | 
|  | // A couple of valid languages. | 
|  | EXPECT_EQ(DW_LANG_C89, getLanguage("DW_LANG_C89")); | 
|  | EXPECT_EQ(DW_LANG_C_plus_plus_11, getLanguage("DW_LANG_C_plus_plus_11")); | 
|  | EXPECT_EQ(DW_LANG_OCaml, getLanguage("DW_LANG_OCaml")); | 
|  | EXPECT_EQ(DW_LANG_Mips_Assembler, getLanguage("DW_LANG_Mips_Assembler")); | 
|  |  | 
|  | // Invalid languages. | 
|  | EXPECT_EQ(0u, getLanguage("DW_LANG_invalid")); | 
|  | EXPECT_EQ(0u, getLanguage("DW_TAG_array_type")); | 
|  | EXPECT_EQ(0u, getLanguage("something else")); | 
|  |  | 
|  | // Language range markers should not be recognized. | 
|  | EXPECT_EQ(0u, getLanguage("DW_LANG_lo_user")); | 
|  | EXPECT_EQ(0u, getLanguage("DW_LANG_hi_user")); | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, AttributeEncodingStringOnInvalid) { | 
|  | // This is invalid, so it shouldn't be stringified. | 
|  | EXPECT_EQ(StringRef(), AttributeEncodingString(0)); | 
|  |  | 
|  | // These aren't really tags: they describe ranges within tags.  They | 
|  | // shouldn't be stringified either. | 
|  | EXPECT_EQ(StringRef(), AttributeEncodingString(DW_ATE_lo_user)); | 
|  | EXPECT_EQ(StringRef(), AttributeEncodingString(DW_ATE_hi_user)); | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, getAttributeEncoding) { | 
|  | // A couple of valid languages. | 
|  | EXPECT_EQ(DW_ATE_boolean, getAttributeEncoding("DW_ATE_boolean")); | 
|  | EXPECT_EQ(DW_ATE_imaginary_float, | 
|  | getAttributeEncoding("DW_ATE_imaginary_float")); | 
|  |  | 
|  | // Invalid languages. | 
|  | EXPECT_EQ(0u, getAttributeEncoding("DW_ATE_invalid")); | 
|  | EXPECT_EQ(0u, getAttributeEncoding("DW_TAG_array_type")); | 
|  | EXPECT_EQ(0u, getAttributeEncoding("something else")); | 
|  |  | 
|  | // AttributeEncoding range markers should not be recognized. | 
|  | EXPECT_EQ(0u, getAttributeEncoding("DW_ATE_lo_user")); | 
|  | EXPECT_EQ(0u, getAttributeEncoding("DW_ATE_hi_user")); | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, VirtualityString) { | 
|  | EXPECT_EQ(StringRef("DW_VIRTUALITY_none"), | 
|  | VirtualityString(DW_VIRTUALITY_none)); | 
|  | EXPECT_EQ(StringRef("DW_VIRTUALITY_virtual"), | 
|  | VirtualityString(DW_VIRTUALITY_virtual)); | 
|  | EXPECT_EQ(StringRef("DW_VIRTUALITY_pure_virtual"), | 
|  | VirtualityString(DW_VIRTUALITY_pure_virtual)); | 
|  |  | 
|  | // DW_VIRTUALITY_max should be pure virtual. | 
|  | EXPECT_EQ(StringRef("DW_VIRTUALITY_pure_virtual"), | 
|  | VirtualityString(DW_VIRTUALITY_max)); | 
|  |  | 
|  | // Invalid numbers shouldn't be stringified. | 
|  | EXPECT_EQ(StringRef(), VirtualityString(DW_VIRTUALITY_max + 1)); | 
|  | EXPECT_EQ(StringRef(), VirtualityString(DW_VIRTUALITY_max + 77)); | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, getVirtuality) { | 
|  | EXPECT_EQ(DW_VIRTUALITY_none, getVirtuality("DW_VIRTUALITY_none")); | 
|  | EXPECT_EQ(DW_VIRTUALITY_virtual, getVirtuality("DW_VIRTUALITY_virtual")); | 
|  | EXPECT_EQ(DW_VIRTUALITY_pure_virtual, | 
|  | getVirtuality("DW_VIRTUALITY_pure_virtual")); | 
|  |  | 
|  | // Invalid strings. | 
|  | EXPECT_EQ(DW_VIRTUALITY_invalid, getVirtuality("DW_VIRTUALITY_invalid")); | 
|  | EXPECT_EQ(DW_VIRTUALITY_invalid, getVirtuality("DW_VIRTUALITY_max")); | 
|  | EXPECT_EQ(DW_VIRTUALITY_invalid, getVirtuality("something else")); | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, FixedFormSizes) { | 
|  | std::optional<uint8_t> RefSize; | 
|  | std::optional<uint8_t> AddrSize; | 
|  |  | 
|  | // Test 32 bit DWARF version 2 with 4 byte addresses. | 
|  | FormParams Params_2_4_32 = {2, 4, DWARF32}; | 
|  | RefSize = getFixedFormByteSize(DW_FORM_ref_addr, Params_2_4_32); | 
|  | AddrSize = getFixedFormByteSize(DW_FORM_ref_addr, Params_2_4_32); | 
|  | EXPECT_TRUE(RefSize.has_value()); | 
|  | EXPECT_TRUE(AddrSize.has_value()); | 
|  | EXPECT_EQ(*RefSize, *AddrSize); | 
|  |  | 
|  | // Test 32 bit DWARF version 2 with 8 byte addresses. | 
|  | FormParams Params_2_8_32 = {2, 8, DWARF32}; | 
|  | RefSize = getFixedFormByteSize(DW_FORM_ref_addr, Params_2_8_32); | 
|  | AddrSize = getFixedFormByteSize(DW_FORM_ref_addr, Params_2_8_32); | 
|  | EXPECT_TRUE(RefSize.has_value()); | 
|  | EXPECT_TRUE(AddrSize.has_value()); | 
|  | EXPECT_EQ(*RefSize, *AddrSize); | 
|  |  | 
|  | // DW_FORM_ref_addr is 4 bytes in DWARF 32 in DWARF version 3 and beyond. | 
|  | FormParams Params_3_4_32 = {3, 4, DWARF32}; | 
|  | RefSize = getFixedFormByteSize(DW_FORM_ref_addr, Params_3_4_32); | 
|  | EXPECT_TRUE(RefSize.has_value()); | 
|  | EXPECT_EQ(*RefSize, 4); | 
|  |  | 
|  | FormParams Params_4_4_32 = {4, 4, DWARF32}; | 
|  | RefSize = getFixedFormByteSize(DW_FORM_ref_addr, Params_4_4_32); | 
|  | EXPECT_TRUE(RefSize.has_value()); | 
|  | EXPECT_EQ(*RefSize, 4); | 
|  |  | 
|  | FormParams Params_5_4_32 = {5, 4, DWARF32}; | 
|  | RefSize = getFixedFormByteSize(DW_FORM_ref_addr, Params_5_4_32); | 
|  | EXPECT_TRUE(RefSize.has_value()); | 
|  | EXPECT_EQ(*RefSize, 4); | 
|  |  | 
|  | // DW_FORM_ref_addr is 8 bytes in DWARF 64 in DWARF version 3 and beyond. | 
|  | FormParams Params_3_8_64 = {3, 8, DWARF64}; | 
|  | RefSize = getFixedFormByteSize(DW_FORM_ref_addr, Params_3_8_64); | 
|  | EXPECT_TRUE(RefSize.has_value()); | 
|  | EXPECT_EQ(*RefSize, 8); | 
|  |  | 
|  | FormParams Params_4_8_64 = {4, 8, DWARF64}; | 
|  | RefSize = getFixedFormByteSize(DW_FORM_ref_addr, Params_4_8_64); | 
|  | EXPECT_TRUE(RefSize.has_value()); | 
|  | EXPECT_EQ(*RefSize, 8); | 
|  |  | 
|  | FormParams Params_5_8_64 = {5, 8, DWARF64}; | 
|  | RefSize = getFixedFormByteSize(DW_FORM_ref_addr, Params_5_8_64); | 
|  | EXPECT_TRUE(RefSize.has_value()); | 
|  | EXPECT_EQ(*RefSize, 8); | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, format_provider) { | 
|  | EXPECT_EQ("DW_AT_name", formatv("{0}", DW_AT_name).str()); | 
|  | EXPECT_EQ("DW_AT_unknown_3fff", formatv("{0}", DW_AT_hi_user).str()); | 
|  | EXPECT_EQ("DW_FORM_addr", formatv("{0}", DW_FORM_addr).str()); | 
|  | EXPECT_EQ("DW_FORM_unknown_1f00", formatv("{0}", DW_FORM_lo_user).str()); | 
|  | EXPECT_EQ("DW_IDX_compile_unit", formatv("{0}", DW_IDX_compile_unit).str()); | 
|  | EXPECT_EQ("DW_IDX_unknown_3fff", formatv("{0}", DW_IDX_hi_user).str()); | 
|  | EXPECT_EQ("DW_TAG_compile_unit", formatv("{0}", DW_TAG_compile_unit).str()); | 
|  | EXPECT_EQ("DW_TAG_unknown_ffff", formatv("{0}", DW_TAG_hi_user).str()); | 
|  | EXPECT_EQ("DW_OP_lit0", formatv("{0}", DW_OP_lit0).str()); | 
|  | EXPECT_EQ("DW_OP_unknown_ff", formatv("{0}", DW_OP_hi_user).str()); | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, lname) { | 
|  | auto roundtrip = [](llvm::dwarf::SourceLanguage sl) { | 
|  | auto name_version = toDW_LNAME(sl); | 
|  | // Ignore ones without a defined mapping. | 
|  | if (sl == DW_LANG_Mips_Assembler || sl == DW_LANG_GOOGLE_RenderScript || | 
|  | !name_version.has_value()) | 
|  | return sl; | 
|  | return dwarf::toDW_LANG(name_version->first, name_version->second) | 
|  | .value_or(sl); | 
|  | }; | 
|  | #define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR)                 \ | 
|  | EXPECT_EQ(roundtrip(DW_LANG_##NAME), DW_LANG_##NAME); | 
|  | #include "llvm/BinaryFormat/Dwarf.def" | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, lname_getSourceLanguageName) { | 
|  | // Some basics. | 
|  | EXPECT_EQ(getSourceLanguageName("DW_LNAME_Ada"), DW_LNAME_Ada); | 
|  | EXPECT_EQ(getSourceLanguageName("DW_LNAME_Metal"), DW_LNAME_Metal); | 
|  |  | 
|  | // Test invalid input. | 
|  | EXPECT_EQ(getSourceLanguageName(""), 0U); | 
|  | EXPECT_EQ(getSourceLanguageName("blah"), 0U); | 
|  | EXPECT_EQ(getSourceLanguageName("DW_LNAME__something_unlikely"), 0U); | 
|  | EXPECT_EQ(getSourceLanguageName("DW_LANG_C"), 0U); | 
|  |  | 
|  | // Test that we cover all DW_LNAME_ names. | 
|  | #define xstr(X) #X | 
|  | #define HANDLE_DW_LNAME(ID, NAME, DESC, LOWER_BOUND)                           \ | 
|  | EXPECT_EQ(getSourceLanguageName(xstr(DW_LNAME_##NAME)), DW_LNAME_##NAME); | 
|  | #include "llvm/BinaryFormat/Dwarf.def" | 
|  | } | 
|  |  | 
|  | TEST(DwarfTest, lname_SourceLanguageNameString) { | 
|  | // Some basics. | 
|  | EXPECT_EQ(SourceLanguageNameString(DW_LNAME_C_plus_plus), | 
|  | "DW_LNAME_C_plus_plus"); | 
|  | EXPECT_EQ(SourceLanguageNameString(DW_LNAME_CPP_for_OpenCL), | 
|  | "DW_LNAME_CPP_for_OpenCL"); | 
|  |  | 
|  | // Test invalid input. | 
|  | EXPECT_EQ(SourceLanguageNameString(static_cast<SourceLanguageName>(0)), ""); | 
|  |  | 
|  | // Test that we cover all DW_LNAME_ names. | 
|  | #define xstr(X) #X | 
|  | #define HANDLE_DW_LNAME(ID, NAME, DESC, LOWER_BOUND)                           \ | 
|  | EXPECT_EQ(SourceLanguageNameString(DW_LNAME_##NAME), xstr(DW_LNAME_##NAME)); | 
|  | #include "llvm/BinaryFormat/Dwarf.def" | 
|  | } | 
|  |  | 
|  | struct LanguageDescriptionTestCase { | 
|  | llvm::dwarf::SourceLanguageName LName; | 
|  | uint32_t LVersion; | 
|  | llvm::StringRef ExpectedDescription; | 
|  | }; | 
|  |  | 
|  | LanguageDescriptionTestCase LanguageDescriptionTestCases[] = { | 
|  | {static_cast<SourceLanguageName>(0), 0, "Unknown"}, | 
|  | {static_cast<SourceLanguageName>(0), 1, "Unknown"}, | 
|  | {DW_LNAME_Ada, 0, "Ada 83"}, | 
|  | {DW_LNAME_Ada, 1982, "Ada 83"}, | 
|  | {DW_LNAME_Ada, 1983, "Ada 83"}, | 
|  | {DW_LNAME_Ada, 1994, "Ada 95"}, | 
|  | {DW_LNAME_Ada, 1995, "Ada 95"}, | 
|  | {DW_LNAME_Ada, 2004, "Ada 2005"}, | 
|  | {DW_LNAME_Ada, 2005, "Ada 2005"}, | 
|  | {DW_LNAME_Ada, 2011, "Ada 2012"}, | 
|  | {DW_LNAME_Ada, 2012, "Ada 2012"}, | 
|  | {DW_LNAME_Ada, 2013, "ISO Ada"}, | 
|  | {DW_LNAME_Cobol, 0, "COBOL-74"}, | 
|  | {DW_LNAME_Cobol, 1973, "COBOL-74"}, | 
|  | {DW_LNAME_Cobol, 1974, "COBOL-74"}, | 
|  | {DW_LNAME_Cobol, 1984, "COBOL-85"}, | 
|  | {DW_LNAME_Cobol, 1985, "COBOL-85"}, | 
|  | {DW_LNAME_Cobol, 1986, "ISO Cobol"}, | 
|  | {DW_LNAME_Fortran, 0, "FORTRAN 77"}, | 
|  | {DW_LNAME_Fortran, 1976, "FORTRAN 77"}, | 
|  | {DW_LNAME_Fortran, 1977, "FORTRAN 77"}, | 
|  | {DW_LNAME_Fortran, 1989, "FORTRAN 90"}, | 
|  | {DW_LNAME_Fortran, 1990, "FORTRAN 90"}, | 
|  | {DW_LNAME_Fortran, 1994, "Fortran 95"}, | 
|  | {DW_LNAME_Fortran, 1995, "Fortran 95"}, | 
|  | {DW_LNAME_Fortran, 2002, "Fortran 2003"}, | 
|  | {DW_LNAME_Fortran, 2003, "Fortran 2003"}, | 
|  | {DW_LNAME_Fortran, 2007, "Fortran 2008"}, | 
|  | {DW_LNAME_Fortran, 2008, "Fortran 2008"}, | 
|  | {DW_LNAME_Fortran, 2017, "Fortran 2018"}, | 
|  | {DW_LNAME_Fortran, 2018, "Fortran 2018"}, | 
|  | {DW_LNAME_Fortran, 2019, "ISO Fortran"}, | 
|  | {DW_LNAME_C, 0, "C (K&R and ISO)"}, | 
|  | {DW_LNAME_C, 198911, "C89"}, | 
|  | {DW_LNAME_C, 198912, "C89"}, | 
|  | {DW_LNAME_C, 199901, "C99"}, | 
|  | {DW_LNAME_C, 199902, "C11"}, | 
|  | {DW_LNAME_C, 201111, "C11"}, | 
|  | {DW_LNAME_C, 201112, "C11"}, | 
|  | {DW_LNAME_C, 201201, "C17"}, | 
|  | {DW_LNAME_C, 201709, "C17"}, | 
|  | {DW_LNAME_C, 201710, "C17"}, | 
|  | {DW_LNAME_C, 201711, "C (K&R and ISO)"}, | 
|  | {DW_LNAME_C_plus_plus, 0, "ISO C++"}, | 
|  | {DW_LNAME_C_plus_plus, 199710, "C++98"}, | 
|  | {DW_LNAME_C_plus_plus, 199711, "C++98"}, | 
|  | {DW_LNAME_C_plus_plus, 199712, "C++03"}, | 
|  | {DW_LNAME_C_plus_plus, 200310, "C++03"}, | 
|  | {DW_LNAME_C_plus_plus, 200311, "C++11"}, | 
|  | {DW_LNAME_C_plus_plus, 201102, "C++11"}, | 
|  | {DW_LNAME_C_plus_plus, 201103, "C++11"}, | 
|  | {DW_LNAME_C_plus_plus, 201104, "C++14"}, | 
|  | {DW_LNAME_C_plus_plus, 201401, "C++14"}, | 
|  | {DW_LNAME_C_plus_plus, 201402, "C++14"}, | 
|  | {DW_LNAME_C_plus_plus, 201403, "C++17"}, | 
|  | {DW_LNAME_C_plus_plus, 201702, "C++17"}, | 
|  | {DW_LNAME_C_plus_plus, 201703, "C++17"}, | 
|  | {DW_LNAME_C_plus_plus, 201704, "C++20"}, | 
|  | {DW_LNAME_C_plus_plus, 202001, "C++20"}, | 
|  | {DW_LNAME_C_plus_plus, 202002, "C++20"}, | 
|  | {DW_LNAME_C_plus_plus, 202003, "ISO C++"}, | 
|  | {DW_LNAME_ObjC_plus_plus, 0, LanguageDescription(DW_LNAME_ObjC_plus_plus)}, | 
|  | {DW_LNAME_ObjC_plus_plus, 1, LanguageDescription(DW_LNAME_ObjC_plus_plus)}, | 
|  | {DW_LNAME_ObjC, 0, LanguageDescription(DW_LNAME_ObjC)}, | 
|  | {DW_LNAME_ObjC, 1, LanguageDescription(DW_LNAME_ObjC)}, | 
|  | {DW_LNAME_Move, 0, LanguageDescription(DW_LNAME_Move)}, | 
|  | {DW_LNAME_Move, 1, LanguageDescription(DW_LNAME_Move)}, | 
|  | {DW_LNAME_SYCL, 0, LanguageDescription(DW_LNAME_SYCL)}, | 
|  | {DW_LNAME_SYCL, 1, LanguageDescription(DW_LNAME_SYCL)}, | 
|  | {DW_LNAME_BLISS, 0, LanguageDescription(DW_LNAME_BLISS)}, | 
|  | {DW_LNAME_BLISS, 1, LanguageDescription(DW_LNAME_BLISS)}, | 
|  | {DW_LNAME_Crystal, 0, LanguageDescription(DW_LNAME_Crystal)}, | 
|  | {DW_LNAME_Crystal, 1, LanguageDescription(DW_LNAME_Crystal)}, | 
|  | {DW_LNAME_D, 0, LanguageDescription(DW_LNAME_D)}, | 
|  | {DW_LNAME_D, 1, LanguageDescription(DW_LNAME_D)}, | 
|  | {DW_LNAME_Dylan, 0, LanguageDescription(DW_LNAME_Dylan)}, | 
|  | {DW_LNAME_Dylan, 1, LanguageDescription(DW_LNAME_Dylan)}, | 
|  | {DW_LNAME_Go, 0, LanguageDescription(DW_LNAME_Go)}, | 
|  | {DW_LNAME_Go, 1, LanguageDescription(DW_LNAME_Go)}, | 
|  | {DW_LNAME_Haskell, 0, LanguageDescription(DW_LNAME_Haskell)}, | 
|  | {DW_LNAME_Haskell, 1, LanguageDescription(DW_LNAME_Haskell)}, | 
|  | {DW_LNAME_HLSL, 0, LanguageDescription(DW_LNAME_HLSL)}, | 
|  | {DW_LNAME_HLSL, 1, LanguageDescription(DW_LNAME_HLSL)}, | 
|  | {DW_LNAME_Java, 0, LanguageDescription(DW_LNAME_Java)}, | 
|  | {DW_LNAME_Java, 1, LanguageDescription(DW_LNAME_Java)}, | 
|  | {DW_LNAME_Julia, 0, LanguageDescription(DW_LNAME_Julia)}, | 
|  | {DW_LNAME_Julia, 1, LanguageDescription(DW_LNAME_Julia)}, | 
|  | {DW_LNAME_Kotlin, 0, LanguageDescription(DW_LNAME_Kotlin)}, | 
|  | {DW_LNAME_Kotlin, 1, LanguageDescription(DW_LNAME_Kotlin)}, | 
|  | {DW_LNAME_Modula2, 0, LanguageDescription(DW_LNAME_Modula2)}, | 
|  | {DW_LNAME_Modula2, 1, LanguageDescription(DW_LNAME_Modula2)}, | 
|  | {DW_LNAME_Modula3, 0, LanguageDescription(DW_LNAME_Modula3)}, | 
|  | {DW_LNAME_Modula3, 1, LanguageDescription(DW_LNAME_Modula3)}, | 
|  | {DW_LNAME_OCaml, 0, LanguageDescription(DW_LNAME_OCaml)}, | 
|  | {DW_LNAME_OCaml, 1, LanguageDescription(DW_LNAME_OCaml)}, | 
|  | {DW_LNAME_OpenCL_C, 0, LanguageDescription(DW_LNAME_OpenCL_C)}, | 
|  | {DW_LNAME_OpenCL_C, 1, LanguageDescription(DW_LNAME_OpenCL_C)}, | 
|  | {DW_LNAME_Pascal, 0, LanguageDescription(DW_LNAME_Pascal)}, | 
|  | {DW_LNAME_Pascal, 1, LanguageDescription(DW_LNAME_Pascal)}, | 
|  | {DW_LNAME_PLI, 0, LanguageDescription(DW_LNAME_PLI)}, | 
|  | {DW_LNAME_PLI, 1, LanguageDescription(DW_LNAME_PLI)}, | 
|  | {DW_LNAME_Python, 0, LanguageDescription(DW_LNAME_Python)}, | 
|  | {DW_LNAME_Python, 1, LanguageDescription(DW_LNAME_Python)}, | 
|  | {DW_LNAME_RenderScript, 0, LanguageDescription(DW_LNAME_RenderScript)}, | 
|  | {DW_LNAME_RenderScript, 1, LanguageDescription(DW_LNAME_RenderScript)}, | 
|  | {DW_LNAME_Rust, 0, LanguageDescription(DW_LNAME_Rust)}, | 
|  | {DW_LNAME_Rust, 1, LanguageDescription(DW_LNAME_Rust)}, | 
|  | {DW_LNAME_Swift, 0, LanguageDescription(DW_LNAME_Swift)}, | 
|  | {DW_LNAME_Swift, 1, LanguageDescription(DW_LNAME_Swift)}, | 
|  | {DW_LNAME_UPC, 0, LanguageDescription(DW_LNAME_UPC)}, | 
|  | {DW_LNAME_UPC, 1, LanguageDescription(DW_LNAME_UPC)}, | 
|  | {DW_LNAME_Zig, 0, LanguageDescription(DW_LNAME_Zig)}, | 
|  | {DW_LNAME_Zig, 1, LanguageDescription(DW_LNAME_Zig)}, | 
|  | {DW_LNAME_Assembly, 0, LanguageDescription(DW_LNAME_Assembly)}, | 
|  | {DW_LNAME_Assembly, 1, LanguageDescription(DW_LNAME_Assembly)}, | 
|  | {DW_LNAME_C_sharp, 0, LanguageDescription(DW_LNAME_C_sharp)}, | 
|  | {DW_LNAME_C_sharp, 1, LanguageDescription(DW_LNAME_C_sharp)}, | 
|  | {DW_LNAME_Mojo, 0, LanguageDescription(DW_LNAME_Mojo)}, | 
|  | {DW_LNAME_Mojo, 1, LanguageDescription(DW_LNAME_Mojo)}, | 
|  | {DW_LNAME_GLSL, 0, LanguageDescription(DW_LNAME_GLSL)}, | 
|  | {DW_LNAME_GLSL, 1, LanguageDescription(DW_LNAME_GLSL)}, | 
|  | {DW_LNAME_GLSL_ES, 0, LanguageDescription(DW_LNAME_GLSL_ES)}, | 
|  | {DW_LNAME_GLSL_ES, 1, LanguageDescription(DW_LNAME_GLSL_ES)}, | 
|  | {DW_LNAME_OpenCL_CPP, 0, LanguageDescription(DW_LNAME_OpenCL_CPP)}, | 
|  | {DW_LNAME_OpenCL_CPP, 1, LanguageDescription(DW_LNAME_OpenCL_CPP)}, | 
|  | {DW_LNAME_CPP_for_OpenCL, 0, LanguageDescription(DW_LNAME_CPP_for_OpenCL)}, | 
|  | {DW_LNAME_CPP_for_OpenCL, 1, LanguageDescription(DW_LNAME_CPP_for_OpenCL)}, | 
|  | {DW_LNAME_Ruby, 0, LanguageDescription(DW_LNAME_Ruby)}, | 
|  | {DW_LNAME_Ruby, 1, LanguageDescription(DW_LNAME_Ruby)}, | 
|  | {DW_LNAME_Hylo, 0, LanguageDescription(DW_LNAME_Hylo)}, | 
|  | {DW_LNAME_Hylo, 1, LanguageDescription(DW_LNAME_Hylo)}, | 
|  | {DW_LNAME_Metal, 0, LanguageDescription(DW_LNAME_Metal)}, | 
|  | {DW_LNAME_Metal, 1, LanguageDescription(DW_LNAME_Metal)}}; | 
|  |  | 
|  | struct LanguageDescriptionTestFixture | 
|  | : public testing::Test, | 
|  | public testing::WithParamInterface<LanguageDescriptionTestCase> {}; | 
|  |  | 
|  | TEST_P(LanguageDescriptionTestFixture, TestLanguageDescription) { | 
|  | auto [LName, LVersion, ExpectedDescription] = GetParam(); | 
|  |  | 
|  | // Basic test. | 
|  | EXPECT_EQ(llvm::dwarf::LanguageDescription(LName, LVersion), | 
|  | ExpectedDescription); | 
|  |  | 
|  | // Now do the same test but roundtrip through the DW_LANG_ <-> DW_LNAME_ | 
|  | // conversion APIs first. | 
|  |  | 
|  | auto DWLang = llvm::dwarf::toDW_LANG(LName, LVersion); | 
|  | // Some languages are not 1-to-1 mapped. In which case there's nothing else | 
|  | // to test. | 
|  | if (!DWLang) | 
|  | return; | 
|  |  | 
|  | std::optional<std::pair<SourceLanguageName, uint32_t>> DWLName = | 
|  | llvm::dwarf::toDW_LNAME(*DWLang); | 
|  |  | 
|  | // We are roundtripping, so there definitely should be a mapping back to | 
|  | // DW_LNAME_. | 
|  | ASSERT_TRUE(DWLName); | 
|  |  | 
|  | // There is no official DW_LANG_ code for C++98. So the roundtripping turns it | 
|  | // into a plain DW_LANG_C_plus_plus. | 
|  | if (DWLang == DW_LANG_C_plus_plus && LVersion <= 199711) | 
|  | EXPECT_EQ(llvm::dwarf::LanguageDescription(DWLName->first, DWLName->second), | 
|  | "ISO C++"); | 
|  | else | 
|  | EXPECT_EQ(llvm::dwarf::LanguageDescription(DWLName->first, DWLName->second), | 
|  | ExpectedDescription); | 
|  | } | 
|  |  | 
|  | INSTANTIATE_TEST_SUITE_P(LanguageDescriptionTests, | 
|  | LanguageDescriptionTestFixture, | 
|  | ::testing::ValuesIn(LanguageDescriptionTestCases)); | 
|  |  | 
|  | } // end namespace |