diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h @@ -17,7 +17,9 @@ #include "llvm/DebugInfo/LogicalView/Core/LVObject.h" #include "llvm/DebugInfo/LogicalView/Core/LVStringPool.h" #include "llvm/Support/Casting.h" +#include #include +#include namespace llvm { namespace logicalview { @@ -60,6 +62,8 @@ enum class LVElementKind { Discarded, Global, Optimized, LastEntry }; using LVElementKindSet = std::set; +using LVElementDispatch = std::map; +using LVElementRequest = std::vector; class LVElement : public LVObject { enum class Property { @@ -98,6 +102,7 @@ }; // Typed bitvector with properties for this element. LVProperties Properties; + static LVElementDispatch Dispatch; /// RTTI. const LVSubclassID SubclassID; @@ -330,6 +335,9 @@ virtual void resolveName(); virtual void resolveReferences() {} void resolveParents(); + +public: + static LVElementDispatch &getDispatch() { return Dispatch; } }; } // end namespace logicalview diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h @@ -33,11 +33,14 @@ LastEntry }; using LVLineKindSet = std::set; +using LVLineDispatch = std::map; +using LVLineRequest = std::vector; // Class to represent a logical line. class LVLine : public LVElement { // Typed bitvector with kinds for this line. LVProperties Kinds; + static LVLineDispatch Dispatch; public: LVLine() : LVElement(LVSubclassID::LV_LINE) { @@ -78,6 +81,8 @@ return lineAsString(getLineNumber(), getDiscriminator(), ShowZero); } + static LVLineDispatch &getDispatch() { return Dispatch; } + void print(raw_ostream &OS, bool Full = true) const override; void printExtra(raw_ostream &OS, bool Full = true) const override {} diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h @@ -16,10 +16,10 @@ #include "llvm/ADT/StringSet.h" #include "llvm/DebugInfo/LogicalView/Core/LVLine.h" -#include "llvm/DebugInfo/LogicalView/Core/LVOptions.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/Regex.h" #include #include @@ -445,6 +445,201 @@ inline LVOptions &options() { return (*LVOptions::getOptions()); } inline void setOptions(LVOptions *Options) { LVOptions::setOptions(Options); } +class LVPatterns final { + // Pattern Mode. + enum class LVMatchMode { + None = 0, // No given pattern. + Match, // Perfect match. + NoCase, // Ignore case. + Regex // Regular expression. + }; + + // Keep the search pattern information. + struct LVMatch { + std::string Pattern; // Normal pattern. + std::shared_ptr RE; // Regular Expression Pattern. + LVMatchMode Mode = LVMatchMode::None; // Match mode. + }; + + using LVMatchInfo = std::vector; + LVMatchInfo GenericMatchInfo; + using LVMatchOffsets = std::vector; + LVMatchOffsets OffsetMatchInfo; + + // Element selection. + LVElementDispatch ElementDispatch; + LVLineDispatch LineDispatch; + LVScopeDispatch ScopeDispatch; + LVSymbolDispatch SymbolDispatch; + LVTypeDispatch TypeDispatch; + + // Element selection request. + LVElementRequest ElementRequest; + LVLineRequest LineRequest; + LVScopeRequest ScopeRequest; + LVSymbolRequest SymbolRequest; + LVTypeRequest TypeRequest; + + // Check an element printing Request. + template + bool checkElementRequest(const T *Element, const U &Requests) const { + assert(Element && "Element must not be nullptr"); + for (const auto &Request : Requests) + if ((Element->*Request)()) + return true; + // Check generic element requests. + for (const LVElementGetFunction &Request : ElementRequest) + if ((Element->*Request)()) + return true; + return false; + } + + // Add an element printing request based on its kind. + template + void addRequest(const T &Selection, const U &Dispatch, V &Request) const { + for (const auto &Entry : Selection) { + // Find target function to fullfit request. + typename U::const_iterator Iter = Dispatch.find(Entry); + if (Iter != Dispatch.end()) + Request.push_back(Iter->second); + } + } + + void addElement(LVElement *Element); + + template + void resolveGenericPatternMatch(T *Element, const U &Requests) { + assert(Element && "Element must not be nullptr"); + auto CheckPattern = [=]() -> bool { + return Element->isNamed() && + (matchGenericPattern(Element->getName()) || + matchGenericPattern(Element->getTypeName())); + }; + auto CheckOffset = [=]() -> bool { + return matchOffsetPattern(Element->getOffset()); + }; + if ((options().getSelectGenericPattern() && CheckPattern()) || + (options().getSelectOffsetPattern() && CheckOffset()) || + ((Requests.size() || ElementRequest.size()) && + checkElementRequest(Element, Requests))) + addElement(Element); + } + + template + void resolveGenericPatternMatch(LVLine *Line, const U &Requests) { + assert(Line && "Line must not be nullptr"); + auto CheckPattern = [=]() -> bool { + return matchGenericPattern(Line->lineNumberAsStringStripped()) || + matchGenericPattern(Line->getName()) || + matchGenericPattern(Line->getPathname()); + }; + auto CheckOffset = [=]() -> bool { + return matchOffsetPattern(Line->getAddress()); + }; + if ((options().getSelectGenericPattern() && CheckPattern()) || + (options().getSelectOffsetPattern() && CheckOffset()) || + (Requests.size() && checkElementRequest(Line, Requests))) + addElement(Line); + } + + Error createMatchEntry(LVMatchInfo &Filters, StringRef Pattern, + bool IgnoreCase, bool UseRegex); + +public: + static LVPatterns *getPatterns(); + + LVPatterns() { + ElementDispatch = LVElement::getDispatch(); + LineDispatch = LVLine::getDispatch(); + ScopeDispatch = LVScope::getDispatch(); + SymbolDispatch = LVSymbol::getDispatch(); + TypeDispatch = LVType::getDispatch(); + } + LVPatterns(const LVPatterns &) = delete; + LVPatterns &operator=(const LVPatterns &) = delete; + ~LVPatterns() = default; + + // Clear any existing patterns. + void clear() { + GenericMatchInfo.clear(); + OffsetMatchInfo.clear(); + ElementRequest.clear(); + LineRequest.clear(); + ScopeRequest.clear(); + SymbolRequest.clear(); + TypeRequest.clear(); + + options().resetSelectGenericKind(); + options().resetSelectGenericPattern(); + options().resetSelectOffsetPattern(); + } + + void addRequest(LVElementKindSet &Selection) { + addRequest(Selection, ElementDispatch, ElementRequest); + } + void addRequest(LVLineKindSet &Selection) { + addRequest(Selection, LineDispatch, LineRequest); + } + void addRequest(LVScopeKindSet &Selection) { + addRequest(Selection, ScopeDispatch, ScopeRequest); + } + void addRequest(LVSymbolKindSet &Selection) { + addRequest(Selection, SymbolDispatch, SymbolRequest); + } + void addRequest(LVTypeKindSelection &Selection) { + addRequest(Selection, TypeDispatch, TypeRequest); + } + + void updateReportOptions(); + + bool matchPattern(StringRef Input, const LVMatchInfo &MatchInfo); + // Match a pattern (--select='pattern'). + bool matchGenericPattern(StringRef Input) { + return matchPattern(Input, GenericMatchInfo); + } + bool matchOffsetPattern(LVOffset Offset) { + return std::find(OffsetMatchInfo.begin(), OffsetMatchInfo.end(), Offset) != + OffsetMatchInfo.end(); + } + + void resolvePatternMatch(LVLine *Line) { + resolveGenericPatternMatch(Line, LineRequest); + } + + void resolvePatternMatch(LVScope *Scope) { + resolveGenericPatternMatch(Scope, ScopeRequest); + } + + void resolvePatternMatch(LVSymbol *Symbol) { + resolveGenericPatternMatch(Symbol, SymbolRequest); + } + + void resolvePatternMatch(LVType *Type) { + resolveGenericPatternMatch(Type, TypeRequest); + } + + void addPatterns(StringSet<> &Patterns, LVMatchInfo &Filters); + + // Add generic and offset patterns info. + void addGenericPatterns(StringSet<> &Patterns); + void addOffsetPatterns(const LVOffsetSet &Patterns); + + // Conditions to print an object. + bool printElement(const LVLine *Line) const; + bool printObject(const LVLocation *Location) const; + bool printElement(const LVScope *Scope) const; + bool printElement(const LVSymbol *Symbol) const; + bool printElement(const LVType *Type) const; + + void print(raw_ostream &OS) const; + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + void dump() const { print(dbgs()); } +#endif +}; + +inline LVPatterns &patterns() { return *LVPatterns::getPatterns(); } + } // namespace logicalview } // namespace llvm diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h @@ -141,11 +141,21 @@ LVSplitContext &getSplitContext() { return SplitContext; } // Conditions to print an object. - bool doPrintLine(const LVLine *Line) const { return true; } - bool doPrintLocation(const LVLocation *Location) const { return true; } - bool doPrintScope(const LVScope *Scope) const { return true; } - bool doPrintSymbol(const LVSymbol *Symbol) const { return true; } - bool doPrintType(const LVType *Type) const { return true; } + bool doPrintLine(const LVLine *Line) const { + return patterns().printElement(Line); + } + bool doPrintLocation(const LVLocation *Location) const { + return patterns().printObject(Location); + } + bool doPrintScope(const LVScope *Scope) const { + return patterns().printElement(Scope); + } + bool doPrintSymbol(const LVSymbol *Symbol) const { + return patterns().printElement(Symbol); + } + bool doPrintType(const LVType *Type) const { + return patterns().printElement(Type); + } static LVReader &getInstance(); static void setInstance(LVReader *Reader); diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h @@ -53,6 +53,8 @@ LastEntry }; using LVScopeKindSet = std::set; +using LVScopeDispatch = std::map; +using LVScopeRequest = std::vector; using LVOffsetElementMap = std::map; @@ -78,6 +80,7 @@ // Typed bitvector with kinds and properties for this scope. LVProperties Kinds; LVProperties Properties; + static LVScopeDispatch Dispatch; // Coverage factor in units (bytes). unsigned CoverageFactor = 0; @@ -118,8 +121,8 @@ void printEncodedArgs(raw_ostream &OS, bool Full) const; void printActiveRanges(raw_ostream &OS, bool Full = true) const; - virtual void printSizes(raw_ostream &OS) const {}; - virtual void printSummary(raw_ostream &OS) const {}; + virtual void printSizes(raw_ostream &OS) const {} + virtual void printSummary(raw_ostream &OS) const {} // Encoded template arguments. virtual StringRef getEncodedArgs() const { return StringRef(); } @@ -259,6 +262,8 @@ void resolveElements(); + static LVScopeDispatch &getDispatch() { return Dispatch; } + void print(raw_ostream &OS, bool Full = true) const override; void printExtra(raw_ostream &OS, bool Full = true) const override; virtual void printMatchedElements(raw_ostream &OS, bool UseMatchedElements) {} @@ -385,6 +390,10 @@ LVScopeCompileUnit &operator=(const LVScopeCompileUnit &) = delete; ~LVScopeCompileUnit() = default; + LVScope *getCompileUnitParent() const override { + return static_cast(const_cast(this)); + } + // Get the line located at the given address. LVLine *lineLowerBound(LVAddress Address) const; LVLine *lineUpperBound(LVAddress Address) const; @@ -412,6 +421,14 @@ void processRangeLocationCoverage( LVValidLocation ValidLocation = &LVLocation::validateRanges); + // Add matched element. + void addMatched(LVElement *Element) { MatchedElements.push_back(Element); } + void addMatched(LVScope *Scope) { MatchedScopes.push_back(Scope); } + void propagatePatternMatch(); + + const LVElements &getMatchedElements() const { return MatchedElements; } + const LVScopes &getMatchedScopes() const { return MatchedScopes; } + void printLocalNames(raw_ostream &OS, bool Full = true) const; void printSummary(raw_ostream &OS, const LVCounter &Counter, const char *Header) const; diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h @@ -30,6 +30,8 @@ LastEntry }; using LVSymbolKindSet = std::set; +using LVSymbolDispatch = std::map; +using LVSymbolRequest = std::vector; class LVSymbol final : public LVElement { enum class Property { HasLocation, FillGaps, LastEntry }; @@ -37,6 +39,7 @@ // Typed bitvector with kinds and properties for this symbol. LVProperties Kinds; LVProperties Properties; + static LVSymbolDispatch Dispatch; // CodeView symbol Linkage name. size_t LinkageNameIndex = 0; @@ -152,6 +155,8 @@ void resolveName() override; void resolveReferences() override; + static LVSymbolDispatch &getDispatch() { return Dispatch; } + void print(raw_ostream &OS, bool Full = true) const override; void printExtra(raw_ostream &OS, bool Full = true) const override; diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h @@ -44,6 +44,8 @@ LastEntry }; using LVTypeKindSelection = std::set; +using LVTypeDispatch = std::map; +using LVTypeRequest = std::vector; // Class to represent a DWARF Type. class LVType : public LVElement { @@ -52,6 +54,7 @@ // Typed bitvector with kinds and properties for this type. LVProperties Kinds; LVProperties Properties; + static LVTypeDispatch Dispatch; public: LVType() : LVElement(LVSubclassID::LV_TYPE) { setIsType(); } @@ -106,6 +109,8 @@ void resolveName() override; void resolveReferences() override; + static LVTypeDispatch &getDispatch() { return Dispatch; } + void print(raw_ostream &OS, bool Full = true) const override; void printExtra(raw_ostream &OS, bool Full = true) const override; diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp --- a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp @@ -21,6 +21,11 @@ #define DEBUG_TYPE "Element" +LVElementDispatch LVElement::Dispatch = { + {LVElementKind::Discarded, &LVElement::getIsDiscarded}, + {LVElementKind::Global, &LVElement::getIsGlobalReference}, + {LVElementKind::Optimized, &LVElement::getIsOptimized}}; + LVType *LVElement::getTypeAsType() const { return ElementType && ElementType->getIsType() ? static_cast(ElementType) diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp --- a/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp @@ -45,6 +45,18 @@ return Kind; } +LVLineDispatch LVLine::Dispatch = { + {LVLineKind::IsBasicBlock, &LVLine::getIsBasicBlock}, + {LVLineKind::IsDiscriminator, &LVLine::getIsDiscriminator}, + {LVLineKind::IsEndSequence, &LVLine::getIsEndSequence}, + {LVLineKind::IsLineDebug, &LVLine::getIsLineDebug}, + {LVLineKind::IsLineAssembler, &LVLine::getIsLineAssembler}, + {LVLineKind::IsNewStatement, &LVLine::getIsNewStatement}, + {LVLineKind::IsEpilogueBegin, &LVLine::getIsEpilogueBegin}, + {LVLineKind::IsPrologueEnd, &LVLine::getIsPrologueEnd}, + {LVLineKind::IsAlwaysStepInto, &LVLine::getIsAlwaysStepInto}, + {LVLineKind::IsNeverStepInto, &LVLine::getIsNeverStepInto}}; + // String used as padding for printing elements with no line number. std::string LVLine::noLineAsString(bool ShowZero) const { return (ShowZero || options().getAttributeZero()) ? (" 0 ") diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp --- a/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp @@ -11,6 +11,8 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" +#include "llvm/DebugInfo/LogicalView/Core/LVReader.h" +#include "llvm/Support/Errc.h" using namespace llvm; using namespace llvm::logicalview; @@ -394,3 +396,181 @@ << "Tag: " << Options.getInternalTag() << "\n" << "\n"; } + +//===----------------------------------------------------------------------===// +// Logical element selection using patterns. +//===----------------------------------------------------------------------===// +LVPatterns *LVPatterns::getPatterns() { + static LVPatterns Patterns; + return &Patterns; +} + +Error LVPatterns::createMatchEntry(LVMatchInfo &Filters, StringRef Pattern, + bool IgnoreCase, bool UseRegex) { + LVMatch Match; + // Process pattern as regular expression. + if (UseRegex) { + Match.Pattern = std::string(Pattern); + if (Pattern.size()) { + Match.RE = std::make_shared(Pattern, IgnoreCase ? Regex::IgnoreCase + : Regex::NoFlags); + std::string Error; + if (!Match.RE->isValid(Error)) + return createStringError(errc::invalid_argument, + "Error in regular expression: %s", + Error.c_str()); + + Match.Mode = LVMatchMode::Regex; + Filters.push_back(Match); + return Error::success(); + } + } + + // Process pattern as an exact string match, depending on the case. + Match.Pattern = std::string(Pattern); + if (Match.Pattern.size()) { + Match.Mode = IgnoreCase ? LVMatchMode::NoCase : LVMatchMode::Match; + Filters.push_back(Match); + } + + return Error::success(); +} + +void LVPatterns::addGenericPatterns(StringSet<> &Patterns) { + addPatterns(Patterns, GenericMatchInfo); + if (GenericMatchInfo.size()) { + options().setSelectGenericPattern(); + options().setSelectExecute(); + } +} + +void LVPatterns::addOffsetPatterns(const LVOffsetSet &Patterns) { + for (const LVOffset &Entry : Patterns) + OffsetMatchInfo.push_back(Entry); + if (OffsetMatchInfo.size()) { + options().setSelectOffsetPattern(); + options().setSelectExecute(); + } +} + +void LVPatterns::addPatterns(StringSet<> &Patterns, LVMatchInfo &Filters) { + bool IgnoreCase = options().getSelectIgnoreCase(); + bool UseRegex = options().getSelectUseRegex(); + for (const StringSet<>::value_type &Entry : Patterns) { + StringRef Pattern = Entry.first(); + if (Error Err = createMatchEntry(Filters, Pattern, IgnoreCase, UseRegex)) + consumeError(std::move(Err)); + } + + LLVM_DEBUG({ + dbgs() << "\nPattern Information:\n"; + for (LVMatch &Match : Filters) + dbgs() << "Mode: " + << (Match.Mode == LVMatchMode::Match ? "Match" : "Regex") + << " Pattern: '" << Match.Pattern << "'\n"; + }); +} + +void LVPatterns::addElement(LVElement *Element) { + // Mark any element that matches a given pattern. + Element->setIsMatched(); + options().setSelectExecute(); + if (options().getReportList()) + getReaderCompileUnit()->addMatched(Element); + if (options().getReportAnyView()) { + getReaderCompileUnit()->addMatched(Element->getIsScope() + ? static_cast(Element) + : Element->getParentScope()); + // Mark element as matched. + if (!Element->getIsScope()) + Element->setHasPattern(); + } +} + +void LVPatterns::updateReportOptions() { + if (ElementRequest.size() || LineRequest.size() || ScopeRequest.size() || + SymbolRequest.size() || TypeRequest.size()) { + options().setSelectGenericKind(); + options().setSelectExecute(); + } + + // If we have selected requests and there are no specified report options, + // assume the 'details' option. + if (options().getSelectExecute() && !options().getReportExecute()) { + options().setReportExecute(); + options().setReportList(); + } +} + +// Match a general pattern. +bool LVPatterns::matchPattern(StringRef Input, const LVMatchInfo &MatchInfo) { + bool Matched = false; + // Traverse all match specifications. + for (const LVMatch &Match : MatchInfo) { + switch (Match.Mode) { + case LVMatchMode::Match: + Matched = Input.equals(Match.Pattern); + break; + case LVMatchMode::NoCase: + Matched = Input.equals_insensitive(Match.Pattern); + break; + case LVMatchMode::Regex: + Matched = Match.RE->match(Input); + break; + default: + break; + } + // Return if we have a match. + if (Matched) + return true; + } + return Matched; +} + +bool LVPatterns::printElement(const LVLine *Line) const { + return (options().getPrintLines() && Line->getIsLineDebug()) || + (options().getPrintInstructions() && Line->getIsLineAssembler()); +} + +bool LVPatterns::printObject(const LVLocation *Location) const { + if (options().getAttributeAll()) + return true; + bool DoPrint = options().getAttributeAnyLocation(); + // Consider the case of filler locations. + if (DoPrint && Location && Location->getIsGapEntry()) + DoPrint = options().getAttributeGaps(); + return DoPrint; +} + +bool LVPatterns::printElement(const LVScope *Scope) const { + // A scope will be printed depending on the following rules: + // - Request to print scopes. + // - Request to print any of its children. + // - If the scope is Root or CompileUnit: + // Request to print summary, sizes or warnings. + return options().getPrintScopes() || + (options().getPrintSymbols() && Scope->getHasSymbols()) || + (options().getPrintAnyLine() && Scope->getHasLines()) || + (options().getPrintTypes() && Scope->getHasTypes()) || + ((options().getPrintSizesSummary() || options().getPrintWarnings()) && + (Scope->getIsRoot() || Scope->getIsCompileUnit())); +} + +bool LVPatterns::printElement(const LVSymbol *Symbol) const { + // Print compiler generated symbols only if command line option. + if (Symbol->getIsArtificial()) + return options().getAttributeGenerated() && options().getPrintSymbols(); + return options().getPrintSymbols(); +} + +bool LVPatterns::printElement(const LVType *Type) const { + // Print array subranges only if print types is requested. + if (Type->getIsSubrange()) + return options().getAttributeSubrange() && options().getPrintTypes(); + return options().getPrintTypes(); +} + +void LVPatterns::print(raw_ostream &OS) const { + OS << "LVPatterns\n"; + LLVM_DEBUG(dbgs() << "Print Patterns\n"); +} diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp --- a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp @@ -129,6 +129,22 @@ // Set current Reader instance. setInstance(this); + // Before any scopes creation, process any pattern specified by the + // --select and --select-offsets options. + patterns().addGenericPatterns(options().Select.Generic); + patterns().addOffsetPatterns(options().Select.Offsets); + + // Add any specific element printing requests based on the element kind. + patterns().addRequest(options().Select.Elements); + patterns().addRequest(options().Select.Lines); + patterns().addRequest(options().Select.Scopes); + patterns().addRequest(options().Select.Symbols); + patterns().addRequest(options().Select.Types); + + // Once we have processed the requests for any particular kind of elements, + // we need to update the report options, in order to have a default value. + patterns().updateReportOptions(); + // Delegate the scope tree creation to the specific reader. if (Error Err = createScopes()) return Err; @@ -150,6 +166,24 @@ // Set current Reader instance. setInstance(this); + // Check for any '--report' request. + if (options().getReportExecute()) { + // Requested details. + if (options().getReportList()) + if (Error Err = printMatchedElements(/*UseMatchedElements=*/true)) + return Err; + // Requested only children. + if (options().getReportChildren() && !options().getReportParents()) + if (Error Err = printMatchedElements(/*UseMatchedElements=*/false)) + return Err; + // Requested (parents) or (parents and children). + if (options().getReportParents() || options().getReportView()) + if (Error Err = printScopes()) + return Err; + + return Error::success(); + } + return printScopes(); } @@ -159,7 +193,9 @@ return Err; // Start printing from the root. - bool DoMatch = false; + bool DoMatch = options().getSelectGenericPattern() || + options().getSelectGenericKind() || + options().getSelectOffsetPattern(); return Root->doPrint(OutputSplit, DoMatch, DoPrint, OS); } diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp --- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp @@ -87,6 +87,30 @@ return Kind; } +LVScopeDispatch LVScope::Dispatch = { + {LVScopeKind::IsAggregate, &LVScope::getIsAggregate}, + {LVScopeKind::IsArray, &LVScope::getIsArray}, + {LVScopeKind::IsBlock, &LVScope::getIsBlock}, + {LVScopeKind::IsCallSite, &LVScope::getIsCallSite}, + {LVScopeKind::IsCatchBlock, &LVScope::getIsCatchBlock}, + {LVScopeKind::IsClass, &LVScope::getIsClass}, + {LVScopeKind::IsCompileUnit, &LVScope::getIsCompileUnit}, + {LVScopeKind::IsEntryPoint, &LVScope::getIsEntryPoint}, + {LVScopeKind::IsEnumeration, &LVScope::getIsEnumeration}, + {LVScopeKind::IsFunction, &LVScope::getIsFunction}, + {LVScopeKind::IsFunctionType, &LVScope::getIsFunctionType}, + {LVScopeKind::IsInlinedFunction, &LVScope::getIsInlinedFunction}, + {LVScopeKind::IsLabel, &LVScope::getIsLabel}, + {LVScopeKind::IsLexicalBlock, &LVScope::getIsLexicalBlock}, + {LVScopeKind::IsNamespace, &LVScope::getIsNamespace}, + {LVScopeKind::IsRoot, &LVScope::getIsRoot}, + {LVScopeKind::IsStructure, &LVScope::getIsStructure}, + {LVScopeKind::IsTemplate, &LVScope::getIsTemplate}, + {LVScopeKind::IsTemplateAlias, &LVScope::getIsTemplateAlias}, + {LVScopeKind::IsTemplatePack, &LVScope::getIsTemplatePack}, + {LVScopeKind::IsTryBlock, &LVScope::getIsTryBlock}, + {LVScopeKind::IsUnion, &LVScope::getIsUnion}}; + void LVScope::addToChildren(LVElement *Element) { if (!Children) Children = new LVElements(); @@ -395,6 +419,9 @@ } LVElement::resolveName(); + + // Resolve any given pattern. + patterns().resolvePatternMatch(this); } void LVScope::resolveReferences() { @@ -432,6 +459,8 @@ LVScopeCompileUnit *CompileUnit = static_cast(Scope); getReader().setCompileUnit(CompileUnit); CompileUnit->resolve(); + // Propagate any matching information into the scopes tree. + CompileUnit->propagatePatternMatch(); } } @@ -530,6 +559,13 @@ } bool LVScope::resolvePrinting() const { + // In selection mode, always print the root scope regardless of the + // number of matched elements. If no matches, the root by itself will + // indicate no matches. + if (options().getSelectExecute()) { + return getIsRoot() || getIsCompileUnit() || getHasPattern(); + } + bool Globals = options().getAttributeGlobal(); bool Locals = options().getAttributeLocal(); if ((Globals && Locals) || (!Globals && !Locals)) { @@ -794,7 +830,8 @@ void LVScope::print(raw_ostream &OS, bool Full) const { if (getIncludeInPrint() && getReader().doPrintScope(this)) { // For a summary (printed elements), do not count the scope root. - if (!(getIsRoot())) + // For a summary (selected elements) do not count a compile unit. + if (!(getIsRoot() || (getIsCompileUnit() && options().getSelectExecute()))) getReaderCompileUnit()->incrementPrintedScopes(); LVElement::print(OS, Full); printExtra(OS, Full); @@ -939,9 +976,28 @@ CUContributionSize = Size; } +// Update parents and children with pattern information. +void LVScopeCompileUnit::propagatePatternMatch() { + // At this stage, we have finished creating the Scopes tree and we have + // a list of elements that match the pattern specified in the command line. + // The pattern corresponds to a scope or element; mark parents and/or + // children as having that pattern, before any printing is done. + if (!options().getSelectExecute()) + return; + + if (MatchedScopes.size()) { + for (LVScope *Scope : MatchedScopes) + Scope->traverseParentsAndChildren(&LVScope::getHasPattern, + &LVScope::setHasPattern); + } else { + // Mark the compile unit as having a pattern to enable any requests to + // print sizes and summary as that information is recorded at that level. + setHasPattern(); + } +} + void LVScopeCompileUnit::processRangeLocationCoverage( LVValidLocation ValidLocation) { - if (options().getAttributeRange()) { // Traverse the scopes to get scopes that have invalid ranges. LVLocations Locations; @@ -975,10 +1031,18 @@ return getStringPool().getString(Filenames[Index - 1]); } -void LVScopeCompileUnit::incrementPrintedLines() { ++Printed.Lines; } -void LVScopeCompileUnit::incrementPrintedScopes() { ++Printed.Scopes; } -void LVScopeCompileUnit::incrementPrintedSymbols() { ++Printed.Symbols; } -void LVScopeCompileUnit::incrementPrintedTypes() { ++Printed.Types; } +void LVScopeCompileUnit::incrementPrintedLines() { + options().getSelectExecute() ? ++Found.Lines : ++Printed.Lines; +} +void LVScopeCompileUnit::incrementPrintedScopes() { + options().getSelectExecute() ? ++Found.Scopes : ++Printed.Scopes; +} +void LVScopeCompileUnit::incrementPrintedSymbols() { + options().getSelectExecute() ? ++Found.Symbols : ++Printed.Symbols; +} +void LVScopeCompileUnit::incrementPrintedTypes() { + options().getSelectExecute() ? ++Found.Types : ++Printed.Types; +} // Values are used by '--summary' option (allocated). void LVScopeCompileUnit::increment(LVLine *Line) { @@ -1074,6 +1138,13 @@ // Recursively print the contributions for each scope. std::function PrintScope = [&](const LVScope *Scope) { + // If we have selection criteria, then use only the selected scopes. + if (options().getSelectExecute() && options().getReportAnyView()) { + for (const LVScope *Scope : MatchedScopes) + if (Scope->getLevel() < options().getOutputLevel()) + printScopeSize(Scope, OS); + return; + } if (Scope->getLevel() < options().getOutputLevel()) { if (const LVScopes *Scopes = Scope->getScopes()) for (const LVScope *Scope : *Scopes) { @@ -1108,7 +1179,7 @@ } void LVScopeCompileUnit::printSummary(raw_ostream &OS) const { - printSummary(OS, Printed, "Printed"); + printSummary(OS, options().getSelectExecute() ? Found : Printed, "Printed"); } // Print summary details for the scopes tree. diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp --- a/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp @@ -51,6 +51,15 @@ return Kind; } +LVSymbolDispatch LVSymbol::Dispatch = { + {LVSymbolKind::IsCallSiteParameter, &LVSymbol::getIsCallSiteParameter}, + {LVSymbolKind::IsConstant, &LVSymbol::getIsConstant}, + {LVSymbolKind::IsInheritance, &LVSymbol::getIsInheritance}, + {LVSymbolKind::IsMember, &LVSymbol::getIsMember}, + {LVSymbolKind::IsParameter, &LVSymbol::getIsParameter}, + {LVSymbolKind::IsUnspecified, &LVSymbol::getIsUnspecified}, + {LVSymbolKind::IsVariable, &LVSymbol::getIsVariable}}; + // Add a Location Entry. void LVSymbol::addLocation(dwarf::Attribute Attr, LVAddress LowPC, LVAddress HighPC, LVUnsigned SectionOffset, @@ -212,6 +221,9 @@ setIsResolvedName(); LVElement::resolveName(); + + // Resolve any given pattern. + patterns().resolvePatternMatch(this); } void LVSymbol::resolveReferences() { diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp --- a/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp @@ -83,6 +83,28 @@ return Kind; } +LVTypeDispatch LVType::Dispatch = { + {LVTypeKind::IsBase, &LVType::getIsBase}, + {LVTypeKind::IsConst, &LVType::getIsConst}, + {LVTypeKind::IsEnumerator, &LVType::getIsEnumerator}, + {LVTypeKind::IsImport, &LVType::getIsImport}, + {LVTypeKind::IsImportDeclaration, &LVType::getIsImportDeclaration}, + {LVTypeKind::IsImportModule, &LVType::getIsImportModule}, + {LVTypeKind::IsPointer, &LVType::getIsPointer}, + {LVTypeKind::IsPointerMember, &LVType::getIsPointerMember}, + {LVTypeKind::IsReference, &LVType::getIsReference}, + {LVTypeKind::IsRestrict, &LVType::getIsRestrict}, + {LVTypeKind::IsRvalueReference, &LVType::getIsRvalueReference}, + {LVTypeKind::IsSubrange, &LVType::getIsSubrange}, + {LVTypeKind::IsTemplateParam, &LVType::getIsTemplateParam}, + {LVTypeKind::IsTemplateTemplateParam, &LVType::getIsTemplateTemplateParam}, + {LVTypeKind::IsTemplateTypeParam, &LVType::getIsTemplateTypeParam}, + {LVTypeKind::IsTemplateValueParam, &LVType::getIsTemplateValueParam}, + {LVTypeKind::IsTypedef, &LVType::getIsTypedef}, + {LVTypeKind::IsUnaligned, &LVType::getIsUnaligned}, + {LVTypeKind::IsUnspecified, &LVType::getIsUnspecified}, + {LVTypeKind::IsVolatile, &LVType::getIsVolatile}}; + void LVType::resolveReferences() { // Some DWARF tags are the representation of types. However, we associate // some of them to scopes. The ones associated with types, do not have @@ -136,6 +158,9 @@ generateName(); LVElement::resolveName(); + + // Resolve any given pattern. + patterns().resolvePatternMatch(this); } StringRef LVType::resolveReferencesChain() { diff --git a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt --- a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt +++ b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt @@ -4,6 +4,7 @@ add_llvm_unittest(DebugInfoLogicalViewTests CommandLineOptionsTest.cpp + SelectElementsTest.cpp LocationRangesTest.cpp LogicalElementsTest.cpp StringPoolTest.cpp diff --git a/llvm/unittests/DebugInfo/LogicalView/SelectElementsTest.cpp b/llvm/unittests/DebugInfo/LogicalView/SelectElementsTest.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/DebugInfo/LogicalView/SelectElementsTest.cpp @@ -0,0 +1,399 @@ +//===- 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 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::setIsBase); + + // Create the logical scopes. + CompileUnit = create( + &LVScope::setIsCompileUnit); + Function = + create(&LVScope::setIsFunction); + NestedScope = + create(&LVScope::setIsLexicalBlock); + Namespace = + create(&LVScope::setIsNamespace); + Aggregate = + create(&LVScope::setIsAggregate); + + // Create the logical symbols. + ClassMember = create(&LVSymbol::setIsMember); + LocalVariable = + create(&LVSymbol::setIsVariable); + NestedVariable = + create(&LVSymbol::setIsVariable); + Parameter = create(&LVSymbol::setIsParameter); + + // Create the logical lines. + LineOne = create(&LVLine::setIsLineDebug); + LineTwo = create(&LVLine::setIsBasicBlock); + LineThree = create(&LVLine::setIsNewStatement); + LineFour = create(&LVLine::setIsPrologueEnd); + LineFive = create(&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 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