blob: 58ab40361ba2477d76fb300543e99801a8291eb8 [file] [log] [blame]
Chris Lattnera092b142007-06-27 17:24:55 +00001//===--- DiagChecker.cpp - Diagnostic Checking Functions ------------------===//
Bill Wendling469211a2007-06-27 03:19:45 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Bill Wendling and is distributed under the
6// University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Process the input files and check that the diagnostic messages are expected.
11//
12//===----------------------------------------------------------------------===//
13
Chris Lattner23e63532007-06-28 04:54:17 +000014#include "clang.h"
Bill Wendling469211a2007-06-27 03:19:45 +000015#include "ASTStreamers.h"
Chris Lattner23e63532007-06-28 04:54:17 +000016#include "TextDiagnosticBuffer.h"
Bill Wendling469211a2007-06-27 03:19:45 +000017#include "clang/Basic/SourceManager.h"
18#include "clang/Lex/Preprocessor.h"
19using namespace clang;
20
Bill Wendling52b0a4e2007-06-27 07:24:11 +000021typedef TextDiagnosticBuffer::DiagList DiagList;
22
Bill Wendling469211a2007-06-27 03:19:45 +000023// USING THE DIAGNOSTIC CHECKER:
24//
25// Indicating that a line expects an error or a warning is simple. Put a comment
26// on the line that has the diagnostic, use "expected-{error,warning}" to tag
27// if it's an expected error or warning, and place the expected text between {{
28// and }} markers. The full text doesn't have to be included, only enough to
29// ensure that the correct diagnostic was emitted.
30//
31// Here's an example:
32//
33// int A = B; // expected-error {{use of undeclared identifier 'B'}}
34//
35// You can place as many diagnostics on one line as you wish. To make the code
36// more readable, you can use slash-newline to separate out the diagnostics.
37
38static const char * const ExpectedErrStr = "expected-error";
39static const char * const ExpectedWarnStr = "expected-warning";
40
41/// FindDiagnostics - Go through the comment and see if it indicates expected
42/// diagnostics. If so, then put them in a diagnostic list.
43///
44static void FindDiagnostics(const std::string &Comment,
Bill Wendling469211a2007-06-27 03:19:45 +000045 DiagList &ExpectedDiags,
46 SourceManager &SourceMgr,
47 SourceLocation Pos,
48 const char * const ExpectedStr) {
49 // Find all expected diagnostics
50 typedef std::string::size_type size_type;
51 size_type ColNo = std::string::npos;
52
53 for (;;) {
54 ColNo = Comment.find(ExpectedStr, ColNo);
55 if (ColNo == std::string::npos) break;
56
57 size_type OpenDiag = Comment.find_first_of("{{", ColNo);
58
59 if (OpenDiag == std::string::npos) {
60 fprintf(stderr,
61 "oops:%d: Cannot find beginning of expected error string\n",
62 SourceMgr.getLineNumber(Pos));
63 break;
64 }
65
66 OpenDiag += 2;
67 size_type CloseDiag = Comment.find_first_of("}}", OpenDiag);
68
69 if (CloseDiag == std::string::npos) {
70 fprintf(stderr,
71 "oops:%d: Cannot find end of expected error string\n",
72 SourceMgr.getLineNumber(Pos));
73 break;
74 }
75
76 std::string Msg(Comment.substr(OpenDiag, CloseDiag - OpenDiag));
77 ExpectedDiags.push_back(std::make_pair(Pos, Msg));
78 ColNo = CloseDiag + 2;
79 }
80}
81
82/// ProcessFileDiagnosticChecking - This lexes the file and finds all of the
83/// expected errors and warnings. It then does the actual parsing of the
84/// program. The parsing will report its diagnostics, and a function can be
85/// called later to report any discrepencies between the diagnostics expected
86/// and those actually seen.
87///
Chris Lattner0d210462007-06-28 05:10:07 +000088static void ProcessFileDiagnosticChecking(Preprocessor &PP,
Bill Wendling469211a2007-06-27 03:19:45 +000089 unsigned MainFileID,
90 DiagList &ExpectedErrors,
91 DiagList &ExpectedWarnings) {
Chris Lattner23e63532007-06-28 04:54:17 +000092 // Return comments as tokens, this is how we find expected diagnostics.
Bill Wendling469211a2007-06-27 03:19:45 +000093 PP.SetCommentRetentionState(true, true);
94
95 // Enter the cave.
96 PP.EnterSourceFile(MainFileID, 0, true);
97
Chris Lattner23e63532007-06-28 04:54:17 +000098 LexerToken Tok;
Bill Wendling469211a2007-06-27 03:19:45 +000099 do {
100 PP.Lex(Tok);
101
102 if (Tok.getKind() == tok::comment) {
103 std::string Comment = PP.getSpelling(Tok);
104
105 // Find all expected errors
Chris Lattner0d210462007-06-28 05:10:07 +0000106 FindDiagnostics(Comment, ExpectedErrors,PP.getSourceManager(),
Bill Wendling469211a2007-06-27 03:19:45 +0000107 Tok.getLocation(), ExpectedErrStr);
108
109 // Find all expected warnings
Chris Lattner0d210462007-06-28 05:10:07 +0000110 FindDiagnostics(Comment, ExpectedWarnings, PP.getSourceManager(),
111 Tok.getLocation(), ExpectedWarnStr);
Bill Wendling469211a2007-06-27 03:19:45 +0000112 }
113 } while (Tok.getKind() != tok::eof);
114
115 // Parsing the specified input file.
116 PP.SetCommentRetentionState(false, false);
117 BuildASTs(PP, MainFileID, false);
118}
119
120typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
121
122/// PrintProblem - This takes a diagnostic map of the delta between expected and
123/// seen diagnostics. If there's anything in it, then something unexpected
124/// happened. Print the map out in a nice format and return "true". If the map
125/// is empty and we're not going to print things, then return "false".
126///
127static bool PrintProblem(SourceManager &SourceMgr,
128 const_diag_iterator diag_begin,
129 const_diag_iterator diag_end,
130 const char *Msg) {
131 if (diag_begin == diag_end) return false;
132
133 fprintf(stderr, "%s\n", Msg);
134
Bill Wendling97d41462007-06-27 04:06:59 +0000135 for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I)
Chris Lattnerc2d81632007-06-27 17:26:23 +0000136 fprintf(stderr, " Line %d: %s\n",
Bill Wendling97d41462007-06-27 04:06:59 +0000137 SourceMgr.getLineNumber(I->first),
138 I->second.c_str());
Bill Wendling469211a2007-06-27 03:19:45 +0000139
140 return true;
141}
142
143/// CompareDiagLists - Compare two diangnostic lists and return the difference
144/// between them.
145///
146static bool CompareDiagLists(SourceManager &SourceMgr,
147 const_diag_iterator d1_begin,
148 const_diag_iterator d1_end,
149 const_diag_iterator d2_begin,
150 const_diag_iterator d2_end,
151 const char *Msg) {
Bill Wendling52b0a4e2007-06-27 07:24:11 +0000152 DiagList DiffList;
Bill Wendling469211a2007-06-27 03:19:45 +0000153
Bill Wendling97d41462007-06-27 04:06:59 +0000154 for (const_diag_iterator I = d1_begin, E = d1_end; I != E; ++I) {
Bill Wendlinga5b3bb12007-06-27 07:43:27 +0000155 unsigned LineNo1 = SourceMgr.getLineNumber(I->first);
Bill Wendling97d41462007-06-27 04:06:59 +0000156 const std::string &Diag1 = I->second;
Bill Wendling469211a2007-06-27 03:19:45 +0000157 bool Found = false;
158
Bill Wendling97d41462007-06-27 04:06:59 +0000159 for (const_diag_iterator II = d2_begin, IE = d2_end; II != IE; ++II) {
Bill Wendlinga5b3bb12007-06-27 07:43:27 +0000160 unsigned LineNo2 = SourceMgr.getLineNumber(II->first);
161 if (LineNo1 != LineNo2) continue;
Bill Wendling97d41462007-06-27 04:06:59 +0000162
Bill Wendlinga5b3bb12007-06-27 07:43:27 +0000163 const std::string &Diag2 = II->second;
Bill Wendling97d41462007-06-27 04:06:59 +0000164 if (Diag2.find(Diag1) != std::string::npos ||
165 Diag1.find(Diag2) != std::string::npos) {
Bill Wendling469211a2007-06-27 03:19:45 +0000166 Found = true;
167 break;
168 }
169 }
170
171 if (!Found)
Bill Wendlinga5b3bb12007-06-27 07:43:27 +0000172 DiffList.push_back(std::make_pair(I->first, Diag1));
Bill Wendling469211a2007-06-27 03:19:45 +0000173 }
174
175 return PrintProblem(SourceMgr, DiffList.begin(), DiffList.end(), Msg);
176}
177
178/// ReportCheckingResults - This compares the expected results to those that
179/// were actually reported. It emits any discrepencies. Return "true" if there
180/// were problems. Return "false" otherwise.
181///
Chris Lattner23e63532007-06-28 04:54:17 +0000182static bool ReportCheckingResults(const TextDiagnosticBuffer &DiagClient,
Bill Wendling469211a2007-06-27 03:19:45 +0000183 const DiagList &ExpectedErrors,
184 const DiagList &ExpectedWarnings,
185 SourceManager &SourceMgr) {
186 // We want to capture the delta between what was expected and what was
187 // seen.
188 //
189 // Expected \ Seen - set expected but not seen
190 // Seen \ Expected - set seen but not expected
191 bool HadProblem = false;
192
193 // See if there were errors that were expected but not seen.
194 HadProblem |= CompareDiagLists(SourceMgr,
195 ExpectedErrors.begin(), ExpectedErrors.end(),
196 DiagClient.err_begin(), DiagClient.err_end(),
197 "Errors expected but not seen:");
198
199 // See if there were errors that were seen but not expected.
200 HadProblem |= CompareDiagLists(SourceMgr,
201 DiagClient.err_begin(), DiagClient.err_end(),
202 ExpectedErrors.begin(), ExpectedErrors.end(),
203 "Errors seen but not expected:");
204
205 // See if there were warnings that were expected but not seen.
206 HadProblem |= CompareDiagLists(SourceMgr,
207 ExpectedWarnings.begin(),
208 ExpectedWarnings.end(),
209 DiagClient.warn_begin(), DiagClient.warn_end(),
210 "Warnings expected but not seen:");
211
212 // See if there were warnings that were seen but not expected.
213 HadProblem |= CompareDiagLists(SourceMgr,
214 DiagClient.warn_begin(), DiagClient.warn_end(),
215 ExpectedWarnings.begin(),
216 ExpectedWarnings.end(),
217 "Warnings seen but not expected:");
218
219 return HadProblem;
220}
Chris Lattner23e63532007-06-28 04:54:17 +0000221
222/// CheckDiagnostics - Implement the -parse-ast-check diagnostic verifier.
223bool clang::CheckDiagnostics(Preprocessor &PP, unsigned MainFileID) {
Chris Lattner23e63532007-06-28 04:54:17 +0000224 // Gather the set of expected diagnostics.
225 DiagList ExpectedErrors, ExpectedWarnings;
Chris Lattner0d210462007-06-28 05:10:07 +0000226 ProcessFileDiagnosticChecking(PP, MainFileID, ExpectedErrors,
Chris Lattner23e63532007-06-28 04:54:17 +0000227 ExpectedWarnings);
228
Chris Lattner0d210462007-06-28 05:10:07 +0000229 const TextDiagnosticBuffer &Diags =
230 static_cast<const TextDiagnosticBuffer&>(PP.getDiagnostics().getClient());
Chris Lattner23e63532007-06-28 04:54:17 +0000231
232 return ReportCheckingResults(Diags, ExpectedErrors,
233 ExpectedWarnings, PP.getSourceManager());
234}
235
236