@@ -173,9 +173,11 @@ class Action : public clang::ASTFrontendAction {
173
173
if (!HTMLReportPath.empty ())
174
174
writeHTML ();
175
175
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);
179
181
llvm::StringRef Code = SM.getBufferData (SM.getMainFileID ());
180
182
181
183
auto Results =
@@ -185,7 +187,7 @@ class Action : public clang::ASTFrontendAction {
185
187
Results.Missing .clear ();
186
188
if (!Remove)
187
189
Results.Unused .clear ();
188
- std::string Final = fixIncludes (Results, Path , Code, getStyle (Path ));
190
+ std::string Final = fixIncludes (Results, AbsPath , Code, getStyle (AbsPath ));
189
191
190
192
if (Print.getNumOccurrences ()) {
191
193
switch (Print) {
@@ -202,7 +204,7 @@ class Action : public clang::ASTFrontendAction {
202
204
}
203
205
204
206
if (!Results.Missing .empty () || !Results.Unused .empty ())
205
- EditedFiles.try_emplace (Path , Final);
207
+ EditedFiles.try_emplace (AbsPath , Final);
206
208
}
207
209
208
210
void writeHTML () {
@@ -280,6 +282,48 @@ std::function<bool(llvm::StringRef)> headerFilter() {
280
282
};
281
283
}
282
284
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
+
283
327
} // namespace
284
328
} // namespace include_cleaner
285
329
} // namespace clang
@@ -305,8 +349,16 @@ int main(int argc, const char **argv) {
305
349
}
306
350
}
307
351
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 ());
310
362
311
363
auto HeaderFilter = headerFilter ();
312
364
if (!HeaderFilter)
@@ -316,6 +368,10 @@ int main(int argc, const char **argv) {
316
368
if (Edit) {
317
369
for (const auto &NameAndContent : Factory.editedFiles ()) {
318
370
llvm::StringRef FileName = NameAndContent.first ();
371
+ if (auto It = CDBToAbsPaths->find (FileName.str ());
372
+ It != CDBToAbsPaths->end ())
373
+ FileName = It->second ;
374
+
319
375
const std::string &FinalCode = NameAndContent.second ;
320
376
if (auto Err = llvm::writeToOutput (
321
377
FileName, [&](llvm::raw_ostream &OS) -> llvm::Error {
0 commit comments