LLVM: lib/FileCheck/FileCheck.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
24#include
25#include
26#include
27#include
28#include
29
30using namespace llvm;
31
44 }
46}
47
50
51 auto CreatePrecisionRegex = [&](StringRef S) {
52 return (Twine(AlternateFormPrefix) + S + Twine('{') + Twine(Precision) +
53 "}")
54 .str();
55 };
56
59 if (Precision)
60 return CreatePrecisionRegex("([1-9][0-9]*)?[0-9]");
61 return std::string("[0-9]+");
63 if (Precision)
64 return CreatePrecisionRegex("-?([1-9][0-9]*)?[0-9]");
65 return std::string("-?[0-9]+");
67 if (Precision)
68 return CreatePrecisionRegex("([1-9A-F][0-9A-F]*)?[0-9A-F]");
69 return (Twine(AlternateFormPrefix) + Twine("[0-9A-F]+")).str();
71 if (Precision)
72 return CreatePrecisionRegex("([1-9a-f][0-9a-f]*)?[0-9a-f]");
73 return (Twine(AlternateFormPrefix) + Twine("[0-9a-f]+")).str();
74 default:
76 "trying to match value with invalid format");
77 }
78}
79
83 return make_error();
84
85 unsigned Radix;
86 bool UpperCase = false;
92 Radix = 10;
93 break;
95 UpperCase = true;
96 Radix = 16;
97 break;
99 Radix = 16;
100 UpperCase = false;
101 break;
102 default:
104 "trying to match value with invalid format");
105 }
106 IntValue.abs().toString(AbsoluteValueStr, Radix, false,
107 false,
108 UpperCase);
109
111
112 if (Precision > AbsoluteValueStr.size()) {
113 unsigned LeadingZeros = Precision - AbsoluteValueStr.size();
114 return (Twine(SignPrefix) + Twine(AlternateFormPrefix) +
115 std::string(LeadingZeros, '0') + AbsoluteValueStr)
116 .str();
117 }
118
119 return (Twine(SignPrefix) + Twine(AlternateFormPrefix) + AbsoluteValueStr)
120 .str();
121}
122
126}
127
131 APInt Result = AbsVal;
132 if (Negative)
133 Result.negate();
134 return Result;
135}
136
140 bool Negative = StrVal.consume_front("-");
142 bool MissingFormPrefix =
143 !ValueIsSigned && AlternateForm && !StrVal.consume_front("0x");
144 (void)MissingFormPrefix;
145 assert(!MissingFormPrefix && "missing alternate form prefix");
146 APInt ResultValue;
147 [[maybe_unused]] bool ParseFailure =
148 StrVal.getAsInteger(Hex ? 16 : 10, ResultValue);
149
150
151
152 assert(!ParseFailure && "unable to represent numeric value");
153 return toSigned(ResultValue, Negative);
154}
155
157 const APInt &RightOperand, bool &Overflow) {
158 return LeftOperand.sadd_ov(RightOperand, Overflow);
159}
160
162 const APInt &RightOperand, bool &Overflow) {
163 return LeftOperand.ssub_ov(RightOperand, Overflow);
164}
165
167 const APInt &RightOperand, bool &Overflow) {
168 return LeftOperand.smul_ov(RightOperand, Overflow);
169}
170
172 const APInt &RightOperand, bool &Overflow) {
173
174 if (RightOperand.isZero())
175 return make_error();
176
177 return LeftOperand.sdiv_ov(RightOperand, Overflow);
178}
179
181 const APInt &RightOperand, bool &Overflow) {
182 Overflow = false;
183 return LeftOperand.slt(RightOperand) ? RightOperand : LeftOperand;
184}
185
187 const APInt &RightOperand, bool &Overflow) {
188 Overflow = false;
189 if (cantFail(exprMax(LeftOperand, RightOperand, Overflow)) == LeftOperand)
190 return RightOperand;
191
192 return LeftOperand;
193}
194
196 std::optional Value = Variable->getValue();
199
201}
202
206
207
208
209 if (!MaybeLeftOp || !MaybeRightOp) {
211 if (!MaybeLeftOp)
213 if (!MaybeRightOp)
215 return std::move(Err);
216 }
217
218 APInt LeftOp = *MaybeLeftOp;
219 APInt RightOp = *MaybeRightOp;
220 bool Overflow;
221
222 unsigned LeftBitWidth = LeftOp.getBitWidth();
223 unsigned RightBitWidth = RightOp.getBitWidth();
224 unsigned NewBitWidth = std::max(LeftBitWidth, RightBitWidth);
225 LeftOp = LeftOp.sext(NewBitWidth);
226 RightOp = RightOp.sext(NewBitWidth);
227 do {
228 Expected MaybeResult = EvalBinop(LeftOp, RightOp, Overflow);
229 if (!MaybeResult)
231
232 if (!Overflow)
233 return MaybeResult;
234
236 LeftOp = LeftOp.sext(NewBitWidth);
237 RightOp = RightOp.sext(NewBitWidth);
238 } while (true);
239}
240
245 if (!LeftFormat || !RightFormat) {
247 if (!LeftFormat)
249 if (!RightFormat)
251 return std::move(Err);
252 }
253
256 *LeftFormat != *RightFormat)
259 "implicit format conflict between '" + LeftOperand->getExpressionStr() +
260 "' (" + LeftFormat->toString() + ") and '" +
261 RightOperand->getExpressionStr() + "' (" + RightFormat->toString() +
262 "), need an explicit format specifier");
263
265 : *RightFormat;
266}
267
269 assert(ExpressionPointer->getAST() != nullptr &&
270 "Substituting empty expression");
271 Expected EvaluatedValue = ExpressionPointer->getAST()->eval();
272 if (!EvaluatedValue)
273 return EvaluatedValue.takeError();
275 return Format.getMatchingString(*EvaluatedValue);
276}
277
279
281 if (!VarVal)
284}
285
287
290 if (Str.empty())
292
293 size_t I = 0;
294 bool IsPseudo = Str[0] == '@';
295
296
297 if (Str[0] == '$' || IsPseudo)
298 ++I;
299
300 if (I == Str.size())
303 (IsPseudo ? "pseudo " : "global ") +
304 "variable name");
305
308
309 for (size_t E = Str.size(); I != E; ++I)
310
311 if (Str[I] != '_' && !isAlnum(Str[I]))
312 break;
313
315 Str = Str.substr(I);
317}
318
319
320
322
323
327 return C;
328}
329
335
338 std::optional<size_t> LineNumber, ExpressionFormat ImplicitFormat,
341 if (!ParseVarResult)
342 return ParseVarResult.takeError();
344
345 if (ParseVarResult->IsPseudo)
347 SM, Name, "definition of pseudo numeric variable unsupported");
348
349
350
351 if (Context->DefinedVariableTable.contains(Name))
353 SM, Name, "string variable with name '" + Name + "' already exists");
354
356 if (!Expr.empty())
358 SM, Expr, "unexpected characters after numeric variable name");
359
361 auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
362 if (VarTableIter != Context->GlobalNumericVariableTable.end()) {
363 DefinedNumericVariable = VarTableIter->second;
364 if (DefinedNumericVariable->getImplicitFormat() != ImplicitFormat)
366 SM, Expr, "format different from previous variable definition");
367 } else
368 DefinedNumericVariable =
369 Context->makeNumericVariable(Name, ImplicitFormat, LineNumber);
370
371 return DefinedNumericVariable;
372}
373
375 StringRef Name, bool IsPseudo, std::optional<size_t> LineNumber,
377 if (IsPseudo && Name != "@LINE")
379 SM, Name, "invalid pseudo numeric variable '" + Name + "'");
380
381
382
383
384
385
386
387
388
389 auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
391 if (VarTableIter != Context->GlobalNumericVariableTable.end())
393 else {
397 }
398
400 if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber)
403 "numeric variable '" + Name +
404 "' defined earlier in the same CHECK directive");
405
407}
408
410 StringRef &Expr, AllowedOperand AO, bool MaybeInvalidConstraint,
414 if (AO != AllowedOperand::Any)
416 SM, Expr, "parenthesized expression not permitted here");
417 return parseParenExpr(Expr, LineNumber, Context, SM);
418 }
419
420 if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {
421
424 if (ParseVarResult) {
425
427 if (AO != AllowedOperand::Any)
429 "unexpected function call");
430
431 return parseCallExpr(Expr, ParseVarResult->Name, LineNumber, Context,
432 SM);
433 }
434
435 return parseNumericVariableUse(ParseVarResult->Name,
436 ParseVarResult->IsPseudo, LineNumber,
437 Context, SM);
438 }
439
440 if (AO == AllowedOperand::LineVar)
441 return ParseVarResult.takeError();
442
444 }
445
446
450 if (!Expr.consumeInteger((AO == AllowedOperand::LegacyLiteral) ? 10 : 0,
451 LiteralValue)) {
453 return std::make_unique(SaveExpr.drop_back(Expr.size()),
454 LiteralValue);
455 }
457 SM, SaveExpr,
458 Twine("invalid ") +
459 (MaybeInvalidConstraint ? "matching constraint or " : "") +
460 "operand format");
461}
462
464Pattern::parseParenExpr(StringRef &Expr, std::optional<size_t> LineNumber,
468
469
472 if (Expr.empty())
474
475
477 Expr, AllowedOperand::Any, false, LineNumber,
478 Context, SM);
480 while (SubExprResult && !Expr.empty() && !Expr.starts_with(")")) {
482 SubExprResult = parseBinop(OrigExpr, Expr, std::move(*SubExprResult), false,
483 LineNumber, Context, SM);
485 }
486 if (!SubExprResult)
487 return SubExprResult;
488
491 "missing ')' at end of nested expression");
492 }
493 return SubExprResult;
494}
495
498 std::unique_ptr LeftOp,
499 bool IsLegacyLineExpr, std::optional<size_t> LineNumber,
502 if (RemainingExpr.empty())
503 return std::move(LeftOp);
504
505
506
511 case '+':
513 break;
514 case '-':
516 break;
517 default:
519 SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'");
520 }
521
522
524 if (RemainingExpr.empty())
526 "missing operand in expression");
527
528 AllowedOperand AO =
529 IsLegacyLineExpr ? AllowedOperand::LegacyLiteral : AllowedOperand::Any;
531 parseNumericOperand(RemainingExpr, AO, false,
532 LineNumber, Context, SM);
533 if (!RightOpResult)
534 return RightOpResult;
535
537 return std::make_unique(Expr, EvalBinop, std::move(LeftOp),
538 std::move(*RightOpResult));
539}
540
543 std::optional<size_t> LineNumber,
547
556
557 if (!OptFunc)
559 SM, FuncName, Twine("call to undefined function '") + FuncName + "'");
560
563
564
569
570
573 Expr, AllowedOperand::Any, false, LineNumber,
574 Context, SM);
575 while (Arg && !Expr.empty()) {
577
579 break;
580
581
582 Arg = parseBinop(OuterBinOpExpr, Expr, std::move(*Arg), false, LineNumber,
583 Context, SM);
584 }
585
586
587 if (!Arg)
589 Args.push_back(std::move(*Arg));
590
591
594 break;
595
599 }
600
603 "missing ')' at end of call expression");
604
605 const unsigned NumArgs = Args.size();
606 if (NumArgs == 2)
607 return std::make_unique(Expr, *OptFunc, std::move(Args[0]),
608 std::move(Args[1]));
609
610
612 Twine("function '") + FuncName +
613 Twine("' takes 2 arguments but ") +
614 Twine(NumArgs) + " given");
615}
616
618 StringRef Expr, std::optional<NumericVariable *> &DefinedNumericVariable,
619 bool IsLegacyLineExpr, std::optional<size_t> LineNumber,
621 std::unique_ptr ExpressionASTPointer = nullptr;
623 DefinedNumericVariable = std::nullopt;
625 unsigned Precision = 0;
626
627
628 size_t FormatSpecEnd = Expr.find(',');
629 size_t FunctionStart = Expr.find('(');
630 if (FormatSpecEnd != StringRef::npos && FormatSpecEnd < FunctionStart) {
632 Expr = Expr.drop_front(FormatSpecEnd + 1);
636 SM, FormatExpr,
637 "invalid matching format specification in expression");
638
639
641 bool AlternateForm = FormatExpr.consume_front("#");
642
643
647 "invalid precision in format specifier");
648 }
649
650 if (!FormatExpr.empty()) {
651
652
654 switch (popFront(FormatExpr)) {
655 case 'u':
656 ExplicitFormat =
658 break;
659 case 'd':
660 ExplicitFormat =
662 break;
663 case 'x':
665 Precision, AlternateForm);
666 break;
667 case 'X':
669 Precision, AlternateForm);
670 break;
671 default:
673 "invalid format specifier in expression");
674 }
675 }
676
680 SM, AlternateFormFlagLoc,
681 "alternate form only supported for hex values");
682
684 if (!FormatExpr.empty())
686 SM, FormatExpr,
687 "invalid matching format specification in expression");
688 }
689
690
691 size_t DefEnd = Expr.find(':');
693 DefExpr = Expr.substr(0, DefEnd);
694 Expr = Expr.substr(DefEnd + 1);
695 }
696
697
699 bool HasParsedValidConstraint = Expr.consume_front("==");
700
701
703 if (Expr.empty()) {
704 if (HasParsedValidConstraint)
706 SM, Expr, "empty numeric expression should not have a constraint");
707 } else {
710
711
712 AllowedOperand AO =
713 IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
715 Expr, AO, !HasParsedValidConstraint, LineNumber, Context, SM);
718 IsLegacyLineExpr, LineNumber, Context, SM);
719
722 SM, Expr,
723 "unexpected characters at end of expression '" + Expr + "'");
724 }
727 ExpressionASTPointer = std::move(*ParseResult);
728 }
729
730
731
732
733
735 if (ExplicitFormat)
736 Format = ExplicitFormat;
737 else if (ExpressionASTPointer) {
739 ExpressionASTPointer->getImplicitFormat(SM);
740 if (!ImplicitFormat)
741 return ImplicitFormat.takeError();
742 Format = *ImplicitFormat;
743 }
746
747 std::unique_ptr ExpressionPointer =
748 std::make_unique(std::move(ExpressionASTPointer), Format);
749
750
754 DefExpr, Context, LineNumber, ExpressionPointer->getFormat(), SM);
755
759 }
760
761 return std::move(ExpressionPointer);
762}
763
768
770
772
773 PatternStr = PatternStr.rtrim(" \t");
774
775
778 "found empty check string with prefix '" + Prefix + ":'");
779 return true;
780 }
781
785 "found non-empty check string for empty check with prefix '" + Prefix +
786 ":'");
787 return true;
788 }
789
791 RegExStr = "(\n$)";
792 return false;
793 }
794
795
797 FixedStr = PatternStr;
798 return false;
799 }
800
801
802 if (!MatchFullLinesHere &&
803 (PatternStr.size() < 2 ||
804 (!PatternStr.contains("{{") && !PatternStr.contains("[[")))) {
805 FixedStr = PatternStr;
806 return false;
807 }
808
809 if (MatchFullLinesHere) {
810 RegExStr += '^';
812 RegExStr += " *";
813 }
814
815
816
817 unsigned CurParen = 1;
818
819
820
821 while (!PatternStr.empty()) {
822
824
825 size_t End = PatternStr.find("}}");
829 "found start of regex string with no end '}}'");
830 return true;
831 }
832
833
834
835
836
837 bool HasAlternation = PatternStr.contains('|');
838 if (HasAlternation) {
839 RegExStr += '(';
840 ++CurParen;
841 }
842
843 if (AddRegExToRegEx(PatternStr.substr(2, End - 2), CurParen, SM))
844 return true;
845 if (HasAlternation)
846 RegExStr += ')';
847
848 PatternStr = PatternStr.substr(End + 2);
849 continue;
850 }
851
852
853
854
855
856
857
858
859
860
861
864
865
866 size_t End = FindRegexVarEnd(UnparsedPatternStr, SM);
869
873 "Invalid substitution block, no ]] found");
874 return true;
875 }
876
877
878
879 PatternStr = UnparsedPatternStr.substr(End + 2);
880
881 bool IsDefinition = false;
882 bool SubstNeeded = false;
883
884
885 bool IsLegacyLineExpr = false;
889 std::string WildcardRegexp;
890 size_t SubstInsertIdx = RegExStr.size();
891
892
893 if (!IsNumBlock) {
894 size_t VarEndIdx = MatchStr.find(':');
899 return true;
900 }
901
902
903 StringRef OrigMatchStr = MatchStr;
906 if (!ParseVarResult) {
908 return true;
909 }
911 bool IsPseudo = ParseVarResult->IsPseudo;
912
914 SubstNeeded = !IsDefinition;
915 if (IsDefinition) {
916 if ((IsPseudo || !MatchStr.consume_front(":"))) {
919 "invalid name in string variable definition");
920 return true;
921 }
922
923
924
925 if (Context->GlobalNumericVariableTable.contains(Name)) {
928 "numeric variable with name '" + Name + "' already exists");
929 return true;
930 }
931 DefName = Name;
932 MatchRegexp = MatchStr;
933 } else {
934 if (IsPseudo) {
935 MatchStr = OrigMatchStr;
936 IsLegacyLineExpr = IsNumBlock = true;
937 } else {
938 if (!MatchStr.empty()) {
941 "invalid name in string variable use");
942 return true;
943 }
944 SubstStr = Name;
945 }
946 }
947 }
948
949
950 std::unique_ptr ExpressionPointer;
951 std::optional<NumericVariable *> DefinedNumericVariable;
952 if (IsNumBlock) {
955 IsLegacyLineExpr, LineNumber, Context,
956 SM);
959 return true;
960 }
961 ExpressionPointer = std::move(*ParseResult);
962 SubstNeeded = ExpressionPointer->getAST() != nullptr;
963 if (DefinedNumericVariable) {
964 IsDefinition = true;
965 DefName = (*DefinedNumericVariable)->getName();
966 }
967 if (SubstNeeded)
968 SubstStr = MatchStr;
969 else {
971 WildcardRegexp = cantFail(Format.getWildcardRegex());
972 MatchRegexp = WildcardRegexp;
973 }
974 }
975
976
977 if (IsDefinition) {
978 RegExStr += '(';
979 ++SubstInsertIdx;
980
981 if (IsNumBlock) {
982 NumericVariableMatch NumericVariableDefinition = {
983 *DefinedNumericVariable, CurParen};
984 NumericVariableDefs[DefName] = NumericVariableDefinition;
985
986
987
988
989 Context->GlobalNumericVariableTable[DefName] =
990 *DefinedNumericVariable;
991 } else {
992 VariableDefs[DefName] = CurParen;
993
994
995
996
997
998
999 Context->DefinedVariableTable[DefName] = true;
1000 }
1001
1002 ++CurParen;
1003 }
1004
1005 if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM))
1006 return true;
1007
1008 if (IsDefinition)
1009 RegExStr += ')';
1010
1011
1012 if (SubstNeeded) {
1013
1014
1015
1016 if (!IsNumBlock && VariableDefs.find(SubstStr) != VariableDefs.end()) {
1017 unsigned CaptureParenGroup = VariableDefs[SubstStr];
1018 if (CaptureParenGroup < 1 || CaptureParenGroup > 9) {
1021 "Can't back-reference more than 9 variables");
1022 return true;
1023 }
1024 AddBackrefToRegEx(CaptureParenGroup);
1025 } else {
1026
1027
1029 IsNumBlock
1030 ? Context->makeNumericSubstitution(
1031 SubstStr, std::move(ExpressionPointer), SubstInsertIdx)
1032 : Context->makeStringSubstitution(SubstStr, SubstInsertIdx);
1034 }
1035 }
1036
1037 continue;
1038 }
1039
1040
1041
1042 size_t FixedMatchEnd =
1043 std::min(PatternStr.find("{{", 1), PatternStr.find("[[", 1));
1045 PatternStr = PatternStr.substr(FixedMatchEnd);
1046 }
1047
1048 if (MatchFullLinesHere) {
1050 RegExStr += " *";
1051 RegExStr += '$';
1052 }
1053
1054 return false;
1055}
1056
1057bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) {
1059 std::string Error;
1060 if (!R.isValid(Error)) {
1062 "invalid regex: " + Error);
1063 return true;
1064 }
1065
1066 RegExStr += RS.str();
1067 CurParen += R.getNumMatches();
1068 return false;
1069}
1070
1071void Pattern::AddBackrefToRegEx(unsigned BackrefNum) {
1072 assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number");
1073 std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum);
1074 RegExStr += Backref;
1075}
1076
1079
1082
1083
1084 if (!FixedStr.empty()) {
1085 size_t Pos =
1088 return make_error();
1090 }
1091
1092
1093
1094
1095
1096 StringRef RegExToMatch = RegExStr;
1097 std::string TmpStr;
1098 if (!Substitutions.empty()) {
1099 TmpStr = RegExStr;
1100 if (LineNumber)
1101 Context->LineVariable->setValue(
1102 APInt(sizeof(*LineNumber) * 8, *LineNumber));
1103
1104 size_t InsertOffset = 0;
1105
1106
1107
1109 for (const auto &Substitution : Substitutions) {
1110
1113
1114
1115
1118 Value.takeError(),
1120 return ErrorDiagnostic::get(
1121 SM, Substitution->getFromString(),
1122 "unable to substitute variable or "
1123 "numeric expression: overflow error");
1124 },
1126 return ErrorDiagnostic::get(SM, E.getVarName(),
1127 E.message());
1128 }));
1129 continue;
1130 }
1131
1132
1135 InsertOffset += Value->size();
1136 }
1137 if (Errs)
1138 return std::move(Errs);
1139
1140
1141 RegExToMatch = TmpStr;
1142 }
1143
1146 if (IgnoreCase)
1148 if ((RegExToMatch, Flags).match(Buffer, &MatchInfo))
1149 return make_error();
1150
1151
1152 assert(!MatchInfo.empty() && "Didn't get any match");
1153 StringRef FullMatch = MatchInfo[0];
1154
1155
1156 for (const auto &VariableDef : VariableDefs) {
1157 assert(VariableDef.second < MatchInfo.size() && "Internal paren error");
1158 Context->GlobalVariableTable[VariableDef.first] =
1159 MatchInfo[VariableDef.second];
1160 }
1161
1162
1163
1164
1167 TheMatch.Pos = FullMatch.data() - Buffer.data() + MatchStartSkip;
1168 TheMatch.Len = FullMatch.size() - MatchStartSkip;
1169
1170
1171 for (const auto &NumericVariableDef : NumericVariableDefs) {
1172 const NumericVariableMatch &NumericVariableMatch =
1173 NumericVariableDef.getValue();
1174 unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup;
1175 assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error");
1177 NumericVariableMatch.DefinedNumericVariable;
1178
1179 StringRef MatchedValue = MatchInfo[CaptureParenGroup];
1182 DefinedNumericVariable->setValue(Value, MatchedValue);
1183 }
1184
1186}
1187
1188unsigned Pattern::computeMatchDistance(StringRef Buffer) const {
1189
1190
1191
1192
1193
1194
1195 StringRef ExampleString(FixedStr);
1196 if (ExampleString.empty())
1197 ExampleString = RegExStr;
1198
1199
1200 StringRef BufferPrefix = Buffer.substr(0, ExampleString.size());
1201 BufferPrefix = BufferPrefix.split('\n').first;
1202 return BufferPrefix.edit_distance(ExampleString);
1203}
1204
1208 std::vector *Diags) const {
1209
1210 if (!Substitutions.empty()) {
1211 for (const auto &Substitution : Substitutions) {
1214
1216
1217 if (!MatchedValue) {
1219 continue;
1220 }
1221
1222 OS << "with \"";
1225
1226
1227
1228
1229
1230 if (Diags)
1231 Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy,
1233 else
1235 }
1236 }
1237}
1238
1241 std::vector *Diags) const {
1242 if (VariableDefs.empty() && NumericVariableDefs.empty())
1243 return;
1244
1245 struct VarCapture {
1248 };
1250 for (const auto &VariableDef : VariableDefs) {
1251 VarCapture VC;
1252 VC.Name = VariableDef.first;
1253 StringRef Value = Context->GlobalVariableTable[VC.Name];
1258 }
1259 for (const auto &VariableDef : NumericVariableDefs) {
1260 VarCapture VC;
1261 VC.Name = VariableDef.getKey();
1262 std::optional StrValue =
1263 VariableDef.getValue().DefinedNumericVariable->getStringValue();
1264 if (!StrValue)
1265 continue;
1270 }
1271
1272
1273 llvm::sort(VarCaptures, [](const VarCapture &A, const VarCapture &B) {
1275 return false;
1276 assert(A.Range.Start != B.Range.Start &&
1277 "unexpected overlapping variable captures");
1278 return A.Range.Start.getPointer() < B.Range.Start.getPointer();
1279 });
1280
1281 for (const VarCapture &VC : VarCaptures) {
1284 OS << "captured var \"" << VC.Name << "\"";
1285 if (Diags)
1286 Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy, VC.Range, OS.str());
1287 else
1289 }
1290}
1291
1295 StringRef Buffer, size_t Pos, size_t Len,
1296 std::vector *Diags,
1297 bool AdjustPrevDiags = false) {
1301 if (Diags) {
1302 if (AdjustPrevDiags) {
1303 SMLoc CheckLoc = Diags->rbegin()->CheckLoc;
1304 for (auto I = Diags->rbegin(), E = Diags->rend();
1305 I != E && I->CheckLoc == CheckLoc; ++I)
1306 I->MatchTy = MatchTy;
1307 } else
1308 Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);
1309 }
1311}
1312
1314 std::vector *Diags) const {
1315
1316
1317
1318
1319 size_t NumLinesForward = 0;
1321 double BestQuality = 0;
1322
1323
1324 for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) {
1325 if (Buffer[i] == '\n')
1326 ++NumLinesForward;
1327
1328
1329
1330 if (Buffer[i] == ' ' || Buffer[i] == '\t')
1331 continue;
1332
1333
1334
1335 unsigned Distance = computeMatchDistance(Buffer.substr(i));
1336 double Quality = Distance + (NumLinesForward / 100.);
1337
1339 Best = i;
1340 BestQuality = Quality;
1341 }
1342 }
1343
1344
1345
1346
1347 if (Best && Best != StringRef::npos && BestQuality < 50) {
1350 getCheckTy(), Buffer, Best, 0, Diags);
1352 "possible intended match here");
1353
1354
1355
1356 }
1357}
1358
1361 auto VarIter = GlobalVariableTable.find(VarName);
1362 if (VarIter == GlobalVariableTable.end())
1363 return make_error(VarName);
1364
1365 return VarIter->second;
1366}
1367
1368template <class... Types>
1369NumericVariable *FileCheckPatternContext::makeNumericVariable(Types... args) {
1370 NumericVariables.push_back(std::make_unique(args...));
1371 return NumericVariables.back().get();
1372}
1373
1375FileCheckPatternContext::makeStringSubstitution(StringRef VarName,
1376 size_t InsertIdx) {
1377 Substitutions.push_back(
1378 std::make_unique(this, VarName, InsertIdx));
1379 return Substitutions.back().get();
1380}
1381
1382Substitution *FileCheckPatternContext::makeNumericSubstitution(
1384 size_t InsertIdx) {
1385 Substitutions.push_back(std::make_unique(
1386 this, ExpressionStr, std::move(Expression), InsertIdx));
1387 return Substitutions.back().get();
1388}
1389
1391
1393
1394 size_t BracketDepth = 0;
1395
1396 while (!Str.empty()) {
1397 if (Str.starts_with("]]") && BracketDepth == 0)
1399 if (Str[0] == '\\') {
1400
1401 Str = Str.substr(2);
1403 } else {
1404 switch (Str[0]) {
1405 default:
1406 break;
1407 case '[':
1408 BracketDepth++;
1409 break;
1410 case ']':
1411 if (BracketDepth == 0) {
1414 "missing closing \"]\" for regex variable");
1415 exit(1);
1416 }
1417 BracketDepth--;
1418 break;
1419 }
1420 Str = Str.substr(1);
1422 }
1423 }
1424
1426}
1427
1431
1434
1435 if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') {
1436 continue;
1437 }
1438
1439
1440
1443 continue;
1444 }
1445
1446
1448 while (Ptr + 1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t'))
1450 }
1451
1452
1455}
1456
1461 : CheckTy(CheckTy), CheckLoc(CheckLoc), MatchTy(MatchTy), Note(Note) {
1468}
1469
1471 return (isAlnum(c) || c == '-' || c == '_');
1472}
1473
1475 assert(Count > 0 && "zero and negative counts are not supported");
1477 "count supported only for plain CHECK directives");
1478 Count = C;
1479 return *this;
1480}
1481
1483 if (Modifiers.none())
1484 return "";
1485 std::string Ret;
1487 OS << '{';
1488 if (isLiteralMatch())
1489 OS << "LITERAL";
1490 OS << '}';
1491 return Ret;
1492}
1493
1495
1496 auto WithModifiers = [this, Prefix](StringRef Str) -> std::string {
1497 return (Prefix + Str + getModifiersDescription()).str();
1498 };
1499
1500 switch (Kind) {
1502 return "invalid";
1504 return "misspelled";
1506 if (Count > 1)
1507 return WithModifiers("-COUNT");
1508 return WithModifiers("");
1510 return WithModifiers("-NEXT");
1512 return WithModifiers("-SAME");
1514 return WithModifiers("-NOT");
1516 return WithModifiers("-DAG");
1518 return WithModifiers("-LABEL");
1520 return WithModifiers("-EMPTY");
1522 return std::string(Prefix);
1524 return "implicit EOF";
1526 return "bad NOT";
1528 return "bad COUNT";
1529 }
1531}
1532
1533static std::pair<Check::FileCheckType, StringRef>
1535 bool &Misspelled) {
1536 if (Buffer.size() <= Prefix.size())
1538
1540
1544
1546 }
1547
1549 -> std::pair<Check::FileCheckType, StringRef> {
1551 return {Ret, Rest};
1554
1555
1556 do {
1557
1558 Rest = Rest.ltrim();
1560 Ret.setLiteralMatch();
1561 else
1563
1564 Rest = Rest.ltrim();
1568 return {Ret, Rest};
1569 };
1570
1571
1574 if (Rest.front() == '{')
1576
1578 Misspelled = true;
1581
1583 int64_t Count;
1585
1587 if (Count <= 0 || Count > INT32_MAX)
1589 if (Rest.front() != ':' && Rest.front() != '{')
1591 return ConsumeModifiers(
1593 }
1594
1595
1601
1604
1607
1610
1613
1616
1619
1621}
1622
1623static std::pair<Check::FileCheckType, StringRef>
1625 bool Misspelled = false;
1626 auto Res = FindCheckType(Req, Buffer, Prefix, Misspelled);
1629 return Res;
1630}
1631
1632
1634 while (Loc < Str.size() && IsPartOfWord(Str[Loc]))
1635 ++Loc;
1636 return Loc;
1637}
1638
1641
1647 }
1651}
1652
1654
1657
1660 : Input(Input) {
1661 for (StringRef Prefix : CheckPrefixes)
1662 Prefixes.push_back({Prefix, Input.find(Prefix)});
1663 for (StringRef Prefix : CommentPrefixes)
1664 Prefixes.push_back({Prefix, Input.find(Prefix)});
1665
1666
1668 [](auto A, auto B) { return A.first.size() > B.first.size(); });
1669 }
1670
1671
1672
1675 Buffer.data() + Buffer.size() == Input.data() + Input.size() &&
1676 "Buffer must be suffix of Input");
1677
1680 for (auto &[Prefix, Pos] : Prefixes) {
1681
1682 if (Pos < From)
1683 Pos = Input.find(Prefix, From);
1684
1686 (Match.empty() || size_t(Match.data() - Input.data()) > Pos))
1688 }
1690 }
1691};
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716static std::pair<StringRef, StringRef>
1718 StringRef &Buffer, unsigned &LineNumber,
1720 while (!Buffer.empty()) {
1721
1723 if (Prefix.empty())
1724
1726
1727 assert(Prefix.data() >= Buffer.data() &&
1728 Prefix.data() < Buffer.data() + Buffer.size() &&
1729 "Prefix doesn't start inside of buffer!");
1730 size_t Loc = Prefix.data() - Buffer.data();
1733 LineNumber += Skipped.count('\n');
1734
1735
1736
1737
1738
1739
1741
1743 std::tie(CheckTy, AfterSuffix) = FindCheckType(Req, Buffer, Prefix);
1744
1745
1747 return {Prefix, AfterSuffix};
1748 }
1749
1750
1751
1752
1754 }
1755
1756
1758}
1759
1761 assert(!LineVariable && "@LINE pseudo numeric variable already created");
1763 LineVariable = makeNumericVariable(
1765 GlobalNumericVariableTable[LineName] = LineVariable;
1766}
1767
1770
1772
1775 std::pair<unsigned, unsigned> *ImpPatBufferIDRange) {
1776 if (ImpPatBufferIDRange)
1777 ImpPatBufferIDRange->first = ImpPatBufferIDRange->second = 0;
1778
1779 Error DefineError =
1780 PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM);
1781 if (DefineError) {
1783 return true;
1784 }
1785
1786 PatternContext->createLineVariable();
1787
1788 std::vectorFileCheckString::DagNotPrefixInfo ImplicitNegativeChecks;
1790
1791
1792 std::string Prefix = "-implicit-check-not='";
1793 std::string Suffix = "'";
1795 (Prefix + PatternString + Suffix).str(), "command line");
1796
1798 CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());
1800 if (ImpPatBufferIDRange) {
1801 if (ImpPatBufferIDRange->first == ImpPatBufferIDRange->second) {
1802 ImpPatBufferIDRange->first = BufferID;
1803 ImpPatBufferIDRange->second = BufferID + 1;
1804 } else {
1805 assert(BufferID == ImpPatBufferIDRange->second &&
1806 "expected consecutive source buffer IDs");
1807 ++ImpPatBufferIDRange->second;
1808 }
1809 }
1810
1811 ImplicitNegativeChecks.emplace_back(
1814 ImplicitNegativeChecks.back().DagNotPat.parsePattern(
1815 PatternInBuffer, "IMPLICIT-CHECK", SM, Req);
1816 }
1817
1818 std::vectorFileCheckString::DagNotPrefixInfo DagNotMatches =
1819 ImplicitNegativeChecks;
1820
1821
1822 unsigned LineNumber = 1;
1823
1826 std::set PrefixesNotFound(Req.CheckPrefixes.begin(),
1828 const size_t DistinctPrefixes = PrefixesNotFound.size();
1829 while (true) {
1831
1832
1835 std::tie(UsedPrefix, AfterSuffix) =
1837 if (UsedPrefix.empty())
1838 break;
1840 PrefixesNotFound.erase(UsedPrefix);
1841
1843 "Failed to move Buffer's start forward, or pointed prefix outside "
1844 "of the buffer!");
1846 AfterSuffix.data() < Buffer.data() + Buffer.size() &&
1847 "Parsing after suffix doesn't start inside of buffer!");
1848
1849
1850 const char *UsedPrefixStart = UsedPrefix.data();
1851
1852
1853
1855 : AfterSuffix;
1856
1857
1860 AfterSuffix.data() - UsedPrefix.data());
1863 "misspelled directive '" + UsedDirective + "'");
1864 return true;
1865 }
1866
1867
1870 "unsupported -NOT combo on prefix '" + UsedPrefix + "'");
1871 return true;
1872 }
1873
1874
1877 "invalid count in -COUNT specification on prefix '" +
1878 UsedPrefix + "'");
1879 return true;
1880 }
1881
1882
1883
1886
1887
1889
1890
1892
1893
1895 Buffer = Buffer.substr(EOL);
1896
1897
1899 continue;
1900
1901
1902 Pattern P(CheckTy, PatternContext.get(), LineNumber);
1903 if (P.parsePattern(PatternBuffer, UsedPrefix, SM, Req))
1904 return true;
1905
1906
1910 "found '" + UsedPrefix + "-LABEL:'"
1911 " with variable definition or use");
1912 return true;
1913 }
1914
1915
1918 CheckStrings.empty()) {
1920 ? "NEXT"
1924 "found '" + UsedPrefix + "-" + Type +
1925 "' without previous '" + UsedPrefix + ": line");
1926 return true;
1927 }
1928
1929
1931 DagNotMatches.emplace_back(P, UsedPrefix);
1932 continue;
1933 }
1934
1935
1936 CheckStrings.emplace_back(P, UsedPrefix, PatternLoc);
1937 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
1938 DagNotMatches = ImplicitNegativeChecks;
1939 }
1940
1941
1942
1943 const bool NoPrefixesFound = PrefixesNotFound.size() == DistinctPrefixes;
1944 const bool SomePrefixesUnexpectedlyNotUsed =
1946 if ((NoPrefixesFound || SomePrefixesUnexpectedlyNotUsed) &&
1948 errs() << "error: no check strings found with prefix"
1949 << (PrefixesNotFound.size() > 1 ? "es " : " ");
1950 bool First = true;
1951 for (StringRef MissingPrefix : PrefixesNotFound) {
1953 errs() << ", ";
1954 errs() << "\'" << MissingPrefix << ":'";
1956 }
1957 errs() << '\n';
1958 return true;
1959 }
1960
1961
1962
1963 if (!DagNotMatches.empty()) {
1964 CheckStrings.emplace_back(
1967 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
1968 }
1969
1970 return false;
1971}
1972
1973
1974
1977 int MatchedCount, StringRef Buffer,
1980 std::vector *Diags) {
1981
1982 bool HasError = !ExpectedMatch || MatchResult.TheError;
1983 bool PrintDiag = true;
1984 if (!HasError) {
1989
1990
1991
1992 PrintDiag = !Diags;
1993 }
1994
1995
2000 Buffer, MatchResult.TheMatch->Pos,
2001 MatchResult.TheMatch->Len, Diags);
2002 if (Diags) {
2005 }
2006 if (!PrintDiag) {
2007 assert(!HasError && "expected to report more diagnostics for error");
2009 }
2010
2011
2012 std::string Message = formatv("{0}: {1} string found in input",
2014 (ExpectedMatch ? "expected" : "excluded"))
2015 .str();
2017 Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
2021 {MatchRange});
2022
2023
2026
2027
2028
2029
2032 E.log(errs());
2033 if (Diags) {
2034 Diags->emplace_back(SM, Pat.getCheckTy(), Loc,
2035 FileCheckDiag::MatchFoundErrorNote,
2036 E.getRange(), E.getMessage().str());
2037 }
2038 });
2040}
2041
2042
2043
2044
2047 int MatchedCount, StringRef Buffer, Error MatchError,
2048 bool VerboseVerbose,
2049 std::vector *Diags) {
2050
2051 bool HasError = ExpectedMatch;
2052 bool HasPatternError = false;
2058 std::move(MatchError),
2060 HasError = HasPatternError = true;
2063 if (Diags)
2065 },
2066
2068
2069
2070 bool PrintDiag = true;
2071 if (!HasError) {
2072 if (!VerboseVerbose)
2074
2075
2076
2077 PrintDiag = !Diags;
2078 }
2079
2080
2081
2082
2083
2084
2085
2086
2088 Buffer, 0, Buffer.size(), Diags);
2089 if (Diags) {
2091 for (StringRef ErrorMsg : ErrorMsgs)
2092 Diags->emplace_back(SM, Pat.getCheckTy(), Loc, MatchTy, NoteRange,
2093 ErrorMsg);
2095 }
2096 if (!PrintDiag) {
2097 assert(!HasError && "expected to report more diagnostics for error");
2099 }
2100
2101
2102
2103 if (!HasPatternError) {
2104 std::string Message = formatv("{0}: {1} string not found in input",
2106 (ExpectedMatch ? "expected" : "excluded"))
2107 .str();
2109 Message +=
2110 formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
2113 Message);
2115 "scanning from here");
2116 }
2117
2118
2119
2121 if (ExpectedMatch)
2124}
2125
2126
2127
2130 int MatchedCount, StringRef Buffer,
2133 std::vector *Diags) {
2135 return printMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer,
2136 std::move(MatchResult), Req, Diags);
2137 return printNoMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer,
2139 Diags);
2140}
2141
2142
2144 const char *&FirstNewLine) {
2145 unsigned NumNewLines = 0;
2146 while (true) {
2147
2149 if (Range.empty())
2150 return NumNewLines;
2151
2152 ++NumNewLines;
2153
2154
2155 if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') &&
2159
2160 if (NumNewLines == 1)
2161 FirstNewLine = Range.begin();
2162 }
2163}
2164
2166 bool IsLabelScanMode, size_t &MatchLen,
2168 std::vector *Diags) const {
2169 size_t LastPos = 0;
2170 std::vector<const DagNotPrefixInfo *> NotStrings;
2171
2172
2173
2174
2175
2176 if (!IsLabelScanMode) {
2177
2178 LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags);
2181 }
2182
2183
2184 size_t LastMatchEnd = LastPos;
2185 size_t FirstMatchPos = 0;
2186
2187
2189 for (int i = 1; i <= Pat.getCount(); i++) {
2191
2193
2194
2196 Pat, i, MatchBuffer,
2197 std::move(MatchResult), Req, Diags)) {
2200 }
2201
2202 size_t MatchPos = MatchResult.TheMatch->Pos;
2203 if (i == 1)
2204 FirstMatchPos = LastPos + MatchPos;
2205
2206
2207 LastMatchEnd += MatchPos + MatchResult.TheMatch->Len;
2208 }
2209
2210 MatchLen = LastMatchEnd - FirstMatchPos;
2211
2212
2213
2214 if (!IsLabelScanMode) {
2215 size_t MatchPos = FirstMatchPos - LastPos;
2217 StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
2218
2219
2220
2221 if (CheckNext(SM, SkippedRegion)) {
2223 Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
2226 }
2227
2228
2229
2230 if (CheckSame(SM, SkippedRegion)) {
2232 Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
2235 }
2236
2237
2238
2239 if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
2241 }
2242
2243 return FirstMatchPos;
2244}
2245
2249 return false;
2250
2251 Twine CheckName =
2254
2255
2256 const char *FirstNewLine = nullptr;
2258
2259 if (NumNewLines == 0) {
2261 CheckName + ": is on the same line as previous match");
2263 "'next' match was here");
2265 "previous match ended here");
2266 return true;
2267 }
2268
2269 if (NumNewLines != 1) {
2271 CheckName +
2272 ": is not on the line after the previous match");
2274 "'next' match was here");
2276 "previous match ended here");
2278 "non-matching line after previous match is here");
2279 return true;
2280 }
2281
2282 return false;
2283}
2284
2287 return false;
2288
2289
2290 const char *FirstNewLine = nullptr;
2292
2293 if (NumNewLines != 0) {
2296 "-SAME: is not on the same line as the previous match");
2298 "'next' match was here");
2300 "previous match ended here");
2301 return true;
2302 }
2303
2304 return false;
2305}
2306
2309 const std::vector<const DagNotPrefixInfo *> &NotStrings,
2310 const FileCheckRequest &Req, std::vector *Diags) const {
2311 bool DirectiveFail = false;
2312 for (auto NotInfo : NotStrings) {
2314 "Expect CHECK-NOT!");
2317 false, SM, NotInfo->DagNotPrefix,
2318 NotInfo->DagNotPat.getLoc(), NotInfo->DagNotPat, 1, Buffer,
2319 std::move(MatchResult), Req, Diags)) {
2321 DirectiveFail = true;
2322 continue;
2323 }
2324 }
2325 return DirectiveFail;
2326}
2327
2328size_t
2330 std::vector<const DagNotPrefixInfo *> &NotStrings,
2332 std::vector *Diags) const {
2334 return 0;
2335
2336
2337 size_t StartPos = 0;
2338
2339 struct MatchRange {
2340 size_t Pos;
2341 size_t End;
2342 };
2343
2344
2345
2346 std::list MatchRanges;
2347
2348
2349
2351 PatItr != PatEnd; ++PatItr) {
2352 const Pattern &Pat = PatItr->DagNotPat;
2353 const StringRef DNPrefix = PatItr->DagNotPrefix;
2356 "Invalid CHECK-DAG or CHECK-NOT!");
2357
2359 NotStrings.push_back(&*PatItr);
2360 continue;
2361 }
2362
2364
2365
2366 size_t MatchLen = 0, MatchPos = StartPos;
2367
2368
2369
2370 for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {
2373
2374
2378 std::move(MatchResult), Req, Diags)) {
2382 }
2383 }
2384 MatchLen = MatchResult.TheMatch->Len;
2385
2386
2387 MatchPos += MatchResult.TheMatch->Pos;
2388 MatchRange M{MatchPos, MatchPos + MatchLen};
2390
2391
2392
2393 if (MatchRanges.empty())
2394 MatchRanges.insert(MatchRanges.end(), M);
2395 else {
2396 auto Block = MatchRanges.begin();
2397 Block->Pos = std::min(Block->Pos, M.Pos);
2398 Block->End = std::max(Block->End, M.End);
2399 }
2400 break;
2401 }
2402
2403 bool Overlap = false;
2405 if (M.Pos < MI->End) {
2406
2407
2408 Overlap = MI->Pos < M.End;
2409 break;
2410 }
2411 }
2412 if (!Overlap) {
2413
2414 MatchRanges.insert(MI, M);
2415 break;
2416 }
2418
2419
2420
2421 if (!Diags) {
2424 SMRange OldRange(OldStart, OldEnd);
2426 "match discarded, overlaps earlier DAG match here",
2427 {OldRange});
2428 } else {
2429 SMLoc CheckLoc = Diags->rbegin()->CheckLoc;
2430 for (auto I = Diags->rbegin(), E = Diags->rend();
2431 I != E && I->CheckLoc == CheckLoc; ++I)
2433 }
2434 }
2435 MatchPos = MI->End;
2436 }
2439 true, SM, DNPrefix, Pat.getLoc(), Pat, 1, Buffer,
2441 Diags));
2442
2443
2444 if (std::next(PatItr) == PatEnd ||
2445 std::next(PatItr)->DagNotPat.getCheckTy() == Check::CheckNot) {
2446 if (!NotStrings.empty()) {
2447
2448
2449
2451 Buffer.slice(StartPos, MatchRanges.begin()->Pos);
2452 if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
2454
2455 NotStrings.clear();
2456 }
2457
2458
2459 StartPos = MatchRanges.rbegin()->End;
2460
2461 MatchRanges.clear();
2462 }
2463 }
2464
2465 return StartPos;
2466}
2467
2470 for (StringRef Prefix : SuppliedPrefixes) {
2471 if (Prefix.empty()) {
2472 errs() << "error: supplied " << Kind << " prefix must not be the empty "
2473 << "string\n";
2474 return false;
2475 }
2476 static const Regex Validator("^[a-zA-Z0-9_-]*$");
2477 if (!Validator.match(Prefix)) {
2478 errs() << "error: supplied " << Kind << " prefix must start with a "
2479 << "letter and contain only alphanumeric characters, hyphens, and "
2480 << "underscores: '" << Prefix << "'\n";
2481 return false;
2482 }
2483 if (!UniquePrefixes.insert(Prefix).second) {
2484 errs() << "error: supplied " << Kind << " prefix must be unique among "
2485 << "check and comment prefixes: '" << Prefix << "'\n";
2486 return false;
2487 }
2488 }
2489 return true;
2490}
2491
2494
2497 UniquePrefixes.insert(Prefix);
2498 }
2501 UniquePrefixes.insert(Prefix);
2502 }
2503
2504
2506 return false;
2508 return false;
2509 return true;
2510}
2511
2514 assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() &&
2515 "Overriding defined variable with command-line variable definitions");
2516
2517 if (CmdlineDefines.empty())
2519
2520
2521
2522
2523 unsigned I = 0;
2525 std::string CmdlineDefsDiag;
2527 for (StringRef CmdlineDef : CmdlineDefines) {
2528 std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str();
2529 size_t EqIdx = CmdlineDef.find('=');
2531 CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0));
2532 continue;
2533 }
2534
2535 if (CmdlineDef[0] == '#') {
2536
2537
2538
2539 CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str();
2540 std::string SubstitutionStr = std::string(CmdlineDef);
2541 SubstitutionStr[EqIdx] = ':';
2543 std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size()));
2544 CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str();
2545 } else {
2546 CmdlineDefsDiag += DefPrefix;
2548 std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size()));
2549 CmdlineDefsDiag += (CmdlineDef + "\n").str();
2550 }
2551 }
2552
2553
2554
2555
2556 std::unique_ptr CmdLineDefsDiagBuffer =
2558 StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();
2560
2561 for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {
2562 StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,
2563 CmdlineDefIndices.second);
2564 if (CmdlineDef.empty()) {
2566 std::move(Errs),
2568 "missing equal sign in global definition"));
2569 continue;
2570 }
2571
2572
2573 if (CmdlineDef[0] == '#') {
2574
2575
2577 std::optional<NumericVariable *> DefinedNumericVariable;
2580 DefinedNumericVariable, false,
2581 std::nullopt, this, SM);
2582 if (!ExpressionResult) {
2584 continue;
2585 }
2586 std::unique_ptr Expression = std::move(*ExpressionResult);
2587
2588
2589
2590
2594 continue;
2595 }
2596
2597 assert(DefinedNumericVariable && "No variable defined");
2598 (*DefinedNumericVariable)->setValue(*Value);
2599
2600
2601 GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] =
2602 *DefinedNumericVariable;
2603 } else {
2604
2605 std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
2606 StringRef CmdlineName = CmdlineNameVal.first;
2607 StringRef OrigCmdlineName = CmdlineName;
2610 if (!ParseVarResult) {
2612 continue;
2613 }
2614
2615
2616
2617 if (ParseVarResult->IsPseudo || !CmdlineName.empty()) {
2620 SM, OrigCmdlineName,
2621 "invalid name in string variable definition '" +
2622 OrigCmdlineName + "'"));
2623 continue;
2624 }
2626
2627
2628
2629 if (GlobalNumericVariableTable.contains(Name)) {
2632 "numeric variable with name '" +
2633 Name + "' already exists"));
2634 continue;
2635 }
2636 GlobalVariableTable.insert(CmdlineNameVal);
2637
2638
2639
2640
2641
2642
2643 DefinedVariableTable[Name] = true;
2644 }
2645 }
2646
2647 return Errs;
2648}
2649
2653 if (Var.first()[0] != '$')
2654 LocalPatternVars.push_back(Var.first());
2655
2656
2657
2658
2659
2660
2661
2662 for (const auto &Var : GlobalNumericVariableTable)
2663 if (Var.first()[0] != '$') {
2664 Var.getValue()->clearValue();
2665 LocalNumericVars.push_back(Var.first());
2666 }
2667
2668 for (const auto &Var : LocalPatternVars)
2669 GlobalVariableTable.erase(Var);
2670 for (const auto &Var : LocalNumericVars)
2671 GlobalNumericVariableTable.erase(Var);
2672}
2673
2675 std::vector *Diags) {
2676 bool ChecksFailed = false;
2677
2678 unsigned i = 0, j = 0, e = CheckStrings.size();
2679 while (true) {
2681 if (j == e) {
2682 CheckRegion = Buffer;
2683 } else {
2686 ++j;
2687 continue;
2688 }
2689
2690
2691 size_t MatchLabelLen = 0;
2692 size_t MatchLabelPos =
2693 CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags);
2695
2696 return false;
2697
2698 CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);
2699 Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen);
2700 ++j;
2701 }
2702
2703
2704
2705
2707 PatternContext->clearLocalVars();
2708
2709 for (; i != j; ++i) {
2711
2712
2713
2714 size_t MatchLen = 0;
2715 size_t MatchPos =
2716 CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags);
2717
2719 ChecksFailed = true;
2720 i = j;
2721 break;
2722 }
2723
2724 CheckRegion = CheckRegion.substr(MatchPos + MatchLen);
2725 }
2726
2727 if (j == e)
2728 break;
2729 }
2730
2731
2732 return !ChecksFailed;
2733}
BlockVerifier::State From
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static std::pair< StringRef, StringRef > FindFirstMatchingPrefix(const FileCheckRequest &Req, PrefixMatcher &Matcher, StringRef &Buffer, unsigned &LineNumber, Check::FileCheckType &CheckTy)
Searches the buffer for the first prefix in the prefix regular expression.
static size_t SkipWord(StringRef Str, size_t Loc)
static char popFront(StringRef &S)
constexpr StringLiteral SpaceChars
static Error reportMatchResult(bool ExpectedMatch, const SourceMgr &SM, StringRef Prefix, SMLoc Loc, const Pattern &Pat, int MatchedCount, StringRef Buffer, Pattern::MatchResult MatchResult, const FileCheckRequest &Req, std::vector< FileCheckDiag > *Diags)
Returns either (1) ErrorSuccess if there was no error, or (2) ErrorReported if an error was reported.
static Error printNoMatch(bool ExpectedMatch, const SourceMgr &SM, StringRef Prefix, SMLoc Loc, const Pattern &Pat, int MatchedCount, StringRef Buffer, Error MatchError, bool VerboseVerbose, std::vector< FileCheckDiag > *Diags)
Returns either (1) ErrorSuccess if there was no error, or (2) ErrorReported if an error was reported,...
static std::pair< Check::FileCheckType, StringRef > FindCheckType(const FileCheckRequest &Req, StringRef Buffer, StringRef Prefix, bool &Misspelled)
static const char * DefaultCheckPrefixes[]
static const char * DefaultCommentPrefixes[]
static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy, const SourceMgr &SM, SMLoc Loc, Check::FileCheckType CheckTy, StringRef Buffer, size_t Pos, size_t Len, std::vector< FileCheckDiag > *Diags, bool AdjustPrevDiags=false)
static unsigned CountNumNewlinesBetween(StringRef Range, const char *&FirstNewLine)
Counts the number of newlines in the specified range.
static APInt toSigned(APInt AbsVal, bool Negative)
static Error printMatch(bool ExpectedMatch, const SourceMgr &SM, StringRef Prefix, SMLoc Loc, const Pattern &Pat, int MatchedCount, StringRef Buffer, Pattern::MatchResult MatchResult, const FileCheckRequest &Req, std::vector< FileCheckDiag > *Diags)
Returns either (1) ErrorSuccess if there was no error or (2) ErrorReported if an error was reported,...
static bool ValidatePrefixes(StringRef Kind, StringSet<> &UniquePrefixes, ArrayRef< StringRef > SuppliedPrefixes)
static void addDefaultPrefixes(FileCheckRequest &Req)
static unsigned nextAPIntBitWidth(unsigned BitWidth)
static bool IsPartOfWord(char c)
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
StringSet - A set-like wrapper for the StringMap.
Class for arbitrary precision integers.
APInt zext(unsigned width) const
Zero extend to a new width.
APInt abs() const
Get the absolute value.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
unsigned getBitWidth() const
Return the number of bits in the APInt.
bool isNegative() const
Determine sign of this APInt.
APInt sadd_ov(const APInt &RHS, bool &Overflow) const
APInt sdiv_ov(const APInt &RHS, bool &Overflow) const
static constexpr unsigned APINT_BITS_PER_WORD
Bits in a word.
APInt smul_ov(const APInt &RHS, bool &Overflow) const
APInt sext(unsigned width) const
Sign extend to a new width.
bool isSignBitSet() const
Determine if sign bit of this APInt is set.
bool slt(const APInt &RHS) const
Signed less than comparison.
APInt ssub_ov(const APInt &RHS, bool &Overflow) const
void toString(SmallVectorImpl< char > &Str, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false) const
Converts an APInt to a string and append it to Str.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
bool empty() const
empty - Check if the array is empty.
Expected< ExpressionFormat > getImplicitFormat(const SourceMgr &SM) const override
Expected< APInt > eval() const override
Evaluates the value of the binary operation represented by this AST, using EvalBinop on the result of...
std::string getDescription(StringRef Prefix) const
bool isLiteralMatch() const
std::string getModifiersDescription() const
FileCheckType & setCount(int C)
Class to represent an error holding a diagnostic with location information used when printing it.
StringRef getMessage() const
void log(raw_ostream &OS) const override
Print diagnostic associated with this error when printing the error.
static Error get(const SourceMgr &SM, SMLoc Loc, const Twine &ErrMsg, SMRange Range=std::nullopt)
An error that has already been reported.
static Error reportedOrSuccess(bool HasErrorReported)
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
virtual Expected< APInt > eval() const =0
Evaluates and.
StringRef getExpressionStr() const
Class representing an expression and its matching format.
ExpressionAST * getAST() const
Class holding the Pattern global state, shared by all patterns: tables holding values of variables an...
Error defineCmdlineVariables(ArrayRef< StringRef > CmdlineDefines, SourceMgr &SM)
Defines string and numeric variables from definitions given on the command line, passed as a vector o...
void createLineVariable()
Create @LINE pseudo variable.
Expected< StringRef > getPatternVarValue(StringRef VarName)
void clearLocalVars()
Undefines local variables (variables whose name does not start with a '$' sign), i....
bool readCheckFile(SourceMgr &SM, StringRef Buffer, std::pair< unsigned, unsigned > *ImpPatBufferIDRange=nullptr)
Reads the check file from Buffer and records the expected strings it contains.
StringRef CanonicalizeFile(MemoryBuffer &MB, SmallVectorImpl< char > &OutputBuffer)
Canonicalizes whitespaces in the file.
FileCheck(FileCheckRequest Req)
bool checkInput(SourceMgr &SM, StringRef Buffer, std::vector< FileCheckDiag > *Diags=nullptr)
Checks the input to FileCheck provided in the Buffer against the expected strings read from the check...
bool ValidateCheckPrefixes()
This interface provides simple read-only access to a block of memory, and provides simple methods for...
size_t getBufferSize() const
static std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")
Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it.
const char * getBufferEnd() const
const char * getBufferStart() const
Expected< std::string > getResult() const override
Expected< APInt > eval() const override
Class representing a numeric variable and its associated current value.
void setValue(APInt NewValue, std::optional< StringRef > NewStrValue=std::nullopt)
Sets value of this numeric variable to NewValue, and sets the input buffer string from which it was p...
ExpressionFormat getImplicitFormat() const
std::optional< APInt > getValue() const
std::optional< size_t > getDefLineNumber() const
This is a utility class that provides an abstraction for the common functionality between Instruction...
Class to represent an overflow error that might result when manipulating a value.
This class represents success/failure for parsing-like operations that find it important to chain tog...
static Expected< VariableProperties > parseVariable(StringRef &Str, const SourceMgr &SM)
Parses the string at the start of Str for a variable name.
MatchResult match(StringRef Buffer, const SourceMgr &SM) const
Matches the pattern string against the input buffer Buffer.
void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer, std::vector< FileCheckDiag > *Diags) const
void printSubstitutions(const SourceMgr &SM, StringRef Buffer, SMRange MatchRange, FileCheckDiag::MatchType MatchTy, std::vector< FileCheckDiag > *Diags) const
Prints the value of successful substitutions.
static Expected< std::unique_ptr< Expression > > parseNumericSubstitutionBlock(StringRef Expr, std::optional< NumericVariable * > &DefinedNumericVariable, bool IsLegacyLineExpr, std::optional< size_t > LineNumber, FileCheckPatternContext *Context, const SourceMgr &SM)
Parses Expr for a numeric substitution block at line LineNumber, or before input is parsed if LineNum...
void printVariableDefs(const SourceMgr &SM, FileCheckDiag::MatchType MatchTy, std::vector< FileCheckDiag > *Diags) const
static bool isValidVarNameStart(char C)
Check::FileCheckType getCheckTy() const
bool parsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM, const FileCheckRequest &Req)
Parses the pattern in PatternStr and initializes this Pattern instance accordingly.
@ Newline
Compile for newline-sensitive matching.
@ IgnoreCase
Compile for matching that ignores upper/lower case distinctions.
static std::string escape(StringRef String)
Turn String into a regex by escaping its special characters.
bool match(StringRef String, SmallVectorImpl< StringRef > *Matches=nullptr, std::string *Error=nullptr) const
matches - Match the regex against a given String.
Represents a location in source code.
static SMLoc getFromPointer(const char *Ptr)
Represents a range in source code.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void reserve(size_type N)
void push_back(const T &Elt)
pointer data()
Return a pointer to the vector's buffer, even if empty().
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
This owns the files read by a parser, handles include stacks, and handles diagnostic wrangling.
std::pair< unsigned, unsigned > getLineAndColumn(SMLoc Loc, unsigned BufferID=0) const
Find the line and column number for the specified location in the specified file.
void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, const Twine &Msg, ArrayRef< SMRange > Ranges={}, ArrayRef< SMFixIt > FixIts={}, bool ShowColors=true) const
Emit a message about the specified location with the specified string.
unsigned AddNewSourceBuffer(std::unique_ptr< MemoryBuffer > F, SMLoc IncludeLoc)
Add a new source buffer to this source manager.
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
StringMapEntry - This is used to represent one value that is inserted into a StringMap.
bool contains(StringRef Key) const
contains - Return true if the element is in the map, false otherwise.
StringRef - Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool consumeInteger(unsigned Radix, T &Result)
Parse the current string as an integer of the specified radix.
std::string str() const
str - Get the contents as an std::string.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
empty - Check if the string is empty.
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
unsigned edit_distance(StringRef Other, bool AllowReplacements=true, unsigned MaxEditDistance=0) const
Determine the edit distance between this string and another string.
char back() const
back - Get the last character in the string.
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
constexpr size_t size() const
size - Get the string size.
char front() const
front - Get the first character in the string.
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
StringRef ltrim(char Char) const
Return string with consecutive Char characters starting from the the left removed.
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
bool consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
size_t find_first_of(char C, size_t From=0) const
Find the first character in the string that is C, or npos if not found.
StringRef rtrim(char Char) const
Return string with consecutive Char characters starting from the right removed.
StringRef take_front(size_t N=1) const
Return a StringRef equal to 'this' but with only the first N elements remaining.
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
StringRef trim(char Char) const
Return string with consecutive Char characters starting from the left and right removed.
size_t find_insensitive(char C, size_t From=0) const
Search for the first character C in the string, ignoring case.
size_t count(char C) const
Return the number of occurrences of C in the string.
static constexpr size_t npos
StringRef drop_back(size_t N=1) const
Return a StringRef equal to 'this' but with the last N elements dropped.
size_t find_first_not_of(char C, size_t From=0) const
Find the first character in the string that is not C or npos if not found.
StringSet - A wrapper for StringMap that provides set-like functionality.
std::pair< typename Base::iterator, bool > insert(StringRef key)
Expected< std::string > getResult() const override
A switch()-like statement whose cases are string literals.
StringSwitch & Case(StringLiteral S, T Value)
Class representing a substitution to perform in the RegExStr string.
StringRef getFromString() const
FileCheckPatternContext * Context
Pointer to a class instance holding, among other things, the table with the values of live string var...
StringRef FromStr
The string that needs to be substituted for something else.
virtual Expected< std::string > getResult() const =0
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
Class to represent an undefined variable error, which quotes that variable's name when printed.
LLVM Value Representation.
raw_ostream & write_escaped(StringRef Str, bool UseHexEscapes=false)
Output Str, turning '\', '\t', ' ', '"', and anything that doesn't satisfy llvm::isPrint into an esca...
A raw_ostream that writes to an std::string.
A raw_ostream that writes to an SmallVector or SmallString.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ C
The default llvm calling convention, compatible with C.
@ CheckBadNot
Marks when parsing found a -NOT check combined with another CHECK suffix.
@ CheckBadCount
Marks when parsing found a -COUNT directive with invalid count value.
@ CheckEOF
Indicates the pattern only matches the end of file.
This is an optimization pass for GlobalISel generic memory operations.
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
Expected< APInt > exprAdd(const APInt &Lhs, const APInt &Rhs, bool &Overflow)
Performs operation and.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
Error joinErrors(Error E1, Error E2)
Concatenate errors.
void sort(IteratorTy Start, IteratorTy End)
Expected< APInt > exprMul(const APInt &Lhs, const APInt &Rhs, bool &Overflow)
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
constexpr unsigned BitWidth
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Expected< APInt > exprMax(const APInt &Lhs, const APInt &Rhs, bool &Overflow)
Expected< APInt > exprDiv(const APInt &Lhs, const APInt &Rhs, bool &Overflow)
Expected< APInt > exprMin(const APInt &Lhs, const APInt &Rhs, bool &Overflow)
Expected< APInt > exprSub(const APInt &Lhs, const APInt &Rhs, bool &Overflow)
void consumeError(Error Err)
Consume a Error without doing anything.
Implement std::hash so that hash_code can be used in STL containers.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
StringRef match(StringRef Buffer)
Find the next match of a prefix in Buffer.
SmallVector< std::pair< StringRef, size_t > > Prefixes
Prefixes and their first occurrence past the current position.
PrefixMatcher(ArrayRef< StringRef > CheckPrefixes, ArrayRef< StringRef > CommentPrefixes, StringRef Input)
Type representing the format an expression value should be textualized into for matching.
APInt valueFromStringRepr(StringRef StrVal, const SourceMgr &SM) const
StringRef toString() const
Expected< std::string > getMatchingString(APInt Value) const
Expected< std::string > getWildcardRegex() const
@ HexLower
Value should be printed as a lowercase hex number.
@ HexUpper
Value should be printed as an uppercase hex number.
@ Signed
Value is a signed integer and should be printed as a decimal number.
@ Unsigned
Value is an unsigned integer and should be printed as a decimal number.
@ NoFormat
Denote absence of format.
unsigned InputStartLine
The search range if MatchTy starts with MatchNone, or the match range otherwise.
FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy, SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange, StringRef Note="")
MatchType
What type of match result does this diagnostic describe?
@ MatchFoundButWrongLine
Indicates a match for an expected pattern, but the match is on the wrong line.
@ MatchNoneAndExcluded
Indicates no match for an excluded pattern.
@ MatchFoundButExcluded
Indicates a match for an excluded pattern.
@ MatchFuzzy
Indicates a fuzzy match that serves as a suggestion for the next intended match for an expected patte...
@ MatchFoundButDiscarded
Indicates a discarded match for an expected pattern.
@ MatchNoneForInvalidPattern
Indicates no match due to an expected or excluded pattern that has proven to be invalid at match time...
@ MatchFoundAndExpected
Indicates a good match for an expected pattern.
@ MatchNoneButExpected
Indicates no match for an expected pattern, but this might follow good matches when multiple matches ...
Contains info about various FileCheck options.
bool IsDefaultCheckPrefix
std::vector< StringRef > GlobalDefines
bool NoCanonicalizeWhiteSpace
std::vector< StringRef > ImplicitCheckNot
std::vector< StringRef > CommentPrefixes
std::vector< StringRef > CheckPrefixes
bool AllowDeprecatedDagOverlap
A check that we found in the input file.
bool CheckNext(const SourceMgr &SM, StringRef Buffer) const
Verifies that there is a single line in the given Buffer.
Pattern Pat
The pattern to match.
bool CheckSame(const SourceMgr &SM, StringRef Buffer) const
Verifies that there is no newline in the given Buffer.
std::vector< DagNotPrefixInfo > DagNotStrings
Hold the DAG/NOT strings occurring in the input file.
SMLoc Loc
The location in the match file that the check string was specified.
StringRef Prefix
Which prefix name this check matched.
size_t CheckDag(const SourceMgr &SM, StringRef Buffer, std::vector< const DagNotPrefixInfo * > &NotStrings, const FileCheckRequest &Req, std::vector< FileCheckDiag > *Diags) const
Matches "dag strings" and their mixed "not strings".
size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode, size_t &MatchLen, FileCheckRequest &Req, std::vector< FileCheckDiag > *Diags) const
Matches check string and its "not strings" and/or "dag strings".
bool CheckNot(const SourceMgr &SM, StringRef Buffer, const std::vector< const DagNotPrefixInfo * > &NotStrings, const FileCheckRequest &Req, std::vector< FileCheckDiag > *Diags) const
Verifies that none of the strings in NotStrings are found in the given Buffer.
std::optional< Match > TheMatch
Parsing information about a variable.