diff --git a/llvm/lib/Support/YAMLParser.cpp b/llvm/lib/Support/YAMLParser.cpp --- a/llvm/lib/Support/YAMLParser.cpp +++ b/llvm/lib/Support/YAMLParser.cpp @@ -259,11 +259,14 @@ Token getNext(); void printError(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Message, - ArrayRef Ranges = None) { - SM.PrintMessage(Loc, Kind, Message, Ranges, /* FixIts= */ None, ShowColors); + ArrayRef Ranges = None, + ArrayRef Fixes = None) { + SM.PrintMessage(Loc, Kind, Message, Ranges, Fixes, ShowColors); } - void setError(const Twine &Message, StringRef::iterator Position) { + void setError(const Twine &Message, StringRef::iterator Position, + ArrayRef Ranges = None, + ArrayRef Fixes = None) { if (Position >= End) Position = End - 1; @@ -274,7 +277,8 @@ // Don't print out more errors after the first one we encounter. The rest // are just the result of the first, and have no meaning. if (!Failed) - printError(SMLoc::getFromPointer(Position), SourceMgr::DK_Error, Message); + printError(SMLoc::getFromPointer(Position), SourceMgr::DK_Error, Message, + Ranges, Fixes); Failed = true; } @@ -2446,6 +2450,11 @@ return stream.scanner->failed(); } +static SMRange getRangeFromStringRef(StringRef Str) { + return SMRange(SMLoc::getFromPointer(Str.begin()), + SMLoc::getFromPointer(Str.end())); +} + Node *Document::parseBlockNode() { Token T = peekNext(); // Handle properties. @@ -2453,9 +2462,6 @@ Token TagInfo; parse_property: switch (T.Kind) { - case Token::TK_Alias: - getNext(); - return new (NodeAllocator) AliasNode(stream.CurrentDoc, T.Range.substr(1)); case Token::TK_Anchor: if (AnchorInfo.Kind == Token::TK_Anchor) { setError("Already encountered an anchor for this node!", T); @@ -2477,6 +2483,47 @@ } switch (T.Kind) { + case Token::TK_Alias: + getNext(); + // YAML1.2 - 7.1 Alias Nodes + // + // Note that an alias node must not specify any properties or content, as + // these were already specified at the first occurrence of the node. + if (AnchorInfo.Kind == Token::TK_Anchor || TagInfo.Kind == Token::TK_Tag) { + // If there was already an error, the below error message won't be + // emitted. + bool EmitFixes = !stream.scanner->failed(); + stream.scanner->setError("Alias node cannot have any properties", + T.Range.begin(), + {getRangeFromStringRef(T.Range)}); + if (EmitFixes) { + bool HasAnchor = AnchorInfo.Kind == Token::TK_Anchor; + bool HasTag = TagInfo.Kind == Token::TK_Tag; + const char *Begin; + StringRef Warning; + SmallVector Fixes; + if (HasAnchor) { + if (HasTag) { + Begin = std::min(AnchorInfo.Range.begin(), TagInfo.Range.begin()); + Warning = "remove anchor and tag"; + } else { + Begin = AnchorInfo.Range.begin(); + Warning = "remove anchor"; + } + } else { + Begin = TagInfo.Range.begin(); + Warning = "remove tag"; + } + if (HasAnchor) + Fixes.emplace_back(getRangeFromStringRef(AnchorInfo.Range), ""); + if (HasTag) + Fixes.emplace_back(getRangeFromStringRef(TagInfo.Range), ""); + stream.scanner->printError(SMLoc::getFromPointer(Begin), + SourceMgr::DK_Note, Warning, {}, Fixes); + } + return nullptr; + } + return new (NodeAllocator) AliasNode(stream.CurrentDoc, T.Range.substr(1)); case Token::TK_BlockEntry: // We got an unindented BlockEntry sequence. This is not terminated with // a BlockEnd. diff --git a/llvm/unittests/Support/YAMLParserTest.cpp b/llvm/unittests/Support/YAMLParserTest.cpp --- a/llvm/unittests/Support/YAMLParserTest.cpp +++ b/llvm/unittests/Support/YAMLParserTest.cpp @@ -183,6 +183,12 @@ ExpectParseError("KeyValueNode with null value", "test: '"); } +TEST(YAMLParser, FailsOnAliasProperties) { + ExpectParseError("Alias node cannot have any properties", "&A *B"); + ExpectParseError("Alias node cannot have any properties", "!A *B"); + ExpectParseError("Alias node cannot have any properties", "!A &A *B"); +} + // Checks that the given string can be parsed into an identical string inside // of an array. static void ExpectCanParseString(StringRef String) {