================ @@ -1029,5 +1172,151 @@ size_t renameRangeAdjustmentCost(ArrayRef<Range> Indexed, ArrayRef<Range> Lexed, return Cost; } +static bool isMatchingSelectorName(const syntax::Token &Cur, + const syntax::Token &Next, + const SourceManager &SM, + llvm::StringRef SelectorName) { + if (SelectorName.empty()) + return Cur.kind() == tok::colon; + return Cur.kind() == tok::identifier && Next.kind() == tok::colon && + Cur.text(SM) == SelectorName && + // We require the selector name and : to be contiguous. + // e.g. support `foo:` but not `foo :`. + Cur.endLocation() == Next.location(); +} + +static bool isSelectorLike(const syntax::Token &Cur, + const syntax::Token &Next) { + return Cur.kind() == tok::identifier && Next.kind() == tok::colon && + // We require the selector name and : to be contiguous. + // e.g. support `foo:` but not `foo :`. + Cur.endLocation() == Next.location(); +} + +static void +lex(llvm::StringRef Code, const LangOptions &LangOpts, + llvm::function_ref<void(const syntax::Token &, const SourceManager &SM)> + Action) { + // FIXME: InMemoryFileAdapter crashes unless the buffer is null terminated! + std::string NullTerminatedCode = Code.str(); + SourceManagerForFile FileSM("mock_file_name.cpp", NullTerminatedCode); + auto &SM = FileSM.get(); + for (const auto &Tok : syntax::tokenize(SM.getMainFileID(), SM, LangOpts)) + Action(Tok, SM); +} + +std::vector<SymbolRange> collectRenameIdentifierRanges( + llvm::StringRef Identifier, llvm::StringRef Content, + const LangOptions &LangOpts, std::optional<Selector> Selector) { + std::vector<SymbolRange> Ranges; + if (!Selector) { + lex(Content, LangOpts, + [&](const syntax::Token &Tok, const SourceManager &SM) { + if (Tok.kind() != tok::identifier || Tok.text(SM) != Identifier) + return; + Ranges.emplace_back( + halfOpenToRange(SM, Tok.range(SM).toCharRange(SM))); + }); + return Ranges; + } + // FIXME: InMemoryFileAdapter crashes unless the buffer is null terminated! + std::string NullTerminatedCode = Content.str(); + SourceManagerForFile FileSM("mock_file_name.cpp", NullTerminatedCode); + auto &SM = FileSM.get(); + + auto Tokens = syntax::tokenize(SM.getMainFileID(), SM, LangOpts); + unsigned Last = Tokens.size() - 1; + + // One parser state for top level and each `[]` pair, can be nested. + // Technically we should have a state or recursion for each ()/{} as well, + // but since we're expecting well formed code it shouldn't matter in practice. + struct ParserState { + unsigned ParenCount = 0; + unsigned BraceCount = 0; + std::vector<Range> Pieces; + }; + + // We have to track square brackets, parens and braces as we want to skip the + // tokens inside them. This ensures that we don't use identical selector + // pieces in inner message sends, blocks, lambdas and @selector expressions. + std::vector<ParserState> States = {ParserState()}; + unsigned NumPieces = Selector->getNumArgs(); + + for (unsigned Index = 0; Index < Last; ++Index) { + auto &State = States.back(); + auto &Pieces = State.Pieces; + const auto &Tok = Tokens[Index]; + const auto Kind = Tok.kind(); + auto PieceCount = Pieces.size(); + + if (State.ParenCount == 0) { + // Check for matches until we find all selector pieces. + if (PieceCount < NumPieces && + isMatchingSelectorName(Tok, Tokens[Index + 1], SM, + Selector->getNameForSlot(PieceCount))) { + if (!Selector->getNameForSlot(PieceCount).empty()) { + // Skip the ':' after the name. This ensures that it won't match a + // follow-up selector piece with an empty name. + ++Index; + } + Pieces.push_back(halfOpenToRange(SM, Tok.range(SM).toCharRange(SM))); + continue; + } + // If we've found all pieces, we still need to try to consume more pieces + // as it's possible the selector being renamed is a prefix of this method + // name. ---------------- DavidGoldman wrote:
Updated, parseMessageExpression can return early but the top level parse can't. https://github.com/llvm/llvm-project/pull/76466 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits