Index: llvm/trunk/include/llvm/Support/FileCheck.h =================================================================== --- llvm/trunk/include/llvm/Support/FileCheck.h +++ llvm/trunk/include/llvm/Support/FileCheck.h @@ -116,37 +116,20 @@ /// 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; } @@ -154,15 +137,48 @@ /// \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 getResult() const; + /// \returns a string containing the result of the substitution represented + /// by this class instance or None if substitution failed. + virtual llvm::Optional 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 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 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; }; //===----------------------------------------------------------------------===// @@ -245,6 +261,10 @@ /// automatically free them once they are guaranteed to no longer be used. std::vector> NumericVariables; + /// Vector holding pointers to all substitutions. Used to automatically free + /// them once they are guaranteed to no longer be used. + std::vector> Substitutions; + public: /// \returns the value of string variable \p VarName or None if no such /// variable has been defined. @@ -273,6 +293,17 @@ /// 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 { @@ -292,7 +323,7 @@ /// 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 Substitutions; + std::vector Substitutions; /// Maps names of string variables defined in a pattern to the parenthesized /// capture numbers of their last definition. Index: llvm/trunk/lib/Support/FileCheck.cpp =================================================================== --- llvm/trunk/lib/Support/FileCheck.cpp +++ llvm/trunk/lib/Support/FileCheck.cpp @@ -52,14 +52,14 @@ return StringRef(); } -llvm::Optional FileCheckSubstitution::getResult() const { - if (IsNumSubst) { - llvm::Optional EvaluatedValue = NumExpr->eval(); - if (!EvaluatedValue) - return llvm::None; - return utostr(*EvaluatedValue); - } +llvm::Optional FileCheckNumericSubstitution::getResult() const { + llvm::Optional EvaluatedValue = NumExpr->eval(); + if (!EvaluatedValue) + return llvm::None; + return utostr(*EvaluatedValue); +} +llvm::Optional FileCheckStringSubstitution::getResult() const { // Look up the value and escape it so that we can put it into the regex. llvm::Optional VarVal = Context->getPatternVarValue(FromStr); if (!VarVal) @@ -67,12 +67,13 @@ 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; @@ -385,11 +386,11 @@ } else { // Handle substitution of string variables ([[]]) 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; @@ -471,12 +472,12 @@ // handled by back-references. for (const auto &Substitution : Substitutions) { // Substitute and check for failure (e.g. use of undefined variable). - llvm::Optional Value = Substitution.getResult(); + llvm::Optional 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(); } @@ -532,24 +533,20 @@ for (const auto &Substitution : Substitutions) { SmallString<256> Msg; raw_svector_ostream OS(Msg); - bool IsNumSubst = Substitution.isNumSubst(); - llvm::Optional MatchedValue = Substitution.getResult(); + llvm::Optional 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) << "\""; } @@ -653,6 +650,21 @@ return NumericVariables.back().get(); } +FileCheckSubstitution * +FileCheckPatternContext::makeStringSubstitution(StringRef VarName, + size_t InsertIdx) { + Substitutions.push_back( + llvm::make_unique(this, VarName, InsertIdx)); + return Substitutions.back().get(); +} + +FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution( + StringRef Expr, FileCheckNumExpr *NumExpr, size_t InsertIdx) { + Substitutions.push_back(llvm::make_unique( + 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; Index: llvm/trunk/test/FileCheck/numeric-defines.txt =================================================================== --- llvm/trunk/test/FileCheck/numeric-defines.txt +++ llvm/trunk/test/FileCheck/numeric-defines.txt @@ -14,9 +14,9 @@ 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" Index: llvm/trunk/test/FileCheck/string-defines.txt =================================================================== --- llvm/trunk/test/FileCheck/string-defines.txt +++ llvm/trunk/test/FileCheck/string-defines.txt @@ -15,12 +15,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 Index: llvm/trunk/test/FileCheck/verbose.txt =================================================================== --- llvm/trunk/test/FileCheck/verbose.txt +++ llvm/trunk/test/FileCheck/verbose.txt @@ -41,7 +41,7 @@ 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: {{^}}^~~~~~~~~{{$}} @@ -51,7 +51,7 @@ 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: {{^}}^~~~~~~~~~~~~{{$}} Index: llvm/trunk/unittests/Support/FileCheckTest.cpp =================================================================== --- llvm/trunk/unittests/Support/FileCheckTest.cpp +++ llvm/trunk/unittests/Support/FileCheckTest.cpp @@ -229,9 +229,9 @@ 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. @@ -239,10 +239,10 @@ 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 Value = SubstitutionLine.getResult(); EXPECT_TRUE(Value); EXPECT_EQ("42", *Value); @@ -258,8 +258,8 @@ // 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); } @@ -273,29 +273,30 @@ // 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); }