brintos

brintos / llvm-project-archived public Read only

0
0
Text · 29.5 KiB · baac797 Raw
936 lines · cpp
1//===- Parser.cpp - Matcher expression parser -----------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// Recursive parser implementation for the matcher expression grammar.11///12//===----------------------------------------------------------------------===//13 14#include "clang/ASTMatchers/Dynamic/Parser.h"15#include "clang/ASTMatchers/ASTMatchersInternal.h"16#include "clang/ASTMatchers/Dynamic/Diagnostics.h"17#include "clang/ASTMatchers/Dynamic/Registry.h"18#include "clang/Basic/CharInfo.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/Support/ErrorHandling.h"21#include "llvm/Support/ManagedStatic.h"22#include <cassert>23#include <cerrno>24#include <cstddef>25#include <cstdlib>26#include <optional>27#include <string>28#include <utility>29#include <vector>30 31namespace clang {32namespace ast_matchers {33namespace dynamic {34 35/// Simple structure to hold information for one token from the parser.36struct Parser::TokenInfo {37  /// Different possible tokens.38  enum TokenKind {39    TK_Eof,40    TK_NewLine,41    TK_OpenParen,42    TK_CloseParen,43    TK_Comma,44    TK_Period,45    TK_Literal,46    TK_Ident,47    TK_InvalidChar,48    TK_Error,49    TK_CodeCompletion50  };51 52  /// Some known identifiers.53  static const char* const ID_Bind;54  static const char *const ID_With;55 56  TokenInfo() = default;57 58  StringRef Text;59  TokenKind Kind = TK_Eof;60  SourceRange Range;61  VariantValue Value;62};63 64const char* const Parser::TokenInfo::ID_Bind = "bind";65const char *const Parser::TokenInfo::ID_With = "with";66 67/// Simple tokenizer for the parser.68class Parser::CodeTokenizer {69public:70  explicit CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error)71      : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) {72    NextToken = getNextToken();73  }74 75  CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error,76                unsigned CodeCompletionOffset)77      : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error),78        CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) {79    NextToken = getNextToken();80  }81 82  /// Returns but doesn't consume the next token.83  const TokenInfo &peekNextToken() const { return NextToken; }84 85  /// Consumes and returns the next token.86  TokenInfo consumeNextToken() {87    TokenInfo ThisToken = NextToken;88    NextToken = getNextToken();89    return ThisToken;90  }91 92  TokenInfo SkipNewlines() {93    while (NextToken.Kind == TokenInfo::TK_NewLine)94      NextToken = getNextToken();95    return NextToken;96  }97 98  TokenInfo consumeNextTokenIgnoreNewlines() {99    SkipNewlines();100    if (NextToken.Kind == TokenInfo::TK_Eof)101      return NextToken;102    return consumeNextToken();103  }104 105  TokenInfo::TokenKind nextTokenKind() const { return NextToken.Kind; }106 107private:108  TokenInfo getNextToken() {109    consumeWhitespace();110    TokenInfo Result;111    Result.Range.Start = currentLocation();112 113    if (CodeCompletionLocation && CodeCompletionLocation <= Code.data()) {114      Result.Kind = TokenInfo::TK_CodeCompletion;115      Result.Text = StringRef(CodeCompletionLocation, 0);116      CodeCompletionLocation = nullptr;117      return Result;118    }119 120    if (Code.empty()) {121      Result.Kind = TokenInfo::TK_Eof;122      Result.Text = "";123      return Result;124    }125 126    switch (Code[0]) {127    case '#':128      Code = Code.drop_until([](char c) { return c == '\n'; });129      return getNextToken();130    case ',':131      Result.Kind = TokenInfo::TK_Comma;132      Result.Text = Code.substr(0, 1);133      Code = Code.drop_front();134      break;135    case '.':136      Result.Kind = TokenInfo::TK_Period;137      Result.Text = Code.substr(0, 1);138      Code = Code.drop_front();139      break;140    case '\n':141      ++Line;142      StartOfLine = Code.drop_front();143      Result.Kind = TokenInfo::TK_NewLine;144      Result.Text = Code.substr(0, 1);145      Code = Code.drop_front();146      break;147    case '(':148      Result.Kind = TokenInfo::TK_OpenParen;149      Result.Text = Code.substr(0, 1);150      Code = Code.drop_front();151      break;152    case ')':153      Result.Kind = TokenInfo::TK_CloseParen;154      Result.Text = Code.substr(0, 1);155      Code = Code.drop_front();156      break;157 158    case '"':159    case '\'':160      // Parse a string literal.161      consumeStringLiteral(&Result);162      break;163 164    case '0': case '1': case '2': case '3': case '4':165    case '5': case '6': case '7': case '8': case '9':166      // Parse an unsigned and float literal.167      consumeNumberLiteral(&Result);168      break;169 170    default:171      if (isAlphanumeric(Code[0])) {172        // Parse an identifier173        size_t TokenLength = 1;174        while (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.178          if (CodeCompletionLocation == Code.data() + TokenLength) {179            CodeCompletionLocation = nullptr;180            Result.Kind = TokenInfo::TK_CodeCompletion;181            Result.Text = Code.substr(0, TokenLength);182            Code = Code.drop_front(TokenLength);183            return Result;184          }185          if (TokenLength == Code.size() || !isAlphanumeric(Code[TokenLength]))186            break;187          ++TokenLength;188        }189        if (TokenLength == 4 && Code.starts_with("true")) {190          Result.Kind = TokenInfo::TK_Literal;191          Result.Value = true;192        } else if (TokenLength == 5 && Code.starts_with("false")) {193          Result.Kind = TokenInfo::TK_Literal;194          Result.Value = false;195        } else {196          Result.Kind = TokenInfo::TK_Ident;197          Result.Text = Code.substr(0, TokenLength);198        }199        Code = Code.drop_front(TokenLength);200      } else {201        Result.Kind = TokenInfo::TK_InvalidChar;202        Result.Text = Code.substr(0, 1);203        Code = Code.drop_front(1);204      }205      break;206    }207 208    Result.Range.End = currentLocation();209    return Result;210  }211 212  /// Consume an unsigned and float literal.213  void consumeNumberLiteral(TokenInfo *Result) {214    bool isFloatingLiteral = false;215    unsigned Length = 1;216    if (Code.size() > 1) {217      // Consume the 'x' or 'b' radix modifier, if present.218      switch (toLowercase(Code[1])) {219      case 'x': case 'b': Length = 2;220      }221    }222    while (Length < Code.size() && isHexDigit(Code[Length]))223      ++Length;224 225    // Try to recognize a floating point literal.226    while (Length < Code.size()) {227      char c = Code[Length];228      if (c == '-' || c == '+' || c == '.' || isHexDigit(c)) {229        isFloatingLiteral = true;230        Length++;231      } else {232        break;233      }234    }235 236    Result->Text = Code.substr(0, Length);237    Code = Code.drop_front(Length);238 239    if (isFloatingLiteral) {240      char *end;241      errno = 0;242      std::string Text = Result->Text.str();243      double doubleValue = strtod(Text.c_str(), &end);244      if (*end == 0 && errno == 0) {245        Result->Kind = TokenInfo::TK_Literal;246        Result->Value = doubleValue;247        return;248      }249    } else {250      unsigned Value;251      if (!Result->Text.getAsInteger(0, Value)) {252        Result->Kind = TokenInfo::TK_Literal;253        Result->Value = Value;254        return;255      }256    }257 258    SourceRange Range;259    Range.Start = Result->Range.Start;260    Range.End = currentLocation();261    Error->addError(Range, Error->ET_ParserNumberError) << Result->Text;262    Result->Kind = TokenInfo::TK_Error;263  }264 265  /// 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.269  void consumeStringLiteral(TokenInfo *Result) {270    bool InEscape = false;271    const char Marker = Code[0];272    for (size_t Length = 1, Size = Code.size(); Length != Size; ++Length) {273      if (InEscape) {274        InEscape = false;275        continue;276      }277      if (Code[Length] == '\\') {278        InEscape = true;279        continue;280      }281      if (Code[Length] == Marker) {282        Result->Kind = TokenInfo::TK_Literal;283        Result->Text = Code.substr(0, Length + 1);284        Result->Value = Code.substr(1, Length - 1);285        Code = Code.drop_front(Length + 1);286        return;287      }288    }289 290    StringRef ErrorText = Code;291    Code = Code.drop_front(Code.size());292    SourceRange Range;293    Range.Start = Result->Range.Start;294    Range.End = currentLocation();295    Error->addError(Range, Error->ET_ParserStringError) << ErrorText;296    Result->Kind = TokenInfo::TK_Error;297  }298 299  /// Consume all leading whitespace from \c Code.300  void consumeWhitespace() {301    // Don't trim newlines.302    Code = Code.ltrim(" \t\v\f\r");303  }304 305  SourceLocation currentLocation() {306    SourceLocation Location;307    Location.Line = Line;308    Location.Column = Code.data() - StartOfLine.data() + 1;309    return Location;310  }311 312  StringRef &Code;313  StringRef StartOfLine;314  unsigned Line = 1;315  Diagnostics *Error;316  TokenInfo NextToken;317  const char *CodeCompletionLocation = nullptr;318};319 320Parser::Sema::~Sema() = default;321 322std::vector<ArgKind> Parser::Sema::getAcceptedCompletionTypes(323    llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {324  return {};325}326 327std::vector<MatcherCompletion>328Parser::Sema::getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) {329  return {};330}331 332struct Parser::ScopedContextEntry {333  Parser *P;334 335  ScopedContextEntry(Parser *P, MatcherCtor C) : P(P) {336    P->ContextStack.push_back(std::make_pair(C, 0u));337  }338 339  ~ScopedContextEntry() {340    P->ContextStack.pop_back();341  }342 343  void nextArg() {344    ++P->ContextStack.back().second;345  }346};347 348/// 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) {354  const TokenInfo NameToken = Tokenizer->consumeNextToken();355 356  if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) {357    // Parse as a named value.358    if (const VariantValue NamedValue =359            NamedValues ? NamedValues->lookup(NameToken.Text)360                        : VariantValue()) {361 362      if (Tokenizer->nextTokenKind() != TokenInfo::TK_Period) {363        *Value = NamedValue;364        return true;365      }366 367      std::string BindID;368      Tokenizer->consumeNextToken();369      TokenInfo ChainCallToken = Tokenizer->consumeNextToken();370      if (ChainCallToken.Kind == TokenInfo::TK_CodeCompletion) {371        addCompletion(ChainCallToken, MatcherCompletion("bind(\"", "bind", 1));372        return false;373      }374 375      if (ChainCallToken.Kind != TokenInfo::TK_Ident ||376          (ChainCallToken.Text != TokenInfo::ID_Bind &&377           ChainCallToken.Text != TokenInfo::ID_With)) {378        Error->addError(ChainCallToken.Range,379                        Error->ET_ParserMalformedChainedExpr);380        return false;381      }382      if (ChainCallToken.Text == TokenInfo::ID_With) {383 384        Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,385                                 NameToken.Text, NameToken.Range);386 387        Error->addError(ChainCallToken.Range,388                        Error->ET_RegistryMatcherNoWithSupport);389        return false;390      }391      if (!parseBindID(BindID))392        return false;393 394      assert(NamedValue.isMatcher());395      std::optional<DynTypedMatcher> Result =396          NamedValue.getMatcher().getSingleMatcher();397      if (Result) {398        std::optional<DynTypedMatcher> Bound = Result->tryBind(BindID);399        if (Bound) {400          *Value = VariantMatcher::SingleMatcher(*Bound);401          return true;402        }403      }404      return false;405    }406 407    if (Tokenizer->nextTokenKind() == TokenInfo::TK_NewLine) {408      Error->addError(Tokenizer->peekNextToken().Range,409                      Error->ET_ParserNoOpenParen)410          << "NewLine";411      return false;412    }413 414    // If the syntax is correct and the name is not a matcher either, report415    // unknown named value.416    if ((Tokenizer->nextTokenKind() == TokenInfo::TK_Comma ||417         Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen ||418         Tokenizer->nextTokenKind() == TokenInfo::TK_NewLine ||419         Tokenizer->nextTokenKind() == TokenInfo::TK_Eof) &&420        !S->lookupMatcherCtor(NameToken.Text)) {421      Error->addError(NameToken.Range, Error->ET_RegistryValueNotFound)422          << NameToken.Text;423      return false;424    }425    // Otherwise, fallback to the matcher parser.426  }427 428  Tokenizer->SkipNewlines();429 430  assert(NameToken.Kind == TokenInfo::TK_Ident);431  TokenInfo OpenToken = Tokenizer->consumeNextToken();432  if (OpenToken.Kind != TokenInfo::TK_OpenParen) {433    Error->addError(OpenToken.Range, Error->ET_ParserNoOpenParen)434        << OpenToken.Text;435    return false;436  }437 438  std::optional<MatcherCtor> Ctor = S->lookupMatcherCtor(NameToken.Text);439 440  // Parse as a matcher expression.441  return parseMatcherExpressionImpl(NameToken, OpenToken, Ctor, Value);442}443 444bool Parser::parseBindID(std::string &BindID) {445  // Parse the parenthesized argument to .bind("foo")446  const TokenInfo OpenToken = Tokenizer->consumeNextToken();447  const TokenInfo IDToken = Tokenizer->consumeNextTokenIgnoreNewlines();448  const TokenInfo CloseToken = Tokenizer->consumeNextTokenIgnoreNewlines();449 450  // TODO: We could use different error codes for each/some to be more451  //       explicit about the syntax error.452  if (OpenToken.Kind != TokenInfo::TK_OpenParen) {453    Error->addError(OpenToken.Range, Error->ET_ParserMalformedBindExpr);454    return false;455  }456  if (IDToken.Kind != TokenInfo::TK_Literal || !IDToken.Value.isString()) {457    Error->addError(IDToken.Range, Error->ET_ParserMalformedBindExpr);458    return false;459  }460  if (CloseToken.Kind != TokenInfo::TK_CloseParen) {461    Error->addError(CloseToken.Range, Error->ET_ParserMalformedBindExpr);462    return false;463  }464  BindID = IDToken.Value.getString();465  return true;466}467 468bool Parser::parseMatcherBuilder(MatcherCtor Ctor, const TokenInfo &NameToken,469                                 const TokenInfo &OpenToken,470                                 VariantValue *Value) {471  std::vector<ParserValue> Args;472  TokenInfo EndToken;473 474  Tokenizer->SkipNewlines();475 476  {477    ScopedContextEntry SCE(this, Ctor);478 479    while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) {480      if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) {481        // End of args.482        EndToken = Tokenizer->consumeNextToken();483        break;484      }485      if (!Args.empty()) {486        // We must find a , token to continue.487        TokenInfo CommaToken = Tokenizer->consumeNextToken();488        if (CommaToken.Kind != TokenInfo::TK_Comma) {489          Error->addError(CommaToken.Range, Error->ET_ParserNoComma)490              << CommaToken.Text;491          return false;492        }493        // Allow for a trailing , token and possibly a new line.494        Tokenizer->SkipNewlines();495        if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) {496          continue;497        }498      }499 500      Diagnostics::Context Ctx(Diagnostics::Context::MatcherArg, Error,501                               NameToken.Text, NameToken.Range,502                               Args.size() + 1);503      ParserValue ArgValue;504      Tokenizer->SkipNewlines();505 506      if (Tokenizer->peekNextToken().Kind == TokenInfo::TK_CodeCompletion) {507        addExpressionCompletions();508        return false;509      }510 511      TokenInfo NodeMatcherToken = Tokenizer->consumeNextToken();512 513      if (NodeMatcherToken.Kind != TokenInfo::TK_Ident) {514        Error->addError(NameToken.Range, Error->ET_ParserFailedToBuildMatcher)515            << NameToken.Text;516        return false;517      }518 519      ArgValue.Text = NodeMatcherToken.Text;520      ArgValue.Range = NodeMatcherToken.Range;521 522      std::optional<MatcherCtor> MappedMatcher =523          S->lookupMatcherCtor(ArgValue.Text);524 525      if (!MappedMatcher) {526        Error->addError(NodeMatcherToken.Range,527                        Error->ET_RegistryMatcherNotFound)528            << NodeMatcherToken.Text;529        return false;530      }531 532      ASTNodeKind NK = S->nodeMatcherType(*MappedMatcher);533 534      if (NK.isNone()) {535        Error->addError(NodeMatcherToken.Range,536                        Error->ET_RegistryNonNodeMatcher)537            << NodeMatcherToken.Text;538        return false;539      }540 541      ArgValue.Value = NK;542 543      Tokenizer->SkipNewlines();544      Args.push_back(ArgValue);545 546      SCE.nextArg();547    }548  }549 550  if (EndToken.Kind == TokenInfo::TK_Eof) {551    Error->addError(OpenToken.Range, Error->ET_ParserNoCloseParen);552    return false;553  }554 555  internal::MatcherDescriptorPtr BuiltCtor =556      S->buildMatcherCtor(Ctor, NameToken.Range, Args, Error);557 558  if (!BuiltCtor.get()) {559    Error->addError(NameToken.Range, Error->ET_ParserFailedToBuildMatcher)560        << NameToken.Text;561    return false;562  }563 564  std::string BindID;565  if (Tokenizer->peekNextToken().Kind == TokenInfo::TK_Period) {566    Tokenizer->consumeNextToken();567    TokenInfo ChainCallToken = Tokenizer->consumeNextToken();568    if (ChainCallToken.Kind == TokenInfo::TK_CodeCompletion) {569      addCompletion(ChainCallToken, MatcherCompletion("bind(\"", "bind", 1));570      addCompletion(ChainCallToken, MatcherCompletion("with(", "with", 1));571      return false;572    }573    if (ChainCallToken.Kind != TokenInfo::TK_Ident ||574        (ChainCallToken.Text != TokenInfo::ID_Bind &&575         ChainCallToken.Text != TokenInfo::ID_With)) {576      Error->addError(ChainCallToken.Range,577                      Error->ET_ParserMalformedChainedExpr);578      return false;579    }580    if (ChainCallToken.Text == TokenInfo::ID_Bind) {581      if (!parseBindID(BindID))582        return false;583      Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,584                               NameToken.Text, NameToken.Range);585      SourceRange MatcherRange = NameToken.Range;586      MatcherRange.End = ChainCallToken.Range.End;587      VariantMatcher Result = S->actOnMatcherExpression(588          BuiltCtor.get(), MatcherRange, BindID, {}, Error);589      if (Result.isNull())590        return false;591 592      *Value = Result;593      return true;594    } else if (ChainCallToken.Text == TokenInfo::ID_With) {595      Tokenizer->SkipNewlines();596 597      if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) {598        StringRef ErrTxt = Tokenizer->nextTokenKind() == TokenInfo::TK_Eof599                               ? StringRef("EOF")600                               : Tokenizer->peekNextToken().Text;601        Error->addError(Tokenizer->peekNextToken().Range,602                        Error->ET_ParserNoOpenParen)603            << ErrTxt;604        return false;605      }606 607      TokenInfo WithOpenToken = Tokenizer->consumeNextToken();608 609      return parseMatcherExpressionImpl(NameToken, WithOpenToken,610                                        BuiltCtor.get(), Value);611    }612  }613 614  Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,615                           NameToken.Text, NameToken.Range);616  SourceRange MatcherRange = NameToken.Range;617  MatcherRange.End = EndToken.Range.End;618  VariantMatcher Result = S->actOnMatcherExpression(619      BuiltCtor.get(), MatcherRange, BindID, {}, Error);620  if (Result.isNull())621    return false;622 623  *Value = Result;624  return true;625}626 627/// Parse and validate a matcher expression.628/// \return \c true on success, in which case \c Value has the matcher parsed.629///   If the input is malformed, or some argument has an error, it630///   returns \c false.631bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,632                                        const TokenInfo &OpenToken,633                                        std::optional<MatcherCtor> Ctor,634                                        VariantValue *Value) {635  if (!Ctor) {636    Error->addError(NameToken.Range, Error->ET_RegistryMatcherNotFound)637        << NameToken.Text;638    // Do not return here. We need to continue to give completion suggestions.639  }640 641  if (Ctor && *Ctor && S->isBuilderMatcher(*Ctor))642    return parseMatcherBuilder(*Ctor, NameToken, OpenToken, Value);643 644  std::vector<ParserValue> Args;645  TokenInfo EndToken;646 647  Tokenizer->SkipNewlines();648 649  {650    ScopedContextEntry SCE(this, Ctor.value_or(nullptr));651 652    while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) {653      if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) {654        // End of args.655        EndToken = Tokenizer->consumeNextToken();656        break;657      }658      if (!Args.empty()) {659        // We must find a , token to continue.660        const TokenInfo CommaToken = Tokenizer->consumeNextToken();661        if (CommaToken.Kind != TokenInfo::TK_Comma) {662          Error->addError(CommaToken.Range, Error->ET_ParserNoComma)663              << CommaToken.Text;664          return false;665        }666        // Allow for a trailing , token and possibly a new line.667        Tokenizer->SkipNewlines();668        if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) {669          continue;670        }671      }672 673      Diagnostics::Context Ctx(Diagnostics::Context::MatcherArg, Error,674                               NameToken.Text, NameToken.Range,675                               Args.size() + 1);676      ParserValue ArgValue;677      Tokenizer->SkipNewlines();678      ArgValue.Text = Tokenizer->peekNextToken().Text;679      ArgValue.Range = Tokenizer->peekNextToken().Range;680      if (!parseExpressionImpl(&ArgValue.Value)) {681        return false;682      }683 684      Tokenizer->SkipNewlines();685      Args.push_back(ArgValue);686      SCE.nextArg();687    }688  }689 690  if (EndToken.Kind == TokenInfo::TK_Eof) {691    Error->addError(OpenToken.Range, Error->ET_ParserNoCloseParen);692    return false;693  }694 695  std::string BindID;696  if (Tokenizer->peekNextToken().Kind == TokenInfo::TK_Period) {697    Tokenizer->consumeNextToken();698    TokenInfo ChainCallToken = Tokenizer->consumeNextToken();699    if (ChainCallToken.Kind == TokenInfo::TK_CodeCompletion) {700      addCompletion(ChainCallToken, MatcherCompletion("bind(\"", "bind", 1));701      return false;702    }703 704    if (ChainCallToken.Kind != TokenInfo::TK_Ident) {705      Error->addError(ChainCallToken.Range,706                      Error->ET_ParserMalformedChainedExpr);707      return false;708    }709    if (ChainCallToken.Text == TokenInfo::ID_With) {710 711      Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,712                               NameToken.Text, NameToken.Range);713 714      Error->addError(ChainCallToken.Range,715                      Error->ET_RegistryMatcherNoWithSupport);716      return false;717    }718    if (ChainCallToken.Text != TokenInfo::ID_Bind) {719      Error->addError(ChainCallToken.Range,720                      Error->ET_ParserMalformedChainedExpr);721      return false;722    }723    if (!parseBindID(BindID))724      return false;725  }726 727  if (!Ctor)728    return false;729 730  // Merge the start and end infos.731  Diagnostics::Context Ctx(Diagnostics::Context::ConstructMatcher, Error,732                           NameToken.Text, NameToken.Range);733  SourceRange MatcherRange = NameToken.Range;734  MatcherRange.End = EndToken.Range.End;735  VariantMatcher Result = S->actOnMatcherExpression(736      *Ctor, MatcherRange, BindID, Args, Error);737  if (Result.isNull()) return false;738 739  *Value = Result;740  return true;741}742 743// If the prefix of this completion matches the completion token, add it to744// Completions minus the prefix.745void Parser::addCompletion(const TokenInfo &CompToken,746                           const MatcherCompletion& Completion) {747  if (StringRef(Completion.TypedText).starts_with(CompToken.Text) &&748      Completion.Specificity > 0) {749    Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()),750                             Completion.MatcherDecl, Completion.Specificity);751  }752}753 754std::vector<MatcherCompletion> Parser::getNamedValueCompletions(755    ArrayRef<ArgKind> AcceptedTypes) {756  if (!NamedValues) return std::vector<MatcherCompletion>();757  std::vector<MatcherCompletion> Result;758  for (const auto &Entry : *NamedValues) {759    unsigned Specificity;760    if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) {761      std::string Decl =762          (Entry.getValue().getTypeAsString() + " " + Entry.getKey()).str();763      Result.emplace_back(Entry.getKey(), Decl, Specificity);764    }765  }766  return Result;767}768 769void Parser::addExpressionCompletions() {770  const TokenInfo CompToken = Tokenizer->consumeNextTokenIgnoreNewlines();771  assert(CompToken.Kind == TokenInfo::TK_CodeCompletion);772 773  // We cannot complete code if there is an invalid element on the context774  // stack.775  for (ContextStackTy::iterator I = ContextStack.begin(),776                                E = ContextStack.end();777       I != E; ++I) {778    if (!I->first)779      return;780  }781 782  auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack);783  for (const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) {784    addCompletion(CompToken, Completion);785  }786 787  for (const auto &Completion : getNamedValueCompletions(AcceptedTypes)) {788    addCompletion(CompToken, Completion);789  }790}791 792/// Parse an <Expression>793bool Parser::parseExpressionImpl(VariantValue *Value) {794  switch (Tokenizer->nextTokenKind()) {795  case TokenInfo::TK_Literal:796    *Value = Tokenizer->consumeNextToken().Value;797    return true;798 799  case TokenInfo::TK_Ident:800    return parseIdentifierPrefixImpl(Value);801 802  case TokenInfo::TK_CodeCompletion:803    addExpressionCompletions();804    return false;805 806  case TokenInfo::TK_Eof:807    Error->addError(Tokenizer->consumeNextToken().Range,808                    Error->ET_ParserNoCode);809    return false;810 811  case TokenInfo::TK_Error:812    // This error was already reported by the tokenizer.813    return false;814  case TokenInfo::TK_NewLine:815  case TokenInfo::TK_OpenParen:816  case TokenInfo::TK_CloseParen:817  case TokenInfo::TK_Comma:818  case TokenInfo::TK_Period:819  case TokenInfo::TK_InvalidChar:820    const TokenInfo Token = Tokenizer->consumeNextToken();821    Error->addError(Token.Range, Error->ET_ParserInvalidToken)822        << (Token.Kind == TokenInfo::TK_NewLine ? "NewLine" : Token.Text);823    return false;824  }825 826  llvm_unreachable("Unknown token kind.");827}828 829static llvm::ManagedStatic<Parser::RegistrySema> DefaultRegistrySema;830 831Parser::Parser(CodeTokenizer *Tokenizer, Sema *S,832               const NamedValueMap *NamedValues, Diagnostics *Error)833    : Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema),834      NamedValues(NamedValues), Error(Error) {}835 836Parser::RegistrySema::~RegistrySema() = default;837 838std::optional<MatcherCtor>839Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {840  return Registry::lookupMatcherCtor(MatcherName);841}842 843VariantMatcher Parser::RegistrySema::actOnMatcherExpression(844    MatcherCtor Ctor, SourceRange NameRange, StringRef BindID,845    ArrayRef<ParserValue> Args, Diagnostics *Error) {846  if (BindID.empty()) {847    return Registry::constructMatcher(Ctor, NameRange, Args, Error);848  } else {849    return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,850                                           Error);851  }852}853 854std::vector<ArgKind> Parser::RegistrySema::getAcceptedCompletionTypes(855    ArrayRef<std::pair<MatcherCtor, unsigned>> Context) {856  return Registry::getAcceptedCompletionTypes(Context);857}858 859std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions(860    ArrayRef<ArgKind> AcceptedTypes) {861  return Registry::getMatcherCompletions(AcceptedTypes);862}863 864bool Parser::RegistrySema::isBuilderMatcher(MatcherCtor Ctor) const {865  return Registry::isBuilderMatcher(Ctor);866}867 868ASTNodeKind Parser::RegistrySema::nodeMatcherType(MatcherCtor Ctor) const {869  return Registry::nodeMatcherType(Ctor);870}871 872internal::MatcherDescriptorPtr873Parser::RegistrySema::buildMatcherCtor(MatcherCtor Ctor, SourceRange NameRange,874                                       ArrayRef<ParserValue> Args,875                                       Diagnostics *Error) const {876  return Registry::buildMatcherCtor(Ctor, NameRange, Args, Error);877}878 879bool Parser::parseExpression(StringRef &Code, Sema *S,880                             const NamedValueMap *NamedValues,881                             VariantValue *Value, Diagnostics *Error) {882  CodeTokenizer Tokenizer(Code, Error);883  if (!Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value))884    return false;885  auto NT = Tokenizer.peekNextToken();886  if (NT.Kind != TokenInfo::TK_Eof && NT.Kind != TokenInfo::TK_NewLine) {887    Error->addError(Tokenizer.peekNextToken().Range,888                    Error->ET_ParserTrailingCode);889    return false;890  }891  return true;892}893 894std::vector<MatcherCompletion>895Parser::completeExpression(StringRef &Code, unsigned CompletionOffset, Sema *S,896                           const NamedValueMap *NamedValues) {897  Diagnostics Error;898  CodeTokenizer Tokenizer(Code, &Error, CompletionOffset);899  Parser P(&Tokenizer, S, NamedValues, &Error);900  VariantValue Dummy;901  P.parseExpressionImpl(&Dummy);902 903  // Sort by specificity, then by name.904  llvm::sort(P.Completions,905             [](const MatcherCompletion &A, const MatcherCompletion &B) {906               if (A.Specificity != B.Specificity)907                 return A.Specificity > B.Specificity;908               return A.TypedText < B.TypedText;909             });910 911  return P.Completions;912}913 914std::optional<DynTypedMatcher>915Parser::parseMatcherExpression(StringRef &Code, Sema *S,916                               const NamedValueMap *NamedValues,917                               Diagnostics *Error) {918  VariantValue Value;919  if (!parseExpression(Code, S, NamedValues, &Value, Error))920    return std::nullopt;921  if (!Value.isMatcher()) {922    Error->addError(SourceRange(), Error->ET_ParserNotAMatcher);923    return std::nullopt;924  }925  std::optional<DynTypedMatcher> Result = Value.getMatcher().getSingleMatcher();926  if (!Result) {927    Error->addError(SourceRange(), Error->ET_ParserOverloadedType)928        << Value.getTypeAsString();929  }930  return Result;931}932 933} // namespace dynamic934} // namespace ast_matchers935} // namespace clang936