1818#include " clang/AST/ASTContext.h"
1919#include " clang/AST/ASTTypeTraits.h"
2020#include " clang/AST/Decl.h"
21+ #include " clang/AST/DeclBase.h"
2122#include " clang/AST/DeclCXX.h"
2223#include " clang/AST/DeclObjC.h"
2324#include " clang/AST/DeclTemplate.h"
25+ #include " clang/AST/DeclarationName.h"
2426#include " clang/AST/ParentMapContext.h"
2527#include " clang/AST/Stmt.h"
2628#include " clang/Basic/CharInfo.h"
@@ -597,11 +599,12 @@ bool isMatchingSelectorName(const syntax::Token &Cur, const syntax::Token &Next,
597599// The search will terminate upon seeing Terminator or a ; at the top level.
598600std::optional<SymbolRange>
599601findAllSelectorPieces (llvm::ArrayRef<syntax::Token> Tokens,
600- const SourceManager &SM, Selector Sel ,
602+ const SourceManager &SM, const RenameSymbolName &Name ,
601603 tok::TokenKind Terminator) {
602604 assert (!Tokens.empty ());
603605
604- unsigned NumArgs = Sel.getNumArgs ();
606+ ArrayRef<std::string> NamePieces = Name.getNamePieces ();
607+ unsigned NumArgs = NamePieces.size ();
605608 llvm::SmallVector<tok::TokenKind, 8 > Closes;
606609 std::vector<Range> SelectorPieces;
607610 for (unsigned Index = 0 , Last = Tokens.size (); Index < Last - 1 ; ++Index) {
@@ -611,12 +614,12 @@ findAllSelectorPieces(llvm::ArrayRef<syntax::Token> Tokens,
611614 auto PieceCount = SelectorPieces.size ();
612615 if (PieceCount < NumArgs &&
613616 isMatchingSelectorName (Tok, Tokens[Index + 1 ], SM,
614- Sel. getNameForSlot ( PieceCount) )) {
617+ NamePieces[ PieceCount] )) {
615618 // If 'foo:' instead of ':' (empty selector), we need to skip the ':'
616619 // token after the name. We don't currently properly support empty
617620 // selectors since we may lex them improperly due to ternary statements
618621 // as well as don't properly support storing their ranges for edits.
619- if (!Sel. getNameForSlot ( PieceCount) .empty ())
622+ if (!NamePieces[ PieceCount] .empty ())
620623 ++Index;
621624 SelectorPieces.push_back (
622625 halfOpenToRange (SM, Tok.range (SM).toCharRange (SM)));
@@ -668,16 +671,17 @@ findAllSelectorPieces(llvm::ArrayRef<syntax::Token> Tokens,
668671
669672// / Collects all ranges of the given identifier/selector in the source code.
670673// /
671- // / If a selector is given, this does a full lex of the given source code in
672- // / order to identify all selector fragments (e.g. in method exprs/decls) since
673- // / they are non-contiguous.
674- std::vector<SymbolRange> collectRenameIdentifierRanges (
675- llvm::StringRef Identifier, llvm::StringRef Content,
676- const LangOptions &LangOpts, std::optional<Selector> Selector) {
674+ // / If `Name` is an Objective-C symbol name, this does a full lex of the given
675+ // / source code in order to identify all selector fragments (e.g. in method
676+ // / exprs/decls) since they are non-contiguous.
677+ std::vector<SymbolRange>
678+ collectRenameIdentifierRanges (const RenameSymbolName &Name,
679+ llvm::StringRef Content,
680+ const LangOptions &LangOpts) {
677681 std::vector<SymbolRange> Ranges;
678- if (!Selector ) {
682+ if (auto SinglePiece = Name. getSinglePiece () ) {
679683 auto IdentifierRanges =
680- collectIdentifierRanges (Identifier , Content, LangOpts);
684+ collectIdentifierRanges (*SinglePiece , Content, LangOpts);
681685 for (const auto &R : IdentifierRanges)
682686 Ranges.emplace_back (R);
683687 return Ranges;
@@ -691,7 +695,7 @@ std::vector<SymbolRange> collectRenameIdentifierRanges(
691695 // parsing a method declaration or definition which isn't at the top level or
692696 // similar looking expressions (e.g. an @selector() expression).
693697 llvm::SmallVector<tok::TokenKind, 8 > Closes;
694- llvm::StringRef FirstSelPiece = Selector-> getNameForSlot ( 0 ) ;
698+ llvm::StringRef FirstSelPiece = Name. getNamePieces ()[ 0 ] ;
695699
696700 auto Tokens = syntax::tokenize (SM.getMainFileID (), SM, LangOpts);
697701 unsigned Last = Tokens.size () - 1 ;
@@ -723,7 +727,7 @@ std::vector<SymbolRange> collectRenameIdentifierRanges(
723727 // Check if we can find all the relevant selector peices starting from
724728 // this token
725729 auto SelectorRanges =
726- findAllSelectorPieces (ArrayRef (Tokens).slice (Index), SM, *Selector ,
730+ findAllSelectorPieces (ArrayRef (Tokens).slice (Index), SM, Name ,
727731 Closes.empty () ? tok::l_brace : Closes.back ());
728732 if (SelectorRanges)
729733 Ranges.emplace_back (std::move (*SelectorRanges));
@@ -770,7 +774,6 @@ renameObjCMethodWithinFile(ParsedAST &AST, const ObjCMethodDecl *MD,
770774 std::vector<SourceLocation> SelectorOccurences) {
771775 const SourceManager &SM = AST.getSourceManager ();
772776 auto Code = SM.getBufferData (SM.getMainFileID ());
773- auto RenameIdentifier = MD->getSelector ().getNameForSlot (0 ).str ();
774777 llvm::SmallVector<llvm::StringRef, 8 > NewNames;
775778 NewName.split (NewNames, " :" );
776779
@@ -780,7 +783,7 @@ renameObjCMethodWithinFile(ParsedAST &AST, const ObjCMethodDecl *MD,
780783 Ranges.push_back (tokenRangeForLoc (AST, Loc, SM, LangOpts));
781784 auto FilePath = AST.tuPath ();
782785 auto RenameRanges = collectRenameIdentifierRanges (
783- RenameIdentifier , Code, LangOpts, MD-> getSelector () );
786+ RenameSymbolName (MD-> getDeclName ()) , Code, LangOpts);
784787 auto RenameEdit = buildRenameEdit (FilePath, Code, RenameRanges, NewNames);
785788 if (!RenameEdit)
786789 return error (" failed to rename in file {0}: {1}" , FilePath,
@@ -942,21 +945,14 @@ renameOutsideFile(const NamedDecl &RenameDecl, llvm::StringRef MainFilePath,
942945 ExpBuffer.getError ().message ());
943946 continue ;
944947 }
945- std::string RenameIdentifier = RenameDecl.getNameAsString ();
946- std::optional<Selector> Selector = std::nullopt ;
948+ RenameSymbolName RenameName (RenameDecl.getDeclName ());
947949 llvm::SmallVector<llvm::StringRef, 8 > NewNames;
948- if (const auto *MD = dyn_cast<ObjCMethodDecl>(&RenameDecl)) {
949- RenameIdentifier = MD->getSelector ().getNameForSlot (0 ).str ();
950- if (MD->getSelector ().getNumArgs () > 1 )
951- Selector = MD->getSelector ();
952- }
953950 NewName.split (NewNames, " :" );
954951
955952 auto AffectedFileCode = (*ExpBuffer)->getBuffer ();
956- auto RenameRanges =
957- adjustRenameRanges (AffectedFileCode, RenameIdentifier,
958- std::move (FileAndOccurrences.second ),
959- RenameDecl.getASTContext ().getLangOpts (), Selector);
953+ auto RenameRanges = adjustRenameRanges (
954+ AffectedFileCode, RenameName, std::move (FileAndOccurrences.second ),
955+ RenameDecl.getASTContext ().getLangOpts ());
960956 if (!RenameRanges) {
961957 // Our heuristics fails to adjust rename ranges to the current state of
962958 // the file, it is most likely the index is stale, so we give up the
@@ -1017,6 +1013,50 @@ void findNearMiss(
10171013
10181014} // namespace
10191015
1016+ RenameSymbolName::RenameSymbolName () : NamePieces({}) {}
1017+
1018+ namespace {
1019+ std::vector<std::string> extractNamePieces (const DeclarationName &DeclName) {
1020+ if (DeclName.getNameKind () ==
1021+ DeclarationName::NameKind::ObjCMultiArgSelector ||
1022+ DeclName.getNameKind () == DeclarationName::NameKind::ObjCOneArgSelector) {
1023+ const Selector &Sel = DeclName.getObjCSelector ();
1024+ std::vector<std::string> Result;
1025+ for (unsigned Slot = 0 ; Slot < Sel.getNumArgs (); ++Slot) {
1026+ Result.push_back (Sel.getNameForSlot (Slot).str ());
1027+ }
1028+ return Result;
1029+ }
1030+ return {DeclName.getAsString ()};
1031+ }
1032+ } // namespace
1033+
1034+ RenameSymbolName::RenameSymbolName (const DeclarationName &DeclName)
1035+ : RenameSymbolName(extractNamePieces(DeclName)) {}
1036+
1037+ RenameSymbolName::RenameSymbolName (ArrayRef<std::string> NamePieces) {
1038+ for (const auto &Piece : NamePieces)
1039+ this ->NamePieces .push_back (Piece);
1040+ }
1041+
1042+ std::optional<std::string> RenameSymbolName::getSinglePiece () const {
1043+ if (getNamePieces ().size () == 1 ) {
1044+ return NamePieces.front ();
1045+ }
1046+ return std::nullopt ;
1047+ }
1048+
1049+ std::string RenameSymbolName::getAsString () const {
1050+ std::string Result;
1051+ llvm::raw_string_ostream OS (Result);
1052+ this ->print (OS);
1053+ return Result;
1054+ }
1055+
1056+ void RenameSymbolName::print (raw_ostream &OS) const {
1057+ llvm::interleave (NamePieces, OS, " :" );
1058+ }
1059+
10201060SymbolRange::SymbolRange (Range R) : Ranges({R}) {}
10211061
10221062SymbolRange::SymbolRange (std::vector<Range> Ranges)
@@ -1244,14 +1284,13 @@ llvm::Expected<Edit> buildRenameEdit(llvm::StringRef AbsFilePath,
12441284// were inserted). If such a "near miss" is found, the rename is still
12451285// possible
12461286std::optional<std::vector<SymbolRange>>
1247- adjustRenameRanges (llvm::StringRef DraftCode, llvm::StringRef Identifier,
1248- std::vector<Range> Indexed, const LangOptions &LangOpts,
1249- std::optional<Selector> Selector) {
1287+ adjustRenameRanges (llvm::StringRef DraftCode, const RenameSymbolName &Name,
1288+ std::vector<Range> Indexed, const LangOptions &LangOpts) {
12501289 trace::Span Tracer (" AdjustRenameRanges" );
12511290 assert (!Indexed.empty ());
12521291 assert (llvm::is_sorted (Indexed));
12531292 std::vector<SymbolRange> Lexed =
1254- collectRenameIdentifierRanges (Identifier , DraftCode, LangOpts, Selector );
1293+ collectRenameIdentifierRanges (Name , DraftCode, LangOpts);
12551294 llvm::sort (Lexed);
12561295 return getMappedRanges (Indexed, Lexed);
12571296}
0 commit comments