1*5f757f3fSDimitry Andric //===- RemarkCounter.cpp --------------------------------------------------===// 2*5f757f3fSDimitry Andric // 3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5f757f3fSDimitry Andric // 7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 8*5f757f3fSDimitry Andric // 9*5f757f3fSDimitry Andric // Generic tool to count remarks based on properties 10*5f757f3fSDimitry Andric // 11*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 12*5f757f3fSDimitry Andric 13*5f757f3fSDimitry Andric #include "RemarkCounter.h" 14*5f757f3fSDimitry Andric #include "RemarkUtilRegistry.h" 15*5f757f3fSDimitry Andric #include "llvm/Support/CommandLine.h" 16*5f757f3fSDimitry Andric #include "llvm/Support/Regex.h" 17*5f757f3fSDimitry Andric 18*5f757f3fSDimitry Andric using namespace llvm; 19*5f757f3fSDimitry Andric using namespace remarks; 20*5f757f3fSDimitry Andric using namespace llvm::remarkutil; 21*5f757f3fSDimitry Andric 22*5f757f3fSDimitry Andric static cl::SubCommand CountSub("count", 23*5f757f3fSDimitry Andric "Collect remarks based on specified criteria."); 24*5f757f3fSDimitry Andric 25*5f757f3fSDimitry Andric INPUT_FORMAT_COMMAND_LINE_OPTIONS(CountSub) 26*5f757f3fSDimitry Andric INPUT_OUTPUT_COMMAND_LINE_OPTIONS(CountSub) 27*5f757f3fSDimitry Andric 28*5f757f3fSDimitry Andric static cl::list<std::string> 29*5f757f3fSDimitry Andric Keys("args", cl::desc("Specify remark argument/s to count by."), 30*5f757f3fSDimitry Andric cl::value_desc("arguments"), cl::sub(CountSub), cl::ValueOptional); 31*5f757f3fSDimitry Andric static cl::list<std::string> RKeys( 32*5f757f3fSDimitry Andric "rargs", 33*5f757f3fSDimitry Andric cl::desc( 34*5f757f3fSDimitry Andric "Specify remark argument/s to count (accepts regular expressions)."), 35*5f757f3fSDimitry Andric cl::value_desc("arguments"), cl::sub(CountSub), cl::ValueOptional); 36*5f757f3fSDimitry Andric static cl::opt<std::string> 37*5f757f3fSDimitry Andric RemarkNameOpt("remark-name", 38*5f757f3fSDimitry Andric cl::desc("Optional remark name to filter collection by."), 39*5f757f3fSDimitry Andric cl::ValueOptional, cl::sub(CountSub)); 40*5f757f3fSDimitry Andric static cl::opt<std::string> 41*5f757f3fSDimitry Andric PassNameOpt("pass-name", cl::ValueOptional, 42*5f757f3fSDimitry Andric cl::desc("Optional remark pass name to filter collection by."), 43*5f757f3fSDimitry Andric cl::sub(CountSub)); 44*5f757f3fSDimitry Andric 45*5f757f3fSDimitry Andric static cl::opt<std::string> RemarkFilterArgByOpt( 46*5f757f3fSDimitry Andric "filter-arg-by", cl::desc("Optional remark arg to filter collection by."), 47*5f757f3fSDimitry Andric cl::ValueOptional, cl::sub(CountSub)); 48*5f757f3fSDimitry Andric static cl::opt<std::string> 49*5f757f3fSDimitry Andric RemarkNameOptRE("rremark-name", 50*5f757f3fSDimitry Andric cl::desc("Optional remark name to filter collection by " 51*5f757f3fSDimitry Andric "(accepts regular expressions)."), 52*5f757f3fSDimitry Andric cl::ValueOptional, cl::sub(CountSub)); 53*5f757f3fSDimitry Andric static cl::opt<std::string> 54*5f757f3fSDimitry Andric RemarkArgFilterOptRE("rfilter-arg-by", 55*5f757f3fSDimitry Andric cl::desc("Optional remark arg to filter collection by " 56*5f757f3fSDimitry Andric "(accepts regular expressions)."), 57*5f757f3fSDimitry Andric cl::sub(CountSub), cl::ValueOptional); 58*5f757f3fSDimitry Andric static cl::opt<std::string> 59*5f757f3fSDimitry Andric PassNameOptRE("rpass-name", cl::ValueOptional, 60*5f757f3fSDimitry Andric cl::desc("Optional remark pass name to filter collection " 61*5f757f3fSDimitry Andric "by (accepts regular expressions)."), 62*5f757f3fSDimitry Andric cl::sub(CountSub)); 63*5f757f3fSDimitry Andric static cl::opt<Type> RemarkTypeOpt( 64*5f757f3fSDimitry Andric "remark-type", cl::desc("Optional remark type to filter collection by."), 65*5f757f3fSDimitry Andric cl::values(clEnumValN(Type::Unknown, "unknown", "UNKOWN"), 66*5f757f3fSDimitry Andric clEnumValN(Type::Passed, "passed", "PASSED"), 67*5f757f3fSDimitry Andric clEnumValN(Type::Missed, "missed", "MISSED"), 68*5f757f3fSDimitry Andric clEnumValN(Type::Analysis, "analysis", "ANALYSIS"), 69*5f757f3fSDimitry Andric clEnumValN(Type::AnalysisFPCommute, "analysis-fp-commute", 70*5f757f3fSDimitry Andric "ANALYSIS_FP_COMMUTE"), 71*5f757f3fSDimitry Andric clEnumValN(Type::AnalysisAliasing, "analysis-aliasing", 72*5f757f3fSDimitry Andric "ANALYSIS_ALIASING"), 73*5f757f3fSDimitry Andric clEnumValN(Type::Failure, "failure", "FAILURE")), 74*5f757f3fSDimitry Andric cl::init(Type::Failure), cl::sub(CountSub)); 75*5f757f3fSDimitry Andric static cl::opt<CountBy> CountByOpt( 76*5f757f3fSDimitry Andric "count-by", cl::desc("Specify the property to collect remarks by."), 77*5f757f3fSDimitry Andric cl::values( 78*5f757f3fSDimitry Andric clEnumValN(CountBy::REMARK, "remark-name", 79*5f757f3fSDimitry Andric "Counts individual remarks based on how many of the remark " 80*5f757f3fSDimitry Andric "exists."), 81*5f757f3fSDimitry Andric clEnumValN(CountBy::ARGUMENT, "arg", 82*5f757f3fSDimitry Andric "Counts based on the value each specified argument has. The " 83*5f757f3fSDimitry Andric "argument has to have a number value to be considered.")), 84*5f757f3fSDimitry Andric cl::init(CountBy::REMARK), cl::sub(CountSub)); 85*5f757f3fSDimitry Andric static cl::opt<GroupBy> GroupByOpt( 86*5f757f3fSDimitry Andric "group-by", cl::desc("Specify the property to group remarks by."), 87*5f757f3fSDimitry Andric cl::values( 88*5f757f3fSDimitry Andric clEnumValN( 89*5f757f3fSDimitry Andric GroupBy::PER_SOURCE, "source", 90*5f757f3fSDimitry Andric "Display the count broken down by the filepath of each remark " 91*5f757f3fSDimitry Andric "emitted. Requires remarks to have DebugLoc information."), 92*5f757f3fSDimitry Andric clEnumValN(GroupBy::PER_FUNCTION, "function", 93*5f757f3fSDimitry Andric "Breakdown the count by function name."), 94*5f757f3fSDimitry Andric clEnumValN( 95*5f757f3fSDimitry Andric GroupBy::PER_FUNCTION_WITH_DEBUG_LOC, "function-with-loc", 96*5f757f3fSDimitry Andric "Breakdown the count by function name taking into consideration " 97*5f757f3fSDimitry Andric "the filepath info from the DebugLoc of the remark."), 98*5f757f3fSDimitry Andric clEnumValN(GroupBy::TOTAL, "total", 99*5f757f3fSDimitry Andric "Output the total number corresponding to the count for the " 100*5f757f3fSDimitry Andric "provided input file.")), 101*5f757f3fSDimitry Andric cl::init(GroupBy::PER_SOURCE), cl::sub(CountSub)); 102*5f757f3fSDimitry Andric 103*5f757f3fSDimitry Andric /// Look for matching argument with \p Key in \p Remark and return the parsed 104*5f757f3fSDimitry Andric /// integer value or 0 if it is has no integer value. 105*5f757f3fSDimitry Andric static unsigned getValForKey(StringRef Key, const Remark &Remark) { 106*5f757f3fSDimitry Andric auto *RemarkArg = find_if(Remark.Args, [&Key](const Argument &Arg) { 107*5f757f3fSDimitry Andric return Arg.Key == Key && Arg.isValInt(); 108*5f757f3fSDimitry Andric }); 109*5f757f3fSDimitry Andric if (RemarkArg == Remark.Args.end()) 110*5f757f3fSDimitry Andric return 0; 111*5f757f3fSDimitry Andric return *RemarkArg->getValAsInt(); 112*5f757f3fSDimitry Andric } 113*5f757f3fSDimitry Andric 114*5f757f3fSDimitry Andric Error Filters::regexArgumentsValid() { 115*5f757f3fSDimitry Andric if (RemarkNameFilter && RemarkNameFilter->IsRegex) 116*5f757f3fSDimitry Andric if (auto E = checkRegex(RemarkNameFilter->FilterRE)) 117*5f757f3fSDimitry Andric return E; 118*5f757f3fSDimitry Andric if (PassNameFilter && PassNameFilter->IsRegex) 119*5f757f3fSDimitry Andric if (auto E = checkRegex(PassNameFilter->FilterRE)) 120*5f757f3fSDimitry Andric return E; 121*5f757f3fSDimitry Andric if (ArgFilter && ArgFilter->IsRegex) 122*5f757f3fSDimitry Andric if (auto E = checkRegex(ArgFilter->FilterRE)) 123*5f757f3fSDimitry Andric return E; 124*5f757f3fSDimitry Andric return Error::success(); 125*5f757f3fSDimitry Andric } 126*5f757f3fSDimitry Andric 127*5f757f3fSDimitry Andric bool Filters::filterRemark(const Remark &Remark) { 128*5f757f3fSDimitry Andric if (RemarkNameFilter && !RemarkNameFilter->match(Remark.RemarkName)) 129*5f757f3fSDimitry Andric return false; 130*5f757f3fSDimitry Andric if (PassNameFilter && !PassNameFilter->match(Remark.PassName)) 131*5f757f3fSDimitry Andric return false; 132*5f757f3fSDimitry Andric if (RemarkTypeFilter) 133*5f757f3fSDimitry Andric return *RemarkTypeFilter == Remark.RemarkType; 134*5f757f3fSDimitry Andric if (ArgFilter) { 135*5f757f3fSDimitry Andric if (!any_of(Remark.Args, 136*5f757f3fSDimitry Andric [this](Argument Arg) { return ArgFilter->match(Arg.Val); })) 137*5f757f3fSDimitry Andric return false; 138*5f757f3fSDimitry Andric } 139*5f757f3fSDimitry Andric return true; 140*5f757f3fSDimitry Andric } 141*5f757f3fSDimitry Andric 142*5f757f3fSDimitry Andric Error ArgumentCounter::getAllMatchingArgumentsInRemark( 143*5f757f3fSDimitry Andric StringRef Buffer, ArrayRef<FilterMatcher> Arguments, Filters &Filter) { 144*5f757f3fSDimitry Andric auto MaybeParser = createRemarkParser(InputFormat, Buffer); 145*5f757f3fSDimitry Andric if (!MaybeParser) 146*5f757f3fSDimitry Andric return MaybeParser.takeError(); 147*5f757f3fSDimitry Andric auto &Parser = **MaybeParser; 148*5f757f3fSDimitry Andric auto MaybeRemark = Parser.next(); 149*5f757f3fSDimitry Andric for (; MaybeRemark; MaybeRemark = Parser.next()) { 150*5f757f3fSDimitry Andric auto &Remark = **MaybeRemark; 151*5f757f3fSDimitry Andric // Only collect keys from remarks included in the filter. 152*5f757f3fSDimitry Andric if (!Filter.filterRemark(Remark)) 153*5f757f3fSDimitry Andric continue; 154*5f757f3fSDimitry Andric for (auto &Key : Arguments) { 155*5f757f3fSDimitry Andric for (Argument Arg : Remark.Args) 156*5f757f3fSDimitry Andric if (Key.match(Arg.Key) && Arg.isValInt()) 157*5f757f3fSDimitry Andric ArgumentSetIdxMap.insert({Arg.Key, ArgumentSetIdxMap.size()}); 158*5f757f3fSDimitry Andric } 159*5f757f3fSDimitry Andric } 160*5f757f3fSDimitry Andric 161*5f757f3fSDimitry Andric auto E = MaybeRemark.takeError(); 162*5f757f3fSDimitry Andric if (!E.isA<EndOfFileError>()) 163*5f757f3fSDimitry Andric return E; 164*5f757f3fSDimitry Andric consumeError(std::move(E)); 165*5f757f3fSDimitry Andric return Error::success(); 166*5f757f3fSDimitry Andric } 167*5f757f3fSDimitry Andric 168*5f757f3fSDimitry Andric std::optional<std::string> Counter::getGroupByKey(const Remark &Remark) { 169*5f757f3fSDimitry Andric switch (Group) { 170*5f757f3fSDimitry Andric case GroupBy::PER_FUNCTION: 171*5f757f3fSDimitry Andric return Remark.FunctionName.str(); 172*5f757f3fSDimitry Andric case GroupBy::TOTAL: 173*5f757f3fSDimitry Andric return "Total"; 174*5f757f3fSDimitry Andric case GroupBy::PER_SOURCE: 175*5f757f3fSDimitry Andric case GroupBy::PER_FUNCTION_WITH_DEBUG_LOC: 176*5f757f3fSDimitry Andric if (!Remark.Loc.has_value()) 177*5f757f3fSDimitry Andric return std::nullopt; 178*5f757f3fSDimitry Andric 179*5f757f3fSDimitry Andric if (Group == GroupBy::PER_FUNCTION_WITH_DEBUG_LOC) 180*5f757f3fSDimitry Andric return Remark.Loc->SourceFilePath.str() + ":" + Remark.FunctionName.str(); 181*5f757f3fSDimitry Andric return Remark.Loc->SourceFilePath.str(); 182*5f757f3fSDimitry Andric } 183*5f757f3fSDimitry Andric llvm_unreachable("Fully covered switch above!"); 184*5f757f3fSDimitry Andric } 185*5f757f3fSDimitry Andric 186*5f757f3fSDimitry Andric void ArgumentCounter::collect(const Remark &Remark) { 187*5f757f3fSDimitry Andric SmallVector<unsigned, 4> Row(ArgumentSetIdxMap.size()); 188*5f757f3fSDimitry Andric std::optional<std::string> GroupByKey = getGroupByKey(Remark); 189*5f757f3fSDimitry Andric // Early return if we don't have a value 190*5f757f3fSDimitry Andric if (!GroupByKey) 191*5f757f3fSDimitry Andric return; 192*5f757f3fSDimitry Andric auto GroupVal = *GroupByKey; 193*5f757f3fSDimitry Andric CountByKeysMap.insert({GroupVal, Row}); 194*5f757f3fSDimitry Andric for (auto [Key, Idx] : ArgumentSetIdxMap) { 195*5f757f3fSDimitry Andric auto Count = getValForKey(Key, Remark); 196*5f757f3fSDimitry Andric CountByKeysMap[GroupVal][Idx] += Count; 197*5f757f3fSDimitry Andric } 198*5f757f3fSDimitry Andric } 199*5f757f3fSDimitry Andric 200*5f757f3fSDimitry Andric void RemarkCounter::collect(const Remark &Remark) { 201*5f757f3fSDimitry Andric std::optional<std::string> Key = getGroupByKey(Remark); 202*5f757f3fSDimitry Andric if (!Key.has_value()) 203*5f757f3fSDimitry Andric return; 204*5f757f3fSDimitry Andric auto Iter = CountedByRemarksMap.insert({*Key, 1}); 205*5f757f3fSDimitry Andric if (!Iter.second) 206*5f757f3fSDimitry Andric Iter.first->second += 1; 207*5f757f3fSDimitry Andric } 208*5f757f3fSDimitry Andric 209*5f757f3fSDimitry Andric Error ArgumentCounter::print(StringRef OutputFileName) { 210*5f757f3fSDimitry Andric auto MaybeOF = 211*5f757f3fSDimitry Andric getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF); 212*5f757f3fSDimitry Andric if (!MaybeOF) 213*5f757f3fSDimitry Andric return MaybeOF.takeError(); 214*5f757f3fSDimitry Andric 215*5f757f3fSDimitry Andric auto OF = std::move(*MaybeOF); 216*5f757f3fSDimitry Andric OF->os() << groupByToStr(Group) << ","; 217*5f757f3fSDimitry Andric unsigned Idx = 0; 218*5f757f3fSDimitry Andric for (auto [Key, _] : ArgumentSetIdxMap) { 219*5f757f3fSDimitry Andric OF->os() << Key; 220*5f757f3fSDimitry Andric if (Idx != ArgumentSetIdxMap.size() - 1) 221*5f757f3fSDimitry Andric OF->os() << ","; 222*5f757f3fSDimitry Andric Idx++; 223*5f757f3fSDimitry Andric } 224*5f757f3fSDimitry Andric OF->os() << "\n"; 225*5f757f3fSDimitry Andric for (auto [Header, CountVector] : CountByKeysMap) { 226*5f757f3fSDimitry Andric OF->os() << Header << ","; 227*5f757f3fSDimitry Andric unsigned Idx = 0; 228*5f757f3fSDimitry Andric for (auto Count : CountVector) { 229*5f757f3fSDimitry Andric OF->os() << Count; 230*5f757f3fSDimitry Andric if (Idx != ArgumentSetIdxMap.size() - 1) 231*5f757f3fSDimitry Andric OF->os() << ","; 232*5f757f3fSDimitry Andric Idx++; 233*5f757f3fSDimitry Andric } 234*5f757f3fSDimitry Andric OF->os() << "\n"; 235*5f757f3fSDimitry Andric } 236*5f757f3fSDimitry Andric return Error::success(); 237*5f757f3fSDimitry Andric } 238*5f757f3fSDimitry Andric 239*5f757f3fSDimitry Andric Error RemarkCounter::print(StringRef OutputFileName) { 240*5f757f3fSDimitry Andric auto MaybeOF = 241*5f757f3fSDimitry Andric getOutputFileWithFlags(OutputFileName, sys::fs::OF_TextWithCRLF); 242*5f757f3fSDimitry Andric if (!MaybeOF) 243*5f757f3fSDimitry Andric return MaybeOF.takeError(); 244*5f757f3fSDimitry Andric 245*5f757f3fSDimitry Andric auto OF = std::move(*MaybeOF); 246*5f757f3fSDimitry Andric OF->os() << groupByToStr(Group) << "," 247*5f757f3fSDimitry Andric << "Count\n"; 248*5f757f3fSDimitry Andric for (auto [Key, Count] : CountedByRemarksMap) 249*5f757f3fSDimitry Andric OF->os() << Key << "," << Count << "\n"; 250*5f757f3fSDimitry Andric OF->keep(); 251*5f757f3fSDimitry Andric return Error::success(); 252*5f757f3fSDimitry Andric } 253*5f757f3fSDimitry Andric 254*5f757f3fSDimitry Andric Expected<Filters> getRemarkFilter() { 255*5f757f3fSDimitry Andric // Create Filter properties. 256*5f757f3fSDimitry Andric std::optional<FilterMatcher> RemarkNameFilter; 257*5f757f3fSDimitry Andric std::optional<FilterMatcher> PassNameFilter; 258*5f757f3fSDimitry Andric std::optional<FilterMatcher> RemarkArgFilter; 259*5f757f3fSDimitry Andric std::optional<Type> RemarkType; 260*5f757f3fSDimitry Andric if (!RemarkNameOpt.empty()) 261*5f757f3fSDimitry Andric RemarkNameFilter = {RemarkNameOpt, false}; 262*5f757f3fSDimitry Andric else if (!RemarkNameOptRE.empty()) 263*5f757f3fSDimitry Andric RemarkNameFilter = {RemarkNameOptRE, true}; 264*5f757f3fSDimitry Andric if (!PassNameOpt.empty()) 265*5f757f3fSDimitry Andric PassNameFilter = {PassNameOpt, false}; 266*5f757f3fSDimitry Andric else if (!PassNameOptRE.empty()) 267*5f757f3fSDimitry Andric PassNameFilter = {PassNameOptRE, true}; 268*5f757f3fSDimitry Andric if (RemarkTypeOpt != Type::Failure) 269*5f757f3fSDimitry Andric RemarkType = RemarkTypeOpt; 270*5f757f3fSDimitry Andric if (!RemarkFilterArgByOpt.empty()) 271*5f757f3fSDimitry Andric RemarkArgFilter = {RemarkFilterArgByOpt, false}; 272*5f757f3fSDimitry Andric else if (!RemarkArgFilterOptRE.empty()) 273*5f757f3fSDimitry Andric RemarkArgFilter = {RemarkArgFilterOptRE, true}; 274*5f757f3fSDimitry Andric // Create RemarkFilter. 275*5f757f3fSDimitry Andric return Filters::createRemarkFilter(std::move(RemarkNameFilter), 276*5f757f3fSDimitry Andric std::move(PassNameFilter), 277*5f757f3fSDimitry Andric std::move(RemarkArgFilter), RemarkType); 278*5f757f3fSDimitry Andric } 279*5f757f3fSDimitry Andric 280*5f757f3fSDimitry Andric Error useCollectRemark(StringRef Buffer, Counter &Counter, Filters &Filter) { 281*5f757f3fSDimitry Andric // Create Parser. 282*5f757f3fSDimitry Andric auto MaybeParser = createRemarkParser(InputFormat, Buffer); 283*5f757f3fSDimitry Andric if (!MaybeParser) 284*5f757f3fSDimitry Andric return MaybeParser.takeError(); 285*5f757f3fSDimitry Andric auto &Parser = **MaybeParser; 286*5f757f3fSDimitry Andric auto MaybeRemark = Parser.next(); 287*5f757f3fSDimitry Andric for (; MaybeRemark; MaybeRemark = Parser.next()) { 288*5f757f3fSDimitry Andric const Remark &Remark = **MaybeRemark; 289*5f757f3fSDimitry Andric if (Filter.filterRemark(Remark)) 290*5f757f3fSDimitry Andric Counter.collect(Remark); 291*5f757f3fSDimitry Andric } 292*5f757f3fSDimitry Andric 293*5f757f3fSDimitry Andric if (auto E = Counter.print(OutputFileName)) 294*5f757f3fSDimitry Andric return E; 295*5f757f3fSDimitry Andric auto E = MaybeRemark.takeError(); 296*5f757f3fSDimitry Andric if (!E.isA<EndOfFileError>()) 297*5f757f3fSDimitry Andric return E; 298*5f757f3fSDimitry Andric consumeError(std::move(E)); 299*5f757f3fSDimitry Andric return Error::success(); 300*5f757f3fSDimitry Andric } 301*5f757f3fSDimitry Andric 302*5f757f3fSDimitry Andric static Error collectRemarks() { 303*5f757f3fSDimitry Andric // Create a parser for the user-specified input format. 304*5f757f3fSDimitry Andric auto MaybeBuf = getInputMemoryBuffer(InputFileName); 305*5f757f3fSDimitry Andric if (!MaybeBuf) 306*5f757f3fSDimitry Andric return MaybeBuf.takeError(); 307*5f757f3fSDimitry Andric StringRef Buffer = (*MaybeBuf)->getBuffer(); 308*5f757f3fSDimitry Andric auto MaybeFilter = getRemarkFilter(); 309*5f757f3fSDimitry Andric if (!MaybeFilter) 310*5f757f3fSDimitry Andric return MaybeFilter.takeError(); 311*5f757f3fSDimitry Andric auto &Filter = *MaybeFilter; 312*5f757f3fSDimitry Andric if (CountByOpt == CountBy::REMARK) { 313*5f757f3fSDimitry Andric RemarkCounter RC(GroupByOpt); 314*5f757f3fSDimitry Andric if (auto E = useCollectRemark(Buffer, RC, Filter)) 315*5f757f3fSDimitry Andric return E; 316*5f757f3fSDimitry Andric } else if (CountByOpt == CountBy::ARGUMENT) { 317*5f757f3fSDimitry Andric SmallVector<FilterMatcher, 4> ArgumentsVector; 318*5f757f3fSDimitry Andric if (!Keys.empty()) { 319*5f757f3fSDimitry Andric for (auto &Key : Keys) 320*5f757f3fSDimitry Andric ArgumentsVector.push_back({Key, false}); 321*5f757f3fSDimitry Andric } else if (!RKeys.empty()) 322*5f757f3fSDimitry Andric for (auto Key : RKeys) 323*5f757f3fSDimitry Andric ArgumentsVector.push_back({Key, true}); 324*5f757f3fSDimitry Andric else 325*5f757f3fSDimitry Andric ArgumentsVector.push_back({".*", true}); 326*5f757f3fSDimitry Andric 327*5f757f3fSDimitry Andric Expected<ArgumentCounter> AC = ArgumentCounter::createArgumentCounter( 328*5f757f3fSDimitry Andric GroupByOpt, ArgumentsVector, Buffer, Filter); 329*5f757f3fSDimitry Andric if (!AC) 330*5f757f3fSDimitry Andric return AC.takeError(); 331*5f757f3fSDimitry Andric if (auto E = useCollectRemark(Buffer, *AC, Filter)) 332*5f757f3fSDimitry Andric return E; 333*5f757f3fSDimitry Andric } 334*5f757f3fSDimitry Andric return Error::success(); 335*5f757f3fSDimitry Andric } 336*5f757f3fSDimitry Andric 337*5f757f3fSDimitry Andric static CommandRegistration CountReg(&CountSub, collectRemarks); 338