@@ -173,9 +173,11 @@ class Action : public clang::ASTFrontendAction {
173173 if (!HTMLReportPath.empty ())
174174 writeHTML ();
175175
176- llvm::StringRef Path =
177- SM.getFileEntryRefForID (SM.getMainFileID ())->getName ();
178- assert (!Path.empty () && " Main file path not known?" );
176+ // Source File's path of compiler invocation, converted to absolute path.
177+ llvm::SmallString<256 > AbsPath (
178+ SM.getFileEntryRefForID (SM.getMainFileID ())->getName ());
179+ assert (!AbsPath.empty () && " Main file path not known?" );
180+ SM.getFileManager ().makeAbsolutePath (AbsPath);
179181 llvm::StringRef Code = SM.getBufferData (SM.getMainFileID ());
180182
181183 auto Results =
@@ -185,7 +187,7 @@ class Action : public clang::ASTFrontendAction {
185187 Results.Missing .clear ();
186188 if (!Remove)
187189 Results.Unused .clear ();
188- std::string Final = fixIncludes (Results, Path , Code, getStyle (Path ));
190+ std::string Final = fixIncludes (Results, AbsPath , Code, getStyle (AbsPath ));
189191
190192 if (Print.getNumOccurrences ()) {
191193 switch (Print) {
@@ -202,7 +204,7 @@ class Action : public clang::ASTFrontendAction {
202204 }
203205
204206 if (!Results.Missing .empty () || !Results.Unused .empty ())
205- EditedFiles.try_emplace (Path , Final);
207+ EditedFiles.try_emplace (AbsPath , Final);
206208 }
207209
208210 void writeHTML () {
@@ -280,6 +282,48 @@ std::function<bool(llvm::StringRef)> headerFilter() {
280282 };
281283}
282284
285+ // Maps absolute path of each files of each compilation commands to the
286+ // absolute path of the input file.
287+ llvm::Expected<std::map<std::string, std::string>>
288+ mapInputsToAbsPaths (clang::tooling::CompilationDatabase &CDB,
289+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
290+ const std::vector<std::string> &Inputs) {
291+ std::map<std::string, std::string> CDBToAbsPaths;
292+ // Factory.editedFiles()` will contain the final code, along with the
293+ // path given in the compilation database. That path can be
294+ // absolute or relative, and if it is relative, it is relative to the
295+ // "Directory" field in the compilation database. We need to make it
296+ // absolute to write the final code to the correct path.
297+ for (auto &Source : Inputs) {
298+ llvm::SmallString<256 > AbsPath (Source);
299+ if (auto Err = VFS->makeAbsolute (AbsPath)) {
300+ llvm::errs () << " Failed to get absolute path for " << Source << " : "
301+ << Err.message () << ' \n ' ;
302+ return std::move (llvm::errorCodeToError (Err));
303+ }
304+ std::vector<clang::tooling::CompileCommand> Cmds =
305+ CDB.getCompileCommands (AbsPath);
306+ if (Cmds.empty ()) {
307+ // It should be found in the compilation database, even user didn't
308+ // specify the compilation database, the `FixedCompilationDatabase` will
309+ // create an entry from the arguments. So it is an error if we can't
310+ // find the compile commands.
311+ std::string ErrorMsg =
312+ llvm::formatv (" No compile commands found for {0}" , AbsPath).str ();
313+ llvm::errs () << ErrorMsg << ' \n ' ;
314+ return llvm::make_error<llvm::StringError>(
315+ ErrorMsg, llvm::inconvertibleErrorCode ());
316+ }
317+ for (const auto &Cmd : Cmds) {
318+ llvm::SmallString<256 > CDBPath (Cmd.Filename );
319+ std::string Directory (Cmd.Directory );
320+ llvm::sys::fs::make_absolute (Cmd.Directory , CDBPath);
321+ CDBToAbsPaths[std::string (CDBPath)] = std::string (AbsPath);
322+ }
323+ }
324+ return CDBToAbsPaths;
325+ }
326+
283327} // namespace
284328} // namespace include_cleaner
285329} // namespace clang
@@ -305,8 +349,16 @@ int main(int argc, const char **argv) {
305349 }
306350 }
307351
308- clang::tooling::ClangTool Tool (OptionsParser->getCompilations (),
309- OptionsParser->getSourcePathList ());
352+ auto VFS = llvm::vfs::getRealFileSystem ();
353+ auto &CDB = OptionsParser->getCompilations ();
354+ // CDBToAbsPaths is a map from the path in the compilation database to the
355+ // writable absolute path of the file.
356+ auto CDBToAbsPaths =
357+ mapInputsToAbsPaths (CDB, VFS, OptionsParser->getSourcePathList ());
358+ if (!CDBToAbsPaths)
359+ return 1 ;
360+
361+ clang::tooling::ClangTool Tool (CDB, OptionsParser->getSourcePathList ());
310362
311363 auto HeaderFilter = headerFilter ();
312364 if (!HeaderFilter)
@@ -316,6 +368,10 @@ int main(int argc, const char **argv) {
316368 if (Edit) {
317369 for (const auto &NameAndContent : Factory.editedFiles ()) {
318370 llvm::StringRef FileName = NameAndContent.first ();
371+ if (auto It = CDBToAbsPaths->find (FileName.str ());
372+ It != CDBToAbsPaths->end ())
373+ FileName = It->second ;
374+
319375 const std::string &FinalCode = NameAndContent.second ;
320376 if (auto Err = llvm::writeToOutput (
321377 FileName, [&](llvm::raw_ostream &OS) -> llvm::Error {
0 commit comments