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