mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-14 19:49:36 +00:00
[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
This commit is contained in:
parent
898d7a0695
commit
a209a8000e
@ -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 @@ public:
|
||||
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));
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user