//===- llvm/unittest/DebugInfo/LogicalView/SelectElementsTest.cpp ---------===// // // 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/DebugInfo/LogicalView/Core/LVLine.h" #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h" #include "llvm/DebugInfo/LogicalView/Core/LVType.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" using namespace llvm; using namespace llvm::logicalview; namespace { class ReaderTestSelection : public LVReader { #define CREATE(VARIABLE, CREATE_FUNCTION, SET_FUNCTION) \ VARIABLE = CREATE_FUNCTION(); \ EXPECT_NE(VARIABLE, nullptr); \ VARIABLE->SET_FUNCTION(); // Types. LVType *IntegerType = nullptr; // Scopes. LVScope *NestedScope = nullptr; LVScopeAggregate *Aggregate = nullptr; LVScopeFunction *Function = nullptr; LVScopeNamespace *Namespace = nullptr; // Symbols. LVSymbol *ClassMember = nullptr; LVSymbol *LocalVariable = nullptr; LVSymbol *NestedVariable = nullptr; LVSymbol *Parameter = nullptr; // Lines. LVLine *LineOne = nullptr; LVLine *LineTwo = nullptr; LVLine *LineThree = nullptr; LVLine *LineFour = nullptr; LVLine *LineFive = nullptr; protected: void add(LVScope *Parent, LVElement *Element); void set(LVElement *Element, StringRef Name, LVOffset Offset, uint32_t LineNumber = 0, LVElement *Type = nullptr); public: ReaderTestSelection(ScopedPrinter &W) : LVReader("", "", W) { setInstance(this); } Error createScopes() { return LVReader::createScopes(); } void createElements(); void addElements(); void initElements(); void resolvePatterns(LVPatterns &Patterns); void checkFlexiblePatterns(); void checkGenericPatterns(); void checkKindPatterns(); }; // Helper function to add a logical element to a given scope. void ReaderTestSelection::add(LVScope *Parent, LVElement *Child) { Parent->addElement(Child); EXPECT_EQ(Child->getParent(), Parent); EXPECT_EQ(Child->getLevel(), Parent->getLevel() + 1); } // Helper function to set the initial values for a given logical element. void ReaderTestSelection::set(LVElement *Element, StringRef Name, LVOffset Offset, uint32_t LineNumber, LVElement *Type) { Element->setName(Name); Element->setOffset(Offset); Element->setLineNumber(LineNumber); Element->setType(Type); EXPECT_EQ(Element->getName(), Name); EXPECT_EQ(Element->getOffset(), Offset); EXPECT_EQ(Element->getLineNumber(), LineNumber); EXPECT_EQ(Element->getType(), Type); } // Create the logical elements. void ReaderTestSelection::createElements() { // Create scope root. Error Err = createScopes(); ASSERT_THAT_ERROR(std::move(Err), Succeeded()); Root = getScopesRoot(); EXPECT_NE(Root, nullptr); // Create the logical types. CREATE(IntegerType, createType, setIsBase); // Create the logical scopes. CREATE(CompileUnit, createScopeCompileUnit, setIsCompileUnit); CREATE(Function, createScopeFunction, setIsFunction); CREATE(NestedScope, createScope, setIsLexicalBlock); CREATE(Namespace, createScopeNamespace, setIsNamespace); CREATE(Aggregate, createScopeAggregate, setIsAggregate); // Create the logical symbols. CREATE(ClassMember, createSymbol, setIsMember); CREATE(LocalVariable, createSymbol, setIsVariable); CREATE(NestedVariable, createSymbol, setIsVariable); CREATE(Parameter, createSymbol, setIsParameter); // Create the logical lines. CREATE(LineOne, createLine, setIsLineDebug); CREATE(LineTwo, createLine, setIsBasicBlock); CREATE(LineThree, createLine, setIsNewStatement); CREATE(LineFour, createLine, setIsPrologueEnd); CREATE(LineFive, createLine, setIsLineAssembler); } // Create the logical view adding the created logical elements. void ReaderTestSelection::addElements() { setCompileUnit(CompileUnit); // Root // CompileUnit // IntegerType // Namespace // Aggregate // ClassMember // Function // Parameter // LocalVariable // LineOne // LineTwo // NestedScope // NestedVariable // LineThree // LineFour // LineFive // Add elements to Root. add(Root, CompileUnit); // Add elements to CompileUnit. add(CompileUnit, IntegerType); add(CompileUnit, Namespace); add(CompileUnit, Function); // Add elements to Namespace. add(Namespace, Aggregate); // Add elements to Function. add(Function, Parameter); add(Function, LocalVariable); add(Function, LineOne); add(Function, LineTwo); add(Function, LineFive); add(Function, NestedScope); // Add elements to Aggregate. add(Aggregate, ClassMember); // Add elements to NestedScope. add(NestedScope, NestedVariable); add(NestedScope, LineThree); add(NestedScope, LineFour); } void ReaderTestSelection::resolvePatterns(LVPatterns &Patterns) { // Traverse the given scope and its children applying the pattern match. // Before applying the pattern, reset previous matched state. std::function TraverseScope = [&](LVScope *Parent) { auto Traverse = [&](const auto *Set) { if (Set) for (const auto &Entry : *Set) { Entry->resetIsMatched(); Patterns.resolvePatternMatch(Entry); } }; Parent->resetIsMatched(); Patterns.resolvePatternMatch(Parent); Traverse(Parent->getSymbols()); Traverse(Parent->getTypes()); Traverse(Parent->getLines()); if (const LVScopes *Scopes = Parent->getScopes()) for (LVScope *Scope : *Scopes) { Scope->resetIsMatched(); Patterns.resolvePatternMatch(Scope); TraverseScope(Scope); } }; // Start traversing the scopes root and apply any matching pattern. TraverseScope(Root); } // Set initial values to logical elements. void ReaderTestSelection::initElements() { // Types. set(IntegerType, "int", 0x1000); // Scopes. set(CompileUnit, "test.cpp", 0x2000); set(Namespace, "anyNamespace", 0x3000, 300); set(Aggregate, "anyClass", 0x4000, 400); set(Function, "anyFunction", 0x5000, 500, IntegerType); set(NestedScope, "", 0x6000, 600); // Symbols. set(Parameter, "Param", 0x5100, 510, IntegerType); set(LocalVariable, "LocalVariable", 0x5200, 520, IntegerType); set(NestedVariable, "NestedVariable", 0x6200, 620, IntegerType); // Lines. set(LineOne, "", 0x5110, 511); set(LineTwo, "", 0x5210, 521); set(LineThree, "", 0x6110, 611); set(LineFour, "", 0x6210, 621); set(LineFive, "", 0x7110, 711); } // Check logical elements kind patterns. void ReaderTestSelection::checkKindPatterns() { // Add patterns. LVPatterns &Patterns = patterns(); Patterns.clear(); LVElementKindSet KindElements; // --select-elements= LVLineKindSet KindLines; // --select-lines= LVScopeKindSet KindScopes; // --select-scopes= LVSymbolKindSet KindSymbols; // --select-symbols= LVTypeKindSelection KindTypes; // --select-types= KindElements.insert(LVElementKind::Global); KindLines.insert(LVLineKind::IsLineDebug); KindLines.insert(LVLineKind::IsNewStatement); KindLines.insert(LVLineKind::IsLineAssembler); KindScopes.insert(LVScopeKind::IsLexicalBlock); KindSymbols.insert(LVSymbolKind::IsMember); KindSymbols.insert(LVSymbolKind::IsParameter); KindTypes.insert(LVTypeKind::IsBase); // Add requests based on the element kind. Patterns.addRequest(KindElements); Patterns.addRequest(KindLines); Patterns.addRequest(KindScopes); Patterns.addRequest(KindSymbols); Patterns.addRequest(KindTypes); // Apply the collected patterns. resolvePatterns(Patterns); EXPECT_FALSE(CompileUnit->getIsMatched()); EXPECT_FALSE(Namespace->getIsMatched()); EXPECT_FALSE(Aggregate->getIsMatched()); EXPECT_FALSE(Function->getIsMatched()); EXPECT_TRUE(NestedScope->getIsMatched()); EXPECT_TRUE(IntegerType->getIsMatched()); EXPECT_TRUE(ClassMember->getIsMatched()); EXPECT_TRUE(Parameter->getIsMatched()); EXPECT_FALSE(LocalVariable->getIsMatched()); EXPECT_FALSE(NestedVariable->getIsMatched()); EXPECT_TRUE(LineOne->getIsMatched()); EXPECT_FALSE(LineTwo->getIsMatched()); EXPECT_TRUE(LineThree->getIsMatched()); EXPECT_FALSE(LineFour->getIsMatched()); EXPECT_TRUE(LineFive->getIsMatched()); } // Check logical elements generic patterns (Case sensitive). void ReaderTestSelection::checkGenericPatterns() { // Add patterns. LVPatterns &Patterns = patterns(); Patterns.clear(); StringSet<> Generic; // --select= Generic.insert(Function->getName()); // anyFunction Generic.insert(Namespace->getName()); // anyNamespace Generic.insert(LocalVariable->getName()); // LocalVariable LVOffsetSet Offsets; // --select-offset= Offsets.insert(IntegerType->getOffset()); Offsets.insert(LineOne->getOffset()); Offsets.insert(LineTwo->getOffset()); // Add requests based on the generic string and offset. Patterns.addGenericPatterns(Generic); Patterns.addOffsetPatterns(Offsets); // Apply the collected patterns. resolvePatterns(Patterns); EXPECT_FALSE(CompileUnit->getIsMatched()); EXPECT_TRUE(Namespace->getIsMatched()); EXPECT_FALSE(Aggregate->getIsMatched()); EXPECT_TRUE(Function->getIsMatched()); EXPECT_FALSE(NestedScope->getIsMatched()); EXPECT_TRUE(IntegerType->getIsMatched()); EXPECT_FALSE(ClassMember->getIsMatched()); EXPECT_FALSE(Parameter->getIsMatched()); EXPECT_TRUE(LocalVariable->getIsMatched()); EXPECT_FALSE(NestedVariable->getIsMatched()); EXPECT_TRUE(LineOne->getIsMatched()); EXPECT_TRUE(LineTwo->getIsMatched()); EXPECT_FALSE(LineThree->getIsMatched()); EXPECT_FALSE(LineFour->getIsMatched()); EXPECT_FALSE(LineFive->getIsMatched()); } // Check logical elements flexible patterns (case insensitive, RegEx). void ReaderTestSelection::checkFlexiblePatterns() { options().setSelectIgnoreCase(); options().setSelectUseRegex(); // Add patterns. LVPatterns &Patterns = patterns(); Patterns.clear(); StringSet<> Generic; // --select= Generic.insert("function"); Generic.insert("NaMeSpAcE"); Generic.insert("[a-z]*Variable"); Generic.insert("[0-9]21"); // Add requests based on the flexible string. Patterns.addGenericPatterns(Generic); // Apply the collected patterns. resolvePatterns(Patterns); EXPECT_FALSE(CompileUnit->getIsMatched()); EXPECT_TRUE(Namespace->getIsMatched()); // anyNamespace EXPECT_FALSE(Aggregate->getIsMatched()); EXPECT_TRUE(Function->getIsMatched()); // anyFunction EXPECT_FALSE(NestedScope->getIsMatched()); EXPECT_FALSE(IntegerType->getIsMatched()); EXPECT_FALSE(ClassMember->getIsMatched()); EXPECT_FALSE(Parameter->getIsMatched()); EXPECT_TRUE(LocalVariable->getIsMatched()); // LocalVariable EXPECT_TRUE(NestedVariable->getIsMatched()); // NestedVariable EXPECT_FALSE(LineOne->getIsMatched()); EXPECT_TRUE(LineTwo->getIsMatched()); // 521 EXPECT_FALSE(LineThree->getIsMatched()); EXPECT_TRUE(LineFour->getIsMatched()); // 621 EXPECT_FALSE(LineFive->getIsMatched()); } TEST(LogicalViewTest, SelectElements) { ScopedPrinter W(outs()); ReaderTestSelection Reader(W); // Reader options. LVOptions ReaderOptions; ReaderOptions.setAttributeOffset(); ReaderOptions.setPrintAll(); ReaderOptions.setReportList(); ReaderOptions.setReportAnyView(); ReaderOptions.resolveDependencies(); options().setOptions(&ReaderOptions); Reader.createElements(); Reader.addElements(); Reader.initElements(); Reader.checkKindPatterns(); Reader.checkGenericPatterns(); Reader.checkFlexiblePatterns(); } } // namespace