annotate clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @ 176:de4ac79aef9d

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 17:13:11 +0900
parents 0572611fdcc8
children 2e18cbf3894f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===- VerifyDiagnosticConsumer.cpp - Verifying Diagnostic Client ---------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // This is a concrete diagnostic client, which buffers the diagnostic messages.
anatofuz
parents:
diff changeset
10 //
anatofuz
parents:
diff changeset
11 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
12
anatofuz
parents:
diff changeset
13 #include "clang/Frontend/VerifyDiagnosticConsumer.h"
anatofuz
parents:
diff changeset
14 #include "clang/Basic/CharInfo.h"
anatofuz
parents:
diff changeset
15 #include "clang/Basic/Diagnostic.h"
anatofuz
parents:
diff changeset
16 #include "clang/Basic/DiagnosticOptions.h"
anatofuz
parents:
diff changeset
17 #include "clang/Basic/FileManager.h"
anatofuz
parents:
diff changeset
18 #include "clang/Basic/LLVM.h"
anatofuz
parents:
diff changeset
19 #include "clang/Basic/SourceLocation.h"
anatofuz
parents:
diff changeset
20 #include "clang/Basic/SourceManager.h"
anatofuz
parents:
diff changeset
21 #include "clang/Basic/TokenKinds.h"
anatofuz
parents:
diff changeset
22 #include "clang/Frontend/FrontendDiagnostic.h"
anatofuz
parents:
diff changeset
23 #include "clang/Frontend/TextDiagnosticBuffer.h"
anatofuz
parents:
diff changeset
24 #include "clang/Lex/HeaderSearch.h"
anatofuz
parents:
diff changeset
25 #include "clang/Lex/Lexer.h"
anatofuz
parents:
diff changeset
26 #include "clang/Lex/PPCallbacks.h"
anatofuz
parents:
diff changeset
27 #include "clang/Lex/Preprocessor.h"
anatofuz
parents:
diff changeset
28 #include "clang/Lex/Token.h"
anatofuz
parents:
diff changeset
29 #include "llvm/ADT/STLExtras.h"
anatofuz
parents:
diff changeset
30 #include "llvm/ADT/SmallPtrSet.h"
anatofuz
parents:
diff changeset
31 #include "llvm/ADT/SmallString.h"
anatofuz
parents:
diff changeset
32 #include "llvm/ADT/StringRef.h"
anatofuz
parents:
diff changeset
33 #include "llvm/ADT/Twine.h"
anatofuz
parents:
diff changeset
34 #include "llvm/Support/ErrorHandling.h"
anatofuz
parents:
diff changeset
35 #include "llvm/Support/Regex.h"
anatofuz
parents:
diff changeset
36 #include "llvm/Support/raw_ostream.h"
anatofuz
parents:
diff changeset
37 #include <algorithm>
anatofuz
parents:
diff changeset
38 #include <cassert>
anatofuz
parents:
diff changeset
39 #include <cstddef>
anatofuz
parents:
diff changeset
40 #include <cstring>
anatofuz
parents:
diff changeset
41 #include <iterator>
anatofuz
parents:
diff changeset
42 #include <memory>
anatofuz
parents:
diff changeset
43 #include <string>
anatofuz
parents:
diff changeset
44 #include <utility>
anatofuz
parents:
diff changeset
45 #include <vector>
anatofuz
parents:
diff changeset
46
anatofuz
parents:
diff changeset
47 using namespace clang;
anatofuz
parents:
diff changeset
48
anatofuz
parents:
diff changeset
49 using Directive = VerifyDiagnosticConsumer::Directive;
anatofuz
parents:
diff changeset
50 using DirectiveList = VerifyDiagnosticConsumer::DirectiveList;
anatofuz
parents:
diff changeset
51 using ExpectedData = VerifyDiagnosticConsumer::ExpectedData;
anatofuz
parents:
diff changeset
52
anatofuz
parents:
diff changeset
53 #ifndef NDEBUG
anatofuz
parents:
diff changeset
54
anatofuz
parents:
diff changeset
55 namespace {
anatofuz
parents:
diff changeset
56
anatofuz
parents:
diff changeset
57 class VerifyFileTracker : public PPCallbacks {
anatofuz
parents:
diff changeset
58 VerifyDiagnosticConsumer &Verify;
anatofuz
parents:
diff changeset
59 SourceManager &SM;
anatofuz
parents:
diff changeset
60
anatofuz
parents:
diff changeset
61 public:
anatofuz
parents:
diff changeset
62 VerifyFileTracker(VerifyDiagnosticConsumer &Verify, SourceManager &SM)
anatofuz
parents:
diff changeset
63 : Verify(Verify), SM(SM) {}
anatofuz
parents:
diff changeset
64
anatofuz
parents:
diff changeset
65 /// Hook into the preprocessor and update the list of parsed
anatofuz
parents:
diff changeset
66 /// files when the preprocessor indicates a new file is entered.
anatofuz
parents:
diff changeset
67 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
anatofuz
parents:
diff changeset
68 SrcMgr::CharacteristicKind FileType,
anatofuz
parents:
diff changeset
69 FileID PrevFID) override {
anatofuz
parents:
diff changeset
70 Verify.UpdateParsedFileStatus(SM, SM.getFileID(Loc),
anatofuz
parents:
diff changeset
71 VerifyDiagnosticConsumer::IsParsed);
anatofuz
parents:
diff changeset
72 }
anatofuz
parents:
diff changeset
73 };
anatofuz
parents:
diff changeset
74
anatofuz
parents:
diff changeset
75 } // namespace
anatofuz
parents:
diff changeset
76
anatofuz
parents:
diff changeset
77 #endif
anatofuz
parents:
diff changeset
78
anatofuz
parents:
diff changeset
79 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
80 // Checking diagnostics implementation.
anatofuz
parents:
diff changeset
81 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
82
anatofuz
parents:
diff changeset
83 using DiagList = TextDiagnosticBuffer::DiagList;
anatofuz
parents:
diff changeset
84 using const_diag_iterator = TextDiagnosticBuffer::const_iterator;
anatofuz
parents:
diff changeset
85
anatofuz
parents:
diff changeset
86 namespace {
anatofuz
parents:
diff changeset
87
anatofuz
parents:
diff changeset
88 /// StandardDirective - Directive with string matching.
anatofuz
parents:
diff changeset
89 class StandardDirective : public Directive {
anatofuz
parents:
diff changeset
90 public:
anatofuz
parents:
diff changeset
91 StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
92 bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
93 unsigned Min, unsigned Max)
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
94 : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyFileAndLine,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
95 MatchAnyLine, Text, Min, Max) {}
150
anatofuz
parents:
diff changeset
96
anatofuz
parents:
diff changeset
97 bool isValid(std::string &Error) override {
anatofuz
parents:
diff changeset
98 // all strings are considered valid; even empty ones
anatofuz
parents:
diff changeset
99 return true;
anatofuz
parents:
diff changeset
100 }
anatofuz
parents:
diff changeset
101
anatofuz
parents:
diff changeset
102 bool match(StringRef S) override {
anatofuz
parents:
diff changeset
103 return S.find(Text) != StringRef::npos;
anatofuz
parents:
diff changeset
104 }
anatofuz
parents:
diff changeset
105 };
anatofuz
parents:
diff changeset
106
anatofuz
parents:
diff changeset
107 /// RegexDirective - Directive with regular-expression matching.
anatofuz
parents:
diff changeset
108 class RegexDirective : public Directive {
anatofuz
parents:
diff changeset
109 public:
anatofuz
parents:
diff changeset
110 RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
111 bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
112 unsigned Min, unsigned Max, StringRef RegexStr)
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
113 : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyFileAndLine,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
114 MatchAnyLine, Text, Min, Max),
150
anatofuz
parents:
diff changeset
115 Regex(RegexStr) {}
anatofuz
parents:
diff changeset
116
anatofuz
parents:
diff changeset
117 bool isValid(std::string &Error) override {
anatofuz
parents:
diff changeset
118 return Regex.isValid(Error);
anatofuz
parents:
diff changeset
119 }
anatofuz
parents:
diff changeset
120
anatofuz
parents:
diff changeset
121 bool match(StringRef S) override {
anatofuz
parents:
diff changeset
122 return Regex.match(S);
anatofuz
parents:
diff changeset
123 }
anatofuz
parents:
diff changeset
124
anatofuz
parents:
diff changeset
125 private:
anatofuz
parents:
diff changeset
126 llvm::Regex Regex;
anatofuz
parents:
diff changeset
127 };
anatofuz
parents:
diff changeset
128
anatofuz
parents:
diff changeset
129 class ParseHelper
anatofuz
parents:
diff changeset
130 {
anatofuz
parents:
diff changeset
131 public:
anatofuz
parents:
diff changeset
132 ParseHelper(StringRef S)
anatofuz
parents:
diff changeset
133 : Begin(S.begin()), End(S.end()), C(Begin), P(Begin) {}
anatofuz
parents:
diff changeset
134
anatofuz
parents:
diff changeset
135 // Return true if string literal is next.
anatofuz
parents:
diff changeset
136 bool Next(StringRef S) {
anatofuz
parents:
diff changeset
137 P = C;
anatofuz
parents:
diff changeset
138 PEnd = C + S.size();
anatofuz
parents:
diff changeset
139 if (PEnd > End)
anatofuz
parents:
diff changeset
140 return false;
anatofuz
parents:
diff changeset
141 return memcmp(P, S.data(), S.size()) == 0;
anatofuz
parents:
diff changeset
142 }
anatofuz
parents:
diff changeset
143
anatofuz
parents:
diff changeset
144 // Return true if number is next.
anatofuz
parents:
diff changeset
145 // Output N only if number is next.
anatofuz
parents:
diff changeset
146 bool Next(unsigned &N) {
anatofuz
parents:
diff changeset
147 unsigned TMP = 0;
anatofuz
parents:
diff changeset
148 P = C;
anatofuz
parents:
diff changeset
149 PEnd = P;
anatofuz
parents:
diff changeset
150 for (; PEnd < End && *PEnd >= '0' && *PEnd <= '9'; ++PEnd) {
anatofuz
parents:
diff changeset
151 TMP *= 10;
anatofuz
parents:
diff changeset
152 TMP += *PEnd - '0';
anatofuz
parents:
diff changeset
153 }
anatofuz
parents:
diff changeset
154 if (PEnd == C)
anatofuz
parents:
diff changeset
155 return false;
anatofuz
parents:
diff changeset
156 N = TMP;
anatofuz
parents:
diff changeset
157 return true;
anatofuz
parents:
diff changeset
158 }
anatofuz
parents:
diff changeset
159
anatofuz
parents:
diff changeset
160 // Return true if a marker is next.
anatofuz
parents:
diff changeset
161 // A marker is the longest match for /#[A-Za-z0-9_-]+/.
anatofuz
parents:
diff changeset
162 bool NextMarker() {
anatofuz
parents:
diff changeset
163 P = C;
anatofuz
parents:
diff changeset
164 if (P == End || *P != '#')
anatofuz
parents:
diff changeset
165 return false;
anatofuz
parents:
diff changeset
166 PEnd = P;
anatofuz
parents:
diff changeset
167 ++PEnd;
anatofuz
parents:
diff changeset
168 while ((isAlphanumeric(*PEnd) || *PEnd == '-' || *PEnd == '_') &&
anatofuz
parents:
diff changeset
169 PEnd < End)
anatofuz
parents:
diff changeset
170 ++PEnd;
anatofuz
parents:
diff changeset
171 return PEnd > P + 1;
anatofuz
parents:
diff changeset
172 }
anatofuz
parents:
diff changeset
173
anatofuz
parents:
diff changeset
174 // Return true if string literal S is matched in content.
anatofuz
parents:
diff changeset
175 // When true, P marks begin-position of the match, and calling Advance sets C
anatofuz
parents:
diff changeset
176 // to end-position of the match.
anatofuz
parents:
diff changeset
177 // If S is the empty string, then search for any letter instead (makes sense
anatofuz
parents:
diff changeset
178 // with FinishDirectiveToken=true).
anatofuz
parents:
diff changeset
179 // If EnsureStartOfWord, then skip matches that don't start a new word.
anatofuz
parents:
diff changeset
180 // If FinishDirectiveToken, then assume the match is the start of a comment
anatofuz
parents:
diff changeset
181 // directive for -verify, and extend the match to include the entire first
anatofuz
parents:
diff changeset
182 // token of that directive.
anatofuz
parents:
diff changeset
183 bool Search(StringRef S, bool EnsureStartOfWord = false,
anatofuz
parents:
diff changeset
184 bool FinishDirectiveToken = false) {
anatofuz
parents:
diff changeset
185 do {
anatofuz
parents:
diff changeset
186 if (!S.empty()) {
anatofuz
parents:
diff changeset
187 P = std::search(C, End, S.begin(), S.end());
anatofuz
parents:
diff changeset
188 PEnd = P + S.size();
anatofuz
parents:
diff changeset
189 }
anatofuz
parents:
diff changeset
190 else {
anatofuz
parents:
diff changeset
191 P = C;
anatofuz
parents:
diff changeset
192 while (P != End && !isLetter(*P))
anatofuz
parents:
diff changeset
193 ++P;
anatofuz
parents:
diff changeset
194 PEnd = P + 1;
anatofuz
parents:
diff changeset
195 }
anatofuz
parents:
diff changeset
196 if (P == End)
anatofuz
parents:
diff changeset
197 break;
anatofuz
parents:
diff changeset
198 // If not start of word but required, skip and search again.
anatofuz
parents:
diff changeset
199 if (EnsureStartOfWord
anatofuz
parents:
diff changeset
200 // Check if string literal starts a new word.
anatofuz
parents:
diff changeset
201 && !(P == Begin || isWhitespace(P[-1])
anatofuz
parents:
diff changeset
202 // Or it could be preceded by the start of a comment.
anatofuz
parents:
diff changeset
203 || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
anatofuz
parents:
diff changeset
204 && P[-2] == '/')))
anatofuz
parents:
diff changeset
205 continue;
anatofuz
parents:
diff changeset
206 if (FinishDirectiveToken) {
anatofuz
parents:
diff changeset
207 while (PEnd != End && (isAlphanumeric(*PEnd)
anatofuz
parents:
diff changeset
208 || *PEnd == '-' || *PEnd == '_'))
anatofuz
parents:
diff changeset
209 ++PEnd;
anatofuz
parents:
diff changeset
210 // Put back trailing digits and hyphens to be parsed later as a count
anatofuz
parents:
diff changeset
211 // or count range. Because -verify prefixes must start with letters,
anatofuz
parents:
diff changeset
212 // we know the actual directive we found starts with a letter, so
anatofuz
parents:
diff changeset
213 // we won't put back the entire directive word and thus record an empty
anatofuz
parents:
diff changeset
214 // string.
anatofuz
parents:
diff changeset
215 assert(isLetter(*P) && "-verify prefix must start with a letter");
anatofuz
parents:
diff changeset
216 while (isDigit(PEnd[-1]) || PEnd[-1] == '-')
anatofuz
parents:
diff changeset
217 --PEnd;
anatofuz
parents:
diff changeset
218 }
anatofuz
parents:
diff changeset
219 return true;
anatofuz
parents:
diff changeset
220 } while (Advance());
anatofuz
parents:
diff changeset
221 return false;
anatofuz
parents:
diff changeset
222 }
anatofuz
parents:
diff changeset
223
anatofuz
parents:
diff changeset
224 // Return true if a CloseBrace that closes the OpenBrace at the current nest
anatofuz
parents:
diff changeset
225 // level is found. When true, P marks begin-position of CloseBrace.
anatofuz
parents:
diff changeset
226 bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {
anatofuz
parents:
diff changeset
227 unsigned Depth = 1;
anatofuz
parents:
diff changeset
228 P = C;
anatofuz
parents:
diff changeset
229 while (P < End) {
anatofuz
parents:
diff changeset
230 StringRef S(P, End - P);
anatofuz
parents:
diff changeset
231 if (S.startswith(OpenBrace)) {
anatofuz
parents:
diff changeset
232 ++Depth;
anatofuz
parents:
diff changeset
233 P += OpenBrace.size();
anatofuz
parents:
diff changeset
234 } else if (S.startswith(CloseBrace)) {
anatofuz
parents:
diff changeset
235 --Depth;
anatofuz
parents:
diff changeset
236 if (Depth == 0) {
anatofuz
parents:
diff changeset
237 PEnd = P + CloseBrace.size();
anatofuz
parents:
diff changeset
238 return true;
anatofuz
parents:
diff changeset
239 }
anatofuz
parents:
diff changeset
240 P += CloseBrace.size();
anatofuz
parents:
diff changeset
241 } else {
anatofuz
parents:
diff changeset
242 ++P;
anatofuz
parents:
diff changeset
243 }
anatofuz
parents:
diff changeset
244 }
anatofuz
parents:
diff changeset
245 return false;
anatofuz
parents:
diff changeset
246 }
anatofuz
parents:
diff changeset
247
anatofuz
parents:
diff changeset
248 // Advance 1-past previous next/search.
anatofuz
parents:
diff changeset
249 // Behavior is undefined if previous next/search failed.
anatofuz
parents:
diff changeset
250 bool Advance() {
anatofuz
parents:
diff changeset
251 C = PEnd;
anatofuz
parents:
diff changeset
252 return C < End;
anatofuz
parents:
diff changeset
253 }
anatofuz
parents:
diff changeset
254
anatofuz
parents:
diff changeset
255 // Return the text matched by the previous next/search.
anatofuz
parents:
diff changeset
256 // Behavior is undefined if previous next/search failed.
anatofuz
parents:
diff changeset
257 StringRef Match() { return StringRef(P, PEnd - P); }
anatofuz
parents:
diff changeset
258
anatofuz
parents:
diff changeset
259 // Skip zero or more whitespace.
anatofuz
parents:
diff changeset
260 void SkipWhitespace() {
anatofuz
parents:
diff changeset
261 for (; C < End && isWhitespace(*C); ++C)
anatofuz
parents:
diff changeset
262 ;
anatofuz
parents:
diff changeset
263 }
anatofuz
parents:
diff changeset
264
anatofuz
parents:
diff changeset
265 // Return true if EOF reached.
anatofuz
parents:
diff changeset
266 bool Done() {
anatofuz
parents:
diff changeset
267 return !(C < End);
anatofuz
parents:
diff changeset
268 }
anatofuz
parents:
diff changeset
269
anatofuz
parents:
diff changeset
270 // Beginning of expected content.
anatofuz
parents:
diff changeset
271 const char * const Begin;
anatofuz
parents:
diff changeset
272
anatofuz
parents:
diff changeset
273 // End of expected content (1-past).
anatofuz
parents:
diff changeset
274 const char * const End;
anatofuz
parents:
diff changeset
275
anatofuz
parents:
diff changeset
276 // Position of next char in content.
anatofuz
parents:
diff changeset
277 const char *C;
anatofuz
parents:
diff changeset
278
anatofuz
parents:
diff changeset
279 // Previous next/search subject start.
anatofuz
parents:
diff changeset
280 const char *P;
anatofuz
parents:
diff changeset
281
anatofuz
parents:
diff changeset
282 private:
anatofuz
parents:
diff changeset
283 // Previous next/search subject end (1-past).
anatofuz
parents:
diff changeset
284 const char *PEnd = nullptr;
anatofuz
parents:
diff changeset
285 };
anatofuz
parents:
diff changeset
286
anatofuz
parents:
diff changeset
287 // The information necessary to create a directive.
anatofuz
parents:
diff changeset
288 struct UnattachedDirective {
anatofuz
parents:
diff changeset
289 DirectiveList *DL = nullptr;
anatofuz
parents:
diff changeset
290 bool RegexKind = false;
anatofuz
parents:
diff changeset
291 SourceLocation DirectivePos, ContentBegin;
anatofuz
parents:
diff changeset
292 std::string Text;
anatofuz
parents:
diff changeset
293 unsigned Min = 1, Max = 1;
anatofuz
parents:
diff changeset
294 };
anatofuz
parents:
diff changeset
295
anatofuz
parents:
diff changeset
296 // Attach the specified directive to the line of code indicated by
anatofuz
parents:
diff changeset
297 // \p ExpectedLoc.
anatofuz
parents:
diff changeset
298 void attachDirective(DiagnosticsEngine &Diags, const UnattachedDirective &UD,
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
299 SourceLocation ExpectedLoc,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
300 bool MatchAnyFileAndLine = false,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
301 bool MatchAnyLine = false) {
150
anatofuz
parents:
diff changeset
302 // Construct new directive.
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
303 std::unique_ptr<Directive> D = Directive::create(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
304 UD.RegexKind, UD.DirectivePos, ExpectedLoc, MatchAnyFileAndLine,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
305 MatchAnyLine, UD.Text, UD.Min, UD.Max);
150
anatofuz
parents:
diff changeset
306
anatofuz
parents:
diff changeset
307 std::string Error;
anatofuz
parents:
diff changeset
308 if (!D->isValid(Error)) {
anatofuz
parents:
diff changeset
309 Diags.Report(UD.ContentBegin, diag::err_verify_invalid_content)
anatofuz
parents:
diff changeset
310 << (UD.RegexKind ? "regex" : "string") << Error;
anatofuz
parents:
diff changeset
311 }
anatofuz
parents:
diff changeset
312
anatofuz
parents:
diff changeset
313 UD.DL->push_back(std::move(D));
anatofuz
parents:
diff changeset
314 }
anatofuz
parents:
diff changeset
315
anatofuz
parents:
diff changeset
316 } // anonymous
anatofuz
parents:
diff changeset
317
anatofuz
parents:
diff changeset
318 // Tracker for markers in the input files. A marker is a comment of the form
anatofuz
parents:
diff changeset
319 //
anatofuz
parents:
diff changeset
320 // n = 123; // #123
anatofuz
parents:
diff changeset
321 //
anatofuz
parents:
diff changeset
322 // ... that can be referred to by a later expected-* directive:
anatofuz
parents:
diff changeset
323 //
anatofuz
parents:
diff changeset
324 // // expected-error@#123 {{undeclared identifier 'n'}}
anatofuz
parents:
diff changeset
325 //
anatofuz
parents:
diff changeset
326 // Marker declarations must be at the start of a comment or preceded by
anatofuz
parents:
diff changeset
327 // whitespace to distinguish them from uses of markers in directives.
anatofuz
parents:
diff changeset
328 class VerifyDiagnosticConsumer::MarkerTracker {
anatofuz
parents:
diff changeset
329 DiagnosticsEngine &Diags;
anatofuz
parents:
diff changeset
330
anatofuz
parents:
diff changeset
331 struct Marker {
anatofuz
parents:
diff changeset
332 SourceLocation DefLoc;
anatofuz
parents:
diff changeset
333 SourceLocation RedefLoc;
anatofuz
parents:
diff changeset
334 SourceLocation UseLoc;
anatofuz
parents:
diff changeset
335 };
anatofuz
parents:
diff changeset
336 llvm::StringMap<Marker> Markers;
anatofuz
parents:
diff changeset
337
anatofuz
parents:
diff changeset
338 // Directives that couldn't be created yet because they name an unknown
anatofuz
parents:
diff changeset
339 // marker.
anatofuz
parents:
diff changeset
340 llvm::StringMap<llvm::SmallVector<UnattachedDirective, 2>> DeferredDirectives;
anatofuz
parents:
diff changeset
341
anatofuz
parents:
diff changeset
342 public:
anatofuz
parents:
diff changeset
343 MarkerTracker(DiagnosticsEngine &Diags) : Diags(Diags) {}
anatofuz
parents:
diff changeset
344
anatofuz
parents:
diff changeset
345 // Register a marker.
anatofuz
parents:
diff changeset
346 void addMarker(StringRef MarkerName, SourceLocation Pos) {
anatofuz
parents:
diff changeset
347 auto InsertResult = Markers.insert(
anatofuz
parents:
diff changeset
348 {MarkerName, Marker{Pos, SourceLocation(), SourceLocation()}});
anatofuz
parents:
diff changeset
349
anatofuz
parents:
diff changeset
350 Marker &M = InsertResult.first->second;
anatofuz
parents:
diff changeset
351 if (!InsertResult.second) {
anatofuz
parents:
diff changeset
352 // Marker was redefined.
anatofuz
parents:
diff changeset
353 M.RedefLoc = Pos;
anatofuz
parents:
diff changeset
354 } else {
anatofuz
parents:
diff changeset
355 // First definition: build any deferred directives.
anatofuz
parents:
diff changeset
356 auto Deferred = DeferredDirectives.find(MarkerName);
anatofuz
parents:
diff changeset
357 if (Deferred != DeferredDirectives.end()) {
anatofuz
parents:
diff changeset
358 for (auto &UD : Deferred->second) {
anatofuz
parents:
diff changeset
359 if (M.UseLoc.isInvalid())
anatofuz
parents:
diff changeset
360 M.UseLoc = UD.DirectivePos;
anatofuz
parents:
diff changeset
361 attachDirective(Diags, UD, Pos);
anatofuz
parents:
diff changeset
362 }
anatofuz
parents:
diff changeset
363 DeferredDirectives.erase(Deferred);
anatofuz
parents:
diff changeset
364 }
anatofuz
parents:
diff changeset
365 }
anatofuz
parents:
diff changeset
366 }
anatofuz
parents:
diff changeset
367
anatofuz
parents:
diff changeset
368 // Register a directive at the specified marker.
anatofuz
parents:
diff changeset
369 void addDirective(StringRef MarkerName, const UnattachedDirective &UD) {
anatofuz
parents:
diff changeset
370 auto MarkerIt = Markers.find(MarkerName);
anatofuz
parents:
diff changeset
371 if (MarkerIt != Markers.end()) {
anatofuz
parents:
diff changeset
372 Marker &M = MarkerIt->second;
anatofuz
parents:
diff changeset
373 if (M.UseLoc.isInvalid())
anatofuz
parents:
diff changeset
374 M.UseLoc = UD.DirectivePos;
anatofuz
parents:
diff changeset
375 return attachDirective(Diags, UD, M.DefLoc);
anatofuz
parents:
diff changeset
376 }
anatofuz
parents:
diff changeset
377 DeferredDirectives[MarkerName].push_back(UD);
anatofuz
parents:
diff changeset
378 }
anatofuz
parents:
diff changeset
379
anatofuz
parents:
diff changeset
380 // Ensure we have no remaining deferred directives, and no
anatofuz
parents:
diff changeset
381 // multiply-defined-and-used markers.
anatofuz
parents:
diff changeset
382 void finalize() {
anatofuz
parents:
diff changeset
383 for (auto &MarkerInfo : Markers) {
anatofuz
parents:
diff changeset
384 StringRef Name = MarkerInfo.first();
anatofuz
parents:
diff changeset
385 Marker &M = MarkerInfo.second;
anatofuz
parents:
diff changeset
386 if (M.RedefLoc.isValid() && M.UseLoc.isValid()) {
anatofuz
parents:
diff changeset
387 Diags.Report(M.UseLoc, diag::err_verify_ambiguous_marker) << Name;
anatofuz
parents:
diff changeset
388 Diags.Report(M.DefLoc, diag::note_verify_ambiguous_marker) << Name;
anatofuz
parents:
diff changeset
389 Diags.Report(M.RedefLoc, diag::note_verify_ambiguous_marker) << Name;
anatofuz
parents:
diff changeset
390 }
anatofuz
parents:
diff changeset
391 }
anatofuz
parents:
diff changeset
392
anatofuz
parents:
diff changeset
393 for (auto &DeferredPair : DeferredDirectives) {
anatofuz
parents:
diff changeset
394 Diags.Report(DeferredPair.second.front().DirectivePos,
anatofuz
parents:
diff changeset
395 diag::err_verify_no_such_marker)
anatofuz
parents:
diff changeset
396 << DeferredPair.first();
anatofuz
parents:
diff changeset
397 }
anatofuz
parents:
diff changeset
398 }
anatofuz
parents:
diff changeset
399 };
anatofuz
parents:
diff changeset
400
anatofuz
parents:
diff changeset
401 /// ParseDirective - Go through the comment and see if it indicates expected
anatofuz
parents:
diff changeset
402 /// diagnostics. If so, then put them in the appropriate directive list.
anatofuz
parents:
diff changeset
403 ///
anatofuz
parents:
diff changeset
404 /// Returns true if any valid directives were found.
anatofuz
parents:
diff changeset
405 static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
anatofuz
parents:
diff changeset
406 Preprocessor *PP, SourceLocation Pos,
anatofuz
parents:
diff changeset
407 VerifyDiagnosticConsumer::DirectiveStatus &Status,
anatofuz
parents:
diff changeset
408 VerifyDiagnosticConsumer::MarkerTracker &Markers) {
anatofuz
parents:
diff changeset
409 DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics();
anatofuz
parents:
diff changeset
410
anatofuz
parents:
diff changeset
411 // First, scan the comment looking for markers.
anatofuz
parents:
diff changeset
412 for (ParseHelper PH(S); !PH.Done();) {
anatofuz
parents:
diff changeset
413 if (!PH.Search("#", true))
anatofuz
parents:
diff changeset
414 break;
anatofuz
parents:
diff changeset
415 PH.C = PH.P;
anatofuz
parents:
diff changeset
416 if (!PH.NextMarker()) {
anatofuz
parents:
diff changeset
417 PH.Next("#");
anatofuz
parents:
diff changeset
418 PH.Advance();
anatofuz
parents:
diff changeset
419 continue;
anatofuz
parents:
diff changeset
420 }
anatofuz
parents:
diff changeset
421 PH.Advance();
anatofuz
parents:
diff changeset
422 Markers.addMarker(PH.Match(), Pos);
anatofuz
parents:
diff changeset
423 }
anatofuz
parents:
diff changeset
424
anatofuz
parents:
diff changeset
425 // A single comment may contain multiple directives.
anatofuz
parents:
diff changeset
426 bool FoundDirective = false;
anatofuz
parents:
diff changeset
427 for (ParseHelper PH(S); !PH.Done();) {
anatofuz
parents:
diff changeset
428 // Search for the initial directive token.
anatofuz
parents:
diff changeset
429 // If one prefix, save time by searching only for its directives.
anatofuz
parents:
diff changeset
430 // Otherwise, search for any potential directive token and check it later.
anatofuz
parents:
diff changeset
431 const auto &Prefixes = Diags.getDiagnosticOptions().VerifyPrefixes;
anatofuz
parents:
diff changeset
432 if (!(Prefixes.size() == 1 ? PH.Search(*Prefixes.begin(), true, true)
anatofuz
parents:
diff changeset
433 : PH.Search("", true, true)))
anatofuz
parents:
diff changeset
434 break;
anatofuz
parents:
diff changeset
435
anatofuz
parents:
diff changeset
436 StringRef DToken = PH.Match();
anatofuz
parents:
diff changeset
437 PH.Advance();
anatofuz
parents:
diff changeset
438
anatofuz
parents:
diff changeset
439 // Default directive kind.
anatofuz
parents:
diff changeset
440 UnattachedDirective D;
anatofuz
parents:
diff changeset
441 const char *KindStr = "string";
anatofuz
parents:
diff changeset
442
anatofuz
parents:
diff changeset
443 // Parse the initial directive token in reverse so we can easily determine
anatofuz
parents:
diff changeset
444 // its exact actual prefix. If we were to parse it from the front instead,
anatofuz
parents:
diff changeset
445 // it would be harder to determine where the prefix ends because there
anatofuz
parents:
diff changeset
446 // might be multiple matching -verify prefixes because some might prefix
anatofuz
parents:
diff changeset
447 // others.
anatofuz
parents:
diff changeset
448
anatofuz
parents:
diff changeset
449 // Regex in initial directive token: -re
anatofuz
parents:
diff changeset
450 if (DToken.endswith("-re")) {
anatofuz
parents:
diff changeset
451 D.RegexKind = true;
anatofuz
parents:
diff changeset
452 KindStr = "regex";
anatofuz
parents:
diff changeset
453 DToken = DToken.substr(0, DToken.size()-3);
anatofuz
parents:
diff changeset
454 }
anatofuz
parents:
diff changeset
455
anatofuz
parents:
diff changeset
456 // Type in initial directive token: -{error|warning|note|no-diagnostics}
anatofuz
parents:
diff changeset
457 bool NoDiag = false;
anatofuz
parents:
diff changeset
458 StringRef DType;
anatofuz
parents:
diff changeset
459 if (DToken.endswith(DType="-error"))
anatofuz
parents:
diff changeset
460 D.DL = ED ? &ED->Errors : nullptr;
anatofuz
parents:
diff changeset
461 else if (DToken.endswith(DType="-warning"))
anatofuz
parents:
diff changeset
462 D.DL = ED ? &ED->Warnings : nullptr;
anatofuz
parents:
diff changeset
463 else if (DToken.endswith(DType="-remark"))
anatofuz
parents:
diff changeset
464 D.DL = ED ? &ED->Remarks : nullptr;
anatofuz
parents:
diff changeset
465 else if (DToken.endswith(DType="-note"))
anatofuz
parents:
diff changeset
466 D.DL = ED ? &ED->Notes : nullptr;
anatofuz
parents:
diff changeset
467 else if (DToken.endswith(DType="-no-diagnostics")) {
anatofuz
parents:
diff changeset
468 NoDiag = true;
anatofuz
parents:
diff changeset
469 if (D.RegexKind)
anatofuz
parents:
diff changeset
470 continue;
anatofuz
parents:
diff changeset
471 }
anatofuz
parents:
diff changeset
472 else
anatofuz
parents:
diff changeset
473 continue;
anatofuz
parents:
diff changeset
474 DToken = DToken.substr(0, DToken.size()-DType.size());
anatofuz
parents:
diff changeset
475
anatofuz
parents:
diff changeset
476 // What's left in DToken is the actual prefix. That might not be a -verify
anatofuz
parents:
diff changeset
477 // prefix even if there is only one -verify prefix (for example, the full
anatofuz
parents:
diff changeset
478 // DToken is foo-bar-warning, but foo is the only -verify prefix).
anatofuz
parents:
diff changeset
479 if (!std::binary_search(Prefixes.begin(), Prefixes.end(), DToken))
anatofuz
parents:
diff changeset
480 continue;
anatofuz
parents:
diff changeset
481
anatofuz
parents:
diff changeset
482 if (NoDiag) {
anatofuz
parents:
diff changeset
483 if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
anatofuz
parents:
diff changeset
484 Diags.Report(Pos, diag::err_verify_invalid_no_diags)
anatofuz
parents:
diff changeset
485 << /*IsExpectedNoDiagnostics=*/true;
anatofuz
parents:
diff changeset
486 else
anatofuz
parents:
diff changeset
487 Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
anatofuz
parents:
diff changeset
488 continue;
anatofuz
parents:
diff changeset
489 }
anatofuz
parents:
diff changeset
490 if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
anatofuz
parents:
diff changeset
491 Diags.Report(Pos, diag::err_verify_invalid_no_diags)
anatofuz
parents:
diff changeset
492 << /*IsExpectedNoDiagnostics=*/false;
anatofuz
parents:
diff changeset
493 continue;
anatofuz
parents:
diff changeset
494 }
anatofuz
parents:
diff changeset
495 Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives;
anatofuz
parents:
diff changeset
496
anatofuz
parents:
diff changeset
497 // If a directive has been found but we're not interested
anatofuz
parents:
diff changeset
498 // in storing the directive information, return now.
anatofuz
parents:
diff changeset
499 if (!D.DL)
anatofuz
parents:
diff changeset
500 return true;
anatofuz
parents:
diff changeset
501
anatofuz
parents:
diff changeset
502 // Next optional token: @
anatofuz
parents:
diff changeset
503 SourceLocation ExpectedLoc;
anatofuz
parents:
diff changeset
504 StringRef Marker;
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
505 bool MatchAnyFileAndLine = false;
150
anatofuz
parents:
diff changeset
506 bool MatchAnyLine = false;
anatofuz
parents:
diff changeset
507 if (!PH.Next("@")) {
anatofuz
parents:
diff changeset
508 ExpectedLoc = Pos;
anatofuz
parents:
diff changeset
509 } else {
anatofuz
parents:
diff changeset
510 PH.Advance();
anatofuz
parents:
diff changeset
511 unsigned Line = 0;
anatofuz
parents:
diff changeset
512 bool FoundPlus = PH.Next("+");
anatofuz
parents:
diff changeset
513 if (FoundPlus || PH.Next("-")) {
anatofuz
parents:
diff changeset
514 // Relative to current line.
anatofuz
parents:
diff changeset
515 PH.Advance();
anatofuz
parents:
diff changeset
516 bool Invalid = false;
anatofuz
parents:
diff changeset
517 unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid);
anatofuz
parents:
diff changeset
518 if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {
anatofuz
parents:
diff changeset
519 if (FoundPlus) ExpectedLine += Line;
anatofuz
parents:
diff changeset
520 else ExpectedLine -= Line;
anatofuz
parents:
diff changeset
521 ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1);
anatofuz
parents:
diff changeset
522 }
anatofuz
parents:
diff changeset
523 } else if (PH.Next(Line)) {
anatofuz
parents:
diff changeset
524 // Absolute line number.
anatofuz
parents:
diff changeset
525 if (Line > 0)
anatofuz
parents:
diff changeset
526 ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1);
anatofuz
parents:
diff changeset
527 } else if (PH.NextMarker()) {
anatofuz
parents:
diff changeset
528 Marker = PH.Match();
anatofuz
parents:
diff changeset
529 } else if (PP && PH.Search(":")) {
anatofuz
parents:
diff changeset
530 // Specific source file.
anatofuz
parents:
diff changeset
531 StringRef Filename(PH.C, PH.P-PH.C);
anatofuz
parents:
diff changeset
532 PH.Advance();
anatofuz
parents:
diff changeset
533
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
534 if (Filename == "*") {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
535 MatchAnyFileAndLine = true;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
536 if (!PH.Next("*")) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
537 Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
538 diag::err_verify_missing_line)
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
539 << "'*'";
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
540 continue;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
541 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
542 MatchAnyLine = true;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
543 ExpectedLoc = SourceLocation();
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
544 } else {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
545 // Lookup file via Preprocessor, like a #include.
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
546 const DirectoryLookup *CurDir;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
547 Optional<FileEntryRef> File =
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
548 PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
549 nullptr, nullptr, nullptr, nullptr, nullptr);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
550 if (!File) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
551 Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
552 diag::err_verify_missing_file)
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
553 << Filename << KindStr;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
554 continue;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
555 }
150
anatofuz
parents:
diff changeset
556
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
557 const FileEntry *FE = &File->getFileEntry();
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
558 if (SM.translateFile(FE).isInvalid())
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
559 SM.createFileID(FE, Pos, SrcMgr::C_User);
150
anatofuz
parents:
diff changeset
560
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
561 if (PH.Next(Line) && Line > 0)
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
562 ExpectedLoc = SM.translateFileLineCol(FE, Line, 1);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
563 else if (PH.Next("*")) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
564 MatchAnyLine = true;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
565 ExpectedLoc = SM.translateFileLineCol(FE, 1, 1);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
566 }
150
anatofuz
parents:
diff changeset
567 }
anatofuz
parents:
diff changeset
568 } else if (PH.Next("*")) {
anatofuz
parents:
diff changeset
569 MatchAnyLine = true;
anatofuz
parents:
diff changeset
570 ExpectedLoc = SourceLocation();
anatofuz
parents:
diff changeset
571 }
anatofuz
parents:
diff changeset
572
anatofuz
parents:
diff changeset
573 if (ExpectedLoc.isInvalid() && !MatchAnyLine && Marker.empty()) {
anatofuz
parents:
diff changeset
574 Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
anatofuz
parents:
diff changeset
575 diag::err_verify_missing_line) << KindStr;
anatofuz
parents:
diff changeset
576 continue;
anatofuz
parents:
diff changeset
577 }
anatofuz
parents:
diff changeset
578 PH.Advance();
anatofuz
parents:
diff changeset
579 }
anatofuz
parents:
diff changeset
580
anatofuz
parents:
diff changeset
581 // Skip optional whitespace.
anatofuz
parents:
diff changeset
582 PH.SkipWhitespace();
anatofuz
parents:
diff changeset
583
anatofuz
parents:
diff changeset
584 // Next optional token: positive integer or a '+'.
anatofuz
parents:
diff changeset
585 if (PH.Next(D.Min)) {
anatofuz
parents:
diff changeset
586 PH.Advance();
anatofuz
parents:
diff changeset
587 // A positive integer can be followed by a '+' meaning min
anatofuz
parents:
diff changeset
588 // or more, or by a '-' meaning a range from min to max.
anatofuz
parents:
diff changeset
589 if (PH.Next("+")) {
anatofuz
parents:
diff changeset
590 D.Max = Directive::MaxCount;
anatofuz
parents:
diff changeset
591 PH.Advance();
anatofuz
parents:
diff changeset
592 } else if (PH.Next("-")) {
anatofuz
parents:
diff changeset
593 PH.Advance();
anatofuz
parents:
diff changeset
594 if (!PH.Next(D.Max) || D.Max < D.Min) {
anatofuz
parents:
diff changeset
595 Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
anatofuz
parents:
diff changeset
596 diag::err_verify_invalid_range) << KindStr;
anatofuz
parents:
diff changeset
597 continue;
anatofuz
parents:
diff changeset
598 }
anatofuz
parents:
diff changeset
599 PH.Advance();
anatofuz
parents:
diff changeset
600 } else {
anatofuz
parents:
diff changeset
601 D.Max = D.Min;
anatofuz
parents:
diff changeset
602 }
anatofuz
parents:
diff changeset
603 } else if (PH.Next("+")) {
anatofuz
parents:
diff changeset
604 // '+' on its own means "1 or more".
anatofuz
parents:
diff changeset
605 D.Max = Directive::MaxCount;
anatofuz
parents:
diff changeset
606 PH.Advance();
anatofuz
parents:
diff changeset
607 }
anatofuz
parents:
diff changeset
608
anatofuz
parents:
diff changeset
609 // Skip optional whitespace.
anatofuz
parents:
diff changeset
610 PH.SkipWhitespace();
anatofuz
parents:
diff changeset
611
anatofuz
parents:
diff changeset
612 // Next token: {{
anatofuz
parents:
diff changeset
613 if (!PH.Next("{{")) {
anatofuz
parents:
diff changeset
614 Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
anatofuz
parents:
diff changeset
615 diag::err_verify_missing_start) << KindStr;
anatofuz
parents:
diff changeset
616 continue;
anatofuz
parents:
diff changeset
617 }
anatofuz
parents:
diff changeset
618 PH.Advance();
anatofuz
parents:
diff changeset
619 const char* const ContentBegin = PH.C; // mark content begin
anatofuz
parents:
diff changeset
620 // Search for token: }}
anatofuz
parents:
diff changeset
621 if (!PH.SearchClosingBrace("{{", "}}")) {
anatofuz
parents:
diff changeset
622 Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
anatofuz
parents:
diff changeset
623 diag::err_verify_missing_end) << KindStr;
anatofuz
parents:
diff changeset
624 continue;
anatofuz
parents:
diff changeset
625 }
anatofuz
parents:
diff changeset
626 const char* const ContentEnd = PH.P; // mark content end
anatofuz
parents:
diff changeset
627 PH.Advance();
anatofuz
parents:
diff changeset
628
anatofuz
parents:
diff changeset
629 D.DirectivePos = Pos;
anatofuz
parents:
diff changeset
630 D.ContentBegin = Pos.getLocWithOffset(ContentBegin - PH.Begin);
anatofuz
parents:
diff changeset
631
anatofuz
parents:
diff changeset
632 // Build directive text; convert \n to newlines.
anatofuz
parents:
diff changeset
633 StringRef NewlineStr = "\\n";
anatofuz
parents:
diff changeset
634 StringRef Content(ContentBegin, ContentEnd-ContentBegin);
anatofuz
parents:
diff changeset
635 size_t CPos = 0;
anatofuz
parents:
diff changeset
636 size_t FPos;
anatofuz
parents:
diff changeset
637 while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
anatofuz
parents:
diff changeset
638 D.Text += Content.substr(CPos, FPos-CPos);
anatofuz
parents:
diff changeset
639 D.Text += '\n';
anatofuz
parents:
diff changeset
640 CPos = FPos + NewlineStr.size();
anatofuz
parents:
diff changeset
641 }
anatofuz
parents:
diff changeset
642 if (D.Text.empty())
anatofuz
parents:
diff changeset
643 D.Text.assign(ContentBegin, ContentEnd);
anatofuz
parents:
diff changeset
644
anatofuz
parents:
diff changeset
645 // Check that regex directives contain at least one regex.
anatofuz
parents:
diff changeset
646 if (D.RegexKind && D.Text.find("{{") == StringRef::npos) {
anatofuz
parents:
diff changeset
647 Diags.Report(D.ContentBegin, diag::err_verify_missing_regex) << D.Text;
anatofuz
parents:
diff changeset
648 return false;
anatofuz
parents:
diff changeset
649 }
anatofuz
parents:
diff changeset
650
anatofuz
parents:
diff changeset
651 if (Marker.empty())
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
652 attachDirective(Diags, D, ExpectedLoc, MatchAnyFileAndLine, MatchAnyLine);
150
anatofuz
parents:
diff changeset
653 else
anatofuz
parents:
diff changeset
654 Markers.addDirective(Marker, D);
anatofuz
parents:
diff changeset
655 FoundDirective = true;
anatofuz
parents:
diff changeset
656 }
anatofuz
parents:
diff changeset
657
anatofuz
parents:
diff changeset
658 return FoundDirective;
anatofuz
parents:
diff changeset
659 }
anatofuz
parents:
diff changeset
660
anatofuz
parents:
diff changeset
661 VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &Diags_)
anatofuz
parents:
diff changeset
662 : Diags(Diags_), PrimaryClient(Diags.getClient()),
anatofuz
parents:
diff changeset
663 PrimaryClientOwner(Diags.takeClient()),
anatofuz
parents:
diff changeset
664 Buffer(new TextDiagnosticBuffer()), Markers(new MarkerTracker(Diags)),
anatofuz
parents:
diff changeset
665 Status(HasNoDirectives) {
anatofuz
parents:
diff changeset
666 if (Diags.hasSourceManager())
anatofuz
parents:
diff changeset
667 setSourceManager(Diags.getSourceManager());
anatofuz
parents:
diff changeset
668 }
anatofuz
parents:
diff changeset
669
anatofuz
parents:
diff changeset
670 VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
anatofuz
parents:
diff changeset
671 assert(!ActiveSourceFiles && "Incomplete parsing of source files!");
anatofuz
parents:
diff changeset
672 assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!");
anatofuz
parents:
diff changeset
673 SrcManager = nullptr;
anatofuz
parents:
diff changeset
674 CheckDiagnostics();
anatofuz
parents:
diff changeset
675 assert(!Diags.ownsClient() &&
anatofuz
parents:
diff changeset
676 "The VerifyDiagnosticConsumer takes over ownership of the client!");
anatofuz
parents:
diff changeset
677 }
anatofuz
parents:
diff changeset
678
anatofuz
parents:
diff changeset
679 // DiagnosticConsumer interface.
anatofuz
parents:
diff changeset
680
anatofuz
parents:
diff changeset
681 void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
anatofuz
parents:
diff changeset
682 const Preprocessor *PP) {
anatofuz
parents:
diff changeset
683 // Attach comment handler on first invocation.
anatofuz
parents:
diff changeset
684 if (++ActiveSourceFiles == 1) {
anatofuz
parents:
diff changeset
685 if (PP) {
anatofuz
parents:
diff changeset
686 CurrentPreprocessor = PP;
anatofuz
parents:
diff changeset
687 this->LangOpts = &LangOpts;
anatofuz
parents:
diff changeset
688 setSourceManager(PP->getSourceManager());
anatofuz
parents:
diff changeset
689 const_cast<Preprocessor *>(PP)->addCommentHandler(this);
anatofuz
parents:
diff changeset
690 #ifndef NDEBUG
anatofuz
parents:
diff changeset
691 // Debug build tracks parsed files.
anatofuz
parents:
diff changeset
692 const_cast<Preprocessor *>(PP)->addPPCallbacks(
anatofuz
parents:
diff changeset
693 std::make_unique<VerifyFileTracker>(*this, *SrcManager));
anatofuz
parents:
diff changeset
694 #endif
anatofuz
parents:
diff changeset
695 }
anatofuz
parents:
diff changeset
696 }
anatofuz
parents:
diff changeset
697
anatofuz
parents:
diff changeset
698 assert((!PP || CurrentPreprocessor == PP) && "Preprocessor changed!");
anatofuz
parents:
diff changeset
699 PrimaryClient->BeginSourceFile(LangOpts, PP);
anatofuz
parents:
diff changeset
700 }
anatofuz
parents:
diff changeset
701
anatofuz
parents:
diff changeset
702 void VerifyDiagnosticConsumer::EndSourceFile() {
anatofuz
parents:
diff changeset
703 assert(ActiveSourceFiles && "No active source files!");
anatofuz
parents:
diff changeset
704 PrimaryClient->EndSourceFile();
anatofuz
parents:
diff changeset
705
anatofuz
parents:
diff changeset
706 // Detach comment handler once last active source file completed.
anatofuz
parents:
diff changeset
707 if (--ActiveSourceFiles == 0) {
anatofuz
parents:
diff changeset
708 if (CurrentPreprocessor)
anatofuz
parents:
diff changeset
709 const_cast<Preprocessor *>(CurrentPreprocessor)->
anatofuz
parents:
diff changeset
710 removeCommentHandler(this);
anatofuz
parents:
diff changeset
711
anatofuz
parents:
diff changeset
712 // Diagnose any used-but-not-defined markers.
anatofuz
parents:
diff changeset
713 Markers->finalize();
anatofuz
parents:
diff changeset
714
anatofuz
parents:
diff changeset
715 // Check diagnostics once last file completed.
anatofuz
parents:
diff changeset
716 CheckDiagnostics();
anatofuz
parents:
diff changeset
717 CurrentPreprocessor = nullptr;
anatofuz
parents:
diff changeset
718 LangOpts = nullptr;
anatofuz
parents:
diff changeset
719 }
anatofuz
parents:
diff changeset
720 }
anatofuz
parents:
diff changeset
721
anatofuz
parents:
diff changeset
722 void VerifyDiagnosticConsumer::HandleDiagnostic(
anatofuz
parents:
diff changeset
723 DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
anatofuz
parents:
diff changeset
724 if (Info.hasSourceManager()) {
anatofuz
parents:
diff changeset
725 // If this diagnostic is for a different source manager, ignore it.
anatofuz
parents:
diff changeset
726 if (SrcManager && &Info.getSourceManager() != SrcManager)
anatofuz
parents:
diff changeset
727 return;
anatofuz
parents:
diff changeset
728
anatofuz
parents:
diff changeset
729 setSourceManager(Info.getSourceManager());
anatofuz
parents:
diff changeset
730 }
anatofuz
parents:
diff changeset
731
anatofuz
parents:
diff changeset
732 #ifndef NDEBUG
anatofuz
parents:
diff changeset
733 // Debug build tracks unparsed files for possible
anatofuz
parents:
diff changeset
734 // unparsed expected-* directives.
anatofuz
parents:
diff changeset
735 if (SrcManager) {
anatofuz
parents:
diff changeset
736 SourceLocation Loc = Info.getLocation();
anatofuz
parents:
diff changeset
737 if (Loc.isValid()) {
anatofuz
parents:
diff changeset
738 ParsedStatus PS = IsUnparsed;
anatofuz
parents:
diff changeset
739
anatofuz
parents:
diff changeset
740 Loc = SrcManager->getExpansionLoc(Loc);
anatofuz
parents:
diff changeset
741 FileID FID = SrcManager->getFileID(Loc);
anatofuz
parents:
diff changeset
742
anatofuz
parents:
diff changeset
743 const FileEntry *FE = SrcManager->getFileEntryForID(FID);
anatofuz
parents:
diff changeset
744 if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) {
anatofuz
parents:
diff changeset
745 // If the file is a modules header file it shall not be parsed
anatofuz
parents:
diff changeset
746 // for expected-* directives.
anatofuz
parents:
diff changeset
747 HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();
anatofuz
parents:
diff changeset
748 if (HS.findModuleForHeader(FE))
anatofuz
parents:
diff changeset
749 PS = IsUnparsedNoDirectives;
anatofuz
parents:
diff changeset
750 }
anatofuz
parents:
diff changeset
751
anatofuz
parents:
diff changeset
752 UpdateParsedFileStatus(*SrcManager, FID, PS);
anatofuz
parents:
diff changeset
753 }
anatofuz
parents:
diff changeset
754 }
anatofuz
parents:
diff changeset
755 #endif
anatofuz
parents:
diff changeset
756
anatofuz
parents:
diff changeset
757 // Send the diagnostic to the buffer, we will check it once we reach the end
anatofuz
parents:
diff changeset
758 // of the source file (or are destructed).
anatofuz
parents:
diff changeset
759 Buffer->HandleDiagnostic(DiagLevel, Info);
anatofuz
parents:
diff changeset
760 }
anatofuz
parents:
diff changeset
761
anatofuz
parents:
diff changeset
762 /// HandleComment - Hook into the preprocessor and extract comments containing
anatofuz
parents:
diff changeset
763 /// expected errors and warnings.
anatofuz
parents:
diff changeset
764 bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
anatofuz
parents:
diff changeset
765 SourceRange Comment) {
anatofuz
parents:
diff changeset
766 SourceManager &SM = PP.getSourceManager();
anatofuz
parents:
diff changeset
767
anatofuz
parents:
diff changeset
768 // If this comment is for a different source manager, ignore it.
anatofuz
parents:
diff changeset
769 if (SrcManager && &SM != SrcManager)
anatofuz
parents:
diff changeset
770 return false;
anatofuz
parents:
diff changeset
771
anatofuz
parents:
diff changeset
772 SourceLocation CommentBegin = Comment.getBegin();
anatofuz
parents:
diff changeset
773
anatofuz
parents:
diff changeset
774 const char *CommentRaw = SM.getCharacterData(CommentBegin);
anatofuz
parents:
diff changeset
775 StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw);
anatofuz
parents:
diff changeset
776
anatofuz
parents:
diff changeset
777 if (C.empty())
anatofuz
parents:
diff changeset
778 return false;
anatofuz
parents:
diff changeset
779
anatofuz
parents:
diff changeset
780 // Fold any "\<EOL>" sequences
anatofuz
parents:
diff changeset
781 size_t loc = C.find('\\');
anatofuz
parents:
diff changeset
782 if (loc == StringRef::npos) {
anatofuz
parents:
diff changeset
783 ParseDirective(C, &ED, SM, &PP, CommentBegin, Status, *Markers);
anatofuz
parents:
diff changeset
784 return false;
anatofuz
parents:
diff changeset
785 }
anatofuz
parents:
diff changeset
786
anatofuz
parents:
diff changeset
787 std::string C2;
anatofuz
parents:
diff changeset
788 C2.reserve(C.size());
anatofuz
parents:
diff changeset
789
anatofuz
parents:
diff changeset
790 for (size_t last = 0;; loc = C.find('\\', last)) {
anatofuz
parents:
diff changeset
791 if (loc == StringRef::npos || loc == C.size()) {
anatofuz
parents:
diff changeset
792 C2 += C.substr(last);
anatofuz
parents:
diff changeset
793 break;
anatofuz
parents:
diff changeset
794 }
anatofuz
parents:
diff changeset
795 C2 += C.substr(last, loc-last);
anatofuz
parents:
diff changeset
796 last = loc + 1;
anatofuz
parents:
diff changeset
797
anatofuz
parents:
diff changeset
798 if (C[last] == '\n' || C[last] == '\r') {
anatofuz
parents:
diff changeset
799 ++last;
anatofuz
parents:
diff changeset
800
anatofuz
parents:
diff changeset
801 // Escape \r\n or \n\r, but not \n\n.
anatofuz
parents:
diff changeset
802 if (last < C.size())
anatofuz
parents:
diff changeset
803 if (C[last] == '\n' || C[last] == '\r')
anatofuz
parents:
diff changeset
804 if (C[last] != C[last-1])
anatofuz
parents:
diff changeset
805 ++last;
anatofuz
parents:
diff changeset
806 } else {
anatofuz
parents:
diff changeset
807 // This was just a normal backslash.
anatofuz
parents:
diff changeset
808 C2 += '\\';
anatofuz
parents:
diff changeset
809 }
anatofuz
parents:
diff changeset
810 }
anatofuz
parents:
diff changeset
811
anatofuz
parents:
diff changeset
812 if (!C2.empty())
anatofuz
parents:
diff changeset
813 ParseDirective(C2, &ED, SM, &PP, CommentBegin, Status, *Markers);
anatofuz
parents:
diff changeset
814 return false;
anatofuz
parents:
diff changeset
815 }
anatofuz
parents:
diff changeset
816
anatofuz
parents:
diff changeset
817 #ifndef NDEBUG
anatofuz
parents:
diff changeset
818 /// Lex the specified source file to determine whether it contains
anatofuz
parents:
diff changeset
819 /// any expected-* directives. As a Lexer is used rather than a full-blown
anatofuz
parents:
diff changeset
820 /// Preprocessor, directives inside skipped #if blocks will still be found.
anatofuz
parents:
diff changeset
821 ///
anatofuz
parents:
diff changeset
822 /// \return true if any directives were found.
anatofuz
parents:
diff changeset
823 static bool findDirectives(SourceManager &SM, FileID FID,
anatofuz
parents:
diff changeset
824 const LangOptions &LangOpts) {
anatofuz
parents:
diff changeset
825 // Create a raw lexer to pull all the comments out of FID.
anatofuz
parents:
diff changeset
826 if (FID.isInvalid())
anatofuz
parents:
diff changeset
827 return false;
anatofuz
parents:
diff changeset
828
anatofuz
parents:
diff changeset
829 // Create a lexer to lex all the tokens of the main file in raw mode.
anatofuz
parents:
diff changeset
830 const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
anatofuz
parents:
diff changeset
831 Lexer RawLex(FID, FromFile, SM, LangOpts);
anatofuz
parents:
diff changeset
832
anatofuz
parents:
diff changeset
833 // Return comments as tokens, this is how we find expected diagnostics.
anatofuz
parents:
diff changeset
834 RawLex.SetCommentRetentionState(true);
anatofuz
parents:
diff changeset
835
anatofuz
parents:
diff changeset
836 Token Tok;
anatofuz
parents:
diff changeset
837 Tok.setKind(tok::comment);
anatofuz
parents:
diff changeset
838 VerifyDiagnosticConsumer::DirectiveStatus Status =
anatofuz
parents:
diff changeset
839 VerifyDiagnosticConsumer::HasNoDirectives;
anatofuz
parents:
diff changeset
840 while (Tok.isNot(tok::eof)) {
anatofuz
parents:
diff changeset
841 RawLex.LexFromRawLexer(Tok);
anatofuz
parents:
diff changeset
842 if (!Tok.is(tok::comment)) continue;
anatofuz
parents:
diff changeset
843
anatofuz
parents:
diff changeset
844 std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts);
anatofuz
parents:
diff changeset
845 if (Comment.empty()) continue;
anatofuz
parents:
diff changeset
846
anatofuz
parents:
diff changeset
847 // We don't care about tracking markers for this phase.
anatofuz
parents:
diff changeset
848 VerifyDiagnosticConsumer::MarkerTracker Markers(SM.getDiagnostics());
anatofuz
parents:
diff changeset
849
anatofuz
parents:
diff changeset
850 // Find first directive.
anatofuz
parents:
diff changeset
851 if (ParseDirective(Comment, nullptr, SM, nullptr, Tok.getLocation(),
anatofuz
parents:
diff changeset
852 Status, Markers))
anatofuz
parents:
diff changeset
853 return true;
anatofuz
parents:
diff changeset
854 }
anatofuz
parents:
diff changeset
855 return false;
anatofuz
parents:
diff changeset
856 }
anatofuz
parents:
diff changeset
857 #endif // !NDEBUG
anatofuz
parents:
diff changeset
858
anatofuz
parents:
diff changeset
859 /// Takes a list of diagnostics that have been generated but not matched
anatofuz
parents:
diff changeset
860 /// by an expected-* directive and produces a diagnostic to the user from this.
anatofuz
parents:
diff changeset
861 static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
anatofuz
parents:
diff changeset
862 const_diag_iterator diag_begin,
anatofuz
parents:
diff changeset
863 const_diag_iterator diag_end,
anatofuz
parents:
diff changeset
864 const char *Kind) {
anatofuz
parents:
diff changeset
865 if (diag_begin == diag_end) return 0;
anatofuz
parents:
diff changeset
866
anatofuz
parents:
diff changeset
867 SmallString<256> Fmt;
anatofuz
parents:
diff changeset
868 llvm::raw_svector_ostream OS(Fmt);
anatofuz
parents:
diff changeset
869 for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
anatofuz
parents:
diff changeset
870 if (I->first.isInvalid() || !SourceMgr)
anatofuz
parents:
diff changeset
871 OS << "\n (frontend)";
anatofuz
parents:
diff changeset
872 else {
anatofuz
parents:
diff changeset
873 OS << "\n ";
anatofuz
parents:
diff changeset
874 if (const FileEntry *File = SourceMgr->getFileEntryForID(
anatofuz
parents:
diff changeset
875 SourceMgr->getFileID(I->first)))
anatofuz
parents:
diff changeset
876 OS << " File " << File->getName();
anatofuz
parents:
diff changeset
877 OS << " Line " << SourceMgr->getPresumedLineNumber(I->first);
anatofuz
parents:
diff changeset
878 }
anatofuz
parents:
diff changeset
879 OS << ": " << I->second;
anatofuz
parents:
diff changeset
880 }
anatofuz
parents:
diff changeset
881
anatofuz
parents:
diff changeset
882 Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
anatofuz
parents:
diff changeset
883 << Kind << /*Unexpected=*/true << OS.str();
anatofuz
parents:
diff changeset
884 return std::distance(diag_begin, diag_end);
anatofuz
parents:
diff changeset
885 }
anatofuz
parents:
diff changeset
886
anatofuz
parents:
diff changeset
887 /// Takes a list of diagnostics that were expected to have been generated
anatofuz
parents:
diff changeset
888 /// but were not and produces a diagnostic to the user from this.
anatofuz
parents:
diff changeset
889 static unsigned PrintExpected(DiagnosticsEngine &Diags,
anatofuz
parents:
diff changeset
890 SourceManager &SourceMgr,
anatofuz
parents:
diff changeset
891 std::vector<Directive *> &DL, const char *Kind) {
anatofuz
parents:
diff changeset
892 if (DL.empty())
anatofuz
parents:
diff changeset
893 return 0;
anatofuz
parents:
diff changeset
894
anatofuz
parents:
diff changeset
895 SmallString<256> Fmt;
anatofuz
parents:
diff changeset
896 llvm::raw_svector_ostream OS(Fmt);
anatofuz
parents:
diff changeset
897 for (const auto *D : DL) {
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
898 if (D->DiagnosticLoc.isInvalid() || D->MatchAnyFileAndLine)
150
anatofuz
parents:
diff changeset
899 OS << "\n File *";
anatofuz
parents:
diff changeset
900 else
anatofuz
parents:
diff changeset
901 OS << "\n File " << SourceMgr.getFilename(D->DiagnosticLoc);
anatofuz
parents:
diff changeset
902 if (D->MatchAnyLine)
anatofuz
parents:
diff changeset
903 OS << " Line *";
anatofuz
parents:
diff changeset
904 else
anatofuz
parents:
diff changeset
905 OS << " Line " << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
anatofuz
parents:
diff changeset
906 if (D->DirectiveLoc != D->DiagnosticLoc)
anatofuz
parents:
diff changeset
907 OS << " (directive at "
anatofuz
parents:
diff changeset
908 << SourceMgr.getFilename(D->DirectiveLoc) << ':'
anatofuz
parents:
diff changeset
909 << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << ')';
anatofuz
parents:
diff changeset
910 OS << ": " << D->Text;
anatofuz
parents:
diff changeset
911 }
anatofuz
parents:
diff changeset
912
anatofuz
parents:
diff changeset
913 Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
anatofuz
parents:
diff changeset
914 << Kind << /*Unexpected=*/false << OS.str();
anatofuz
parents:
diff changeset
915 return DL.size();
anatofuz
parents:
diff changeset
916 }
anatofuz
parents:
diff changeset
917
anatofuz
parents:
diff changeset
918 /// Determine whether two source locations come from the same file.
anatofuz
parents:
diff changeset
919 static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
anatofuz
parents:
diff changeset
920 SourceLocation DiagnosticLoc) {
anatofuz
parents:
diff changeset
921 while (DiagnosticLoc.isMacroID())
anatofuz
parents:
diff changeset
922 DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc);
anatofuz
parents:
diff changeset
923
anatofuz
parents:
diff changeset
924 if (SM.isWrittenInSameFile(DirectiveLoc, DiagnosticLoc))
anatofuz
parents:
diff changeset
925 return true;
anatofuz
parents:
diff changeset
926
anatofuz
parents:
diff changeset
927 const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc));
anatofuz
parents:
diff changeset
928 if (!DiagFile && SM.isWrittenInMainFile(DirectiveLoc))
anatofuz
parents:
diff changeset
929 return true;
anatofuz
parents:
diff changeset
930
anatofuz
parents:
diff changeset
931 return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
anatofuz
parents:
diff changeset
932 }
anatofuz
parents:
diff changeset
933
anatofuz
parents:
diff changeset
934 /// CheckLists - Compare expected to seen diagnostic lists and return the
anatofuz
parents:
diff changeset
935 /// the difference between them.
anatofuz
parents:
diff changeset
936 static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
anatofuz
parents:
diff changeset
937 const char *Label,
anatofuz
parents:
diff changeset
938 DirectiveList &Left,
anatofuz
parents:
diff changeset
939 const_diag_iterator d2_begin,
anatofuz
parents:
diff changeset
940 const_diag_iterator d2_end,
anatofuz
parents:
diff changeset
941 bool IgnoreUnexpected) {
anatofuz
parents:
diff changeset
942 std::vector<Directive *> LeftOnly;
anatofuz
parents:
diff changeset
943 DiagList Right(d2_begin, d2_end);
anatofuz
parents:
diff changeset
944
anatofuz
parents:
diff changeset
945 for (auto &Owner : Left) {
anatofuz
parents:
diff changeset
946 Directive &D = *Owner;
anatofuz
parents:
diff changeset
947 unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
anatofuz
parents:
diff changeset
948
anatofuz
parents:
diff changeset
949 for (unsigned i = 0; i < D.Max; ++i) {
anatofuz
parents:
diff changeset
950 DiagList::iterator II, IE;
anatofuz
parents:
diff changeset
951 for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
anatofuz
parents:
diff changeset
952 if (!D.MatchAnyLine) {
anatofuz
parents:
diff changeset
953 unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
anatofuz
parents:
diff changeset
954 if (LineNo1 != LineNo2)
anatofuz
parents:
diff changeset
955 continue;
anatofuz
parents:
diff changeset
956 }
anatofuz
parents:
diff changeset
957
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
958 if (!D.DiagnosticLoc.isInvalid() && !D.MatchAnyFileAndLine &&
150
anatofuz
parents:
diff changeset
959 !IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
anatofuz
parents:
diff changeset
960 continue;
anatofuz
parents:
diff changeset
961
anatofuz
parents:
diff changeset
962 const std::string &RightText = II->second;
anatofuz
parents:
diff changeset
963 if (D.match(RightText))
anatofuz
parents:
diff changeset
964 break;
anatofuz
parents:
diff changeset
965 }
anatofuz
parents:
diff changeset
966 if (II == IE) {
anatofuz
parents:
diff changeset
967 // Not found.
anatofuz
parents:
diff changeset
968 if (i >= D.Min) break;
anatofuz
parents:
diff changeset
969 LeftOnly.push_back(&D);
anatofuz
parents:
diff changeset
970 } else {
anatofuz
parents:
diff changeset
971 // Found. The same cannot be found twice.
anatofuz
parents:
diff changeset
972 Right.erase(II);
anatofuz
parents:
diff changeset
973 }
anatofuz
parents:
diff changeset
974 }
anatofuz
parents:
diff changeset
975 }
anatofuz
parents:
diff changeset
976 // Now all that's left in Right are those that were not matched.
anatofuz
parents:
diff changeset
977 unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label);
anatofuz
parents:
diff changeset
978 if (!IgnoreUnexpected)
anatofuz
parents:
diff changeset
979 num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
anatofuz
parents:
diff changeset
980 return num;
anatofuz
parents:
diff changeset
981 }
anatofuz
parents:
diff changeset
982
anatofuz
parents:
diff changeset
983 /// CheckResults - This compares the expected results to those that
anatofuz
parents:
diff changeset
984 /// were actually reported. It emits any discrepencies. Return "true" if there
anatofuz
parents:
diff changeset
985 /// were problems. Return "false" otherwise.
anatofuz
parents:
diff changeset
986 static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
anatofuz
parents:
diff changeset
987 const TextDiagnosticBuffer &Buffer,
anatofuz
parents:
diff changeset
988 ExpectedData &ED) {
anatofuz
parents:
diff changeset
989 // We want to capture the delta between what was expected and what was
anatofuz
parents:
diff changeset
990 // seen.
anatofuz
parents:
diff changeset
991 //
anatofuz
parents:
diff changeset
992 // Expected \ Seen - set expected but not seen
anatofuz
parents:
diff changeset
993 // Seen \ Expected - set seen but not expected
anatofuz
parents:
diff changeset
994 unsigned NumProblems = 0;
anatofuz
parents:
diff changeset
995
anatofuz
parents:
diff changeset
996 const DiagnosticLevelMask DiagMask =
anatofuz
parents:
diff changeset
997 Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();
anatofuz
parents:
diff changeset
998
anatofuz
parents:
diff changeset
999 // See if there are error mismatches.
anatofuz
parents:
diff changeset
1000 NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
anatofuz
parents:
diff changeset
1001 Buffer.err_begin(), Buffer.err_end(),
anatofuz
parents:
diff changeset
1002 bool(DiagnosticLevelMask::Error & DiagMask));
anatofuz
parents:
diff changeset
1003
anatofuz
parents:
diff changeset
1004 // See if there are warning mismatches.
anatofuz
parents:
diff changeset
1005 NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
anatofuz
parents:
diff changeset
1006 Buffer.warn_begin(), Buffer.warn_end(),
anatofuz
parents:
diff changeset
1007 bool(DiagnosticLevelMask::Warning & DiagMask));
anatofuz
parents:
diff changeset
1008
anatofuz
parents:
diff changeset
1009 // See if there are remark mismatches.
anatofuz
parents:
diff changeset
1010 NumProblems += CheckLists(Diags, SourceMgr, "remark", ED.Remarks,
anatofuz
parents:
diff changeset
1011 Buffer.remark_begin(), Buffer.remark_end(),
anatofuz
parents:
diff changeset
1012 bool(DiagnosticLevelMask::Remark & DiagMask));
anatofuz
parents:
diff changeset
1013
anatofuz
parents:
diff changeset
1014 // See if there are note mismatches.
anatofuz
parents:
diff changeset
1015 NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
anatofuz
parents:
diff changeset
1016 Buffer.note_begin(), Buffer.note_end(),
anatofuz
parents:
diff changeset
1017 bool(DiagnosticLevelMask::Note & DiagMask));
anatofuz
parents:
diff changeset
1018
anatofuz
parents:
diff changeset
1019 return NumProblems;
anatofuz
parents:
diff changeset
1020 }
anatofuz
parents:
diff changeset
1021
anatofuz
parents:
diff changeset
1022 void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM,
anatofuz
parents:
diff changeset
1023 FileID FID,
anatofuz
parents:
diff changeset
1024 ParsedStatus PS) {
anatofuz
parents:
diff changeset
1025 // Check SourceManager hasn't changed.
anatofuz
parents:
diff changeset
1026 setSourceManager(SM);
anatofuz
parents:
diff changeset
1027
anatofuz
parents:
diff changeset
1028 #ifndef NDEBUG
anatofuz
parents:
diff changeset
1029 if (FID.isInvalid())
anatofuz
parents:
diff changeset
1030 return;
anatofuz
parents:
diff changeset
1031
anatofuz
parents:
diff changeset
1032 const FileEntry *FE = SM.getFileEntryForID(FID);
anatofuz
parents:
diff changeset
1033
anatofuz
parents:
diff changeset
1034 if (PS == IsParsed) {
anatofuz
parents:
diff changeset
1035 // Move the FileID from the unparsed set to the parsed set.
anatofuz
parents:
diff changeset
1036 UnparsedFiles.erase(FID);
anatofuz
parents:
diff changeset
1037 ParsedFiles.insert(std::make_pair(FID, FE));
anatofuz
parents:
diff changeset
1038 } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
anatofuz
parents:
diff changeset
1039 // Add the FileID to the unparsed set if we haven't seen it before.
anatofuz
parents:
diff changeset
1040
anatofuz
parents:
diff changeset
1041 // Check for directives.
anatofuz
parents:
diff changeset
1042 bool FoundDirectives;
anatofuz
parents:
diff changeset
1043 if (PS == IsUnparsedNoDirectives)
anatofuz
parents:
diff changeset
1044 FoundDirectives = false;
anatofuz
parents:
diff changeset
1045 else
anatofuz
parents:
diff changeset
1046 FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts);
anatofuz
parents:
diff changeset
1047
anatofuz
parents:
diff changeset
1048 // Add the FileID to the unparsed set.
anatofuz
parents:
diff changeset
1049 UnparsedFiles.insert(std::make_pair(FID,
anatofuz
parents:
diff changeset
1050 UnparsedFileStatus(FE, FoundDirectives)));
anatofuz
parents:
diff changeset
1051 }
anatofuz
parents:
diff changeset
1052 #endif
anatofuz
parents:
diff changeset
1053 }
anatofuz
parents:
diff changeset
1054
anatofuz
parents:
diff changeset
1055 void VerifyDiagnosticConsumer::CheckDiagnostics() {
anatofuz
parents:
diff changeset
1056 // Ensure any diagnostics go to the primary client.
anatofuz
parents:
diff changeset
1057 DiagnosticConsumer *CurClient = Diags.getClient();
anatofuz
parents:
diff changeset
1058 std::unique_ptr<DiagnosticConsumer> Owner = Diags.takeClient();
anatofuz
parents:
diff changeset
1059 Diags.setClient(PrimaryClient, false);
anatofuz
parents:
diff changeset
1060
anatofuz
parents:
diff changeset
1061 #ifndef NDEBUG
anatofuz
parents:
diff changeset
1062 // In a debug build, scan through any files that may have been missed
anatofuz
parents:
diff changeset
1063 // during parsing and issue a fatal error if directives are contained
anatofuz
parents:
diff changeset
1064 // within these files. If a fatal error occurs, this suggests that
anatofuz
parents:
diff changeset
1065 // this file is being parsed separately from the main file, in which
anatofuz
parents:
diff changeset
1066 // case consider moving the directives to the correct place, if this
anatofuz
parents:
diff changeset
1067 // is applicable.
anatofuz
parents:
diff changeset
1068 if (!UnparsedFiles.empty()) {
anatofuz
parents:
diff changeset
1069 // Generate a cache of parsed FileEntry pointers for alias lookups.
anatofuz
parents:
diff changeset
1070 llvm::SmallPtrSet<const FileEntry *, 8> ParsedFileCache;
anatofuz
parents:
diff changeset
1071 for (const auto &I : ParsedFiles)
anatofuz
parents:
diff changeset
1072 if (const FileEntry *FE = I.second)
anatofuz
parents:
diff changeset
1073 ParsedFileCache.insert(FE);
anatofuz
parents:
diff changeset
1074
anatofuz
parents:
diff changeset
1075 // Iterate through list of unparsed files.
anatofuz
parents:
diff changeset
1076 for (const auto &I : UnparsedFiles) {
anatofuz
parents:
diff changeset
1077 const UnparsedFileStatus &Status = I.second;
anatofuz
parents:
diff changeset
1078 const FileEntry *FE = Status.getFile();
anatofuz
parents:
diff changeset
1079
anatofuz
parents:
diff changeset
1080 // Skip files that have been parsed via an alias.
anatofuz
parents:
diff changeset
1081 if (FE && ParsedFileCache.count(FE))
anatofuz
parents:
diff changeset
1082 continue;
anatofuz
parents:
diff changeset
1083
anatofuz
parents:
diff changeset
1084 // Report a fatal error if this file contained directives.
anatofuz
parents:
diff changeset
1085 if (Status.foundDirectives()) {
anatofuz
parents:
diff changeset
1086 llvm::report_fatal_error(Twine("-verify directives found after rather"
anatofuz
parents:
diff changeset
1087 " than during normal parsing of ",
anatofuz
parents:
diff changeset
1088 StringRef(FE ? FE->getName() : "(unknown)")));
anatofuz
parents:
diff changeset
1089 }
anatofuz
parents:
diff changeset
1090 }
anatofuz
parents:
diff changeset
1091
anatofuz
parents:
diff changeset
1092 // UnparsedFiles has been processed now, so clear it.
anatofuz
parents:
diff changeset
1093 UnparsedFiles.clear();
anatofuz
parents:
diff changeset
1094 }
anatofuz
parents:
diff changeset
1095 #endif // !NDEBUG
anatofuz
parents:
diff changeset
1096
anatofuz
parents:
diff changeset
1097 if (SrcManager) {
anatofuz
parents:
diff changeset
1098 // Produce an error if no expected-* directives could be found in the
anatofuz
parents:
diff changeset
1099 // source file(s) processed.
anatofuz
parents:
diff changeset
1100 if (Status == HasNoDirectives) {
anatofuz
parents:
diff changeset
1101 Diags.Report(diag::err_verify_no_directives).setForceEmit();
anatofuz
parents:
diff changeset
1102 ++NumErrors;
anatofuz
parents:
diff changeset
1103 Status = HasNoDirectivesReported;
anatofuz
parents:
diff changeset
1104 }
anatofuz
parents:
diff changeset
1105
anatofuz
parents:
diff changeset
1106 // Check that the expected diagnostics occurred.
anatofuz
parents:
diff changeset
1107 NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
anatofuz
parents:
diff changeset
1108 } else {
anatofuz
parents:
diff changeset
1109 const DiagnosticLevelMask DiagMask =
anatofuz
parents:
diff changeset
1110 ~Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();
anatofuz
parents:
diff changeset
1111 if (bool(DiagnosticLevelMask::Error & DiagMask))
anatofuz
parents:
diff changeset
1112 NumErrors += PrintUnexpected(Diags, nullptr, Buffer->err_begin(),
anatofuz
parents:
diff changeset
1113 Buffer->err_end(), "error");
anatofuz
parents:
diff changeset
1114 if (bool(DiagnosticLevelMask::Warning & DiagMask))
anatofuz
parents:
diff changeset
1115 NumErrors += PrintUnexpected(Diags, nullptr, Buffer->warn_begin(),
anatofuz
parents:
diff changeset
1116 Buffer->warn_end(), "warn");
anatofuz
parents:
diff changeset
1117 if (bool(DiagnosticLevelMask::Remark & DiagMask))
anatofuz
parents:
diff changeset
1118 NumErrors += PrintUnexpected(Diags, nullptr, Buffer->remark_begin(),
anatofuz
parents:
diff changeset
1119 Buffer->remark_end(), "remark");
anatofuz
parents:
diff changeset
1120 if (bool(DiagnosticLevelMask::Note & DiagMask))
anatofuz
parents:
diff changeset
1121 NumErrors += PrintUnexpected(Diags, nullptr, Buffer->note_begin(),
anatofuz
parents:
diff changeset
1122 Buffer->note_end(), "note");
anatofuz
parents:
diff changeset
1123 }
anatofuz
parents:
diff changeset
1124
anatofuz
parents:
diff changeset
1125 Diags.setClient(CurClient, Owner.release() != nullptr);
anatofuz
parents:
diff changeset
1126
anatofuz
parents:
diff changeset
1127 // Reset the buffer, we have processed all the diagnostics in it.
anatofuz
parents:
diff changeset
1128 Buffer.reset(new TextDiagnosticBuffer());
anatofuz
parents:
diff changeset
1129 ED.Reset();
anatofuz
parents:
diff changeset
1130 }
anatofuz
parents:
diff changeset
1131
anatofuz
parents:
diff changeset
1132 std::unique_ptr<Directive> Directive::create(bool RegexKind,
anatofuz
parents:
diff changeset
1133 SourceLocation DirectiveLoc,
anatofuz
parents:
diff changeset
1134 SourceLocation DiagnosticLoc,
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1135 bool MatchAnyFileAndLine,
150
anatofuz
parents:
diff changeset
1136 bool MatchAnyLine, StringRef Text,
anatofuz
parents:
diff changeset
1137 unsigned Min, unsigned Max) {
anatofuz
parents:
diff changeset
1138 if (!RegexKind)
anatofuz
parents:
diff changeset
1139 return std::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1140 MatchAnyFileAndLine,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1141 MatchAnyLine, Text, Min, Max);
150
anatofuz
parents:
diff changeset
1142
anatofuz
parents:
diff changeset
1143 // Parse the directive into a regular expression.
anatofuz
parents:
diff changeset
1144 std::string RegexStr;
anatofuz
parents:
diff changeset
1145 StringRef S = Text;
anatofuz
parents:
diff changeset
1146 while (!S.empty()) {
anatofuz
parents:
diff changeset
1147 if (S.startswith("{{")) {
anatofuz
parents:
diff changeset
1148 S = S.drop_front(2);
anatofuz
parents:
diff changeset
1149 size_t RegexMatchLength = S.find("}}");
anatofuz
parents:
diff changeset
1150 assert(RegexMatchLength != StringRef::npos);
anatofuz
parents:
diff changeset
1151 // Append the regex, enclosed in parentheses.
anatofuz
parents:
diff changeset
1152 RegexStr += "(";
anatofuz
parents:
diff changeset
1153 RegexStr.append(S.data(), RegexMatchLength);
anatofuz
parents:
diff changeset
1154 RegexStr += ")";
anatofuz
parents:
diff changeset
1155 S = S.drop_front(RegexMatchLength + 2);
anatofuz
parents:
diff changeset
1156 } else {
anatofuz
parents:
diff changeset
1157 size_t VerbatimMatchLength = S.find("{{");
anatofuz
parents:
diff changeset
1158 if (VerbatimMatchLength == StringRef::npos)
anatofuz
parents:
diff changeset
1159 VerbatimMatchLength = S.size();
anatofuz
parents:
diff changeset
1160 // Escape and append the fixed string.
anatofuz
parents:
diff changeset
1161 RegexStr += llvm::Regex::escape(S.substr(0, VerbatimMatchLength));
anatofuz
parents:
diff changeset
1162 S = S.drop_front(VerbatimMatchLength);
anatofuz
parents:
diff changeset
1163 }
anatofuz
parents:
diff changeset
1164 }
anatofuz
parents:
diff changeset
1165
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1166 return std::make_unique<RegexDirective>(DirectiveLoc, DiagnosticLoc,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1167 MatchAnyFileAndLine, MatchAnyLine,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1168 Text, Min, Max, RegexStr);
150
anatofuz
parents:
diff changeset
1169 }