Index: clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
===================================================================
--- clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -16,6 +16,7 @@
 
 #include "clang/AST/Decl.h"
 #include "clang/AST/Stmt.h"
+#include "clang/Sema/Sema.h"
 
 namespace clang {
 
@@ -51,10 +52,10 @@
   }
 };
 
-// This function invokes the analysis and allows the caller to react to it
-// through the handler class.
-void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler,
-                            bool EmitFixits);
+/// Analyze all function declarations in a complete `TU`: 
+void checkUnsafeBufferUsageForTU(const TranslationUnitDecl *TU,
+                                 UnsafeBufferUsageHandler &Handler,
+                                 clang::Sema &S, bool EmitFixits);
 
 namespace internal {
 // Tests if any two `FixItHint`s in `FixIts` conflict.  Two `FixItHint`s
Index: clang/include/clang/Sema/AnalysisBasedWarnings.h
===================================================================
--- clang/include/clang/Sema/AnalysisBasedWarnings.h
+++ clang/include/clang/Sema/AnalysisBasedWarnings.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H
 #define LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H
 
+#include "clang/AST/Decl.h"
 #include "llvm/ADT/DenseMap.h"
 #include <memory>
 
@@ -95,6 +96,9 @@
   void IssueWarnings(Policy P, FunctionScopeInfo *fscope,
                      const Decl *D, QualType BlockType);
 
+  // Issue warnings that require whole-translation-unit analysis.
+  void IssueWarnings(const TranslationUnitDecl *D);
+
   Policy getDefaultPolicy() { return DefaultPolicy; }
 
   void PrintStats() const;
Index: clang/lib/Analysis/UnsafeBufferUsage.cpp
===================================================================
--- clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1412,7 +1412,7 @@
   return S;
 }
 
-void clang::checkUnsafeBufferUsage(const Decl *D,
+void checkUnsafeBufferUsage(const Decl *D,
                                    UnsafeBufferUsageHandler &Handler,
                                    bool EmitFixits) {
   assert(D && D->getBody());
@@ -1468,3 +1468,58 @@
     }
   }
 }
+
+void clang::checkUnsafeBufferUsageForTU(const TranslationUnitDecl *TU,
+                                 UnsafeBufferUsageHandler &Handler,
+                                 clang::Sema &S, bool EmitFixits) {
+  DiagnosticsEngine &Diags = S.getDiagnostics();
+  static constexpr StringRef Tag = "Callable";
+
+  struct CallableFinderCallback : MatchFinder::MatchCallback {
+    UnsafeBufferUsageHandler &Handler;
+    DiagnosticsEngine &Diags;
+    clang::Sema &S;
+    const bool EmitFixits;
+
+    CallableFinderCallback(UnsafeBufferUsageHandler &Handler,
+                           DiagnosticsEngine &Diags, clang::Sema &S,
+                           bool EmitFixits)
+        : Handler(Handler), Diags(Diags), S(S), EmitFixits(EmitFixits) {}
+
+    void run(const MatchFinder::MatchResult &Result) override {
+      if (const auto *Callable = Result.Nodes.getNodeAs<Decl>(Tag)) {
+        // Do not do any analysis if we are going to just ignore them.
+        if (Diags.getIgnoreAllWarnings() ||
+            (Diags.getSuppressSystemWarnings() &&
+             S.SourceMgr.isInSystemHeader(Callable->getLocation())))
+          return;
+
+        // For code in dependent contexts, we'll do this at instantiation time.
+        if (cast<DeclContext>(Callable)->isDependentContext())
+          return;
+
+        if (S.hasUncompilableErrorOccurred())
+          return;
+
+        assert (Callable->getBody());
+
+        // Above checks and early returns are copied from
+        // `clang::sema::AnalysisBasedWarnings::IssueWarnings`.
+        checkUnsafeBufferUsage(Callable, Handler, EmitFixits);
+        // FIXME: add notes for template instantiations
+      }
+    }
+  };
+
+  MatchFinder Finder;
+  CallableFinderCallback CB(Handler, Diags, S, EmitFixits);
+
+  Finder.addMatcher(
+      decl(forEachDescendant(decl(anyOf(
+          functionDecl(hasBody(anything())).bind(Tag),
+          objcMethodDecl(isDefinition()).bind(Tag), blockDecl().bind(Tag))))),
+      &CB);
+  Finder.addMatcher(stmt(forEachDescendant(stmt(lambdaExpr().bind(Tag)))), &CB);
+  Finder.match(*TU, TU->getASTContext());
+}
+
Index: clang/lib/Sema/AnalysisBasedWarnings.cpp
===================================================================
--- clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2284,6 +2284,24 @@
     S.Diag(D.Loc, D.PD);
 }
 
+void clang::sema::AnalysisBasedWarnings::IssueWarnings(
+    const TranslationUnitDecl *TU) {
+  if (!TU)
+    return; // This is unexpected, give up quietly.
+
+  DiagnosticsEngine &Diags = S.getDiagnostics();
+
+  // Emit unsafe buffer usage warnings and fixits.
+  if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, SourceLocation()) ||
+      !Diags.isIgnored(diag::warn_unsafe_buffer_variable, SourceLocation())) {
+    UnsafeBufferUsageReporter R(S);
+    checkUnsafeBufferUsageForTU(
+        TU, R, S,
+        /*EmitFixits=*/S.getDiagnostics().getDiagnosticOptions().ShowFixits &&
+            S.getLangOpts().CPlusPlus20);
+  }
+}
+
 void clang::sema::AnalysisBasedWarnings::IssueWarnings(
     sema::AnalysisBasedWarnings::Policy P, sema::FunctionScopeInfo *fscope,
     const Decl *D, QualType BlockType) {
@@ -2512,16 +2530,6 @@
       if (S.getLangOpts().CPlusPlus && isNoexcept(FD))
         checkThrowInNonThrowingFunc(S, FD, AC);
 
-  // Emit unsafe buffer usage warnings and fixits.
-  if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, D->getBeginLoc()) ||
-      !Diags.isIgnored(diag::warn_unsafe_buffer_variable, D->getBeginLoc())) {
-    UnsafeBufferUsageReporter R(S);
-    checkUnsafeBufferUsage(
-        D, R,
-        /*EmitFixits=*/S.getDiagnostics().getDiagnosticOptions().ShowFixits &&
-            S.getLangOpts().CPlusPlus20);
-  }
-
   // If none of the previous checks caused a CFG build, trigger one here
   // for the logical error handler.
   if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -1430,6 +1430,8 @@
     }
   }
 
+  AnalysisWarnings.IssueWarnings(Context.getTranslationUnitDecl());
+
   // Check we've noticed that we're no longer parsing the initializer for every
   // variable. If we miss cases, then at best we have a performance issue and
   // at worst a rejects-valid bug.
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp
===================================================================
--- clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp
+++ clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp
@@ -226,11 +226,11 @@
 void testTemplate(int * p) {
   int *a[10];
   foo(f(p, &p, a, a)[1]); // expected-warning{{unsafe buffer access}}
-                          // expected-note@-1{{in instantiation of function template specialization 'f<int *, 10>' requested here}}
+                          // FIXME: expected note@-1{{in instantiation of function template specialization 'f<int *, 10>' requested here}}
 
   const int **q = const_cast<const int **>(&p);
 
-  testPointerArithmetic(p, q, p); //expected-note{{in instantiation of}}
+  testPointerArithmetic(p, q, p); // FIXME: expected note{{in instantiation of}}
 }
 
 void testPointerToMember() {
@@ -321,7 +321,7 @@
   foo(ar[5]);   // expected-note{{used in buffer access here}}
 }
 
-template void fArr<int>(int t[]); // expected-note {{in instantiation of}}
+template void fArr<int>(int t[]); // FIXME: expected note {{in instantiation of}}
 
 int testReturn(int t[]) {
   // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}}