clang API Documentation

VerifyDiagnosticConsumer.h
Go to the documentation of this file.
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