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 Optional<const ParsedStringTable *> StrTab) 59 : Parser{Format::YAML}, StrTab(StrTab), LastErrorMessage(), 60 SM(setupSM(LastErrorMessage)), Stream(Buf, SM), YAMLIt(Stream.begin()) {} 61 62 Error YAMLRemarkParser::error(StringRef Message, yaml::Node &Node) { 63 return make_error<YAMLParseError>(Message, SM, Stream, Node); 64 } 65 66 Error YAMLRemarkParser::error() { 67 if (LastErrorMessage.empty()) 68 return Error::success(); 69 Error E = make_error<YAMLParseError>(LastErrorMessage); 70 LastErrorMessage.clear(); 71 return E; 72 } 73 74 Expected<std::unique_ptr<Remark>> 75 YAMLRemarkParser::parseRemark(yaml::Document &RemarkEntry) { 76 if (Error E = error()) 77 return std::move(E); 78 79 yaml::Node *YAMLRoot = RemarkEntry.getRoot(); 80 if (!YAMLRoot) { 81 return createStringError(std::make_error_code(std::errc::invalid_argument), 82 "not a valid YAML file."); 83 } 84 85 auto *Root = dyn_cast<yaml::MappingNode>(YAMLRoot); 86 if (!Root) 87 return error("document root is not of mapping type.", *YAMLRoot); 88 89 std::unique_ptr<Remark> Result = llvm::make_unique<Remark>(); 90 Remark &TheRemark = *Result; 91 92 // First, the type. It needs special handling since is not part of the 93 // key-value stream. 94 Expected<Type> T = parseType(*Root); 95 if (!T) 96 return T.takeError(); 97 else 98 TheRemark.RemarkType = *T; 99 100 // Then, parse the fields, one by one. 101 for (yaml::KeyValueNode &RemarkField : *Root) { 102 Expected<StringRef> MaybeKey = parseKey(RemarkField); 103 if (!MaybeKey) 104 return MaybeKey.takeError(); 105 StringRef KeyName = *MaybeKey; 106 107 if (KeyName == "Pass") { 108 if (Expected<StringRef> MaybeStr = parseStr(RemarkField)) 109 TheRemark.PassName = *MaybeStr; 110 else 111 return MaybeStr.takeError(); 112 } else if (KeyName == "Name") { 113 if (Expected<StringRef> MaybeStr = parseStr(RemarkField)) 114 TheRemark.RemarkName = *MaybeStr; 115 else 116 return MaybeStr.takeError(); 117 } else if (KeyName == "Function") { 118 if (Expected<StringRef> MaybeStr = parseStr(RemarkField)) 119 TheRemark.FunctionName = *MaybeStr; 120 else 121 return MaybeStr.takeError(); 122 } else if (KeyName == "Hotness") { 123 if (Expected<unsigned> MaybeU = parseUnsigned(RemarkField)) 124 TheRemark.Hotness = *MaybeU; 125 else 126 return MaybeU.takeError(); 127 } else if (KeyName == "DebugLoc") { 128 if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(RemarkField)) 129 TheRemark.Loc = *MaybeLoc; 130 else 131 return MaybeLoc.takeError(); 132 } else if (KeyName == "Args") { 133 auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue()); 134 if (!Args) 135 return error("wrong value type for key.", RemarkField); 136 137 for (yaml::Node &Arg : *Args) { 138 if (Expected<Argument> MaybeArg = parseArg(Arg)) 139 TheRemark.Args.push_back(*MaybeArg); 140 else 141 return MaybeArg.takeError(); 142 } 143 } else { 144 return error("unknown key.", RemarkField); 145 } 146 } 147 148 // Check if any of the mandatory fields are missing. 149 if (TheRemark.RemarkType == Type::Unknown || TheRemark.PassName.empty() || 150 TheRemark.RemarkName.empty() || TheRemark.FunctionName.empty()) 151 return error("Type, Pass, Name or Function missing.", 152 *RemarkEntry.getRoot()); 153 154 return std::move(Result); 155 } 156 157 Expected<Type> YAMLRemarkParser::parseType(yaml::MappingNode &Node) { 158 auto Type = StringSwitch<remarks::Type>(Node.getRawTag()) 159 .Case("!Passed", remarks::Type::Passed) 160 .Case("!Missed", remarks::Type::Missed) 161 .Case("!Analysis", remarks::Type::Analysis) 162 .Case("!AnalysisFPCommute", remarks::Type::AnalysisFPCommute) 163 .Case("!AnalysisAliasing", remarks::Type::AnalysisAliasing) 164 .Case("!Failure", remarks::Type::Failure) 165 .Default(remarks::Type::Unknown); 166 if (Type == remarks::Type::Unknown) 167 return error("expected a remark tag.", Node); 168 return Type; 169 } 170 171 Expected<StringRef> YAMLRemarkParser::parseKey(yaml::KeyValueNode &Node) { 172 if (auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey())) 173 return Key->getRawValue(); 174 175 return error("key is not a string.", Node); 176 } 177 178 Expected<StringRef> YAMLRemarkParser::parseStr(yaml::KeyValueNode &Node) { 179 auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 180 if (!Value) 181 return error("expected a value of scalar type.", Node); 182 StringRef Result; 183 if (!StrTab) { 184 Result = Value->getRawValue(); 185 } else { 186 // If we have a string table, parse it as an unsigned. 187 unsigned StrID = 0; 188 if (Expected<unsigned> MaybeStrID = parseUnsigned(Node)) 189 StrID = *MaybeStrID; 190 else 191 return MaybeStrID.takeError(); 192 193 if (Expected<StringRef> Str = (**StrTab)[StrID]) 194 Result = *Str; 195 else 196 return Str.takeError(); 197 } 198 199 if (Result.front() == '\'') 200 Result = Result.drop_front(); 201 202 if (Result.back() == '\'') 203 Result = Result.drop_back(); 204 205 return Result; 206 } 207 208 Expected<unsigned> YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode &Node) { 209 SmallVector<char, 4> Tmp; 210 auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue()); 211 if (!Value) 212 return error("expected a value of scalar type.", Node); 213 unsigned UnsignedValue = 0; 214 if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue)) 215 return error("expected a value of integer type.", *Value); 216 return UnsignedValue; 217 } 218 219 Expected<RemarkLocation> 220 YAMLRemarkParser::parseDebugLoc(yaml::KeyValueNode &Node) { 221 auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue()); 222 if (!DebugLoc) 223 return error("expected a value of mapping type.", Node); 224 225 Optional<StringRef> File; 226 Optional<unsigned> Line; 227 Optional<unsigned> Column; 228 229 for (yaml::KeyValueNode &DLNode : *DebugLoc) { 230 Expected<StringRef> MaybeKey = parseKey(DLNode); 231 if (!MaybeKey) 232 return MaybeKey.takeError(); 233 StringRef KeyName = *MaybeKey; 234 235 if (KeyName == "File") { 236 if (Expected<StringRef> MaybeStr = parseStr(DLNode)) 237 File = *MaybeStr; 238 else 239 return MaybeStr.takeError(); 240 } else if (KeyName == "Column") { 241 if (Expected<unsigned> MaybeU = parseUnsigned(DLNode)) 242 Column = *MaybeU; 243 else 244 return MaybeU.takeError(); 245 } else if (KeyName == "Line") { 246 if (Expected<unsigned> MaybeU = parseUnsigned(DLNode)) 247 Line = *MaybeU; 248 else 249 return MaybeU.takeError(); 250 } else { 251 return error("unknown entry in DebugLoc map.", DLNode); 252 } 253 } 254 255 // If any of the debug loc fields is missing, return an error. 256 if (!File || !Line || !Column) 257 return error("DebugLoc node incomplete.", Node); 258 259 return RemarkLocation{*File, *Line, *Column}; 260 } 261 262 Expected<Argument> YAMLRemarkParser::parseArg(yaml::Node &Node) { 263 auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node); 264 if (!ArgMap) 265 return error("expected a value of mapping type.", Node); 266 267 Optional<StringRef> KeyStr; 268 Optional<StringRef> ValueStr; 269 Optional<RemarkLocation> Loc; 270 271 for (yaml::KeyValueNode &ArgEntry : *ArgMap) { 272 Expected<StringRef> MaybeKey = parseKey(ArgEntry); 273 if (!MaybeKey) 274 return MaybeKey.takeError(); 275 StringRef KeyName = *MaybeKey; 276 277 // Try to parse debug locs. 278 if (KeyName == "DebugLoc") { 279 // Can't have multiple DebugLoc entries per argument. 280 if (Loc) 281 return error("only one DebugLoc entry is allowed per argument.", 282 ArgEntry); 283 284 if (Expected<RemarkLocation> MaybeLoc = parseDebugLoc(ArgEntry)) { 285 Loc = *MaybeLoc; 286 continue; 287 } else 288 return MaybeLoc.takeError(); 289 } 290 291 // If we already have a string, error out. 292 if (ValueStr) 293 return error("only one string entry is allowed per argument.", ArgEntry); 294 295 // Try to parse the value. 296 if (Expected<StringRef> MaybeStr = parseStr(ArgEntry)) 297 ValueStr = *MaybeStr; 298 else 299 return MaybeStr.takeError(); 300 301 // Keep the key from the string. 302 KeyStr = KeyName; 303 } 304 305 if (!KeyStr) 306 return error("argument key is missing.", *ArgMap); 307 if (!ValueStr) 308 return error("argument value is missing.", *ArgMap); 309 310 return Argument{*KeyStr, *ValueStr, Loc}; 311 } 312 313 Expected<std::unique_ptr<Remark>> YAMLRemarkParser::next() { 314 if (YAMLIt == Stream.end()) 315 return make_error<EndOfFileError>(); 316 317 Expected<std::unique_ptr<Remark>> MaybeResult = parseRemark(*YAMLIt); 318 if (!MaybeResult) { 319 // Avoid garbage input, set the iterator to the end. 320 YAMLIt = Stream.end(); 321 return MaybeResult.takeError(); 322 } 323 324 ++YAMLIt; 325 326 return std::move(*MaybeResult); 327 } 328