1

我想使用 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 ()
4

0 回答 0