Kale updated this revision to Diff 427313.
Kale added a comment.

Fix path in compile_commands.json for windows.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124816/new/

https://reviews.llvm.org/D124816

Files:
  clang/include/clang/Basic/FileManager.h
  clang/include/clang/Tooling/Tooling.h
  clang/lib/Tooling/Tooling.cpp
  
clang/test/Tooling/multiple-source-include-different-header-with-same-relative-path.cpp

Index: clang/test/Tooling/multiple-source-include-different-header-with-same-relative-path.cpp
===================================================================
--- /dev/null
+++ clang/test/Tooling/multiple-source-include-different-header-with-same-relative-path.cpp
@@ -0,0 +1,42 @@
+// This test case presents a circumstance that the information related one file
+// is misused by another.
+//
+// The path tree of the test directory is as follors.
+//   .
+//   ├── a
+//   │   ├── a.c
+//   │   └── config.h
+//   ├── b
+//   │   ├── b.c
+//   │   └── config.h
+//   └── compile_commands.json
+//
+// Both source files (a/a.c and b/b.c) includes the config.h file of their own
+// directory with `#include "config.h"`. However, the two config.h files are
+// different. File a/config.h is longer than b/config.h. Both a/a.c and b/b.c
+// are compiled in their own directory, which is recorded in the compilation
+// database.
+//
+// When using ClangTool to parse these two source files one by one, since the
+// file name of both header files are the same, the FileManager will confuse
+// with them and using the file entry of a/config.h for b/config.h. And the
+// wrong file length will lead to a buffer overflow when reading the file.
+//
+// In this test case, to avoid buffer overflow, we use the leading '\0' in an
+// empty buffer to trigger the problem. We set a/config.h as an empty line
+// comment, and leave b/config.h empty. Firstly, a/config.h is read and cached,
+// then when reading b/config.h, if the size of a/config.h is used, the first
+// two chars are read and the first one must be a '\0'.
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t/a
+// RUN: mkdir -p %t/b
+// RUN: echo '#include "config.h"' > %t/a/a.c
+// RUN: echo '#include "config.h"' > %t/b/b.c
+// RUN: echo '//' > %t/a/config.h
+// RUN: echo ''   > %t/b/config.h
+// RUN: echo '[{"arguments": ["cc", "-c", "-o", "a.o", "a.c"], "directory": "%t/a", "file": "a.c"}, {"arguments": ["cc", "-c", "-o", "b.o", "b.c"], "directory": "%t/b", "file": "b.c"}]' | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
+
+// The following two test RUNs should have no output.
+// RUN: cd %t && clang-check a/a.c b/b.c 2>&1 | count 0
+// RUN: cd %t && clang-check b/b.c a/a.c 2>&1 | count 0
Index: clang/lib/Tooling/Tooling.cpp
===================================================================
--- clang/lib/Tooling/Tooling.cpp
+++ clang/lib/Tooling/Tooling.cpp
@@ -208,7 +208,7 @@
   StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
 
   llvm::IntrusiveRefCntPtr<FileManager> Files(
-      new FileManager(FileSystemOptions(), VFS));
+      new ToolingFileManager(FileSystemOptions(), VFS));
   ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster();
   ToolInvocation Invocation(
       getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef),
@@ -436,7 +436,8 @@
       OverlayFileSystem(new llvm::vfs::OverlayFileSystem(std::move(BaseFS))),
       InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
       Files(Files ? Files
-                  : new FileManager(FileSystemOptions(), OverlayFileSystem)) {
+                  : new ToolingFileManager(FileSystemOptions(),
+                                           OverlayFileSystem)) {
   OverlayFileSystem->pushOverlay(InMemoryFileSystem);
   appendArgumentsAdjuster(getClangStripOutputAdjuster());
   appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
@@ -656,7 +657,7 @@
       new llvm::vfs::InMemoryFileSystem);
   OverlayFileSystem->pushOverlay(InMemoryFileSystem);
   llvm::IntrusiveRefCntPtr<FileManager> Files(
-      new FileManager(FileSystemOptions(), OverlayFileSystem));
+      new ToolingFileManager(FileSystemOptions(), OverlayFileSystem));
 
   ToolInvocation Invocation(
       getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileName), FileName),
Index: clang/include/clang/Tooling/Tooling.h
===================================================================
--- clang/include/clang/Tooling/Tooling.h
+++ clang/include/clang/Tooling/Tooling.h
@@ -65,6 +65,69 @@
 
 class CompilationDatabase;
 
+class ToolingFileManager : public FileManager {
+  // Use a FileManager for each different CWD
+  mutable std::map<std::string, FileManager *> fileManagers;
+
+public:
+  ToolingFileManager(const FileSystemOptions &FileSystemOpts,
+                     IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr)
+      : FileManager(FileSystemOpts, FS){};
+
+  size_t getNumUniqueRealFiles() const override {
+    return getRealFileManager()->getNumUniqueRealFiles();
+  }
+
+  llvm::Expected<DirectoryEntryRef>
+  getDirectoryRef(StringRef DirName, bool CacheFailure = true) override {
+    auto realFileManager = getRealFileManager();
+    return realFileManager->getDirectoryRef(DirName, CacheFailure);
+  }
+
+  llvm::Expected<FileEntryRef> getFileRef(StringRef Filename, bool openFile,
+                                          bool CacheFailure) override {
+    auto realFileManager = getRealFileManager();
+    return realFileManager->getFileRef(Filename, openFile, CacheFailure);
+  }
+
+  FileEntryRef getVirtualFileRef(StringRef Filename, off_t Size,
+                                 time_t ModificationTime) override {
+    return getRealFileManager()->getVirtualFileRef(Filename, Size,
+                                                   ModificationTime);
+  }
+
+  llvm::Optional<FileEntryRef> getBypassFile(FileEntryRef VFE) override {
+    return getRealFileManager()->getBypassFile(VFE);
+  }
+
+  void GetUniqueIDMapping(
+      SmallVectorImpl<const FileEntry *> &UIDToFiles) const override {
+    getRealFileManager()->GetUniqueIDMapping(UIDToFiles);
+  }
+
+  StringRef getCanonicalName(const DirectoryEntry *Dir) override {
+    return getRealFileManager()->getCanonicalName(Dir);
+  }
+
+  StringRef getCanonicalName(const FileEntry *File) override {
+    return getRealFileManager()->getCanonicalName(File);
+  }
+
+  void PrintStats() const override { getRealFileManager()->PrintStats(); }
+
+  FileManager *getRealFileManager() const {
+    auto Success = getVirtualFileSystem().getCurrentWorkingDirectory();
+    if (!Success)
+      llvm::report_fatal_error("Cannot get current working directory!\n");
+    std::string Cwd = Success.get();
+    if (!fileManagers.count(Cwd)) {
+      fileManagers[Cwd] =
+          new FileManager(getFileSystemOpts(), &getVirtualFileSystem());
+    }
+    return fileManagers[Cwd];
+  }
+};
+
 /// Retrieves the flags of the `-cc1` job in `Compilation` that has only source
 /// files as its inputs.
 /// Returns nullptr if there are no such jobs or multiple of them. Note that
Index: clang/include/clang/Basic/FileManager.h
===================================================================
--- clang/include/clang/Basic/FileManager.h
+++ clang/include/clang/Basic/FileManager.h
@@ -135,7 +135,7 @@
   /// llvm::vfs::getRealFileSystem().
   FileManager(const FileSystemOptions &FileSystemOpts,
               IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr);
-  ~FileManager();
+  virtual ~FileManager();
 
   /// Installs the provided FileSystemStatCache object within
   /// the FileManager.
@@ -150,7 +150,9 @@
   void clearStatCache();
 
   /// Returns the number of unique real file entries cached by the file manager.
-  size_t getNumUniqueRealFiles() const { return UniqueRealFiles.size(); }
+  virtual size_t getNumUniqueRealFiles() const {
+    return UniqueRealFiles.size();
+  }
 
   /// Lookup, cache, and verify the specified directory (real or
   /// virtual).
@@ -162,8 +164,8 @@
   ///
   /// \param CacheFailure If true and the file does not exist, we'll cache
   /// the failure to find this file.
-  llvm::Expected<DirectoryEntryRef> getDirectoryRef(StringRef DirName,
-                                                    bool CacheFailure = true);
+  virtual llvm::Expected<DirectoryEntryRef>
+  getDirectoryRef(StringRef DirName, bool CacheFailure = true);
 
   /// Get a \c DirectoryEntryRef if it exists, without doing anything on error.
   llvm::Optional<DirectoryEntryRef>
@@ -218,9 +220,9 @@
   ///
   /// \param CacheFailure If true and the file does not exist, we'll cache
   /// the failure to find this file.
-  llvm::Expected<FileEntryRef> getFileRef(StringRef Filename,
-                                          bool OpenFile = false,
-                                          bool CacheFailure = true);
+  virtual llvm::Expected<FileEntryRef> getFileRef(StringRef Filename,
+                                                  bool OpenFile = false,
+                                                  bool CacheFailure = true);
 
   /// Get the FileEntryRef for stdin, returning an error if stdin cannot be
   /// read.
@@ -252,8 +254,8 @@
   /// if there were a file with the given name on disk.
   ///
   /// The file itself is not accessed.
-  FileEntryRef getVirtualFileRef(StringRef Filename, off_t Size,
-                                 time_t ModificationTime);
+  virtual FileEntryRef getVirtualFileRef(StringRef Filename, off_t Size,
+                                         time_t ModificationTime);
 
   const FileEntry *getVirtualFile(StringRef Filename, off_t Size,
                                   time_t ModificationTime);
@@ -266,7 +268,7 @@
   /// bypasses all mapping and uniquing, blindly creating a new FileEntry.
   /// There is no attempt to deduplicate these; if you bypass the same file
   /// twice, you get two new file entries.
-  llvm::Optional<FileEntryRef> getBypassFile(FileEntryRef VFE);
+  virtual llvm::Optional<FileEntryRef> getBypassFile(FileEntryRef VFE);
 
   /// Open the specified file as a MemoryBuffer, returning a new
   /// MemoryBuffer if successful, otherwise returning null.
@@ -308,24 +310,24 @@
 
   /// Produce an array mapping from the unique IDs assigned to each
   /// file to the corresponding FileEntry pointer.
-  void GetUniqueIDMapping(
-                    SmallVectorImpl<const FileEntry *> &UIDToFiles) const;
+  virtual void
+  GetUniqueIDMapping(SmallVectorImpl<const FileEntry *> &UIDToFiles) const;
 
   /// Retrieve the canonical name for a given directory.
   ///
   /// This is a very expensive operation, despite its results being cached,
   /// and should only be used when the physical layout of the file system is
   /// required, which is (almost) never.
-  StringRef getCanonicalName(const DirectoryEntry *Dir);
+  virtual StringRef getCanonicalName(const DirectoryEntry *Dir);
 
   /// Retrieve the canonical name for a given file.
   ///
   /// This is a very expensive operation, despite its results being cached,
   /// and should only be used when the physical layout of the file system is
   /// required, which is (almost) never.
-  StringRef getCanonicalName(const FileEntry *File);
+  virtual StringRef getCanonicalName(const FileEntry *File);
 
-  void PrintStats() const;
+  virtual void PrintStats() const;
 };
 
 } // end namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to