| //===- 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 { |
| // 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); |
| template <typename T, typename F> T *create(F Function) { |
| // 'Function' will update a specific kind of the logical element to |
| // have the ability of kind selection. |
| T *Element = new (std::nothrow) T(); |
| EXPECT_NE(Element, nullptr); |
| (Element->*Function)(); |
| return 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. |
| IntegerType = create<LVType, LVTypeSetFunction>(&LVType::setIsBase); |
| |
| // Create the logical scopes. |
| CompileUnit = create<LVScopeCompileUnit, LVScopeSetFunction>( |
| &LVScope::setIsCompileUnit); |
| Function = |
| create<LVScopeFunction, LVScopeSetFunction>(&LVScope::setIsFunction); |
| NestedScope = |
| create<LVScope, LVScopeSetFunction>(&LVScope::setIsLexicalBlock); |
| Namespace = |
| create<LVScopeNamespace, LVScopeSetFunction>(&LVScope::setIsNamespace); |
| Aggregate = |
| create<LVScopeAggregate, LVScopeSetFunction>(&LVScope::setIsAggregate); |
| |
| // Create the logical symbols. |
| ClassMember = create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsMember); |
| LocalVariable = |
| create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsVariable); |
| NestedVariable = |
| create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsVariable); |
| Parameter = create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsParameter); |
| |
| // Create the logical lines. |
| LineOne = create<LVLine, LVLineSetFunction>(&LVLine::setIsLineDebug); |
| LineTwo = create<LVLine, LVLineSetFunction>(&LVLine::setIsBasicBlock); |
| LineThree = create<LVLine, LVLineSetFunction>(&LVLine::setIsNewStatement); |
| LineFour = create<LVLine, LVLineSetFunction>(&LVLine::setIsPrologueEnd); |
| LineFive = create<LVLine, LVLineSetFunction>(&LVLine::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<void(LVScope * Parent)> 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=<Kind> |
| LVLineKindSet KindLines; // --select-lines=<Kind> |
| LVScopeKindSet KindScopes; // --select-scopes=<Kind> |
| LVSymbolKindSet KindSymbols; // --select-symbols=<Kind> |
| LVTypeKindSelection KindTypes; // --select-types=<Kind> |
| |
| 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=<Pattern> |
| Generic.insert(Function->getName()); // anyFunction |
| Generic.insert(Namespace->getName()); // anyNamespace |
| Generic.insert(LocalVariable->getName()); // LocalVariable |
| |
| LVOffsetSet Offsets; // --select-offset=<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=<Pattern> |
| 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 |