arphaman created this revision.
arphaman added reviewers: Bigcheese, bruno, dexonsmith.
Herald added subscribers: ributzka, jkorous.
Herald added a project: clang.

This patch is similar to the FileEntryRef patch, in that it introduces a 
parallel API to get the directory entry, without replacing all uses. The 
immediate use in the patch fixes the issue where a file manager was reused in 
clang-scan-deps, but reported an different file path whenever a framework 
lookup was done through a symlink.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D67026

Files:
  clang/include/clang/Basic/FileManager.h
  clang/include/clang/Lex/DirectoryLookup.h
  clang/lib/Basic/FileManager.cpp
  clang/lib/Frontend/InitHeaderSearch.cpp
  clang/lib/Lex/HeaderSearch.cpp
  clang/lib/Lex/PPDirectives.cpp
  clang/test/ClangScanDeps/Inputs/subframework_header_dir_symlink_cdb.json
  clang/test/ClangScanDeps/subframework_header_dir_symlink.m

Index: clang/test/ClangScanDeps/subframework_header_dir_symlink.m
===================================================================
--- clang/test/ClangScanDeps/subframework_header_dir_symlink.m
+++ clang/test/ClangScanDeps/subframework_header_dir_symlink.m
@@ -10,9 +10,8 @@
 // RUN: sed -e "s|DIR|%/t.dir|g" %S/Inputs/subframework_header_dir_symlink_cdb.json > %t.cdb
 // RUN: clang-scan-deps -compilation-database %t.cdb -j 1  -reuse-filemanager=0 | \
 // RUN:   FileCheck %s
-// FIXME: Make this work when the filemanager is reused:
 // RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -reuse-filemanager=1 | \
-// RUN:   not FileCheck %s
+// RUN:   FileCheck %s
 
 #ifndef EMPTY
 #include "Framework/Framework.h"
Index: clang/test/ClangScanDeps/Inputs/subframework_header_dir_symlink_cdb.json
===================================================================
--- clang/test/ClangScanDeps/Inputs/subframework_header_dir_symlink_cdb.json
+++ clang/test/ClangScanDeps/Inputs/subframework_header_dir_symlink_cdb.json
@@ -6,7 +6,7 @@
 },
 {
   "directory": "DIR",
-  "command": "clang -E DIR/subframework_header_dir_symlink2.m -FInputs/frameworks_symlink -iframework Inputs/frameworks",
+  "command": "clang -E DIR/subframework_header_dir_symlink2.m -FInputs/frameworks -iframework Inputs/frameworks_symlink",
   "file": "DIR/subframework_header_dir_symlink2.m"
 }
 ]
Index: clang/lib/Lex/PPDirectives.cpp
===================================================================
--- clang/lib/Lex/PPDirectives.cpp
+++ clang/lib/Lex/PPDirectives.cpp
@@ -1695,7 +1695,7 @@
     // Give the clients a chance to recover.
     SmallString<128> RecoveryPath;
     if (Callbacks->FileNotFound(Filename, RecoveryPath)) {
-      if (auto DE = FileMgr.getDirectory(RecoveryPath)) {
+      if (auto DE = FileMgr.getOptionalDirectoryRef(RecoveryPath)) {
         // Add the recovery path to the list of search paths.
         DirectoryLookup DL(*DE, SrcMgr::C_User, false);
         HeaderInfo.AddSearchPath(DL, isAngled);
Index: clang/lib/Lex/HeaderSearch.cpp
===================================================================
--- clang/lib/Lex/HeaderSearch.cpp
+++ clang/lib/Lex/HeaderSearch.cpp
@@ -296,6 +296,7 @@
 /// getName - Return the directory or filename corresponding to this lookup
 /// object.
 StringRef DirectoryLookup::getName() const {
+  // FIXME: Use the name from \c DirectoryEntryRef.
   if (isNormalDir())
     return getDir()->getName();
   if (isFramework())
@@ -496,7 +497,7 @@
 
   // FrameworkName = "/System/Library/Frameworks/"
   SmallString<1024> FrameworkName;
-  FrameworkName += getFrameworkDir()->getName();
+  FrameworkName += getFrameworkDirRef()->getName();
   if (FrameworkName.empty() || FrameworkName.back() != '/')
     FrameworkName.push_back('/');
 
Index: clang/lib/Frontend/InitHeaderSearch.cpp
===================================================================
--- clang/lib/Frontend/InitHeaderSearch.cpp
+++ clang/lib/Frontend/InitHeaderSearch.cpp
@@ -148,7 +148,7 @@
   }
 
   // If the directory exists, add it.
-  if (auto DE = FM.getDirectory(MappedPathStr)) {
+  if (auto DE = FM.getOptionalDirectoryRef(MappedPathStr)) {
     IncludePath.push_back(
       std::make_pair(Group, DirectoryLookup(*DE, Type, isFramework)));
     return true;
Index: clang/lib/Basic/FileManager.cpp
===================================================================
--- clang/lib/Basic/FileManager.cpp
+++ clang/lib/Basic/FileManager.cpp
@@ -107,16 +107,8 @@
   addAncestorsAsVirtualDirs(DirName);
 }
 
-/// Converts a llvm::ErrorOr<T &> to an llvm::ErrorOr<T *> by promoting
-/// the address of the inner reference to a pointer or by propagating the error.
-template <typename T>
-static llvm::ErrorOr<T *> promoteInnerReference(llvm::ErrorOr<T &> value) {
-  if (value) return &*value;
-  return value.getError();
-}
-
-llvm::ErrorOr<const DirectoryEntry *>
-FileManager::getDirectory(StringRef DirName, bool CacheFailure) {
+llvm::Expected<DirectoryEntryRef>
+FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) {
   // stat doesn't like trailing separators except for root directory.
   // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'.
   // (though it can strip '\\')
@@ -141,8 +133,11 @@
   // contains both virtual and real directories.
   auto SeenDirInsertResult =
       SeenDirEntries.insert({DirName, std::errc::no_such_file_or_directory});
-  if (!SeenDirInsertResult.second)
-    return promoteInnerReference(SeenDirInsertResult.first->second);
+  if (!SeenDirInsertResult.second) {
+    if (SeenDirInsertResult.first->second)
+      return DirectoryEntryRef(&*SeenDirInsertResult.first);
+    return llvm::errorCodeToError(SeenDirInsertResult.first->second.getError());
+  }
 
   // We've not seen this before. Fill it in.
   ++NumDirCacheMisses;
@@ -163,7 +158,7 @@
       NamedDirEnt.second = statError;
     else
       SeenDirEntries.erase(DirName);
-    return statError;
+    return llvm::errorCodeToError(statError);
   }
 
   // It exists.  See if we have already opened a directory with the
@@ -179,7 +174,15 @@
     UDE.Name  = InterndDirName;
   }
 
-  return &UDE;
+  return DirectoryEntryRef(&NamedDirEnt);
+}
+
+llvm::ErrorOr<const DirectoryEntry *>
+FileManager::getDirectory(StringRef DirName, bool CacheFailure) {
+  auto Result = getDirectoryRef(DirName, CacheFailure);
+  if (Result)
+    return Result->getDirEntry();
+  return llvm::errorToErrorCode(Result.takeError());
 }
 
 llvm::ErrorOr<const FileEntry *>
Index: clang/include/clang/Lex/DirectoryLookup.h
===================================================================
--- clang/include/clang/Lex/DirectoryLookup.h
+++ clang/include/clang/Lex/DirectoryLookup.h
@@ -36,14 +36,17 @@
     LT_HeaderMap
   };
 private:
-  union {  // This union is discriminated by isHeaderMap.
+  union DLU { // This union is discriminated by isHeaderMap.
     /// Dir - This is the actual directory that we're referring to for a normal
     /// directory or a framework.
-    const DirectoryEntry *Dir;
+    DirectoryEntryRef Dir;
 
     /// Map - This is the HeaderMap if this is a headermap lookup.
     ///
     const HeaderMap *Map;
+
+    DLU(DirectoryEntryRef Dir) : Dir(Dir) {}
+    DLU(const HeaderMap *Map) : Map(Map) {}
   } u;
 
   /// DirCharacteristic - The type of directory this is: this is an instance of
@@ -64,22 +67,18 @@
 public:
   /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
   /// 'dir'.
-  DirectoryLookup(const DirectoryEntry *dir, SrcMgr::CharacteristicKind DT,
+  DirectoryLookup(DirectoryEntryRef Dir, SrcMgr::CharacteristicKind DT,
                   bool isFramework)
-    : DirCharacteristic(DT),
-      LookupType(isFramework ? LT_Framework : LT_NormalDir),
-      IsIndexHeaderMap(false), SearchedAllModuleMaps(false) {
-    u.Dir = dir;
-  }
+      : u(Dir), DirCharacteristic(DT),
+        LookupType(isFramework ? LT_Framework : LT_NormalDir),
+        IsIndexHeaderMap(false), SearchedAllModuleMaps(false) {}
 
   /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
   /// 'map'.
-  DirectoryLookup(const HeaderMap *map, SrcMgr::CharacteristicKind DT,
+  DirectoryLookup(const HeaderMap *Map, SrcMgr::CharacteristicKind DT,
                   bool isIndexHeaderMap)
-    : DirCharacteristic(DT), LookupType(LT_HeaderMap),
-      IsIndexHeaderMap(isIndexHeaderMap), SearchedAllModuleMaps(false) {
-    u.Map = map;
-  }
+      : u(Map), DirCharacteristic(DT), LookupType(LT_HeaderMap),
+        IsIndexHeaderMap(isIndexHeaderMap), SearchedAllModuleMaps(false) {}
 
   /// getLookupType - Return the kind of directory lookup that this is: either a
   /// normal directory, a framework path, or a HeaderMap.
@@ -92,13 +91,17 @@
   /// getDir - Return the directory that this entry refers to.
   ///
   const DirectoryEntry *getDir() const {
-    return isNormalDir() ? u.Dir : nullptr;
+    return isNormalDir() ? u.Dir.getDirEntry() : nullptr;
   }
 
   /// getFrameworkDir - Return the directory that this framework refers to.
   ///
   const DirectoryEntry *getFrameworkDir() const {
-    return isFramework() ? u.Dir : nullptr;
+    return isFramework() ? u.Dir.getDirEntry() : nullptr;
+  }
+
+  Optional<DirectoryEntryRef> getFrameworkDirRef() const {
+    return isFramework() ? Optional<DirectoryEntryRef>(u.Dir) : None;
   }
 
   /// getHeaderMap - Return the directory that this entry refers to.
Index: clang/include/clang/Basic/FileManager.h
===================================================================
--- clang/include/clang/Basic/FileManager.h
+++ clang/include/clang/Basic/FileManager.h
@@ -45,12 +45,31 @@
 class DirectoryEntry {
   friend class FileManager;
 
+  // FIXME: We should not be storing a directory entry name here.
   StringRef Name; // Name of the directory.
 
 public:
   StringRef getName() const { return Name; }
 };
 
+/// A reference to a \c DirectoryEntry  that includes the name of the directory
+/// as it was accessed by the FileManager's client.
+class DirectoryEntryRef {
+public:
+  const DirectoryEntry *getDirEntry() const { return &(*Entry->getValue()); }
+
+  StringRef getName() const { return Entry->getKey(); }
+
+private:
+  friend class FileManager;
+
+  DirectoryEntryRef(
+      llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>> *Entry)
+      : Entry(Entry) {}
+
+  const llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>> *Entry;
+};
+
 /// Cached information about one file (either on disk
 /// or in the virtual file system).
 ///
@@ -246,6 +265,29 @@
   /// virtual).
   ///
   /// This returns a \c std::error_code if there was an error reading the
+  /// directory. On success, returns the reference to the directory entry
+  /// together with the exact path that was used to access a file by a
+  /// particular call to getDirectoryRef.
+  ///
+  /// \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);
+
+  /// Get a \c DirectoryEntryRef if it exists, without doing anything on error.
+  llvm::Optional<DirectoryEntryRef>
+  getOptionalDirectoryRef(StringRef DirName, bool CacheFailure = true) {
+    return llvm::expectedToOptional(getDirectoryRef(DirName, CacheFailure));
+  }
+
+  /// Lookup, cache, and verify the specified directory (real or
+  /// virtual).
+  ///
+  /// This function is deprecated and will be removed at some point in the
+  /// future, new clients should use
+  ///  \c getDirectoryRef.
+  ///
+  /// This returns a \c std::error_code if there was an error reading the
   /// directory. If there is no error, the DirectoryEntry is guaranteed to be
   /// non-NULL.
   ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D67026: In... Alex Lorenz via Phabricator via cfe-commits

Reply via email to