[clang] [clang-tools-extra] [llvm] [clangd] Avoid bogus error about recursive inclusion (PR #95200)
Nathan Ridge via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 11 22:47:28 PDT 2024
https://github.com/HighCommander4 created https://github.com/llvm/llvm-project/pull/95200
Fixes https://github.com/clangd/clangd/issues/337
>From 063d7f4977f0d75f88484c1110ca465aa50fc90a Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Wed, 12 Jun 2024 01:20:15 -0400
Subject: [PATCH] [clangd] Avoid bogus error about recursive inclusion
Fixes https://github.com/clangd/clangd/issues/337
---
.../clangd/unittests/SymbolCollectorTests.cpp | 39 +++++++++++++++++++
clang/lib/Serialization/ASTReader.cpp | 11 ++++++
clang/lib/Serialization/ASTWriter.cpp | 12 ++++++
llvm/include/llvm/Support/OnDiskHashTable.h | 4 +-
4 files changed, 64 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
index 1e7a30e69fabe..75c31f88d0fed 100644
--- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
@@ -1719,6 +1719,45 @@ TEST_F(SymbolCollectorTest, HeaderGuardDetected) {
EXPECT_THAT(Symbols, Each(includeHeader()));
}
+TEST_F(SymbolCollectorTest, HeaderGuardDetectedPragmaInPreamble) {
+ // TestTU builds with a preamble.
+ auto TU = TestTU::withCode(R"cpp(
+ #pragma once
+
+ // Symbols are seen before the header guard is complete.
+ #define MACRO
+ int decl();
+ #define MACRO2
+ )cpp");
+ TU.HeaderFilename = "Foo.h";
+ auto Symbols = TU.headerSymbols();
+ EXPECT_THAT(Symbols, Not(Contains(qName("HEADER_GUARD_"))));
+ EXPECT_THAT(Symbols, Contains(qName("MACRO")));
+ EXPECT_THAT(Symbols, Contains(qName("MACRO2")));
+ EXPECT_THAT(Symbols, Contains(qName("decl")));
+}
+
+TEST_F(SymbolCollectorTest, HeaderGuardDetectedIfdefInPreamble) {
+ // TestTU builds with a preamble.
+ auto TU = TestTU::withCode(R"cpp(
+ #ifndef HEADER_GUARD_
+ #define HEADER_GUARD_
+
+ // Symbols are seen before the header guard is complete.
+ #define MACRO
+ int decl();
+ #define MACRO2
+
+ #endif // Header guard is recognized here.
+ )cpp");
+ TU.HeaderFilename = "Foo.h";
+ auto Symbols = TU.headerSymbols();
+ EXPECT_THAT(Symbols, Not(Contains(qName("HEADER_GUARD_"))));
+ EXPECT_THAT(Symbols, Contains(qName("MACRO")));
+ EXPECT_THAT(Symbols, Contains(qName("MACRO2")));
+ EXPECT_THAT(Symbols, Contains(qName("decl")));
+}
+
TEST_F(SymbolCollectorTest, NonModularHeader) {
auto TU = TestTU::withHeaderCode("int x();");
EXPECT_THAT(TU.headerSymbols(), ElementsAre(includeHeader()));
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 44e23919ea18e..36d0e499e72b8 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -6518,6 +6518,17 @@ namespace {
// Look in the on-disk hash table for an entry for this file name.
HeaderFileInfoLookupTable::iterator Pos = Table->find(FE);
+ // Preambles may be reused with different main-file content.
+ // A second entry with size zero is stored for the main-file, try that.
+ // To avoid doing this on every miss, require the bare filename to match.
+ if (Pos == Table->end() && M.Kind == clang::serialization::MK_Preamble &&
+ llvm::sys::path::filename(FE.getName()) ==
+ llvm::sys::path::filename(M.OriginalSourceFileName)) {
+ auto InternalKey = Table->getInfoObj().GetInternalKey(FE);
+ InternalKey.Size = 0;
+ Pos = Table->find_hashed(InternalKey,
+ Table->getInfoObj().ComputeHash(InternalKey));
+ }
if (Pos == Table->end())
return false;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 8a4b36207c473..0a9093e0d189b 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -2044,6 +2044,10 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
SmallVector<OptionalFileEntryRef, 16> FilesByUID;
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
+ const auto &SM = Context->getSourceManager();
+ unsigned MainFileUID = -1;
+ if (const auto *Entry = SM.getFileEntryForID(SM.getMainFileID()))
+ MainFileUID = Entry->getUID();
if (FilesByUID.size() > HS.header_file_size())
FilesByUID.resize(HS.header_file_size());
@@ -2082,6 +2086,14 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
};
Generator.insert(Key, Data, GeneratorTrait);
++NumHeaderSearchEntries;
+ // We may reuse a preamble even if the rest of the file is different, so
+ // allow looking up info for the main file with a zero size.
+ if (this->getASTContext().getLangOpts().CompilingPCH &&
+ File->getUID() == MainFileUID) {
+ Key.Size = 0;
+ Generator.insert(Key, Data, GeneratorTrait);
+ ++NumHeaderSearchEntries;
+ }
}
// Create the on-disk hash table in a buffer.
diff --git a/llvm/include/llvm/Support/OnDiskHashTable.h b/llvm/include/llvm/Support/OnDiskHashTable.h
index f6b4055e74de7..561208aa9a679 100644
--- a/llvm/include/llvm/Support/OnDiskHashTable.h
+++ b/llvm/include/llvm/Support/OnDiskHashTable.h
@@ -321,8 +321,8 @@ template <typename Info> class OnDiskChainedHashTable {
class iterator {
internal_key_type Key;
- const unsigned char *const Data;
- const offset_type Len;
+ const unsigned char *Data;
+ offset_type Len;
Info *InfoObj;
public:
More information about the llvm-commits
mailing list