Skip to content

Commit 868d2e0

Browse files
committed
[clangd] Address review comments to support rename of Objective-C selectors
1 parent 8ce6dd8 commit 868d2e0

File tree

10 files changed

+77
-81
lines changed

10 files changed

+77
-81
lines changed

clang-tools-extra/clangd/refactor/Rename.cpp

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -526,23 +526,25 @@ std::optional<InvalidName> checkName(const NamedDecl &RenameDecl,
526526
static constexpr trace::Metric InvalidNameMetric(
527527
"rename_name_invalid", trace::Metric::Counter, "invalid_kind");
528528
auto &ASTCtx = RenameDecl.getASTContext();
529+
auto Identifier = NewName.getSinglePiece();
530+
if (!Identifier) {
531+
return std::nullopt;
532+
}
529533
std::optional<InvalidName> Result;
530-
if (auto Identifier = NewName.getSinglePiece()) {
531-
if (isKeyword(*Identifier, ASTCtx.getLangOpts()))
532-
Result = InvalidName{InvalidName::Keywords, *Identifier};
533-
else if (!mayBeValidIdentifier(*Identifier))
534-
Result = InvalidName{InvalidName::BadIdentifier, *Identifier};
535-
else {
536-
// Name conflict detection.
537-
// Function conflicts are subtle (overloading), so ignore them.
538-
if (RenameDecl.getKind() != Decl::Function &&
539-
RenameDecl.getKind() != Decl::CXXMethod) {
540-
if (auto *Conflict =
541-
lookupSiblingWithName(ASTCtx, RenameDecl, *Identifier))
542-
Result = InvalidName{
543-
InvalidName::Conflict,
544-
Conflict->getLocation().printToString(ASTCtx.getSourceManager())};
545-
}
534+
if (isKeyword(*Identifier, ASTCtx.getLangOpts())) {
535+
Result = InvalidName{InvalidName::Keywords, *Identifier};
536+
} else if (!mayBeValidIdentifier(*Identifier)) {
537+
Result = InvalidName{InvalidName::BadIdentifier, *Identifier};
538+
} else {
539+
// Name conflict detection.
540+
// Function conflicts are subtle (overloading), so ignore them.
541+
if (RenameDecl.getKind() != Decl::Function &&
542+
RenameDecl.getKind() != Decl::CXXMethod) {
543+
if (auto *Conflict =
544+
lookupSiblingWithName(ASTCtx, RenameDecl, *Identifier))
545+
Result = InvalidName{
546+
InvalidName::Conflict,
547+
Conflict->getLocation().printToString(ASTCtx.getSourceManager())};
546548
}
547549
}
548550
if (Result)
@@ -579,24 +581,26 @@ renameWithinFile(ParsedAST &AST, const NamedDecl &RenameDecl,
579581
if (std::optional<std::string> Identifier = NewName.getSinglePiece()) {
580582
tooling::Replacement NewReplacement(
581583
SM, CharSourceRange::getTokenRange(RenameLoc), *Identifier);
582-
if (auto Err = FilteredChanges.add(NewReplacement))
584+
if (auto Err = FilteredChanges.add(NewReplacement)) {
583585
return std::move(Err);
584-
} else {
585-
llvm::Expected<SmallVector<SourceLocation>> PieceLocations =
586-
findObjCSymbolSelectorPieces(
587-
AST.getTokens().expandedTokens(), SM, RenameLoc, OldName,
588-
tooling::ObjCSymbolSelectorKind::Unknown);
589-
if (!PieceLocations) {
590-
return PieceLocations.takeError();
591-
}
592-
assert(PieceLocations->size() == NewName.getNamePieces().size());
593-
for (auto [Location, NewPiece] :
594-
llvm::zip_equal(*PieceLocations, NewName.getNamePieces())) {
595-
tooling::Replacement NewReplacement(
596-
SM, CharSourceRange::getTokenRange(Location), NewPiece);
597-
if (auto Err = FilteredChanges.add(NewReplacement))
598-
return std::move(Err);
599586
}
587+
continue;
588+
}
589+
SmallVector<SourceLocation> PieceLocations;
590+
llvm::Error Error = findObjCSymbolSelectorPieces(
591+
AST.getTokens().expandedTokens(), SM, RenameLoc, OldName,
592+
tooling::ObjCSymbolSelectorKind::Unknown, PieceLocations);
593+
if (Error) {
594+
// Ignore the error. We simply skip over all selectors that didn't match.
595+
consumeError(std::move(Error));
596+
continue;
597+
}
598+
for (auto [Location, NewPiece] :
599+
llvm::zip_equal(PieceLocations, NewName.getNamePieces())) {
600+
tooling::Replacement NewReplacement(
601+
SM, CharSourceRange::getTokenRange(Location), NewPiece);
602+
if (auto Err = FilteredChanges.add(NewReplacement))
603+
return std::move(Err);
600604
}
601605
}
602606
return FilteredChanges;
@@ -811,18 +815,16 @@ llvm::Expected<RenameResult> rename(const RenameInputs &RInputs) {
811815
if (!Name)
812816
return makeError(ReasonToReject::UnsupportedSymbol);
813817
SymbolName OldSymbolName(Name);
814-
SymbolName NewSymbolName(ArrayRef<StringRef>{});
815-
if (std::optional<StringRef> NewName = RInputs.NewName) {
816-
NewSymbolName = SymbolName(*NewName, AST.getLangOpts());
818+
SymbolName NewSymbolName;
819+
if (RInputs.NewName) {
820+
NewSymbolName = SymbolName(*RInputs.NewName, AST.getLangOpts());
817821
} else {
818822
// If no new name is given, we are perfoming a pseudo rename for the
819823
// prepareRename request to check if the rename is possible. Construct a
820824
// new symbol name that has as many name pieces as the old name and is thus
821825
// a valid new name.
822-
std::vector<std::string> NewNamePieces;
823-
for (StringRef Piece : OldSymbolName.getNamePieces()) {
824-
NewNamePieces.push_back(Piece.str() + "__clangd_rename_placeholder");
825-
}
826+
std::vector<std::string> NewNamePieces = OldSymbolName.getNamePieces();
827+
NewNamePieces[0] += "__clangd_rename_placeholder";
826828
NewSymbolName = SymbolName(NewNamePieces);
827829
}
828830
if (OldSymbolName == NewSymbolName)
@@ -961,18 +963,20 @@ buildRenameEdit(llvm::StringRef AbsFilePath, llvm::StringRef InitialCode,
961963
AbsFilePath, R.first, ByteLength, *Identifier)))
962964
return std::move(Err);
963965
} else {
964-
llvm::Expected<SmallVector<SourceLocation>> PieceLocations =
965-
findObjCSymbolSelectorPieces(
966-
Tokens.tokens(), SM,
967-
SM.getLocForStartOfFile(SM.getMainFileID())
968-
.getLocWithOffset(R.first),
969-
OldName, tooling::ObjCSymbolSelectorKind::Unknown);
970-
if (!PieceLocations) {
971-
return PieceLocations.takeError();
966+
SmallVector<SourceLocation> PieceLocations;
967+
llvm::Error Error = findObjCSymbolSelectorPieces(
968+
Tokens.tokens(), SM,
969+
SM.getLocForStartOfFile(SM.getMainFileID()).getLocWithOffset(R.first),
970+
OldName, tooling::ObjCSymbolSelectorKind::Unknown, PieceLocations);
971+
if (Error) {
972+
// Ignore the error. We simply skip over all selectors that didn't
973+
// match.
974+
consumeError(std::move(Error));
975+
continue;
972976
}
973-
assert(PieceLocations->size() == NewName.getNamePieces().size());
977+
assert(PieceLocations.size() == NewName.getNamePieces().size());
974978
for (auto [Location, NewPiece] :
975-
llvm::zip_equal(*PieceLocations, NewName.getNamePieces())) {
979+
llvm::zip_equal(PieceLocations, NewName.getNamePieces())) {
976980
tooling::Replacement NewReplacement(
977981
SM, CharSourceRange::getTokenRange(Location), NewPiece);
978982
if (auto Err = RenameEdit.add(NewReplacement))

clang-tools-extra/clangd/refactor/Rename.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ llvm::Expected<RenameResult> rename(const RenameInputs &RInputs);
7575
/// Generates rename edits that replaces all given occurrences with the
7676
/// `NewName`.
7777
///
78-
/// `OldName` is and `Tokens` are used to to find the argument labels of
78+
/// `OldName` and `Tokens` are used to to find the argument labels of
7979
/// Objective-C selectors.
8080
///
8181
/// Exposed for testing only.

clang-tools-extra/clangd/unittests/RenameTests.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,7 +1535,6 @@ TEST(RenameTest, PrepareRenameObjC) {
15351535
for (Position Point : Input.points()) {
15361536
auto Results = runPrepareRename(Server, Path, Point,
15371537
/*NewName=*/std::nullopt, {});
1538-
// Verify that for multi-file rename, we only return main-file occurrences.
15391538
ASSERT_TRUE(bool(Results)) << Results.takeError();
15401539
ASSERT_EQ(Results->OldName, "performAction:with:");
15411540
}
@@ -1947,8 +1946,7 @@ TEST(CrossFileRenameTests, WithUpToDateIndex) {
19471946
TEST(CrossFileRenameTests, ObjC) {
19481947
MockCompilationDatabase CDB;
19491948
CDB.ExtraClangFlags = {"-xobjective-c"};
1950-
// rename is runnning on all "^" points in FooH, and "[[]]" ranges are the
1951-
// expected rename occurrences.
1949+
// rename is runnning on all "^" points in FooH.
19521950
struct Case {
19531951
llvm::StringRef FooH;
19541952
llvm::StringRef FooM;

clang/include/clang/Tooling/Refactoring/Rename/RenamingAction.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ enum class ObjCSymbolSelectorKind {
132132
Unknown
133133
};
134134

135-
llvm::Expected<SmallVector<SourceLocation>> findObjCSymbolSelectorPieces(
135+
llvm::Error findObjCSymbolSelectorPieces(
136136
ArrayRef<syntax::Token> Tokens, const SourceManager &SrcMgr,
137137
SourceLocation RenameLoc, const SymbolName &OldName,
138-
ObjCSymbolSelectorKind Kind);
138+
ObjCSymbolSelectorKind Kind, SmallVectorImpl<SourceLocation> &Result);
139139

140140
} // end namespace tooling
141141
} // end namespace clang

clang/include/clang/Tooling/Refactoring/Rename/SymbolName.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class SymbolName {
3434
llvm::SmallVector<std::string, 1> NamePieces;
3535

3636
public:
37+
SymbolName();
38+
3739
/// Create a new \c SymbolName with the specified pieces.
3840
explicit SymbolName(ArrayRef<StringRef> NamePieces);
3941
explicit SymbolName(ArrayRef<std::string> NamePieces);

clang/include/clang/Tooling/Syntax/Tokens.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,6 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Token &T);
148148
/// A list of tokens as lexed from the input file, without expanding
149149
/// preprocessor macros.
150150
class UnexpandedTokenBuffer {
151-
std::string Code;
152151
std::vector<syntax::Token> Tokens;
153152
std::unique_ptr<SourceManagerForFile> SrcMgr;
154153

clang/lib/Tooling/Refactoring/Rename/RenamingAction.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,12 @@ static bool isMatchingSelectorName(const syntax::Token &Tok,
285285
Next.kind() == tok::colon && Tok.text(SrcMgr) == NamePiece;
286286
}
287287

288-
llvm::Expected<SmallVector<SourceLocation>>
289-
findObjCSymbolSelectorPieces(ArrayRef<syntax::Token> AllTokens,
290-
const SourceManager &SM, SourceLocation RenameLoc,
291-
const SymbolName &OldName,
292-
ObjCSymbolSelectorKind Kind) {
288+
Error findObjCSymbolSelectorPieces(ArrayRef<syntax::Token> AllTokens,
289+
const SourceManager &SM,
290+
SourceLocation RenameLoc,
291+
const SymbolName &OldName,
292+
ObjCSymbolSelectorKind Kind,
293+
SmallVectorImpl<SourceLocation> &Result) {
293294
ArrayRef<syntax::Token> Tokens =
294295
AllTokens.drop_while([RenameLoc](syntax::Token Tok) -> bool {
295296
return Tok.location() != RenameLoc;
@@ -298,7 +299,6 @@ findObjCSymbolSelectorPieces(ArrayRef<syntax::Token> AllTokens,
298299
assert(OldName.getNamePieces()[0].empty() ||
299300
Tokens[0].text(SM) == OldName.getNamePieces()[0]);
300301
assert(OldName.getNamePieces().size() > 1);
301-
SmallVector<SourceLocation> Result;
302302

303303
Result.push_back(Tokens[0].location());
304304

@@ -328,7 +328,7 @@ findObjCSymbolSelectorPieces(ArrayRef<syntax::Token> AllTokens,
328328
Result.push_back(Tok.location());
329329
// All the selector pieces have been found.
330330
if (Result.size() == OldName.getNamePieces().size())
331-
return Result;
331+
return Error::success();
332332
} else if (Tok.kind() == tok::r_square) {
333333
// Stop scanning at the end of the message send.
334334
// Also account for spurious ']' in blocks or lambdas.
@@ -337,11 +337,11 @@ findObjCSymbolSelectorPieces(ArrayRef<syntax::Token> AllTokens,
337337
break;
338338
if (SquareCount)
339339
--SquareCount;
340-
} else if (Tok.kind() == tok::l_square)
340+
} else if (Tok.kind() == tok::l_square) {
341341
++SquareCount;
342-
else if (Tok.kind() == tok::l_paren)
342+
} else if (Tok.kind() == tok::l_paren) {
343343
++ParenCount;
344-
else if (Tok.kind() == tok::r_paren) {
344+
} else if (Tok.kind() == tok::r_paren) {
345345
if (!ParenCount)
346346
break;
347347
--ParenCount;

clang/lib/Tooling/Refactoring/SymbolName.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
namespace clang {
1414
namespace tooling {
1515

16+
SymbolName::SymbolName() : NamePieces({}) {}
17+
1618
SymbolName::SymbolName(const DeclarationName &DeclName)
1719
: SymbolName(DeclName.getAsString(),
1820
/*IsObjectiveCSelector=*/DeclName.getNameKind() ==
@@ -49,9 +51,8 @@ SymbolName::SymbolName(ArrayRef<std::string> NamePieces) {
4951
std::optional<std::string> SymbolName::getSinglePiece() const {
5052
if (getNamePieces().size() == 1) {
5153
return NamePieces.front();
52-
} else {
53-
return std::nullopt;
5454
}
55+
return std::nullopt;
5556
}
5657

5758
std::string SymbolName::getAsString() const {
@@ -62,11 +63,7 @@ std::string SymbolName::getAsString() const {
6263
}
6364

6465
void SymbolName::print(raw_ostream &OS) const {
65-
for (size_t I = 0, E = NamePieces.size(); I != E; ++I) {
66-
if (I != 0)
67-
OS << ':';
68-
OS << NamePieces[I];
69-
}
66+
llvm::interleave(NamePieces, OS, ":");
7067
}
7168

7269
} // end namespace tooling

clang/lib/Tooling/Syntax/Tokens.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,11 +227,7 @@ llvm::StringRef FileRange::text(const SourceManager &SM) const {
227227

228228
UnexpandedTokenBuffer::UnexpandedTokenBuffer(StringRef Code,
229229
const LangOptions &LangOpts) {
230-
// InMemoryFileAdapter crashes unless the buffer is null terminated, so ensure
231-
// the string is null-terminated.
232-
this->Code = Code.str();
233-
SrcMgr =
234-
std::make_unique<SourceManagerForFile>("mock_file_name.cpp", this->Code);
230+
SrcMgr = std::make_unique<SourceManagerForFile>("mock_file_name.cpp", Code);
235231
Tokens = syntax::tokenize(sourceManager().getMainFileID(), sourceManager(),
236232
LangOpts);
237233
}

clang/unittests/Tooling/RefactoringActionRulesTest.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,9 @@ TEST_F(RefactoringActionRulesTest, ReturnSymbolOccurrences) {
211211
Expected<SymbolOccurrences>
212212
findSymbolOccurrences(RefactoringRuleContext &) override {
213213
SymbolOccurrences Occurrences;
214-
Occurrences.push_back(SymbolOccurrence(SymbolName("test"),
215-
SymbolOccurrence::MatchingSymbol,
216-
Selection.getBegin()));
214+
Occurrences.push_back(SymbolOccurrence(
215+
SymbolName("test", /*IsObjectiveCSelector=*/false),
216+
SymbolOccurrence::MatchingSymbol, Selection.getBegin()));
217217
return std::move(Occurrences);
218218
}
219219
};

0 commit comments

Comments
 (0)