Skip to content

Commit 898d7a0

Browse files
committed
[clangd] Delete default arguments while moving functions out-of-line
Summary: Only function declarations should have the default arguments. This patch makes sure we don't propogate those arguments to out-of-line definitions. Fixes clangd/clangd#221 Reviewers: hokein Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D71187
1 parent fc3417c commit 898d7a0

File tree

2 files changed

+47
-10
lines changed

2 files changed

+47
-10
lines changed

clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "FindTarget.h"
1111
#include "HeaderSourceSwitch.h"
1212
#include "Logger.h"
13+
#include "ParsedAST.h"
1314
#include "Path.h"
1415
#include "Selection.h"
1516
#include "SourceCode.h"
@@ -21,11 +22,15 @@
2122
#include "clang/AST/Stmt.h"
2223
#include "clang/Basic/SourceLocation.h"
2324
#include "clang/Basic/SourceManager.h"
25+
#include "clang/Basic/TokenKinds.h"
2426
#include "clang/Driver/Types.h"
2527
#include "clang/Format/Format.h"
28+
#include "clang/Lex/Lexer.h"
2629
#include "clang/Tooling/Core/Replacement.h"
30+
#include "clang/Tooling/Syntax/Tokens.h"
2731
#include "llvm/ADT/None.h"
2832
#include "llvm/ADT/Optional.h"
33+
#include "llvm/ADT/STLExtras.h"
2934
#include "llvm/ADT/StringRef.h"
3035
#include "llvm/Support/Casting.h"
3136
#include "llvm/Support/Error.h"
@@ -133,12 +138,14 @@ getFunctionSourceAfterReplacements(const FunctionDecl *FD,
133138

134139
// Creates a modified version of function definition that can be inserted at a
135140
// different location, qualifies return value and function name to achieve that.
136-
// Contains function signature, body and template parameters if applicable.
137-
// No need to qualify parameters, as they are looked up in the context
138-
// containing the function/method.
141+
// Contains function signature, except defaulted parameter arguments, body and
142+
// template parameters if applicable. No need to qualify parameters, as they are
143+
// looked up in the context containing the function/method.
139144
llvm::Expected<std::string>
140-
getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace) {
141-
auto &SM = FD->getASTContext().getSourceManager();
145+
getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace,
146+
const syntax::TokenBuffer &TokBuf) {
147+
auto &AST = FD->getASTContext();
148+
auto &SM = AST.getSourceManager();
142149
auto TargetContext = findContextForNS(TargetNamespace, FD->getDeclContext());
143150
if (!TargetContext)
144151
return llvm::createStringError(
@@ -169,14 +176,38 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace) {
169176
}
170177
}
171178
const NamedDecl *ND = Ref.Targets.front();
172-
const std::string Qualifier =
173-
getQualification(FD->getASTContext(), *TargetContext,
174-
SM.getLocForStartOfFile(SM.getMainFileID()), ND);
179+
const std::string Qualifier = getQualification(
180+
AST, *TargetContext, SM.getLocForStartOfFile(SM.getMainFileID()), ND);
175181
if (auto Err = QualifierInsertions.add(
176182
tooling::Replacement(SM, Ref.NameLoc, 0, Qualifier)))
177183
Errors = llvm::joinErrors(std::move(Errors), std::move(Err));
178184
});
179185

186+
// Get rid of default arguments, since they should not be specified in
187+
// out-of-line definition.
188+
for (const auto *PVD : FD->parameters()) {
189+
if (PVD->hasDefaultArg()) {
190+
// Deletion range initially spans the initializer, excluding the `=`.
191+
auto DelRange = CharSourceRange::getTokenRange(PVD->getDefaultArgRange());
192+
// Get all tokens before the default argument.
193+
auto Tokens = TokBuf.expandedTokens(PVD->getSourceRange())
194+
.take_while([&SM, &DelRange](const syntax::Token &Tok) {
195+
return SM.isBeforeInTranslationUnit(
196+
Tok.location(), DelRange.getBegin());
197+
});
198+
// Find the last `=` before the default arg.
199+
auto Tok =
200+
llvm::find_if(llvm::reverse(Tokens), [](const syntax::Token &Tok) {
201+
return Tok.kind() == tok::equal;
202+
});
203+
assert(Tok != Tokens.rend());
204+
DelRange.setBegin(Tok->location());
205+
if (auto Err =
206+
QualifierInsertions.add(tooling::Replacement(SM, DelRange, "")))
207+
Errors = llvm::joinErrors(std::move(Errors), std::move(Err));
208+
}
209+
}
210+
180211
if (Errors)
181212
return std::move(Errors);
182213
return getFunctionSourceAfterReplacements(FD, QualifierInsertions);
@@ -290,8 +321,8 @@ class DefineOutline : public Tweak {
290321
if (!InsertionPoint)
291322
return InsertionPoint.takeError();
292323

293-
auto FuncDef =
294-
getFunctionSourceCode(Source, InsertionPoint->EnclosingNamespace);
324+
auto FuncDef = getFunctionSourceCode(
325+
Source, InsertionPoint->EnclosingNamespace, Sel.AST.getTokens());
295326
if (!FuncDef)
296327
return FuncDef.takeError();
297328

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,6 +1973,12 @@ TEST_F(DefineOutlineTest, ApplyTest) {
19731973
template <> void foo<int>() ;)cpp",
19741974
"template <> void foo<int>() { return; }",
19751975
},
1976+
// Default args.
1977+
{
1978+
"void fo^o(int x, int y = 5, int = 2, int (*foo)(int) = nullptr) {}",
1979+
"void foo(int x, int y = 5, int = 2, int (*foo)(int) = nullptr) ;",
1980+
"void foo(int x, int y , int , int (*foo)(int) ) {}",
1981+
},
19761982
};
19771983
for (const auto &Case : Cases) {
19781984
SCOPED_TRACE(Case.Test);

0 commit comments

Comments
 (0)