hans updated this revision to Diff 59982.
hans added a comment.

Add --show-includes test.


http://reviews.llvm.org/D21113

Files:
  include/clang/Basic/VirtualFileSystem.h
  include/clang/Driver/Options.td
  include/clang/Lex/HeaderSearchOptions.h
  lib/Basic/VirtualFileSystem.cpp
  lib/Driver/Tools.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/Driver/cl-options.c
  test/Frontend/Inputs/case-insensitive-includes.h
  test/Frontend/case-insensitive-includes.c
  unittests/Basic/VirtualFileSystemTest.cpp

Index: unittests/Basic/VirtualFileSystemTest.cpp
===================================================================
--- unittests/Basic/VirtualFileSystemTest.cpp
+++ unittests/Basic/VirtualFileSystemTest.cpp
@@ -107,8 +107,15 @@
 
   vfs::directory_iterator dir_begin(const Twine &Dir,
                                     std::error_code &EC) override {
-    return vfs::directory_iterator(
+    auto I = vfs::directory_iterator(
         std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
+
+    // Even if there is no entry for /foo, /foo/bar may exist, so only set the
+    // error code if /foo returns an empty iterator.
+    if (I == vfs::directory_iterator())
+      EC = status(Dir).getError();
+
+    return I;
   }
 
   void addEntry(StringRef Path, const vfs::Status &Status) {
@@ -1164,3 +1171,52 @@
   }
   EXPECT_EQ(I, E);
 }
+
+class CaseInsensitiveFileSystemTest : public ::testing::Test {
+private:
+  IntrusiveRefCntPtr<DummyFileSystem> Base;
+
+protected:
+  IntrusiveRefCntPtr<clang::vfs::FileSystem> FS;
+
+  CaseInsensitiveFileSystemTest()
+      : Base(new DummyFileSystem()),
+        FS(new clang::vfs::CaseInsensitiveFileSystem(Base)) {
+    Base->addRegularFile("/foo");
+    Base->addDirectory("/bar");
+    Base->addRegularFile("/bar/baz");
+  }
+};
+
+TEST_F(CaseInsensitiveFileSystemTest, Basic) {
+  // Not just accepting anything.
+  auto Status = FS->status("/F00");
+  ASSERT_EQ(llvm::errc::no_such_file_or_directory, Status.getError());
+
+  // Case-insensitive file is found.
+  Status = FS->status("/FoO");
+  ASSERT_FALSE(Status.getError());
+
+  // Case-insensitive dir works too.
+  Status = FS->status("/bAr/baZ");
+  ASSERT_FALSE(Status.getError());
+
+  // Test openFileForRead.
+  auto File = FS->openFileForRead("/F00");
+  ASSERT_EQ(llvm::errc::no_such_file_or_directory, File.getError());
+  File = FS->openFileForRead("/Foo");
+  ASSERT_FALSE(File.getError());
+  File = FS->openFileForRead("/Bar/Baz");
+  ASSERT_FALSE(File.getError());
+
+  // Test directory listing.
+  std::error_code EC;
+  auto Dir = FS->dir_begin("/b4r", EC);
+  ASSERT_EQ(llvm::errc::no_such_file_or_directory, EC);
+  Dir = FS->dir_begin("/bAr", EC);
+  ASSERT_FALSE(EC);
+  ASSERT_EQ("/bar/baz", Dir->getName());
+  Dir.increment(EC);
+  ASSERT_FALSE(EC);
+  ASSERT_EQ(vfs::directory_iterator(), Dir);
+}
Index: test/Frontend/case-insensitive-includes.c
===================================================================
--- /dev/null
+++ test/Frontend/case-insensitive-includes.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -fcase-insensitive-includes -verify %s
+// RUN: %clang_cc1 -fsyntax-only --show-includes -fcase-insensitive-includes %s | FileCheck %s
+
+#include "InpUts/CasE-InsensitivE-Includes.h" // expected-no-diagnostics
+
+// Make sure the real filename is used when printing header dependencies.
+// CHECK: including file: {{.*}}case-insensitive-includes.h
Index: test/Driver/cl-options.c
===================================================================
--- test/Driver/cl-options.c
+++ test/Driver/cl-options.c
@@ -466,6 +466,7 @@
 // RUN:     -mllvm -disable-llvm-optzns \
 // RUN:     -Wunused-variable \
 // RUN:     -fmacro-backtrace-limit=0 \
+// RUN:     -fcase-insensitive-includes \
 // RUN:     -Werror /Zs -- %s 2>&1
 
 
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1447,6 +1447,8 @@
 
   for (const Arg *A : Args.filtered(OPT_ivfsoverlay))
     Opts.AddVFSOverlayFile(A->getValue());
+
+  Opts.CaseInsensitive = Args.hasArg(OPT_fcase_insensitive_includes);
 }
 
 void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
@@ -2538,12 +2540,8 @@
   GraveYard[Idx] = Ptr;
 }
 
-IntrusiveRefCntPtr<vfs::FileSystem>
-createVFSFromCompilerInvocation(const CompilerInvocation &CI,
-                                DiagnosticsEngine &Diags) {
-  if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
-    return vfs::getRealFileSystem();
-
+static IntrusiveRefCntPtr<vfs::FileSystem>
+getOverlayFS(const CompilerInvocation &CI, DiagnosticsEngine &Diags) {
   IntrusiveRefCntPtr<vfs::OverlayFileSystem>
     Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
   // earlier vfs files are on the bottom
@@ -2565,4 +2563,20 @@
   }
   return Overlay;
 }
+
+IntrusiveRefCntPtr<vfs::FileSystem>
+createVFSFromCompilerInvocation(const CompilerInvocation &CI,
+                                DiagnosticsEngine &Diags) {
+  IntrusiveRefCntPtr<vfs::FileSystem> FS;
+
+  if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
+    FS = vfs::getRealFileSystem();
+  else
+    FS = getOverlayFS(CI, Diags);
+
+  if (CI.getHeaderSearchOpts().CaseInsensitive)
+    FS = new vfs::CaseInsensitiveFileSystem(FS);
+
+  return FS;
+}
 } // end namespace clang
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -570,6 +570,9 @@
   // Add CUDA include arguments, if needed.
   if (types::isCuda(Inputs[0].getType()))
     getToolChain().AddCudaIncludeArgs(Args, CmdArgs);
+
+  if (Args.hasArg(options::OPT_fcase_insensitive_includes))
+    CmdArgs.push_back("-fcase-insensitive-includes");
 }
 
 // FIXME: Move to target hook.
Index: lib/Basic/VirtualFileSystem.cpp
===================================================================
--- lib/Basic/VirtualFileSystem.cpp
+++ lib/Basic/VirtualFileSystem.cpp
@@ -392,6 +392,94 @@
       std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC));
 }
 
+//===-----------------------------------------------------------------------===/
+// CaseInsensitiveFileSystem implementation
+//===-----------------------------------------------------------------------===/
+
+CaseInsensitiveFileSystem::CaseInsensitiveFileSystem(
+    IntrusiveRefCntPtr<FileSystem> Base)
+    : Base(Base) {}
+
+std::error_code CaseInsensitiveFileSystem::findCaseInsensitivePath(
+    StringRef Path, SmallVectorImpl<char> &FoundPath) {
+  StringRef FileName = llvm::sys::path::filename(Path);
+  StringRef Dir = llvm::sys::path::parent_path(Path);
+
+  // Open the directory for iterating. In the common case, the directory exists.
+  std::error_code EC;
+  directory_iterator I = Base->dir_begin(Dir, EC), E;
+
+  if (EC == errc::no_such_file_or_directory) {
+    // If the dir doesn't exist, try to find it and try again.
+    if (llvm::sys::path::parent_path(Dir).empty())
+      return EC;
+    SmallVector<char, 512> NewDir;
+    if ((EC = findCaseInsensitivePath(Dir, NewDir)))
+      return EC;
+    llvm::sys::path::append(NewDir, FileName);
+    return findCaseInsensitivePath(StringRef(NewDir.data(), NewDir.size()),
+                                   FoundPath);
+  }
+
+  for (; !EC && I != E; I.increment(EC)) {
+    StringRef DirEntry = llvm::sys::path::filename(I->getName());
+    if (DirEntry.equals_lower(FileName)) {
+      llvm::sys::path::append(FoundPath, Dir, DirEntry);
+      return std::error_code();
+    }
+  }
+
+  return EC ? EC : llvm::errc::no_such_file_or_directory;
+}
+
+llvm::ErrorOr<Status> CaseInsensitiveFileSystem::status(const Twine &Path) {
+  auto S = Base->status(Path);
+  if (S.getError() != llvm::errc::no_such_file_or_directory)
+    return S;
+
+  SmallVector<char, 512> NewPath;
+  if (std::error_code EC = findCaseInsensitivePath(Path.str(), NewPath))
+    return EC;
+
+  return Base->status(NewPath);
+}
+
+llvm::ErrorOr<std::unique_ptr<File>>
+CaseInsensitiveFileSystem::openFileForRead(const Twine &Path) {
+  auto F = Base->openFileForRead(Path);
+  if (F.getError() != llvm::errc::no_such_file_or_directory)
+    return F;
+
+  SmallVector<char, 512> NewPath;
+  if (std::error_code EC = findCaseInsensitivePath(Path.str(), NewPath))
+    return EC;
+
+  return Base->openFileForRead(NewPath);
+}
+
+directory_iterator CaseInsensitiveFileSystem::dir_begin(const Twine &Path,
+                                                        std::error_code &EC) {
+  auto I = Base->dir_begin(Path, EC);
+  if (EC != llvm::errc::no_such_file_or_directory)
+    return I;
+
+  SmallVector<char, 512> NewPath;
+  if ((EC = findCaseInsensitivePath(Path.str(), NewPath)))
+    return directory_iterator();
+
+  return Base->dir_begin(NewPath, EC);
+}
+
+llvm::ErrorOr<std::string>
+CaseInsensitiveFileSystem::getCurrentWorkingDirectory() const {
+  return Base->getCurrentWorkingDirectory();
+}
+
+std::error_code
+CaseInsensitiveFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
+  return Base->setCurrentWorkingDirectory(Path);
+}
+
 namespace clang {
 namespace vfs {
 namespace detail {
Index: include/clang/Lex/HeaderSearchOptions.h
===================================================================
--- include/clang/Lex/HeaderSearchOptions.h
+++ include/clang/Lex/HeaderSearchOptions.h
@@ -161,6 +161,9 @@
   /// Whether header search information should be output as for -v.
   unsigned Verbose : 1;
 
+  /// Whether header search should be case-insensitive.
+  unsigned CaseInsensitive : 1;
+
   /// \brief If true, skip verifying input files used by modules if the
   /// module was already verified during this build session (see
   /// \c BuildSessionTimestamp).
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -525,6 +525,8 @@
 def fdiagnostics_color_EQ : Joined<["-"], "fdiagnostics-color=">, Group<f_Group>;
 def fansi_escape_codes : Flag<["-"], "fansi-escape-codes">, Group<f_Group>,
   Flags<[CoreOption, CC1Option]>, HelpText<"Use ANSI escape codes for diagnostics">;
+def fcase_insensitive_includes : Flag<["-"], "fcase-insensitive-includes">, Group<f_Group>,
+  Flags<[CC1Option, CoreOption]>, HelpText<"Make include lookups case-insensitive">;
 def fcomment_block_commands : CommaJoined<["-"], "fcomment-block-commands=">, Group<f_clang_Group>, Flags<[CC1Option]>,
   HelpText<"Treat each comma separated argument in <arg> as a documentation comment block command">,
   MetaVarName<"<arg>">;
Index: include/clang/Basic/VirtualFileSystem.h
===================================================================
--- include/clang/Basic/VirtualFileSystem.h
+++ include/clang/Basic/VirtualFileSystem.h
@@ -272,6 +272,24 @@
   iterator overlays_end() { return FSList.rend(); }
 };
 
+class CaseInsensitiveFileSystem : public FileSystem {
+  IntrusiveRefCntPtr<FileSystem> Base;
+
+  /// Try to find Path by means of case-insensitive lookup. Stores the result in
+  /// FoundPath on success, or returns an error code otherwise.
+  std::error_code findCaseInsensitivePath(StringRef Path,
+                                          SmallVectorImpl<char> &FoundPath);
+public:
+  CaseInsensitiveFileSystem(IntrusiveRefCntPtr<FileSystem> Base);
+
+  llvm::ErrorOr<Status> status(const Twine &Path) override;
+  llvm::ErrorOr<std::unique_ptr<File>>
+  openFileForRead(const Twine &Path) override;
+  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
+  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
+  std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
+};
+
 namespace detail {
 class InMemoryDirectory;
 } // end namespace detail
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to