我想使用 clang 运行一些源到源的转换。而不是使用 JSONCompilationDatabase 为输入 Im 使用 commonoptions。它对单个文件运行良好,但在多个文件上运行时,特别是在文件被覆盖后,它会收到 SIGBUS。问题必须与 clang::rewriter 有关,因为如果我删除 InsertText 或 overwritechangedfiles 调用它就可以工作。
GDB 也没有太大帮助,因为回溯位于 Clang 的 API 中。有关堆栈跟踪,请参见下文。
到目前为止的代码:
#include <algorithm>
#include <fstream>
#include <memory>
#include <string>
#include <unordered_set>
#include <m_bdedeproconverter_deprinfo.h>
#include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/ASTMatchers/ASTMatchFinder.h>
#include <clang/ASTMatchers/ASTMatchers.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendActions.h>
#include <clang/Frontend/FrontendPluginRegistry.h>
#include <clang/Rewrite/Core/Rewriter.h>
#include <clang/Rewrite/Frontend/FrontendActions.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/JSONCompilationDatabase.h>
#include <clang/Tooling/Tooling.h>
#include <clang/Lex/PPCallbacks.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/raw_ostream.h>
using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::tooling;
using namespace llvm;
using namespace std;
using Comments = llvm::ArrayRef<RawComment*>;
class SymbolCollector : public MatchFinder::MatchCallback {
public:
SymbolCollector(Rewriter& rewriter)
: d_rewriter(rewriter) {}
virtual void run(const MatchFinder::MatchResult& Result) {
auto* decl = Result.Nodes.getNodeAs<Decl>("declaration");
auto replacement = "placeholder";
d_rewriter.InsertText(decl->getBeginLoc(),
replacement,
false); // <------- HERE
}
void setComments(Comments comments) {
d_comments = comments;
}
private:
Rewriter& d_rewriter;
Comments d_comments;
};
class NamespaceCollector : public MatchFinder::MatchCallback {
public:
NamespaceCollector(vector<string>& results) : d_collectedNamespaces(results) {}
virtual void run(const MatchFinder::MatchResult& Result) {
auto* namespaceDecl = Result.Nodes.getNodeAs<NamespaceDecl>("namespace");
namespaceDecl = namespaceDecl->getCanonicalDecl();
d_collectedNamespaces.push_back(namespaceDecl->getName());
}
private:
vector<string>& d_collectedNamespaces;
};
class AnnotateDeprecationConsumer : public ASTConsumer {
public:
AnnotateDeprecationConsumer(Rewriter& rewriter)
: d_scollector(rewriter),
d_ncollector(d_namespaces),
d_rewriter(rewriter) {
DeclarationMatcher namespaceMatch = namespaceDecl(
isExpansionInMainFile()
).bind("namespace");
d_matcher[0].addMatcher(namespaceMatch, &d_ncollector);
}
void HandleTranslationUnit(ASTContext& Context) override {
auto comments = Context.getRawCommentList().getComments();
d_scollector.setComments(comments);
d_matcher[0].matchAST(Context);
if (d_namespaces.empty())
return;
DeclarationMatcher funcMatch = functionDecl(
unless(isDefinition()),
hasAncestor(
namespaceDecl(hasName(d_namespaces[0]))
),
unless(isImplicit()),
unless(hasName("main"))
).bind("declaration");
d_matcher[1].addMatcher(funcMatch, &d_scollector);
d_matcher[1].matchAST(Context);
d_rewriter.overwriteChangedFiles(); // <--------- HERE
}
private:
MatchFinder d_matcher[2];
SymbolCollector d_scollector;
NamespaceCollector d_ncollector;
Rewriter& d_rewriter;
vector<string> d_namespaces;
};
class AnnotateDeprecationAction : public ASTFrontendAction {
public:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance& CI,
llvm::StringRef) override {
d_rewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
return llvm::make_unique<AnnotateDeprecationConsumer>(d_rewriter);
}
private:
Rewriter d_rewriter;
};
// Apply a custom category to all command-line options so that they are the
// only ones displayed.
static llvm::cl::OptionCategory MyCategory("Mytool options");
int main(int argc, const char** argv) {
if (argc != 2) {
llvm::errs() << "Usage: mytool /path/to/compilation/database\n";
return -1;
}
string errorMsg;
auto compDatabase = JSONCompilationDatabase::loadFromFile(argv[1], errorMsg, JSONCommandLineSyntax::AutoDetect);
if (compDatabase == nullptr){
llvm::errs() << "An error occurred while trying to load the compilation database : "
<< errorMsg << "\n";
return -1;
}
ClangTool Tool(*compDatabase.get(), compDatabase->getAllFiles());
int ret = Tool.run(
newFrontendActionFactory<AnnotateDeprecationAction>().get());
if (ret == 1) {
llvm::errs() << "An unknown error occurred during the conversion.\n";
return -1;
}
return 0;
}
堆栈跟踪:
Program received signal SIGBUS, Bus error.
0x000000000067fbeb in ComputeLineNumbers(clang::DiagnosticsEngine&, clang::SrcMgr::ContentCache*, llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul>&, clang::SourceManager const&, bool&) [clone .constprop.336] ()
(gdb) bt
#0 0x000000000067fbeb in ComputeLineNumbers(clang::DiagnosticsEngine&, clang::SrcMgr::ContentCache*, llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul>&, clang::SourceManager const&, bool&) [clone .constprop.336] ()
#1 0x0000000000680068 in clang::SourceManager::getLineNumber(clang::FileID, unsigned int, bool*) const ()
#2 0x00000000006813a1 in clang::SourceManager::getPresumedLoc(clang::SourceLocation, bool) const ()
#3 0x000000000068153d in clang::SourceManager::getPresumedColumnNumber(clang::SourceLocation, bool*) const ()
#4 0x000000000059234f in clang::RawCommentList::addComment(clang::RawComment const&, clang::CommentOptions const&, llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul>&) ()
#5 0x00000000007cf2b9 in clang::Sema::ActOnComment(clang::SourceRange) ()
#6 0x0000000000e4d4d0 in (anonymous namespace)::ActionCommentHandler::HandleComment(clang::Preprocessor&, clang::SourceRange) ()
#7 0x00000000007a8777 in clang::Preprocessor::HandleComment(clang::Token&, clang::SourceRange) ()
#8 0x000000000073ec69 in clang::Lexer::SkipLineComment(clang::Token&, char const*, bool&) ()
#9 0x0000000000744b35 in clang::Lexer::LexTokenInternal(clang::Token&, bool) ()
#10 0x00000000007a7cbf in clang::Preprocessor::Lex(clang::Token&) ()
#11 0x0000000000e4d6eb in clang::Parser::ConsumeBrace() ()
#12 0x0000000000e55d66 in clang::BalancedDelimiterTracker::consumeClose() ()
#13 0x0000000000e8a144 in clang::Parser::ParseInnerNamespace(llvm::SmallVector<clang::Parser::InnerNamespaceInfo, 4u> const&, unsigned int, clang::SourceLocation&, clang::ParsedAttributes&, clang::BalancedDelimiterTracker&) ()
#14 0x0000000000e8aa03 in clang::Parser::ParseNamespace(clang::DeclaratorContext, clang::SourceLocation&, clang::SourceLocation) ()
#15 0x0000000000e7887f in clang::Parser::ParseDeclaration(clang::DeclaratorContext, clang::SourceLocation&, clang::Parser::ParsedAttributesWithRange&) ()
#16 0x0000000000e5676e in clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange&, clang::ParsingDeclSpec*) ()
#17 0x0000000000e5795a in clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&) ()
#18 0x0000000000e4d1e3 in clang::ParseAST(clang::Sema&, bool, bool) ()
#19 0x000000000068f1de in clang::FrontendAction::Execute() ()
#20 0x00000000006b1536 in clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) ()
#21 0x0000000000e3c418 in clang::tooling::FrontendActionFactory::runInvocation(std::shared_ptr<clang::CompilerInvocation>, clang::FileManager*, std::shared_ptr<clang::PCHContainerOperations>, clang::DiagnosticConsumer*) ()
#22 0x0000000000e375fc in clang::tooling::ToolInvocation::runInvocation(char const*, clang::driver::Compilation*, std::shared_ptr<clang::CompilerInvocation>, std::shared_ptr<clang::PCHContainerOperations>) ()
#23 0x0000000000e3932b in clang::tooling::ToolInvocation::run() ()
#24 0x0000000000e3ae57 in clang::tooling::ClangTool::run(clang::tooling::ToolAction*) ()
#25 0x0000000000455b11 in main ()