ClangTool::ClangTool(const CompilationDatabase &Compilations, ArrayRef<std::string> SourcePaths) : Files(new FileManager(FileSystemOptions())), DiagConsumer(NULL) { ArgsAdjusters.push_back(new ClangStripOutputAdjuster()); ArgsAdjusters.push_back(new ClangSyntaxOnlyAdjuster()); for (const auto &SourcePath : SourcePaths) { std::string File(getAbsolutePath(SourcePath)); std::vector<CompileCommand> CompileCommandsForFile = Compilations.getCompileCommands(File); if (!CompileCommandsForFile.empty()) { for (CompileCommand &CompileCommand : CompileCommandsForFile) { CompileCommands.push_back( std::make_pair(File, std::move(CompileCommand))); } } else { // FIXME: There are two use cases here: doing a fuzzy // "find . -name '*.cc' |xargs tool" match, where as a user I don't care // about the .cc files that were not found, and the use case where I // specify all files I want to run over explicitly, where this should // be an error. We'll want to add an option for this. llvm::errs() << "Skipping " << File << ". Compile command not found.\n"; } } }
chimera::cd_utils::CompileCommandVector chimera::cd_utils::getCompileCommandsByFilePath( const CompilationDatabase &database, StringRef filename) { // First search for the correct "file" Twine targetFilePath = Twine(filename); std::string foundFilePath; ChimeraLogger::verboseAndIncr("Retrieving compileCommands for " + targetFilePath.str()); // Find the foundFilename to access specific compileCommands // Get all "file" field of the compilation database auto compileFile = database.getAllFiles(); // Check if it's empty if (!compileFile.empty()) { // This isn't a FixedCompilationDatabase for (auto file = compileFile.begin(); file != compileFile.end(); ++file) { // Compare with targetFilename Twine filePathToCompare(*file); ChimeraLogger::verbose("Comparing with File: " + *file); // llvm::sys::fs::equivalent to test the really equivalence if (llvm::sys::fs::equivalent(targetFilePath, filePathToCompare)) { ChimeraLogger::verbose("Successful. Match found!"); foundFilePath = *file; break; } } } else { // This is a FixedCompilationDatabase ChimeraLogger::verbose( "CompilationDatabase with an empty filelist. Maybe provided by hand"); foundFilePath = targetFilePath.str(); } ChimeraLogger::decrActualVLevel(); // Return compileCommands return database.getCompileCommands(foundFilePath); }
ClangTool::ClangTool(const CompilationDatabase &Compilations, ArrayRef<std::string> SourcePaths) : Files((FileSystemOptions())), ArgsAdjuster(new ClangSyntaxOnlyAdjuster()) { llvm::SmallString<1024> BaseDirectory; if (const char *PWD = ::getenv("PWD")) BaseDirectory = PWD; else llvm::sys::fs::current_path(BaseDirectory); for (unsigned I = 0, E = SourcePaths.size(); I != E; ++I) { llvm::SmallString<1024> File(getAbsolutePath( SourcePaths[I], BaseDirectory)); std::vector<CompileCommand> CompileCommandsForFile = Compilations.getCompileCommands(File.str()); if (!CompileCommandsForFile.empty()) { for (int I = 0, E = CompileCommandsForFile.size(); I != E; ++I) { CompileCommands.push_back(std::make_pair(File.str(), CompileCommandsForFile[I])); } } else { // FIXME: There are two use cases here: doing a fuzzy // "find . -name '*.cc' |xargs tool" match, where as a user I don't care // about the .cc files that were not found, and the use case where I // specify all files I want to run over explicitly, where this should // be an error. We'll want to add an option for this. llvm::outs() << "Skipping " << File << ". Command line not found.\n"; } } }
TranslationUnit::TranslationUnit(Index& index, const std::string& source, CompilationDatabase& comp_db) { auto commands = comp_db.getCompileCommands(source); unsigned cmd_args = commands.getSize(); if (cmd_args == 0) { throw std::runtime_error("No compilation info for file `" + source + "`"); } auto command = commands.getCommand(0); auto arguments = command.GetArguments(1); arguments.push_back("-I" + comp_db.GetClangHeadersLocation()); std::vector<const char*> c_arguments; c_arguments.reserve(arguments.size()); bool skip = false; for (auto& arg : arguments) { if (skip) { skip = false; continue; } if (arg == "-c") { skip = true; continue; } c_arguments.push_back(arg.c_str()); } CXErrorCode code = clang_parseTranslationUnit2( index.index_, source.c_str(), c_arguments.data(), c_arguments.size(), nullptr, 0, CXTranslationUnit_DetailedPreprocessingRecord, &unit_); if (code != CXError_Success) { throw std::runtime_error("Error while parsing file `" + source + "`: " + ErrorCodeToString(code)); } }