1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_BASE_TF_DIAGNOSTIC_BASE_H
25 #define PXR_BASE_TF_DIAGNOSTIC_BASE_H
26 
27 /// \file tf/diagnosticBase.h
28 
29 #include "pxr/pxr.h"
30 #include "pxr/base/tf/callContext.h"
31 #include "pxr/base/tf/enum.h"
32 #include "pxr/base/tf/refBase.h"
33 #include "pxr/base/tf/stringUtils.h"
34 #include "pxr/base/tf/weakPtr.h"
35 
36 #include "pxr/base/arch/inttypes.h"
37 #include "pxr/base/arch/attributes.h"
38 #include "pxr/base/arch/function.h"
39 
40 #include <boost/any.hpp>
41 #include <cstdarg>
42 #include <string>
43 
44 PXR_NAMESPACE_OPEN_SCOPE
45 
46 typedef boost::any TfDiagnosticInfo;
47 
48 class TfDiagnosticMgr;
49 
50 /// \class TfDiagnosticBase
51 /// \ingroup group_tf_TfError
52 ///
53 /// Represents the base class of an object representing a diagnostic message.
54 ///
55 /// This forms the base class for specific types associated with errors,
56 /// warnings and status messages. It associates a diagnostic code (which is an
57 /// enum value) with the message. It can also hold on to arbitrary information
58 /// associated with the message in a TfDiagnosticInfo.
59 ///
60 /// See \ref page_tf_TfError in the C++ API reference for a detailed example.
61 /// For a description of how to post an error, warning or a status message see
62 /// \c TF_ERROR(), \c TF_WARN and \c TF_STATUS also in the C++ API reference.
63 ///
64 class TfDiagnosticBase {
65 public:
66 
67     /// Return the call context where the message was issued.
GetContext()68     const TfCallContext &GetContext() const {
69         return _context;
70     }
71 
72     /// Return the source file name that the diagnostic message was posted from.
GetSourceFileName()73     std::string GetSourceFileName() const {
74         return _context.GetFile();
75     }
76 
77     /// Return the source line number that the diagnostic message was posted
78     /// from.
GetSourceLineNumber()79     size_t GetSourceLineNumber() const {
80         return _context.GetLine();
81     }
82 
83     /// Return the commentary string describing this diagnostic message.
GetCommentary()84     std::string const &GetCommentary() const {
85         return _commentary;
86     }
87 
88     /// Return the source function that the diagnostic message was posted from.
GetSourceFunction()89     std::string GetSourceFunction() const {
90         return ArchGetPrettierFunctionName(_context.GetFunction(),
91                                            _context.GetPrettyFunction());
92     }
93 
94     /// Add to the commentary string describing this diagnostic message.
95     ///
96     /// Note: each string added to the commentary is separated from
97     /// the previous one with a newline. This means that
98     /// you the string \c s should \e not end with a newline. Thus,
99     /// \code
100     ///    cout << e.GetCommentary() << "\n";
101     /// \endcode
102     /// always prints the entire commentary string as a newline
103     /// separated sequence of messages.
AugmentCommentary(const std::string & s)104     void AugmentCommentary(const std::string& s) {
105         if (_commentary.empty())
106             _commentary = s;
107         else {
108             _commentary += "\n";
109             _commentary += s;
110         }
111     }
112 
113     /// Return the diagnostic code posted.
GetDiagnosticCode()114     TfEnum GetDiagnosticCode() const {
115         return _code;
116     }
117 
118 
119     /// Return the diagnostic code posted as a string.
120     ///
121     /// If the enum value posted with the message has been registered
122     /// with \c TF_ADD_ENUM_NAME(), then \c GetDiagnosticCodeAsString() will
123     /// return the symbolic name of the enum.
124     ///
125     /// If the enum has not been registered, then code of the form
126     /// \code
127     ///     TF_ERROR(PUCE).Post("is an ugly color");
128     /// \endcode
129     /// will still result in \c GetDiagnosticCodeAsString() returning the string
130     /// "PUCE"; however, code of the form
131     /// \code
132     ///     MyErrorCode c = PUCE;
133     ///     TF_ERROR(c).Post("is still ugly");
134     /// \endcode
135     /// will result in \c GetDiagnosticCodeAsString() returning the
136     /// (uninformative) string "c".
GetDiagnosticCodeAsString()137     const std::string& GetDiagnosticCodeAsString() const {
138         return _codeString;
139     }
140 
141     /// Return a (possibly NULL) const pointer to the info object associated
142     /// with this message.
143     ///
144     /// If this message was posted without supplying an \c info argument to
145     /// Post(), e.g.
146     /// \code
147     ///    TF_ERROR(SOME_CODE).Post("something went wrong");
148     /// \endcode
149     ///
150     /// then \c GetInfo() returns NULL.  Otherwise, when info is supplied,
151     /// e.g.
152     /// \code
153     ///    T myInfo = ...
154     ///    TF_ERROR(SOME_CODE).Post("something went wrong")->SetInfo(myInfo);
155     /// \endcode
156     ///
157     /// then a const pointer to a copy of myInfo in the above example is
158     /// returned by GetInfo<T>().  If the type T doesn't match the held type
159     /// then GetInfo() returns NULL.
160     template <typename T>
GetInfo()161     const T* GetInfo() const {
162         return boost::any_cast<T>(&_info);
163     }
164 
165     /// Set the info object associated with this diagnostic message.
166     /// \see GetInfo()
SetInfo(TfDiagnosticInfo any)167     void SetInfo(TfDiagnosticInfo any) {
168         _info = any;
169     }
170 
171     /// Return true if the message was posted via \c PostQuietly().
172     ///
173     /// Notices sent from \c PostQuietly() are indicating that an immediate
174     /// printout of the error is not desirable, because someone higher up on
175     /// the stack may actually handle this error. This is rare, but it does
176     /// happen on occasion.
GetQuiet()177     bool GetQuiet() const {
178         return _quiet;
179     }
180 
181     /// Return the commentary string.
182     std::string GetPrettyPrintString() const;
183 
184     /// Return true if this diagnostic's code is a fatal code.
185     bool IsFatal() const;
186 
187     /// Return true if this diagnostic's code is either a fatal or nonfatal
188     /// coding error.
189     bool IsCodingError() const;
190 
191     /// Construct an instance.
192     TfDiagnosticBase(TfEnum code, char const *codeString,
193                      TfCallContext const &context,
194                      const std::string& commentary,
195                      TfDiagnosticInfo info, bool quiet);
196 
197 protected:
198     TfCallContext _context;
199 
200     std::string _commentary;
201     TfEnum _code;
202     std::string _codeString;
203     TfDiagnosticInfo _info;
204     size_t _serial = 0;
205     bool _quiet = false;
206 
207     friend class TfDiagnosticMgr;
208     friend class TfErrorTransport;
209     friend class TfErrorMark;
210 };
211 
212 PXR_NAMESPACE_CLOSE_SCOPE
213 
214 #endif // PXR_BASE_TF_DIAGNOSTIC_BASE_H
215