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/FileManager.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
26namespace clang {
27
28class FileEntry;
29class LangOptions;
30class SourceManager;
31class 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. See clang/docs/InternalsManual.rst for details about how to
36/// write tests to verify diagnostics.
37///
38class VerifyDiagnosticConsumer: public DiagnosticConsumer,
39 public CommentHandler {
40public:
41 /// Directive - Abstract class representing a parsed verify directive.
42 ///
43 class Directive {
44 public:
45 static std::unique_ptr<Directive>
46 create(bool RegexKind, SourceLocation DirectiveLoc,
47 SourceLocation DiagnosticLoc, bool MatchAnyFileAndLine,
48 bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max);
49
50 public:
51 /// Constant representing n or more matches.
52 static const unsigned MaxCount = std::numeric_limits<unsigned>::max();
53
54 SourceLocation DirectiveLoc;
55 SourceLocation DiagnosticLoc;
56 const std::string Text;
57 unsigned Min, Max;
58 bool MatchAnyLine;
59 bool MatchAnyFileAndLine; // `MatchAnyFileAndLine` implies `MatchAnyLine`.
60
61 Directive(const Directive &) = delete;
62 Directive &operator=(const Directive &) = delete;
63 virtual ~Directive() = default;
64
65 // Returns true if directive text is valid.
66 // Otherwise returns false and populates E.
67 virtual bool isValid(std::string &Error) = 0;
68
69 // Returns true on match.
70 virtual bool match(StringRef S) = 0;
71
72 protected:
73 Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
74 bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
75 unsigned Min, unsigned Max)
76 : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), Text(Text),
77 Min(Min), Max(Max), MatchAnyLine(MatchAnyLine || MatchAnyFileAndLine),
78 MatchAnyFileAndLine(MatchAnyFileAndLine) {
79 assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!");
80 assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) &&
81 "DiagnosticLoc is invalid!");
82 }
83 };
84
85 using DirectiveList = std::vector<std::unique_ptr<Directive>>;
86
87 /// ExpectedData - owns directive objects and deletes on destructor.
88 struct ExpectedData {
89 DirectiveList Errors;
90 DirectiveList Warnings;
91 DirectiveList Remarks;
92 DirectiveList Notes;
93
94 void Reset() {
95 Errors.clear();
96 Warnings.clear();
97 Remarks.clear();
98 Notes.clear();
99 }
100 };
101
102 enum DirectiveStatus {
103 HasNoDirectives,
104 HasNoDirectivesReported,
105 HasExpectedNoDiagnostics,
106 HasOtherExpectedDirectives
107 };
108
109 class MarkerTracker;
110
111private:
112 DiagnosticsEngine &Diags;
113 DiagnosticConsumer *PrimaryClient;
114 std::unique_ptr<DiagnosticConsumer> PrimaryClientOwner;
115 std::unique_ptr<TextDiagnosticBuffer> Buffer;
116 std::unique_ptr<MarkerTracker> Markers;
117 const Preprocessor *CurrentPreprocessor = nullptr;
118 const LangOptions *LangOpts = nullptr;
119 SourceManager *SrcManager = nullptr;
120 unsigned ActiveSourceFiles = 0;
121 DirectiveStatus Status;
122 ExpectedData ED;
123
124 void CheckDiagnostics();
125
126 void setSourceManager(SourceManager &SM) {
127 assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!");
128 SrcManager = &SM;
129 }
130
131 // These facilities are used for validation in debug builds.
132 class UnparsedFileStatus {
133 OptionalFileEntryRef File;
134 bool FoundDirectives;
135
136 public:
137 UnparsedFileStatus(OptionalFileEntryRef File, bool FoundDirectives)
138 : File(File), FoundDirectives(FoundDirectives) {}
139
140 OptionalFileEntryRef getFile() const { return File; }
141 bool foundDirectives() const { return FoundDirectives; }
142 };
143
144 using ParsedFilesMap = llvm::DenseMap<FileID, const FileEntry *>;
145 using UnparsedFilesMap = llvm::DenseMap<FileID, UnparsedFileStatus>;
146
147 ParsedFilesMap ParsedFiles;
148 UnparsedFilesMap UnparsedFiles;
149
150public:
151 /// Create a new verifying diagnostic client, which will issue errors to
152 /// the currently-attached diagnostic client when a diagnostic does not match
153 /// what is expected (as indicated in the source file).
154 VerifyDiagnosticConsumer(DiagnosticsEngine &Diags);
155 ~VerifyDiagnosticConsumer() override;
156
157 void BeginSourceFile(const LangOptions &LangOpts,
158 const Preprocessor *PP) override;
159
160 void EndSourceFile() override;
161
162 enum ParsedStatus {
163 /// File has been processed via HandleComment.
164 IsParsed,
165
166 /// File has diagnostics and may have directives.
167 IsUnparsed,
168
169 /// File has diagnostics but guaranteed no directives.
170 IsUnparsedNoDirectives
171 };
172
173 /// Update lists of parsed and unparsed files.
174 void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS);
175
176 bool HandleComment(Preprocessor &PP, SourceRange Comment) override;
177
178 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
179 const Diagnostic &Info) override;
180};
181
182} // namespace clang
183
184#endif // LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H
185

source code of clang/include/clang/Frontend/VerifyDiagnosticConsumer.h