Example #1
0
    inline args_t load_compilation_database(std::string const &file, fs::path filename)
    {
      static const std::string source_extensions[] {".c", ".cpp", ".cc"};
      static const std::string header_extensions[] {".h", ".hpp", ".hh"};
      std::string error;
#if LLVM_VERSION_MAJOR >= 4
      auto const database_ptr
      (
        ::clang::tooling::JSONCompilationDatabase::loadFromFile
        (
          file,
          error,
          ::clang::tooling::JSONCommandLineSyntax::Gnu
        )
      );
#else
      auto const database_ptr
      (
        ::clang::tooling::JSONCompilationDatabase::loadFromFile
        (
          file,
          error
        )
      );
#endif
      if(!database_ptr)
      {
          core::last_error(error);
          return {};
      }

      std::vector<fs::path> files{filename};
      auto const ext(filename.extension());
      if(std::find(begin(header_extensions), end(header_extensions), ext) != end(header_extensions))
      {
        auto path = filename.string();
        auto const include_it = path.rfind("include");
        if(include_it != std::string::npos)
        {
            filename = path.replace(include_it, 7, "src");
        }
        for(auto const &extension : source_extensions)
        {
          files.emplace_back(filename.replace_extension(extension));
        }
      }

      std::vector<::clang::tooling::CompileCommand> compile_commands;
      for(auto const &file : files)
      {
        compile_commands = database_ptr->getCompileCommands(file.string());

        if(!compile_commands.empty())
        {
          filename = file;
          break;
        }

      }

      if(compile_commands.empty())
      { return {}; }

      // Skip argv[0] which is the name of the clang executable.
      args_t commands((compile_commands[0].CommandLine.begin() + 1), compile_commands[0].CommandLine.end());

      // Get rid of the source filename itself.
      // NOTE: '-o <output>' and '-c' will be automatically ignored by libclang.
      commands.erase(std::remove(commands.begin(), commands.end(), filename), commands.end());
      commands.erase(std::remove(commands.begin(), commands.end(), compile_commands[0].Filename), commands.end());

      return commands;
    }