Coverage Report

Created: 2019-02-20 07:29

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