HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
diagnosticTrap.h
Go to the documentation of this file.
1 //
2 // Copyright 2026 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_TF_DIAGNOSTIC_TRAP_H
8 #define PXR_BASE_TF_DIAGNOSTIC_TRAP_H
9 
10 /// \file tf/diagnosticTrap.h
11 
12 #include "pxr/pxr.h"
13 #include "pxr/base/tf/api.h"
16 #include "pxr/base/tf/tryInvoke.h"
17 
18 #include <vector>
19 
21 
22 /// \class TfDiagnosticTrap
23 /// \ingroup group_tf_Diagnostic
24 ///
25 /// A scoped, stack-based mechanism for intercepting and examining diagnostics
26 /// issued on the current thread.
27 ///
28 /// When a \c TfDiagnosticTrap is active, any \c TfError, \c TfWarning, or \c
29 /// TfStatus \em reported on the current thread is captured by the trap rather
30 /// than being forwarded to registered \c TfDiagnosticMgr delegates or
31 /// reported. Traps nest: if multiple traps are active on the same thread, the
32 /// innermost trap captures all diagnostics.
33 ///
34 /// Captured diagnostics may be inspected at any time during the trap's
35 /// lifetime. On destruction, any diagnostics not explicitly cleared are
36 /// re-posted, letting them propagate to the next enclosing trap or to
37 /// diagnostic delegates.
38 ///
39 /// To discard captured diagnostics, call \c Clear(), \c ClearErrors(), \c
40 /// ClearWarnings(), \c ClearStatuses(), or \c EraseMatching() before the trap
41 /// is destroyed.
42 ///
43 /// Example usage in a unit test:
44 /// \code
45 /// TfDiagnosticTrap trap;
46 /// DoSomethingExpectedToWarn();
47 /// TF_AXIOM(trap.HasWarnings());
48 /// trap.ClearWarnings();
49 /// // warnings are discarded; other diagnostics (if any) will re-report on
50 /// // destruction
51 /// \endcode
52 ///
53 /// \note \c TfDiagnosticTrap operates at \em report time, not at \em raise
54 /// time. When no \c TfErrorMark is active, errors are reported immediately and
55 /// will be captured by the active trap. However, when a \c TfErrorMark is
56 /// active on the current thread, errors are accumulated in the mark rather than
57 /// immediately reported, and will \em not be captured by the trap. Warnings
58 /// and status messages are always reported immediately and therefore are not
59 /// affected by this distinction.
61 public:
62  TfDiagnosticTrap(const TfDiagnosticTrap&) = delete;
64 
65  /// Construct a trap and install it as the active interceptor on the current
66  /// thread.
68 
69  /// Destroy the trap, re-posting any diagnostics not explicitly discarded by
70  /// calls to the Clear or Erase families of member functions.
72 
73  /// Re-post any uncleared diagnostics and deactivate the trap; called
74  /// automatically on destruction if not called explicitly.
75  TF_API void Dismiss();
76 
77  /// Discard all captured diagnostics. They will not be re-posted.
78  TF_API void Clear();
79 
80  /// Discard all captured errors. They will not be re-posted.
81  TF_API void ClearErrors();
82 
83  /// Discard all captured warnings. They will not be re-posted.
84  TF_API void ClearWarnings();
85 
86  /// Discard all captured status messages. They will not be re-posted.
87  TF_API void ClearStatuses();
88 
89  /// Erase all captured diagnostics for which \p pred returns true,
90  /// preserving the relative order of the remaining diagnostics. Return the
91  /// number of diagnostics erased. Erased diagnostics will not be re-posted.
92  /// The passed \p pred may accept any subset of \c TfError, \c TfWarning,
93  /// and \c TfStatus. Diagnostics whose type \p pred cannot accept are left
94  /// untouched. The \p pred may also accept \c TfDiagnosticBase const & to
95  /// match against all types uniformly. This is safe to call during \c
96  /// ForEach iteration.
97  template <class Predicate>
98  size_t EraseMatching(Predicate &&pred) {
100  size_t erased = 0;
101  auto it = _container.GetIterator();
102  while (it.Next([&](auto const &d) {
103  if (auto r = TfTryInvoke<bool>(std::forward<Predicate>(pred), d)) {
104  if (*r) {
105  ++erased;
106  return; // erase
107  }
108  }
109  result.Append(d); // keep
110  }));
111  if (erased) {
112  _container = std::move(result);
113  _OnContentsChanged();
114  }
115  return erased;
116  }
117 
118  /// Return true if no diagnostics have been captured.
119  TF_API bool IsClean() const;
120 
121  /// Return true if any errors have been captured.
122  TF_API bool HasErrors() const;
123 
124  /// Return true if any warnings have been captured.
125  TF_API bool HasWarnings() const;
126 
127  /// Return true if any status messages have been captured.
128  TF_API bool HasStatuses() const;
129 
130  /// Invoke \p pred on the captured diagnostics in order, returning true as
131  /// soon as \p pred returns true for any of them. \p pred may accept any
132  /// subset of \c TfError, \c TfWarning, and \c TfStatus, or \c
133  /// TfDiagnosticBase const & to test all types uniformly. Diagnostics whose
134  /// type \p pred cannot accept are considered not matching.
135  template <class Predicate>
136  bool HasAnyMatching(Predicate &&pred) const {
137  auto it = _container.GetIterator();
138  while (auto r = it.Next(std::forward<Predicate>(pred))) {
139  if (*r) {
140  return true;
141  }
142  }
143  return false;
144  }
145 
146  /// Invoke \p pred on the captured diagnostics in order, returning false as
147  /// soon as \p pred returns false for any of them. \p pred may accept any
148  /// subset of \c TfError, \c TfWarning, and \c TfStatus, or \c
149  /// TfDiagnosticBase const & to test all types uniformly. The diagnostic
150  /// types that \p pred accepts defines the domain that HasAllMatching()
151  /// operates on. For example, a call like:
152  /// \code
153  /// bool hasOnlyDeprecationWarnings =
154  /// trap.HasAllMatching([](TfWarning const &w) {
155  /// return TfStringContains(w.GetCommentary(), "deprecated");
156  /// });
157  /// \endcode
158  /// Returns true if all the trapped warnings contain "deprecated" in their
159  /// commentaries \em regardless of whether or not the trap contains errors
160  /// or status messages. Pass a predicate that accepts all diagnostic types
161  /// to consider their presence not-matching:
162  /// \code
163  /// bool hasOnlyWarningsOfDeprecation =
164  /// trap.HasAllMatching(TfOverloads {
165  /// [](TfWarning const &w) {
166  /// return TfStringContains(w.GetCommentary(), "deprecated");
167  /// },
168  /// [](TfDiagnosticBase const &) {
169  /// return false;
170  /// }
171  /// });
172  /// \endcode
173  ///
174  /// Return true vacuously if \p pred is not invoked.
175  template <class Predicate>
176  bool HasAllMatching(Predicate &&pred) const {
177  auto it = _container.GetIterator();
178  while (auto r = it.Next(std::forward<Predicate>(pred))) {
179  if (!*r) {
180  return false;
181  }
182  }
183  return true;
184  }
185 
186  /// Return the number of captured diagnostics for which \p pred returns
187  /// true. \p pred may accept any subset of \c TfError, \c TfWarning, and \c
188  /// TfStatus, or \c TfDiagnosticBase const& to test all types uniformly.
189  /// Diagnostics whose type \p pred cannot accept are not counted.
190  template <class Predicate>
191  size_t CountMatching(Predicate &&pred) const {
192  size_t count = 0;
193  auto it = _container.GetIterator();
194  while (auto r = it.Next(std::forward<Predicate>(pred))) {
195  if (*r) {
196  ++count;
197  }
198  }
199  return count;
200  }
201 
202  /// Return the captured errors.
203  TF_API std::vector<TfError> const& GetErrors() const;
204 
205  /// Return the captured warnings.
206  TF_API std::vector<TfWarning> const& GetWarnings() const;
207 
208  /// Return the captured status messages.
209  TF_API std::vector<TfStatus> const& GetStatuses() const;
210 
211  /// Invoke \p fn for each captured diagnostic in the order they were
212  /// received. \p fn may be a callable taking \c TfDiagnosticBase const & to
213  /// handle all diagnostic types uniformly, or a \c TfOverloads visitor with
214  /// overloads for any subset of \c TfError, \c TfWarning, and \c TfStatus -
215  /// diagnostics whose type \p fn cannot accept are silently skipped. A
216  /// snapshot of the current diagnostics is taken before iteration so it is
217  /// safe to call mutators like \c EraseMatching or \c Clear() from within \p
218  /// fn.
219  template <class Fn>
220  void ForEach(Fn &&fn) const {
221  Tf_DiagnosticContainer copy(_container);
222  auto it = copy.GetIterator();
223  while (it.Next(std::forward<Fn>(fn))) {}
224  }
225 
226  /// Move all accumulated diagnostics into a \c TfDiagnosticTransport,
227  /// leaving this trap active but empty. The transport can be used to
228  /// re-post the diagnostics on another thread. This is analogous to \c
229  /// TfErrorMark::Transport().
230  TF_API TfDiagnosticTransport Transport();
231 
232 private:
233  friend class TfDiagnosticMgr;
234 
235  TF_API void _OnContentsChanged() const;
236 
237  Tf_DiagnosticContainer _container;
238  bool _active = false;
239 };
240 
242 
243 #endif // PXR_BASE_TF_DIAGNOSTIC_TRAP_H
#define TF_API
Definition: api.h:23
TF_API void Clear()
Discard all captured diagnostics. They will not be re-posted.
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
TF_API TfDiagnosticTrap()
**But if you need a result
Definition: thread.h:622
bool HasAllMatching(Predicate &&pred) const
TF_API void ClearWarnings()
Discard all captured warnings. They will not be re-posted.
Iterator GetIterator() const
size_t CountMatching(Predicate &&pred) const
TF_API void Dismiss()
size_t EraseMatching(Predicate &&pred)
TF_API void ClearErrors()
Discard all captured errors. They will not be re-posted.
TF_API ~TfDiagnosticTrap()
void ForEach(Fn &&fn) const
TF_API void ClearStatuses()
Discard all captured status messages. They will not be re-posted.
TfDiagnosticTrap & operator=(const TfDiagnosticTrap &)=delete
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
bool HasAnyMatching(Predicate &&pred) const
if(num_boxed_items<=0)
Definition: UT_RTreeImpl.h:697
void Append(TfError const &e)
GLboolean r
Definition: glcorearb.h:1222
GLint GLsizei count
Definition: glcorearb.h:405