1af732203SDimitry Andric //===- FileCheck.cpp - Check that File's Contents match what is expected --===//
2af732203SDimitry Andric //
3af732203SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4af732203SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5af732203SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6af732203SDimitry Andric //
7af732203SDimitry Andric //===----------------------------------------------------------------------===//
8af732203SDimitry Andric //
9af732203SDimitry Andric // FileCheck does a line-by line check of a file that validates whether it
10af732203SDimitry Andric // contains the expected content. This is useful for regression tests etc.
11af732203SDimitry Andric //
12af732203SDimitry Andric // This file implements most of the API that will be used by the FileCheck utility
13af732203SDimitry Andric // as well as various unittests.
14af732203SDimitry Andric //===----------------------------------------------------------------------===//
15af732203SDimitry Andric
16af732203SDimitry Andric #include "llvm/FileCheck/FileCheck.h"
17af732203SDimitry Andric #include "FileCheckImpl.h"
18af732203SDimitry Andric #include "llvm/ADT/STLExtras.h"
19af732203SDimitry Andric #include "llvm/ADT/StringSet.h"
20af732203SDimitry Andric #include "llvm/ADT/Twine.h"
21af732203SDimitry Andric #include "llvm/Support/CheckedArithmetic.h"
22af732203SDimitry Andric #include "llvm/Support/FormatVariadic.h"
23af732203SDimitry Andric #include <cstdint>
24af732203SDimitry Andric #include <list>
25af732203SDimitry Andric #include <set>
26af732203SDimitry Andric #include <tuple>
27af732203SDimitry Andric #include <utility>
28af732203SDimitry Andric
29af732203SDimitry Andric using namespace llvm;
30af732203SDimitry Andric
toString() const31af732203SDimitry Andric StringRef ExpressionFormat::toString() const {
32af732203SDimitry Andric switch (Value) {
33af732203SDimitry Andric case Kind::NoFormat:
34af732203SDimitry Andric return StringRef("<none>");
35af732203SDimitry Andric case Kind::Unsigned:
36af732203SDimitry Andric return StringRef("%u");
37af732203SDimitry Andric case Kind::Signed:
38af732203SDimitry Andric return StringRef("%d");
39af732203SDimitry Andric case Kind::HexUpper:
40af732203SDimitry Andric return StringRef("%X");
41af732203SDimitry Andric case Kind::HexLower:
42af732203SDimitry Andric return StringRef("%x");
43af732203SDimitry Andric }
44af732203SDimitry Andric llvm_unreachable("unknown expression format");
45af732203SDimitry Andric }
46af732203SDimitry Andric
getWildcardRegex() const47af732203SDimitry Andric Expected<std::string> ExpressionFormat::getWildcardRegex() const {
48*5f7ddb14SDimitry Andric StringRef AlternateFormPrefix = AlternateForm ? StringRef("0x") : StringRef();
49*5f7ddb14SDimitry Andric
50*5f7ddb14SDimitry Andric auto CreatePrecisionRegex = [&](StringRef S) {
51*5f7ddb14SDimitry Andric return (Twine(AlternateFormPrefix) + S + Twine('{') + Twine(Precision) +
52*5f7ddb14SDimitry Andric "}")
53*5f7ddb14SDimitry Andric .str();
54af732203SDimitry Andric };
55af732203SDimitry Andric
56af732203SDimitry Andric switch (Value) {
57af732203SDimitry Andric case Kind::Unsigned:
58af732203SDimitry Andric if (Precision)
59af732203SDimitry Andric return CreatePrecisionRegex("([1-9][0-9]*)?[0-9]");
60af732203SDimitry Andric return std::string("[0-9]+");
61af732203SDimitry Andric case Kind::Signed:
62af732203SDimitry Andric if (Precision)
63af732203SDimitry Andric return CreatePrecisionRegex("-?([1-9][0-9]*)?[0-9]");
64af732203SDimitry Andric return std::string("-?[0-9]+");
65af732203SDimitry Andric case Kind::HexUpper:
66af732203SDimitry Andric if (Precision)
67af732203SDimitry Andric return CreatePrecisionRegex("([1-9A-F][0-9A-F]*)?[0-9A-F]");
68*5f7ddb14SDimitry Andric return (Twine(AlternateFormPrefix) + Twine("[0-9A-F]+")).str();
69af732203SDimitry Andric case Kind::HexLower:
70af732203SDimitry Andric if (Precision)
71af732203SDimitry Andric return CreatePrecisionRegex("([1-9a-f][0-9a-f]*)?[0-9a-f]");
72*5f7ddb14SDimitry Andric return (Twine(AlternateFormPrefix) + Twine("[0-9a-f]+")).str();
73af732203SDimitry Andric default:
74af732203SDimitry Andric return createStringError(std::errc::invalid_argument,
75af732203SDimitry Andric "trying to match value with invalid format");
76af732203SDimitry Andric }
77af732203SDimitry Andric }
78af732203SDimitry Andric
79af732203SDimitry Andric Expected<std::string>
getMatchingString(ExpressionValue IntegerValue) const80af732203SDimitry Andric ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const {
81af732203SDimitry Andric uint64_t AbsoluteValue;
82af732203SDimitry Andric StringRef SignPrefix = IntegerValue.isNegative() ? "-" : "";
83af732203SDimitry Andric
84af732203SDimitry Andric if (Value == Kind::Signed) {
85af732203SDimitry Andric Expected<int64_t> SignedValue = IntegerValue.getSignedValue();
86af732203SDimitry Andric if (!SignedValue)
87af732203SDimitry Andric return SignedValue.takeError();
88af732203SDimitry Andric if (*SignedValue < 0)
89af732203SDimitry Andric AbsoluteValue = cantFail(IntegerValue.getAbsolute().getUnsignedValue());
90af732203SDimitry Andric else
91af732203SDimitry Andric AbsoluteValue = *SignedValue;
92af732203SDimitry Andric } else {
93af732203SDimitry Andric Expected<uint64_t> UnsignedValue = IntegerValue.getUnsignedValue();
94af732203SDimitry Andric if (!UnsignedValue)
95af732203SDimitry Andric return UnsignedValue.takeError();
96af732203SDimitry Andric AbsoluteValue = *UnsignedValue;
97af732203SDimitry Andric }
98af732203SDimitry Andric
99af732203SDimitry Andric std::string AbsoluteValueStr;
100af732203SDimitry Andric switch (Value) {
101af732203SDimitry Andric case Kind::Unsigned:
102af732203SDimitry Andric case Kind::Signed:
103af732203SDimitry Andric AbsoluteValueStr = utostr(AbsoluteValue);
104af732203SDimitry Andric break;
105af732203SDimitry Andric case Kind::HexUpper:
106af732203SDimitry Andric case Kind::HexLower:
107af732203SDimitry Andric AbsoluteValueStr = utohexstr(AbsoluteValue, Value == Kind::HexLower);
108af732203SDimitry Andric break;
109af732203SDimitry Andric default:
110af732203SDimitry Andric return createStringError(std::errc::invalid_argument,
111af732203SDimitry Andric "trying to match value with invalid format");
112af732203SDimitry Andric }
113af732203SDimitry Andric
114*5f7ddb14SDimitry Andric StringRef AlternateFormPrefix = AlternateForm ? StringRef("0x") : StringRef();
115*5f7ddb14SDimitry Andric
116af732203SDimitry Andric if (Precision > AbsoluteValueStr.size()) {
117af732203SDimitry Andric unsigned LeadingZeros = Precision - AbsoluteValueStr.size();
118*5f7ddb14SDimitry Andric return (Twine(SignPrefix) + Twine(AlternateFormPrefix) +
119*5f7ddb14SDimitry Andric std::string(LeadingZeros, '0') + AbsoluteValueStr)
120af732203SDimitry Andric .str();
121af732203SDimitry Andric }
122af732203SDimitry Andric
123*5f7ddb14SDimitry Andric return (Twine(SignPrefix) + Twine(AlternateFormPrefix) + AbsoluteValueStr)
124*5f7ddb14SDimitry Andric .str();
125af732203SDimitry Andric }
126af732203SDimitry Andric
127af732203SDimitry Andric Expected<ExpressionValue>
valueFromStringRepr(StringRef StrVal,const SourceMgr & SM) const128af732203SDimitry Andric ExpressionFormat::valueFromStringRepr(StringRef StrVal,
129af732203SDimitry Andric const SourceMgr &SM) const {
130af732203SDimitry Andric bool ValueIsSigned = Value == Kind::Signed;
131*5f7ddb14SDimitry Andric // Both the FileCheck utility and library only call this method with a valid
132*5f7ddb14SDimitry Andric // value in StrVal. This is guaranteed by the regex returned by
133*5f7ddb14SDimitry Andric // getWildcardRegex() above. Only underflow and overflow errors can thus
134*5f7ddb14SDimitry Andric // occur. However new uses of this method could be added in the future so
135*5f7ddb14SDimitry Andric // the error message does not make assumptions about StrVal.
136*5f7ddb14SDimitry Andric StringRef IntegerParseErrorStr = "unable to represent numeric value";
137af732203SDimitry Andric if (ValueIsSigned) {
138af732203SDimitry Andric int64_t SignedValue;
139af732203SDimitry Andric
140af732203SDimitry Andric if (StrVal.getAsInteger(10, SignedValue))
141*5f7ddb14SDimitry Andric return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr);
142af732203SDimitry Andric
143af732203SDimitry Andric return ExpressionValue(SignedValue);
144af732203SDimitry Andric }
145af732203SDimitry Andric
146af732203SDimitry Andric bool Hex = Value == Kind::HexUpper || Value == Kind::HexLower;
147af732203SDimitry Andric uint64_t UnsignedValue;
148*5f7ddb14SDimitry Andric bool MissingFormPrefix = AlternateForm && !StrVal.consume_front("0x");
149af732203SDimitry Andric if (StrVal.getAsInteger(Hex ? 16 : 10, UnsignedValue))
150*5f7ddb14SDimitry Andric return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr);
151*5f7ddb14SDimitry Andric
152*5f7ddb14SDimitry Andric // Error out for a missing prefix only now that we know we have an otherwise
153*5f7ddb14SDimitry Andric // valid integer. For example, "-0x18" is reported above instead.
154*5f7ddb14SDimitry Andric if (MissingFormPrefix)
155*5f7ddb14SDimitry Andric return ErrorDiagnostic::get(SM, StrVal, "missing alternate form prefix");
156af732203SDimitry Andric
157af732203SDimitry Andric return ExpressionValue(UnsignedValue);
158af732203SDimitry Andric }
159af732203SDimitry Andric
getAsSigned(uint64_t UnsignedValue)160af732203SDimitry Andric static int64_t getAsSigned(uint64_t UnsignedValue) {
161af732203SDimitry Andric // Use memcpy to reinterpret the bitpattern in Value since casting to
162af732203SDimitry Andric // signed is implementation-defined if the unsigned value is too big to be
163af732203SDimitry Andric // represented in the signed type and using an union violates type aliasing
164af732203SDimitry Andric // rules.
165af732203SDimitry Andric int64_t SignedValue;
166af732203SDimitry Andric memcpy(&SignedValue, &UnsignedValue, sizeof(SignedValue));
167af732203SDimitry Andric return SignedValue;
168af732203SDimitry Andric }
169af732203SDimitry Andric
getSignedValue() const170af732203SDimitry Andric Expected<int64_t> ExpressionValue::getSignedValue() const {
171af732203SDimitry Andric if (Negative)
172af732203SDimitry Andric return getAsSigned(Value);
173af732203SDimitry Andric
174af732203SDimitry Andric if (Value > (uint64_t)std::numeric_limits<int64_t>::max())
175af732203SDimitry Andric return make_error<OverflowError>();
176af732203SDimitry Andric
177af732203SDimitry Andric // Value is in the representable range of int64_t so we can use cast.
178af732203SDimitry Andric return static_cast<int64_t>(Value);
179af732203SDimitry Andric }
180af732203SDimitry Andric
getUnsignedValue() const181af732203SDimitry Andric Expected<uint64_t> ExpressionValue::getUnsignedValue() const {
182af732203SDimitry Andric if (Negative)
183af732203SDimitry Andric return make_error<OverflowError>();
184af732203SDimitry Andric
185af732203SDimitry Andric return Value;
186af732203SDimitry Andric }
187af732203SDimitry Andric
getAbsolute() const188af732203SDimitry Andric ExpressionValue ExpressionValue::getAbsolute() const {
189af732203SDimitry Andric if (!Negative)
190af732203SDimitry Andric return *this;
191af732203SDimitry Andric
192af732203SDimitry Andric int64_t SignedValue = getAsSigned(Value);
193af732203SDimitry Andric int64_t MaxInt64 = std::numeric_limits<int64_t>::max();
194af732203SDimitry Andric // Absolute value can be represented as int64_t.
195af732203SDimitry Andric if (SignedValue >= -MaxInt64)
196af732203SDimitry Andric return ExpressionValue(-getAsSigned(Value));
197af732203SDimitry Andric
198af732203SDimitry Andric // -X == -(max int64_t + Rem), negate each component independently.
199af732203SDimitry Andric SignedValue += MaxInt64;
200af732203SDimitry Andric uint64_t RemainingValueAbsolute = -SignedValue;
201af732203SDimitry Andric return ExpressionValue(MaxInt64 + RemainingValueAbsolute);
202af732203SDimitry Andric }
203af732203SDimitry Andric
operator +(const ExpressionValue & LeftOperand,const ExpressionValue & RightOperand)204af732203SDimitry Andric Expected<ExpressionValue> llvm::operator+(const ExpressionValue &LeftOperand,
205af732203SDimitry Andric const ExpressionValue &RightOperand) {
206af732203SDimitry Andric if (LeftOperand.isNegative() && RightOperand.isNegative()) {
207af732203SDimitry Andric int64_t LeftValue = cantFail(LeftOperand.getSignedValue());
208af732203SDimitry Andric int64_t RightValue = cantFail(RightOperand.getSignedValue());
209af732203SDimitry Andric Optional<int64_t> Result = checkedAdd<int64_t>(LeftValue, RightValue);
210af732203SDimitry Andric if (!Result)
211af732203SDimitry Andric return make_error<OverflowError>();
212af732203SDimitry Andric
213af732203SDimitry Andric return ExpressionValue(*Result);
214af732203SDimitry Andric }
215af732203SDimitry Andric
216af732203SDimitry Andric // (-A) + B == B - A.
217af732203SDimitry Andric if (LeftOperand.isNegative())
218af732203SDimitry Andric return RightOperand - LeftOperand.getAbsolute();
219af732203SDimitry Andric
220af732203SDimitry Andric // A + (-B) == A - B.
221af732203SDimitry Andric if (RightOperand.isNegative())
222af732203SDimitry Andric return LeftOperand - RightOperand.getAbsolute();
223af732203SDimitry Andric
224af732203SDimitry Andric // Both values are positive at this point.
225af732203SDimitry Andric uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
226af732203SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
227af732203SDimitry Andric Optional<uint64_t> Result =
228af732203SDimitry Andric checkedAddUnsigned<uint64_t>(LeftValue, RightValue);
229af732203SDimitry Andric if (!Result)
230af732203SDimitry Andric return make_error<OverflowError>();
231af732203SDimitry Andric
232af732203SDimitry Andric return ExpressionValue(*Result);
233af732203SDimitry Andric }
234af732203SDimitry Andric
operator -(const ExpressionValue & LeftOperand,const ExpressionValue & RightOperand)235af732203SDimitry Andric Expected<ExpressionValue> llvm::operator-(const ExpressionValue &LeftOperand,
236af732203SDimitry Andric const ExpressionValue &RightOperand) {
237af732203SDimitry Andric // Result will be negative and thus might underflow.
238af732203SDimitry Andric if (LeftOperand.isNegative() && !RightOperand.isNegative()) {
239af732203SDimitry Andric int64_t LeftValue = cantFail(LeftOperand.getSignedValue());
240af732203SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
241af732203SDimitry Andric // Result <= -1 - (max int64_t) which overflows on 1- and 2-complement.
242af732203SDimitry Andric if (RightValue > (uint64_t)std::numeric_limits<int64_t>::max())
243af732203SDimitry Andric return make_error<OverflowError>();
244af732203SDimitry Andric Optional<int64_t> Result =
245af732203SDimitry Andric checkedSub(LeftValue, static_cast<int64_t>(RightValue));
246af732203SDimitry Andric if (!Result)
247af732203SDimitry Andric return make_error<OverflowError>();
248af732203SDimitry Andric
249af732203SDimitry Andric return ExpressionValue(*Result);
250af732203SDimitry Andric }
251af732203SDimitry Andric
252af732203SDimitry Andric // (-A) - (-B) == B - A.
253af732203SDimitry Andric if (LeftOperand.isNegative())
254af732203SDimitry Andric return RightOperand.getAbsolute() - LeftOperand.getAbsolute();
255af732203SDimitry Andric
256af732203SDimitry Andric // A - (-B) == A + B.
257af732203SDimitry Andric if (RightOperand.isNegative())
258af732203SDimitry Andric return LeftOperand + RightOperand.getAbsolute();
259af732203SDimitry Andric
260af732203SDimitry Andric // Both values are positive at this point.
261af732203SDimitry Andric uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
262af732203SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
263af732203SDimitry Andric if (LeftValue >= RightValue)
264af732203SDimitry Andric return ExpressionValue(LeftValue - RightValue);
265af732203SDimitry Andric else {
266af732203SDimitry Andric uint64_t AbsoluteDifference = RightValue - LeftValue;
267af732203SDimitry Andric uint64_t MaxInt64 = std::numeric_limits<int64_t>::max();
268af732203SDimitry Andric // Value might underflow.
269af732203SDimitry Andric if (AbsoluteDifference > MaxInt64) {
270af732203SDimitry Andric AbsoluteDifference -= MaxInt64;
271af732203SDimitry Andric int64_t Result = -MaxInt64;
272af732203SDimitry Andric int64_t MinInt64 = std::numeric_limits<int64_t>::min();
273af732203SDimitry Andric // Underflow, tested by:
274af732203SDimitry Andric // abs(Result + (max int64_t)) > abs((min int64_t) + (max int64_t))
275af732203SDimitry Andric if (AbsoluteDifference > static_cast<uint64_t>(-(MinInt64 - Result)))
276af732203SDimitry Andric return make_error<OverflowError>();
277af732203SDimitry Andric Result -= static_cast<int64_t>(AbsoluteDifference);
278af732203SDimitry Andric return ExpressionValue(Result);
279af732203SDimitry Andric }
280af732203SDimitry Andric
281af732203SDimitry Andric return ExpressionValue(-static_cast<int64_t>(AbsoluteDifference));
282af732203SDimitry Andric }
283af732203SDimitry Andric }
284af732203SDimitry Andric
operator *(const ExpressionValue & LeftOperand,const ExpressionValue & RightOperand)285af732203SDimitry Andric Expected<ExpressionValue> llvm::operator*(const ExpressionValue &LeftOperand,
286af732203SDimitry Andric const ExpressionValue &RightOperand) {
287af732203SDimitry Andric // -A * -B == A * B
288af732203SDimitry Andric if (LeftOperand.isNegative() && RightOperand.isNegative())
289af732203SDimitry Andric return LeftOperand.getAbsolute() * RightOperand.getAbsolute();
290af732203SDimitry Andric
291af732203SDimitry Andric // A * -B == -B * A
292af732203SDimitry Andric if (RightOperand.isNegative())
293af732203SDimitry Andric return RightOperand * LeftOperand;
294af732203SDimitry Andric
295af732203SDimitry Andric assert(!RightOperand.isNegative() && "Unexpected negative operand!");
296af732203SDimitry Andric
297af732203SDimitry Andric // Result will be negative and can underflow.
298af732203SDimitry Andric if (LeftOperand.isNegative()) {
299af732203SDimitry Andric auto Result = LeftOperand.getAbsolute() * RightOperand.getAbsolute();
300af732203SDimitry Andric if (!Result)
301af732203SDimitry Andric return Result;
302af732203SDimitry Andric
303af732203SDimitry Andric return ExpressionValue(0) - *Result;
304af732203SDimitry Andric }
305af732203SDimitry Andric
306af732203SDimitry Andric // Result will be positive and can overflow.
307af732203SDimitry Andric uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
308af732203SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
309af732203SDimitry Andric Optional<uint64_t> Result =
310af732203SDimitry Andric checkedMulUnsigned<uint64_t>(LeftValue, RightValue);
311af732203SDimitry Andric if (!Result)
312af732203SDimitry Andric return make_error<OverflowError>();
313af732203SDimitry Andric
314af732203SDimitry Andric return ExpressionValue(*Result);
315af732203SDimitry Andric }
316af732203SDimitry Andric
operator /(const ExpressionValue & LeftOperand,const ExpressionValue & RightOperand)317af732203SDimitry Andric Expected<ExpressionValue> llvm::operator/(const ExpressionValue &LeftOperand,
318af732203SDimitry Andric const ExpressionValue &RightOperand) {
319af732203SDimitry Andric // -A / -B == A / B
320af732203SDimitry Andric if (LeftOperand.isNegative() && RightOperand.isNegative())
321af732203SDimitry Andric return LeftOperand.getAbsolute() / RightOperand.getAbsolute();
322af732203SDimitry Andric
323af732203SDimitry Andric // Check for divide by zero.
324af732203SDimitry Andric if (RightOperand == ExpressionValue(0))
325af732203SDimitry Andric return make_error<OverflowError>();
326af732203SDimitry Andric
327af732203SDimitry Andric // Result will be negative and can underflow.
328af732203SDimitry Andric if (LeftOperand.isNegative() || RightOperand.isNegative())
329af732203SDimitry Andric return ExpressionValue(0) -
330af732203SDimitry Andric cantFail(LeftOperand.getAbsolute() / RightOperand.getAbsolute());
331af732203SDimitry Andric
332af732203SDimitry Andric uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
333af732203SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
334af732203SDimitry Andric return ExpressionValue(LeftValue / RightValue);
335af732203SDimitry Andric }
336af732203SDimitry Andric
max(const ExpressionValue & LeftOperand,const ExpressionValue & RightOperand)337af732203SDimitry Andric Expected<ExpressionValue> llvm::max(const ExpressionValue &LeftOperand,
338af732203SDimitry Andric const ExpressionValue &RightOperand) {
339af732203SDimitry Andric if (LeftOperand.isNegative() && RightOperand.isNegative()) {
340af732203SDimitry Andric int64_t LeftValue = cantFail(LeftOperand.getSignedValue());
341af732203SDimitry Andric int64_t RightValue = cantFail(RightOperand.getSignedValue());
342af732203SDimitry Andric return ExpressionValue(std::max(LeftValue, RightValue));
343af732203SDimitry Andric }
344af732203SDimitry Andric
345af732203SDimitry Andric if (!LeftOperand.isNegative() && !RightOperand.isNegative()) {
346af732203SDimitry Andric uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
347af732203SDimitry Andric uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
348af732203SDimitry Andric return ExpressionValue(std::max(LeftValue, RightValue));
349af732203SDimitry Andric }
350af732203SDimitry Andric
351af732203SDimitry Andric if (LeftOperand.isNegative())
352af732203SDimitry Andric return RightOperand;
353af732203SDimitry Andric
354af732203SDimitry Andric return LeftOperand;
355af732203SDimitry Andric }
356af732203SDimitry Andric
min(const ExpressionValue & LeftOperand,const ExpressionValue & RightOperand)357af732203SDimitry Andric Expected<ExpressionValue> llvm::min(const ExpressionValue &LeftOperand,
358af732203SDimitry Andric const ExpressionValue &RightOperand) {
359af732203SDimitry Andric if (cantFail(max(LeftOperand, RightOperand)) == LeftOperand)
360af732203SDimitry Andric return RightOperand;
361af732203SDimitry Andric
362af732203SDimitry Andric return LeftOperand;
363af732203SDimitry Andric }
364af732203SDimitry Andric
eval() const365af732203SDimitry Andric Expected<ExpressionValue> NumericVariableUse::eval() const {
366af732203SDimitry Andric Optional<ExpressionValue> Value = Variable->getValue();
367af732203SDimitry Andric if (Value)
368af732203SDimitry Andric return *Value;
369af732203SDimitry Andric
370af732203SDimitry Andric return make_error<UndefVarError>(getExpressionStr());
371af732203SDimitry Andric }
372af732203SDimitry Andric
eval() const373af732203SDimitry Andric Expected<ExpressionValue> BinaryOperation::eval() const {
374af732203SDimitry Andric Expected<ExpressionValue> LeftOp = LeftOperand->eval();
375af732203SDimitry Andric Expected<ExpressionValue> RightOp = RightOperand->eval();
376af732203SDimitry Andric
377af732203SDimitry Andric // Bubble up any error (e.g. undefined variables) in the recursive
378af732203SDimitry Andric // evaluation.
379af732203SDimitry Andric if (!LeftOp || !RightOp) {
380af732203SDimitry Andric Error Err = Error::success();
381af732203SDimitry Andric if (!LeftOp)
382af732203SDimitry Andric Err = joinErrors(std::move(Err), LeftOp.takeError());
383af732203SDimitry Andric if (!RightOp)
384af732203SDimitry Andric Err = joinErrors(std::move(Err), RightOp.takeError());
385af732203SDimitry Andric return std::move(Err);
386af732203SDimitry Andric }
387af732203SDimitry Andric
388af732203SDimitry Andric return EvalBinop(*LeftOp, *RightOp);
389af732203SDimitry Andric }
390af732203SDimitry Andric
391af732203SDimitry Andric Expected<ExpressionFormat>
getImplicitFormat(const SourceMgr & SM) const392af732203SDimitry Andric BinaryOperation::getImplicitFormat(const SourceMgr &SM) const {
393af732203SDimitry Andric Expected<ExpressionFormat> LeftFormat = LeftOperand->getImplicitFormat(SM);
394af732203SDimitry Andric Expected<ExpressionFormat> RightFormat = RightOperand->getImplicitFormat(SM);
395af732203SDimitry Andric if (!LeftFormat || !RightFormat) {
396af732203SDimitry Andric Error Err = Error::success();
397af732203SDimitry Andric if (!LeftFormat)
398af732203SDimitry Andric Err = joinErrors(std::move(Err), LeftFormat.takeError());
399af732203SDimitry Andric if (!RightFormat)
400af732203SDimitry Andric Err = joinErrors(std::move(Err), RightFormat.takeError());
401af732203SDimitry Andric return std::move(Err);
402af732203SDimitry Andric }
403af732203SDimitry Andric
404af732203SDimitry Andric if (*LeftFormat != ExpressionFormat::Kind::NoFormat &&
405af732203SDimitry Andric *RightFormat != ExpressionFormat::Kind::NoFormat &&
406af732203SDimitry Andric *LeftFormat != *RightFormat)
407af732203SDimitry Andric return ErrorDiagnostic::get(
408af732203SDimitry Andric SM, getExpressionStr(),
409af732203SDimitry Andric "implicit format conflict between '" + LeftOperand->getExpressionStr() +
410af732203SDimitry Andric "' (" + LeftFormat->toString() + ") and '" +
411af732203SDimitry Andric RightOperand->getExpressionStr() + "' (" + RightFormat->toString() +
412af732203SDimitry Andric "), need an explicit format specifier");
413af732203SDimitry Andric
414af732203SDimitry Andric return *LeftFormat != ExpressionFormat::Kind::NoFormat ? *LeftFormat
415af732203SDimitry Andric : *RightFormat;
416af732203SDimitry Andric }
417af732203SDimitry Andric
getResult() const418af732203SDimitry Andric Expected<std::string> NumericSubstitution::getResult() const {
419af732203SDimitry Andric assert(ExpressionPointer->getAST() != nullptr &&
420af732203SDimitry Andric "Substituting empty expression");
421af732203SDimitry Andric Expected<ExpressionValue> EvaluatedValue =
422af732203SDimitry Andric ExpressionPointer->getAST()->eval();
423af732203SDimitry Andric if (!EvaluatedValue)
424af732203SDimitry Andric return EvaluatedValue.takeError();
425af732203SDimitry Andric ExpressionFormat Format = ExpressionPointer->getFormat();
426af732203SDimitry Andric return Format.getMatchingString(*EvaluatedValue);
427af732203SDimitry Andric }
428af732203SDimitry Andric
getResult() const429af732203SDimitry Andric Expected<std::string> StringSubstitution::getResult() const {
430af732203SDimitry Andric // Look up the value and escape it so that we can put it into the regex.
431af732203SDimitry Andric Expected<StringRef> VarVal = Context->getPatternVarValue(FromStr);
432af732203SDimitry Andric if (!VarVal)
433af732203SDimitry Andric return VarVal.takeError();
434af732203SDimitry Andric return Regex::escape(*VarVal);
435af732203SDimitry Andric }
436af732203SDimitry Andric
isValidVarNameStart(char C)437af732203SDimitry Andric bool Pattern::isValidVarNameStart(char C) { return C == '_' || isAlpha(C); }
438af732203SDimitry Andric
439af732203SDimitry Andric Expected<Pattern::VariableProperties>
parseVariable(StringRef & Str,const SourceMgr & SM)440af732203SDimitry Andric Pattern::parseVariable(StringRef &Str, const SourceMgr &SM) {
441af732203SDimitry Andric if (Str.empty())
442af732203SDimitry Andric return ErrorDiagnostic::get(SM, Str, "empty variable name");
443af732203SDimitry Andric
444af732203SDimitry Andric size_t I = 0;
445af732203SDimitry Andric bool IsPseudo = Str[0] == '@';
446af732203SDimitry Andric
447af732203SDimitry Andric // Global vars start with '$'.
448af732203SDimitry Andric if (Str[0] == '$' || IsPseudo)
449af732203SDimitry Andric ++I;
450af732203SDimitry Andric
451af732203SDimitry Andric if (!isValidVarNameStart(Str[I++]))
452af732203SDimitry Andric return ErrorDiagnostic::get(SM, Str, "invalid variable name");
453af732203SDimitry Andric
454af732203SDimitry Andric for (size_t E = Str.size(); I != E; ++I)
455af732203SDimitry Andric // Variable names are composed of alphanumeric characters and underscores.
456af732203SDimitry Andric if (Str[I] != '_' && !isAlnum(Str[I]))
457af732203SDimitry Andric break;
458af732203SDimitry Andric
459af732203SDimitry Andric StringRef Name = Str.take_front(I);
460af732203SDimitry Andric Str = Str.substr(I);
461af732203SDimitry Andric return VariableProperties {Name, IsPseudo};
462af732203SDimitry Andric }
463af732203SDimitry Andric
464af732203SDimitry Andric // StringRef holding all characters considered as horizontal whitespaces by
465af732203SDimitry Andric // FileCheck input canonicalization.
466af732203SDimitry Andric constexpr StringLiteral SpaceChars = " \t";
467af732203SDimitry Andric
468af732203SDimitry Andric // Parsing helper function that strips the first character in S and returns it.
popFront(StringRef & S)469af732203SDimitry Andric static char popFront(StringRef &S) {
470af732203SDimitry Andric char C = S.front();
471af732203SDimitry Andric S = S.drop_front();
472af732203SDimitry Andric return C;
473af732203SDimitry Andric }
474af732203SDimitry Andric
475af732203SDimitry Andric char OverflowError::ID = 0;
476af732203SDimitry Andric char UndefVarError::ID = 0;
477af732203SDimitry Andric char ErrorDiagnostic::ID = 0;
478af732203SDimitry Andric char NotFoundError::ID = 0;
479*5f7ddb14SDimitry Andric char ErrorReported::ID = 0;
480af732203SDimitry Andric
parseNumericVariableDefinition(StringRef & Expr,FileCheckPatternContext * Context,Optional<size_t> LineNumber,ExpressionFormat ImplicitFormat,const SourceMgr & SM)481af732203SDimitry Andric Expected<NumericVariable *> Pattern::parseNumericVariableDefinition(
482af732203SDimitry Andric StringRef &Expr, FileCheckPatternContext *Context,
483af732203SDimitry Andric Optional<size_t> LineNumber, ExpressionFormat ImplicitFormat,
484af732203SDimitry Andric const SourceMgr &SM) {
485af732203SDimitry Andric Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);
486af732203SDimitry Andric if (!ParseVarResult)
487af732203SDimitry Andric return ParseVarResult.takeError();
488af732203SDimitry Andric StringRef Name = ParseVarResult->Name;
489af732203SDimitry Andric
490af732203SDimitry Andric if (ParseVarResult->IsPseudo)
491af732203SDimitry Andric return ErrorDiagnostic::get(
492af732203SDimitry Andric SM, Name, "definition of pseudo numeric variable unsupported");
493af732203SDimitry Andric
494af732203SDimitry Andric // Detect collisions between string and numeric variables when the latter
495af732203SDimitry Andric // is created later than the former.
496af732203SDimitry Andric if (Context->DefinedVariableTable.find(Name) !=
497af732203SDimitry Andric Context->DefinedVariableTable.end())
498af732203SDimitry Andric return ErrorDiagnostic::get(
499af732203SDimitry Andric SM, Name, "string variable with name '" + Name + "' already exists");
500af732203SDimitry Andric
501af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
502af732203SDimitry Andric if (!Expr.empty())
503af732203SDimitry Andric return ErrorDiagnostic::get(
504af732203SDimitry Andric SM, Expr, "unexpected characters after numeric variable name");
505af732203SDimitry Andric
506af732203SDimitry Andric NumericVariable *DefinedNumericVariable;
507af732203SDimitry Andric auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
508af732203SDimitry Andric if (VarTableIter != Context->GlobalNumericVariableTable.end()) {
509af732203SDimitry Andric DefinedNumericVariable = VarTableIter->second;
510af732203SDimitry Andric if (DefinedNumericVariable->getImplicitFormat() != ImplicitFormat)
511af732203SDimitry Andric return ErrorDiagnostic::get(
512af732203SDimitry Andric SM, Expr, "format different from previous variable definition");
513af732203SDimitry Andric } else
514af732203SDimitry Andric DefinedNumericVariable =
515af732203SDimitry Andric Context->makeNumericVariable(Name, ImplicitFormat, LineNumber);
516af732203SDimitry Andric
517af732203SDimitry Andric return DefinedNumericVariable;
518af732203SDimitry Andric }
519af732203SDimitry Andric
parseNumericVariableUse(StringRef Name,bool IsPseudo,Optional<size_t> LineNumber,FileCheckPatternContext * Context,const SourceMgr & SM)520af732203SDimitry Andric Expected<std::unique_ptr<NumericVariableUse>> Pattern::parseNumericVariableUse(
521af732203SDimitry Andric StringRef Name, bool IsPseudo, Optional<size_t> LineNumber,
522af732203SDimitry Andric FileCheckPatternContext *Context, const SourceMgr &SM) {
523af732203SDimitry Andric if (IsPseudo && !Name.equals("@LINE"))
524af732203SDimitry Andric return ErrorDiagnostic::get(
525af732203SDimitry Andric SM, Name, "invalid pseudo numeric variable '" + Name + "'");
526af732203SDimitry Andric
527af732203SDimitry Andric // Numeric variable definitions and uses are parsed in the order in which
528af732203SDimitry Andric // they appear in the CHECK patterns. For each definition, the pointer to the
529af732203SDimitry Andric // class instance of the corresponding numeric variable definition is stored
530af732203SDimitry Andric // in GlobalNumericVariableTable in parsePattern. Therefore, if the pointer
531af732203SDimitry Andric // we get below is null, it means no such variable was defined before. When
532af732203SDimitry Andric // that happens, we create a dummy variable so that parsing can continue. All
533af732203SDimitry Andric // uses of undefined variables, whether string or numeric, are then diagnosed
534*5f7ddb14SDimitry Andric // in printNoMatch() after failing to match.
535af732203SDimitry Andric auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
536af732203SDimitry Andric NumericVariable *NumericVariable;
537af732203SDimitry Andric if (VarTableIter != Context->GlobalNumericVariableTable.end())
538af732203SDimitry Andric NumericVariable = VarTableIter->second;
539af732203SDimitry Andric else {
540af732203SDimitry Andric NumericVariable = Context->makeNumericVariable(
541af732203SDimitry Andric Name, ExpressionFormat(ExpressionFormat::Kind::Unsigned));
542af732203SDimitry Andric Context->GlobalNumericVariableTable[Name] = NumericVariable;
543af732203SDimitry Andric }
544af732203SDimitry Andric
545af732203SDimitry Andric Optional<size_t> DefLineNumber = NumericVariable->getDefLineNumber();
546af732203SDimitry Andric if (DefLineNumber && LineNumber && *DefLineNumber == *LineNumber)
547af732203SDimitry Andric return ErrorDiagnostic::get(
548af732203SDimitry Andric SM, Name,
549af732203SDimitry Andric "numeric variable '" + Name +
550af732203SDimitry Andric "' defined earlier in the same CHECK directive");
551af732203SDimitry Andric
552af732203SDimitry Andric return std::make_unique<NumericVariableUse>(Name, NumericVariable);
553af732203SDimitry Andric }
554af732203SDimitry Andric
parseNumericOperand(StringRef & Expr,AllowedOperand AO,bool MaybeInvalidConstraint,Optional<size_t> LineNumber,FileCheckPatternContext * Context,const SourceMgr & SM)555af732203SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand(
556af732203SDimitry Andric StringRef &Expr, AllowedOperand AO, bool MaybeInvalidConstraint,
557af732203SDimitry Andric Optional<size_t> LineNumber, FileCheckPatternContext *Context,
558af732203SDimitry Andric const SourceMgr &SM) {
559af732203SDimitry Andric if (Expr.startswith("(")) {
560af732203SDimitry Andric if (AO != AllowedOperand::Any)
561af732203SDimitry Andric return ErrorDiagnostic::get(
562af732203SDimitry Andric SM, Expr, "parenthesized expression not permitted here");
563af732203SDimitry Andric return parseParenExpr(Expr, LineNumber, Context, SM);
564af732203SDimitry Andric }
565af732203SDimitry Andric
566af732203SDimitry Andric if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {
567af732203SDimitry Andric // Try to parse as a numeric variable use.
568af732203SDimitry Andric Expected<Pattern::VariableProperties> ParseVarResult =
569af732203SDimitry Andric parseVariable(Expr, SM);
570af732203SDimitry Andric if (ParseVarResult) {
571af732203SDimitry Andric // Try to parse a function call.
572af732203SDimitry Andric if (Expr.ltrim(SpaceChars).startswith("(")) {
573af732203SDimitry Andric if (AO != AllowedOperand::Any)
574af732203SDimitry Andric return ErrorDiagnostic::get(SM, ParseVarResult->Name,
575af732203SDimitry Andric "unexpected function call");
576af732203SDimitry Andric
577af732203SDimitry Andric return parseCallExpr(Expr, ParseVarResult->Name, LineNumber, Context,
578af732203SDimitry Andric SM);
579af732203SDimitry Andric }
580af732203SDimitry Andric
581af732203SDimitry Andric return parseNumericVariableUse(ParseVarResult->Name,
582af732203SDimitry Andric ParseVarResult->IsPseudo, LineNumber,
583af732203SDimitry Andric Context, SM);
584af732203SDimitry Andric }
585af732203SDimitry Andric
586af732203SDimitry Andric if (AO == AllowedOperand::LineVar)
587af732203SDimitry Andric return ParseVarResult.takeError();
588af732203SDimitry Andric // Ignore the error and retry parsing as a literal.
589af732203SDimitry Andric consumeError(ParseVarResult.takeError());
590af732203SDimitry Andric }
591af732203SDimitry Andric
592af732203SDimitry Andric // Otherwise, parse it as a literal.
593af732203SDimitry Andric int64_t SignedLiteralValue;
594af732203SDimitry Andric uint64_t UnsignedLiteralValue;
595af732203SDimitry Andric StringRef SaveExpr = Expr;
596af732203SDimitry Andric // Accept both signed and unsigned literal, default to signed literal.
597af732203SDimitry Andric if (!Expr.consumeInteger((AO == AllowedOperand::LegacyLiteral) ? 10 : 0,
598af732203SDimitry Andric UnsignedLiteralValue))
599af732203SDimitry Andric return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()),
600af732203SDimitry Andric UnsignedLiteralValue);
601af732203SDimitry Andric Expr = SaveExpr;
602af732203SDimitry Andric if (AO == AllowedOperand::Any && !Expr.consumeInteger(0, SignedLiteralValue))
603af732203SDimitry Andric return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()),
604af732203SDimitry Andric SignedLiteralValue);
605af732203SDimitry Andric
606af732203SDimitry Andric return ErrorDiagnostic::get(
607af732203SDimitry Andric SM, Expr,
608af732203SDimitry Andric Twine("invalid ") +
609af732203SDimitry Andric (MaybeInvalidConstraint ? "matching constraint or " : "") +
610af732203SDimitry Andric "operand format");
611af732203SDimitry Andric }
612af732203SDimitry Andric
613af732203SDimitry Andric Expected<std::unique_ptr<ExpressionAST>>
parseParenExpr(StringRef & Expr,Optional<size_t> LineNumber,FileCheckPatternContext * Context,const SourceMgr & SM)614af732203SDimitry Andric Pattern::parseParenExpr(StringRef &Expr, Optional<size_t> LineNumber,
615af732203SDimitry Andric FileCheckPatternContext *Context, const SourceMgr &SM) {
616af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
617af732203SDimitry Andric assert(Expr.startswith("("));
618af732203SDimitry Andric
619af732203SDimitry Andric // Parse right operand.
620af732203SDimitry Andric Expr.consume_front("(");
621af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
622af732203SDimitry Andric if (Expr.empty())
623af732203SDimitry Andric return ErrorDiagnostic::get(SM, Expr, "missing operand in expression");
624af732203SDimitry Andric
625af732203SDimitry Andric // Note: parseNumericOperand handles nested opening parentheses.
626af732203SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> SubExprResult = parseNumericOperand(
627af732203SDimitry Andric Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber,
628af732203SDimitry Andric Context, SM);
629af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
630af732203SDimitry Andric while (SubExprResult && !Expr.empty() && !Expr.startswith(")")) {
631af732203SDimitry Andric StringRef OrigExpr = Expr;
632af732203SDimitry Andric SubExprResult = parseBinop(OrigExpr, Expr, std::move(*SubExprResult), false,
633af732203SDimitry Andric LineNumber, Context, SM);
634af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
635af732203SDimitry Andric }
636af732203SDimitry Andric if (!SubExprResult)
637af732203SDimitry Andric return SubExprResult;
638af732203SDimitry Andric
639af732203SDimitry Andric if (!Expr.consume_front(")")) {
640af732203SDimitry Andric return ErrorDiagnostic::get(SM, Expr,
641af732203SDimitry Andric "missing ')' at end of nested expression");
642af732203SDimitry Andric }
643af732203SDimitry Andric return SubExprResult;
644af732203SDimitry Andric }
645af732203SDimitry Andric
646af732203SDimitry Andric Expected<std::unique_ptr<ExpressionAST>>
parseBinop(StringRef Expr,StringRef & RemainingExpr,std::unique_ptr<ExpressionAST> LeftOp,bool IsLegacyLineExpr,Optional<size_t> LineNumber,FileCheckPatternContext * Context,const SourceMgr & SM)647af732203SDimitry Andric Pattern::parseBinop(StringRef Expr, StringRef &RemainingExpr,
648af732203SDimitry Andric std::unique_ptr<ExpressionAST> LeftOp,
649af732203SDimitry Andric bool IsLegacyLineExpr, Optional<size_t> LineNumber,
650af732203SDimitry Andric FileCheckPatternContext *Context, const SourceMgr &SM) {
651af732203SDimitry Andric RemainingExpr = RemainingExpr.ltrim(SpaceChars);
652af732203SDimitry Andric if (RemainingExpr.empty())
653af732203SDimitry Andric return std::move(LeftOp);
654af732203SDimitry Andric
655af732203SDimitry Andric // Check if this is a supported operation and select a function to perform
656af732203SDimitry Andric // it.
657af732203SDimitry Andric SMLoc OpLoc = SMLoc::getFromPointer(RemainingExpr.data());
658af732203SDimitry Andric char Operator = popFront(RemainingExpr);
659af732203SDimitry Andric binop_eval_t EvalBinop;
660af732203SDimitry Andric switch (Operator) {
661af732203SDimitry Andric case '+':
662af732203SDimitry Andric EvalBinop = operator+;
663af732203SDimitry Andric break;
664af732203SDimitry Andric case '-':
665af732203SDimitry Andric EvalBinop = operator-;
666af732203SDimitry Andric break;
667af732203SDimitry Andric default:
668af732203SDimitry Andric return ErrorDiagnostic::get(
669af732203SDimitry Andric SM, OpLoc, Twine("unsupported operation '") + Twine(Operator) + "'");
670af732203SDimitry Andric }
671af732203SDimitry Andric
672af732203SDimitry Andric // Parse right operand.
673af732203SDimitry Andric RemainingExpr = RemainingExpr.ltrim(SpaceChars);
674af732203SDimitry Andric if (RemainingExpr.empty())
675af732203SDimitry Andric return ErrorDiagnostic::get(SM, RemainingExpr,
676af732203SDimitry Andric "missing operand in expression");
677af732203SDimitry Andric // The second operand in a legacy @LINE expression is always a literal.
678af732203SDimitry Andric AllowedOperand AO =
679af732203SDimitry Andric IsLegacyLineExpr ? AllowedOperand::LegacyLiteral : AllowedOperand::Any;
680af732203SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> RightOpResult =
681af732203SDimitry Andric parseNumericOperand(RemainingExpr, AO, /*MaybeInvalidConstraint=*/false,
682af732203SDimitry Andric LineNumber, Context, SM);
683af732203SDimitry Andric if (!RightOpResult)
684af732203SDimitry Andric return RightOpResult;
685af732203SDimitry Andric
686af732203SDimitry Andric Expr = Expr.drop_back(RemainingExpr.size());
687af732203SDimitry Andric return std::make_unique<BinaryOperation>(Expr, EvalBinop, std::move(LeftOp),
688af732203SDimitry Andric std::move(*RightOpResult));
689af732203SDimitry Andric }
690af732203SDimitry Andric
691af732203SDimitry Andric Expected<std::unique_ptr<ExpressionAST>>
parseCallExpr(StringRef & Expr,StringRef FuncName,Optional<size_t> LineNumber,FileCheckPatternContext * Context,const SourceMgr & SM)692af732203SDimitry Andric Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName,
693af732203SDimitry Andric Optional<size_t> LineNumber,
694af732203SDimitry Andric FileCheckPatternContext *Context, const SourceMgr &SM) {
695af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
696af732203SDimitry Andric assert(Expr.startswith("("));
697af732203SDimitry Andric
698af732203SDimitry Andric auto OptFunc = StringSwitch<Optional<binop_eval_t>>(FuncName)
699af732203SDimitry Andric .Case("add", operator+)
700af732203SDimitry Andric .Case("div", operator/)
701af732203SDimitry Andric .Case("max", max)
702af732203SDimitry Andric .Case("min", min)
703af732203SDimitry Andric .Case("mul", operator*)
704af732203SDimitry Andric .Case("sub", operator-)
705af732203SDimitry Andric .Default(None);
706af732203SDimitry Andric
707af732203SDimitry Andric if (!OptFunc)
708af732203SDimitry Andric return ErrorDiagnostic::get(
709af732203SDimitry Andric SM, FuncName, Twine("call to undefined function '") + FuncName + "'");
710af732203SDimitry Andric
711af732203SDimitry Andric Expr.consume_front("(");
712af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
713af732203SDimitry Andric
714af732203SDimitry Andric // Parse call arguments, which are comma separated.
715af732203SDimitry Andric SmallVector<std::unique_ptr<ExpressionAST>, 4> Args;
716af732203SDimitry Andric while (!Expr.empty() && !Expr.startswith(")")) {
717af732203SDimitry Andric if (Expr.startswith(","))
718af732203SDimitry Andric return ErrorDiagnostic::get(SM, Expr, "missing argument");
719af732203SDimitry Andric
720af732203SDimitry Andric // Parse the argument, which is an arbitary expression.
721af732203SDimitry Andric StringRef OuterBinOpExpr = Expr;
722af732203SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> Arg = parseNumericOperand(
723af732203SDimitry Andric Expr, AllowedOperand::Any, /*MaybeInvalidConstraint=*/false, LineNumber,
724af732203SDimitry Andric Context, SM);
725af732203SDimitry Andric while (Arg && !Expr.empty()) {
726af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
727af732203SDimitry Andric // Have we reached an argument terminator?
728af732203SDimitry Andric if (Expr.startswith(",") || Expr.startswith(")"))
729af732203SDimitry Andric break;
730af732203SDimitry Andric
731af732203SDimitry Andric // Arg = Arg <op> <expr>
732af732203SDimitry Andric Arg = parseBinop(OuterBinOpExpr, Expr, std::move(*Arg), false, LineNumber,
733af732203SDimitry Andric Context, SM);
734af732203SDimitry Andric }
735af732203SDimitry Andric
736af732203SDimitry Andric // Prefer an expression error over a generic invalid argument message.
737af732203SDimitry Andric if (!Arg)
738af732203SDimitry Andric return Arg.takeError();
739af732203SDimitry Andric Args.push_back(std::move(*Arg));
740af732203SDimitry Andric
741af732203SDimitry Andric // Have we parsed all available arguments?
742af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
743af732203SDimitry Andric if (!Expr.consume_front(","))
744af732203SDimitry Andric break;
745af732203SDimitry Andric
746af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
747af732203SDimitry Andric if (Expr.startswith(")"))
748af732203SDimitry Andric return ErrorDiagnostic::get(SM, Expr, "missing argument");
749af732203SDimitry Andric }
750af732203SDimitry Andric
751af732203SDimitry Andric if (!Expr.consume_front(")"))
752af732203SDimitry Andric return ErrorDiagnostic::get(SM, Expr,
753af732203SDimitry Andric "missing ')' at end of call expression");
754af732203SDimitry Andric
755af732203SDimitry Andric const unsigned NumArgs = Args.size();
756af732203SDimitry Andric if (NumArgs == 2)
757af732203SDimitry Andric return std::make_unique<BinaryOperation>(Expr, *OptFunc, std::move(Args[0]),
758af732203SDimitry Andric std::move(Args[1]));
759af732203SDimitry Andric
760af732203SDimitry Andric // TODO: Support more than binop_eval_t.
761af732203SDimitry Andric return ErrorDiagnostic::get(SM, FuncName,
762af732203SDimitry Andric Twine("function '") + FuncName +
763af732203SDimitry Andric Twine("' takes 2 arguments but ") +
764af732203SDimitry Andric Twine(NumArgs) + " given");
765af732203SDimitry Andric }
766af732203SDimitry Andric
parseNumericSubstitutionBlock(StringRef Expr,Optional<NumericVariable * > & DefinedNumericVariable,bool IsLegacyLineExpr,Optional<size_t> LineNumber,FileCheckPatternContext * Context,const SourceMgr & SM)767af732203SDimitry Andric Expected<std::unique_ptr<Expression>> Pattern::parseNumericSubstitutionBlock(
768af732203SDimitry Andric StringRef Expr, Optional<NumericVariable *> &DefinedNumericVariable,
769af732203SDimitry Andric bool IsLegacyLineExpr, Optional<size_t> LineNumber,
770af732203SDimitry Andric FileCheckPatternContext *Context, const SourceMgr &SM) {
771af732203SDimitry Andric std::unique_ptr<ExpressionAST> ExpressionASTPointer = nullptr;
772af732203SDimitry Andric StringRef DefExpr = StringRef();
773af732203SDimitry Andric DefinedNumericVariable = None;
774af732203SDimitry Andric ExpressionFormat ExplicitFormat = ExpressionFormat();
775af732203SDimitry Andric unsigned Precision = 0;
776af732203SDimitry Andric
777af732203SDimitry Andric // Parse format specifier (NOTE: ',' is also an argument seperator).
778af732203SDimitry Andric size_t FormatSpecEnd = Expr.find(',');
779af732203SDimitry Andric size_t FunctionStart = Expr.find('(');
780af732203SDimitry Andric if (FormatSpecEnd != StringRef::npos && FormatSpecEnd < FunctionStart) {
781af732203SDimitry Andric StringRef FormatExpr = Expr.take_front(FormatSpecEnd);
782af732203SDimitry Andric Expr = Expr.drop_front(FormatSpecEnd + 1);
783af732203SDimitry Andric FormatExpr = FormatExpr.trim(SpaceChars);
784af732203SDimitry Andric if (!FormatExpr.consume_front("%"))
785af732203SDimitry Andric return ErrorDiagnostic::get(
786af732203SDimitry Andric SM, FormatExpr,
787af732203SDimitry Andric "invalid matching format specification in expression");
788af732203SDimitry Andric
789*5f7ddb14SDimitry Andric // Parse alternate form flag.
790*5f7ddb14SDimitry Andric SMLoc AlternateFormFlagLoc = SMLoc::getFromPointer(FormatExpr.data());
791*5f7ddb14SDimitry Andric bool AlternateForm = FormatExpr.consume_front("#");
792*5f7ddb14SDimitry Andric
793af732203SDimitry Andric // Parse precision.
794af732203SDimitry Andric if (FormatExpr.consume_front(".")) {
795af732203SDimitry Andric if (FormatExpr.consumeInteger(10, Precision))
796af732203SDimitry Andric return ErrorDiagnostic::get(SM, FormatExpr,
797af732203SDimitry Andric "invalid precision in format specifier");
798af732203SDimitry Andric }
799af732203SDimitry Andric
800af732203SDimitry Andric if (!FormatExpr.empty()) {
801af732203SDimitry Andric // Check for unknown matching format specifier and set matching format in
802af732203SDimitry Andric // class instance representing this expression.
803af732203SDimitry Andric SMLoc FmtLoc = SMLoc::getFromPointer(FormatExpr.data());
804af732203SDimitry Andric switch (popFront(FormatExpr)) {
805af732203SDimitry Andric case 'u':
806af732203SDimitry Andric ExplicitFormat =
807af732203SDimitry Andric ExpressionFormat(ExpressionFormat::Kind::Unsigned, Precision);
808af732203SDimitry Andric break;
809af732203SDimitry Andric case 'd':
810af732203SDimitry Andric ExplicitFormat =
811af732203SDimitry Andric ExpressionFormat(ExpressionFormat::Kind::Signed, Precision);
812af732203SDimitry Andric break;
813af732203SDimitry Andric case 'x':
814*5f7ddb14SDimitry Andric ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexLower,
815*5f7ddb14SDimitry Andric Precision, AlternateForm);
816af732203SDimitry Andric break;
817af732203SDimitry Andric case 'X':
818*5f7ddb14SDimitry Andric ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexUpper,
819*5f7ddb14SDimitry Andric Precision, AlternateForm);
820af732203SDimitry Andric break;
821af732203SDimitry Andric default:
822af732203SDimitry Andric return ErrorDiagnostic::get(SM, FmtLoc,
823af732203SDimitry Andric "invalid format specifier in expression");
824af732203SDimitry Andric }
825af732203SDimitry Andric }
826af732203SDimitry Andric
827*5f7ddb14SDimitry Andric if (AlternateForm && ExplicitFormat != ExpressionFormat::Kind::HexLower &&
828*5f7ddb14SDimitry Andric ExplicitFormat != ExpressionFormat::Kind::HexUpper)
829*5f7ddb14SDimitry Andric return ErrorDiagnostic::get(
830*5f7ddb14SDimitry Andric SM, AlternateFormFlagLoc,
831*5f7ddb14SDimitry Andric "alternate form only supported for hex values");
832*5f7ddb14SDimitry Andric
833af732203SDimitry Andric FormatExpr = FormatExpr.ltrim(SpaceChars);
834af732203SDimitry Andric if (!FormatExpr.empty())
835af732203SDimitry Andric return ErrorDiagnostic::get(
836af732203SDimitry Andric SM, FormatExpr,
837af732203SDimitry Andric "invalid matching format specification in expression");
838af732203SDimitry Andric }
839af732203SDimitry Andric
840af732203SDimitry Andric // Save variable definition expression if any.
841af732203SDimitry Andric size_t DefEnd = Expr.find(':');
842af732203SDimitry Andric if (DefEnd != StringRef::npos) {
843af732203SDimitry Andric DefExpr = Expr.substr(0, DefEnd);
844af732203SDimitry Andric Expr = Expr.substr(DefEnd + 1);
845af732203SDimitry Andric }
846af732203SDimitry Andric
847af732203SDimitry Andric // Parse matching constraint.
848af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
849af732203SDimitry Andric bool HasParsedValidConstraint = false;
850af732203SDimitry Andric if (Expr.consume_front("=="))
851af732203SDimitry Andric HasParsedValidConstraint = true;
852af732203SDimitry Andric
853af732203SDimitry Andric // Parse the expression itself.
854af732203SDimitry Andric Expr = Expr.ltrim(SpaceChars);
855af732203SDimitry Andric if (Expr.empty()) {
856af732203SDimitry Andric if (HasParsedValidConstraint)
857af732203SDimitry Andric return ErrorDiagnostic::get(
858af732203SDimitry Andric SM, Expr, "empty numeric expression should not have a constraint");
859af732203SDimitry Andric } else {
860af732203SDimitry Andric Expr = Expr.rtrim(SpaceChars);
861af732203SDimitry Andric StringRef OuterBinOpExpr = Expr;
862af732203SDimitry Andric // The first operand in a legacy @LINE expression is always the @LINE
863af732203SDimitry Andric // pseudo variable.
864af732203SDimitry Andric AllowedOperand AO =
865af732203SDimitry Andric IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
866af732203SDimitry Andric Expected<std::unique_ptr<ExpressionAST>> ParseResult = parseNumericOperand(
867af732203SDimitry Andric Expr, AO, !HasParsedValidConstraint, LineNumber, Context, SM);
868af732203SDimitry Andric while (ParseResult && !Expr.empty()) {
869af732203SDimitry Andric ParseResult = parseBinop(OuterBinOpExpr, Expr, std::move(*ParseResult),
870af732203SDimitry Andric IsLegacyLineExpr, LineNumber, Context, SM);
871af732203SDimitry Andric // Legacy @LINE expressions only allow 2 operands.
872af732203SDimitry Andric if (ParseResult && IsLegacyLineExpr && !Expr.empty())
873af732203SDimitry Andric return ErrorDiagnostic::get(
874af732203SDimitry Andric SM, Expr,
875af732203SDimitry Andric "unexpected characters at end of expression '" + Expr + "'");
876af732203SDimitry Andric }
877af732203SDimitry Andric if (!ParseResult)
878af732203SDimitry Andric return ParseResult.takeError();
879af732203SDimitry Andric ExpressionASTPointer = std::move(*ParseResult);
880af732203SDimitry Andric }
881af732203SDimitry Andric
882af732203SDimitry Andric // Select format of the expression, i.e. (i) its explicit format, if any,
883af732203SDimitry Andric // otherwise (ii) its implicit format, if any, otherwise (iii) the default
884af732203SDimitry Andric // format (unsigned). Error out in case of conflicting implicit format
885af732203SDimitry Andric // without explicit format.
886af732203SDimitry Andric ExpressionFormat Format;
887af732203SDimitry Andric if (ExplicitFormat)
888af732203SDimitry Andric Format = ExplicitFormat;
889af732203SDimitry Andric else if (ExpressionASTPointer) {
890af732203SDimitry Andric Expected<ExpressionFormat> ImplicitFormat =
891af732203SDimitry Andric ExpressionASTPointer->getImplicitFormat(SM);
892af732203SDimitry Andric if (!ImplicitFormat)
893af732203SDimitry Andric return ImplicitFormat.takeError();
894af732203SDimitry Andric Format = *ImplicitFormat;
895af732203SDimitry Andric }
896af732203SDimitry Andric if (!Format)
897af732203SDimitry Andric Format = ExpressionFormat(ExpressionFormat::Kind::Unsigned, Precision);
898af732203SDimitry Andric
899af732203SDimitry Andric std::unique_ptr<Expression> ExpressionPointer =
900af732203SDimitry Andric std::make_unique<Expression>(std::move(ExpressionASTPointer), Format);
901af732203SDimitry Andric
902af732203SDimitry Andric // Parse the numeric variable definition.
903af732203SDimitry Andric if (DefEnd != StringRef::npos) {
904af732203SDimitry Andric DefExpr = DefExpr.ltrim(SpaceChars);
905af732203SDimitry Andric Expected<NumericVariable *> ParseResult = parseNumericVariableDefinition(
906af732203SDimitry Andric DefExpr, Context, LineNumber, ExpressionPointer->getFormat(), SM);
907af732203SDimitry Andric
908af732203SDimitry Andric if (!ParseResult)
909af732203SDimitry Andric return ParseResult.takeError();
910af732203SDimitry Andric DefinedNumericVariable = *ParseResult;
911af732203SDimitry Andric }
912af732203SDimitry Andric
913af732203SDimitry Andric return std::move(ExpressionPointer);
914af732203SDimitry Andric }
915af732203SDimitry Andric
parsePattern(StringRef PatternStr,StringRef Prefix,SourceMgr & SM,const FileCheckRequest & Req)916af732203SDimitry Andric bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix,
917af732203SDimitry Andric SourceMgr &SM, const FileCheckRequest &Req) {
918af732203SDimitry Andric bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot;
919af732203SDimitry Andric IgnoreCase = Req.IgnoreCase;
920af732203SDimitry Andric
921af732203SDimitry Andric PatternLoc = SMLoc::getFromPointer(PatternStr.data());
922af732203SDimitry Andric
923af732203SDimitry Andric if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
924af732203SDimitry Andric // Ignore trailing whitespace.
925af732203SDimitry Andric while (!PatternStr.empty() &&
926af732203SDimitry Andric (PatternStr.back() == ' ' || PatternStr.back() == '\t'))
927af732203SDimitry Andric PatternStr = PatternStr.substr(0, PatternStr.size() - 1);
928af732203SDimitry Andric
929af732203SDimitry Andric // Check that there is something on the line.
930af732203SDimitry Andric if (PatternStr.empty() && CheckTy != Check::CheckEmpty) {
931af732203SDimitry Andric SM.PrintMessage(PatternLoc, SourceMgr::DK_Error,
932af732203SDimitry Andric "found empty check string with prefix '" + Prefix + ":'");
933af732203SDimitry Andric return true;
934af732203SDimitry Andric }
935af732203SDimitry Andric
936af732203SDimitry Andric if (!PatternStr.empty() && CheckTy == Check::CheckEmpty) {
937af732203SDimitry Andric SM.PrintMessage(
938af732203SDimitry Andric PatternLoc, SourceMgr::DK_Error,
939af732203SDimitry Andric "found non-empty check string for empty check with prefix '" + Prefix +
940af732203SDimitry Andric ":'");
941af732203SDimitry Andric return true;
942af732203SDimitry Andric }
943af732203SDimitry Andric
944af732203SDimitry Andric if (CheckTy == Check::CheckEmpty) {
945af732203SDimitry Andric RegExStr = "(\n$)";
946af732203SDimitry Andric return false;
947af732203SDimitry Andric }
948af732203SDimitry Andric
949af732203SDimitry Andric // If literal check, set fixed string.
950af732203SDimitry Andric if (CheckTy.isLiteralMatch()) {
951af732203SDimitry Andric FixedStr = PatternStr;
952af732203SDimitry Andric return false;
953af732203SDimitry Andric }
954af732203SDimitry Andric
955af732203SDimitry Andric // Check to see if this is a fixed string, or if it has regex pieces.
956af732203SDimitry Andric if (!MatchFullLinesHere &&
957af732203SDimitry Andric (PatternStr.size() < 2 || (PatternStr.find("{{") == StringRef::npos &&
958af732203SDimitry Andric PatternStr.find("[[") == StringRef::npos))) {
959af732203SDimitry Andric FixedStr = PatternStr;
960af732203SDimitry Andric return false;
961af732203SDimitry Andric }
962af732203SDimitry Andric
963af732203SDimitry Andric if (MatchFullLinesHere) {
964af732203SDimitry Andric RegExStr += '^';
965af732203SDimitry Andric if (!Req.NoCanonicalizeWhiteSpace)
966af732203SDimitry Andric RegExStr += " *";
967af732203SDimitry Andric }
968af732203SDimitry Andric
969af732203SDimitry Andric // Paren value #0 is for the fully matched string. Any new parenthesized
970af732203SDimitry Andric // values add from there.
971af732203SDimitry Andric unsigned CurParen = 1;
972af732203SDimitry Andric
973af732203SDimitry Andric // Otherwise, there is at least one regex piece. Build up the regex pattern
974af732203SDimitry Andric // by escaping scary characters in fixed strings, building up one big regex.
975af732203SDimitry Andric while (!PatternStr.empty()) {
976af732203SDimitry Andric // RegEx matches.
977af732203SDimitry Andric if (PatternStr.startswith("{{")) {
978af732203SDimitry Andric // This is the start of a regex match. Scan for the }}.
979af732203SDimitry Andric size_t End = PatternStr.find("}}");
980af732203SDimitry Andric if (End == StringRef::npos) {
981af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
982af732203SDimitry Andric SourceMgr::DK_Error,
983af732203SDimitry Andric "found start of regex string with no end '}}'");
984af732203SDimitry Andric return true;
985af732203SDimitry Andric }
986af732203SDimitry Andric
987af732203SDimitry Andric // Enclose {{}} patterns in parens just like [[]] even though we're not
988af732203SDimitry Andric // capturing the result for any purpose. This is required in case the
989af732203SDimitry Andric // expression contains an alternation like: CHECK: abc{{x|z}}def. We
990af732203SDimitry Andric // want this to turn into: "abc(x|z)def" not "abcx|zdef".
991af732203SDimitry Andric RegExStr += '(';
992af732203SDimitry Andric ++CurParen;
993af732203SDimitry Andric
994af732203SDimitry Andric if (AddRegExToRegEx(PatternStr.substr(2, End - 2), CurParen, SM))
995af732203SDimitry Andric return true;
996af732203SDimitry Andric RegExStr += ')';
997af732203SDimitry Andric
998af732203SDimitry Andric PatternStr = PatternStr.substr(End + 2);
999af732203SDimitry Andric continue;
1000af732203SDimitry Andric }
1001af732203SDimitry Andric
1002af732203SDimitry Andric // String and numeric substitution blocks. Pattern substitution blocks come
1003af732203SDimitry Andric // in two forms: [[foo:.*]] and [[foo]]. The former matches .* (or some
1004af732203SDimitry Andric // other regex) and assigns it to the string variable 'foo'. The latter
1005af732203SDimitry Andric // substitutes foo's value. Numeric substitution blocks recognize the same
1006af732203SDimitry Andric // form as string ones, but start with a '#' sign after the double
1007af732203SDimitry Andric // brackets. They also accept a combined form which sets a numeric variable
1008af732203SDimitry Andric // to the evaluation of an expression. Both string and numeric variable
1009af732203SDimitry Andric // names must satisfy the regular expression "[a-zA-Z_][0-9a-zA-Z_]*" to be
1010af732203SDimitry Andric // valid, as this helps catch some common errors.
1011af732203SDimitry Andric if (PatternStr.startswith("[[")) {
1012af732203SDimitry Andric StringRef UnparsedPatternStr = PatternStr.substr(2);
1013af732203SDimitry Andric // Find the closing bracket pair ending the match. End is going to be an
1014af732203SDimitry Andric // offset relative to the beginning of the match string.
1015af732203SDimitry Andric size_t End = FindRegexVarEnd(UnparsedPatternStr, SM);
1016af732203SDimitry Andric StringRef MatchStr = UnparsedPatternStr.substr(0, End);
1017af732203SDimitry Andric bool IsNumBlock = MatchStr.consume_front("#");
1018af732203SDimitry Andric
1019af732203SDimitry Andric if (End == StringRef::npos) {
1020af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(PatternStr.data()),
1021af732203SDimitry Andric SourceMgr::DK_Error,
1022af732203SDimitry Andric "Invalid substitution block, no ]] found");
1023af732203SDimitry Andric return true;
1024af732203SDimitry Andric }
1025af732203SDimitry Andric // Strip the substitution block we are parsing. End points to the start
1026af732203SDimitry Andric // of the "]]" closing the expression so account for it in computing the
1027af732203SDimitry Andric // index of the first unparsed character.
1028af732203SDimitry Andric PatternStr = UnparsedPatternStr.substr(End + 2);
1029af732203SDimitry Andric
1030af732203SDimitry Andric bool IsDefinition = false;
1031af732203SDimitry Andric bool SubstNeeded = false;
1032af732203SDimitry Andric // Whether the substitution block is a legacy use of @LINE with string
1033af732203SDimitry Andric // substitution block syntax.
1034af732203SDimitry Andric bool IsLegacyLineExpr = false;
1035af732203SDimitry Andric StringRef DefName;
1036af732203SDimitry Andric StringRef SubstStr;
1037af732203SDimitry Andric std::string MatchRegexp;
1038af732203SDimitry Andric size_t SubstInsertIdx = RegExStr.size();
1039af732203SDimitry Andric
1040af732203SDimitry Andric // Parse string variable or legacy @LINE expression.
1041af732203SDimitry Andric if (!IsNumBlock) {
1042af732203SDimitry Andric size_t VarEndIdx = MatchStr.find(':');
1043af732203SDimitry Andric size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");
1044af732203SDimitry Andric if (SpacePos != StringRef::npos) {
1045af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(MatchStr.data() + SpacePos),
1046af732203SDimitry Andric SourceMgr::DK_Error, "unexpected whitespace");
1047af732203SDimitry Andric return true;
1048af732203SDimitry Andric }
1049af732203SDimitry Andric
1050af732203SDimitry Andric // Get the name (e.g. "foo") and verify it is well formed.
1051af732203SDimitry Andric StringRef OrigMatchStr = MatchStr;
1052af732203SDimitry Andric Expected<Pattern::VariableProperties> ParseVarResult =
1053af732203SDimitry Andric parseVariable(MatchStr, SM);
1054af732203SDimitry Andric if (!ParseVarResult) {
1055af732203SDimitry Andric logAllUnhandledErrors(ParseVarResult.takeError(), errs());
1056af732203SDimitry Andric return true;
1057af732203SDimitry Andric }
1058af732203SDimitry Andric StringRef Name = ParseVarResult->Name;
1059af732203SDimitry Andric bool IsPseudo = ParseVarResult->IsPseudo;
1060af732203SDimitry Andric
1061af732203SDimitry Andric IsDefinition = (VarEndIdx != StringRef::npos);
1062af732203SDimitry Andric SubstNeeded = !IsDefinition;
1063af732203SDimitry Andric if (IsDefinition) {
1064af732203SDimitry Andric if ((IsPseudo || !MatchStr.consume_front(":"))) {
1065af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
1066af732203SDimitry Andric SourceMgr::DK_Error,
1067af732203SDimitry Andric "invalid name in string variable definition");
1068af732203SDimitry Andric return true;
1069af732203SDimitry Andric }
1070af732203SDimitry Andric
1071af732203SDimitry Andric // Detect collisions between string and numeric variables when the
1072af732203SDimitry Andric // former is created later than the latter.
1073af732203SDimitry Andric if (Context->GlobalNumericVariableTable.find(Name) !=
1074af732203SDimitry Andric Context->GlobalNumericVariableTable.end()) {
1075af732203SDimitry Andric SM.PrintMessage(
1076af732203SDimitry Andric SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error,
1077af732203SDimitry Andric "numeric variable with name '" + Name + "' already exists");
1078af732203SDimitry Andric return true;
1079af732203SDimitry Andric }
1080af732203SDimitry Andric DefName = Name;
1081af732203SDimitry Andric MatchRegexp = MatchStr.str();
1082af732203SDimitry Andric } else {
1083af732203SDimitry Andric if (IsPseudo) {
1084af732203SDimitry Andric MatchStr = OrigMatchStr;
1085af732203SDimitry Andric IsLegacyLineExpr = IsNumBlock = true;
1086*5f7ddb14SDimitry Andric } else {
1087*5f7ddb14SDimitry Andric if (!MatchStr.empty()) {
1088*5f7ddb14SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Name.data()),
1089*5f7ddb14SDimitry Andric SourceMgr::DK_Error,
1090*5f7ddb14SDimitry Andric "invalid name in string variable use");
1091*5f7ddb14SDimitry Andric return true;
1092*5f7ddb14SDimitry Andric }
1093af732203SDimitry Andric SubstStr = Name;
1094af732203SDimitry Andric }
1095af732203SDimitry Andric }
1096*5f7ddb14SDimitry Andric }
1097af732203SDimitry Andric
1098af732203SDimitry Andric // Parse numeric substitution block.
1099af732203SDimitry Andric std::unique_ptr<Expression> ExpressionPointer;
1100af732203SDimitry Andric Optional<NumericVariable *> DefinedNumericVariable;
1101af732203SDimitry Andric if (IsNumBlock) {
1102af732203SDimitry Andric Expected<std::unique_ptr<Expression>> ParseResult =
1103af732203SDimitry Andric parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,
1104af732203SDimitry Andric IsLegacyLineExpr, LineNumber, Context,
1105af732203SDimitry Andric SM);
1106af732203SDimitry Andric if (!ParseResult) {
1107af732203SDimitry Andric logAllUnhandledErrors(ParseResult.takeError(), errs());
1108af732203SDimitry Andric return true;
1109af732203SDimitry Andric }
1110af732203SDimitry Andric ExpressionPointer = std::move(*ParseResult);
1111af732203SDimitry Andric SubstNeeded = ExpressionPointer->getAST() != nullptr;
1112af732203SDimitry Andric if (DefinedNumericVariable) {
1113af732203SDimitry Andric IsDefinition = true;
1114af732203SDimitry Andric DefName = (*DefinedNumericVariable)->getName();
1115af732203SDimitry Andric }
1116af732203SDimitry Andric if (SubstNeeded)
1117af732203SDimitry Andric SubstStr = MatchStr;
1118af732203SDimitry Andric else {
1119af732203SDimitry Andric ExpressionFormat Format = ExpressionPointer->getFormat();
1120af732203SDimitry Andric MatchRegexp = cantFail(Format.getWildcardRegex());
1121af732203SDimitry Andric }
1122af732203SDimitry Andric }
1123af732203SDimitry Andric
1124af732203SDimitry Andric // Handle variable definition: [[<def>:(...)]] and [[#(...)<def>:(...)]].
1125af732203SDimitry Andric if (IsDefinition) {
1126af732203SDimitry Andric RegExStr += '(';
1127af732203SDimitry Andric ++SubstInsertIdx;
1128af732203SDimitry Andric
1129af732203SDimitry Andric if (IsNumBlock) {
1130af732203SDimitry Andric NumericVariableMatch NumericVariableDefinition = {
1131af732203SDimitry Andric *DefinedNumericVariable, CurParen};
1132af732203SDimitry Andric NumericVariableDefs[DefName] = NumericVariableDefinition;
1133af732203SDimitry Andric // This store is done here rather than in match() to allow
1134af732203SDimitry Andric // parseNumericVariableUse() to get the pointer to the class instance
1135af732203SDimitry Andric // of the right variable definition corresponding to a given numeric
1136af732203SDimitry Andric // variable use.
1137af732203SDimitry Andric Context->GlobalNumericVariableTable[DefName] =
1138af732203SDimitry Andric *DefinedNumericVariable;
1139af732203SDimitry Andric } else {
1140af732203SDimitry Andric VariableDefs[DefName] = CurParen;
1141af732203SDimitry Andric // Mark string variable as defined to detect collisions between
1142af732203SDimitry Andric // string and numeric variables in parseNumericVariableUse() and
1143af732203SDimitry Andric // defineCmdlineVariables() when the latter is created later than the
1144af732203SDimitry Andric // former. We cannot reuse GlobalVariableTable for this by populating
1145af732203SDimitry Andric // it with an empty string since we would then lose the ability to
1146af732203SDimitry Andric // detect the use of an undefined variable in match().
1147af732203SDimitry Andric Context->DefinedVariableTable[DefName] = true;
1148af732203SDimitry Andric }
1149af732203SDimitry Andric
1150af732203SDimitry Andric ++CurParen;
1151af732203SDimitry Andric }
1152af732203SDimitry Andric
1153af732203SDimitry Andric if (!MatchRegexp.empty() && AddRegExToRegEx(MatchRegexp, CurParen, SM))
1154af732203SDimitry Andric return true;
1155af732203SDimitry Andric
1156af732203SDimitry Andric if (IsDefinition)
1157af732203SDimitry Andric RegExStr += ')';
1158af732203SDimitry Andric
1159af732203SDimitry Andric // Handle substitutions: [[foo]] and [[#<foo expr>]].
1160af732203SDimitry Andric if (SubstNeeded) {
1161af732203SDimitry Andric // Handle substitution of string variables that were defined earlier on
1162af732203SDimitry Andric // the same line by emitting a backreference. Expressions do not
1163af732203SDimitry Andric // support substituting a numeric variable defined on the same line.
1164af732203SDimitry Andric if (!IsNumBlock && VariableDefs.find(SubstStr) != VariableDefs.end()) {
1165af732203SDimitry Andric unsigned CaptureParenGroup = VariableDefs[SubstStr];
1166af732203SDimitry Andric if (CaptureParenGroup < 1 || CaptureParenGroup > 9) {
1167af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(SubstStr.data()),
1168af732203SDimitry Andric SourceMgr::DK_Error,
1169af732203SDimitry Andric "Can't back-reference more than 9 variables");
1170af732203SDimitry Andric return true;
1171af732203SDimitry Andric }
1172af732203SDimitry Andric AddBackrefToRegEx(CaptureParenGroup);
1173af732203SDimitry Andric } else {
1174af732203SDimitry Andric // Handle substitution of string variables ([[<var>]]) defined in
1175af732203SDimitry Andric // previous CHECK patterns, and substitution of expressions.
1176af732203SDimitry Andric Substitution *Substitution =
1177af732203SDimitry Andric IsNumBlock
1178af732203SDimitry Andric ? Context->makeNumericSubstitution(
1179af732203SDimitry Andric SubstStr, std::move(ExpressionPointer), SubstInsertIdx)
1180af732203SDimitry Andric : Context->makeStringSubstitution(SubstStr, SubstInsertIdx);
1181af732203SDimitry Andric Substitutions.push_back(Substitution);
1182af732203SDimitry Andric }
1183af732203SDimitry Andric }
1184af732203SDimitry Andric }
1185af732203SDimitry Andric
1186af732203SDimitry Andric // Handle fixed string matches.
1187af732203SDimitry Andric // Find the end, which is the start of the next regex.
1188af732203SDimitry Andric size_t FixedMatchEnd = PatternStr.find("{{");
1189af732203SDimitry Andric FixedMatchEnd = std::min(FixedMatchEnd, PatternStr.find("[["));
1190af732203SDimitry Andric RegExStr += Regex::escape(PatternStr.substr(0, FixedMatchEnd));
1191af732203SDimitry Andric PatternStr = PatternStr.substr(FixedMatchEnd);
1192af732203SDimitry Andric }
1193af732203SDimitry Andric
1194af732203SDimitry Andric if (MatchFullLinesHere) {
1195af732203SDimitry Andric if (!Req.NoCanonicalizeWhiteSpace)
1196af732203SDimitry Andric RegExStr += " *";
1197af732203SDimitry Andric RegExStr += '$';
1198af732203SDimitry Andric }
1199af732203SDimitry Andric
1200af732203SDimitry Andric return false;
1201af732203SDimitry Andric }
1202af732203SDimitry Andric
AddRegExToRegEx(StringRef RS,unsigned & CurParen,SourceMgr & SM)1203af732203SDimitry Andric bool Pattern::AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM) {
1204af732203SDimitry Andric Regex R(RS);
1205af732203SDimitry Andric std::string Error;
1206af732203SDimitry Andric if (!R.isValid(Error)) {
1207af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(RS.data()), SourceMgr::DK_Error,
1208af732203SDimitry Andric "invalid regex: " + Error);
1209af732203SDimitry Andric return true;
1210af732203SDimitry Andric }
1211af732203SDimitry Andric
1212af732203SDimitry Andric RegExStr += RS.str();
1213af732203SDimitry Andric CurParen += R.getNumMatches();
1214af732203SDimitry Andric return false;
1215af732203SDimitry Andric }
1216af732203SDimitry Andric
AddBackrefToRegEx(unsigned BackrefNum)1217af732203SDimitry Andric void Pattern::AddBackrefToRegEx(unsigned BackrefNum) {
1218af732203SDimitry Andric assert(BackrefNum >= 1 && BackrefNum <= 9 && "Invalid backref number");
1219af732203SDimitry Andric std::string Backref = std::string("\\") + std::string(1, '0' + BackrefNum);
1220af732203SDimitry Andric RegExStr += Backref;
1221af732203SDimitry Andric }
1222af732203SDimitry Andric
match(StringRef Buffer,const SourceMgr & SM) const1223*5f7ddb14SDimitry Andric Pattern::MatchResult Pattern::match(StringRef Buffer,
1224af732203SDimitry Andric const SourceMgr &SM) const {
1225af732203SDimitry Andric // If this is the EOF pattern, match it immediately.
1226*5f7ddb14SDimitry Andric if (CheckTy == Check::CheckEOF)
1227*5f7ddb14SDimitry Andric return MatchResult(Buffer.size(), 0, Error::success());
1228af732203SDimitry Andric
1229af732203SDimitry Andric // If this is a fixed string pattern, just match it now.
1230af732203SDimitry Andric if (!FixedStr.empty()) {
1231af732203SDimitry Andric size_t Pos =
1232*5f7ddb14SDimitry Andric IgnoreCase ? Buffer.find_insensitive(FixedStr) : Buffer.find(FixedStr);
1233af732203SDimitry Andric if (Pos == StringRef::npos)
1234af732203SDimitry Andric return make_error<NotFoundError>();
1235*5f7ddb14SDimitry Andric return MatchResult(Pos, /*MatchLen=*/FixedStr.size(), Error::success());
1236af732203SDimitry Andric }
1237af732203SDimitry Andric
1238af732203SDimitry Andric // Regex match.
1239af732203SDimitry Andric
1240af732203SDimitry Andric // If there are substitutions, we need to create a temporary string with the
1241af732203SDimitry Andric // actual value.
1242af732203SDimitry Andric StringRef RegExToMatch = RegExStr;
1243af732203SDimitry Andric std::string TmpStr;
1244af732203SDimitry Andric if (!Substitutions.empty()) {
1245af732203SDimitry Andric TmpStr = RegExStr;
1246af732203SDimitry Andric if (LineNumber)
1247af732203SDimitry Andric Context->LineVariable->setValue(ExpressionValue(*LineNumber));
1248af732203SDimitry Andric
1249af732203SDimitry Andric size_t InsertOffset = 0;
1250af732203SDimitry Andric // Substitute all string variables and expressions whose values are only
1251af732203SDimitry Andric // now known. Use of string variables defined on the same line are handled
1252af732203SDimitry Andric // by back-references.
1253*5f7ddb14SDimitry Andric Error Errs = Error::success();
1254af732203SDimitry Andric for (const auto &Substitution : Substitutions) {
1255af732203SDimitry Andric // Substitute and check for failure (e.g. use of undefined variable).
1256af732203SDimitry Andric Expected<std::string> Value = Substitution->getResult();
1257af732203SDimitry Andric if (!Value) {
1258af732203SDimitry Andric // Convert to an ErrorDiagnostic to get location information. This is
1259*5f7ddb14SDimitry Andric // done here rather than printMatch/printNoMatch since now we know which
1260af732203SDimitry Andric // substitution block caused the overflow.
1261*5f7ddb14SDimitry Andric Errs = joinErrors(std::move(Errs),
1262*5f7ddb14SDimitry Andric handleErrors(
1263*5f7ddb14SDimitry Andric Value.takeError(),
1264*5f7ddb14SDimitry Andric [&](const OverflowError &E) {
1265*5f7ddb14SDimitry Andric return ErrorDiagnostic::get(
1266*5f7ddb14SDimitry Andric SM, Substitution->getFromString(),
1267af732203SDimitry Andric "unable to substitute variable or "
1268af732203SDimitry Andric "numeric expression: overflow error");
1269*5f7ddb14SDimitry Andric },
1270*5f7ddb14SDimitry Andric [&SM](const UndefVarError &E) {
1271*5f7ddb14SDimitry Andric return ErrorDiagnostic::get(SM, E.getVarName(),
1272*5f7ddb14SDimitry Andric E.message());
1273*5f7ddb14SDimitry Andric }));
1274*5f7ddb14SDimitry Andric continue;
1275af732203SDimitry Andric }
1276af732203SDimitry Andric
1277af732203SDimitry Andric // Plop it into the regex at the adjusted offset.
1278af732203SDimitry Andric TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset,
1279af732203SDimitry Andric Value->begin(), Value->end());
1280af732203SDimitry Andric InsertOffset += Value->size();
1281af732203SDimitry Andric }
1282*5f7ddb14SDimitry Andric if (Errs)
1283*5f7ddb14SDimitry Andric return std::move(Errs);
1284af732203SDimitry Andric
1285af732203SDimitry Andric // Match the newly constructed regex.
1286af732203SDimitry Andric RegExToMatch = TmpStr;
1287af732203SDimitry Andric }
1288af732203SDimitry Andric
1289af732203SDimitry Andric SmallVector<StringRef, 4> MatchInfo;
1290af732203SDimitry Andric unsigned int Flags = Regex::Newline;
1291af732203SDimitry Andric if (IgnoreCase)
1292af732203SDimitry Andric Flags |= Regex::IgnoreCase;
1293af732203SDimitry Andric if (!Regex(RegExToMatch, Flags).match(Buffer, &MatchInfo))
1294af732203SDimitry Andric return make_error<NotFoundError>();
1295af732203SDimitry Andric
1296af732203SDimitry Andric // Successful regex match.
1297af732203SDimitry Andric assert(!MatchInfo.empty() && "Didn't get any match");
1298af732203SDimitry Andric StringRef FullMatch = MatchInfo[0];
1299af732203SDimitry Andric
1300af732203SDimitry Andric // If this defines any string variables, remember their values.
1301af732203SDimitry Andric for (const auto &VariableDef : VariableDefs) {
1302af732203SDimitry Andric assert(VariableDef.second < MatchInfo.size() && "Internal paren error");
1303af732203SDimitry Andric Context->GlobalVariableTable[VariableDef.first] =
1304af732203SDimitry Andric MatchInfo[VariableDef.second];
1305af732203SDimitry Andric }
1306af732203SDimitry Andric
1307*5f7ddb14SDimitry Andric // Like CHECK-NEXT, CHECK-EMPTY's match range is considered to start after
1308*5f7ddb14SDimitry Andric // the required preceding newline, which is consumed by the pattern in the
1309*5f7ddb14SDimitry Andric // case of CHECK-EMPTY but not CHECK-NEXT.
1310*5f7ddb14SDimitry Andric size_t MatchStartSkip = CheckTy == Check::CheckEmpty;
1311*5f7ddb14SDimitry Andric Match TheMatch;
1312*5f7ddb14SDimitry Andric TheMatch.Pos = FullMatch.data() - Buffer.data() + MatchStartSkip;
1313*5f7ddb14SDimitry Andric TheMatch.Len = FullMatch.size() - MatchStartSkip;
1314*5f7ddb14SDimitry Andric
1315af732203SDimitry Andric // If this defines any numeric variables, remember their values.
1316af732203SDimitry Andric for (const auto &NumericVariableDef : NumericVariableDefs) {
1317af732203SDimitry Andric const NumericVariableMatch &NumericVariableMatch =
1318af732203SDimitry Andric NumericVariableDef.getValue();
1319af732203SDimitry Andric unsigned CaptureParenGroup = NumericVariableMatch.CaptureParenGroup;
1320af732203SDimitry Andric assert(CaptureParenGroup < MatchInfo.size() && "Internal paren error");
1321af732203SDimitry Andric NumericVariable *DefinedNumericVariable =
1322af732203SDimitry Andric NumericVariableMatch.DefinedNumericVariable;
1323af732203SDimitry Andric
1324af732203SDimitry Andric StringRef MatchedValue = MatchInfo[CaptureParenGroup];
1325af732203SDimitry Andric ExpressionFormat Format = DefinedNumericVariable->getImplicitFormat();
1326af732203SDimitry Andric Expected<ExpressionValue> Value =
1327af732203SDimitry Andric Format.valueFromStringRepr(MatchedValue, SM);
1328af732203SDimitry Andric if (!Value)
1329*5f7ddb14SDimitry Andric return MatchResult(TheMatch, Value.takeError());
1330af732203SDimitry Andric DefinedNumericVariable->setValue(*Value, MatchedValue);
1331af732203SDimitry Andric }
1332af732203SDimitry Andric
1333*5f7ddb14SDimitry Andric return MatchResult(TheMatch, Error::success());
1334af732203SDimitry Andric }
1335af732203SDimitry Andric
computeMatchDistance(StringRef Buffer) const1336af732203SDimitry Andric unsigned Pattern::computeMatchDistance(StringRef Buffer) const {
1337af732203SDimitry Andric // Just compute the number of matching characters. For regular expressions, we
1338af732203SDimitry Andric // just compare against the regex itself and hope for the best.
1339af732203SDimitry Andric //
1340af732203SDimitry Andric // FIXME: One easy improvement here is have the regex lib generate a single
1341af732203SDimitry Andric // example regular expression which matches, and use that as the example
1342af732203SDimitry Andric // string.
1343af732203SDimitry Andric StringRef ExampleString(FixedStr);
1344af732203SDimitry Andric if (ExampleString.empty())
1345af732203SDimitry Andric ExampleString = RegExStr;
1346af732203SDimitry Andric
1347af732203SDimitry Andric // Only compare up to the first line in the buffer, or the string size.
1348af732203SDimitry Andric StringRef BufferPrefix = Buffer.substr(0, ExampleString.size());
1349af732203SDimitry Andric BufferPrefix = BufferPrefix.split('\n').first;
1350af732203SDimitry Andric return BufferPrefix.edit_distance(ExampleString);
1351af732203SDimitry Andric }
1352af732203SDimitry Andric
printSubstitutions(const SourceMgr & SM,StringRef Buffer,SMRange Range,FileCheckDiag::MatchType MatchTy,std::vector<FileCheckDiag> * Diags) const1353af732203SDimitry Andric void Pattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,
1354af732203SDimitry Andric SMRange Range,
1355af732203SDimitry Andric FileCheckDiag::MatchType MatchTy,
1356af732203SDimitry Andric std::vector<FileCheckDiag> *Diags) const {
1357af732203SDimitry Andric // Print what we know about substitutions.
1358af732203SDimitry Andric if (!Substitutions.empty()) {
1359af732203SDimitry Andric for (const auto &Substitution : Substitutions) {
1360af732203SDimitry Andric SmallString<256> Msg;
1361af732203SDimitry Andric raw_svector_ostream OS(Msg);
1362af732203SDimitry Andric
1363*5f7ddb14SDimitry Andric Expected<std::string> MatchedValue = Substitution->getResult();
1364*5f7ddb14SDimitry Andric // Substitution failures are handled in printNoMatch().
1365af732203SDimitry Andric if (!MatchedValue) {
1366*5f7ddb14SDimitry Andric consumeError(MatchedValue.takeError());
1367*5f7ddb14SDimitry Andric continue;
1368af732203SDimitry Andric }
1369*5f7ddb14SDimitry Andric
1370af732203SDimitry Andric OS << "with \"";
1371af732203SDimitry Andric OS.write_escaped(Substitution->getFromString()) << "\" equal to \"";
1372af732203SDimitry Andric OS.write_escaped(*MatchedValue) << "\"";
1373af732203SDimitry Andric
1374af732203SDimitry Andric // We report only the start of the match/search range to suggest we are
1375af732203SDimitry Andric // reporting the substitutions as set at the start of the match/search.
1376af732203SDimitry Andric // Indicating a non-zero-length range might instead seem to imply that the
1377af732203SDimitry Andric // substitution matches or was captured from exactly that range.
1378af732203SDimitry Andric if (Diags)
1379af732203SDimitry Andric Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy,
1380af732203SDimitry Andric SMRange(Range.Start, Range.Start), OS.str());
1381af732203SDimitry Andric else
1382af732203SDimitry Andric SM.PrintMessage(Range.Start, SourceMgr::DK_Note, OS.str());
1383af732203SDimitry Andric }
1384af732203SDimitry Andric }
1385af732203SDimitry Andric }
1386af732203SDimitry Andric
printVariableDefs(const SourceMgr & SM,FileCheckDiag::MatchType MatchTy,std::vector<FileCheckDiag> * Diags) const1387af732203SDimitry Andric void Pattern::printVariableDefs(const SourceMgr &SM,
1388af732203SDimitry Andric FileCheckDiag::MatchType MatchTy,
1389af732203SDimitry Andric std::vector<FileCheckDiag> *Diags) const {
1390af732203SDimitry Andric if (VariableDefs.empty() && NumericVariableDefs.empty())
1391af732203SDimitry Andric return;
1392af732203SDimitry Andric // Build list of variable captures.
1393af732203SDimitry Andric struct VarCapture {
1394af732203SDimitry Andric StringRef Name;
1395af732203SDimitry Andric SMRange Range;
1396af732203SDimitry Andric };
1397af732203SDimitry Andric SmallVector<VarCapture, 2> VarCaptures;
1398af732203SDimitry Andric for (const auto &VariableDef : VariableDefs) {
1399af732203SDimitry Andric VarCapture VC;
1400af732203SDimitry Andric VC.Name = VariableDef.first;
1401af732203SDimitry Andric StringRef Value = Context->GlobalVariableTable[VC.Name];
1402af732203SDimitry Andric SMLoc Start = SMLoc::getFromPointer(Value.data());
1403af732203SDimitry Andric SMLoc End = SMLoc::getFromPointer(Value.data() + Value.size());
1404af732203SDimitry Andric VC.Range = SMRange(Start, End);
1405af732203SDimitry Andric VarCaptures.push_back(VC);
1406af732203SDimitry Andric }
1407af732203SDimitry Andric for (const auto &VariableDef : NumericVariableDefs) {
1408af732203SDimitry Andric VarCapture VC;
1409af732203SDimitry Andric VC.Name = VariableDef.getKey();
1410*5f7ddb14SDimitry Andric Optional<StringRef> StrValue =
1411*5f7ddb14SDimitry Andric VariableDef.getValue().DefinedNumericVariable->getStringValue();
1412*5f7ddb14SDimitry Andric if (!StrValue)
1413*5f7ddb14SDimitry Andric continue;
1414*5f7ddb14SDimitry Andric SMLoc Start = SMLoc::getFromPointer(StrValue->data());
1415*5f7ddb14SDimitry Andric SMLoc End = SMLoc::getFromPointer(StrValue->data() + StrValue->size());
1416af732203SDimitry Andric VC.Range = SMRange(Start, End);
1417af732203SDimitry Andric VarCaptures.push_back(VC);
1418af732203SDimitry Andric }
1419af732203SDimitry Andric // Sort variable captures by the order in which they matched the input.
1420af732203SDimitry Andric // Ranges shouldn't be overlapping, so we can just compare the start.
1421af732203SDimitry Andric llvm::sort(VarCaptures, [](const VarCapture &A, const VarCapture &B) {
1422af732203SDimitry Andric assert(A.Range.Start != B.Range.Start &&
1423af732203SDimitry Andric "unexpected overlapping variable captures");
1424af732203SDimitry Andric return A.Range.Start.getPointer() < B.Range.Start.getPointer();
1425af732203SDimitry Andric });
1426af732203SDimitry Andric // Create notes for the sorted captures.
1427af732203SDimitry Andric for (const VarCapture &VC : VarCaptures) {
1428af732203SDimitry Andric SmallString<256> Msg;
1429af732203SDimitry Andric raw_svector_ostream OS(Msg);
1430af732203SDimitry Andric OS << "captured var \"" << VC.Name << "\"";
1431af732203SDimitry Andric if (Diags)
1432af732203SDimitry Andric Diags->emplace_back(SM, CheckTy, getLoc(), MatchTy, VC.Range, OS.str());
1433af732203SDimitry Andric else
1434af732203SDimitry Andric SM.PrintMessage(VC.Range.Start, SourceMgr::DK_Note, OS.str(), VC.Range);
1435af732203SDimitry Andric }
1436af732203SDimitry Andric }
1437af732203SDimitry Andric
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)1438af732203SDimitry Andric static SMRange ProcessMatchResult(FileCheckDiag::MatchType MatchTy,
1439af732203SDimitry Andric const SourceMgr &SM, SMLoc Loc,
1440af732203SDimitry Andric Check::FileCheckType CheckTy,
1441af732203SDimitry Andric StringRef Buffer, size_t Pos, size_t Len,
1442af732203SDimitry Andric std::vector<FileCheckDiag> *Diags,
1443af732203SDimitry Andric bool AdjustPrevDiags = false) {
1444af732203SDimitry Andric SMLoc Start = SMLoc::getFromPointer(Buffer.data() + Pos);
1445af732203SDimitry Andric SMLoc End = SMLoc::getFromPointer(Buffer.data() + Pos + Len);
1446af732203SDimitry Andric SMRange Range(Start, End);
1447af732203SDimitry Andric if (Diags) {
1448af732203SDimitry Andric if (AdjustPrevDiags) {
1449af732203SDimitry Andric SMLoc CheckLoc = Diags->rbegin()->CheckLoc;
1450af732203SDimitry Andric for (auto I = Diags->rbegin(), E = Diags->rend();
1451af732203SDimitry Andric I != E && I->CheckLoc == CheckLoc; ++I)
1452af732203SDimitry Andric I->MatchTy = MatchTy;
1453af732203SDimitry Andric } else
1454af732203SDimitry Andric Diags->emplace_back(SM, CheckTy, Loc, MatchTy, Range);
1455af732203SDimitry Andric }
1456af732203SDimitry Andric return Range;
1457af732203SDimitry Andric }
1458af732203SDimitry Andric
printFuzzyMatch(const SourceMgr & SM,StringRef Buffer,std::vector<FileCheckDiag> * Diags) const1459af732203SDimitry Andric void Pattern::printFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
1460af732203SDimitry Andric std::vector<FileCheckDiag> *Diags) const {
1461af732203SDimitry Andric // Attempt to find the closest/best fuzzy match. Usually an error happens
1462af732203SDimitry Andric // because some string in the output didn't exactly match. In these cases, we
1463af732203SDimitry Andric // would like to show the user a best guess at what "should have" matched, to
1464af732203SDimitry Andric // save them having to actually check the input manually.
1465af732203SDimitry Andric size_t NumLinesForward = 0;
1466af732203SDimitry Andric size_t Best = StringRef::npos;
1467af732203SDimitry Andric double BestQuality = 0;
1468af732203SDimitry Andric
1469af732203SDimitry Andric // Use an arbitrary 4k limit on how far we will search.
1470af732203SDimitry Andric for (size_t i = 0, e = std::min(size_t(4096), Buffer.size()); i != e; ++i) {
1471af732203SDimitry Andric if (Buffer[i] == '\n')
1472af732203SDimitry Andric ++NumLinesForward;
1473af732203SDimitry Andric
1474af732203SDimitry Andric // Patterns have leading whitespace stripped, so skip whitespace when
1475af732203SDimitry Andric // looking for something which looks like a pattern.
1476af732203SDimitry Andric if (Buffer[i] == ' ' || Buffer[i] == '\t')
1477af732203SDimitry Andric continue;
1478af732203SDimitry Andric
1479af732203SDimitry Andric // Compute the "quality" of this match as an arbitrary combination of the
1480af732203SDimitry Andric // match distance and the number of lines skipped to get to this match.
1481af732203SDimitry Andric unsigned Distance = computeMatchDistance(Buffer.substr(i));
1482af732203SDimitry Andric double Quality = Distance + (NumLinesForward / 100.);
1483af732203SDimitry Andric
1484af732203SDimitry Andric if (Quality < BestQuality || Best == StringRef::npos) {
1485af732203SDimitry Andric Best = i;
1486af732203SDimitry Andric BestQuality = Quality;
1487af732203SDimitry Andric }
1488af732203SDimitry Andric }
1489af732203SDimitry Andric
1490af732203SDimitry Andric // Print the "possible intended match here" line if we found something
1491af732203SDimitry Andric // reasonable and not equal to what we showed in the "scanning from here"
1492af732203SDimitry Andric // line.
1493af732203SDimitry Andric if (Best && Best != StringRef::npos && BestQuality < 50) {
1494af732203SDimitry Andric SMRange MatchRange =
1495af732203SDimitry Andric ProcessMatchResult(FileCheckDiag::MatchFuzzy, SM, getLoc(),
1496af732203SDimitry Andric getCheckTy(), Buffer, Best, 0, Diags);
1497af732203SDimitry Andric SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note,
1498af732203SDimitry Andric "possible intended match here");
1499af732203SDimitry Andric
1500af732203SDimitry Andric // FIXME: If we wanted to be really friendly we would show why the match
1501af732203SDimitry Andric // failed, as it can be hard to spot simple one character differences.
1502af732203SDimitry Andric }
1503af732203SDimitry Andric }
1504af732203SDimitry Andric
1505af732203SDimitry Andric Expected<StringRef>
getPatternVarValue(StringRef VarName)1506af732203SDimitry Andric FileCheckPatternContext::getPatternVarValue(StringRef VarName) {
1507af732203SDimitry Andric auto VarIter = GlobalVariableTable.find(VarName);
1508af732203SDimitry Andric if (VarIter == GlobalVariableTable.end())
1509af732203SDimitry Andric return make_error<UndefVarError>(VarName);
1510af732203SDimitry Andric
1511af732203SDimitry Andric return VarIter->second;
1512af732203SDimitry Andric }
1513af732203SDimitry Andric
1514af732203SDimitry Andric template <class... Types>
makeNumericVariable(Types...args)1515af732203SDimitry Andric NumericVariable *FileCheckPatternContext::makeNumericVariable(Types... args) {
1516af732203SDimitry Andric NumericVariables.push_back(std::make_unique<NumericVariable>(args...));
1517af732203SDimitry Andric return NumericVariables.back().get();
1518af732203SDimitry Andric }
1519af732203SDimitry Andric
1520af732203SDimitry Andric Substitution *
makeStringSubstitution(StringRef VarName,size_t InsertIdx)1521af732203SDimitry Andric FileCheckPatternContext::makeStringSubstitution(StringRef VarName,
1522af732203SDimitry Andric size_t InsertIdx) {
1523af732203SDimitry Andric Substitutions.push_back(
1524af732203SDimitry Andric std::make_unique<StringSubstitution>(this, VarName, InsertIdx));
1525af732203SDimitry Andric return Substitutions.back().get();
1526af732203SDimitry Andric }
1527af732203SDimitry Andric
makeNumericSubstitution(StringRef ExpressionStr,std::unique_ptr<Expression> Expression,size_t InsertIdx)1528af732203SDimitry Andric Substitution *FileCheckPatternContext::makeNumericSubstitution(
1529af732203SDimitry Andric StringRef ExpressionStr, std::unique_ptr<Expression> Expression,
1530af732203SDimitry Andric size_t InsertIdx) {
1531af732203SDimitry Andric Substitutions.push_back(std::make_unique<NumericSubstitution>(
1532af732203SDimitry Andric this, ExpressionStr, std::move(Expression), InsertIdx));
1533af732203SDimitry Andric return Substitutions.back().get();
1534af732203SDimitry Andric }
1535af732203SDimitry Andric
FindRegexVarEnd(StringRef Str,SourceMgr & SM)1536af732203SDimitry Andric size_t Pattern::FindRegexVarEnd(StringRef Str, SourceMgr &SM) {
1537af732203SDimitry Andric // Offset keeps track of the current offset within the input Str
1538af732203SDimitry Andric size_t Offset = 0;
1539af732203SDimitry Andric // [...] Nesting depth
1540af732203SDimitry Andric size_t BracketDepth = 0;
1541af732203SDimitry Andric
1542af732203SDimitry Andric while (!Str.empty()) {
1543af732203SDimitry Andric if (Str.startswith("]]") && BracketDepth == 0)
1544af732203SDimitry Andric return Offset;
1545af732203SDimitry Andric if (Str[0] == '\\') {
1546af732203SDimitry Andric // Backslash escapes the next char within regexes, so skip them both.
1547af732203SDimitry Andric Str = Str.substr(2);
1548af732203SDimitry Andric Offset += 2;
1549af732203SDimitry Andric } else {
1550af732203SDimitry Andric switch (Str[0]) {
1551af732203SDimitry Andric default:
1552af732203SDimitry Andric break;
1553af732203SDimitry Andric case '[':
1554af732203SDimitry Andric BracketDepth++;
1555af732203SDimitry Andric break;
1556af732203SDimitry Andric case ']':
1557af732203SDimitry Andric if (BracketDepth == 0) {
1558af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Str.data()),
1559af732203SDimitry Andric SourceMgr::DK_Error,
1560af732203SDimitry Andric "missing closing \"]\" for regex variable");
1561af732203SDimitry Andric exit(1);
1562af732203SDimitry Andric }
1563af732203SDimitry Andric BracketDepth--;
1564af732203SDimitry Andric break;
1565af732203SDimitry Andric }
1566af732203SDimitry Andric Str = Str.substr(1);
1567af732203SDimitry Andric Offset++;
1568af732203SDimitry Andric }
1569af732203SDimitry Andric }
1570af732203SDimitry Andric
1571af732203SDimitry Andric return StringRef::npos;
1572af732203SDimitry Andric }
1573af732203SDimitry Andric
CanonicalizeFile(MemoryBuffer & MB,SmallVectorImpl<char> & OutputBuffer)1574af732203SDimitry Andric StringRef FileCheck::CanonicalizeFile(MemoryBuffer &MB,
1575af732203SDimitry Andric SmallVectorImpl<char> &OutputBuffer) {
1576af732203SDimitry Andric OutputBuffer.reserve(MB.getBufferSize());
1577af732203SDimitry Andric
1578af732203SDimitry Andric for (const char *Ptr = MB.getBufferStart(), *End = MB.getBufferEnd();
1579af732203SDimitry Andric Ptr != End; ++Ptr) {
1580af732203SDimitry Andric // Eliminate trailing dosish \r.
1581af732203SDimitry Andric if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') {
1582af732203SDimitry Andric continue;
1583af732203SDimitry Andric }
1584af732203SDimitry Andric
1585af732203SDimitry Andric // If current char is not a horizontal whitespace or if horizontal
1586af732203SDimitry Andric // whitespace canonicalization is disabled, dump it to output as is.
1587af732203SDimitry Andric if (Req.NoCanonicalizeWhiteSpace || (*Ptr != ' ' && *Ptr != '\t')) {
1588af732203SDimitry Andric OutputBuffer.push_back(*Ptr);
1589af732203SDimitry Andric continue;
1590af732203SDimitry Andric }
1591af732203SDimitry Andric
1592af732203SDimitry Andric // Otherwise, add one space and advance over neighboring space.
1593af732203SDimitry Andric OutputBuffer.push_back(' ');
1594af732203SDimitry Andric while (Ptr + 1 != End && (Ptr[1] == ' ' || Ptr[1] == '\t'))
1595af732203SDimitry Andric ++Ptr;
1596af732203SDimitry Andric }
1597af732203SDimitry Andric
1598af732203SDimitry Andric // Add a null byte and then return all but that byte.
1599af732203SDimitry Andric OutputBuffer.push_back('\0');
1600af732203SDimitry Andric return StringRef(OutputBuffer.data(), OutputBuffer.size() - 1);
1601af732203SDimitry Andric }
1602af732203SDimitry Andric
FileCheckDiag(const SourceMgr & SM,const Check::FileCheckType & CheckTy,SMLoc CheckLoc,MatchType MatchTy,SMRange InputRange,StringRef Note)1603af732203SDimitry Andric FileCheckDiag::FileCheckDiag(const SourceMgr &SM,
1604af732203SDimitry Andric const Check::FileCheckType &CheckTy,
1605af732203SDimitry Andric SMLoc CheckLoc, MatchType MatchTy,
1606af732203SDimitry Andric SMRange InputRange, StringRef Note)
1607af732203SDimitry Andric : CheckTy(CheckTy), CheckLoc(CheckLoc), MatchTy(MatchTy), Note(Note) {
1608af732203SDimitry Andric auto Start = SM.getLineAndColumn(InputRange.Start);
1609af732203SDimitry Andric auto End = SM.getLineAndColumn(InputRange.End);
1610af732203SDimitry Andric InputStartLine = Start.first;
1611af732203SDimitry Andric InputStartCol = Start.second;
1612af732203SDimitry Andric InputEndLine = End.first;
1613af732203SDimitry Andric InputEndCol = End.second;
1614af732203SDimitry Andric }
1615af732203SDimitry Andric
IsPartOfWord(char c)1616af732203SDimitry Andric static bool IsPartOfWord(char c) {
1617af732203SDimitry Andric return (isAlnum(c) || c == '-' || c == '_');
1618af732203SDimitry Andric }
1619af732203SDimitry Andric
setCount(int C)1620af732203SDimitry Andric Check::FileCheckType &Check::FileCheckType::setCount(int C) {
1621af732203SDimitry Andric assert(Count > 0 && "zero and negative counts are not supported");
1622af732203SDimitry Andric assert((C == 1 || Kind == CheckPlain) &&
1623af732203SDimitry Andric "count supported only for plain CHECK directives");
1624af732203SDimitry Andric Count = C;
1625af732203SDimitry Andric return *this;
1626af732203SDimitry Andric }
1627af732203SDimitry Andric
getModifiersDescription() const1628af732203SDimitry Andric std::string Check::FileCheckType::getModifiersDescription() const {
1629af732203SDimitry Andric if (Modifiers.none())
1630af732203SDimitry Andric return "";
1631af732203SDimitry Andric std::string Ret;
1632af732203SDimitry Andric raw_string_ostream OS(Ret);
1633af732203SDimitry Andric OS << '{';
1634af732203SDimitry Andric if (isLiteralMatch())
1635af732203SDimitry Andric OS << "LITERAL";
1636af732203SDimitry Andric OS << '}';
1637af732203SDimitry Andric return OS.str();
1638af732203SDimitry Andric }
1639af732203SDimitry Andric
getDescription(StringRef Prefix) const1640af732203SDimitry Andric std::string Check::FileCheckType::getDescription(StringRef Prefix) const {
1641af732203SDimitry Andric // Append directive modifiers.
1642af732203SDimitry Andric auto WithModifiers = [this, Prefix](StringRef Str) -> std::string {
1643af732203SDimitry Andric return (Prefix + Str + getModifiersDescription()).str();
1644af732203SDimitry Andric };
1645af732203SDimitry Andric
1646af732203SDimitry Andric switch (Kind) {
1647af732203SDimitry Andric case Check::CheckNone:
1648af732203SDimitry Andric return "invalid";
1649af732203SDimitry Andric case Check::CheckPlain:
1650af732203SDimitry Andric if (Count > 1)
1651af732203SDimitry Andric return WithModifiers("-COUNT");
1652af732203SDimitry Andric return WithModifiers("");
1653af732203SDimitry Andric case Check::CheckNext:
1654af732203SDimitry Andric return WithModifiers("-NEXT");
1655af732203SDimitry Andric case Check::CheckSame:
1656af732203SDimitry Andric return WithModifiers("-SAME");
1657af732203SDimitry Andric case Check::CheckNot:
1658af732203SDimitry Andric return WithModifiers("-NOT");
1659af732203SDimitry Andric case Check::CheckDAG:
1660af732203SDimitry Andric return WithModifiers("-DAG");
1661af732203SDimitry Andric case Check::CheckLabel:
1662af732203SDimitry Andric return WithModifiers("-LABEL");
1663af732203SDimitry Andric case Check::CheckEmpty:
1664af732203SDimitry Andric return WithModifiers("-EMPTY");
1665af732203SDimitry Andric case Check::CheckComment:
1666af732203SDimitry Andric return std::string(Prefix);
1667af732203SDimitry Andric case Check::CheckEOF:
1668af732203SDimitry Andric return "implicit EOF";
1669af732203SDimitry Andric case Check::CheckBadNot:
1670af732203SDimitry Andric return "bad NOT";
1671af732203SDimitry Andric case Check::CheckBadCount:
1672af732203SDimitry Andric return "bad COUNT";
1673af732203SDimitry Andric }
1674af732203SDimitry Andric llvm_unreachable("unknown FileCheckType");
1675af732203SDimitry Andric }
1676af732203SDimitry Andric
1677af732203SDimitry Andric static std::pair<Check::FileCheckType, StringRef>
FindCheckType(const FileCheckRequest & Req,StringRef Buffer,StringRef Prefix)1678af732203SDimitry Andric FindCheckType(const FileCheckRequest &Req, StringRef Buffer, StringRef Prefix) {
1679af732203SDimitry Andric if (Buffer.size() <= Prefix.size())
1680af732203SDimitry Andric return {Check::CheckNone, StringRef()};
1681af732203SDimitry Andric
1682af732203SDimitry Andric StringRef Rest = Buffer.drop_front(Prefix.size());
1683af732203SDimitry Andric // Check for comment.
1684af732203SDimitry Andric if (llvm::is_contained(Req.CommentPrefixes, Prefix)) {
1685af732203SDimitry Andric if (Rest.consume_front(":"))
1686af732203SDimitry Andric return {Check::CheckComment, Rest};
1687af732203SDimitry Andric // Ignore a comment prefix if it has a suffix like "-NOT".
1688af732203SDimitry Andric return {Check::CheckNone, StringRef()};
1689af732203SDimitry Andric }
1690af732203SDimitry Andric
1691af732203SDimitry Andric auto ConsumeModifiers = [&](Check::FileCheckType Ret)
1692af732203SDimitry Andric -> std::pair<Check::FileCheckType, StringRef> {
1693af732203SDimitry Andric if (Rest.consume_front(":"))
1694af732203SDimitry Andric return {Ret, Rest};
1695af732203SDimitry Andric if (!Rest.consume_front("{"))
1696af732203SDimitry Andric return {Check::CheckNone, StringRef()};
1697af732203SDimitry Andric
1698af732203SDimitry Andric // Parse the modifiers, speparated by commas.
1699af732203SDimitry Andric do {
1700af732203SDimitry Andric // Allow whitespace in modifiers list.
1701af732203SDimitry Andric Rest = Rest.ltrim();
1702af732203SDimitry Andric if (Rest.consume_front("LITERAL"))
1703af732203SDimitry Andric Ret.setLiteralMatch();
1704af732203SDimitry Andric else
1705af732203SDimitry Andric return {Check::CheckNone, Rest};
1706af732203SDimitry Andric // Allow whitespace in modifiers list.
1707af732203SDimitry Andric Rest = Rest.ltrim();
1708af732203SDimitry Andric } while (Rest.consume_front(","));
1709af732203SDimitry Andric if (!Rest.consume_front("}:"))
1710af732203SDimitry Andric return {Check::CheckNone, Rest};
1711af732203SDimitry Andric return {Ret, Rest};
1712af732203SDimitry Andric };
1713af732203SDimitry Andric
1714af732203SDimitry Andric // Verify that the prefix is followed by directive modifiers or a colon.
1715af732203SDimitry Andric if (Rest.consume_front(":"))
1716af732203SDimitry Andric return {Check::CheckPlain, Rest};
1717af732203SDimitry Andric if (Rest.front() == '{')
1718af732203SDimitry Andric return ConsumeModifiers(Check::CheckPlain);
1719af732203SDimitry Andric
1720af732203SDimitry Andric if (!Rest.consume_front("-"))
1721af732203SDimitry Andric return {Check::CheckNone, StringRef()};
1722af732203SDimitry Andric
1723af732203SDimitry Andric if (Rest.consume_front("COUNT-")) {
1724af732203SDimitry Andric int64_t Count;
1725af732203SDimitry Andric if (Rest.consumeInteger(10, Count))
1726af732203SDimitry Andric // Error happened in parsing integer.
1727af732203SDimitry Andric return {Check::CheckBadCount, Rest};
1728af732203SDimitry Andric if (Count <= 0 || Count > INT32_MAX)
1729af732203SDimitry Andric return {Check::CheckBadCount, Rest};
1730af732203SDimitry Andric if (Rest.front() != ':' && Rest.front() != '{')
1731af732203SDimitry Andric return {Check::CheckBadCount, Rest};
1732af732203SDimitry Andric return ConsumeModifiers(
1733af732203SDimitry Andric Check::FileCheckType(Check::CheckPlain).setCount(Count));
1734af732203SDimitry Andric }
1735af732203SDimitry Andric
1736af732203SDimitry Andric // You can't combine -NOT with another suffix.
1737af732203SDimitry Andric if (Rest.startswith("DAG-NOT:") || Rest.startswith("NOT-DAG:") ||
1738af732203SDimitry Andric Rest.startswith("NEXT-NOT:") || Rest.startswith("NOT-NEXT:") ||
1739af732203SDimitry Andric Rest.startswith("SAME-NOT:") || Rest.startswith("NOT-SAME:") ||
1740af732203SDimitry Andric Rest.startswith("EMPTY-NOT:") || Rest.startswith("NOT-EMPTY:"))
1741af732203SDimitry Andric return {Check::CheckBadNot, Rest};
1742af732203SDimitry Andric
1743af732203SDimitry Andric if (Rest.consume_front("NEXT"))
1744af732203SDimitry Andric return ConsumeModifiers(Check::CheckNext);
1745af732203SDimitry Andric
1746af732203SDimitry Andric if (Rest.consume_front("SAME"))
1747af732203SDimitry Andric return ConsumeModifiers(Check::CheckSame);
1748af732203SDimitry Andric
1749af732203SDimitry Andric if (Rest.consume_front("NOT"))
1750af732203SDimitry Andric return ConsumeModifiers(Check::CheckNot);
1751af732203SDimitry Andric
1752af732203SDimitry Andric if (Rest.consume_front("DAG"))
1753af732203SDimitry Andric return ConsumeModifiers(Check::CheckDAG);
1754af732203SDimitry Andric
1755af732203SDimitry Andric if (Rest.consume_front("LABEL"))
1756af732203SDimitry Andric return ConsumeModifiers(Check::CheckLabel);
1757af732203SDimitry Andric
1758af732203SDimitry Andric if (Rest.consume_front("EMPTY"))
1759af732203SDimitry Andric return ConsumeModifiers(Check::CheckEmpty);
1760af732203SDimitry Andric
1761af732203SDimitry Andric return {Check::CheckNone, Rest};
1762af732203SDimitry Andric }
1763af732203SDimitry Andric
1764af732203SDimitry Andric // From the given position, find the next character after the word.
SkipWord(StringRef Str,size_t Loc)1765af732203SDimitry Andric static size_t SkipWord(StringRef Str, size_t Loc) {
1766af732203SDimitry Andric while (Loc < Str.size() && IsPartOfWord(Str[Loc]))
1767af732203SDimitry Andric ++Loc;
1768af732203SDimitry Andric return Loc;
1769af732203SDimitry Andric }
1770af732203SDimitry Andric
1771af732203SDimitry Andric /// Searches the buffer for the first prefix in the prefix regular expression.
1772af732203SDimitry Andric ///
1773af732203SDimitry Andric /// This searches the buffer using the provided regular expression, however it
1774af732203SDimitry Andric /// enforces constraints beyond that:
1775af732203SDimitry Andric /// 1) The found prefix must not be a suffix of something that looks like
1776af732203SDimitry Andric /// a valid prefix.
1777af732203SDimitry Andric /// 2) The found prefix must be followed by a valid check type suffix using \c
1778af732203SDimitry Andric /// FindCheckType above.
1779af732203SDimitry Andric ///
1780af732203SDimitry Andric /// \returns a pair of StringRefs into the Buffer, which combines:
1781af732203SDimitry Andric /// - the first match of the regular expression to satisfy these two is
1782af732203SDimitry Andric /// returned,
1783af732203SDimitry Andric /// otherwise an empty StringRef is returned to indicate failure.
1784af732203SDimitry Andric /// - buffer rewound to the location right after parsed suffix, for parsing
1785af732203SDimitry Andric /// to continue from
1786af732203SDimitry Andric ///
1787af732203SDimitry Andric /// If this routine returns a valid prefix, it will also shrink \p Buffer to
1788af732203SDimitry Andric /// start at the beginning of the returned prefix, increment \p LineNumber for
1789af732203SDimitry Andric /// each new line consumed from \p Buffer, and set \p CheckTy to the type of
1790af732203SDimitry Andric /// check found by examining the suffix.
1791af732203SDimitry Andric ///
1792af732203SDimitry Andric /// If no valid prefix is found, the state of Buffer, LineNumber, and CheckTy
1793af732203SDimitry Andric /// is unspecified.
1794af732203SDimitry Andric static std::pair<StringRef, StringRef>
FindFirstMatchingPrefix(const FileCheckRequest & Req,Regex & PrefixRE,StringRef & Buffer,unsigned & LineNumber,Check::FileCheckType & CheckTy)1795af732203SDimitry Andric FindFirstMatchingPrefix(const FileCheckRequest &Req, Regex &PrefixRE,
1796af732203SDimitry Andric StringRef &Buffer, unsigned &LineNumber,
1797af732203SDimitry Andric Check::FileCheckType &CheckTy) {
1798af732203SDimitry Andric SmallVector<StringRef, 2> Matches;
1799af732203SDimitry Andric
1800af732203SDimitry Andric while (!Buffer.empty()) {
1801af732203SDimitry Andric // Find the first (longest) match using the RE.
1802af732203SDimitry Andric if (!PrefixRE.match(Buffer, &Matches))
1803af732203SDimitry Andric // No match at all, bail.
1804af732203SDimitry Andric return {StringRef(), StringRef()};
1805af732203SDimitry Andric
1806af732203SDimitry Andric StringRef Prefix = Matches[0];
1807af732203SDimitry Andric Matches.clear();
1808af732203SDimitry Andric
1809af732203SDimitry Andric assert(Prefix.data() >= Buffer.data() &&
1810af732203SDimitry Andric Prefix.data() < Buffer.data() + Buffer.size() &&
1811af732203SDimitry Andric "Prefix doesn't start inside of buffer!");
1812af732203SDimitry Andric size_t Loc = Prefix.data() - Buffer.data();
1813af732203SDimitry Andric StringRef Skipped = Buffer.substr(0, Loc);
1814af732203SDimitry Andric Buffer = Buffer.drop_front(Loc);
1815af732203SDimitry Andric LineNumber += Skipped.count('\n');
1816af732203SDimitry Andric
1817af732203SDimitry Andric // Check that the matched prefix isn't a suffix of some other check-like
1818af732203SDimitry Andric // word.
1819af732203SDimitry Andric // FIXME: This is a very ad-hoc check. it would be better handled in some
1820af732203SDimitry Andric // other way. Among other things it seems hard to distinguish between
1821af732203SDimitry Andric // intentional and unintentional uses of this feature.
1822af732203SDimitry Andric if (Skipped.empty() || !IsPartOfWord(Skipped.back())) {
1823af732203SDimitry Andric // Now extract the type.
1824af732203SDimitry Andric StringRef AfterSuffix;
1825af732203SDimitry Andric std::tie(CheckTy, AfterSuffix) = FindCheckType(Req, Buffer, Prefix);
1826af732203SDimitry Andric
1827af732203SDimitry Andric // If we've found a valid check type for this prefix, we're done.
1828af732203SDimitry Andric if (CheckTy != Check::CheckNone)
1829af732203SDimitry Andric return {Prefix, AfterSuffix};
1830af732203SDimitry Andric }
1831af732203SDimitry Andric
1832af732203SDimitry Andric // If we didn't successfully find a prefix, we need to skip this invalid
1833af732203SDimitry Andric // prefix and continue scanning. We directly skip the prefix that was
1834af732203SDimitry Andric // matched and any additional parts of that check-like word.
1835af732203SDimitry Andric Buffer = Buffer.drop_front(SkipWord(Buffer, Prefix.size()));
1836af732203SDimitry Andric }
1837af732203SDimitry Andric
1838af732203SDimitry Andric // We ran out of buffer while skipping partial matches so give up.
1839af732203SDimitry Andric return {StringRef(), StringRef()};
1840af732203SDimitry Andric }
1841af732203SDimitry Andric
createLineVariable()1842af732203SDimitry Andric void FileCheckPatternContext::createLineVariable() {
1843af732203SDimitry Andric assert(!LineVariable && "@LINE pseudo numeric variable already created");
1844af732203SDimitry Andric StringRef LineName = "@LINE";
1845af732203SDimitry Andric LineVariable = makeNumericVariable(
1846af732203SDimitry Andric LineName, ExpressionFormat(ExpressionFormat::Kind::Unsigned));
1847af732203SDimitry Andric GlobalNumericVariableTable[LineName] = LineVariable;
1848af732203SDimitry Andric }
1849af732203SDimitry Andric
FileCheck(FileCheckRequest Req)1850af732203SDimitry Andric FileCheck::FileCheck(FileCheckRequest Req)
1851af732203SDimitry Andric : Req(Req), PatternContext(std::make_unique<FileCheckPatternContext>()),
1852af732203SDimitry Andric CheckStrings(std::make_unique<std::vector<FileCheckString>>()) {}
1853af732203SDimitry Andric
1854af732203SDimitry Andric FileCheck::~FileCheck() = default;
1855af732203SDimitry Andric
readCheckFile(SourceMgr & SM,StringRef Buffer,Regex & PrefixRE,std::pair<unsigned,unsigned> * ImpPatBufferIDRange)1856af732203SDimitry Andric bool FileCheck::readCheckFile(
1857af732203SDimitry Andric SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
1858af732203SDimitry Andric std::pair<unsigned, unsigned> *ImpPatBufferIDRange) {
1859af732203SDimitry Andric if (ImpPatBufferIDRange)
1860af732203SDimitry Andric ImpPatBufferIDRange->first = ImpPatBufferIDRange->second = 0;
1861af732203SDimitry Andric
1862af732203SDimitry Andric Error DefineError =
1863af732203SDimitry Andric PatternContext->defineCmdlineVariables(Req.GlobalDefines, SM);
1864af732203SDimitry Andric if (DefineError) {
1865af732203SDimitry Andric logAllUnhandledErrors(std::move(DefineError), errs());
1866af732203SDimitry Andric return true;
1867af732203SDimitry Andric }
1868af732203SDimitry Andric
1869af732203SDimitry Andric PatternContext->createLineVariable();
1870af732203SDimitry Andric
1871af732203SDimitry Andric std::vector<Pattern> ImplicitNegativeChecks;
1872af732203SDimitry Andric for (StringRef PatternString : Req.ImplicitCheckNot) {
1873af732203SDimitry Andric // Create a buffer with fake command line content in order to display the
1874af732203SDimitry Andric // command line option responsible for the specific implicit CHECK-NOT.
1875af732203SDimitry Andric std::string Prefix = "-implicit-check-not='";
1876af732203SDimitry Andric std::string Suffix = "'";
1877af732203SDimitry Andric std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy(
1878af732203SDimitry Andric (Prefix + PatternString + Suffix).str(), "command line");
1879af732203SDimitry Andric
1880af732203SDimitry Andric StringRef PatternInBuffer =
1881af732203SDimitry Andric CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());
1882af732203SDimitry Andric unsigned BufferID = SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc());
1883af732203SDimitry Andric if (ImpPatBufferIDRange) {
1884af732203SDimitry Andric if (ImpPatBufferIDRange->first == ImpPatBufferIDRange->second) {
1885af732203SDimitry Andric ImpPatBufferIDRange->first = BufferID;
1886af732203SDimitry Andric ImpPatBufferIDRange->second = BufferID + 1;
1887af732203SDimitry Andric } else {
1888af732203SDimitry Andric assert(BufferID == ImpPatBufferIDRange->second &&
1889af732203SDimitry Andric "expected consecutive source buffer IDs");
1890af732203SDimitry Andric ++ImpPatBufferIDRange->second;
1891af732203SDimitry Andric }
1892af732203SDimitry Andric }
1893af732203SDimitry Andric
1894af732203SDimitry Andric ImplicitNegativeChecks.push_back(
1895af732203SDimitry Andric Pattern(Check::CheckNot, PatternContext.get()));
1896af732203SDimitry Andric ImplicitNegativeChecks.back().parsePattern(PatternInBuffer,
1897af732203SDimitry Andric "IMPLICIT-CHECK", SM, Req);
1898af732203SDimitry Andric }
1899af732203SDimitry Andric
1900af732203SDimitry Andric std::vector<Pattern> DagNotMatches = ImplicitNegativeChecks;
1901af732203SDimitry Andric
1902af732203SDimitry Andric // LineNumber keeps track of the line on which CheckPrefix instances are
1903af732203SDimitry Andric // found.
1904af732203SDimitry Andric unsigned LineNumber = 1;
1905af732203SDimitry Andric
1906af732203SDimitry Andric std::set<StringRef> PrefixesNotFound(Req.CheckPrefixes.begin(),
1907af732203SDimitry Andric Req.CheckPrefixes.end());
1908af732203SDimitry Andric const size_t DistinctPrefixes = PrefixesNotFound.size();
1909af732203SDimitry Andric while (true) {
1910af732203SDimitry Andric Check::FileCheckType CheckTy;
1911af732203SDimitry Andric
1912af732203SDimitry Andric // See if a prefix occurs in the memory buffer.
1913af732203SDimitry Andric StringRef UsedPrefix;
1914af732203SDimitry Andric StringRef AfterSuffix;
1915af732203SDimitry Andric std::tie(UsedPrefix, AfterSuffix) =
1916af732203SDimitry Andric FindFirstMatchingPrefix(Req, PrefixRE, Buffer, LineNumber, CheckTy);
1917af732203SDimitry Andric if (UsedPrefix.empty())
1918af732203SDimitry Andric break;
1919af732203SDimitry Andric if (CheckTy != Check::CheckComment)
1920af732203SDimitry Andric PrefixesNotFound.erase(UsedPrefix);
1921af732203SDimitry Andric
1922af732203SDimitry Andric assert(UsedPrefix.data() == Buffer.data() &&
1923af732203SDimitry Andric "Failed to move Buffer's start forward, or pointed prefix outside "
1924af732203SDimitry Andric "of the buffer!");
1925af732203SDimitry Andric assert(AfterSuffix.data() >= Buffer.data() &&
1926af732203SDimitry Andric AfterSuffix.data() < Buffer.data() + Buffer.size() &&
1927af732203SDimitry Andric "Parsing after suffix doesn't start inside of buffer!");
1928af732203SDimitry Andric
1929af732203SDimitry Andric // Location to use for error messages.
1930af732203SDimitry Andric const char *UsedPrefixStart = UsedPrefix.data();
1931af732203SDimitry Andric
1932af732203SDimitry Andric // Skip the buffer to the end of parsed suffix (or just prefix, if no good
1933af732203SDimitry Andric // suffix was processed).
1934af732203SDimitry Andric Buffer = AfterSuffix.empty() ? Buffer.drop_front(UsedPrefix.size())
1935af732203SDimitry Andric : AfterSuffix;
1936af732203SDimitry Andric
1937af732203SDimitry Andric // Complain about useful-looking but unsupported suffixes.
1938af732203SDimitry Andric if (CheckTy == Check::CheckBadNot) {
1939af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,
1940af732203SDimitry Andric "unsupported -NOT combo on prefix '" + UsedPrefix + "'");
1941af732203SDimitry Andric return true;
1942af732203SDimitry Andric }
1943af732203SDimitry Andric
1944af732203SDimitry Andric // Complain about invalid count specification.
1945af732203SDimitry Andric if (CheckTy == Check::CheckBadCount) {
1946af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Error,
1947af732203SDimitry Andric "invalid count in -COUNT specification on prefix '" +
1948af732203SDimitry Andric UsedPrefix + "'");
1949af732203SDimitry Andric return true;
1950af732203SDimitry Andric }
1951af732203SDimitry Andric
1952af732203SDimitry Andric // Okay, we found the prefix, yay. Remember the rest of the line, but ignore
1953af732203SDimitry Andric // leading whitespace.
1954af732203SDimitry Andric if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
1955af732203SDimitry Andric Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
1956af732203SDimitry Andric
1957af732203SDimitry Andric // Scan ahead to the end of line.
1958af732203SDimitry Andric size_t EOL = Buffer.find_first_of("\n\r");
1959af732203SDimitry Andric
1960af732203SDimitry Andric // Remember the location of the start of the pattern, for diagnostics.
1961af732203SDimitry Andric SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data());
1962af732203SDimitry Andric
1963af732203SDimitry Andric // Extract the pattern from the buffer.
1964af732203SDimitry Andric StringRef PatternBuffer = Buffer.substr(0, EOL);
1965af732203SDimitry Andric Buffer = Buffer.substr(EOL);
1966af732203SDimitry Andric
1967af732203SDimitry Andric // If this is a comment, we're done.
1968af732203SDimitry Andric if (CheckTy == Check::CheckComment)
1969af732203SDimitry Andric continue;
1970af732203SDimitry Andric
1971af732203SDimitry Andric // Parse the pattern.
1972af732203SDimitry Andric Pattern P(CheckTy, PatternContext.get(), LineNumber);
1973af732203SDimitry Andric if (P.parsePattern(PatternBuffer, UsedPrefix, SM, Req))
1974af732203SDimitry Andric return true;
1975af732203SDimitry Andric
1976af732203SDimitry Andric // Verify that CHECK-LABEL lines do not define or use variables
1977af732203SDimitry Andric if ((CheckTy == Check::CheckLabel) && P.hasVariable()) {
1978af732203SDimitry Andric SM.PrintMessage(
1979af732203SDimitry Andric SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error,
1980af732203SDimitry Andric "found '" + UsedPrefix + "-LABEL:'"
1981af732203SDimitry Andric " with variable definition or use");
1982af732203SDimitry Andric return true;
1983af732203SDimitry Andric }
1984af732203SDimitry Andric
1985af732203SDimitry Andric // Verify that CHECK-NEXT/SAME/EMPTY lines have at least one CHECK line before them.
1986af732203SDimitry Andric if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame ||
1987af732203SDimitry Andric CheckTy == Check::CheckEmpty) &&
1988af732203SDimitry Andric CheckStrings->empty()) {
1989af732203SDimitry Andric StringRef Type = CheckTy == Check::CheckNext
1990af732203SDimitry Andric ? "NEXT"
1991af732203SDimitry Andric : CheckTy == Check::CheckEmpty ? "EMPTY" : "SAME";
1992af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart),
1993af732203SDimitry Andric SourceMgr::DK_Error,
1994af732203SDimitry Andric "found '" + UsedPrefix + "-" + Type +
1995af732203SDimitry Andric "' without previous '" + UsedPrefix + ": line");
1996af732203SDimitry Andric return true;
1997af732203SDimitry Andric }
1998af732203SDimitry Andric
1999af732203SDimitry Andric // Handle CHECK-DAG/-NOT.
2000af732203SDimitry Andric if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) {
2001af732203SDimitry Andric DagNotMatches.push_back(P);
2002af732203SDimitry Andric continue;
2003af732203SDimitry Andric }
2004af732203SDimitry Andric
2005af732203SDimitry Andric // Okay, add the string we captured to the output vector and move on.
2006af732203SDimitry Andric CheckStrings->emplace_back(P, UsedPrefix, PatternLoc);
2007af732203SDimitry Andric std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);
2008af732203SDimitry Andric DagNotMatches = ImplicitNegativeChecks;
2009af732203SDimitry Andric }
2010af732203SDimitry Andric
2011af732203SDimitry Andric // When there are no used prefixes we report an error except in the case that
2012af732203SDimitry Andric // no prefix is specified explicitly but -implicit-check-not is specified.
2013af732203SDimitry Andric const bool NoPrefixesFound = PrefixesNotFound.size() == DistinctPrefixes;
2014af732203SDimitry Andric const bool SomePrefixesUnexpectedlyNotUsed =
2015af732203SDimitry Andric !Req.AllowUnusedPrefixes && !PrefixesNotFound.empty();
2016af732203SDimitry Andric if ((NoPrefixesFound || SomePrefixesUnexpectedlyNotUsed) &&
2017af732203SDimitry Andric (ImplicitNegativeChecks.empty() || !Req.IsDefaultCheckPrefix)) {
2018af732203SDimitry Andric errs() << "error: no check strings found with prefix"
2019af732203SDimitry Andric << (PrefixesNotFound.size() > 1 ? "es " : " ");
2020af732203SDimitry Andric bool First = true;
2021af732203SDimitry Andric for (StringRef MissingPrefix : PrefixesNotFound) {
2022af732203SDimitry Andric if (!First)
2023af732203SDimitry Andric errs() << ", ";
2024af732203SDimitry Andric errs() << "\'" << MissingPrefix << ":'";
2025af732203SDimitry Andric First = false;
2026af732203SDimitry Andric }
2027af732203SDimitry Andric errs() << '\n';
2028af732203SDimitry Andric return true;
2029af732203SDimitry Andric }
2030af732203SDimitry Andric
2031af732203SDimitry Andric // Add an EOF pattern for any trailing --implicit-check-not/CHECK-DAG/-NOTs,
2032af732203SDimitry Andric // and use the first prefix as a filler for the error message.
2033af732203SDimitry Andric if (!DagNotMatches.empty()) {
2034af732203SDimitry Andric CheckStrings->emplace_back(
2035af732203SDimitry Andric Pattern(Check::CheckEOF, PatternContext.get(), LineNumber + 1),
2036af732203SDimitry Andric *Req.CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()));
2037af732203SDimitry Andric std::swap(DagNotMatches, CheckStrings->back().DagNotStrings);
2038af732203SDimitry Andric }
2039af732203SDimitry Andric
2040af732203SDimitry Andric return false;
2041af732203SDimitry Andric }
2042af732203SDimitry Andric
2043*5f7ddb14SDimitry Andric /// Returns either (1) \c ErrorSuccess if there was no error or (2)
2044*5f7ddb14SDimitry Andric /// \c ErrorReported if an error was reported, such as an unexpected match.
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)2045*5f7ddb14SDimitry Andric static Error printMatch(bool ExpectedMatch, const SourceMgr &SM,
2046af732203SDimitry Andric StringRef Prefix, SMLoc Loc, const Pattern &Pat,
2047*5f7ddb14SDimitry Andric int MatchedCount, StringRef Buffer,
2048*5f7ddb14SDimitry Andric Pattern::MatchResult MatchResult,
2049*5f7ddb14SDimitry Andric const FileCheckRequest &Req,
2050af732203SDimitry Andric std::vector<FileCheckDiag> *Diags) {
2051*5f7ddb14SDimitry Andric // Suppress some verbosity if there's no error.
2052*5f7ddb14SDimitry Andric bool HasError = !ExpectedMatch || MatchResult.TheError;
2053af732203SDimitry Andric bool PrintDiag = true;
2054*5f7ddb14SDimitry Andric if (!HasError) {
2055af732203SDimitry Andric if (!Req.Verbose)
2056*5f7ddb14SDimitry Andric return ErrorReported::reportedOrSuccess(HasError);
2057af732203SDimitry Andric if (!Req.VerboseVerbose && Pat.getCheckTy() == Check::CheckEOF)
2058*5f7ddb14SDimitry Andric return ErrorReported::reportedOrSuccess(HasError);
2059af732203SDimitry Andric // Due to their verbosity, we don't print verbose diagnostics here if we're
2060*5f7ddb14SDimitry Andric // gathering them for Diags to be rendered elsewhere, but we always print
2061*5f7ddb14SDimitry Andric // other diagnostics.
2062af732203SDimitry Andric PrintDiag = !Diags;
2063af732203SDimitry Andric }
2064*5f7ddb14SDimitry Andric
2065*5f7ddb14SDimitry Andric // Add "found" diagnostic, substitutions, and variable definitions to Diags.
2066af732203SDimitry Andric FileCheckDiag::MatchType MatchTy = ExpectedMatch
2067af732203SDimitry Andric ? FileCheckDiag::MatchFoundAndExpected
2068af732203SDimitry Andric : FileCheckDiag::MatchFoundButExcluded;
2069af732203SDimitry Andric SMRange MatchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(),
2070*5f7ddb14SDimitry Andric Buffer, MatchResult.TheMatch->Pos,
2071*5f7ddb14SDimitry Andric MatchResult.TheMatch->Len, Diags);
2072af732203SDimitry Andric if (Diags) {
2073af732203SDimitry Andric Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, Diags);
2074af732203SDimitry Andric Pat.printVariableDefs(SM, MatchTy, Diags);
2075af732203SDimitry Andric }
2076*5f7ddb14SDimitry Andric if (!PrintDiag) {
2077*5f7ddb14SDimitry Andric assert(!HasError && "expected to report more diagnostics for error");
2078*5f7ddb14SDimitry Andric return ErrorReported::reportedOrSuccess(HasError);
2079*5f7ddb14SDimitry Andric }
2080af732203SDimitry Andric
2081*5f7ddb14SDimitry Andric // Print the match.
2082af732203SDimitry Andric std::string Message = formatv("{0}: {1} string found in input",
2083af732203SDimitry Andric Pat.getCheckTy().getDescription(Prefix),
2084af732203SDimitry Andric (ExpectedMatch ? "expected" : "excluded"))
2085af732203SDimitry Andric .str();
2086af732203SDimitry Andric if (Pat.getCount() > 1)
2087af732203SDimitry Andric Message += formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
2088af732203SDimitry Andric SM.PrintMessage(
2089af732203SDimitry Andric Loc, ExpectedMatch ? SourceMgr::DK_Remark : SourceMgr::DK_Error, Message);
2090af732203SDimitry Andric SM.PrintMessage(MatchRange.Start, SourceMgr::DK_Note, "found here",
2091af732203SDimitry Andric {MatchRange});
2092*5f7ddb14SDimitry Andric
2093*5f7ddb14SDimitry Andric // Print additional information, which can be useful even if there are errors.
2094af732203SDimitry Andric Pat.printSubstitutions(SM, Buffer, MatchRange, MatchTy, nullptr);
2095af732203SDimitry Andric Pat.printVariableDefs(SM, MatchTy, nullptr);
2096*5f7ddb14SDimitry Andric
2097*5f7ddb14SDimitry Andric // Print errors and add them to Diags. We report these errors after the match
2098*5f7ddb14SDimitry Andric // itself because we found them after the match. If we had found them before
2099*5f7ddb14SDimitry Andric // the match, we'd be in printNoMatch.
2100*5f7ddb14SDimitry Andric handleAllErrors(std::move(MatchResult.TheError),
2101*5f7ddb14SDimitry Andric [&](const ErrorDiagnostic &E) {
2102*5f7ddb14SDimitry Andric E.log(errs());
2103*5f7ddb14SDimitry Andric if (Diags) {
2104*5f7ddb14SDimitry Andric Diags->emplace_back(SM, Pat.getCheckTy(), Loc,
2105*5f7ddb14SDimitry Andric FileCheckDiag::MatchFoundErrorNote,
2106*5f7ddb14SDimitry Andric E.getRange(), E.getMessage().str());
2107*5f7ddb14SDimitry Andric }
2108*5f7ddb14SDimitry Andric });
2109*5f7ddb14SDimitry Andric return ErrorReported::reportedOrSuccess(HasError);
2110af732203SDimitry Andric }
2111af732203SDimitry Andric
2112*5f7ddb14SDimitry Andric /// Returns either (1) \c ErrorSuccess if there was no error, or (2)
2113*5f7ddb14SDimitry Andric /// \c ErrorReported if an error was reported, such as an expected match not
2114*5f7ddb14SDimitry Andric /// found.
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)2115*5f7ddb14SDimitry Andric static Error printNoMatch(bool ExpectedMatch, const SourceMgr &SM,
2116af732203SDimitry Andric StringRef Prefix, SMLoc Loc, const Pattern &Pat,
2117*5f7ddb14SDimitry Andric int MatchedCount, StringRef Buffer, Error MatchError,
2118*5f7ddb14SDimitry Andric bool VerboseVerbose,
2119*5f7ddb14SDimitry Andric std::vector<FileCheckDiag> *Diags) {
2120*5f7ddb14SDimitry Andric // Print any pattern errors, and record them to be added to Diags later.
2121*5f7ddb14SDimitry Andric bool HasError = ExpectedMatch;
2122*5f7ddb14SDimitry Andric bool HasPatternError = false;
2123af732203SDimitry Andric FileCheckDiag::MatchType MatchTy = ExpectedMatch
2124af732203SDimitry Andric ? FileCheckDiag::MatchNoneButExpected
2125af732203SDimitry Andric : FileCheckDiag::MatchNoneAndExcluded;
2126*5f7ddb14SDimitry Andric SmallVector<std::string, 4> ErrorMsgs;
2127*5f7ddb14SDimitry Andric handleAllErrors(
2128*5f7ddb14SDimitry Andric std::move(MatchError),
2129*5f7ddb14SDimitry Andric [&](const ErrorDiagnostic &E) {
2130*5f7ddb14SDimitry Andric HasError = HasPatternError = true;
2131*5f7ddb14SDimitry Andric MatchTy = FileCheckDiag::MatchNoneForInvalidPattern;
2132*5f7ddb14SDimitry Andric E.log(errs());
2133af732203SDimitry Andric if (Diags)
2134*5f7ddb14SDimitry Andric ErrorMsgs.push_back(E.getMessage().str());
2135*5f7ddb14SDimitry Andric },
2136*5f7ddb14SDimitry Andric // NotFoundError is why printNoMatch was invoked.
2137*5f7ddb14SDimitry Andric [](const NotFoundError &E) {});
2138*5f7ddb14SDimitry Andric
2139*5f7ddb14SDimitry Andric // Suppress some verbosity if there's no error.
2140*5f7ddb14SDimitry Andric bool PrintDiag = true;
2141*5f7ddb14SDimitry Andric if (!HasError) {
2142*5f7ddb14SDimitry Andric if (!VerboseVerbose)
2143*5f7ddb14SDimitry Andric return ErrorReported::reportedOrSuccess(HasError);
2144*5f7ddb14SDimitry Andric // Due to their verbosity, we don't print verbose diagnostics here if we're
2145*5f7ddb14SDimitry Andric // gathering them for Diags to be rendered elsewhere, but we always print
2146*5f7ddb14SDimitry Andric // other diagnostics.
2147*5f7ddb14SDimitry Andric PrintDiag = !Diags;
2148af732203SDimitry Andric }
2149af732203SDimitry Andric
2150*5f7ddb14SDimitry Andric // Add "not found" diagnostic, substitutions, and pattern errors to Diags.
2151*5f7ddb14SDimitry Andric //
2152*5f7ddb14SDimitry Andric // We handle Diags a little differently than the errors we print directly:
2153*5f7ddb14SDimitry Andric // we add the "not found" diagnostic to Diags even if there are pattern
2154*5f7ddb14SDimitry Andric // errors. The reason is that we need to attach pattern errors as notes
2155*5f7ddb14SDimitry Andric // somewhere in the input, and the input search range from the "not found"
2156*5f7ddb14SDimitry Andric // diagnostic is all we have to anchor them.
2157*5f7ddb14SDimitry Andric SMRange SearchRange = ProcessMatchResult(MatchTy, SM, Loc, Pat.getCheckTy(),
2158*5f7ddb14SDimitry Andric Buffer, 0, Buffer.size(), Diags);
2159*5f7ddb14SDimitry Andric if (Diags) {
2160*5f7ddb14SDimitry Andric SMRange NoteRange = SMRange(SearchRange.Start, SearchRange.Start);
2161*5f7ddb14SDimitry Andric for (StringRef ErrorMsg : ErrorMsgs)
2162*5f7ddb14SDimitry Andric Diags->emplace_back(SM, Pat.getCheckTy(), Loc, MatchTy, NoteRange,
2163*5f7ddb14SDimitry Andric ErrorMsg);
2164*5f7ddb14SDimitry Andric Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, Diags);
2165*5f7ddb14SDimitry Andric }
2166*5f7ddb14SDimitry Andric if (!PrintDiag) {
2167*5f7ddb14SDimitry Andric assert(!HasError && "expected to report more diagnostics for error");
2168*5f7ddb14SDimitry Andric return ErrorReported::reportedOrSuccess(HasError);
2169*5f7ddb14SDimitry Andric }
2170af732203SDimitry Andric
2171*5f7ddb14SDimitry Andric // Print "not found" diagnostic, except that's implied if we already printed a
2172*5f7ddb14SDimitry Andric // pattern error.
2173*5f7ddb14SDimitry Andric if (!HasPatternError) {
2174af732203SDimitry Andric std::string Message = formatv("{0}: {1} string not found in input",
2175af732203SDimitry Andric Pat.getCheckTy().getDescription(Prefix),
2176af732203SDimitry Andric (ExpectedMatch ? "expected" : "excluded"))
2177af732203SDimitry Andric .str();
2178af732203SDimitry Andric if (Pat.getCount() > 1)
2179*5f7ddb14SDimitry Andric Message +=
2180*5f7ddb14SDimitry Andric formatv(" ({0} out of {1})", MatchedCount, Pat.getCount()).str();
2181*5f7ddb14SDimitry Andric SM.PrintMessage(Loc,
2182*5f7ddb14SDimitry Andric ExpectedMatch ? SourceMgr::DK_Error : SourceMgr::DK_Remark,
2183*5f7ddb14SDimitry Andric Message);
2184*5f7ddb14SDimitry Andric SM.PrintMessage(SearchRange.Start, SourceMgr::DK_Note,
2185*5f7ddb14SDimitry Andric "scanning from here");
2186af732203SDimitry Andric }
2187af732203SDimitry Andric
2188*5f7ddb14SDimitry Andric // Print additional information, which can be useful even after a pattern
2189*5f7ddb14SDimitry Andric // error.
2190*5f7ddb14SDimitry Andric Pat.printSubstitutions(SM, Buffer, SearchRange, MatchTy, nullptr);
2191*5f7ddb14SDimitry Andric if (ExpectedMatch)
2192*5f7ddb14SDimitry Andric Pat.printFuzzyMatch(SM, Buffer, Diags);
2193*5f7ddb14SDimitry Andric return ErrorReported::reportedOrSuccess(HasError);
2194*5f7ddb14SDimitry Andric }
2195*5f7ddb14SDimitry Andric
2196*5f7ddb14SDimitry Andric /// Returns either (1) \c ErrorSuccess if there was no error, or (2)
2197*5f7ddb14SDimitry Andric /// \c ErrorReported if an error was reported.
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)2198*5f7ddb14SDimitry Andric static Error reportMatchResult(bool ExpectedMatch, const SourceMgr &SM,
2199*5f7ddb14SDimitry Andric StringRef Prefix, SMLoc Loc, const Pattern &Pat,
2200*5f7ddb14SDimitry Andric int MatchedCount, StringRef Buffer,
2201*5f7ddb14SDimitry Andric Pattern::MatchResult MatchResult,
2202*5f7ddb14SDimitry Andric const FileCheckRequest &Req,
2203*5f7ddb14SDimitry Andric std::vector<FileCheckDiag> *Diags) {
2204*5f7ddb14SDimitry Andric if (MatchResult.TheMatch)
2205*5f7ddb14SDimitry Andric return printMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer,
2206*5f7ddb14SDimitry Andric std::move(MatchResult), Req, Diags);
2207*5f7ddb14SDimitry Andric return printNoMatch(ExpectedMatch, SM, Prefix, Loc, Pat, MatchedCount, Buffer,
2208*5f7ddb14SDimitry Andric std::move(MatchResult.TheError), Req.VerboseVerbose,
2209*5f7ddb14SDimitry Andric Diags);
2210af732203SDimitry Andric }
2211af732203SDimitry Andric
2212af732203SDimitry Andric /// Counts the number of newlines in the specified range.
CountNumNewlinesBetween(StringRef Range,const char * & FirstNewLine)2213af732203SDimitry Andric static unsigned CountNumNewlinesBetween(StringRef Range,
2214af732203SDimitry Andric const char *&FirstNewLine) {
2215af732203SDimitry Andric unsigned NumNewLines = 0;
2216af732203SDimitry Andric while (1) {
2217af732203SDimitry Andric // Scan for newline.
2218af732203SDimitry Andric Range = Range.substr(Range.find_first_of("\n\r"));
2219af732203SDimitry Andric if (Range.empty())
2220af732203SDimitry Andric return NumNewLines;
2221af732203SDimitry Andric
2222af732203SDimitry Andric ++NumNewLines;
2223af732203SDimitry Andric
2224af732203SDimitry Andric // Handle \n\r and \r\n as a single newline.
2225af732203SDimitry Andric if (Range.size() > 1 && (Range[1] == '\n' || Range[1] == '\r') &&
2226af732203SDimitry Andric (Range[0] != Range[1]))
2227af732203SDimitry Andric Range = Range.substr(1);
2228af732203SDimitry Andric Range = Range.substr(1);
2229af732203SDimitry Andric
2230af732203SDimitry Andric if (NumNewLines == 1)
2231af732203SDimitry Andric FirstNewLine = Range.begin();
2232af732203SDimitry Andric }
2233af732203SDimitry Andric }
2234af732203SDimitry Andric
Check(const SourceMgr & SM,StringRef Buffer,bool IsLabelScanMode,size_t & MatchLen,FileCheckRequest & Req,std::vector<FileCheckDiag> * Diags) const2235af732203SDimitry Andric size_t FileCheckString::Check(const SourceMgr &SM, StringRef Buffer,
2236af732203SDimitry Andric bool IsLabelScanMode, size_t &MatchLen,
2237af732203SDimitry Andric FileCheckRequest &Req,
2238af732203SDimitry Andric std::vector<FileCheckDiag> *Diags) const {
2239af732203SDimitry Andric size_t LastPos = 0;
2240af732203SDimitry Andric std::vector<const Pattern *> NotStrings;
2241af732203SDimitry Andric
2242af732203SDimitry Andric // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL
2243af732203SDimitry Andric // bounds; we have not processed variable definitions within the bounded block
2244af732203SDimitry Andric // yet so cannot handle any final CHECK-DAG yet; this is handled when going
2245af732203SDimitry Andric // over the block again (including the last CHECK-LABEL) in normal mode.
2246af732203SDimitry Andric if (!IsLabelScanMode) {
2247af732203SDimitry Andric // Match "dag strings" (with mixed "not strings" if any).
2248af732203SDimitry Andric LastPos = CheckDag(SM, Buffer, NotStrings, Req, Diags);
2249af732203SDimitry Andric if (LastPos == StringRef::npos)
2250af732203SDimitry Andric return StringRef::npos;
2251af732203SDimitry Andric }
2252af732203SDimitry Andric
2253af732203SDimitry Andric // Match itself from the last position after matching CHECK-DAG.
2254af732203SDimitry Andric size_t LastMatchEnd = LastPos;
2255af732203SDimitry Andric size_t FirstMatchPos = 0;
2256af732203SDimitry Andric // Go match the pattern Count times. Majority of patterns only match with
2257af732203SDimitry Andric // count 1 though.
2258af732203SDimitry Andric assert(Pat.getCount() != 0 && "pattern count can not be zero");
2259af732203SDimitry Andric for (int i = 1; i <= Pat.getCount(); i++) {
2260af732203SDimitry Andric StringRef MatchBuffer = Buffer.substr(LastMatchEnd);
2261af732203SDimitry Andric // get a match at current start point
2262*5f7ddb14SDimitry Andric Pattern::MatchResult MatchResult = Pat.match(MatchBuffer, SM);
2263af732203SDimitry Andric
2264af732203SDimitry Andric // report
2265*5f7ddb14SDimitry Andric if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix, Loc,
2266*5f7ddb14SDimitry Andric Pat, i, MatchBuffer,
2267*5f7ddb14SDimitry Andric std::move(MatchResult), Req, Diags)) {
2268*5f7ddb14SDimitry Andric cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {}));
2269af732203SDimitry Andric return StringRef::npos;
2270af732203SDimitry Andric }
2271*5f7ddb14SDimitry Andric
2272*5f7ddb14SDimitry Andric size_t MatchPos = MatchResult.TheMatch->Pos;
2273af732203SDimitry Andric if (i == 1)
2274af732203SDimitry Andric FirstMatchPos = LastPos + MatchPos;
2275af732203SDimitry Andric
2276af732203SDimitry Andric // move start point after the match
2277*5f7ddb14SDimitry Andric LastMatchEnd += MatchPos + MatchResult.TheMatch->Len;
2278af732203SDimitry Andric }
2279af732203SDimitry Andric // Full match len counts from first match pos.
2280af732203SDimitry Andric MatchLen = LastMatchEnd - FirstMatchPos;
2281af732203SDimitry Andric
2282af732203SDimitry Andric // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT
2283af732203SDimitry Andric // or CHECK-NOT
2284af732203SDimitry Andric if (!IsLabelScanMode) {
2285af732203SDimitry Andric size_t MatchPos = FirstMatchPos - LastPos;
2286af732203SDimitry Andric StringRef MatchBuffer = Buffer.substr(LastPos);
2287af732203SDimitry Andric StringRef SkippedRegion = Buffer.substr(LastPos, MatchPos);
2288af732203SDimitry Andric
2289af732203SDimitry Andric // If this check is a "CHECK-NEXT", verify that the previous match was on
2290af732203SDimitry Andric // the previous line (i.e. that there is one newline between them).
2291af732203SDimitry Andric if (CheckNext(SM, SkippedRegion)) {
2292af732203SDimitry Andric ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,
2293af732203SDimitry Andric Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
2294af732203SDimitry Andric Diags, Req.Verbose);
2295af732203SDimitry Andric return StringRef::npos;
2296af732203SDimitry Andric }
2297af732203SDimitry Andric
2298af732203SDimitry Andric // If this check is a "CHECK-SAME", verify that the previous match was on
2299af732203SDimitry Andric // the same line (i.e. that there is no newline between them).
2300af732203SDimitry Andric if (CheckSame(SM, SkippedRegion)) {
2301af732203SDimitry Andric ProcessMatchResult(FileCheckDiag::MatchFoundButWrongLine, SM, Loc,
2302af732203SDimitry Andric Pat.getCheckTy(), MatchBuffer, MatchPos, MatchLen,
2303af732203SDimitry Andric Diags, Req.Verbose);
2304af732203SDimitry Andric return StringRef::npos;
2305af732203SDimitry Andric }
2306af732203SDimitry Andric
2307af732203SDimitry Andric // If this match had "not strings", verify that they don't exist in the
2308af732203SDimitry Andric // skipped region.
2309af732203SDimitry Andric if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
2310af732203SDimitry Andric return StringRef::npos;
2311af732203SDimitry Andric }
2312af732203SDimitry Andric
2313af732203SDimitry Andric return FirstMatchPos;
2314af732203SDimitry Andric }
2315af732203SDimitry Andric
CheckNext(const SourceMgr & SM,StringRef Buffer) const2316af732203SDimitry Andric bool FileCheckString::CheckNext(const SourceMgr &SM, StringRef Buffer) const {
2317af732203SDimitry Andric if (Pat.getCheckTy() != Check::CheckNext &&
2318af732203SDimitry Andric Pat.getCheckTy() != Check::CheckEmpty)
2319af732203SDimitry Andric return false;
2320af732203SDimitry Andric
2321af732203SDimitry Andric Twine CheckName =
2322af732203SDimitry Andric Prefix +
2323af732203SDimitry Andric Twine(Pat.getCheckTy() == Check::CheckEmpty ? "-EMPTY" : "-NEXT");
2324af732203SDimitry Andric
2325af732203SDimitry Andric // Count the number of newlines between the previous match and this one.
2326af732203SDimitry Andric const char *FirstNewLine = nullptr;
2327af732203SDimitry Andric unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
2328af732203SDimitry Andric
2329af732203SDimitry Andric if (NumNewLines == 0) {
2330af732203SDimitry Andric SM.PrintMessage(Loc, SourceMgr::DK_Error,
2331af732203SDimitry Andric CheckName + ": is on the same line as previous match");
2332af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
2333af732203SDimitry Andric "'next' match was here");
2334af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
2335af732203SDimitry Andric "previous match ended here");
2336af732203SDimitry Andric return true;
2337af732203SDimitry Andric }
2338af732203SDimitry Andric
2339af732203SDimitry Andric if (NumNewLines != 1) {
2340af732203SDimitry Andric SM.PrintMessage(Loc, SourceMgr::DK_Error,
2341af732203SDimitry Andric CheckName +
2342af732203SDimitry Andric ": is not on the line after the previous match");
2343af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
2344af732203SDimitry Andric "'next' match was here");
2345af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
2346af732203SDimitry Andric "previous match ended here");
2347af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(FirstNewLine), SourceMgr::DK_Note,
2348af732203SDimitry Andric "non-matching line after previous match is here");
2349af732203SDimitry Andric return true;
2350af732203SDimitry Andric }
2351af732203SDimitry Andric
2352af732203SDimitry Andric return false;
2353af732203SDimitry Andric }
2354af732203SDimitry Andric
CheckSame(const SourceMgr & SM,StringRef Buffer) const2355af732203SDimitry Andric bool FileCheckString::CheckSame(const SourceMgr &SM, StringRef Buffer) const {
2356af732203SDimitry Andric if (Pat.getCheckTy() != Check::CheckSame)
2357af732203SDimitry Andric return false;
2358af732203SDimitry Andric
2359af732203SDimitry Andric // Count the number of newlines between the previous match and this one.
2360af732203SDimitry Andric const char *FirstNewLine = nullptr;
2361af732203SDimitry Andric unsigned NumNewLines = CountNumNewlinesBetween(Buffer, FirstNewLine);
2362af732203SDimitry Andric
2363af732203SDimitry Andric if (NumNewLines != 0) {
2364af732203SDimitry Andric SM.PrintMessage(Loc, SourceMgr::DK_Error,
2365af732203SDimitry Andric Prefix +
2366af732203SDimitry Andric "-SAME: is not on the same line as the previous match");
2367af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.end()), SourceMgr::DK_Note,
2368af732203SDimitry Andric "'next' match was here");
2369af732203SDimitry Andric SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note,
2370af732203SDimitry Andric "previous match ended here");
2371af732203SDimitry Andric return true;
2372af732203SDimitry Andric }
2373af732203SDimitry Andric
2374af732203SDimitry Andric return false;
2375af732203SDimitry Andric }
2376af732203SDimitry Andric
CheckNot(const SourceMgr & SM,StringRef Buffer,const std::vector<const Pattern * > & NotStrings,const FileCheckRequest & Req,std::vector<FileCheckDiag> * Diags) const2377af732203SDimitry Andric bool FileCheckString::CheckNot(const SourceMgr &SM, StringRef Buffer,
2378af732203SDimitry Andric const std::vector<const Pattern *> &NotStrings,
2379af732203SDimitry Andric const FileCheckRequest &Req,
2380af732203SDimitry Andric std::vector<FileCheckDiag> *Diags) const {
2381af732203SDimitry Andric bool DirectiveFail = false;
2382af732203SDimitry Andric for (const Pattern *Pat : NotStrings) {
2383af732203SDimitry Andric assert((Pat->getCheckTy() == Check::CheckNot) && "Expect CHECK-NOT!");
2384*5f7ddb14SDimitry Andric Pattern::MatchResult MatchResult = Pat->match(Buffer, SM);
2385*5f7ddb14SDimitry Andric if (Error Err = reportMatchResult(/*ExpectedMatch=*/false, SM, Prefix,
2386*5f7ddb14SDimitry Andric Pat->getLoc(), *Pat, 1, Buffer,
2387*5f7ddb14SDimitry Andric std::move(MatchResult), Req, Diags)) {
2388*5f7ddb14SDimitry Andric cantFail(handleErrors(std::move(Err), [&](const ErrorReported &E) {}));
2389*5f7ddb14SDimitry Andric DirectiveFail = true;
2390af732203SDimitry Andric continue;
2391af732203SDimitry Andric }
2392af732203SDimitry Andric }
2393af732203SDimitry Andric return DirectiveFail;
2394af732203SDimitry Andric }
2395af732203SDimitry Andric
CheckDag(const SourceMgr & SM,StringRef Buffer,std::vector<const Pattern * > & NotStrings,const FileCheckRequest & Req,std::vector<FileCheckDiag> * Diags) const2396af732203SDimitry Andric size_t FileCheckString::CheckDag(const SourceMgr &SM, StringRef Buffer,
2397af732203SDimitry Andric std::vector<const Pattern *> &NotStrings,
2398af732203SDimitry Andric const FileCheckRequest &Req,
2399af732203SDimitry Andric std::vector<FileCheckDiag> *Diags) const {
2400af732203SDimitry Andric if (DagNotStrings.empty())
2401af732203SDimitry Andric return 0;
2402af732203SDimitry Andric
2403af732203SDimitry Andric // The start of the search range.
2404af732203SDimitry Andric size_t StartPos = 0;
2405af732203SDimitry Andric
2406af732203SDimitry Andric struct MatchRange {
2407af732203SDimitry Andric size_t Pos;
2408af732203SDimitry Andric size_t End;
2409af732203SDimitry Andric };
2410af732203SDimitry Andric // A sorted list of ranges for non-overlapping CHECK-DAG matches. Match
2411af732203SDimitry Andric // ranges are erased from this list once they are no longer in the search
2412af732203SDimitry Andric // range.
2413af732203SDimitry Andric std::list<MatchRange> MatchRanges;
2414af732203SDimitry Andric
2415af732203SDimitry Andric // We need PatItr and PatEnd later for detecting the end of a CHECK-DAG
2416af732203SDimitry Andric // group, so we don't use a range-based for loop here.
2417af732203SDimitry Andric for (auto PatItr = DagNotStrings.begin(), PatEnd = DagNotStrings.end();
2418af732203SDimitry Andric PatItr != PatEnd; ++PatItr) {
2419af732203SDimitry Andric const Pattern &Pat = *PatItr;
2420af732203SDimitry Andric assert((Pat.getCheckTy() == Check::CheckDAG ||
2421af732203SDimitry Andric Pat.getCheckTy() == Check::CheckNot) &&
2422af732203SDimitry Andric "Invalid CHECK-DAG or CHECK-NOT!");
2423af732203SDimitry Andric
2424af732203SDimitry Andric if (Pat.getCheckTy() == Check::CheckNot) {
2425af732203SDimitry Andric NotStrings.push_back(&Pat);
2426af732203SDimitry Andric continue;
2427af732203SDimitry Andric }
2428af732203SDimitry Andric
2429af732203SDimitry Andric assert((Pat.getCheckTy() == Check::CheckDAG) && "Expect CHECK-DAG!");
2430af732203SDimitry Andric
2431af732203SDimitry Andric // CHECK-DAG always matches from the start.
2432af732203SDimitry Andric size_t MatchLen = 0, MatchPos = StartPos;
2433af732203SDimitry Andric
2434af732203SDimitry Andric // Search for a match that doesn't overlap a previous match in this
2435af732203SDimitry Andric // CHECK-DAG group.
2436af732203SDimitry Andric for (auto MI = MatchRanges.begin(), ME = MatchRanges.end(); true; ++MI) {
2437af732203SDimitry Andric StringRef MatchBuffer = Buffer.substr(MatchPos);
2438*5f7ddb14SDimitry Andric Pattern::MatchResult MatchResult = Pat.match(MatchBuffer, SM);
2439af732203SDimitry Andric // With a group of CHECK-DAGs, a single mismatching means the match on
2440af732203SDimitry Andric // that group of CHECK-DAGs fails immediately.
2441*5f7ddb14SDimitry Andric if (MatchResult.TheError || Req.VerboseVerbose) {
2442*5f7ddb14SDimitry Andric if (Error Err = reportMatchResult(/*ExpectedMatch=*/true, SM, Prefix,
2443*5f7ddb14SDimitry Andric Pat.getLoc(), Pat, 1, MatchBuffer,
2444*5f7ddb14SDimitry Andric std::move(MatchResult), Req, Diags)) {
2445*5f7ddb14SDimitry Andric cantFail(
2446*5f7ddb14SDimitry Andric handleErrors(std::move(Err), [&](const ErrorReported &E) {}));
2447af732203SDimitry Andric return StringRef::npos;
2448af732203SDimitry Andric }
2449*5f7ddb14SDimitry Andric }
2450*5f7ddb14SDimitry Andric MatchLen = MatchResult.TheMatch->Len;
2451*5f7ddb14SDimitry Andric // Re-calc it as the offset relative to the start of the original
2452*5f7ddb14SDimitry Andric // string.
2453*5f7ddb14SDimitry Andric MatchPos += MatchResult.TheMatch->Pos;
2454af732203SDimitry Andric MatchRange M{MatchPos, MatchPos + MatchLen};
2455af732203SDimitry Andric if (Req.AllowDeprecatedDagOverlap) {
2456af732203SDimitry Andric // We don't need to track all matches in this mode, so we just maintain
2457af732203SDimitry Andric // one match range that encompasses the current CHECK-DAG group's
2458af732203SDimitry Andric // matches.
2459af732203SDimitry Andric if (MatchRanges.empty())
2460af732203SDimitry Andric MatchRanges.insert(MatchRanges.end(), M);
2461af732203SDimitry Andric else {
2462af732203SDimitry Andric auto Block = MatchRanges.begin();
2463af732203SDimitry Andric Block->Pos = std::min(Block->Pos, M.Pos);
2464af732203SDimitry Andric Block->End = std::max(Block->End, M.End);
2465af732203SDimitry Andric }
2466af732203SDimitry Andric break;
2467af732203SDimitry Andric }
2468af732203SDimitry Andric // Iterate previous matches until overlapping match or insertion point.
2469af732203SDimitry Andric bool Overlap = false;
2470af732203SDimitry Andric for (; MI != ME; ++MI) {
2471af732203SDimitry Andric if (M.Pos < MI->End) {
2472af732203SDimitry Andric // !Overlap => New match has no overlap and is before this old match.
2473af732203SDimitry Andric // Overlap => New match overlaps this old match.
2474af732203SDimitry Andric Overlap = MI->Pos < M.End;
2475af732203SDimitry Andric break;
2476af732203SDimitry Andric }
2477af732203SDimitry Andric }
2478af732203SDimitry Andric if (!Overlap) {
2479af732203SDimitry Andric // Insert non-overlapping match into list.
2480af732203SDimitry Andric MatchRanges.insert(MI, M);
2481af732203SDimitry Andric break;
2482af732203SDimitry Andric }
2483af732203SDimitry Andric if (Req.VerboseVerbose) {
2484af732203SDimitry Andric // Due to their verbosity, we don't print verbose diagnostics here if
2485af732203SDimitry Andric // we're gathering them for a different rendering, but we always print
2486af732203SDimitry Andric // other diagnostics.
2487af732203SDimitry Andric if (!Diags) {
2488af732203SDimitry Andric SMLoc OldStart = SMLoc::getFromPointer(Buffer.data() + MI->Pos);
2489af732203SDimitry Andric SMLoc OldEnd = SMLoc::getFromPointer(Buffer.data() + MI->End);
2490af732203SDimitry Andric SMRange OldRange(OldStart, OldEnd);
2491af732203SDimitry Andric SM.PrintMessage(OldStart, SourceMgr::DK_Note,
2492af732203SDimitry Andric "match discarded, overlaps earlier DAG match here",
2493af732203SDimitry Andric {OldRange});
2494af732203SDimitry Andric } else {
2495af732203SDimitry Andric SMLoc CheckLoc = Diags->rbegin()->CheckLoc;
2496af732203SDimitry Andric for (auto I = Diags->rbegin(), E = Diags->rend();
2497af732203SDimitry Andric I != E && I->CheckLoc == CheckLoc; ++I)
2498af732203SDimitry Andric I->MatchTy = FileCheckDiag::MatchFoundButDiscarded;
2499af732203SDimitry Andric }
2500af732203SDimitry Andric }
2501af732203SDimitry Andric MatchPos = MI->End;
2502af732203SDimitry Andric }
2503af732203SDimitry Andric if (!Req.VerboseVerbose)
2504*5f7ddb14SDimitry Andric cantFail(printMatch(
2505*5f7ddb14SDimitry Andric /*ExpectedMatch=*/true, SM, Prefix, Pat.getLoc(), Pat, 1, Buffer,
2506*5f7ddb14SDimitry Andric Pattern::MatchResult(MatchPos, MatchLen, Error::success()), Req,
2507*5f7ddb14SDimitry Andric Diags));
2508af732203SDimitry Andric
2509af732203SDimitry Andric // Handle the end of a CHECK-DAG group.
2510af732203SDimitry Andric if (std::next(PatItr) == PatEnd ||
2511af732203SDimitry Andric std::next(PatItr)->getCheckTy() == Check::CheckNot) {
2512af732203SDimitry Andric if (!NotStrings.empty()) {
2513af732203SDimitry Andric // If there are CHECK-NOTs between two CHECK-DAGs or from CHECK to
2514af732203SDimitry Andric // CHECK-DAG, verify that there are no 'not' strings occurred in that
2515af732203SDimitry Andric // region.
2516af732203SDimitry Andric StringRef SkippedRegion =
2517af732203SDimitry Andric Buffer.slice(StartPos, MatchRanges.begin()->Pos);
2518af732203SDimitry Andric if (CheckNot(SM, SkippedRegion, NotStrings, Req, Diags))
2519af732203SDimitry Andric return StringRef::npos;
2520af732203SDimitry Andric // Clear "not strings".
2521af732203SDimitry Andric NotStrings.clear();
2522af732203SDimitry Andric }
2523af732203SDimitry Andric // All subsequent CHECK-DAGs and CHECK-NOTs should be matched from the
2524af732203SDimitry Andric // end of this CHECK-DAG group's match range.
2525af732203SDimitry Andric StartPos = MatchRanges.rbegin()->End;
2526af732203SDimitry Andric // Don't waste time checking for (impossible) overlaps before that.
2527af732203SDimitry Andric MatchRanges.clear();
2528af732203SDimitry Andric }
2529af732203SDimitry Andric }
2530af732203SDimitry Andric
2531af732203SDimitry Andric return StartPos;
2532af732203SDimitry Andric }
2533af732203SDimitry Andric
ValidatePrefixes(StringRef Kind,StringSet<> & UniquePrefixes,ArrayRef<StringRef> SuppliedPrefixes)2534af732203SDimitry Andric static bool ValidatePrefixes(StringRef Kind, StringSet<> &UniquePrefixes,
2535af732203SDimitry Andric ArrayRef<StringRef> SuppliedPrefixes) {
2536af732203SDimitry Andric for (StringRef Prefix : SuppliedPrefixes) {
2537af732203SDimitry Andric if (Prefix.empty()) {
2538af732203SDimitry Andric errs() << "error: supplied " << Kind << " prefix must not be the empty "
2539af732203SDimitry Andric << "string\n";
2540af732203SDimitry Andric return false;
2541af732203SDimitry Andric }
2542af732203SDimitry Andric static const Regex Validator("^[a-zA-Z0-9_-]*$");
2543af732203SDimitry Andric if (!Validator.match(Prefix)) {
2544af732203SDimitry Andric errs() << "error: supplied " << Kind << " prefix must start with a "
2545af732203SDimitry Andric << "letter and contain only alphanumeric characters, hyphens, and "
2546af732203SDimitry Andric << "underscores: '" << Prefix << "'\n";
2547af732203SDimitry Andric return false;
2548af732203SDimitry Andric }
2549af732203SDimitry Andric if (!UniquePrefixes.insert(Prefix).second) {
2550af732203SDimitry Andric errs() << "error: supplied " << Kind << " prefix must be unique among "
2551af732203SDimitry Andric << "check and comment prefixes: '" << Prefix << "'\n";
2552af732203SDimitry Andric return false;
2553af732203SDimitry Andric }
2554af732203SDimitry Andric }
2555af732203SDimitry Andric return true;
2556af732203SDimitry Andric }
2557af732203SDimitry Andric
2558af732203SDimitry Andric static const char *DefaultCheckPrefixes[] = {"CHECK"};
2559af732203SDimitry Andric static const char *DefaultCommentPrefixes[] = {"COM", "RUN"};
2560af732203SDimitry Andric
ValidateCheckPrefixes()2561af732203SDimitry Andric bool FileCheck::ValidateCheckPrefixes() {
2562af732203SDimitry Andric StringSet<> UniquePrefixes;
2563af732203SDimitry Andric // Add default prefixes to catch user-supplied duplicates of them below.
2564af732203SDimitry Andric if (Req.CheckPrefixes.empty()) {
2565af732203SDimitry Andric for (const char *Prefix : DefaultCheckPrefixes)
2566af732203SDimitry Andric UniquePrefixes.insert(Prefix);
2567af732203SDimitry Andric }
2568af732203SDimitry Andric if (Req.CommentPrefixes.empty()) {
2569af732203SDimitry Andric for (const char *Prefix : DefaultCommentPrefixes)
2570af732203SDimitry Andric UniquePrefixes.insert(Prefix);
2571af732203SDimitry Andric }
2572af732203SDimitry Andric // Do not validate the default prefixes, or diagnostics about duplicates might
2573af732203SDimitry Andric // incorrectly indicate that they were supplied by the user.
2574af732203SDimitry Andric if (!ValidatePrefixes("check", UniquePrefixes, Req.CheckPrefixes))
2575af732203SDimitry Andric return false;
2576af732203SDimitry Andric if (!ValidatePrefixes("comment", UniquePrefixes, Req.CommentPrefixes))
2577af732203SDimitry Andric return false;
2578af732203SDimitry Andric return true;
2579af732203SDimitry Andric }
2580af732203SDimitry Andric
buildCheckPrefixRegex()2581af732203SDimitry Andric Regex FileCheck::buildCheckPrefixRegex() {
2582af732203SDimitry Andric if (Req.CheckPrefixes.empty()) {
2583af732203SDimitry Andric for (const char *Prefix : DefaultCheckPrefixes)
2584af732203SDimitry Andric Req.CheckPrefixes.push_back(Prefix);
2585af732203SDimitry Andric Req.IsDefaultCheckPrefix = true;
2586af732203SDimitry Andric }
2587af732203SDimitry Andric if (Req.CommentPrefixes.empty()) {
2588af732203SDimitry Andric for (const char *Prefix : DefaultCommentPrefixes)
2589af732203SDimitry Andric Req.CommentPrefixes.push_back(Prefix);
2590af732203SDimitry Andric }
2591af732203SDimitry Andric
2592af732203SDimitry Andric // We already validated the contents of CheckPrefixes and CommentPrefixes so
2593af732203SDimitry Andric // just concatenate them as alternatives.
2594af732203SDimitry Andric SmallString<32> PrefixRegexStr;
2595af732203SDimitry Andric for (size_t I = 0, E = Req.CheckPrefixes.size(); I != E; ++I) {
2596af732203SDimitry Andric if (I != 0)
2597af732203SDimitry Andric PrefixRegexStr.push_back('|');
2598af732203SDimitry Andric PrefixRegexStr.append(Req.CheckPrefixes[I]);
2599af732203SDimitry Andric }
2600af732203SDimitry Andric for (StringRef Prefix : Req.CommentPrefixes) {
2601af732203SDimitry Andric PrefixRegexStr.push_back('|');
2602af732203SDimitry Andric PrefixRegexStr.append(Prefix);
2603af732203SDimitry Andric }
2604af732203SDimitry Andric
2605af732203SDimitry Andric return Regex(PrefixRegexStr);
2606af732203SDimitry Andric }
2607af732203SDimitry Andric
defineCmdlineVariables(ArrayRef<StringRef> CmdlineDefines,SourceMgr & SM)2608af732203SDimitry Andric Error FileCheckPatternContext::defineCmdlineVariables(
2609af732203SDimitry Andric ArrayRef<StringRef> CmdlineDefines, SourceMgr &SM) {
2610af732203SDimitry Andric assert(GlobalVariableTable.empty() && GlobalNumericVariableTable.empty() &&
2611af732203SDimitry Andric "Overriding defined variable with command-line variable definitions");
2612af732203SDimitry Andric
2613af732203SDimitry Andric if (CmdlineDefines.empty())
2614af732203SDimitry Andric return Error::success();
2615af732203SDimitry Andric
2616af732203SDimitry Andric // Create a string representing the vector of command-line definitions. Each
2617af732203SDimitry Andric // definition is on its own line and prefixed with a definition number to
2618af732203SDimitry Andric // clarify which definition a given diagnostic corresponds to.
2619af732203SDimitry Andric unsigned I = 0;
2620af732203SDimitry Andric Error Errs = Error::success();
2621af732203SDimitry Andric std::string CmdlineDefsDiag;
2622af732203SDimitry Andric SmallVector<std::pair<size_t, size_t>, 4> CmdlineDefsIndices;
2623af732203SDimitry Andric for (StringRef CmdlineDef : CmdlineDefines) {
2624af732203SDimitry Andric std::string DefPrefix = ("Global define #" + Twine(++I) + ": ").str();
2625af732203SDimitry Andric size_t EqIdx = CmdlineDef.find('=');
2626af732203SDimitry Andric if (EqIdx == StringRef::npos) {
2627af732203SDimitry Andric CmdlineDefsIndices.push_back(std::make_pair(CmdlineDefsDiag.size(), 0));
2628af732203SDimitry Andric continue;
2629af732203SDimitry Andric }
2630af732203SDimitry Andric // Numeric variable definition.
2631af732203SDimitry Andric if (CmdlineDef[0] == '#') {
2632af732203SDimitry Andric // Append a copy of the command-line definition adapted to use the same
2633af732203SDimitry Andric // format as in the input file to be able to reuse
2634af732203SDimitry Andric // parseNumericSubstitutionBlock.
2635af732203SDimitry Andric CmdlineDefsDiag += (DefPrefix + CmdlineDef + " (parsed as: [[").str();
2636af732203SDimitry Andric std::string SubstitutionStr = std::string(CmdlineDef);
2637af732203SDimitry Andric SubstitutionStr[EqIdx] = ':';
2638af732203SDimitry Andric CmdlineDefsIndices.push_back(
2639af732203SDimitry Andric std::make_pair(CmdlineDefsDiag.size(), SubstitutionStr.size()));
2640af732203SDimitry Andric CmdlineDefsDiag += (SubstitutionStr + Twine("]])\n")).str();
2641af732203SDimitry Andric } else {
2642af732203SDimitry Andric CmdlineDefsDiag += DefPrefix;
2643af732203SDimitry Andric CmdlineDefsIndices.push_back(
2644af732203SDimitry Andric std::make_pair(CmdlineDefsDiag.size(), CmdlineDef.size()));
2645af732203SDimitry Andric CmdlineDefsDiag += (CmdlineDef + "\n").str();
2646af732203SDimitry Andric }
2647af732203SDimitry Andric }
2648af732203SDimitry Andric
2649af732203SDimitry Andric // Create a buffer with fake command line content in order to display
2650af732203SDimitry Andric // parsing diagnostic with location information and point to the
2651af732203SDimitry Andric // global definition with invalid syntax.
2652af732203SDimitry Andric std::unique_ptr<MemoryBuffer> CmdLineDefsDiagBuffer =
2653af732203SDimitry Andric MemoryBuffer::getMemBufferCopy(CmdlineDefsDiag, "Global defines");
2654af732203SDimitry Andric StringRef CmdlineDefsDiagRef = CmdLineDefsDiagBuffer->getBuffer();
2655af732203SDimitry Andric SM.AddNewSourceBuffer(std::move(CmdLineDefsDiagBuffer), SMLoc());
2656af732203SDimitry Andric
2657af732203SDimitry Andric for (std::pair<size_t, size_t> CmdlineDefIndices : CmdlineDefsIndices) {
2658af732203SDimitry Andric StringRef CmdlineDef = CmdlineDefsDiagRef.substr(CmdlineDefIndices.first,
2659af732203SDimitry Andric CmdlineDefIndices.second);
2660af732203SDimitry Andric if (CmdlineDef.empty()) {
2661af732203SDimitry Andric Errs = joinErrors(
2662af732203SDimitry Andric std::move(Errs),
2663af732203SDimitry Andric ErrorDiagnostic::get(SM, CmdlineDef,
2664af732203SDimitry Andric "missing equal sign in global definition"));
2665af732203SDimitry Andric continue;
2666af732203SDimitry Andric }
2667af732203SDimitry Andric
2668af732203SDimitry Andric // Numeric variable definition.
2669af732203SDimitry Andric if (CmdlineDef[0] == '#') {
2670af732203SDimitry Andric // Now parse the definition both to check that the syntax is correct and
2671af732203SDimitry Andric // to create the necessary class instance.
2672af732203SDimitry Andric StringRef CmdlineDefExpr = CmdlineDef.substr(1);
2673af732203SDimitry Andric Optional<NumericVariable *> DefinedNumericVariable;
2674af732203SDimitry Andric Expected<std::unique_ptr<Expression>> ExpressionResult =
2675af732203SDimitry Andric Pattern::parseNumericSubstitutionBlock(
2676af732203SDimitry Andric CmdlineDefExpr, DefinedNumericVariable, false, None, this, SM);
2677af732203SDimitry Andric if (!ExpressionResult) {
2678af732203SDimitry Andric Errs = joinErrors(std::move(Errs), ExpressionResult.takeError());
2679af732203SDimitry Andric continue;
2680af732203SDimitry Andric }
2681af732203SDimitry Andric std::unique_ptr<Expression> Expression = std::move(*ExpressionResult);
2682af732203SDimitry Andric // Now evaluate the expression whose value this variable should be set
2683af732203SDimitry Andric // to, since the expression of a command-line variable definition should
2684af732203SDimitry Andric // only use variables defined earlier on the command-line. If not, this
2685af732203SDimitry Andric // is an error and we report it.
2686af732203SDimitry Andric Expected<ExpressionValue> Value = Expression->getAST()->eval();
2687af732203SDimitry Andric if (!Value) {
2688af732203SDimitry Andric Errs = joinErrors(std::move(Errs), Value.takeError());
2689af732203SDimitry Andric continue;
2690af732203SDimitry Andric }
2691af732203SDimitry Andric
2692af732203SDimitry Andric assert(DefinedNumericVariable && "No variable defined");
2693af732203SDimitry Andric (*DefinedNumericVariable)->setValue(*Value);
2694af732203SDimitry Andric
2695af732203SDimitry Andric // Record this variable definition.
2696af732203SDimitry Andric GlobalNumericVariableTable[(*DefinedNumericVariable)->getName()] =
2697af732203SDimitry Andric *DefinedNumericVariable;
2698af732203SDimitry Andric } else {
2699af732203SDimitry Andric // String variable definition.
2700af732203SDimitry Andric std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
2701af732203SDimitry Andric StringRef CmdlineName = CmdlineNameVal.first;
2702af732203SDimitry Andric StringRef OrigCmdlineName = CmdlineName;
2703af732203SDimitry Andric Expected<Pattern::VariableProperties> ParseVarResult =
2704af732203SDimitry Andric Pattern::parseVariable(CmdlineName, SM);
2705af732203SDimitry Andric if (!ParseVarResult) {
2706af732203SDimitry Andric Errs = joinErrors(std::move(Errs), ParseVarResult.takeError());
2707af732203SDimitry Andric continue;
2708af732203SDimitry Andric }
2709af732203SDimitry Andric // Check that CmdlineName does not denote a pseudo variable is only
2710af732203SDimitry Andric // composed of the parsed numeric variable. This catches cases like
2711af732203SDimitry Andric // "FOO+2" in a "FOO+2=10" definition.
2712af732203SDimitry Andric if (ParseVarResult->IsPseudo || !CmdlineName.empty()) {
2713af732203SDimitry Andric Errs = joinErrors(std::move(Errs),
2714af732203SDimitry Andric ErrorDiagnostic::get(
2715af732203SDimitry Andric SM, OrigCmdlineName,
2716af732203SDimitry Andric "invalid name in string variable definition '" +
2717af732203SDimitry Andric OrigCmdlineName + "'"));
2718af732203SDimitry Andric continue;
2719af732203SDimitry Andric }
2720af732203SDimitry Andric StringRef Name = ParseVarResult->Name;
2721af732203SDimitry Andric
2722af732203SDimitry Andric // Detect collisions between string and numeric variables when the former
2723af732203SDimitry Andric // is created later than the latter.
2724af732203SDimitry Andric if (GlobalNumericVariableTable.find(Name) !=
2725af732203SDimitry Andric GlobalNumericVariableTable.end()) {
2726af732203SDimitry Andric Errs = joinErrors(std::move(Errs),
2727af732203SDimitry Andric ErrorDiagnostic::get(SM, Name,
2728af732203SDimitry Andric "numeric variable with name '" +
2729af732203SDimitry Andric Name + "' already exists"));
2730af732203SDimitry Andric continue;
2731af732203SDimitry Andric }
2732af732203SDimitry Andric GlobalVariableTable.insert(CmdlineNameVal);
2733af732203SDimitry Andric // Mark the string variable as defined to detect collisions between
2734af732203SDimitry Andric // string and numeric variables in defineCmdlineVariables when the latter
2735af732203SDimitry Andric // is created later than the former. We cannot reuse GlobalVariableTable
2736af732203SDimitry Andric // for this by populating it with an empty string since we would then
2737af732203SDimitry Andric // lose the ability to detect the use of an undefined variable in
2738af732203SDimitry Andric // match().
2739af732203SDimitry Andric DefinedVariableTable[Name] = true;
2740af732203SDimitry Andric }
2741af732203SDimitry Andric }
2742af732203SDimitry Andric
2743af732203SDimitry Andric return Errs;
2744af732203SDimitry Andric }
2745af732203SDimitry Andric
clearLocalVars()2746af732203SDimitry Andric void FileCheckPatternContext::clearLocalVars() {
2747af732203SDimitry Andric SmallVector<StringRef, 16> LocalPatternVars, LocalNumericVars;
2748af732203SDimitry Andric for (const StringMapEntry<StringRef> &Var : GlobalVariableTable)
2749af732203SDimitry Andric if (Var.first()[0] != '$')
2750af732203SDimitry Andric LocalPatternVars.push_back(Var.first());
2751af732203SDimitry Andric
2752af732203SDimitry Andric // Numeric substitution reads the value of a variable directly, not via
2753af732203SDimitry Andric // GlobalNumericVariableTable. Therefore, we clear local variables by
2754af732203SDimitry Andric // clearing their value which will lead to a numeric substitution failure. We
2755af732203SDimitry Andric // also mark the variable for removal from GlobalNumericVariableTable since
2756af732203SDimitry Andric // this is what defineCmdlineVariables checks to decide that no global
2757af732203SDimitry Andric // variable has been defined.
2758af732203SDimitry Andric for (const auto &Var : GlobalNumericVariableTable)
2759af732203SDimitry Andric if (Var.first()[0] != '$') {
2760af732203SDimitry Andric Var.getValue()->clearValue();
2761af732203SDimitry Andric LocalNumericVars.push_back(Var.first());
2762af732203SDimitry Andric }
2763af732203SDimitry Andric
2764af732203SDimitry Andric for (const auto &Var : LocalPatternVars)
2765af732203SDimitry Andric GlobalVariableTable.erase(Var);
2766af732203SDimitry Andric for (const auto &Var : LocalNumericVars)
2767af732203SDimitry Andric GlobalNumericVariableTable.erase(Var);
2768af732203SDimitry Andric }
2769af732203SDimitry Andric
checkInput(SourceMgr & SM,StringRef Buffer,std::vector<FileCheckDiag> * Diags)2770af732203SDimitry Andric bool FileCheck::checkInput(SourceMgr &SM, StringRef Buffer,
2771af732203SDimitry Andric std::vector<FileCheckDiag> *Diags) {
2772af732203SDimitry Andric bool ChecksFailed = false;
2773af732203SDimitry Andric
2774af732203SDimitry Andric unsigned i = 0, j = 0, e = CheckStrings->size();
2775af732203SDimitry Andric while (true) {
2776af732203SDimitry Andric StringRef CheckRegion;
2777af732203SDimitry Andric if (j == e) {
2778af732203SDimitry Andric CheckRegion = Buffer;
2779af732203SDimitry Andric } else {
2780af732203SDimitry Andric const FileCheckString &CheckLabelStr = (*CheckStrings)[j];
2781af732203SDimitry Andric if (CheckLabelStr.Pat.getCheckTy() != Check::CheckLabel) {
2782af732203SDimitry Andric ++j;
2783af732203SDimitry Andric continue;
2784af732203SDimitry Andric }
2785af732203SDimitry Andric
2786af732203SDimitry Andric // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG
2787af732203SDimitry Andric size_t MatchLabelLen = 0;
2788af732203SDimitry Andric size_t MatchLabelPos =
2789af732203SDimitry Andric CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, Req, Diags);
2790af732203SDimitry Andric if (MatchLabelPos == StringRef::npos)
2791af732203SDimitry Andric // Immediately bail if CHECK-LABEL fails, nothing else we can do.
2792af732203SDimitry Andric return false;
2793af732203SDimitry Andric
2794af732203SDimitry Andric CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen);
2795af732203SDimitry Andric Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen);
2796af732203SDimitry Andric ++j;
2797af732203SDimitry Andric }
2798af732203SDimitry Andric
2799af732203SDimitry Andric // Do not clear the first region as it's the one before the first
2800af732203SDimitry Andric // CHECK-LABEL and it would clear variables defined on the command-line
2801af732203SDimitry Andric // before they get used.
2802af732203SDimitry Andric if (i != 0 && Req.EnableVarScope)
2803af732203SDimitry Andric PatternContext->clearLocalVars();
2804af732203SDimitry Andric
2805af732203SDimitry Andric for (; i != j; ++i) {
2806af732203SDimitry Andric const FileCheckString &CheckStr = (*CheckStrings)[i];
2807af732203SDimitry Andric
2808af732203SDimitry Andric // Check each string within the scanned region, including a second check
2809af732203SDimitry Andric // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG)
2810af732203SDimitry Andric size_t MatchLen = 0;
2811af732203SDimitry Andric size_t MatchPos =
2812af732203SDimitry Andric CheckStr.Check(SM, CheckRegion, false, MatchLen, Req, Diags);
2813af732203SDimitry Andric
2814af732203SDimitry Andric if (MatchPos == StringRef::npos) {
2815af732203SDimitry Andric ChecksFailed = true;
2816af732203SDimitry Andric i = j;
2817af732203SDimitry Andric break;
2818af732203SDimitry Andric }
2819af732203SDimitry Andric
2820af732203SDimitry Andric CheckRegion = CheckRegion.substr(MatchPos + MatchLen);
2821af732203SDimitry Andric }
2822af732203SDimitry Andric
2823af732203SDimitry Andric if (j == e)
2824af732203SDimitry Andric break;
2825af732203SDimitry Andric }
2826af732203SDimitry Andric
2827af732203SDimitry Andric // Success if no checks failed.
2828af732203SDimitry Andric return !ChecksFailed;
2829af732203SDimitry Andric }
2830