vgvassilev wrote:

Does that help:
```diff
diff --git a/clang/unittests/AST/ExternalASTSourceTest.cpp 
b/clang/unittests/AST/ExternalASTSourceTest.cpp
index 15483ad25097..47c8437f54e7 100644
--- a/clang/unittests/AST/ExternalASTSourceTest.cpp
+++ b/clang/unittests/AST/ExternalASTSourceTest.cpp
@@ -17,6 +17,7 @@
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Tooling/Tooling.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "gtest/gtest.h"
 
@@ -87,3 +88,56 @@ TEST(ExternalASTSourceTest, FailedLookupOccursOnce) {
       llvm::makeIntrusiveRefCnt<TestSource>(Calls), "int j, k = j;"));
   EXPECT_EQ(1u, Calls);
 }
+
+namespace {
+/// incrementGeneration is protected, so reaching it needs a source of our own.
+struct BumpableSource : ExternalASTSource {
+  uint32_t bump(ASTContext &C) { return incrementGeneration(C); }
+};
+} // namespace
+
+// A source that is not the one the ASTContext knows about still has to keep
+// step with the one that is. incrementGeneration returns the generation from
+// before the bump, and callers such as LazyGenerationalUpdatePtr decide a
+// cached value is stale by comparing what they stored against getGeneration().
+// A source left a generation behind therefore never looks stale, and whatever
+// it caches is never refreshed.
+TEST(ExternalASTSourceTest, IncrementGenerationKeepsSourcesInStep) {
+  std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCode("");
+  ASSERT_TRUE(AST != nullptr);
+  ASTContext &Ctx = AST->getASTContext();
+
+  auto Topmost = llvm::makeIntrusiveRefCnt<BumpableSource>();
+  auto Secondary = llvm::makeIntrusiveRefCnt<BumpableSource>();
+  Ctx.setExternalSource(Topmost);
+  ASSERT_EQ(Ctx.getExternalSource(), Topmost.get());
+
+  const uint32_t Start = Topmost->getGeneration();
+  ASSERT_EQ(Start, Secondary->getGeneration());
+
+  // Bumping the source the context does not know about must bump the one it
+  // does, and leave the two agreeing on the generation afterwards.
+  EXPECT_EQ(Start, Secondary->bump(Ctx));
+  EXPECT_EQ(Start + 1, Topmost->getGeneration());
+  EXPECT_EQ(Topmost->getGeneration(), Secondary->getGeneration());
+
+  // Bumping again returns the generation before this call rather than the one
+  // before the first, which is what a source that never advanced would report.
+  EXPECT_EQ(Start + 1, Secondary->bump(Ctx));
+  EXPECT_EQ(Start + 2, Topmost->getGeneration());
+  EXPECT_EQ(Topmost->getGeneration(), Secondary->getGeneration());
+}
+
+// The topmost source is its own delegate, so it must not bump twice.
+TEST(ExternalASTSourceTest, IncrementGenerationOnTopmostAdvancesOnce) {
+  std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCode("");
+  ASSERT_TRUE(AST != nullptr);
+  ASTContext &Ctx = AST->getASTContext();
+
+  auto Source = llvm::makeIntrusiveRefCnt<BumpableSource>();
+  Ctx.setExternalSource(Source);
+
+  const uint32_t Start = Source->getGeneration();
+  EXPECT_EQ(Start, Source->bump(Ctx));
+  EXPECT_EQ(Start + 1, Source->getGeneration());
+}
```

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

Reply via email to