/// evaluate their value.
FileCheckPatternContext *Context;
- /// Whether this represents a numeric expression substitution.
- bool IsNumSubst;
-
/// The string that needs to be substituted for something else. For a
/// string variable this is its name, otherwise this is the whole numeric
/// expression.
StringRef FromStr;
- /// If this is a numeric expression substitution, this is the pointer to the
- /// class representing the numeric expression whose value is to be
- /// substituted.
- FileCheckNumExpr *NumExpr = nullptr;
-
// Index in RegExStr of where to do the substitution.
size_t InsertIdx;
public:
- /// Constructor for a pattern variable substitution.
- FileCheckSubstitution(FileCheckPatternContext *Context,
- StringRef VarName, size_t InsertIdx)
- : Context(Context), IsNumSubst(false), FromStr(VarName),
- InsertIdx(InsertIdx) {}
-
- /// Constructor for a numeric expression substitution.
- FileCheckSubstitution(FileCheckPatternContext *Context, StringRef Expr,
- FileCheckNumExpr *NumExpr, size_t InsertIdx)
- : Context(Context), IsNumSubst(true), FromStr(Expr), NumExpr(NumExpr),
- InsertIdx(InsertIdx) {}
+ FileCheckSubstitution(FileCheckPatternContext *Context, StringRef VarName,
+ size_t InsertIdx)
+ : Context(Context), FromStr(VarName), InsertIdx(InsertIdx) {}
- /// \returns whether this is a numeric expression substitution.
- bool isNumSubst() const { return IsNumSubst; }
+ virtual ~FileCheckSubstitution() = default;
/// \returns the string to be substituted for something else.
StringRef getFromString() const { return FromStr; }
/// \returns the index where the substitution is to be performed in RegExStr.
size_t getIndex() const { return InsertIdx; }
- /// \returns the result of the substitution represented by this class
- /// instance or None if substitution failed. Numeric expressions are
- /// substituted by their values. String variables are simply replaced by the
- /// text their definition matched.
- llvm::Optional<std::string> getResult() const;
+ /// \returns a string containing the result of the substitution represented
+ /// by this class instance or None if substitution failed.
+ virtual llvm::Optional<std::string> getResult() const = 0;
- /// \returns the name of the undefined variable used in this substitution, if
- /// any, or an empty string otherwise.
- StringRef getUndefVarName() const;
+ /// \returns the name of the variable used in this substitution if undefined,
+ /// or an empty string otherwise.
+ virtual StringRef getUndefVarName() const = 0;
+};
+
+class FileCheckStringSubstitution : public FileCheckSubstitution {
+public:
+ FileCheckStringSubstitution(FileCheckPatternContext *Context,
+ StringRef VarName, size_t InsertIdx)
+ : FileCheckSubstitution(Context, VarName, InsertIdx) {}
+
+ /// \returns the text that the string variable in this substitution matched
+ /// when defined, or None if the variable is undefined.
+ llvm::Optional<std::string> getResult() const override;
+
+ /// \returns the name of the string variable used in this substitution if
+ /// undefined, or an empty string otherwise.
+ StringRef getUndefVarName() const override;
+};
+
+class FileCheckNumericSubstitution : public FileCheckSubstitution {
+private:
+ /// Pointer to the class representing the numeric expression whose value is
+ /// to be substituted.
+ FileCheckNumExpr *NumExpr;
+
+public:
+ FileCheckNumericSubstitution(FileCheckPatternContext *Context, StringRef Expr,
+ FileCheckNumExpr *NumExpr, size_t InsertIdx)
+ : FileCheckSubstitution(Context, Expr, InsertIdx), NumExpr(NumExpr) {}
+
+ /// \returns a string containing the result of evaluating the numeric
+ /// expression in this substitution, or None if evaluation failed.
+ llvm::Optional<std::string> getResult() const override;
+
+ /// \returns the name of the numeric variable used in this substitution if
+ /// undefined, or an empty string otherwise.
+ StringRef getUndefVarName() const override;
};
//===----------------------------------------------------------------------===//
/// automatically free them once they are guaranteed to no longer be used.
std::vector<std::unique_ptr<FileCheckNumericVariable>> NumericVariables;
+ /// Vector holding pointers to all substitutions. Used to automatically free
+ /// them once they are guaranteed to no longer be used.
+ std::vector<std::unique_ptr<FileCheckSubstitution>> Substitutions;
+
public:
/// \returns the value of string variable \p VarName or None if no such
/// variable has been defined.
/// Makes a new numeric variable and registers it for destruction when the
/// context is destroyed.
FileCheckNumericVariable *makeNumericVariable(StringRef Name, uint64_t Value);
+
+ /// Makes a new string substitution and registers it for destruction when the
+ /// context is destroyed.
+ FileCheckSubstitution *makeStringSubstitution(StringRef VarName,
+ size_t InsertIdx);
+
+ /// Makes a new numeric substitution and registers it for destruction when
+ /// the context is destroyed.
+ FileCheckSubstitution *makeNumericSubstitution(StringRef Expr,
+ FileCheckNumExpr *NumExpr,
+ size_t InsertIdx);
};
class FileCheckPattern {
/// RegExStr will contain "foobaz" and we'll get two entries in this vector
/// that tells us to insert the value of string variable "bar" at offset 3
/// and the value of numeric expression "N+1" at offset 6.
- std::vector<FileCheckSubstitution> Substitutions;
+ std::vector<FileCheckSubstitution *> Substitutions;
/// Maps names of string variables defined in a pattern to the parenthesized
/// capture numbers of their last definition.
return StringRef();
}
-llvm::Optional<std::string> FileCheckSubstitution::getResult() const {
- if (IsNumSubst) {
- llvm::Optional<uint64_t> EvaluatedValue = NumExpr->eval();
- if (!EvaluatedValue)
- return llvm::None;
- return utostr(*EvaluatedValue);
- }
+llvm::Optional<std::string> FileCheckNumericSubstitution::getResult() const {
+ llvm::Optional<uint64_t> EvaluatedValue = NumExpr->eval();
+ if (!EvaluatedValue)
+ return llvm::None;
+ return utostr(*EvaluatedValue);
+}
+llvm::Optional<std::string> FileCheckStringSubstitution::getResult() const {
// Look up the value and escape it so that we can put it into the regex.
llvm::Optional<StringRef> VarVal = Context->getPatternVarValue(FromStr);
if (!VarVal)
return Regex::escape(*VarVal);
}
-StringRef FileCheckSubstitution::getUndefVarName() const {
- if (IsNumSubst)
- // Although a use of an undefined numeric variable is detected at parse
- // time, a numeric variable can be undefined later by ClearLocalVariables.
- return NumExpr->getUndefVarName();
+StringRef FileCheckNumericSubstitution::getUndefVarName() const {
+ // Although a use of an undefined numeric variable is detected at parse
+ // time, a numeric variable can be undefined later by ClearLocalVariables.
+ return NumExpr->getUndefVarName();
+}
+StringRef FileCheckStringSubstitution::getUndefVarName() const {
if (!Context->getPatternVarValue(FromStr))
return FromStr;
} else {
// Handle substitution of string variables ([[<var>]]) defined in
// previous CHECK patterns, and substitution of numeric expressions.
- FileCheckSubstitution Substitution =
- IsNumBlock ? FileCheckSubstitution(Context, MatchStr, NumExpr,
- SubstInsertIdx)
- : FileCheckSubstitution(Context, MatchStr,
- SubstInsertIdx);
+ FileCheckSubstitution *Substitution =
+ IsNumBlock
+ ? Context->makeNumericSubstitution(MatchStr, NumExpr,
+ SubstInsertIdx)
+ : Context->makeStringSubstitution(MatchStr, SubstInsertIdx);
Substitutions.push_back(Substitution);
}
continue;
// handled by back-references.
for (const auto &Substitution : Substitutions) {
// Substitute and check for failure (e.g. use of undefined variable).
- llvm::Optional<std::string> Value = Substitution.getResult();
+ llvm::Optional<std::string> Value = Substitution->getResult();
if (!Value)
return StringRef::npos;
// Plop it into the regex at the adjusted offset.
- TmpStr.insert(TmpStr.begin() + Substitution.getIndex() + InsertOffset,
+ TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset,
Value->begin(), Value->end());
InsertOffset += Value->size();
}
for (const auto &Substitution : Substitutions) {
SmallString<256> Msg;
raw_svector_ostream OS(Msg);
- bool IsNumSubst = Substitution.isNumSubst();
- llvm::Optional<std::string> MatchedValue = Substitution.getResult();
+ llvm::Optional<std::string> MatchedValue = Substitution->getResult();
// Substitution failed or is not known at match time, print the undefined
// variable it uses.
if (!MatchedValue) {
- StringRef UndefVarName = Substitution.getUndefVarName();
+ StringRef UndefVarName = Substitution->getUndefVarName();
if (UndefVarName.empty())
continue;
OS << "uses undefined variable \"";
OS.write_escaped(UndefVarName) << "\"";
} else {
// Substitution succeeded. Print substituted value.
- if (IsNumSubst)
- OS << "with numeric expression \"";
- else
- OS << "with string variable \"";
- OS.write_escaped(Substitution.getFromString()) << "\" equal to \"";
+ OS << "with \"";
+ OS.write_escaped(Substitution->getFromString()) << "\" equal to \"";
OS.write_escaped(*MatchedValue) << "\"";
}
return NumericVariables.back().get();
}
+FileCheckSubstitution *
+FileCheckPatternContext::makeStringSubstitution(StringRef VarName,
+ size_t InsertIdx) {
+ Substitutions.push_back(
+ llvm::make_unique<FileCheckStringSubstitution>(this, VarName, InsertIdx));
+ return Substitutions.back().get();
+}
+
+FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution(
+ StringRef Expr, FileCheckNumExpr *NumExpr, size_t InsertIdx) {
+ Substitutions.push_back(llvm::make_unique<FileCheckNumericSubstitution>(
+ this, Expr, NumExpr, InsertIdx));
+ return Substitutions.back().get();
+}
+
size_t FileCheckPattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) {
// Offset keeps track of the current offset within the input Str
size_t Offset = 0;
NUMERRMSG: defines.txt:[[#@LINE-3]]:11: error: CHECKNUM: expected string not found in input
NUMERRMSG: defines.txt:1:1: note: scanning from here
-NUMERRMSG: defines.txt:1:1: note: with numeric expression "NUMVAL" equal to "8"
+NUMERRMSG: defines.txt:1:1: note: with "NUMVAL" equal to "8"
NUMERRMSG: defines.txt:[[#@LINE-7]]:1: note: possible intended match here
NOT-NUMERRMSG: defines.txt:[[#@LINE-7]]:13: error: {{NUMNOT}}-NOT: excluded string found in input
NOT-NUMERRMSG: defines.txt:[[#@LINE-10]]:1: note: found here
-NOT-NUMERRMSG: defines.txt:[[#@LINE-11]]:1: note: with numeric expression "NUMVAL" equal to "12"
+NOT-NUMERRMSG: defines.txt:[[#@LINE-11]]:1: note: with "NUMVAL" equal to "12"
ERRMSG: defines.txt:[[@LINE-3]]:8: error: CHECK: expected string not found in input
ERRMSG: defines.txt:1:1: note: scanning from here
-ERRMSG: defines.txt:1:1: note: with string variable "VALUE" equal to "20"
+ERRMSG: defines.txt:1:1: note: with "VALUE" equal to "20"
ERRMSG: defines.txt:[[@LINE-7]]:1: note: possible intended match here
NOT-ERRMSG: defines.txt:[[@LINE-7]]:10: error: {{NOT}}-NOT: excluded string found in input
NOT-ERRMSG: defines.txt:[[@LINE-10]]:1: note: found here
-NOT-ERRMSG: defines.txt:[[@LINE-11]]:1: note: with string variable "VALUE" equal to "10"
+NOT-ERRMSG: defines.txt:[[@LINE-11]]:1: note: with "VALUE" equal to "10"
; Definition of string variable to an empty string.
RUN: FileCheck -DVALUE= --check-prefix EMPTY --input-file %s %s 2>&1
V-NEXT: verbose.txt:[[#@LINE-9]]:1: note: found here
V-NEXT: {{^}}NUMVAR:42{{$}}
V-NEXT: {{^}}^~~~~~~~~{{$}}
-V-NEXT: verbose.txt:[[#@LINE-12]]:1: note: with numeric expression "NUMVAR" equal to "42"
+V-NEXT: verbose.txt:[[#@LINE-12]]:1: note: with "NUMVAR" equal to "42"
V-NEXT: {{^}}NUMVAR:42{{$}}
V-NEXT: {{^}}^~~~~~~~~{{$}}
V-NEXT: verbose.txt:[[#@LINE-18]]:1: note: found here
V-NEXT: {{^}}NUMVAR - 1:41{{$}}
V-NEXT: {{^}}^~~~~~~~~~~~~{{$}}
-V-NEXT: verbose.txt:[[#@LINE-21]]:1: note: with numeric expression "NUMVAR - 1" equal to "41"
+V-NEXT: verbose.txt:[[#@LINE-21]]:1: note: with "NUMVAR - 1" equal to "41"
V-NEXT: {{^}}NUMVAR - 1:41{{$}}
V-NEXT: {{^}}^~~~~~~~~~~~~{{$}}
Context.defineCmdlineVariables(GlobalDefines, SM);
// Substitution of an undefined string variable fails.
- FileCheckSubstitution Substitution =
- FileCheckSubstitution(&Context, "VAR404", 42);
- EXPECT_FALSE(Substitution.getResult());
+ FileCheckStringSubstitution StringSubstitution =
+ FileCheckStringSubstitution(&Context, "VAR404", 42);
+ EXPECT_FALSE(StringSubstitution.getResult());
// Substitutions of defined pseudo and non-pseudo numeric variables return
// the right value.
FileCheckNumericVariable NVar = FileCheckNumericVariable("@N", 10);
FileCheckNumExpr NumExprLine = FileCheckNumExpr(doAdd, &LineVar, 0);
FileCheckNumExpr NumExprN = FileCheckNumExpr(doAdd, &NVar, 3);
- FileCheckSubstitution SubstitutionLine =
- FileCheckSubstitution(&Context, "@LINE", &NumExprLine, 12);
- FileCheckSubstitution SubstitutionN =
- FileCheckSubstitution(&Context, "N", &NumExprN, 30);
+ FileCheckNumericSubstitution SubstitutionLine =
+ FileCheckNumericSubstitution(&Context, "@LINE", &NumExprLine, 12);
+ FileCheckNumericSubstitution SubstitutionN =
+ FileCheckNumericSubstitution(&Context, "N", &NumExprN, 30);
llvm::Optional<std::string> Value = SubstitutionLine.getResult();
EXPECT_TRUE(Value);
EXPECT_EQ("42", *Value);
// Substitution of a defined string variable returns the right value.
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context);
- Substitution = FileCheckSubstitution(&Context, "FOO", 42);
- Value = Substitution.getResult();
+ StringSubstitution = FileCheckStringSubstitution(&Context, "FOO", 42);
+ Value = StringSubstitution.getResult();
EXPECT_TRUE(Value);
EXPECT_EQ("BAR", *Value);
}
// getUndefVarName() on a string substitution with an undefined variable
// returns that variable.
- FileCheckSubstitution Substitution =
- FileCheckSubstitution(&Context, "VAR404", 42);
- StringRef UndefVar = Substitution.getUndefVarName();
+ FileCheckStringSubstitution StringSubstitution =
+ FileCheckStringSubstitution(&Context, "VAR404", 42);
+ StringRef UndefVar = StringSubstitution.getUndefVarName();
EXPECT_EQ("VAR404", UndefVar);
// getUndefVarName() on a string substitution with a defined variable returns
// an empty string.
- Substitution = FileCheckSubstitution(&Context, "FOO", 42);
- UndefVar = Substitution.getUndefVarName();
+ StringSubstitution = FileCheckStringSubstitution(&Context, "FOO", 42);
+ UndefVar = StringSubstitution.getUndefVarName();
EXPECT_EQ("", UndefVar);
// getUndefVarName() on a numeric substitution with a defined variable
// returns an empty string.
FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
FileCheckNumExpr NumExpr = FileCheckNumExpr(doAdd, &LineVar, 0);
- Substitution = FileCheckSubstitution(&Context, "@LINE", &NumExpr, 12);
- UndefVar = Substitution.getUndefVarName();
+ FileCheckNumericSubstitution NumericSubstitution =
+ FileCheckNumericSubstitution(&Context, "@LINE", &NumExpr, 12);
+ UndefVar = NumericSubstitution.getUndefVarName();
EXPECT_EQ("", UndefVar);
// getUndefVarName() on a numeric substitution with an undefined variable
// returns that variable.
LineVar.clearValue();
- UndefVar = Substitution.getUndefVarName();
+ UndefVar = NumericSubstitution.getUndefVarName();
EXPECT_EQ("@LINE", UndefVar);
}