[llvm] r359475 - FileCheck [3/12]: Stricter parsing of @LINE expressions
Thomas Preud'homme via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 29 10:46:26 PDT 2019
Author: thopre
Date: Mon Apr 29 10:46:26 2019
New Revision: 359475
URL: http://llvm.org/viewvc/llvm-project?rev=359475&view=rev
Log:
FileCheck [3/12]: Stricter parsing of @LINE expressions
Summary:
This patch is part of a patch series to add support for FileCheck
numeric expressions. This specific patch gives earlier and better
diagnostics for the @LINE expressions.
Rather than detect parsing errors at matching time, this commit adds
enhance parsing to detect issues with @LINE expressions at parse time
and diagnose them more accurately.
Copyright:
- Linaro (changes up to diff 183612 of revision D55940)
- GraphCore (changes in later versions of revision D55940 and
in new revision created off D55940)
Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar, arichardson, rnk
Subscribers: hiraditya, llvm-commits, probinson, dblaikie, grimar, arichardson, tra, rnk, kristina, hfinkel, rogfer01, JonChesterfield
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60383
Modified:
llvm/trunk/include/llvm/Support/FileCheck.h
llvm/trunk/lib/Support/FileCheck.cpp
llvm/trunk/test/FileCheck/line-count.txt
llvm/trunk/unittests/Support/FileCheckTest.cpp
Modified: llvm/trunk/include/llvm/Support/FileCheck.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileCheck.h?rev=359475&r1=359474&r2=359475&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FileCheck.h (original)
+++ llvm/trunk/include/llvm/Support/FileCheck.h Mon Apr 29 10:46:26 2019
@@ -155,6 +155,7 @@ public:
/// Returns the pointer to the global state for all patterns in this
/// FileCheck instance.
FileCheckPatternContext *getContext() const { return Context; }
+
/// Return whether \p is a valid first character for a variable name.
static bool isValidVarNameStart(char C);
/// Verify that the string at the start of \p Str is a well formed variable.
@@ -162,6 +163,11 @@ public:
/// variable and \p TrailIdx to the position of the last character that is
/// part of the variable name. Otherwise, only return true.
static bool parseVariable(StringRef Str, bool &IsPseudo, unsigned &TrailIdx);
+ /// Parse a numeric expression involving pseudo variable \p Name with the
+ /// string corresponding to the operation being performed in \p Trailer.
+ /// Return whether parsing failed in which case errors are reported on \p SM.
+ bool parseExpression(StringRef Name, StringRef Trailer,
+ const SourceMgr &SM) const;
bool ParsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,
unsigned LineNumber, const FileCheckRequest &Req);
size_t match(StringRef Buffer, size_t &MatchLen) const;
@@ -184,7 +190,7 @@ private:
bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM);
void AddBackrefToRegEx(unsigned BackrefNum);
unsigned computeMatchDistance(StringRef Buffer) const;
- bool EvaluateExpression(StringRef Expr, std::string &Value) const;
+ void evaluateExpression(StringRef Expr, std::string &Value) const;
size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);
};
Modified: llvm/trunk/lib/Support/FileCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/FileCheck.cpp?rev=359475&r1=359474&r2=359475&view=diff
==============================================================================
--- llvm/trunk/lib/Support/FileCheck.cpp (original)
+++ llvm/trunk/lib/Support/FileCheck.cpp Mon Apr 29 10:46:26 2019
@@ -55,6 +55,58 @@ bool FileCheckPattern::parseVariable(Str
return false;
}
+// Parsing helper function that strips the first character in S and returns it.
+static char popFront(StringRef &S) {
+ char C = S.front();
+ S = S.drop_front();
+ return C;
+}
+
+bool FileCheckPattern::parseExpression(StringRef Name, StringRef Trailer,
+ const SourceMgr &SM) const {
+ if (!Name.equals("@LINE")) {
+ SM.PrintMessage(SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
+ "invalid pseudo variable '" + Name + "'");
+ return true;
+ }
+
+ // Check if this is a supported operation and select function to perform it.
+ if (Trailer.empty())
+ return false;
+ SMLoc OpLoc = SMLoc::getFromPointer(Trailer.data());
+ char Operator = popFront(Trailer);
+ switch (Operator) {
+ case '+':
+ case '-':
+ break;
+ default:
+ SM.PrintMessage(OpLoc, SourceMgr::DK_Error,
+ Twine("unsupported numeric operation '") + Twine(Operator) +
+ "'");
+ return true;
+ }
+
+ // Parse right operand.
+ if (Trailer.empty()) {
+ SM.PrintMessage(SMLoc::getFromPointer(Trailer.data()), SourceMgr::DK_Error,
+ "missing operand in numeric expression '" + Trailer + "'");
+ return true;
+ }
+ uint64_t Offset;
+ if (Trailer.consumeInteger(10, Offset)) {
+ SM.PrintMessage(SMLoc::getFromPointer(Trailer.data()), SourceMgr::DK_Error,
+ "invalid offset in numeric expression '" + Trailer + "'");
+ return true;
+ }
+ if (!Trailer.empty()) {
+ SM.PrintMessage(SMLoc::getFromPointer(Trailer.data()), SourceMgr::DK_Error,
+ "unexpected characters at end of numeric expression '" +
+ Trailer + "'");
+ return true;
+ }
+ return false;
+}
+
/// Parses the given string into the Pattern.
///
/// \p Prefix provides which prefix is being matched, \p SM provides the
@@ -163,6 +215,14 @@ bool FileCheckPattern::ParsePattern(Stri
MatchStr = MatchStr.substr(0, End);
PatternStr = PatternStr.substr(End + 4);
+ size_t VarEndIdx = MatchStr.find(":");
+ size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");
+ if (SpacePos != StringRef::npos) {
+ SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos),
+ SourceMgr::DK_Error, "unexpected whitespace");
+ return true;
+ }
+
// Get the regex name (e.g. "foo") and verify it is well formed.
bool IsPseudo;
unsigned TrailIdx;
@@ -174,7 +234,7 @@ bool FileCheckPattern::ParsePattern(Stri
StringRef Name = MatchStr.substr(0, TrailIdx);
StringRef Trailer = MatchStr.substr(TrailIdx);
- bool IsVarDef = (Trailer.find(":") != StringRef::npos);
+ bool IsVarDef = (VarEndIdx != StringRef::npos);
if (IsVarDef && (IsPseudo || !Trailer.consume_front(":"))) {
SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data()),
@@ -183,17 +243,9 @@ bool FileCheckPattern::ParsePattern(Stri
return true;
}
- // Verify that the name/expression is well formed. FileCheck currently
- // supports @LINE, @LINE+number, @LINE-number expressions. The check here
- // is relaxed. A stricter check is performed in \c EvaluateExpression.
- if (IsPseudo) {
- for (unsigned I = 0, E = Trailer.size(); I != E; ++I) {
- if (!isalnum(Trailer[I]) && Trailer[I] != '+' && Trailer[I] != '-') {
- SM.PrintMessage(SMLoc::getFromPointer(Name.data() + I),
- SourceMgr::DK_Error, "invalid name in named regex");
- return true;
- }
- }
+ if (!IsVarDef && IsPseudo) {
+ if (parseExpression(Name, Trailer, SM))
+ return true;
}
// Handle [[foo]].
@@ -264,24 +316,16 @@ void FileCheckPattern::AddBackrefToRegEx
}
/// Evaluates expression and stores the result to \p Value.
-///
-/// Returns true on success and false when the expression has invalid syntax.
-bool FileCheckPattern::EvaluateExpression(StringRef Expr, std::string &Value) const {
- // The only supported expression is @LINE([\+-]\d+)?
- if (!Expr.startswith("@LINE"))
- return false;
+void FileCheckPattern::evaluateExpression(StringRef Expr,
+ std::string &Value) const {
Expr = Expr.substr(StringRef("@LINE").size());
int Offset = 0;
if (!Expr.empty()) {
if (Expr[0] == '+')
Expr = Expr.substr(1);
- else if (Expr[0] != '-')
- return false;
- if (Expr.getAsInteger(10, Offset))
- return false;
+ Expr.getAsInteger(10, Offset);
}
Value = llvm::itostr(LineNumber + Offset);
- return true;
}
/// Matches the pattern string against the input buffer \p Buffer
@@ -320,8 +364,7 @@ size_t FileCheckPattern::match(StringRef
std::string Value;
if (VariableUse.first[0] == '@') {
- if (!EvaluateExpression(VariableUse.first, Value))
- return StringRef::npos;
+ evaluateExpression(VariableUse.first, Value);
} else {
llvm::Optional<StringRef> ValueRef =
Context->getVarValue(VariableUse.first);
@@ -397,14 +440,10 @@ void FileCheckPattern::printVariableUses
StringRef Var = VariableUse.first;
if (Var[0] == '@') {
std::string Value;
- if (EvaluateExpression(Var, Value)) {
- OS << "with expression \"";
- OS.write_escaped(Var) << "\" equal to \"";
- OS.write_escaped(Value) << "\"";
- } else {
- OS << "uses incorrect expression \"";
- OS.write_escaped(Var) << "\"";
- }
+ evaluateExpression(Var, Value);
+ OS << "with expression \"";
+ OS.write_escaped(Var) << "\" equal to \"";
+ OS.write_escaped(Value) << "\"";
} else {
llvm::Optional<StringRef> VarValue = Context->getVarValue(Var);
Modified: llvm/trunk/test/FileCheck/line-count.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/line-count.txt?rev=359475&r1=359474&r2=359475&view=diff
==============================================================================
--- llvm/trunk/test/FileCheck/line-count.txt (original)
+++ llvm/trunk/test/FileCheck/line-count.txt Mon Apr 29 10:46:26 2019
@@ -1,15 +1,56 @@
; RUN: FileCheck -input-file %s %s
-; RUN: not FileCheck -check-prefix BAD -input-file %s %s
-3
-4 aaa
-5 bbb
-6 ccc
-7 CHECK: [[@LINE-3]] {{a}}aa
-8 CHECK: [[@LINE-3]] {{b}}bb
-9 CHECK: [[@LINE-3]] {{c}}cc
-10 foobar
-11 CHECK: [[@LINE-1]] {{foo}}bar
-12
-13 arst CHECK: [[@LINE]] {{a}}rst
-14
-15 BAD: [[@LINE:cant-have-regex]]
+; RUN: not FileCheck -check-prefix BAD1 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR1 %s
+; RUN: not FileCheck -check-prefix BAD2 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR2 %s
+; RUN: not FileCheck -check-prefix BAD3 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR3 %s
+; RUN: not FileCheck -check-prefix BAD4 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR4 %s
+; RUN: not FileCheck -check-prefix BAD5 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR5 %s
+; RUN: not FileCheck -check-prefix BAD6 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR6 %s
+; RUN: not FileCheck -check-prefix BAD7 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR7 %s
+; RUN: not FileCheck -check-prefix BAD8 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR8 %s
+; RUN: not FileCheck -check-prefix BAD9 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR9 %s
+; RUN: not FileCheck -check-prefix BAD10 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR10 %s
+; RUN: not FileCheck -check-prefix BAD10 -input-file %s %s 2>&1 | FileCheck -check-prefix ERR10 %s
+13
+14 aaa
+15 bbb
+16 ccc
+17 CHECK: [[@LINE-3]] {{a}}aa
+18 CHECK: [[@LINE-3]] {{b}}bb
+19 CHECK: [[@LINE-3]] {{c}}cc
+20 foobar
+21 CHECK: [[@LINE-1]] {{foo}}bar
+22
+23 arst CHECK: [[@LINE]] {{a}}rst
+24
+25 BAD1: [[@LINE:cant-have-regex]]
+26 ERR1: line-count.txt:[[@LINE-1]]:12: error: invalid name in named regex definition
+27
+28 BAD2: [[ @LINE]]
+29 ERR2: line-count.txt:[[@LINE-1]]:12: error: unexpected whitespace
+30
+31 BAD3: [[@LINE ]]
+32 ERR3: line-count.txt:[[@LINE-1]]:17: error: unexpected whitespace
+33
+34 BAD4: [[ @LINE-1]]
+35 ERR4: line-count.txt:[[@LINE-1]]:12: error: unexpected whitespace
+36
+37 BAD5: [[@LINE -1]]
+38 ERR5: line-count.txt:[[@LINE-1]]:17: error: unexpected whitespace
+39
+40 BAD6: [[@LINE- 1]]
+41 ERR6: line-count.txt:[[@LINE-1]]:18: error: unexpected whitespace
+42
+43 BAD7: [[@LINE-1 ]]
+44 ERR7: line-count.txt:[[@LINE-1]]:19: error: unexpected whitespace
+45
+46 BAD8: [[@LIN]]
+47 ERR8: line-count.txt:[[@LINE-1]]:12: error: invalid pseudo variable '@LIN'
+48
+49 BAD9: [[@LINE*2]]
+50 ERR9: line-count.txt:[[@LINE-1]]:17: error: unsupported numeric operation '*'
+51
+52 BAD10: [[@LINE-x]]
+53 ERR10: line-count.txt:[[@LINE-1]]:19: error: invalid offset in numeric expression 'x'
+54
+55 BAD11: [[@LINE-1x]]
+56 ERR11: line-count.txt:[[@LINE-1]]:19: error: unexpected characters at end of numeric expression 'x'
Modified: llvm/trunk/unittests/Support/FileCheckTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/FileCheckTest.cpp?rev=359475&r1=359474&r2=359475&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/FileCheckTest.cpp (original)
+++ llvm/trunk/unittests/Support/FileCheckTest.cpp Mon Apr 29 10:46:26 2019
@@ -90,6 +90,62 @@ TEST_F(FileCheckTest, ParseVar) {
EXPECT_EQ(TrailIdx, VarName.size() - 1);
}
+class ExprTester {
+private:
+ SourceMgr SM;
+ FileCheckPatternContext Context;
+ FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context);
+
+public:
+ bool parseExpect(std::string &VarName, std::string &Trailer) {
+ StringRef NameTrailer = StringRef(VarName + Trailer);
+ std::unique_ptr<MemoryBuffer> Buffer =
+ MemoryBuffer::getMemBufferCopy(NameTrailer, "TestBuffer");
+ StringRef NameTrailerRef = Buffer->getBuffer();
+ SM.AddNewSourceBuffer(std::move(Buffer), SMLoc());
+ StringRef VarNameRef = NameTrailerRef.substr(0, VarName.size());
+ StringRef TrailerRef = NameTrailerRef.substr(VarName.size());
+ return P.parseExpression(VarNameRef, TrailerRef, SM);
+ }
+};
+
+TEST_F(FileCheckTest, ParseExpr) {
+ ExprTester Tester;
+
+ // @LINE with offset.
+ std::string VarName = "@LINE";
+ std::string Trailer = "+3";
+ EXPECT_FALSE(Tester.parseExpect(VarName, Trailer));
+
+ // @LINE only.
+ Trailer = "";
+ EXPECT_FALSE(Tester.parseExpect(VarName, Trailer));
+
+ // Wrong Pseudovar.
+ VarName = "@FOO";
+ EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
+
+ // Unsupported operator.
+ VarName = "@LINE";
+ Trailer = "/2";
+ EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
+
+ // Missing offset operand.
+ VarName = "@LINE";
+ Trailer = "+";
+ EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
+
+ // Cannot parse offset operand.
+ VarName = "@LINE";
+ Trailer = "+x";
+ EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
+
+ // Unexpected string at end of numeric expression.
+ VarName = "@LINE";
+ Trailer = "+5x";
+ EXPECT_TRUE(Tester.parseExpect(VarName, Trailer));
+}
+
TEST_F(FileCheckTest, FileCheckContext) {
FileCheckPatternContext Cxt = FileCheckPatternContext();
std::vector<std::string> GlobalDefines;
More information about the llvm-commits
mailing list