forked from OSchip/llvm-project
Allow -verify directives to specify a min and max count, not just "+".
void f(); // expected-note 0+ {{previous declaration is here}} void g(); // expected-note 0-1 {{previous declaration is here}} The old "+" syntax is still an alias for "1+", and single numbers still work. Patch by Andy Gibbs! llvm-svn: 159979
This commit is contained in:
parent
e1572eb3e2
commit
b8b2ca6ffb
|
@ -65,6 +65,8 @@ def warn_fe_serialized_diag_failure : Warning<
|
||||||
|
|
||||||
def err_verify_missing_line : Error<
|
def err_verify_missing_line : Error<
|
||||||
"missing or invalid line number following '@' in expected %0">;
|
"missing or invalid line number following '@' in expected %0">;
|
||||||
|
def err_verify_invalid_range : Error<
|
||||||
|
"invalid range following '-' in expected %0">;
|
||||||
def err_verify_missing_start : Error<
|
def err_verify_missing_start : Error<
|
||||||
"cannot find start ('{{') of expected %0">;
|
"cannot find start ('{{') of expected %0">;
|
||||||
def err_verify_missing_end : Error<
|
def err_verify_missing_end : Error<
|
||||||
|
|
|
@ -47,8 +47,10 @@ class TextDiagnosticBuffer;
|
||||||
/// Alternatively, it is possible to specify the line on which the diagnostic
|
/// Alternatively, it is possible to specify the line on which the diagnostic
|
||||||
/// should appear by appending "@<line>" to "expected-<type>", for example:
|
/// should appear by appending "@<line>" to "expected-<type>", for example:
|
||||||
///
|
///
|
||||||
|
/// \code
|
||||||
/// #warning some text
|
/// #warning some text
|
||||||
/// // expected-warning@10 {{some text}}
|
/// // expected-warning@10 {{some text}}
|
||||||
|
/// \endcode
|
||||||
///
|
///
|
||||||
/// The line number may be absolute (as above), or relative to the current
|
/// The line number may be absolute (as above), or relative to the current
|
||||||
/// line by prefixing the number with either '+' or '-'.
|
/// line by prefixing the number with either '+' or '-'.
|
||||||
|
@ -63,6 +65,31 @@ class TextDiagnosticBuffer;
|
||||||
/// void f(); // expected-note 2 {{previous declaration is here}}
|
/// void f(); // expected-note 2 {{previous declaration is here}}
|
||||||
/// \endcode
|
/// \endcode
|
||||||
///
|
///
|
||||||
|
/// Where the diagnostic is expected to occur a minimum number of times, this
|
||||||
|
/// can be specified by appending a '+' to the number. Example:
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// void f(); // expected-note 0+ {{previous declaration is here}}
|
||||||
|
/// void g(); // expected-note 1+ {{previous declaration is here}}
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// In the first example, the diagnostic becomes optional, i.e. it will be
|
||||||
|
/// swallowed if it occurs, but will not generate an error if it does not
|
||||||
|
/// occur. In the second example, the diagnostic must occur at least once.
|
||||||
|
/// As a short-hand, "one or more" can be specified simply by '+'. Example:
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// void g(); // expected-note + {{previous declaration is here}}
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// A range can also be specified by "<n>-<m>". Example:
|
||||||
|
///
|
||||||
|
/// \code
|
||||||
|
/// void f(); // expected-note 0-1 {{previous declaration is here}}
|
||||||
|
/// \endcode
|
||||||
|
///
|
||||||
|
/// In this example, the diagnostic may appear only once, if at all.
|
||||||
|
///
|
||||||
/// Regex matching mode may be selected by appending '-re' to type. Example:
|
/// Regex matching mode may be selected by appending '-re' to type. Example:
|
||||||
///
|
///
|
||||||
/// expected-error-re
|
/// expected-error-re
|
||||||
|
@ -85,15 +112,15 @@ public:
|
||||||
public:
|
public:
|
||||||
static Directive *create(bool RegexKind, SourceLocation DirectiveLoc,
|
static Directive *create(bool RegexKind, SourceLocation DirectiveLoc,
|
||||||
SourceLocation DiagnosticLoc,
|
SourceLocation DiagnosticLoc,
|
||||||
StringRef Text, unsigned Count);
|
StringRef Text, unsigned Min, unsigned Max);
|
||||||
public:
|
public:
|
||||||
/// Constant representing one or more matches aka regex "+".
|
/// Constant representing n or more matches.
|
||||||
static const unsigned OneOrMoreCount = UINT_MAX;
|
static const unsigned MaxCount = UINT_MAX;
|
||||||
|
|
||||||
SourceLocation DirectiveLoc;
|
SourceLocation DirectiveLoc;
|
||||||
SourceLocation DiagnosticLoc;
|
SourceLocation DiagnosticLoc;
|
||||||
const std::string Text;
|
const std::string Text;
|
||||||
unsigned Count;
|
unsigned Min, Max;
|
||||||
|
|
||||||
virtual ~Directive() { }
|
virtual ~Directive() { }
|
||||||
|
|
||||||
|
@ -106,9 +133,12 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
|
Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
|
||||||
StringRef Text, unsigned Count)
|
StringRef Text, unsigned Min, unsigned Max)
|
||||||
: DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc),
|
: DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc),
|
||||||
Text(Text), Count(Count) { }
|
Text(Text), Min(Min), Max(Max) {
|
||||||
|
assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!");
|
||||||
|
assert(!DiagnosticLoc.isInvalid() && "DiagnosticLoc is invalid!");
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Directive(const Directive&); // DO NOT IMPLEMENT
|
Directive(const Directive&); // DO NOT IMPLEMENT
|
||||||
|
|
|
@ -84,8 +84,8 @@ namespace {
|
||||||
class StandardDirective : public Directive {
|
class StandardDirective : public Directive {
|
||||||
public:
|
public:
|
||||||
StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
|
StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
|
||||||
StringRef Text, unsigned Count)
|
StringRef Text, unsigned Min, unsigned Max)
|
||||||
: Directive(DirectiveLoc, DiagnosticLoc, Text, Count) { }
|
: Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max) { }
|
||||||
|
|
||||||
virtual bool isValid(std::string &Error) {
|
virtual bool isValid(std::string &Error) {
|
||||||
// all strings are considered valid; even empty ones
|
// all strings are considered valid; even empty ones
|
||||||
|
@ -102,8 +102,8 @@ public:
|
||||||
class RegexDirective : public Directive {
|
class RegexDirective : public Directive {
|
||||||
public:
|
public:
|
||||||
RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
|
RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
|
||||||
StringRef Text, unsigned Count)
|
StringRef Text, unsigned Min, unsigned Max)
|
||||||
: Directive(DirectiveLoc, DiagnosticLoc, Text, Count), Regex(Text) { }
|
: Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max), Regex(Text) { }
|
||||||
|
|
||||||
virtual bool isValid(std::string &Error) {
|
virtual bool isValid(std::string &Error) {
|
||||||
if (Regex.isValid(Error))
|
if (Regex.isValid(Error))
|
||||||
|
@ -264,11 +264,29 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen,
|
||||||
PH.SkipWhitespace();
|
PH.SkipWhitespace();
|
||||||
|
|
||||||
// Next optional token: positive integer or a '+'.
|
// Next optional token: positive integer or a '+'.
|
||||||
unsigned Count = 1;
|
unsigned Min = 1;
|
||||||
if (PH.Next(Count))
|
unsigned Max = 1;
|
||||||
|
if (PH.Next(Min)) {
|
||||||
PH.Advance();
|
PH.Advance();
|
||||||
else if (PH.Next("+")) {
|
// A positive integer can be followed by a '+' meaning min
|
||||||
Count = Directive::OneOrMoreCount;
|
// or more, or by a '-' meaning a range from min to max.
|
||||||
|
if (PH.Next("+")) {
|
||||||
|
Max = Directive::MaxCount;
|
||||||
|
PH.Advance();
|
||||||
|
} else if (PH.Next("-")) {
|
||||||
|
PH.Advance();
|
||||||
|
if (!PH.Next(Max) || Max < Min) {
|
||||||
|
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
|
||||||
|
diag::err_verify_invalid_range) << KindStr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PH.Advance();
|
||||||
|
} else {
|
||||||
|
Max = Min;
|
||||||
|
}
|
||||||
|
} else if (PH.Next("+")) {
|
||||||
|
// '+' on its own means "1 or more".
|
||||||
|
Max = Directive::MaxCount;
|
||||||
PH.Advance();
|
PH.Advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +326,8 @@ static void ParseDirective(const char *CommentStart, unsigned CommentLen,
|
||||||
Text.assign(ContentBegin, ContentEnd);
|
Text.assign(ContentBegin, ContentEnd);
|
||||||
|
|
||||||
// Construct new directive.
|
// Construct new directive.
|
||||||
Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text, Count);
|
Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text,
|
||||||
|
Min, Max);
|
||||||
std::string Error;
|
std::string Error;
|
||||||
if (D->isValid(Error))
|
if (D->isValid(Error))
|
||||||
DL->push_back(D);
|
DL->push_back(D);
|
||||||
|
@ -411,9 +430,8 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
|
||||||
for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
|
for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
|
||||||
Directive& D = **I;
|
Directive& D = **I;
|
||||||
unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
|
unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
|
||||||
bool FoundOnce = false;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < D.Count; ++i) {
|
for (unsigned i = 0; i < D.Max; ++i) {
|
||||||
DiagList::iterator II, IE;
|
DiagList::iterator II, IE;
|
||||||
for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
|
for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
|
||||||
unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
|
unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
|
||||||
|
@ -425,18 +443,12 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (II == IE) {
|
if (II == IE) {
|
||||||
if (D.Count == D.OneOrMoreCount) {
|
|
||||||
if (!FoundOnce)
|
|
||||||
LeftOnly.push_back(*I);
|
|
||||||
// We are only interested in at least one match, so exit the loop.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Not found.
|
// Not found.
|
||||||
|
if (i >= D.Min) break;
|
||||||
LeftOnly.push_back(*I);
|
LeftOnly.push_back(*I);
|
||||||
} else {
|
} else {
|
||||||
// Found. The same cannot be found twice.
|
// Found. The same cannot be found twice.
|
||||||
Right.erase(II);
|
Right.erase(II);
|
||||||
FoundOnce = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,8 +539,8 @@ VerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const {
|
||||||
|
|
||||||
Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
|
Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
|
||||||
SourceLocation DiagnosticLoc, StringRef Text,
|
SourceLocation DiagnosticLoc, StringRef Text,
|
||||||
unsigned Count) {
|
unsigned Min, unsigned Max) {
|
||||||
if (RegexKind)
|
if (RegexKind)
|
||||||
return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Count);
|
return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
|
||||||
return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Count);
|
return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue