Coverage Report

Created: 2018-11-16 02:38

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