[clang] [LLVM][ADT] Add specialization of `DenseMapInfo` for `SourceRange` (PR #174524)
Victor Chernyakin via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 6 07:29:47 PST 2026
https://github.com/localspook updated https://github.com/llvm/llvm-project/pull/174524
>From 0f765712a6c5586478656998f15a3b581f09d704 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Mon, 5 Jan 2026 19:24:37 -0800
Subject: [PATCH 1/2] [LLVM][ADT] Add specialization of `DenseMapInfo` for
`SourceRange`
---
clang/include/clang/Basic/SourceLocation.h | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/clang/include/clang/Basic/SourceLocation.h b/clang/include/clang/Basic/SourceLocation.h
index 14543cc41a38e..85fe65901d207 100644
--- a/clang/include/clang/Basic/SourceLocation.h
+++ b/clang/include/clang/Basic/SourceLocation.h
@@ -521,6 +521,27 @@ namespace llvm {
static void Profile(const clang::SourceLocation &X, FoldingSetNodeID &ID);
};
+ template <> struct DenseMapInfo<clang::SourceRange, void> {
+ static clang::SourceRange getEmptyKey() {
+ return {DenseMapInfo<clang::SourceLocation>::getEmptyKey(),
+ DenseMapInfo<clang::SourceLocation>::getEmptyKey()};
+ }
+
+ static clang::SourceRange getTombstoneKey() {
+ return {DenseMapInfo<clang::SourceLocation>::getTombstoneKey(),
+ DenseMapInfo<clang::SourceLocation>::getTombstoneKey()};
+ }
+
+ static unsigned getHashValue(clang::SourceRange Range) {
+ return detail::combineHashValue(Range.getBegin().getHashValue(),
+ Range.getEnd().getHashValue());
+ }
+
+ static bool isEqual(clang::SourceRange LHS, clang::SourceRange RHS) {
+ return LHS == RHS;
+ }
+ };
+
} // namespace llvm
#endif // LLVM_CLANG_BASIC_SOURCELOCATION_H
>From 0f2b5b6e683c1c3f7848846777920cfb3d2bd637 Mon Sep 17 00:00:00 2001
From: Victor Chernyakin <chernyakin.victor.j at outlook.com>
Date: Tue, 6 Jan 2026 07:29:33 -0800
Subject: [PATCH 2/2] Add unit tests, slightly simplify implementation
---
clang/include/clang/Basic/SourceLocation.h | 8 +-
clang/unittests/Basic/SourceManagerTest.cpp | 113 +++++++++++---------
2 files changed, 64 insertions(+), 57 deletions(-)
diff --git a/clang/include/clang/Basic/SourceLocation.h b/clang/include/clang/Basic/SourceLocation.h
index 85fe65901d207..bd0038d5ae1ae 100644
--- a/clang/include/clang/Basic/SourceLocation.h
+++ b/clang/include/clang/Basic/SourceLocation.h
@@ -521,15 +521,13 @@ namespace llvm {
static void Profile(const clang::SourceLocation &X, FoldingSetNodeID &ID);
};
- template <> struct DenseMapInfo<clang::SourceRange, void> {
+ template <> struct DenseMapInfo<clang::SourceRange> {
static clang::SourceRange getEmptyKey() {
- return {DenseMapInfo<clang::SourceLocation>::getEmptyKey(),
- DenseMapInfo<clang::SourceLocation>::getEmptyKey()};
+ return DenseMapInfo<clang::SourceLocation>::getEmptyKey();
}
static clang::SourceRange getTombstoneKey() {
- return {DenseMapInfo<clang::SourceLocation>::getTombstoneKey(),
- DenseMapInfo<clang::SourceLocation>::getTombstoneKey()};
+ return DenseMapInfo<clang::SourceLocation>::getTombstoneKey();
}
static unsigned getHashValue(clang::SourceRange Range) {
diff --git a/clang/unittests/Basic/SourceManagerTest.cpp b/clang/unittests/Basic/SourceManagerTest.cpp
index 04b23dd13ba3e..87427241adbbb 100644
--- a/clang/unittests/Basic/SourceManagerTest.cpp
+++ b/clang/unittests/Basic/SourceManagerTest.cpp
@@ -11,6 +11,7 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Lex/HeaderSearch.h"
@@ -18,6 +19,7 @@
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -125,9 +127,8 @@ TEST_F(SourceManagerTest, isInSystemHeader) {
}
TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
- const char *source =
- "#define M(x) [x]\n"
- "M(foo)";
+ const char *source = "#define M(x) [x]\n"
+ "M(foo)";
std::unique_ptr<llvm::MemoryBuffer> Buf =
llvm::MemoryBuffer::getMemBuffer(source);
FileID mainFileID = SourceMgr.createFileID(std::move(Buf));
@@ -150,12 +151,13 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
ASSERT_EQ(tok::l_square, toks[0].getKind());
ASSERT_EQ(tok::identifier, toks[1].getKind());
ASSERT_EQ(tok::r_square, toks[2].getKind());
-
+
SourceLocation lsqrLoc = toks[0].getLocation();
SourceLocation idLoc = toks[1].getLocation();
SourceLocation rsqrLoc = toks[2].getLocation();
-
- SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1);
+
+ SourceLocation macroExpStartLoc =
+ SourceMgr.translateLineCol(mainFileID, 2, 1);
SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6);
ASSERT_TRUE(macroExpStartLoc.isFileID());
ASSERT_TRUE(macroExpEndLoc.isFileID());
@@ -241,9 +243,8 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithTokenSplit) {
}
TEST_F(SourceManagerTest, getColumnNumber) {
- const char *Source =
- "int x;\n"
- "int y;";
+ const char *Source = "int x;\n"
+ "int y;";
std::unique_ptr<llvm::MemoryBuffer> Buf =
llvm::MemoryBuffer::getMemBuffer(Source);
@@ -269,12 +270,12 @@ TEST_F(SourceManagerTest, getColumnNumber) {
EXPECT_TRUE(!Invalid);
Invalid = false;
- EXPECT_EQ(7U, SourceMgr.getColumnNumber(MainFileID, strlen(Source),
- &Invalid));
+ EXPECT_EQ(7U,
+ SourceMgr.getColumnNumber(MainFileID, strlen(Source), &Invalid));
EXPECT_TRUE(!Invalid);
Invalid = false;
- SourceMgr.getColumnNumber(MainFileID, strlen(Source)+1, &Invalid);
+ SourceMgr.getColumnNumber(MainFileID, strlen(Source) + 1, &Invalid);
EXPECT_TRUE(Invalid);
// Test invalid files
@@ -379,21 +380,18 @@ TEST_F(SourceManagerTest, getInvalidBOM) {
"UTF-32 (LE)");
}
-// Regression test - there was an out of bound access for buffers not terminated by zero.
+// Regression test - there was an out of bound access for buffers not terminated
+// by zero.
TEST_F(SourceManagerTest, getLineNumber) {
const unsigned pageSize = llvm::sys::Process::getPageSizeEstimate();
std::unique_ptr<char[]> source(new char[pageSize]);
- for(unsigned i = 0; i < pageSize; ++i) {
+ for (unsigned i = 0; i < pageSize; ++i) {
source[i] = 'a';
}
- std::unique_ptr<llvm::MemoryBuffer> Buf =
- llvm::MemoryBuffer::getMemBuffer(
- llvm::MemoryBufferRef(
- llvm::StringRef(source.get(), 3), "whatever"
- ),
- false
- );
+ std::unique_ptr<llvm::MemoryBuffer> Buf = llvm::MemoryBuffer::getMemBuffer(
+ llvm::MemoryBufferRef(llvm::StringRef(source.get(), 3), "whatever"),
+ false);
FileID mainFileID = SourceMgr.createFileID(std::move(Buf));
SourceMgr.setMainFileID(mainFileID);
@@ -401,6 +399,20 @@ TEST_F(SourceManagerTest, getLineNumber) {
ASSERT_NO_FATAL_FAILURE(SourceMgr.getLineNumber(mainFileID, 1, nullptr));
}
+TEST_F(SourceManagerTest, sourceRangeWorksWithDenseSet) {
+ llvm::DenseSet<SourceRange> Set;
+ SourceRange TestRange = {SourceLocation::getFromRawEncoding(10),
+ SourceLocation::getFromRawEncoding(11)};
+ ASSERT_EQ(Set.size(), 0);
+ Set.insert(TestRange);
+ ASSERT_EQ(Set.size(), 1);
+ ASSERT_TRUE(Set.contains(TestRange));
+ ASSERT_FALSE(Set.contains({SourceLocation::getFromRawEncoding(10),
+ SourceLocation::getFromRawEncoding(10)}));
+ Set.erase(TestRange);
+ ASSERT_EQ(Set.size(), 0);
+}
+
struct FakeExternalSLocEntrySource : ExternalSLocEntrySource {
bool ReadSLocEntry(int ID) override { return {}; }
int getSLocEntryID(SourceLocation::UIntTy SLocOffset) override { return 0; }
@@ -509,17 +521,15 @@ TEST_F(SourceManagerTest, ResetsIncludeLocMap) {
}
TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
- const char *header =
- "#define FM(x,y) x\n";
-
- const char *main =
- "#include \"/test-header.h\"\n"
- "#define VAL 0\n"
- "FM(VAL,0)\n"
- "FM(0,VAL)\n"
- "FM(FM(0,VAL),0)\n"
- "#define CONCAT(X, Y) X##Y\n"
- "CONCAT(1,1)\n";
+ const char *header = "#define FM(x,y) x\n";
+
+ const char *main = "#include \"/test-header.h\"\n"
+ "#define VAL 0\n"
+ "FM(VAL,0)\n"
+ "FM(0,VAL)\n"
+ "FM(FM(0,VAL),0)\n"
+ "#define CONCAT(X, Y) X##Y\n"
+ "CONCAT(1,1)\n";
std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
llvm::MemoryBuffer::getMemBuffer(header);
@@ -580,7 +590,7 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
namespace {
struct MacroAction {
- enum Kind { kExpansion, kDefinition, kUnDefinition};
+ enum Kind { kExpansion, kDefinition, kUnDefinition };
SourceLocation Loc;
std::string Name;
@@ -599,7 +609,7 @@ class MacroTracker : public PPCallbacks {
std::vector<MacroAction> &Macros;
public:
- explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
+ explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) {}
void MacroDefined(const Token &MacroNameTok,
const MacroDirective *MD) override {
@@ -607,9 +617,8 @@ class MacroTracker : public PPCallbacks {
MacroNameTok.getIdentifierInfo()->getName(),
MacroAction::kDefinition));
}
- void MacroUndefined(const Token &MacroNameTok,
- const MacroDefinition &MD,
- const MacroDirective *UD) override {
+ void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
+ const MacroDirective *UD) override {
Macros.push_back(
MacroAction(UD ? UD->getLocation() : SourceLocation(),
MacroNameTok.getIdentifierInfo()->getName(),
@@ -624,21 +633,19 @@ class MacroTracker : public PPCallbacks {
}
};
-}
+} // namespace
TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
- const char *header =
- "#define MACRO_IN_INCLUDE 0\n"
- "#define MACRO_DEFINED\n"
- "#undef MACRO_DEFINED\n"
- "#undef MACRO_UNDEFINED\n";
-
- const char *main =
- "#define M(x) x\n"
- "#define INC \"/test-header.h\"\n"
- "#include M(INC)\n"
- "#define INC2 </test-header.h>\n"
- "#include M(INC2)\n";
+ const char *header = "#define MACRO_IN_INCLUDE 0\n"
+ "#define MACRO_DEFINED\n"
+ "#undef MACRO_DEFINED\n"
+ "#undef MACRO_UNDEFINED\n";
+
+ const char *main = "#define M(x) x\n"
+ "#define INC \"/test-header.h\"\n"
+ "#include M(INC)\n"
+ "#define INC2 </test-header.h>\n"
+ "#include M(INC2)\n";
std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
llvm::MemoryBuffer::getMemBuffer(header);
@@ -712,11 +719,13 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
// The INC expansion in #include M(INC) comes before the first
// MACRO_IN_INCLUDE definition of the included file.
- EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
+ EXPECT_TRUE(
+ SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
// The INC2 expansion in #include M(INC2) comes before the second
// MACRO_IN_INCLUDE definition of the included file.
- EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc));
+ EXPECT_TRUE(
+ SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc));
}
TEST_F(SourceManagerTest, isMainFile) {
More information about the cfe-commits
mailing list