https://github.com/kimgr created 
https://github.com/llvm/llvm-project/pull/174575

Demonstrates:

- A bug where files resolved adjacent to the includer (and not from the header 
search path) do not get their include name mapped
- A surprising behavior where include name mappings are overwritten if files 
are included by more than one name

From 22353c413d871124e65bc2d1b5610a1cd27c88dd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kim=20Gr=C3=A4sman?= <[email protected]>
Date: Tue, 6 Jan 2026 12:35:02 +0100
Subject: [PATCH] Add unit test for #174482

Demonstrates:

- A bug where files resolved adjacent to the includer (and not from the
  header search path) do not get their include name mapped
- A surprising behavior where include name mappings are overwritten if
  files are included by more than one name
---
 clang/unittests/Lex/HeaderSearchTest.cpp | 60 ++++++++++++++++++++++--
 1 file changed, 57 insertions(+), 3 deletions(-)

diff --git a/clang/unittests/Lex/HeaderSearchTest.cpp 
b/clang/unittests/Lex/HeaderSearchTest.cpp
index 0213bfeb8e221..b5de494e10110 100644
--- a/clang/unittests/Lex/HeaderSearchTest.cpp
+++ b/clang/unittests/Lex/HeaderSearchTest.cpp
@@ -37,14 +37,15 @@ class HeaderSearchTest : public ::testing::Test {
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
   }
 
-  void addSearchDir(llvm::StringRef Dir) {
+  void addSearchDir(llvm::StringRef Dir, bool IsSystem = false) {
     VFS->addFile(
         Dir, 0, llvm::MemoryBuffer::getMemBuffer(""), /*User=*/std::nullopt,
         /*Group=*/std::nullopt, llvm::sys::fs::file_type::directory_file);
     auto DE = FileMgr.getOptionalDirectoryRef(Dir);
     assert(DE);
-    auto DL = DirectoryLookup(*DE, SrcMgr::C_User, /*isFramework=*/false);
-    Search.AddSearchPath(DL, /*isAngled=*/false);
+    auto DL = DirectoryLookup(*DE, IsSystem ? SrcMgr::C_System : 
SrcMgr::C_User,
+                              /*isFramework=*/false);
+    Search.AddSearchPath(DL, /*isAngled=*/IsSystem);
   }
 
   void addFrameworkSearchDir(llvm::StringRef Dir, bool IsSystem = true) {
@@ -389,5 +390,58 @@ TEST_F(HeaderSearchTest, HeaderFileInfoMerge) {
   EXPECT_FALSE(Search.getExistingFileInfo(TextualFE)->External);
 }
 
+TEST_F(HeaderSearchTest, IncludeNamesLookup) {
+  auto AddHeader = [&](const std::string &HeaderPath) -> FileEntryRef {
+    VFS->addFile(HeaderPath, 0,
+                 llvm::MemoryBuffer::getMemBufferCopy("", HeaderPath),
+                 /*User=*/std::nullopt, /*Group=*/std::nullopt,
+                 llvm::sys::fs::file_type::regular_file);
+    return *FileMgr.getOptionalFileRef(HeaderPath);
+  };
+
+  auto LookupFile =
+      [&](llvm::StringRef Filename, bool IsAngled,
+          llvm::ArrayRef<std::pair<OptionalFileEntryRef, DirectoryEntryRef>>
+              Includers) -> OptionalFileEntryRef {
+    return Search.LookupFile(
+        Filename, SourceLocation(), /*isAngled=*/IsAngled,
+        /*FromDir=*/nullptr,
+        /*CurDir=*/nullptr, Includers, /*SearchPath=*/nullptr,
+        /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr,
+        /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr,
+        /*IsFrameworkFound=*/nullptr);
+  };
+
+  AddHeader("/sys/bits/textual.h");
+  AddHeader("/sys/bits/detail.h");
+  AddHeader("/sys/system.h");
+  addSearchDir("/sys", /*IsSystem=*/true);
+
+  // main.c: #include <system.h>
+  auto SystemFile = LookupFile("system.h", true, {});
+  ASSERT_TRUE(SystemFile.has_value());
+  // system.h: #include <bits/detail.h>
+  auto DetailFile =
+      LookupFile("bits/detail.h", true, {{SystemFile, SystemFile->getDir()}});
+  ASSERT_TRUE(DetailFile.has_value());
+  // bits/detail.h: #include "textual.h"
+  auto TextualFile =
+      LookupFile("textual.h", false, {{DetailFile, DetailFile->getDir()}});
+  ASSERT_TRUE(TextualFile.has_value());
+
+  EXPECT_EQ(Search.getIncludeNameForHeader(*SystemFile), "system.h");
+  EXPECT_EQ(Search.getIncludeNameForHeader(*DetailFile), "bits/detail.h");
+  // BUG: LookupFile does not add an include name for textual.h.
+  EXPECT_EQ(Search.getIncludeNameForHeader(*TextualFile), "textual.h");
+
+  // bits/detail.h: #include "bits/textual.h"
+  auto R =
+      LookupFile("bits/textual.h", false, {{DetailFile, 
DetailFile->getDir()}});
+  ASSERT_TRUE(R.has_value());
+  // SURPRISE? TextualFile is remapped under the hood because "bits/textual.h"
+  // resolves to the same file as "textual.h".
+  EXPECT_EQ(Search.getIncludeNameForHeader(*TextualFile), "bits/textual.h");
+}
+
 } // namespace
 } // namespace clang

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to