DelAttr(FD->getAttr<OverrideAttr>());
DelAttr(FD->getAttr<FinalAttr>());
- if (FD->isVirtualAsWritten()) {
- SourceRange SpecRange{FD->getBeginLoc(), FD->getLocation()};
- bool HasErrors = true;
-
- // Clang allows duplicating virtual specifiers so check for multiple
- // occurrences.
- for (const auto &Tok : TokBuf.expandedTokens(SpecRange)) {
- if (Tok.kind() != tok::kw_virtual)
+ auto DelKeyword = [&](tok::TokenKind Kind, SourceRange FromRange) {
+ bool FoundAny = false;
+ for (const auto &Tok : TokBuf.expandedTokens(FromRange)) {
+ if (Tok.kind() != Kind)
continue;
+ FoundAny = true;
auto Spelling = TokBuf.spelledForExpanded(llvm::makeArrayRef(Tok));
if (!Spelling) {
- HasErrors = true;
+ Errors = llvm::joinErrors(
+ std::move(Errors),
+ llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ llvm::formatv("define outline: couldn't remove `{0}` keyword.",
+ tok::getKeywordSpelling(Kind))));
break;
}
- HasErrors = false;
CharSourceRange DelRange =
syntax::Token::range(SM, Spelling->front(), Spelling->back())
.toCharRange(SM);
DeclarationCleanups.add(tooling::Replacement(SM, DelRange, "")))
Errors = llvm::joinErrors(std::move(Errors), std::move(Err));
}
- if (HasErrors) {
+ if (!FoundAny) {
Errors = llvm::joinErrors(
std::move(Errors),
- llvm::createStringError(llvm::inconvertibleErrorCode(),
- "define outline: Can't move out of line as "
- "function has a macro `virtual` specifier."));
+ llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ llvm::formatv(
+ "define outline: couldn't find `{0}` keyword to remove.",
+ tok::getKeywordSpelling(Kind))));
}
+ };
+
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (MD->isVirtualAsWritten())
+ DelKeyword(tok::kw_virtual, {FD->getBeginLoc(), FD->getLocation()});
+ if (MD->isStatic())
+ DelKeyword(tok::kw_static, {FD->getBeginLoc(), FD->getLocation()});
}
if (Errors)
};)cpp",
"void B::foo() {}\n",
},
+ {
+ R"cpp(
+ struct A {
+ static void fo^o() {}
+ };)cpp",
+ R"cpp(
+ struct A {
+ static void foo() ;
+ };)cpp",
+ " void A::foo() {}\n",
+ },
+ {
+ R"cpp(
+ struct A {
+ static static void fo^o() {}
+ };)cpp",
+ R"cpp(
+ struct A {
+ static static void foo() ;
+ };)cpp",
+ " void A::foo() {}\n",
+ },
};
for (const auto &Case : Cases) {
SCOPED_TRACE(Case.Test);
STUPID_MACRO(sizeof sizeof int) void foo() ;
};)cpp",
" void A::foo() {}\n"},
+ {R"cpp(#define STAT static
+ struct A {
+ STAT void f^oo() {}
+ };)cpp",
+ R"cpp(#define STAT static
+ struct A {
+ STAT void foo() ;
+ };)cpp",
+ " void A::foo() {}\n"},
+ {R"cpp(#define STUPID_MACRO(X) static
+ struct A {
+ STUPID_MACRO(sizeof sizeof int) void f^oo() {}
+ };)cpp",
+ R"cpp(#define STUPID_MACRO(X) static
+ struct A {
+ STUPID_MACRO(sizeof sizeof int) void foo() ;
+ };)cpp",
+ " void A::foo() {}\n"},
};
for (const auto &Case : Cases) {
SCOPED_TRACE(Case.Test);
struct A {
VIRT fo^o() {}
};)cpp",
- "fail: define outline: Can't move out of line as function has a "
- "macro `virtual` specifier."},
+ "fail: define outline: couldn't remove `virtual` keyword."},
{
R"cpp(
#define OVERFINAL final override