summaryrefslogtreecommitdiffstats
path: root/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2013-12-11 23:40:50 +0000
committerHans Wennborg <hans@hanshq.net>2013-12-11 23:40:50 +0000
commitcda4b6dd007c4726f36f4cd24271b49cc19f1f5a (patch)
treee6ce6c3b704e3032a58fac25b81be60e467c3d60 /clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
parent6030c84a2fc1b6f84494807d27bc96d8f522b5c0 (diff)
downloadbcm5719-llvm-cda4b6dd007c4726f36f4cd24271b49cc19f1f5a.tar.gz
bcm5719-llvm-cda4b6dd007c4726f36f4cd24271b49cc19f1f5a.zip
Change semantics of regex expectations in the diagnostic verifier
Previously, a line like // expected-error-re {{foo}} treats the entirety of foo as a regex. This is inconvenient when matching type names containing regex characters. For example, to match "void *(class test8::A::*)(void)" inside such a regex, one would have to type "void \*\(class test8::A::\*\)\(void\)". This patch changes the semantics of expected-error-re to only treat the parts of the directive wrapped in double curly braces as regexes. This avoids the escaping problem and leads to nicer patterns for those cases; see e.g. the change to test/Sema/format-strings-scanf.c. (The balanced search for closing }} of a directive also makes us handle the full directive in test\SemaCXX\constexpr-printing.cpp:41 and :53.) Differential Revision: http://llvm-reviews.chandlerc.com/D2388 llvm-svn: 197092
Diffstat (limited to 'clang/lib/Frontend/VerifyDiagnosticConsumer.cpp')
-rw-r--r--clang/lib/Frontend/VerifyDiagnosticConsumer.cpp97
1 files changed, 91 insertions, 6 deletions
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 77901a73e15..b53fde257de 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -181,8 +181,8 @@ public:
class RegexDirective : public Directive {
public:
RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
- StringRef Text, unsigned Min, unsigned Max)
- : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max), Regex(Text) { }
+ StringRef Text, unsigned Min, unsigned Max, StringRef RegexStr)
+ : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max), Regex(RegexStr) { }
virtual bool isValid(std::string &Error) {
if (Regex.isValid(Error))
@@ -249,6 +249,30 @@ public:
return false;
}
+ // Return true if a CloseBrace that closes the OpenBrace at the current nest
+ // level is found. When true, P marks begin-position of CloseBrace.
+ bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {
+ unsigned Depth = 1;
+ P = C;
+ while (P < End) {
+ StringRef S(P, End - P);
+ if (S.startswith(OpenBrace)) {
+ ++Depth;
+ P += OpenBrace.size();
+ } else if (S.startswith(CloseBrace)) {
+ --Depth;
+ if (Depth == 0) {
+ PEnd = P + CloseBrace.size();
+ return true;
+ }
+ P += CloseBrace.size();
+ } else {
+ ++P;
+ }
+ }
+ return false;
+ }
+
// Advance 1-past previous next/search.
// Behavior is undefined if previous next/search failed.
bool Advance() {
@@ -437,7 +461,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
const char* const ContentBegin = PH.C; // mark content begin
// Search for token: }}
- if (!PH.Search("}}")) {
+ if (!PH.SearchClosingBrace("{{", "}}")) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_end) << KindStr;
continue;
@@ -459,6 +483,13 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
if (Text.empty())
Text.assign(ContentBegin, ContentEnd);
+ // Check that regex directives contain at least one regex.
+ if (RegexKind && Text.find("{{") == StringRef::npos) {
+ Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
+ diag::err_verify_missing_regex) << Text;
+ return false;
+ }
+
// Construct new directive.
Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text,
Min, Max);
@@ -820,10 +851,64 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
ED.Notes.clear();
}
+// Add the characters from FixedStr to RegexStr, escaping as needed. This
+// avoids the need for backslash-escaping in common patterns.
+static void AddFixedStringToRegEx(StringRef FixedStr, std::string &RegexStr) {
+ // FIXME: Expose FileCheck.cpp's Pattern::AddFixedStringToRegEx as a utility
+ // method in RegEx.
+
+ for (unsigned i = 0, e = FixedStr.size(); i != e; ++i) {
+ switch (FixedStr[i]) {
+ // These are the special characters matched in "p_ere_exp".
+ case '(':
+ case ')':
+ case '^':
+ case '$':
+ case '|':
+ case '*':
+ case '+':
+ case '?':
+ case '.':
+ case '[':
+ case '\\':
+ case '{':
+ RegexStr += '\\';
+ // FALL THROUGH.
+ default:
+ RegexStr += FixedStr[i];
+ break;
+ }
+ }
+}
+
Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
SourceLocation DiagnosticLoc, StringRef Text,
unsigned Min, unsigned Max) {
- if (RegexKind)
- return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
- return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
+ if (!RegexKind)
+ return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
+
+ // Parse the directive into a regular expression.
+ std::string RegexStr;
+ StringRef S = Text;
+ while (!S.empty()) {
+ if (S.startswith("{{")) {
+ S = S.drop_front(2);
+ size_t RegexMatchLength = S.find("}}");
+ assert(RegexMatchLength != StringRef::npos);
+ // Append the regex, enclosed in parentheses.
+ RegexStr += "(";
+ RegexStr.append(S.data(), RegexMatchLength);
+ RegexStr += ")";
+ S = S.drop_front(RegexMatchLength + 2);
+ } else {
+ size_t VerbatimMatchLength = S.find("{{");
+ if (VerbatimMatchLength == StringRef::npos)
+ VerbatimMatchLength = S.size();
+ // Escape and append the fixed string.
+ AddFixedStringToRegEx(S.substr(0, VerbatimMatchLength), RegexStr);
+ S = S.drop_front(VerbatimMatchLength);
+ }
+ }
+
+ return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max, RegexStr);
}
OpenPOWER on IntegriCloud