[clang-tools-extra] a209a80 - [clangd] Delete ctor initializers while moving functions out-of-line
Kadir Cetinkaya via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 9 09:56:26 PST 2019
Author: Kadir Cetinkaya
Date: 2019-12-09T18:52:57+01:00
New Revision: a209a8000e17ef3560598a44825747aab2f7914d
URL: https://github.com/llvm/llvm-project/commit/a209a8000e17ef3560598a44825747aab2f7914d
DIFF: https://github.com/llvm/llvm-project/commit/a209a8000e17ef3560598a44825747aab2f7914d.diff
LOG: [clangd] Delete ctor initializers while moving functions out-of-line
Summary:
Currently we only delete function body from declaration, in addition to
that we should also drop ctor initializers.
Unfortunately CXXConstructorDecl doesn't store the location of `:` before
initializers, therefore we make use of token buffer to figure out where to start
deletion.
Fixes https://github.com/clangd/clangd/issues/220
Reviewers: hokein, ilya-biryukov
Subscribers: MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D71188
Added:
Modified:
clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
clang-tools-extra/clangd/unittests/TweakTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
index 4935aa005153..353da26a0f91 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/SourceLocation.h"
@@ -141,6 +142,7 @@ getFunctionSourceAfterReplacements(const FunctionDecl *FD,
// Contains function signature, except defaulted parameter arguments, body and
// template parameters if applicable. No need to qualify parameters, as they are
// looked up in the context containing the function/method.
+// FIXME: Drop attributes in function signature.
llvm::Expected<std::string>
getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace,
const syntax::TokenBuffer &TokBuf) {
@@ -238,6 +240,45 @@ getInsertionPoint(llvm::StringRef Contents, llvm::StringRef QualifiedName,
return InsertionPoint{Region.EnclosingNamespace, *Offset};
}
+// Returns the range that should be deleted from declaration, which always
+// contains function body. In addition to that it might contain constructor
+// initializers.
+SourceRange getDeletionRange(const FunctionDecl *FD,
+ const syntax::TokenBuffer &TokBuf) {
+ auto DeletionRange = FD->getBody()->getSourceRange();
+ if (auto *CD = llvm::dyn_cast<CXXConstructorDecl>(FD)) {
+ const auto &SM = TokBuf.sourceManager();
+ // AST doesn't contain the location for ":" in ctor initializers. Therefore
+ // we find it by finding the first ":" before the first ctor initializer.
+ SourceLocation InitStart;
+ // Find the first initializer.
+ for (const auto *CInit : CD->inits()) {
+ // We don't care about in-class initializers.
+ if (CInit->isInClassMemberInitializer())
+ continue;
+ if (InitStart.isInvalid() ||
+ SM.isBeforeInTranslationUnit(CInit->getSourceLocation(), InitStart))
+ InitStart = CInit->getSourceLocation();
+ }
+ if (InitStart.isValid()) {
+ auto Toks = TokBuf.expandedTokens(CD->getSourceRange());
+ // Drop any tokens after the initializer.
+ Toks = Toks.take_while([&TokBuf, &InitStart](const syntax::Token &Tok) {
+ return TokBuf.sourceManager().isBeforeInTranslationUnit(Tok.location(),
+ InitStart);
+ });
+ // Look for the first colon.
+ auto Tok =
+ llvm::find_if(llvm::reverse(Toks), [](const syntax::Token &Tok) {
+ return Tok.kind() == tok::colon;
+ });
+ assert(Tok != Toks.rend());
+ DeletionRange.setBegin(Tok->location());
+ }
+ }
+ return DeletionRange;
+}
+
/// Moves definition of a function/method to an appropriate implementation file.
///
/// Before:
@@ -338,7 +379,8 @@ class DefineOutline : public Tweak {
const tooling::Replacement DeleteFuncBody(
Sel.AST.getSourceManager(),
CharSourceRange::getTokenRange(*toHalfOpenFileRange(
- SM, Sel.AST.getLangOpts(), Source->getBody()->getSourceRange())),
+ SM, Sel.AST.getLangOpts(),
+ getDeletionRange(Source, Sel.AST.getTokens()))),
";");
auto HeaderFE = Effect::fileEdit(SM, SM.getMainFileID(),
tooling::Replacements(DeleteFuncBody));
diff --git a/clang-tools-extra/clangd/unittests/TweakTests.cpp b/clang-tools-extra/clangd/unittests/TweakTests.cpp
index 0bc11a898d7e..d50d27afb1c8 100644
--- a/clang-tools-extra/clangd/unittests/TweakTests.cpp
+++ b/clang-tools-extra/clangd/unittests/TweakTests.cpp
@@ -1979,6 +1979,24 @@ TEST_F(DefineOutlineTest, ApplyTest) {
"void foo(int x, int y = 5, int = 2, int (*foo)(int) = nullptr) ;",
"void foo(int x, int y , int , int (*foo)(int) ) {}",
},
+ // Ctor initializers.
+ {
+ R"cpp(
+ class Foo {
+ int y = 2;
+ F^oo(int z) __attribute__((weak)) : bar(2){}
+ int bar;
+ int z = 2;
+ };)cpp",
+ R"cpp(
+ class Foo {
+ int y = 2;
+ Foo(int z) __attribute__((weak)) ;
+ int bar;
+ int z = 2;
+ };)cpp",
+ "Foo::Foo(int z) __attribute__((weak)) : bar(2){}\n",
+ },
};
for (const auto &Case : Cases) {
SCOPED_TRACE(Case.Test);
More information about the cfe-commits
mailing list