Coverage Report

Created: 2019-07-24 05:18

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