Index: include-fixer/IncludeFixer.cpp =================================================================== --- include-fixer/IncludeFixer.cpp +++ include-fixer/IncludeFixer.cpp @@ -25,6 +25,31 @@ namespace include_fixer { namespace { +// Returns a relative filepath to FilePath from Dir. +// For example: +// RelativePath("/foo/bar", "/foo") => "bar" +// RelativePath("/foo/bar/test", "foo/bar/include") => "../test" +std::string RelativePath(StringRef FilePath, StringRef Dir) { + SmallString<256> Result; + SmallVector FilePathComponents; + SmallVector DirComponents; + FilePath.split(FilePathComponents, '/'); + Dir.split(DirComponents, '/'); + + for (size_t FI = 0, DI = 0, FE = FilePathComponents.size(), + DE = DirComponents.size(); + FI < FE && DI < DE; ++FI, ++DI) { + if (FilePathComponents[FI] != DirComponents[DI]) { + for (size_t Count = DE - DI; Count > 0; --Count) + llvm::sys::path::append(Result, ".."); + for (; FI < FE; ++FI) + llvm::sys::path::append(Result, FilePathComponents[FI]); + break; + } + } + return Result.str(); +} + class Action; class PreprocessorHooks : public clang::PPCallbacks { @@ -171,8 +196,16 @@ // Get the FileEntry for the include. StringRef StrippedInclude = Include.trim("\"<>"); + + auto BuildDir = SourceManager.getFileManager() + .getVirtualFileSystem() + ->getCurrentWorkingDirectory(); + if (!BuildDir) + return Include; + StringRef PathRelativeToBuildDir = RelativePath(StrippedInclude, *BuildDir); + const FileEntry *Entry = - SourceManager.getFileManager().getFile(StrippedInclude); + SourceManager.getFileManager().getFile(PathRelativeToBuildDir); // If the file doesn't exist return the path from the database. // FIXME: This should never happen. @@ -182,7 +215,9 @@ bool IsSystem; std::string Suggestion = HeaderSearch.suggestPathToFileForDiagnostics(Entry, &IsSystem); - + // Falls back to orignal file path if fails. + if (Suggestion == PathRelativeToBuildDir) + Suggestion = StrippedInclude; return IsSystem ? '<' + Suggestion + '>' : '"' + Suggestion + '"'; } Index: test/include-fixer/Inputs/database_template.json =================================================================== --- /dev/null +++ test/include-fixer/Inputs/database_template.json @@ -0,0 +1,7 @@ +[ +{ + "directory": "test_dir/build", + "command": "clang++ -I../include -o foo.o test_dir/src/foo.cpp", + "file": "test_dir/src/foo.cpp" +} +] Index: test/include-fixer/Inputs/yaml_db_template.yaml =================================================================== --- /dev/null +++ test/include-fixer/Inputs/yaml_db_template.yaml @@ -0,0 +1,11 @@ +--- +Name: foo +Contexts: + - ContextType: Namespace + ContextName: a + - ContextType: Namespace + ContextName: b +FilePath: test_dir/foo.h +LineNumber: 1 +Type: Class +... Index: test/include-fixer/include_path.cpp =================================================================== --- /dev/null +++ test/include-fixer/include_path.cpp @@ -0,0 +1,14 @@ +// REQUIRES: shell +// RUN: mkdir -p %T/include-fixer/include +// RUN: mkdir -p %T/include-fixer/build +// RUN: mkdir -p %T/include-fixer/src +// RUN: sed 's|test_dir|%T/include-fixer|g' %S/Inputs/database_template.json > %T/include-fixer/build/compile_commands.json +// RUN: sed 's|test_dir|%T/include-fixer/include|g' %S/Inputs/yaml_db_template.yaml > %T/include-fixer/build/fake_yaml_db.yaml +// RUN: echo 'b::a::foo f;' > %T/include-fixer/src/foo.cpp +// RUN: touch %T/include-fixer/include/foo.h +// RUN: cd %T/include-fixer/build +// RUN: clang-include-fixer -db=yaml -input=fake_yaml_db.yaml -p=. %T/include-fixer/src/foo.cpp +// RUN: FileCheck -input-file=%T/include-fixer/src/foo.cpp %s + +// CHECK: #include "foo.h" +// CHECK: b::a::foo f;