aboutsummaryrefslogtreecommitdiff
path: root/lib/Frontend
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Frontend')
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp118
1 files changed, 90 insertions, 28 deletions
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 236b700662..8aa65f1f1f 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/FileManager.h"
#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
@@ -43,15 +44,15 @@ VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
const Preprocessor *PP) {
- // FIXME: Const hack, we screw up the preprocessor but in practice its ok
- // because it doesn't get reused. It would be better if we could make a copy
- // though.
- CurrentPreprocessor = const_cast<Preprocessor*>(PP);
+ CurrentPreprocessor = PP;
+ if (PP) const_cast<Preprocessor*>(PP)->addCommentHandler(this);
PrimaryClient->BeginSourceFile(LangOpts, PP);
}
void VerifyDiagnosticConsumer::EndSourceFile() {
+ if (CurrentPreprocessor)
+ const_cast<Preprocessor*>(CurrentPreprocessor)->removeCommentHandler(this);
CheckDiagnostics();
PrimaryClient->EndSourceFile();
@@ -61,9 +62,9 @@ void VerifyDiagnosticConsumer::EndSourceFile() {
void VerifyDiagnosticConsumer::HandleDiagnostic(
DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
- if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) {
+ if (Info.hasSourceManager()) {
const SourceManager &SM = Info.getSourceManager();
- FirstErrorFID = SM.getFileID(Info.getLocation());
+ FilesWithDiagnostics.insert(SM.getFileID(Info.getLocation()));
}
// Send the diagnostic to the buffer, we will check it once we reach the end
// of the source file (or are destructed).
@@ -122,8 +123,8 @@ private:
class ParseHelper
{
public:
- ParseHelper(const char *Begin, const char *End)
- : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { }
+ ParseHelper(StringRef S)
+ : Begin(S.begin()), End(S.end()), C(Begin), P(Begin), PEnd(NULL) { }
// Return true if string literal is next.
bool Next(StringRef S) {
@@ -190,11 +191,12 @@ private:
/// ParseDirective - Go through the comment and see if it indicates expected
/// diagnostics. If so, then put them in the appropriate directive list.
///
-static void ParseDirective(const char *CommentStart, unsigned CommentLen,
- ExpectedData &ED, SourceManager &SM,
+/// Returns true if any valid directives were found.
+static bool ParseDirective(StringRef S, ExpectedData &ED, SourceManager &SM,
SourceLocation Pos, DiagnosticsEngine &Diags) {
// A single comment may contain multiple directives.
- for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) {
+ bool FoundDirective = false;
+ for (ParseHelper PH(S); !PH.Done();) {
// Search for token: expected
if (!PH.Search("expected"))
break;
@@ -329,19 +331,77 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen,
Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text,
Min, Max);
std::string Error;
- if (D->isValid(Error))
+ if (D->isValid(Error)) {
DL->push_back(D);
- else {
+ FoundDirective = true;
+ } else {
Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
diag::err_verify_invalid_content)
<< KindStr << Error;
}
}
+
+ return FoundDirective;
+}
+
+/// HandleComment - Hook into the preprocessor and extract comments containing
+/// expected errors and warnings.
+bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
+ SourceRange Comment) {
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation CommentBegin = Comment.getBegin();
+
+ const char *CommentRaw = SM.getCharacterData(CommentBegin);
+ StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw);
+
+ if (C.empty())
+ return false;
+
+ // Fold any "\<EOL>" sequences
+ size_t loc = C.find('\\');
+ if (loc == StringRef::npos) {
+ if (ParseDirective(C, ED, SM, CommentBegin, PP.getDiagnostics()))
+ if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(CommentBegin)))
+ FilesWithDirectives.insert(E);
+ return false;
+ }
+
+ std::string C2;
+ C2.reserve(C.size());
+
+ for (size_t last = 0;; loc = C.find('\\', last)) {
+ if (loc == StringRef::npos || loc == C.size()) {
+ C2 += C.substr(last);
+ break;
+ }
+ C2 += C.substr(last, loc-last);
+ last = loc + 1;
+
+ if (C[last] == '\n' || C[last] == '\r') {
+ ++last;
+
+ // Escape \r\n or \n\r, but not \n\n.
+ if (last < C.size())
+ if (C[last] == '\n' || C[last] == '\r')
+ if (C[last] != C[last-1])
+ ++last;
+ } else {
+ // This was just a normal backslash.
+ C2 += '\\';
+ }
+ }
+
+ if (!C2.empty())
+ if (ParseDirective(C2, ED, SM, CommentBegin, PP.getDiagnostics()))
+ if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(CommentBegin)))
+ FilesWithDirectives.insert(E);
+ return false;
}
/// FindExpectedDiags - Lex the main source file to find all of the
// expected errors and warnings.
-static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) {
+static void FindExpectedDiags(const Preprocessor &PP, ExpectedData &ED,
+ FileID FID) {
// Create a raw lexer to pull all the comments out of FID.
if (FID.isInvalid())
return;
@@ -364,8 +424,7 @@ static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) {
if (Comment.empty()) continue;
// Find all expected errors/warnings/notes.
- ParseDirective(&Comment[0], Comment.size(), ED, SM, Tok.getLocation(),
- PP.getDiagnostics());
+ ParseDirective(Comment, ED, SM, Tok.getLocation(), PP.getDiagnostics());
};
}
@@ -497,18 +556,21 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
// markers. If not then any diagnostics are unexpected.
if (CurrentPreprocessor) {
SourceManager &SM = CurrentPreprocessor->getSourceManager();
- // Extract expected-error strings from main file.
- FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID());
- // Only check for expectations in other diagnostic locations
- // if they are not the main file (via ID or FileEntry) - the main
- // file has already been looked at, and its expectations must not
- // be added twice.
- if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID()
- && (!SM.getFileEntryForID(FirstErrorFID)
- || (SM.getFileEntryForID(FirstErrorFID) !=
- SM.getFileEntryForID(SM.getMainFileID())))) {
- FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID);
- FirstErrorFID = FileID();
+ // Only check for expectations in other diagnostic locations not
+ // captured during normal parsing.
+ // FIXME: This check is currently necessary while synthesized files may
+ // not have their expected-* directives captured during parsing. These
+ // cases should be fixed and the following loop replaced with one which
+ // checks only during a debug build and asserts on a mismatch.
+ for (FilesWithDiagnosticsSet::iterator I = FilesWithDiagnostics.begin(),
+ End = FilesWithDiagnostics.end();
+ I != End; ++I) {
+ const FileEntry *E = SM.getFileEntryForID(*I);
+ if (!E || !FilesWithDirectives.count(E)) {
+ if (E)
+ FilesWithDirectives.insert(E);
+ FindExpectedDiags(*CurrentPreprocessor, ED, *I);
+ }
}
// Check that the expected diagnostics occurred.