clang API Documentation
00001 //===- VerifyDiagnosticConsumer.h - Verifying Diagnostic Client -*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 00010 #ifndef LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H 00011 #define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H 00012 00013 #include "clang/Basic/Diagnostic.h" 00014 #include "clang/Lex/Preprocessor.h" 00015 #include "llvm/ADT/DenseMap.h" 00016 #include "llvm/ADT/PointerIntPair.h" 00017 #include "llvm/ADT/STLExtras.h" 00018 #include <climits> 00019 #include <memory> 00020 00021 namespace clang { 00022 00023 class DiagnosticsEngine; 00024 class TextDiagnosticBuffer; 00025 class FileEntry; 00026 00027 /// VerifyDiagnosticConsumer - Create a diagnostic client which will use 00028 /// markers in the input source to check that all the emitted diagnostics match 00029 /// those expected. 00030 /// 00031 /// USING THE DIAGNOSTIC CHECKER: 00032 /// 00033 /// Indicating that a line expects an error or a warning is simple. Put a 00034 /// comment on the line that has the diagnostic, use: 00035 /// 00036 /// \code 00037 /// expected-{error,warning,remark,note} 00038 /// \endcode 00039 /// 00040 /// to tag if it's an expected error, remark or warning, and place the expected 00041 /// text between {{ and }} markers. The full text doesn't have to be included, 00042 /// only enough to ensure that the correct diagnostic was emitted. 00043 /// 00044 /// Here's an example: 00045 /// 00046 /// \code 00047 /// int A = B; // expected-error {{use of undeclared identifier 'B'}} 00048 /// \endcode 00049 /// 00050 /// You can place as many diagnostics on one line as you wish. To make the code 00051 /// more readable, you can use slash-newline to separate out the diagnostics. 00052 /// 00053 /// Alternatively, it is possible to specify the line on which the diagnostic 00054 /// should appear by appending "@<line>" to "expected-<type>", for example: 00055 /// 00056 /// \code 00057 /// #warning some text 00058 /// // expected-warning@10 {{some text}} 00059 /// \endcode 00060 /// 00061 /// The line number may be absolute (as above), or relative to the current 00062 /// line by prefixing the number with either '+' or '-'. 00063 /// 00064 /// If the diagnostic is generated in a separate file, for example in a shared 00065 /// header file, it may be beneficial to be able to declare the file in which 00066 /// the diagnostic will appear, rather than placing the expected-* directive in 00067 /// the actual file itself. This can be done using the following syntax: 00068 /// 00069 /// \code 00070 /// // expected-error@path/include.h:15 {{error message}} 00071 /// \endcode 00072 /// 00073 /// The path can be absolute or relative and the same search paths will be used 00074 /// as for #include directives. The line number in an external file may be 00075 /// substituted with '*' meaning that any line number will match (useful where 00076 /// the included file is, for example, a system header where the actual line 00077 /// number may change and is not critical). 00078 /// 00079 /// The simple syntax above allows each specification to match exactly one 00080 /// error. You can use the extended syntax to customize this. The extended 00081 /// syntax is "expected-<type> <n> {{diag text}}", where <type> is one of 00082 /// "error", "warning" or "note", and <n> is a positive integer. This allows 00083 /// the diagnostic to appear as many times as specified. Example: 00084 /// 00085 /// \code 00086 /// void f(); // expected-note 2 {{previous declaration is here}} 00087 /// \endcode 00088 /// 00089 /// Where the diagnostic is expected to occur a minimum number of times, this 00090 /// can be specified by appending a '+' to the number. Example: 00091 /// 00092 /// \code 00093 /// void f(); // expected-note 0+ {{previous declaration is here}} 00094 /// void g(); // expected-note 1+ {{previous declaration is here}} 00095 /// \endcode 00096 /// 00097 /// In the first example, the diagnostic becomes optional, i.e. it will be 00098 /// swallowed if it occurs, but will not generate an error if it does not 00099 /// occur. In the second example, the diagnostic must occur at least once. 00100 /// As a short-hand, "one or more" can be specified simply by '+'. Example: 00101 /// 00102 /// \code 00103 /// void g(); // expected-note + {{previous declaration is here}} 00104 /// \endcode 00105 /// 00106 /// A range can also be specified by "<n>-<m>". Example: 00107 /// 00108 /// \code 00109 /// void f(); // expected-note 0-1 {{previous declaration is here}} 00110 /// \endcode 00111 /// 00112 /// In this example, the diagnostic may appear only once, if at all. 00113 /// 00114 /// Regex matching mode may be selected by appending '-re' to type and 00115 /// including regexes wrapped in double curly braces in the directive, such as: 00116 /// 00117 /// \code 00118 /// expected-error-re {{format specifies type 'wchar_t **' (aka '{{.+}}')}} 00119 /// \endcode 00120 /// 00121 /// Examples matching error: "variable has incomplete type 'struct s'" 00122 /// 00123 /// \code 00124 /// // expected-error {{variable has incomplete type 'struct s'}} 00125 /// // expected-error {{variable has incomplete type}} 00126 /// 00127 /// // expected-error-re {{variable has type 'struct {{.}}'}} 00128 /// // expected-error-re {{variable has type 'struct {{.*}}'}} 00129 /// // expected-error-re {{variable has type 'struct {{(.*)}}'}} 00130 /// // expected-error-re {{variable has type 'struct{{[[:space:]](.*)}}'}} 00131 /// \endcode 00132 /// 00133 /// VerifyDiagnosticConsumer expects at least one expected-* directive to 00134 /// be found inside the source code. If no diagnostics are expected the 00135 /// following directive can be used to indicate this: 00136 /// 00137 /// \code 00138 /// // expected-no-diagnostics 00139 /// \endcode 00140 /// 00141 class VerifyDiagnosticConsumer: public DiagnosticConsumer, 00142 public CommentHandler { 00143 public: 00144 /// Directive - Abstract class representing a parsed verify directive. 00145 /// 00146 class Directive { 00147 public: 00148 static std::unique_ptr<Directive> create(bool RegexKind, 00149 SourceLocation DirectiveLoc, 00150 SourceLocation DiagnosticLoc, 00151 bool MatchAnyLine, StringRef Text, 00152 unsigned Min, unsigned Max); 00153 00154 public: 00155 /// Constant representing n or more matches. 00156 static const unsigned MaxCount = UINT_MAX; 00157 00158 SourceLocation DirectiveLoc; 00159 SourceLocation DiagnosticLoc; 00160 const std::string Text; 00161 unsigned Min, Max; 00162 bool MatchAnyLine; 00163 00164 virtual ~Directive() { } 00165 00166 // Returns true if directive text is valid. 00167 // Otherwise returns false and populates E. 00168 virtual bool isValid(std::string &Error) = 0; 00169 00170 // Returns true on match. 00171 virtual bool match(StringRef S) = 0; 00172 00173 protected: 00174 Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, 00175 bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max) 00176 : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), 00177 Text(Text), Min(Min), Max(Max), MatchAnyLine(MatchAnyLine) { 00178 assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!"); 00179 assert(!DiagnosticLoc.isInvalid() && "DiagnosticLoc is invalid!"); 00180 } 00181 00182 private: 00183 Directive(const Directive &) LLVM_DELETED_FUNCTION; 00184 void operator=(const Directive &) LLVM_DELETED_FUNCTION; 00185 }; 00186 00187 typedef std::vector<std::unique_ptr<Directive>> DirectiveList; 00188 00189 /// ExpectedData - owns directive objects and deletes on destructor. 00190 /// 00191 struct ExpectedData { 00192 DirectiveList Errors; 00193 DirectiveList Warnings; 00194 DirectiveList Remarks; 00195 DirectiveList Notes; 00196 00197 void Reset() { 00198 Errors.clear(); 00199 Warnings.clear(); 00200 Remarks.clear(); 00201 Notes.clear(); 00202 } 00203 }; 00204 00205 enum DirectiveStatus { 00206 HasNoDirectives, 00207 HasNoDirectivesReported, 00208 HasExpectedNoDiagnostics, 00209 HasOtherExpectedDirectives 00210 }; 00211 00212 private: 00213 DiagnosticsEngine &Diags; 00214 DiagnosticConsumer *PrimaryClient; 00215 std::unique_ptr<DiagnosticConsumer> PrimaryClientOwner; 00216 std::unique_ptr<TextDiagnosticBuffer> Buffer; 00217 const Preprocessor *CurrentPreprocessor; 00218 const LangOptions *LangOpts; 00219 SourceManager *SrcManager; 00220 unsigned ActiveSourceFiles; 00221 DirectiveStatus Status; 00222 ExpectedData ED; 00223 00224 void CheckDiagnostics(); 00225 void setSourceManager(SourceManager &SM) { 00226 assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!"); 00227 SrcManager = &SM; 00228 } 00229 00230 // These facilities are used for validation in debug builds. 00231 class UnparsedFileStatus { 00232 llvm::PointerIntPair<const FileEntry *, 1, bool> Data; 00233 public: 00234 UnparsedFileStatus(const FileEntry *File, bool FoundDirectives) 00235 : Data(File, FoundDirectives) {} 00236 const FileEntry *getFile() const { return Data.getPointer(); } 00237 bool foundDirectives() const { return Data.getInt(); } 00238 }; 00239 typedef llvm::DenseMap<FileID, const FileEntry *> ParsedFilesMap; 00240 typedef llvm::DenseMap<FileID, UnparsedFileStatus> UnparsedFilesMap; 00241 ParsedFilesMap ParsedFiles; 00242 UnparsedFilesMap UnparsedFiles; 00243 00244 public: 00245 /// Create a new verifying diagnostic client, which will issue errors to 00246 /// the currently-attached diagnostic client when a diagnostic does not match 00247 /// what is expected (as indicated in the source file). 00248 VerifyDiagnosticConsumer(DiagnosticsEngine &Diags); 00249 ~VerifyDiagnosticConsumer(); 00250 00251 void BeginSourceFile(const LangOptions &LangOpts, 00252 const Preprocessor *PP) override; 00253 00254 void EndSourceFile() override; 00255 00256 enum ParsedStatus { 00257 /// File has been processed via HandleComment. 00258 IsParsed, 00259 00260 /// File has diagnostics and may have directives. 00261 IsUnparsed, 00262 00263 /// File has diagnostics but guaranteed no directives. 00264 IsUnparsedNoDirectives 00265 }; 00266 00267 /// \brief Update lists of parsed and unparsed files. 00268 void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS); 00269 00270 bool HandleComment(Preprocessor &PP, SourceRange Comment) override; 00271 00272 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 00273 const Diagnostic &Info) override; 00274 }; 00275 00276 } // end namspace clang 00277 00278 #endif