1//===- VerifyDiagnosticConsumer.h - Verifying Diagnostic Client -*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H
11#define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H
12
13#include "clang/Basic/Diagnostic.h"
14#include "clang/Lex/Preprocessor.h"
15#include "llvm/ADT/DenseMap.h"
16#include "llvm/ADT/PointerIntPair.h"
17#include "llvm/ADT/STLExtras.h"
18#include <climits>
19#include <memory>
20
21namespace clang {
22
23class DiagnosticsEngine;
24class TextDiagnosticBuffer;
25class FileEntry;
26
27/// VerifyDiagnosticConsumer - Create a diagnostic client which will use
28/// markers in the input source to check that all the emitted diagnostics match
29/// those expected.
30///
31/// USING THE DIAGNOSTIC CHECKER:
32///
33/// Indicating that a line expects an error or a warning is simple. Put a
34/// comment on the line that has the diagnostic, use:
35///
36/// \code
37///   expected-{error,warning,remark,note}
38/// \endcode
39///
40/// to tag if it's an expected error, remark or warning, and place the expected
41/// text between {{ and }} markers. The full text doesn't have to be included,
42/// only enough to ensure that the correct diagnostic was emitted.
43///
44/// Here's an example:
45///
46/// \code
47///   int A = B; // expected-error {{use of undeclared identifier 'B'}}
48/// \endcode
49///
50/// You can place as many diagnostics on one line as you wish. To make the code
51/// more readable, you can use slash-newline to separate out the diagnostics.
52///
53/// Alternatively, it is possible to specify the line on which the diagnostic
54/// should appear by appending "@<line>" to "expected-<type>", for example:
55///
56/// \code
57///   #warning some text
58///   // expected-warning@10 {{some text}}
59/// \endcode
60///
61/// The line number may be absolute (as above), or relative to the current
62/// line by prefixing the number with either '+' or '-'.
63///
64/// If the diagnostic is generated in a separate file, for example in a shared
65/// header file, it may be beneficial to be able to declare the file in which
66/// the diagnostic will appear, rather than placing the expected-* directive in
67/// the actual file itself.  This can be done using the following syntax:
68///
69/// \code
70///   // expected-error@path/include.h:15 {{error message}}
71/// \endcode
72///
73/// The path can be absolute or relative and the same search paths will be used
74/// as for #include directives.  The line number in an external file may be
75/// substituted with '*' meaning that any line number will match (useful where
76/// the included file is, for example, a system header where the actual line
77/// number may change and is not critical).
78///
79/// The simple syntax above allows each specification to match exactly one
80/// error.  You can use the extended syntax to customize this. The extended
81/// syntax is "expected-<type> <n> {{diag text}}", where \<type> is one of
82/// "error", "warning" or "note", and \<n> is a positive integer. This allows
83/// the diagnostic to appear as many times as specified. Example:
84///
85/// \code
86///   void f(); // expected-note 2 {{previous declaration is here}}
87/// \endcode
88///
89/// Where the diagnostic is expected to occur a minimum number of times, this
90/// can be specified by appending a '+' to the number. Example:
91///
92/// \code
93///   void f(); // expected-note 0+ {{previous declaration is here}}
94///   void g(); // expected-note 1+ {{previous declaration is here}}
95/// \endcode
96///
97/// In the first example, the diagnostic becomes optional, i.e. it will be
98/// swallowed if it occurs, but will not generate an error if it does not
99/// occur.  In the second example, the diagnostic must occur at least once.
100/// As a short-hand, "one or more" can be specified simply by '+'. Example:
101///
102/// \code
103///   void g(); // expected-note + {{previous declaration is here}}
104/// \endcode
105///
106/// A range can also be specified by "<n>-<m>".  Example:
107///
108/// \code
109///   void f(); // expected-note 0-1 {{previous declaration is here}}
110/// \endcode
111///
112/// In this example, the diagnostic may appear only once, if at all.
113///
114/// Regex matching mode may be selected by appending '-re' to type and
115/// including regexes wrapped in double curly braces in the directive, such as:
116///
117/// \code
118///   expected-error-re {{format specifies type 'wchar_t **' (aka '{{.+}}')}}
119/// \endcode
120///
121/// Examples matching error: "variable has incomplete type 'struct s'"
122///
123/// \code
124///   // expected-error {{variable has incomplete type 'struct s'}}
125///   // expected-error {{variable has incomplete type}}
126///
127///   // expected-error-re {{variable has type 'struct {{.}}'}}
128///   // expected-error-re {{variable has type 'struct {{.*}}'}}
129///   // expected-error-re {{variable has type 'struct {{(.*)}}'}}
130///   // expected-error-re {{variable has type 'struct{{[[:space:]](.*)}}'}}
131/// \endcode
132///
133/// VerifyDiagnosticConsumer expects at least one expected-* directive to
134/// be found inside the source code.  If no diagnostics are expected the
135/// following directive can be used to indicate this:
136///
137/// \code
138///   // expected-no-diagnostics
139/// \endcode
140///
141class VerifyDiagnosticConsumer: public DiagnosticConsumer,
142                                public CommentHandler {
143public:
144  /// Directive - Abstract class representing a parsed verify directive.
145  ///
146  class Directive {
147  public:
148    static std::unique_ptr<Directive> create(bool RegexKind,
149                                             SourceLocation DirectiveLoc,
150                                             SourceLocation DiagnosticLoc,
151                                             bool MatchAnyLine, StringRef Text,
152                                             unsigned Min, unsigned Max);
153
154  public:
155    /// Constant representing n or more matches.
156    static const unsigned MaxCount = UINT_MAX;
157
158    SourceLocation DirectiveLoc;
159    SourceLocation DiagnosticLoc;
160    const std::string Text;
161    unsigned Min, Max;
162    bool MatchAnyLine;
163
164    virtual ~Directive() { }
165
166    // Returns true if directive text is valid.
167    // Otherwise returns false and populates E.
168    virtual bool isValid(std::string &Error) = 0;
169
170    // Returns true on match.
171    virtual bool match(StringRef S) = 0;
172
173  protected:
174    Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
175              bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)
176      : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc),
177        Text(Text), Min(Min), Max(Max), MatchAnyLine(MatchAnyLine) {
178    assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!");
179    assert(!DiagnosticLoc.isInvalid() && "DiagnosticLoc is invalid!");
180    }
181
182  private:
183    Directive(const Directive &) = delete;
184    void operator=(const Directive &) = delete;
185  };
186
187  typedef std::vector<std::unique_ptr<Directive>> DirectiveList;
188
189  /// ExpectedData - owns directive objects and deletes on destructor.
190  ///
191  struct ExpectedData {
192    DirectiveList Errors;
193    DirectiveList Warnings;
194    DirectiveList Remarks;
195    DirectiveList Notes;
196
197    void Reset() {
198      Errors.clear();
199      Warnings.clear();
200      Remarks.clear();
201      Notes.clear();
202    }
203  };
204
205  enum DirectiveStatus {
206    HasNoDirectives,
207    HasNoDirectivesReported,
208    HasExpectedNoDiagnostics,
209    HasOtherExpectedDirectives
210  };
211
212private:
213  DiagnosticsEngine &Diags;
214  DiagnosticConsumer *PrimaryClient;
215  std::unique_ptr<DiagnosticConsumer> PrimaryClientOwner;
216  std::unique_ptr<TextDiagnosticBuffer> Buffer;
217  const Preprocessor *CurrentPreprocessor;
218  const LangOptions *LangOpts;
219  SourceManager *SrcManager;
220  unsigned ActiveSourceFiles;
221  DirectiveStatus Status;
222  ExpectedData ED;
223
224  void CheckDiagnostics();
225  void setSourceManager(SourceManager &SM) {
226    assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!");
227    SrcManager = &SM;
228  }
229
230  // These facilities are used for validation in debug builds.
231  class UnparsedFileStatus {
232    llvm::PointerIntPair<const FileEntry *, 1, bool> Data;
233  public:
234    UnparsedFileStatus(const FileEntry *File, bool FoundDirectives)
235      : Data(File, FoundDirectives) {}
236    const FileEntry *getFile() const { return Data.getPointer(); }
237    bool foundDirectives() const { return Data.getInt(); }
238  };
239  typedef llvm::DenseMap<FileID, const FileEntry *> ParsedFilesMap;
240  typedef llvm::DenseMap<FileID, UnparsedFileStatus> UnparsedFilesMap;
241  ParsedFilesMap ParsedFiles;
242  UnparsedFilesMap UnparsedFiles;
243
244public:
245  /// Create a new verifying diagnostic client, which will issue errors to
246  /// the currently-attached diagnostic client when a diagnostic does not match
247  /// what is expected (as indicated in the source file).
248  VerifyDiagnosticConsumer(DiagnosticsEngine &Diags);
249  ~VerifyDiagnosticConsumer() override;
250
251  void BeginSourceFile(const LangOptions &LangOpts,
252                       const Preprocessor *PP) override;
253
254  void EndSourceFile() override;
255
256  enum ParsedStatus {
257    /// File has been processed via HandleComment.
258    IsParsed,
259
260    /// File has diagnostics and may have directives.
261    IsUnparsed,
262
263    /// File has diagnostics but guaranteed no directives.
264    IsUnparsedNoDirectives
265  };
266
267  /// \brief Update lists of parsed and unparsed files.
268  void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS);
269
270  bool HandleComment(Preprocessor &PP, SourceRange Comment) override;
271
272  void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
273                        const Diagnostic &Info) override;
274};
275
276} // end namspace clang
277
278#endif
279