1*0b57cec5SDimitry Andric //===- YAMLRemarkParser.cpp -----------------------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file provides utility methods used by clients that want to use the 10*0b57cec5SDimitry Andric // parser for remark diagnostics in LLVM. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "YAMLRemarkParser.h" 15*0b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 16*0b57cec5SDimitry Andric #include "llvm/Remarks/RemarkParser.h" 17*0b57cec5SDimitry Andric 18*0b57cec5SDimitry Andric using namespace llvm; 19*0b57cec5SDimitry Andric using namespace llvm::remarks; 20*0b57cec5SDimitry Andric 21*0b57cec5SDimitry Andric char YAMLParseError::ID = 0; 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric static void handleDiagnostic(const SMDiagnostic &Diag, void *Ctx) { 24*0b57cec5SDimitry Andric assert(Ctx && "Expected non-null Ctx in diagnostic handler."); 25*0b57cec5SDimitry Andric std::string &Message = *static_cast<std::string *>(Ctx); 26*0b57cec5SDimitry Andric assert(Message.empty() && "Expected an empty string."); 27*0b57cec5SDimitry Andric raw_string_ostream OS(Message); 28*0b57cec5SDimitry Andric Diag.print(/*ProgName=*/nullptr, OS, /*ShowColors*/ false, 29*0b57cec5SDimitry Andric /*ShowKindLabels*/ true); 30*0b57cec5SDimitry Andric OS << '\n'; 31*0b57cec5SDimitry Andric OS.flush(); 32*0b57cec5SDimitry Andric } 33*0b57cec5SDimitry Andric 34*0b57cec5SDimitry Andric YAMLParseError::YAMLParseError(StringRef Msg, SourceMgr &SM, 35*0b57cec5SDimitry Andric yaml::Stream &Stream, yaml::Node &Node) { 36*0b57cec5SDimitry Andric // 1) Set up a diagnostic handler to avoid errors being printed out to 37*0b57cec5SDimitry Andric // stderr. 38*0b57cec5SDimitry Andric // 2) Use the stream to print the error with the associated node. 39*0b57cec5SDimitry Andric // 3) The stream will use the source manager to print the error, which will 40*0b57cec5SDimitry Andric // call the diagnostic handler. 41*0b57cec5SDimitry Andric // 4) The diagnostic handler will stream the error directly into this object's 42*0b57cec5SDimitry Andric // Message member, which is used when logging is asked for. 43*0b57cec5SDimitry Andric auto OldDiagHandler = SM.getDiagHandler(); 44*0b57cec5SDimitry Andric auto OldDiagCtx = SM.getDiagContext(); 45*0b57cec5SDimitry Andric SM.setDiagHandler(handleDiagnostic, &Message); 46*0b57cec5SDimitry Andric Stream.printError(&Node, Twine(Msg) + Twine('\n')); 47*0b57cec5SDimitry Andric // Restore the old handlers. 48*0b57cec5SDimitry Andric SM.setDiagHandler(OldDiagHandler, OldDiagCtx); 49*0b57cec5SDimitry Andric } 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric static SourceMgr setupSM(std::string &LastErrorMessage) { 52*0b57cec5SDimitry Andric SourceMgr SM; 53*0b57cec5SDimitry Andric SM.setDiagHandler(handleDiagnostic, &LastErrorMessage); 54*0b57cec5SDimitry Andric return SM; 55*0b57cec5SDimitry Andric } 56*0b57cec5SDimitry Andric 57*0b57cec5SDimitry Andric YAMLRemarkParser::YAMLRemarkParser(StringRef Buf, 58*0b57cec5SDimitry Andric Optional<const ParsedStringTable *> StrTab) 59*0b57cec5SDimitry Andric : Parser{Format::YAML}, StrTab(StrTab), LastErrorMessage(), 60*0b57cec5SDimitry Andric SM(setupSM(LastErrorMessage)), Stream(Buf, SM), YAMLIt(Stream.begin()) {} 61*0b57cec5SDimitry Andric 62*0b57cec5SDimitry Andric Error YAMLRemarkParser::error(StringRef Message, yaml::Node &Node) { 63*0b57cec5SDimitry Andric return make_error<YAMLParseError>(Message, SM, Stream, Node); 64*0b57cec5SDimitry Andric } 65*0b57cec5SDimitry Andric 66*0b57cec5SDimitry Andric Error YAMLRemarkParser::error() { 67*0b57cec5SDimitry Andric if (LastErrorMessage.empty()) 68*0b57cec5SDimitry Andric return Error::success(); 69*0b57cec5SDimitry Andric Error E = make_error<YAMLParseError>(LastErrorMessage); 70*0b57cec5SDimitry Andric LastErrorMessage.clear(); 71*0b57cec5SDimitry Andric return E; 72*0b57cec5SDimitry Andric } 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric Expected<std::unique_ptr<Remark>> 75*0b57cec5SDimitry Andric YAMLRemarkParser::parseRemark(yaml::Document &RemarkEntry) { 76*0b57cec5SDimitry Andric if (Error E = error()) 77*0b57cec5SDimitry Andric return std::move(E); 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric yaml::Node *YAMLRoot = RemarkEntry.getRoot(); 80*0b57cec5SDimitry Andric if (!YAMLRoot) { 81*0b57cec5SDimitry Andric return createStringError(std::make_error_code(std::errc::invalid_argument), 82*0b57cec5SDimitry Andric "not a valid YAML file."); 83*0b57cec5SDimitry Andric } 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric auto *Root = dyn_cast<yaml::MappingNode>(YAMLRoot); 86*0b57cec5SDimitry Andric if (!Root) 87*0b57cec5SDimitry Andric return error("document root is not of mapping type.", *YAMLRoot); 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric std::unique_ptr<Remark> Result = llvm::make_unique<Remark>(); 90*0b57cec5SDimitry Andric Remark &TheRemark = *Result; 91*0b57cec5SDimitry Andric 92*0b57cec5SDimitry Andric // First, the type. It needs special handling since is not part of the 93*0b57cec5SDimitry Andric // key-value stream. 94*0b57cec5SDimitry Andric Expected<Type> T = parseType(*Root); 95*0b57cec5SDimitry Andric if (!T) 96*0b57cec5SDimitry Andric return T.takeError(); 97*0b57cec5SDimitry Andric else 98*0b57cec5SDimitry Andric TheRemark.RemarkType = *T; 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric // Then, parse the fields, one by one. 101*0b57cec5SDimitry Andric for (yaml::KeyValueNode &RemarkField : *Root) { 102*0b57cec5SDimitry Andric Expected<StringRef> MaybeKey = parseKey(RemarkField); 103*0b57cec5SDimitry Andric if (!MaybeKey) 104*0b57cec5SDimitry Andric return MaybeKey.takeError(); 105*0b57cec5SDimitry Andric StringRef KeyName = *MaybeKey; 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric if (KeyName == "Pass") { 108*0b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(RemarkField)) 109*0b57cec5SDimitry Andric TheRemark.PassName = *MaybeStr; 110*0b57cec5SDimitry Andric else 111*0b57cec5SDimitry Andric return MaybeStr.takeError(); 112*0b57cec5SDimitry Andric } else if (KeyName == "Name") { 113*0b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(RemarkField)) 114*0b57cec5SDimitry Andric TheRemark.RemarkName = *MaybeStr; 115*0b57cec5SDimitry Andric else 116*0b57cec5SDimitry Andric return MaybeStr.takeError(); 117*0b57cec5SDimitry Andric } else if (KeyName == "Function") { 118*0b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(RemarkField)) 119*0b57cec5SDimitry Andric TheRemark.FunctionName = *MaybeStr; 120*0b57cec5SDimitry Andric else 121*0b57cec5SDimitry Andric return MaybeStr.takeError(); 122*0b57cec5SDimitry Andric } else if (KeyName == "Hotness") { 123*0b57cec5SDimitry Andric if (Expected<unsigned> MaybeU = parseUnsigned(RemarkField)) 124*0b57cec5SDimitry Andric TheRemark.Hotness = *MaybeU; 125*0b57cec5SDimitry Andric else 126*0b57cec5SDimitry Andric return MaybeU.takeError(); 127*0b57cec5SDimitry Andric } else if (KeyName == "DebugLoc") { 128*0b57cec5SDimitry Andric if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(RemarkField)) 129*0b57cec5SDimitry Andric TheRemark.Loc = *MaybeLoc; 130*0b57cec5SDimitry Andric else 131*0b57cec5SDimitry Andric return MaybeLoc.takeError(); 132*0b57cec5SDimitry Andric } else if (KeyName == "Args") { 133*0b57cec5SDimitry Andric auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue()); 134*0b57cec5SDimitry Andric if (!Args) 135*0b57cec5SDimitry Andric return error("wrong value type for key.", RemarkField); 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric for (yaml::Node &Arg : *Args) { 138*0b57cec5SDimitry Andric if (Expected<Argument> MaybeArg = parseArg(Arg)) 139*0b57cec5SDimitry Andric TheRemark.Args.push_back(*MaybeArg); 140*0b57cec5SDimitry Andric else 141*0b57cec5SDimitry Andric return MaybeArg.takeError(); 142*0b57cec5SDimitry Andric } 143*0b57cec5SDimitry Andric } else { 144*0b57cec5SDimitry Andric return error("unknown key.", RemarkField); 145*0b57cec5SDimitry Andric } 146*0b57cec5SDimitry Andric } 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric // Check if any of the mandatory fields are missing. 149*0b57cec5SDimitry Andric if (TheRemark.RemarkType == Type::Unknown || TheRemark.PassName.empty() || 150*0b57cec5SDimitry Andric TheRemark.RemarkName.empty() || TheRemark.FunctionName.empty()) 151*0b57cec5SDimitry Andric return error("Type, Pass, Name or Function missing.", 152*0b57cec5SDimitry Andric *RemarkEntry.getRoot()); 153*0b57cec5SDimitry Andric 154*0b57cec5SDimitry Andric return std::move(Result); 155*0b57cec5SDimitry Andric } 156*0b57cec5SDimitry Andric 157*0b57cec5SDimitry Andric Expected<Type> YAMLRemarkParser::parseType(yaml::MappingNode &Node) { 158*0b57cec5SDimitry Andric auto Type = StringSwitch<remarks::Type>(Node.getRawTag()) 159*0b57cec5SDimitry Andric .Case("!Passed", remarks::Type::Passed) 160*0b57cec5SDimitry Andric .Case("!Missed", remarks::Type::Missed) 161*0b57cec5SDimitry Andric .Case("!Analysis", remarks::Type::Analysis) 162*0b57cec5SDimitry Andric .Case("!AnalysisFPCommute", remarks::Type::AnalysisFPCommute) 163*0b57cec5SDimitry Andric .Case("!AnalysisAliasing", remarks::Type::AnalysisAliasing) 164*0b57cec5SDimitry Andric .Case("!Failure", remarks::Type::Failure) 165*0b57cec5SDimitry Andric .Default(remarks::Type::Unknown); 166*0b57cec5SDimitry Andric if (Type == remarks::Type::Unknown) 167*0b57cec5SDimitry Andric return error("expected a remark tag.", Node); 168*0b57cec5SDimitry Andric return Type; 169*0b57cec5SDimitry Andric } 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric Expected<StringRef> YAMLRemarkParser::parseKey(yaml::KeyValueNode &Node) { 172*0b57cec5SDimitry Andric if (auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey())) 173*0b57cec5SDimitry Andric return Key->getRawValue(); 174*0b57cec5SDimitry Andric 175*0b57cec5SDimitry Andric return error("key is not a string.", Node); 176*0b57cec5SDimitry Andric } 177*0b57cec5SDimitry Andric 178*0b57cec5SDimitry Andric Expected<StringRef> YAMLRemarkParser::parseStr(yaml::KeyValueNode &Node) { 179*0b57cec5SDimitry Andric auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 180*0b57cec5SDimitry Andric if (!Value) 181*0b57cec5SDimitry Andric return error("expected a value of scalar type.", Node); 182*0b57cec5SDimitry Andric StringRef Result; 183*0b57cec5SDimitry Andric if (!StrTab) { 184*0b57cec5SDimitry Andric Result = Value->getRawValue(); 185*0b57cec5SDimitry Andric } else { 186*0b57cec5SDimitry Andric // If we have a string table, parse it as an unsigned. 187*0b57cec5SDimitry Andric unsigned StrID = 0; 188*0b57cec5SDimitry Andric if (Expected<unsigned> MaybeStrID = parseUnsigned(Node)) 189*0b57cec5SDimitry Andric StrID = *MaybeStrID; 190*0b57cec5SDimitry Andric else 191*0b57cec5SDimitry Andric return MaybeStrID.takeError(); 192*0b57cec5SDimitry Andric 193*0b57cec5SDimitry Andric if (Expected<StringRef> Str = (**StrTab)[StrID]) 194*0b57cec5SDimitry Andric Result = *Str; 195*0b57cec5SDimitry Andric else 196*0b57cec5SDimitry Andric return Str.takeError(); 197*0b57cec5SDimitry Andric } 198*0b57cec5SDimitry Andric 199*0b57cec5SDimitry Andric if (Result.front() == '\'') 200*0b57cec5SDimitry Andric Result = Result.drop_front(); 201*0b57cec5SDimitry Andric 202*0b57cec5SDimitry Andric if (Result.back() == '\'') 203*0b57cec5SDimitry Andric Result = Result.drop_back(); 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric return Result; 206*0b57cec5SDimitry Andric } 207*0b57cec5SDimitry Andric 208*0b57cec5SDimitry Andric Expected<unsigned> YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode &Node) { 209*0b57cec5SDimitry Andric SmallVector<char, 4> Tmp; 210*0b57cec5SDimitry Andric auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 211*0b57cec5SDimitry Andric if (!Value) 212*0b57cec5SDimitry Andric return error("expected a value of scalar type.", Node); 213*0b57cec5SDimitry Andric unsigned UnsignedValue = 0; 214*0b57cec5SDimitry Andric if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue)) 215*0b57cec5SDimitry Andric return error("expected a value of integer type.", *Value); 216*0b57cec5SDimitry Andric return UnsignedValue; 217*0b57cec5SDimitry Andric } 218*0b57cec5SDimitry Andric 219*0b57cec5SDimitry Andric Expected<RemarkLocation> 220*0b57cec5SDimitry Andric YAMLRemarkParser::parseDebugLoc(yaml::KeyValueNode &Node) { 221*0b57cec5SDimitry Andric auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue()); 222*0b57cec5SDimitry Andric if (!DebugLoc) 223*0b57cec5SDimitry Andric return error("expected a value of mapping type.", Node); 224*0b57cec5SDimitry Andric 225*0b57cec5SDimitry Andric Optional<StringRef> File; 226*0b57cec5SDimitry Andric Optional<unsigned> Line; 227*0b57cec5SDimitry Andric Optional<unsigned> Column; 228*0b57cec5SDimitry Andric 229*0b57cec5SDimitry Andric for (yaml::KeyValueNode &DLNode : *DebugLoc) { 230*0b57cec5SDimitry Andric Expected<StringRef> MaybeKey = parseKey(DLNode); 231*0b57cec5SDimitry Andric if (!MaybeKey) 232*0b57cec5SDimitry Andric return MaybeKey.takeError(); 233*0b57cec5SDimitry Andric StringRef KeyName = *MaybeKey; 234*0b57cec5SDimitry Andric 235*0b57cec5SDimitry Andric if (KeyName == "File") { 236*0b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(DLNode)) 237*0b57cec5SDimitry Andric File = *MaybeStr; 238*0b57cec5SDimitry Andric else 239*0b57cec5SDimitry Andric return MaybeStr.takeError(); 240*0b57cec5SDimitry Andric } else if (KeyName == "Column") { 241*0b57cec5SDimitry Andric if (Expected<unsigned> MaybeU = parseUnsigned(DLNode)) 242*0b57cec5SDimitry Andric Column = *MaybeU; 243*0b57cec5SDimitry Andric else 244*0b57cec5SDimitry Andric return MaybeU.takeError(); 245*0b57cec5SDimitry Andric } else if (KeyName == "Line") { 246*0b57cec5SDimitry Andric if (Expected<unsigned> MaybeU = parseUnsigned(DLNode)) 247*0b57cec5SDimitry Andric Line = *MaybeU; 248*0b57cec5SDimitry Andric else 249*0b57cec5SDimitry Andric return MaybeU.takeError(); 250*0b57cec5SDimitry Andric } else { 251*0b57cec5SDimitry Andric return error("unknown entry in DebugLoc map.", DLNode); 252*0b57cec5SDimitry Andric } 253*0b57cec5SDimitry Andric } 254*0b57cec5SDimitry Andric 255*0b57cec5SDimitry Andric // If any of the debug loc fields is missing, return an error. 256*0b57cec5SDimitry Andric if (!File || !Line || !Column) 257*0b57cec5SDimitry Andric return error("DebugLoc node incomplete.", Node); 258*0b57cec5SDimitry Andric 259*0b57cec5SDimitry Andric return RemarkLocation{*File, *Line, *Column}; 260*0b57cec5SDimitry Andric } 261*0b57cec5SDimitry Andric 262*0b57cec5SDimitry Andric Expected<Argument> YAMLRemarkParser::parseArg(yaml::Node &Node) { 263*0b57cec5SDimitry Andric auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node); 264*0b57cec5SDimitry Andric if (!ArgMap) 265*0b57cec5SDimitry Andric return error("expected a value of mapping type.", Node); 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric Optional<StringRef> KeyStr; 268*0b57cec5SDimitry Andric Optional<StringRef> ValueStr; 269*0b57cec5SDimitry Andric Optional<RemarkLocation> Loc; 270*0b57cec5SDimitry Andric 271*0b57cec5SDimitry Andric for (yaml::KeyValueNode &ArgEntry : *ArgMap) { 272*0b57cec5SDimitry Andric Expected<StringRef> MaybeKey = parseKey(ArgEntry); 273*0b57cec5SDimitry Andric if (!MaybeKey) 274*0b57cec5SDimitry Andric return MaybeKey.takeError(); 275*0b57cec5SDimitry Andric StringRef KeyName = *MaybeKey; 276*0b57cec5SDimitry Andric 277*0b57cec5SDimitry Andric // Try to parse debug locs. 278*0b57cec5SDimitry Andric if (KeyName == "DebugLoc") { 279*0b57cec5SDimitry Andric // Can't have multiple DebugLoc entries per argument. 280*0b57cec5SDimitry Andric if (Loc) 281*0b57cec5SDimitry Andric return error("only one DebugLoc entry is allowed per argument.", 282*0b57cec5SDimitry Andric ArgEntry); 283*0b57cec5SDimitry Andric 284*0b57cec5SDimitry Andric if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(ArgEntry)) { 285*0b57cec5SDimitry Andric Loc = *MaybeLoc; 286*0b57cec5SDimitry Andric continue; 287*0b57cec5SDimitry Andric } else 288*0b57cec5SDimitry Andric return MaybeLoc.takeError(); 289*0b57cec5SDimitry Andric } 290*0b57cec5SDimitry Andric 291*0b57cec5SDimitry Andric // If we already have a string, error out. 292*0b57cec5SDimitry Andric if (ValueStr) 293*0b57cec5SDimitry Andric return error("only one string entry is allowed per argument.", ArgEntry); 294*0b57cec5SDimitry Andric 295*0b57cec5SDimitry Andric // Try to parse the value. 296*0b57cec5SDimitry Andric if (Expected<StringRef> MaybeStr = parseStr(ArgEntry)) 297*0b57cec5SDimitry Andric ValueStr = *MaybeStr; 298*0b57cec5SDimitry Andric else 299*0b57cec5SDimitry Andric return MaybeStr.takeError(); 300*0b57cec5SDimitry Andric 301*0b57cec5SDimitry Andric // Keep the key from the string. 302*0b57cec5SDimitry Andric KeyStr = KeyName; 303*0b57cec5SDimitry Andric } 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric if (!KeyStr) 306*0b57cec5SDimitry Andric return error("argument key is missing.", *ArgMap); 307*0b57cec5SDimitry Andric if (!ValueStr) 308*0b57cec5SDimitry Andric return error("argument value is missing.", *ArgMap); 309*0b57cec5SDimitry Andric 310*0b57cec5SDimitry Andric return Argument{*KeyStr, *ValueStr, Loc}; 311*0b57cec5SDimitry Andric } 312*0b57cec5SDimitry Andric 313*0b57cec5SDimitry Andric Expected<std::unique_ptr<Remark>> YAMLRemarkParser::next() { 314*0b57cec5SDimitry Andric if (YAMLIt == Stream.end()) 315*0b57cec5SDimitry Andric return make_error<EndOfFileError>(); 316*0b57cec5SDimitry Andric 317*0b57cec5SDimitry Andric Expected<std::unique_ptr<Remark>> MaybeResult = parseRemark(*YAMLIt); 318*0b57cec5SDimitry Andric if (!MaybeResult) { 319*0b57cec5SDimitry Andric // Avoid garbage input, set the iterator to the end. 320*0b57cec5SDimitry Andric YAMLIt = Stream.end(); 321*0b57cec5SDimitry Andric return MaybeResult.takeError(); 322*0b57cec5SDimitry Andric } 323*0b57cec5SDimitry Andric 324*0b57cec5SDimitry Andric ++YAMLIt; 325*0b57cec5SDimitry Andric 326*0b57cec5SDimitry Andric return std::move(*MaybeResult); 327*0b57cec5SDimitry Andric } 328