diff --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst index 1264f80206618..956a54e93f93e 100644 --- a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst +++ b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst @@ -365,6 +365,7 @@ output for a single compilation unit. .. code-block:: text + =none: Unsorted output. =kind: Sort by element kind. =line: Sort by element line number. =name: Sort by element name. diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h index eea06cfb99ba2..d2010e663ebed 100644 --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -1032,13 +1032,22 @@ class concat_iterator static constexpr bool ReturnsByValue = !(std::is_reference_v())> && ...); + static constexpr bool ReturnsConvertiblePointer = + std::is_pointer_v && + (std::is_convertible_v()), ValueT> && ...); using reference_type = - typename std::conditional_t; - - using handle_type = - typename std::conditional_t, - ValueT *>; + typename std::conditional_t; + + using optional_value_type = + std::conditional_t, ValueT *>; + // handle_type is used to return an optional value from `getHelper()`. If + // the type resulting from dereferencing all IterTs is a pointer that can be + // converted to `ValueT`, use that pointer type instead to avoid implicit + // conversion issues. + using handle_type = typename std::conditional_t; /// We store both the current and end iterators for each concatenated /// sequence in a tuple of pairs. @@ -1088,7 +1097,7 @@ class concat_iterator if (Begin == End) return {}; - if constexpr (ReturnsByValue) + if constexpr (ReturnsByValue || ReturnsConvertiblePointer) return *Begin; else return &*Begin; @@ -1105,8 +1114,12 @@ class concat_iterator // Loop over them, and return the first result we find. for (auto &GetHelperFn : GetHelperFns) - if (auto P = (this->*GetHelperFn)()) - return *P; + if (auto P = (this->*GetHelperFn)()) { + if constexpr (ReturnsConvertiblePointer) + return P; + else + return *P; + } llvm_unreachable("Attempted to get a pointer from an end concat iterator!"); } diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h index a453923d032e4..23ca291a00bbc 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h @@ -14,6 +14,7 @@ #ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSCOPE_H #define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSCOPE_H +#include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/LogicalView/Core/LVElement.h" #include "llvm/DebugInfo/LogicalView/Core/LVLocation.h" #include "llvm/DebugInfo/LogicalView/Core/LVSort.h" @@ -94,6 +95,11 @@ class LLVM_ABI LVScope : public LVElement { LVProperties Kinds; LVProperties Properties; static LVScopeDispatch Dispatch; + // Empty containers used in `getChildren()` in case there is no Types, + // Symbols, or Scopes. + static const LVTypes EmptyTypes; + static const LVSymbols EmptySymbols; + static const LVScopes EmptyScopes; // Size in bits if this scope represents also a compound type. uint32_t BitSize = 0; @@ -128,14 +134,6 @@ class LLVM_ABI LVScope : public LVElement { std::unique_ptr Lines; std::unique_ptr Ranges; - // Vector of elements (types, scopes and symbols). - // It is the union of (*Types, *Symbols and *Scopes) to be used for - // the following reasons: - // - Preserve the order the logical elements are read in. - // - To have a single container with all the logical elements, when - // the traversal does not require any specific element kind. - std::unique_ptr Children; - // Resolve the template parameters/arguments relationship. void resolveTemplate(); void printEncodedArgs(raw_ostream &OS, bool Full) const; @@ -213,7 +211,14 @@ class LLVM_ABI LVScope : public LVElement { const LVScopes *getScopes() const { return Scopes.get(); } const LVSymbols *getSymbols() const { return Symbols.get(); } const LVTypes *getTypes() const { return Types.get(); } - const LVElements *getChildren() const { return Children.get(); } + // Return view over union of child Types, Symbols, and Scopes. + auto getUnsortedChildren() const { + return llvm::concat(Scopes ? *Scopes : EmptyScopes, + Types ? *Types : EmptyTypes, + Symbols ? *Symbols : EmptySymbols); + } + // Return sorted children (see `LVOptions::setSortMode()`). + LVElements getChildren() const; void addElement(LVElement *Element); void addElement(LVLine *Line); @@ -222,7 +227,6 @@ class LLVM_ABI LVScope : public LVElement { void addElement(LVType *Type); void addObject(LVLocation *Location); void addObject(LVAddress LowerAddress, LVAddress UpperAddress); - void addToChildren(LVElement *Element); // Add the missing elements from the given 'Reference', which is the // scope associated with any DW_AT_specification, DW_AT_abstract_origin. diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h index c8c7310281566..e92fd809d4aeb 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h @@ -46,6 +46,7 @@ LLVM_ABI LVSortValue compareRange(const LVObject *LHS, const LVObject *RHS); LLVM_ABI LVSortValue sortByKind(const LVObject *LHS, const LVObject *RHS); LLVM_ABI LVSortValue sortByLine(const LVObject *LHS, const LVObject *RHS); LLVM_ABI LVSortValue sortByName(const LVObject *LHS, const LVObject *RHS); +LLVM_ABI LVSortValue sortByOffset(const LVObject *LHS, const LVObject *RHS); } // end namespace logicalview } // end namespace llvm diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp index 55880fab5e88e..a36315b2c513d 100644 --- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp @@ -107,10 +107,23 @@ LVScopeDispatch LVScope::Dispatch = { {LVScopeKind::IsTryBlock, &LVScope::getIsTryBlock}, {LVScopeKind::IsUnion, &LVScope::getIsUnion}}; -void LVScope::addToChildren(LVElement *Element) { - if (!Children) - Children = std::make_unique(); - Children->push_back(Element); +const LVTypes LVScope::EmptyTypes{}; +const LVSymbols LVScope::EmptySymbols{}; +const LVScopes LVScope::EmptyScopes{}; + +LVElements LVScope::getChildren() const { + const auto UnsortedChildren = getUnsortedChildren(); + LVElements Elements{UnsortedChildren.begin(), UnsortedChildren.end()}; + if (LVSortFunction SortFunction = getSortFunction()) { + llvm::stable_sort(Elements, SortFunction); + } else { + // No specific sort function, sort by `LVObject::ID` which replicates the + // order in which the elements were created. + llvm::stable_sort(Elements, [](const LVObject *LHS, const LVObject *RHS) { + return LHS->getID() < RHS->getID(); + }); + } + return Elements; } void LVScope::addElement(LVElement *Element) { @@ -175,7 +188,6 @@ void LVScope::addElement(LVScope *Scope) { // Add it to parent. Scopes->push_back(Scope); - addToChildren(Scope); Scope->setParent(this); // Notify the reader about the new element being added. @@ -202,7 +214,6 @@ void LVScope::addElement(LVSymbol *Symbol) { // Add it to parent. Symbols->push_back(Symbol); - addToChildren(Symbol); Symbol->setParent(this); // Notify the reader about the new element being added. @@ -229,7 +240,6 @@ void LVScope::addElement(LVType *Type) { // Add it to parent. Types->push_back(Type); - addToChildren(Type); Type->setParent(this); // Notify the reader about the new element being added. @@ -277,15 +287,12 @@ bool LVScope::removeElement(LVElement *Element) { if (Element->getIsLine()) return RemoveElement(Lines); - if (RemoveElement(Children)) { - if (Element->getIsSymbol()) - return RemoveElement(Symbols); - if (Element->getIsType()) - return RemoveElement(Types); - if (Element->getIsScope()) - return RemoveElement(Scopes); - llvm_unreachable("Invalid element."); - } + if (Element->getIsSymbol()) + return RemoveElement(Symbols); + if (Element->getIsType()) + return RemoveElement(Types); + if (Element->getIsScope()) + return RemoveElement(Scopes); return false; } @@ -356,9 +363,8 @@ void LVScope::updateLevel(LVScope *Parent, bool Moved) { setLevel(Parent->getLevel() + 1); // Update the children. - if (Children) - for (LVElement *Element : *Children) - Element->updateLevel(this, Moved); + for (LVElement *Element : getUnsortedChildren()) + Element->updateLevel(this, Moved); // Update any lines. if (Lines) @@ -374,13 +380,12 @@ void LVScope::resolve() { LVElement::resolve(); // Resolve the children. - if (Children) - for (LVElement *Element : *Children) { - if (getIsGlobalReference()) - // If the scope is a global reference, mark all its children as well. - Element->setIsGlobalReference(); - Element->resolve(); - } + for (LVElement *Element : getUnsortedChildren()) { + if (getIsGlobalReference()) + // If the scope is a global reference, mark all its children as well. + Element->setIsGlobalReference(); + Element->resolve(); + } } void LVScope::resolveName() { @@ -633,14 +638,13 @@ Error LVScope::doPrint(bool Split, bool Match, bool Print, raw_ostream &OS, options().getPrintFormatting() && getLevel() < options().getOutputLevel()) { // Print the children. - if (Children) - for (const LVElement *Element : *Children) { - if (Match && !Element->getHasPattern()) - continue; - if (Error Err = - Element->doPrint(Split, Match, Print, *StreamSplit, Full)) - return Err; - } + for (const LVElement *Element : getChildren()) { + if (Match && !Element->getHasPattern()) + continue; + if (Error Err = + Element->doPrint(Split, Match, Print, *StreamSplit, Full)) + return Err; + } // Print the line records. if (Lines) @@ -692,7 +696,6 @@ void LVScope::sort() { Traverse(Parent->Symbols, SortFunction); Traverse(Parent->Scopes, SortFunction); Traverse(Parent->Ranges, compareRange); - Traverse(Parent->Children, SortFunction); if (Parent->Scopes) for (LVScope *Scope : *Parent->Scopes) @@ -978,9 +981,8 @@ bool LVScope::equals(const LVScopes *References, const LVScopes *Targets) { void LVScope::report(LVComparePass Pass) { getComparator().printItem(this, Pass); getComparator().push(this); - if (Children) - for (LVElement *Element : *Children) - Element->report(Pass); + for (LVElement *Element : getChildren()) + Element->report(Pass); if (Lines) for (LVLine *Line : *Lines) @@ -1656,9 +1658,8 @@ void LVScopeCompileUnit::printMatchedElements(raw_ostream &OS, // Print the view for the matched scopes. for (const LVScope *Scope : MatchedScopes) { Scope->print(OS); - if (const LVElements *Elements = Scope->getChildren()) - for (LVElement *Element : *Elements) - Element->print(OS); + for (LVElement *Element : Scope->getChildren()) + Element->print(OS); } } diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp index a58ba4b3cdfbf..1ed951a2f4eed 100644 --- a/llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp @@ -64,11 +64,13 @@ LVSortValue llvm::logicalview::compareRange(const LVObject *LHS, LVSortValue llvm::logicalview::sortByKind(const LVObject *LHS, const LVObject *RHS) { // Order in which the object attributes are used for comparison: - // kind, name, line number, offset. - std::tuple Left( - LHS->kind(), LHS->getName(), LHS->getLineNumber(), LHS->getOffset()); - std::tuple Right( - RHS->kind(), RHS->getName(), RHS->getLineNumber(), RHS->getOffset()); + // kind, name, line number, offset, ID. + std::tuple Left( + LHS->kind(), LHS->getName(), LHS->getLineNumber(), LHS->getOffset(), + LHS->getID()); + std::tuple Right( + RHS->kind(), RHS->getName(), RHS->getLineNumber(), RHS->getOffset(), + RHS->getID()); return Left < Right; } @@ -76,11 +78,13 @@ LVSortValue llvm::logicalview::sortByKind(const LVObject *LHS, LVSortValue llvm::logicalview::sortByLine(const LVObject *LHS, const LVObject *RHS) { // Order in which the object attributes are used for comparison: - // line number, name, kind, offset. - std::tuple Left( - LHS->getLineNumber(), LHS->getName(), LHS->kind(), LHS->getOffset()); - std::tuple Right( - RHS->getLineNumber(), RHS->getName(), RHS->kind(), RHS->getOffset()); + // line number, name, kind, offset, ID. + std::tuple Left( + LHS->getLineNumber(), LHS->getName(), LHS->kind(), LHS->getOffset(), + LHS->getID()); + std::tuple Right( + RHS->getLineNumber(), RHS->getName(), RHS->kind(), RHS->getOffset(), + RHS->getID()); return Left < Right; } @@ -88,20 +92,32 @@ LVSortValue llvm::logicalview::sortByLine(const LVObject *LHS, LVSortValue llvm::logicalview::sortByName(const LVObject *LHS, const LVObject *RHS) { // Order in which the object attributes are used for comparison: - // name, line number, kind, offset. - std::tuple Left( - LHS->getName(), LHS->getLineNumber(), LHS->kind(), LHS->getOffset()); - std::tuple Right( - RHS->getName(), RHS->getLineNumber(), RHS->kind(), RHS->getOffset()); + // name, line number, kind, offset, ID. + std::tuple Left( + LHS->getName(), LHS->getLineNumber(), LHS->kind(), LHS->getOffset(), + LHS->getID()); + std::tuple Right( + RHS->getName(), RHS->getLineNumber(), RHS->kind(), RHS->getOffset(), + RHS->getID()); + return Left < Right; +} + +// Callback comparator based on multiple keys (First: Offset). +LVSortValue llvm::logicalview::sortByOffset(const LVObject *LHS, + const LVObject *RHS) { + // Order in which the object attributes are used for comparison: + // offset, ID. + std::tuple Left(LHS->getOffset(), LHS->getID()); + std::tuple Right(RHS->getOffset(), RHS->getID()); return Left < Right; } LVSortFunction llvm::logicalview::getSortFunction() { using LVSortInfo = std::map; static LVSortInfo SortInfo = { - {LVSortMode::None, nullptr}, {LVSortMode::Kind, sortByKind}, - {LVSortMode::Line, sortByLine}, {LVSortMode::Name, sortByName}, - {LVSortMode::Offset, compareOffset}, + {LVSortMode::None, nullptr}, {LVSortMode::Kind, sortByKind}, + {LVSortMode::Line, sortByLine}, {LVSortMode::Name, sortByName}, + {LVSortMode::Offset, sortByOffset}, }; LVSortFunction SortFunction = nullptr; diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test index a076887140c28..1b790eeb3b691 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test @@ -35,8 +35,8 @@ ; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int' ; ONE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' ; ONE-NEXT: [003] {Block} -; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' ; ONE-NEXT: +[004] 4 {TypeAlias} 'INTEGER' -> 'int' +; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' ; ONE-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool' ; ONE-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' ; ONE-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test index 278d4f4850f5f..78604d9164c0f 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test @@ -55,8 +55,8 @@ ; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int' ; ONE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' ; ONE-NEXT: [003] {Block} -; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' ; ONE-NEXT: +[004] 4 {TypeAlias} 'INTEGER' -> 'int' +; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' ; ONE-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool' ; ONE-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' ; ONE-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test index f52c9c7cc7164..98fc47e3d3c80 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test @@ -38,8 +38,8 @@ ; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int' ; ONE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' ; ONE-NEXT: [003] {Block} -; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' ; ONE-NEXT: +[004] 4 {TypeAlias} 'INTEGER' -> 'int' +; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' ; ONE-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool' ; ONE-NEXT: [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' ; ONE-NEXT: [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' diff --git a/llvm/tools/llvm-debuginfo-analyzer/Options.cpp b/llvm/tools/llvm-debuginfo-analyzer/Options.cpp index 79e2edccc50b8..b7e337bc21c61 100644 --- a/llvm/tools/llvm-debuginfo-analyzer/Options.cpp +++ b/llvm/tools/llvm-debuginfo-analyzer/Options.cpp @@ -198,7 +198,9 @@ static cl::opt OutputSort( "output-sort", cl::cat(OutputCategory), cl::desc("Primary key when ordering logical view (default: line)."), cl::Hidden, cl::ZeroOrMore, - values(clEnumValN(LVSortMode::Kind, "kind", "Sort by element kind."), + values(clEnumValN(LVSortMode::None, "none", + "Unsorted output (i.e. as read from input)."), + clEnumValN(LVSortMode::Kind, "kind", "Sort by element kind."), clEnumValN(LVSortMode::Line, "line", "Sort by element line number."), clEnumValN(LVSortMode::Name, "name", "Sort by element name."), clEnumValN(LVSortMode::Offset, "offset", "Sort by element offset.")), diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp index 286cfa745fd14..6d893c2295819 100644 --- a/llvm/unittests/ADT/STLExtrasTest.cpp +++ b/llvm/unittests/ADT/STLExtrasTest.cpp @@ -398,6 +398,8 @@ struct some_struct { std::string swap_val; }; +struct derives_from_some_struct : some_struct {}; + std::vector::const_iterator begin(const some_struct &s) { return s.data.begin(); } @@ -532,6 +534,33 @@ TEST(STLExtrasTest, ConcatRangeADL) { EXPECT_THAT(concat(S0, S1), ElementsAre(1, 2, 3, 4)); } +TEST(STLExtrasTest, ConcatRangeRef) { + SmallVector V12{{{1, 2}, "V12[0]"}}; + SmallVector V3456{{{3, 4}, "V3456[0]"}, + {{5, 6}, "V3456[1]"}}; + + // Use concat with `iterator type = some_namespace::some_struct *` and value + // being a reference type. + std::vector Expected = {&V12[0], &V3456[0], + &V3456[1]}; + std::vector Test; + for (auto &i : concat(V12, V3456)) + Test.push_back(&i); + EXPECT_EQ(Expected, Test); +} + +TEST(STLExtrasTest, ConcatRangePtrToDerivedClass) { + some_namespace::some_struct S0{}; + some_namespace::derives_from_some_struct S1{}; + SmallVector V0{&S0}; + SmallVector V1{&S1, &S1}; + + // Use concat over ranges of pointers to different (but related) types. + EXPECT_THAT(concat(V0, V1), + ElementsAre(&S0, static_cast(&S1), + static_cast(&S1))); +} + TEST(STLExtrasTest, MakeFirstSecondRangeADL) { // Make sure that we use the `begin`/`end` functions from `some_namespace`, // using ADL. diff --git a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp index 544c39a3c7b2e..ba6df7489b750 100644 --- a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp +++ b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp @@ -163,13 +163,12 @@ void checkUnspecifiedParameters(LVReader *Reader) { LVPublicNames::const_iterator IterNames = PublicNames.cbegin(); LVScope *Function = (*IterNames).first; EXPECT_EQ(Function->getName(), "foo_printf"); - const LVElements *Elements = Function->getChildren(); - ASSERT_NE(Elements, nullptr); + const auto Elements = Function->getChildren(); // foo_printf is a variadic function whose prototype is // `int foo_printf(const char *, ...)`, where the '...' is represented by a // DW_TAG_unspecified_parameters, i.e. we expect to find at least one child // for which getIsUnspecified() returns true. - EXPECT_TRUE(llvm::any_of(*Elements, [](const LVElement *elt) { + EXPECT_TRUE(llvm::any_of(Elements, [](const LVElement *elt) { return elt->getIsSymbol() && static_cast(elt)->getIsUnspecified(); })); @@ -183,10 +182,9 @@ void checkScopeModule(LVReader *Reader) { EXPECT_EQ(Root->getFileFormatName(), "Mach-O 64-bit x86-64"); EXPECT_EQ(Root->getName(), DwarfClangModule); - ASSERT_NE(CompileUnit->getChildren(), nullptr); - LVElement *FirstChild = *(CompileUnit->getChildren()->begin()); - EXPECT_EQ(FirstChild->getIsScope(), 1); - LVScopeModule *Module = static_cast(FirstChild); + ASSERT_NE(CompileUnit->getScopes(), nullptr); + LVElement *FirstScope = *(CompileUnit->getScopes()->begin()); + LVScopeModule *Module = static_cast(FirstScope); EXPECT_EQ(Module->getIsModule(), 1); EXPECT_EQ(Module->getName(), "DebugModule"); }