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 i = 0, j = 0; + i < FilePathComponents.size() && j < DirComponents.size(); + ++i, ++j) { + if (FilePathComponents[i] != DirComponents[j]) { + for (size_t x = 0; x < DirComponents.size() - j; ++x) + llvm::sys::path::append(Result, ".."); + for (;i < FilePathComponents.size(); ++i) + llvm::sys::path::append(Result, FilePathComponents[i]); + 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. 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;