Path: blob/main/contrib/llvm-project/clang/lib/ASTMatchers/Dynamic/Parser.cpp
35291 views
//===- Parser.cpp - Matcher expression parser -----------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// Recursive parser implementation for the matcher expression grammar.10///11//===----------------------------------------------------------------------===//1213#include "clang/ASTMatchers/Dynamic/Parser.h"14#include "clang/ASTMatchers/ASTMatchersInternal.h"15#include "clang/ASTMatchers/Dynamic/Diagnostics.h"16#include "clang/ASTMatchers/Dynamic/Registry.h"17#include "clang/Basic/CharInfo.h"18#include "llvm/ADT/StringRef.h"19#include "llvm/Support/ErrorHandling.h"20#include "llvm/Support/ManagedStatic.h"21#include <algorithm>22#include <cassert>23#include <cerrno>24#include <cstddef>25#include <cstdlib>26#include <optional>27#include <string>28#include <utility>29#include <vector>3031namespace clang {32namespace ast_matchers {33namespace dynamic {3435/// Simple structure to hold information for one token from the parser.36struct Parser::TokenInfo {37/// Different possible tokens.38enum TokenKind {39TK_Eof,40TK_NewLine,41TK_OpenParen,42TK_CloseParen,43TK_Comma,44TK_Period,45TK_Literal,46TK_Ident,47TK_InvalidChar,48TK_Error,49TK_CodeCompletion50};5152/// Some known identifiers.53static const char* const ID_Bind;54static const char *const ID_With;5556TokenInfo() = default;5758StringRef Text;59TokenKind Kind = TK_Eof;60SourceRange Range;61VariantValue Value;62};6364const char* const Parser::TokenInfo::ID_Bind = "bind";65const char *const Parser::TokenInfo::ID_With = "with";6667/// Simple tokenizer for the parser.68class Parser::CodeTokenizer {69public:70explicit CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error)71: Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) {72NextToken = getNextToken();73}7475CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error,76unsigned CodeCompletionOffset)77: Code(MatcherCode), StartOfLine(MatcherCode), Error(Error),78CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {79NextToken = getNextToken();80}8182/// Returns but doesn't consume the next token.83const TokenInfo &peekNextToken() const { return NextToken; }8485/// Consumes and returns the next token.86TokenInfo consumeNextToken() {87TokenInfo ThisToken = NextToken;88NextToken = getNextToken();89return ThisToken;90}9192TokenInfo SkipNewlines() {93while (NextToken.Kind == TokenInfo::TK_NewLine)94NextToken = getNextToken();95return NextToken;96}9798TokenInfo consumeNextTokenIgnoreNewlines() {99SkipNewlines();100if (NextToken.Kind == TokenInfo::TK_Eof)101return NextToken;102return consumeNextToken();103}104105TokenInfo::TokenKind nextTokenKind() const { return NextToken.Kind; }106107private:108TokenInfo getNextToken() {109consumeWhitespace();110TokenInfo Result;111Result.Range.Start = currentLocation();112113if (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) {114Result.Kind = TokenInfo::TK_CodeCompletion;115Result.Text = StringRef(CodeCompletionLocation, 0);116CodeCompletionLocation = nullptr;117return Result;118}119120if (Code.empty()) {121Result.Kind = TokenInfo::TK_Eof;122Result.Text = "";123return Result;124}125126switch (Code[0]) {127case '#':128Code = Code.drop_until([](char c) { return c == '\n'; });129return getNextToken();130case ',':131Result.Kind = TokenInfo::TK_Comma;132Result.Text = Code.substr(0, 1);133Code = Code.drop_front();134break;135case '.':136Result.Kind = TokenInfo::TK_Period;137Result.Text = Code.substr(0, 1);138Code = Code.drop_front();139break;140case '\n':141++Line;142StartOfLine = Code.drop_front();143Result.Kind = TokenInfo::TK_NewLine;144Result.Text = Code.substr(0, 1);145Code = Code.drop_front();146break;147case '(':148Result.Kind = TokenInfo::TK_OpenParen;149Result.Text = Code.substr(0, 1);150Code = Code.drop_front();151break;152case ')':153Result.Kind = TokenInfo::TK_CloseParen;154Result.Text = Code.substr(0, 1);155Code = Code.drop_front();156break;157158case '"':159case '\'':160// Parse a string literal.161consumeStringLiteral(&Result);162break;163164case '0': case '1': case '2': case '3': case '4':165case '5': case '6': case '7': case '8': case '9':166// Parse an unsigned and float literal.167consumeNumberLiteral(&Result);168break;169170default:171if (isAlphanumeric(Code[0])) {172// Parse an identifier173size_t TokenLength = 1;174while (true) {175// A code completion location in/immediately after an identifier will176// cause the portion of the identifier before the code completion177// location to become a code completion token.178if (CodeCompletionLocation == Code.data() + TokenLength) {179CodeCompletionLocation = nullptr;180Result.Kind = TokenInfo::TK_CodeCompletion;181Result.Text = Code.substr(0, TokenLength);182Code = Code.drop_front(TokenLength);183return Result;184}185if (TokenLength == Code.size() || !isAlphanumeric(Code[TokenLength]))186break;187++TokenLength;188}189if (TokenLength == 4 && Code.starts_with("true")) {190Result.Kind = TokenInfo::TK_Literal;191Result.Value = true;192} else if (TokenLength == 5 && Code.starts_with("false")) {193Result.Kind = TokenInfo::TK_Literal;194Result.Value = false;195} else {196Result.Kind = TokenInfo::TK_Ident;197Result.Text = Code.substr(0, TokenLength);198}199Code = Code.drop_front(TokenLength);200} else {201Result.Kind = TokenInfo::TK_InvalidChar;202Result.Text = Code.substr(0, 1);203Code = Code.drop_front(1);204}205break;206}207208Result.Range.End = currentLocation();209return Result;210}211212/// Consume an unsigned and float literal.213void consumeNumberLiteral(TokenInfo *Result) {214bool isFloatingLiteral = false;215unsigned Length = 1;216if (Code.size() > 1) {217// Consume the 'x' or 'b' radix modifier, if present.218switch (toLowercase(Code[1])) {219case 'x': case 'b': Length = 2;220}221}222while (Length < Code.size() && isHexDigit(Code[Length]))223++Length;224225// Try to recognize a floating point literal.226while (Length < Code.size()) {227char c = Code[Length];228if (c == '-' || c == '+' || c == '.' || isHexDigit(c)) {229isFloatingLiteral = true;230Length++;231} else {232break;233}234}235236Result->Text = Code.substr(0, Length);237Code = Code.drop_front(Length);238239if (isFloatingLiteral) {240char *end;241errno = 0;242std::string Text = Result->Text.str();243double doubleValue = strtod(Text.c_str(), &end);244if (*end == 0 && errno == 0) {245Result->Kind = TokenInfo::TK_Literal;246Result->Value = doubleValue;247return;248}249} else {250unsigned Value;251if (!Result->Text.getAsInteger(0, Value)) {252Result->Kind = TokenInfo::TK_Literal;253Result->Value = Value;254return;255}256}257258SourceRange Range;259Range.Start = Result->Range.Start;260Range.End = currentLocation();261Error->addError(Range, Error->ET_ParserNumberError) << Result->Text;262Result->Kind = TokenInfo::TK_Error;263}264265/// Consume a string literal.266///267/// \c Code must be positioned at the start of the literal (the opening268/// quote). Consumed until it finds the same closing quote character.269void consumeStringLiteral(TokenInfo *Result) {270bool InEscape = false;271const char Marker = Code[0];272for (size_t Length = 1, Size = Code.size(); Length != Size; ++Length) {273if (InEscape) {274InEscape = false;275continue;276}277if (Code[Length] == '\\') {278InEscape = true;279continue;280}281if (Code[Length] == Marker) {282Result->Kind = TokenInfo::TK_Literal;283Result->Text = Code.substr(0, Length + 1);284Result->Value = Code.substr(1, Length - 1);285Code = Code.drop_front(Length + 1);286return;287}288}289290StringRef ErrorText = Code;291Code = Code.drop_front(Code.size());292SourceRange Range;293Range.Start = Result->Range.Start;294Range.End = currentLocation();295Error->addError(Range, Error->ET_ParserStringError) << ErrorText;296Result->Kind = TokenInfo::TK_Error;297}298299/// Consume all leading whitespace from \c Code.300void consumeWhitespace() {301// Don't trim newlines.302Code = Code.ltrim(" \t\v\f\r");303}304305SourceLocation currentLocation() {306SourceLocation Location;307Location.Line = Line;308Location.Column = Code.data() - StartOfLine.data() + 1;309return Location;310}311312StringRef &Code;313StringRef StartOfLine;314unsigned Line = 1;315Diagnostics *Error;316TokenInfo NextToken;317const char *CodeCompletionLocation = nullptr;318};319320Parser::Sema::~Sema() = default;321322std::vector<ArgKind> Parser::Sema::getAcceptedCompletionTypes(323llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {324return {};325}326327std::vector<MatcherCompletion>328Parser::Sema::getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) {329return {};330}331332struct Parser::ScopedContextEntry {333Parser *P;334335ScopedContextEntry(Parser *P, MatcherCtor C) : P(P) {336P->ContextStack.push_back(std::make_pair(C, 0u));337}338339~ScopedContextEntry() {340P->ContextStack.pop_back();341}342343void nextArg() {344++P->ContextStack.back().second;345}346};347348/// Parse expressions that start with an identifier.349///350/// This function can parse named values and matchers.351/// In case of failure it will try to determine the user's intent to give352/// an appropriate error message.353bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) {354const TokenInfo NameToken = Tokenizer->consumeNextToken();355356if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) {357// Parse as a named value.358if (const VariantValue NamedValue =359NamedValues ? NamedValues->lookup(NameToken.Text)360: VariantValue()) {361362if (Tokenizer->nextTokenKind() != TokenInfo::TK_Period) {363*Value = NamedValue;364return true;365}366367std::string BindID;368Tokenizer->consumeNextToken();369TokenInfo ChainCallToken = Tokenizer->consumeNextToken();370if (ChainCallToken.Kind == TokenInfo::TK_CodeCompletion) {371addCompletion(ChainCallToken, MatcherCompletion("bind(\"", "bind", 1));372return false;373}374375if (ChainCallToken.Kind != TokenInfo::TK_Ident ||376(ChainCallToken.Text != TokenInfo::ID_Bind &&377ChainCallToken.Text != TokenInfo::ID_With)) {378Error->addError(ChainCallToken.Range,379Error->ET_ParserMalformedChainedExpr);380return false;381}382if (ChainCallToken.Text == TokenInfo::ID_With) {383384Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,385NameToken.Text, NameToken.Range);386387Error->addError(ChainCallToken.Range,388Error->ET_RegistryMatcherNoWithSupport);389return false;390}391if (!parseBindID(BindID))392return false;393394assert(NamedValue.isMatcher());395std::optional<DynTypedMatcher> Result =396NamedValue.getMatcher().getSingleMatcher();397if (Result) {398std::optional<DynTypedMatcher> Bound = Result->tryBind(BindID);399if (Bound) {400*Value = VariantMatcher::SingleMatcher(*Bound);401return true;402}403}404return false;405}406407if (Tokenizer->nextTokenKind() == TokenInfo::TK_NewLine) {408Error->addError(Tokenizer->peekNextToken().Range,409Error->ET_ParserNoOpenParen)410<< "NewLine";411return false;412}413414// If the syntax is correct and the name is not a matcher either, report415// unknown named value.416if ((Tokenizer->nextTokenKind() == TokenInfo::TK_Comma ||417Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen ||418Tokenizer->nextTokenKind() == TokenInfo::TK_NewLine ||419Tokenizer->nextTokenKind() == TokenInfo::TK_Eof) &&420!S->lookupMatcherCtor(NameToken.Text)) {421Error->addError(NameToken.Range, Error->ET_RegistryValueNotFound)422<< NameToken.Text;423return false;424}425// Otherwise, fallback to the matcher parser.426}427428Tokenizer->SkipNewlines();429430assert(NameToken.Kind == TokenInfo::TK_Ident);431TokenInfo OpenToken = Tokenizer->consumeNextToken();432if (OpenToken.Kind != TokenInfo::TK_OpenParen) {433Error->addError(OpenToken.Range, Error->ET_ParserNoOpenParen)434<< OpenToken.Text;435return false;436}437438std::optional<MatcherCtor> Ctor = S->lookupMatcherCtor(NameToken.Text);439440// Parse as a matcher expression.441return parseMatcherExpressionImpl(NameToken, OpenToken, Ctor, Value);442}443444bool Parser::parseBindID(std::string &BindID) {445// Parse the parenthesized argument to .bind("foo")446const TokenInfo OpenToken = Tokenizer->consumeNextToken();447const TokenInfo IDToken = Tokenizer->consumeNextTokenIgnoreNewlines();448const TokenInfo CloseToken = Tokenizer->consumeNextTokenIgnoreNewlines();449450// TODO: We could use different error codes for each/some to be more451// explicit about the syntax error.452if (OpenToken.Kind != TokenInfo::TK_OpenParen) {453Error->addError(OpenToken.Range, Error->ET_ParserMalformedBindExpr);454return false;455}456if (IDToken.Kind != TokenInfo::TK_Literal || !IDToken.Value.isString()) {457Error->addError(IDToken.Range, Error->ET_ParserMalformedBindExpr);458return false;459}460if (CloseToken.Kind != TokenInfo::TK_CloseParen) {461Error->addError(CloseToken.Range, Error->ET_ParserMalformedBindExpr);462return false;463}464BindID = IDToken.Value.getString();465return true;466}467468bool Parser::parseMatcherBuilder(MatcherCtor Ctor, const TokenInfo &NameToken,469const TokenInfo &OpenToken,470VariantValue *Value) {471std::vector<ParserValue> Args;472TokenInfo EndToken;473474Tokenizer->SkipNewlines();475476{477ScopedContextEntry SCE(this, Ctor);478479while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) {480if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) {481// End of args.482EndToken = Tokenizer->consumeNextToken();483break;484}485if (!Args.empty()) {486// We must find a , token to continue.487TokenInfo CommaToken = Tokenizer->consumeNextToken();488if (CommaToken.Kind != TokenInfo::TK_Comma) {489Error->addError(CommaToken.Range, Error->ET_ParserNoComma)490<< CommaToken.Text;491return false;492}493}494495Diagnostics::Context Ctx(Diagnostics::Context::MatcherArg, Error,496NameToken.Text, NameToken.Range,497Args.size() + 1);498ParserValue ArgValue;499Tokenizer->SkipNewlines();500501if (Tokenizer->peekNextToken().Kind == TokenInfo::TK_CodeCompletion) {502addExpressionCompletions();503return false;504}505506TokenInfo NodeMatcherToken = Tokenizer->consumeNextToken();507508if (NodeMatcherToken.Kind != TokenInfo::TK_Ident) {509Error->addError(NameToken.Range, Error->ET_ParserFailedToBuildMatcher)510<< NameToken.Text;511return false;512}513514ArgValue.Text = NodeMatcherToken.Text;515ArgValue.Range = NodeMatcherToken.Range;516517std::optional<MatcherCtor> MappedMatcher =518S->lookupMatcherCtor(ArgValue.Text);519520if (!MappedMatcher) {521Error->addError(NodeMatcherToken.Range,522Error->ET_RegistryMatcherNotFound)523<< NodeMatcherToken.Text;524return false;525}526527ASTNodeKind NK = S->nodeMatcherType(*MappedMatcher);528529if (NK.isNone()) {530Error->addError(NodeMatcherToken.Range,531Error->ET_RegistryNonNodeMatcher)532<< NodeMatcherToken.Text;533return false;534}535536ArgValue.Value = NK;537538Tokenizer->SkipNewlines();539Args.push_back(ArgValue);540541SCE.nextArg();542}543}544545if (EndToken.Kind == TokenInfo::TK_Eof) {546Error->addError(OpenToken.Range, Error->ET_ParserNoCloseParen);547return false;548}549550internal::MatcherDescriptorPtr BuiltCtor =551S->buildMatcherCtor(Ctor, NameToken.Range, Args, Error);552553if (!BuiltCtor.get()) {554Error->addError(NameToken.Range, Error->ET_ParserFailedToBuildMatcher)555<< NameToken.Text;556return false;557}558559std::string BindID;560if (Tokenizer->peekNextToken().Kind == TokenInfo::TK_Period) {561Tokenizer->consumeNextToken();562TokenInfo ChainCallToken = Tokenizer->consumeNextToken();563if (ChainCallToken.Kind == TokenInfo::TK_CodeCompletion) {564addCompletion(ChainCallToken, MatcherCompletion("bind(\"", "bind", 1));565addCompletion(ChainCallToken, MatcherCompletion("with(", "with", 1));566return false;567}568if (ChainCallToken.Kind != TokenInfo::TK_Ident ||569(ChainCallToken.Text != TokenInfo::ID_Bind &&570ChainCallToken.Text != TokenInfo::ID_With)) {571Error->addError(ChainCallToken.Range,572Error->ET_ParserMalformedChainedExpr);573return false;574}575if (ChainCallToken.Text == TokenInfo::ID_Bind) {576if (!parseBindID(BindID))577return false;578Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,579NameToken.Text, NameToken.Range);580SourceRange MatcherRange = NameToken.Range;581MatcherRange.End = ChainCallToken.Range.End;582VariantMatcher Result = S->actOnMatcherExpression(583BuiltCtor.get(), MatcherRange, BindID, {}, Error);584if (Result.isNull())585return false;586587*Value = Result;588return true;589} else if (ChainCallToken.Text == TokenInfo::ID_With) {590Tokenizer->SkipNewlines();591592if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) {593StringRef ErrTxt = Tokenizer->nextTokenKind() == TokenInfo::TK_Eof594? StringRef("EOF")595: Tokenizer->peekNextToken().Text;596Error->addError(Tokenizer->peekNextToken().Range,597Error->ET_ParserNoOpenParen)598<< ErrTxt;599return false;600}601602TokenInfo WithOpenToken = Tokenizer->consumeNextToken();603604return parseMatcherExpressionImpl(NameToken, WithOpenToken,605BuiltCtor.get(), Value);606}607}608609Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,610NameToken.Text, NameToken.Range);611SourceRange MatcherRange = NameToken.Range;612MatcherRange.End = EndToken.Range.End;613VariantMatcher Result = S->actOnMatcherExpression(614BuiltCtor.get(), MatcherRange, BindID, {}, Error);615if (Result.isNull())616return false;617618*Value = Result;619return true;620}621622/// Parse and validate a matcher expression.623/// \return \c true on success, in which case \c Value has the matcher parsed.624/// If the input is malformed, or some argument has an error, it625/// returns \c false.626bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,627const TokenInfo &OpenToken,628std::optional<MatcherCtor> Ctor,629VariantValue *Value) {630if (!Ctor) {631Error->addError(NameToken.Range, Error->ET_RegistryMatcherNotFound)632<< NameToken.Text;633// Do not return here. We need to continue to give completion suggestions.634}635636if (Ctor && *Ctor && S->isBuilderMatcher(*Ctor))637return parseMatcherBuilder(*Ctor, NameToken, OpenToken, Value);638639std::vector<ParserValue> Args;640TokenInfo EndToken;641642Tokenizer->SkipNewlines();643644{645ScopedContextEntry SCE(this, Ctor.value_or(nullptr));646647while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) {648if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) {649// End of args.650EndToken = Tokenizer->consumeNextToken();651break;652}653if (!Args.empty()) {654// We must find a , token to continue.655const TokenInfo CommaToken = Tokenizer->consumeNextToken();656if (CommaToken.Kind != TokenInfo::TK_Comma) {657Error->addError(CommaToken.Range, Error->ET_ParserNoComma)658<< CommaToken.Text;659return false;660}661}662663Diagnostics::Context Ctx(Diagnostics::Context::MatcherArg, Error,664NameToken.Text, NameToken.Range,665Args.size() + 1);666ParserValue ArgValue;667Tokenizer->SkipNewlines();668ArgValue.Text = Tokenizer->peekNextToken().Text;669ArgValue.Range = Tokenizer->peekNextToken().Range;670if (!parseExpressionImpl(&ArgValue.Value)) {671return false;672}673674Tokenizer->SkipNewlines();675Args.push_back(ArgValue);676SCE.nextArg();677}678}679680if (EndToken.Kind == TokenInfo::TK_Eof) {681Error->addError(OpenToken.Range, Error->ET_ParserNoCloseParen);682return false;683}684685std::string BindID;686if (Tokenizer->peekNextToken().Kind == TokenInfo::TK_Period) {687Tokenizer->consumeNextToken();688TokenInfo ChainCallToken = Tokenizer->consumeNextToken();689if (ChainCallToken.Kind == TokenInfo::TK_CodeCompletion) {690addCompletion(ChainCallToken, MatcherCompletion("bind(\"", "bind", 1));691return false;692}693694if (ChainCallToken.Kind != TokenInfo::TK_Ident) {695Error->addError(ChainCallToken.Range,696Error->ET_ParserMalformedChainedExpr);697return false;698}699if (ChainCallToken.Text == TokenInfo::ID_With) {700701Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,702NameToken.Text, NameToken.Range);703704Error->addError(ChainCallToken.Range,705Error->ET_RegistryMatcherNoWithSupport);706return false;707}708if (ChainCallToken.Text != TokenInfo::ID_Bind) {709Error->addError(ChainCallToken.Range,710Error->ET_ParserMalformedChainedExpr);711return false;712}713if (!parseBindID(BindID))714return false;715}716717if (!Ctor)718return false;719720// Merge the start and end infos.721Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,722NameToken.Text, NameToken.Range);723SourceRange MatcherRange = NameToken.Range;724MatcherRange.End = EndToken.Range.End;725VariantMatcher Result = S->actOnMatcherExpression(726*Ctor, MatcherRange, BindID, Args, Error);727if (Result.isNull()) return false;728729*Value = Result;730return true;731}732733// If the prefix of this completion matches the completion token, add it to734// Completions minus the prefix.735void Parser::addCompletion(const TokenInfo &CompToken,736const MatcherCompletion& Completion) {737if (StringRef(Completion.TypedText).starts_with(CompToken.Text) &&738Completion.Specificity > 0) {739Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()),740Completion.MatcherDecl, Completion.Specificity);741}742}743744std::vector<MatcherCompletion> Parser::getNamedValueCompletions(745ArrayRef<ArgKind> AcceptedTypes) {746if (!NamedValues) return std::vector<MatcherCompletion>();747std::vector<MatcherCompletion> Result;748for (const auto &Entry : *NamedValues) {749unsigned Specificity;750if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) {751std::string Decl =752(Entry.getValue().getTypeAsString() + " " + Entry.getKey()).str();753Result.emplace_back(Entry.getKey(), Decl, Specificity);754}755}756return Result;757}758759void Parser::addExpressionCompletions() {760const TokenInfo CompToken = Tokenizer->consumeNextTokenIgnoreNewlines();761assert(CompToken.Kind == TokenInfo::TK_CodeCompletion);762763// We cannot complete code if there is an invalid element on the context764// stack.765for (ContextStackTy::iterator I = ContextStack.begin(),766E = ContextStack.end();767I != E; ++I) {768if (!I->first)769return;770}771772auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack);773for (const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) {774addCompletion(CompToken, Completion);775}776777for (const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {778addCompletion(CompToken, Completion);779}780}781782/// Parse an <Expression>783bool Parser::parseExpressionImpl(VariantValue *Value) {784switch (Tokenizer->nextTokenKind()) {785case TokenInfo::TK_Literal:786*Value = Tokenizer->consumeNextToken().Value;787return true;788789case TokenInfo::TK_Ident:790return parseIdentifierPrefixImpl(Value);791792case TokenInfo::TK_CodeCompletion:793addExpressionCompletions();794return false;795796case TokenInfo::TK_Eof:797Error->addError(Tokenizer->consumeNextToken().Range,798Error->ET_ParserNoCode);799return false;800801case TokenInfo::TK_Error:802// This error was already reported by the tokenizer.803return false;804case TokenInfo::TK_NewLine:805case TokenInfo::TK_OpenParen:806case TokenInfo::TK_CloseParen:807case TokenInfo::TK_Comma:808case TokenInfo::TK_Period:809case TokenInfo::TK_InvalidChar:810const TokenInfo Token = Tokenizer->consumeNextToken();811Error->addError(Token.Range, Error->ET_ParserInvalidToken)812<< (Token.Kind == TokenInfo::TK_NewLine ? "NewLine" : Token.Text);813return false;814}815816llvm_unreachable("Unknown token kind.");817}818819static llvm::ManagedStatic<Parser::RegistrySema> DefaultRegistrySema;820821Parser::Parser(CodeTokenizer *Tokenizer, Sema *S,822const NamedValueMap *NamedValues, Diagnostics *Error)823: Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema),824NamedValues(NamedValues), Error(Error) {}825826Parser::RegistrySema::~RegistrySema() = default;827828std::optional<MatcherCtor>829Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {830return Registry::lookupMatcherCtor(MatcherName);831}832833VariantMatcher Parser::RegistrySema::actOnMatcherExpression(834MatcherCtor Ctor, SourceRange NameRange, StringRef BindID,835ArrayRef<ParserValue> Args, Diagnostics *Error) {836if (BindID.empty()) {837return Registry::constructMatcher(Ctor, NameRange, Args, Error);838} else {839return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,840Error);841}842}843844std::vector<ArgKind> Parser::RegistrySema::getAcceptedCompletionTypes(845ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {846return Registry::getAcceptedCompletionTypes(Context);847}848849std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions(850ArrayRef<ArgKind> AcceptedTypes) {851return Registry::getMatcherCompletions(AcceptedTypes);852}853854bool Parser::RegistrySema::isBuilderMatcher(MatcherCtor Ctor) const {855return Registry::isBuilderMatcher(Ctor);856}857858ASTNodeKind Parser::RegistrySema::nodeMatcherType(MatcherCtor Ctor) const {859return Registry::nodeMatcherType(Ctor);860}861862internal::MatcherDescriptorPtr863Parser::RegistrySema::buildMatcherCtor(MatcherCtor Ctor, SourceRange NameRange,864ArrayRef<ParserValue> Args,865Diagnostics *Error) const {866return Registry::buildMatcherCtor(Ctor, NameRange, Args, Error);867}868869bool Parser::parseExpression(StringRef &Code, Sema *S,870const NamedValueMap *NamedValues,871VariantValue *Value, Diagnostics *Error) {872CodeTokenizer Tokenizer(Code, Error);873if (!Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value))874return false;875auto NT = Tokenizer.peekNextToken();876if (NT.Kind != TokenInfo::TK_Eof && NT.Kind != TokenInfo::TK_NewLine) {877Error->addError(Tokenizer.peekNextToken().Range,878Error->ET_ParserTrailingCode);879return false;880}881return true;882}883884std::vector<MatcherCompletion>885Parser::completeExpression(StringRef &Code, unsigned CompletionOffset, Sema *S,886const NamedValueMap *NamedValues) {887Diagnostics Error;888CodeTokenizer Tokenizer(Code, &Error, CompletionOffset);889Parser P(&Tokenizer, S, NamedValues, &Error);890VariantValue Dummy;891P.parseExpressionImpl(&Dummy);892893// Sort by specificity, then by name.894llvm::sort(P.Completions,895[](const MatcherCompletion &A, const MatcherCompletion &B) {896if (A.Specificity != B.Specificity)897return A.Specificity > B.Specificity;898return A.TypedText < B.TypedText;899});900901return P.Completions;902}903904std::optional<DynTypedMatcher>905Parser::parseMatcherExpression(StringRef &Code, Sema *S,906const NamedValueMap *NamedValues,907Diagnostics *Error) {908VariantValue Value;909if (!parseExpression(Code, S, NamedValues, &Value, Error))910return std::nullopt;911if (!Value.isMatcher()) {912Error->addError(SourceRange(), Error->ET_ParserNotAMatcher);913return std::nullopt;914}915std::optional<DynTypedMatcher> Result = Value.getMatcher().getSingleMatcher();916if (!Result) {917Error->addError(SourceRange(), Error->ET_ParserOverloadedType)918<< Value.getTypeAsString();919}920return Result;921}922923} // namespace dynamic924} // namespace ast_matchers925} // namespace clang926927928