/// \brief Takes a list of diagnostics that were expected to have been generated /// but were not and produces a diagnostic to the user from this. static unsigned PrintExpected(DiagnosticsEngine &Diags, const llvm::SourceMgr &SourceMgr, DirectiveList &DL, DiagnosticsEngine::Level Kind) { if (DL.empty()) return 0; for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { Directive &D = **I; Diags.ReportError(D.DirectiveLoc,llvm::Twine("Inconsistend verify directive: ")+D.Text); } return DL.size(); }
void DiagnoseFailures(DirectiveList & DL, DirectiveMap & DM) { for(typename DirectiveList::const_iterator I = DL.begin(), E = DL.end(); I != E; ++I) { Underlying & Dir = **I; unsigned int Line = getCompilerInstance().getSourceManager().getExpansionLineNumber(Dir.getLocation()); std::pair<typename DirectiveMap::iterator, typename DirectiveMap::iterator> rng = DM.equal_range(Line); switch (std::distance(rng.first, rng.second)) { case 0: Diags.Report(Dir.getLocation(), ErrVerifyDiagNoCorrespondingDecl); break; default: // Delay evaluation of diagnostics until we are certain that // none of the statements on this line match llvm::SmallVector<MaybeDiagnostic, 4> diags; bool isGood = false; // TODO: If something is unexpected, then it should not appear in any of the subexpressions. for(typename DirectiveMap::iterator it = rng.first, end = rng.second; it != end; ++it) { MaybeDiagnostic MD = Dir.Match(it->second.second,Diags); // unexpected-<foo> must never fail if(Dir.isNegate()) { if(MD.isDiagnostic()) { diags.push_back(MD); isGood = false; break; } } else { if(MD.isDiagnostic()) diags.push_back(MD); else isGood = true; } } if(!isGood) { for(std::size_t ii = 0; ii < diags.size(); ++ii) diags[ii].maybeReport(); } break; } } }
/// CheckLists - Compare expected to seen diagnostic lists and return the /// the difference between them. /// static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const char *Label, DirectiveList &Left, const_diag_iterator d2_begin, const_diag_iterator d2_end) { DirectiveList LeftOnly; DiagList Right(d2_begin, d2_end); for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) { Directive& D = **I; unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc); for (unsigned i = 0; i < D.Max; ++i) { DiagList::iterator II, IE; for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first); if (LineNo1 != LineNo2) continue; if (!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first)) continue; const std::string &RightText = II->second; if (D.match(RightText)) break; } if (II == IE) { // Not found. if (i >= D.Min) break; LeftOnly.push_back(*I); } else { // Found. The same cannot be found twice. Right.erase(II); } } } // Now all that's left in Right are those that were not matched. unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label); num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label); return num; }
static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, DirectiveList &DL, const char *Kind, bool Expected) { if (DL.empty()) return 0; llvm::SmallString<256> Fmt; llvm::raw_svector_ostream OS(Fmt); for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { Directive& D = **I; if (D.Location.isInvalid() || !SourceMgr) OS << "\n (frontend)"; else OS << "\n Line " << SourceMgr->getInstantiationLineNumber(D.Location); OS << ": " << D.Text; } Diags.Report(diag::err_verify_inconsistent_diags) << Kind << !Expected << OS.str(); return DL.size(); }
/// \brief Takes a list of diagnostics that were expected to have been generated /// but were not and produces a diagnostic to the user from this. static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr, DirectiveList &DL, const char *Kind) { if (DL.empty()) return 0; SmallString<256> Fmt; llvm::raw_svector_ostream OS(Fmt); for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { Directive &D = **I; OS << "\n Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc); if (D.DirectiveLoc != D.DiagnosticLoc) OS << " (directive at " << SourceMgr.getFilename(D.DirectiveLoc) << ":" << SourceMgr.getPresumedLineNumber(D.DirectiveLoc) << ")"; OS << ": " << D.Text; } Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit() << Kind << /*Unexpected=*/false << OS.str(); return DL.size(); }
/// CheckLists - Compare expected to seen diagnostic lists and return the /// the difference between them. /// static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr, const char *Label, DirectiveList &Left, const_diag_iterator d2_begin, const_diag_iterator d2_end) { DirectiveList LeftOnly; DiagList Right(d2_begin, d2_end); for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) { Directive& D = **I; unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(D.Location); for (unsigned i = 0; i < D.Count; ++i) { DiagList::iterator II, IE; for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first); if (LineNo1 != LineNo2) continue; const std::string &RightText = II->second; if (D.Match(RightText)) break; } if (II == IE) { // Not found. LeftOnly.push_back(*I); } else { // Found. The same cannot be found twice. Right.erase(II); } } } // Now all that's left in Right are those that were not matched. return (PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true) + PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(), Label, false)); }
/// \brief Takes a list of diagnostics that were expected to have been generated /// but were not and produces a diagnostic to the user from this. static unsigned PrintExpected(DiagnosticsEngine &Diags, llvm::SourceMgr &SourceMgr, DirectiveList &DL, const char *Kind) { if (DL.empty()) return 0; SmallString<256> Fmt; llvm::raw_svector_ostream OS(Fmt); for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { Directive &D = **I; OS << "\n Line " << SourceMgr.getLineAndColumn(D.DiagnosticLoc).first; if (D.DirectiveLoc != D.DiagnosticLoc) { int BufID = SourceMgr.FindBufferContainingLoc(D.DirectiveLoc); OS << " (directive at " << SourceMgr.getMemoryBuffer(BufID)->getBufferIdentifier() << SourceMgr.getLineAndColumn(D.DirectiveLoc).first << ")"; } OS << ": " << D.Text; } Diags.Report(SourceLocation(), diag::verify_inconsistent_diags) << Kind << /*Unexpected=*/false << OS.str(); return DL.size(); }
/// ParseDirective - Go through the comment and see if it indicates expected /// diagnostics. If so, then put them in the appropriate directive list. /// static void ParseDirective(const char *CommentStart, unsigned CommentLen, ExpectedData &ED, Preprocessor &PP, SourceLocation Pos) { // A single comment may contain multiple directives. for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) { // search for token: expected if (!PH.Search("expected")) break; PH.Advance(); // next token: - if (!PH.Next("-")) continue; PH.Advance(); // next token: { error | warning | note } DirectiveList* DL = NULL; if (PH.Next("error")) DL = &ED.Errors; else if (PH.Next("warning")) DL = &ED.Warnings; else if (PH.Next("note")) DL = &ED.Notes; else continue; PH.Advance(); // default directive kind bool RegexKind = false; const char* KindStr = "string"; // next optional token: - if (PH.Next("-re")) { PH.Advance(); RegexKind = true; KindStr = "regex"; } // skip optional whitespace PH.SkipWhitespace(); // next optional token: positive integer unsigned Count = 1; if (PH.Next(Count)) PH.Advance(); // skip optional whitespace PH.SkipWhitespace(); // next token: {{ if (!PH.Next("{{")) { PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_start) << KindStr; continue; } PH.Advance(); const char* const ContentBegin = PH.C; // mark content begin // search for token: }} if (!PH.Search("}}")) { PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_end) << KindStr; continue; } const char* const ContentEnd = PH.P; // mark content end PH.Advance(); // build directive text; convert \n to newlines std::string Text; llvm::StringRef NewlineStr = "\\n"; llvm::StringRef Content(ContentBegin, ContentEnd-ContentBegin); size_t CPos = 0; size_t FPos; while ((FPos = Content.find(NewlineStr, CPos)) != llvm::StringRef::npos) { Text += Content.substr(CPos, FPos-CPos); Text += '\n'; CPos = FPos + NewlineStr.size(); } if (Text.empty()) Text.assign(ContentBegin, ContentEnd); // construct new directive Directive *D = Directive::Create(RegexKind, Pos, Text, Count); std::string Error; if (D->isValid(Error)) DL->push_back(D); else { PP.Diag(Pos.getFileLocWithOffset(ContentBegin-PH.Begin), diag::err_verify_invalid_content) << KindStr << Error; } } }
/// Go through the comment and see if it indicates expected /// diagnostics. If so, then put them in the appropriate directive list. /// /// Returns true if any valid directives were found. static bool ParseDirective(StringRef S, ExpectedData *ED, const llvm::SourceMgr &SM, SourceLocation Pos, DiagnosticsEngine &Diags, VerifyDiagnosticConsumer::DirectiveStatus &Status) { // A single comment may contain multiple directives. bool FoundDirective = false; for (ParseHelper PH(S); !PH.Done();) { // Search for token: expected if (!PH.Search("expected", true)) break; PH.Advance(); // Next token: - if (!PH.Next("-")) continue; PH.Advance(); // Next token: { error | warning | note } DirectiveList* DL = NULL; if (PH.Next("diag")) DL = ED ? &ED->Errors : NULL; else if (PH.Next("note")) DL = ED ? &ED->Notes : NULL; else if (PH.Next("no-diagnostics")) { if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives) Diags.Report(Pos, diag::verify_invalid_no_diags) << /*IsExpectedNoDiagnostics=*/true; else Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics; continue; } else continue; PH.Advance(); if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) { Diags.Report(Pos, diag::verify_invalid_no_diags) << /*IsExpectedNoDiagnostics=*/false; continue; } Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives; // If a directive has been found but we're not interested // in storing the directive information, return now. if (!DL) return true; // Default directive kind. bool RegexKind = false; const char* KindStr = "string"; // Next optional token: - if (PH.Next("-re")) { PH.Advance(); RegexKind = true; KindStr = "regex"; } // Next optional token: @ SourceLocation ExpectedLoc; if (!PH.Next("@")) { ExpectedLoc = Pos; } else { PH.Advance(); unsigned Line = 0; bool FoundPlus = PH.Next("+"); if (FoundPlus || PH.Next("-")) { // Relative to current line. PH.Advance(); unsigned ExpectedLine = SM.getLineAndColumn(Pos).first; if (PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) { if (FoundPlus) ExpectedLine += Line; else ExpectedLine -= Line; ExpectedLoc = locForLine(SM, Pos, ExpectedLine); } } else { // Absolute line number. if (PH.Next(Line) && Line > 0) ExpectedLoc = locForLine(SM, Pos, Line); } if (!ExpectedLoc.isValid()) { Diags.Report(Pos, diag::verify_missing_line) << KindStr; continue; } PH.Advance(); } // Skip optional whitespace. PH.SkipWhitespace(); // Next optional token: positive integer or a '+'. unsigned Min = 1; unsigned Max = 1; if (PH.Next(Min)) { PH.Advance(); // A positive integer can be followed by a '+' meaning min // or more, or by a '-' meaning a range from min to max. if (PH.Next("+")) { Max = Directive::MaxCount; PH.Advance(); } else if (PH.Next("-")) { PH.Advance(); if (!PH.Next(Max) || Max < Min) { Diags.Report(Pos, diag::verify_invalid_range) << KindStr; continue; } PH.Advance(); } else { Max = Min; } } else if (PH.Next("+")) { // '+' on its own means "1 or more". Max = Directive::MaxCount; PH.Advance(); } // Skip optional whitespace. PH.SkipWhitespace(); // Next token: {{ if (!PH.Next("{{")) { Diags.Report(Pos, diag::verify_missing_start) << KindStr; continue; } PH.Advance(); const char* const ContentBegin = PH.C; // mark content begin // Search for token: }} if (!PH.Search("}}")) { Diags.Report(Pos, diag::verify_missing_end) << KindStr; continue; } const char* const ContentEnd = PH.P; // mark content end PH.Advance(); // Build directive text; convert \n to newlines. std::string Text; StringRef NewlineStr = "\\n"; StringRef Content(ContentBegin, ContentEnd-ContentBegin); size_t CPos = 0; size_t FPos; while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) { Text += Content.substr(CPos, FPos-CPos); Text += '\n'; CPos = FPos + NewlineStr.size(); } if (Text.empty()) Text.assign(ContentBegin, ContentEnd); // Construct new directive. Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text, Min, Max); std::string Error; if (D->isValid(Error)) { DL->push_back(D); FoundDirective = true; } else { Diags.Report(Pos, diag::verify_invalid_content) << KindStr << Error; } } return FoundDirective; }
/// ParseDirective - Go through the comment and see if it indicates expected /// diagnostics. If so, then put them in the appropriate directive list. /// /// Returns true if any valid directives were found. static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, Preprocessor *PP, SourceLocation Pos, VerifyDiagnosticConsumer::DirectiveStatus &Status) { DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics(); // A single comment may contain multiple directives. bool FoundDirective = false; for (ParseHelper PH(S); !PH.Done();) { // Search for token: expected if (!PH.Search("expected", true)) break; PH.Advance(); // Next token: - if (!PH.Next("-")) continue; PH.Advance(); // Next token: { error | warning | note } DirectiveList *DL = nullptr; if (PH.Next("error")) DL = ED ? &ED->Errors : nullptr; else if (PH.Next("warning")) DL = ED ? &ED->Warnings : nullptr; else if (PH.Next("remark")) DL = ED ? &ED->Remarks : nullptr; else if (PH.Next("note")) DL = ED ? &ED->Notes : nullptr; else if (PH.Next("no-diagnostics")) { if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives) Diags.Report(Pos, diag::err_verify_invalid_no_diags) << /*IsExpectedNoDiagnostics=*/true; else Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics; continue; } else continue; PH.Advance(); if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) { Diags.Report(Pos, diag::err_verify_invalid_no_diags) << /*IsExpectedNoDiagnostics=*/false; continue; } Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives; // If a directive has been found but we're not interested // in storing the directive information, return now. if (!DL) return true; // Default directive kind. bool RegexKind = false; const char* KindStr = "string"; // Next optional token: - if (PH.Next("-re")) { PH.Advance(); RegexKind = true; KindStr = "regex"; } // Next optional token: @ SourceLocation ExpectedLoc; bool MatchAnyLine = false; if (!PH.Next("@")) { ExpectedLoc = Pos; } else { PH.Advance(); unsigned Line = 0; bool FoundPlus = PH.Next("+"); if (FoundPlus || PH.Next("-")) { // Relative to current line. PH.Advance(); bool Invalid = false; unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid); if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) { if (FoundPlus) ExpectedLine += Line; else ExpectedLine -= Line; ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1); } } else if (PH.Next(Line)) { // Absolute line number. if (Line > 0) ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1); } else if (PP && PH.Search(":")) { // Specific source file. StringRef Filename(PH.C, PH.P-PH.C); PH.Advance(); // Lookup file via Preprocessor, like a #include. const DirectoryLookup *CurDir; const FileEntry *FE = PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir, nullptr, nullptr, nullptr); if (!FE) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_file) << Filename << KindStr; continue; } if (SM.translateFile(FE).isInvalid()) SM.createFileID(FE, Pos, SrcMgr::C_User); if (PH.Next(Line) && Line > 0) ExpectedLoc = SM.translateFileLineCol(FE, Line, 1); else if (PH.Next("*")) { MatchAnyLine = true; ExpectedLoc = SM.translateFileLineCol(FE, 1, 1); } } if (ExpectedLoc.isInvalid()) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_line) << KindStr; continue; } PH.Advance(); } // Skip optional whitespace. PH.SkipWhitespace(); // Next optional token: positive integer or a '+'. unsigned Min = 1; unsigned Max = 1; if (PH.Next(Min)) { PH.Advance(); // A positive integer can be followed by a '+' meaning min // or more, or by a '-' meaning a range from min to max. if (PH.Next("+")) { Max = Directive::MaxCount; PH.Advance(); } else if (PH.Next("-")) { PH.Advance(); if (!PH.Next(Max) || Max < Min) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_invalid_range) << KindStr; continue; } PH.Advance(); } else { Max = Min; } } else if (PH.Next("+")) { // '+' on its own means "1 or more". Max = Directive::MaxCount; PH.Advance(); } // Skip optional whitespace. PH.SkipWhitespace(); // Next token: {{ if (!PH.Next("{{")) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_start) << KindStr; continue; } PH.Advance(); const char* const ContentBegin = PH.C; // mark content begin // Search for token: }} if (!PH.SearchClosingBrace("{{", "}}")) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_end) << KindStr; continue; } const char* const ContentEnd = PH.P; // mark content end PH.Advance(); // Build directive text; convert \n to newlines. std::string Text; StringRef NewlineStr = "\\n"; StringRef Content(ContentBegin, ContentEnd-ContentBegin); size_t CPos = 0; size_t FPos; while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) { Text += Content.substr(CPos, FPos-CPos); Text += '\n'; CPos = FPos + NewlineStr.size(); } if (Text.empty()) Text.assign(ContentBegin, ContentEnd); // Check that regex directives contain at least one regex. if (RegexKind && Text.find("{{") == StringRef::npos) { Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin), diag::err_verify_missing_regex) << Text; return false; } // Construct new directive. std::unique_ptr<Directive> D = Directive::create( RegexKind, Pos, ExpectedLoc, MatchAnyLine, Text, Min, Max); std::string Error; if (D->isValid(Error)) { DL->push_back(std::move(D)); FoundDirective = true; } else { Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin), diag::err_verify_invalid_content) << KindStr << Error; } } return FoundDirective; }
/// ParseDirective - Go through the comment and see if it indicates expected /// diagnostics. If so, then put them in the appropriate directive list. /// /// Returns true if any valid directives were found. static bool ParseDirective(StringRef S, ExpectedData &ED, SourceManager &SM, SourceLocation Pos, DiagnosticsEngine &Diags) { // A single comment may contain multiple directives. bool FoundDirective = false; for (ParseHelper PH(S); !PH.Done();) { // Search for token: expected if (!PH.Search("expected")) break; PH.Advance(); // Next token: - if (!PH.Next("-")) continue; PH.Advance(); // Next token: { error | warning | note } DirectiveList* DL = NULL; if (PH.Next("error")) DL = &ED.Errors; else if (PH.Next("warning")) DL = &ED.Warnings; else if (PH.Next("note")) DL = &ED.Notes; else continue; PH.Advance(); // Default directive kind. bool RegexKind = false; const char* KindStr = "string"; // Next optional token: - if (PH.Next("-re")) { PH.Advance(); RegexKind = true; KindStr = "regex"; } // Next optional token: @ SourceLocation ExpectedLoc; if (!PH.Next("@")) { ExpectedLoc = Pos; } else { PH.Advance(); unsigned Line = 0; bool FoundPlus = PH.Next("+"); if (FoundPlus || PH.Next("-")) { // Relative to current line. PH.Advance(); bool Invalid = false; unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid); if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) { if (FoundPlus) ExpectedLine += Line; else ExpectedLine -= Line; ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1); } } else { // Absolute line number. if (PH.Next(Line) && Line > 0) ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1); } if (ExpectedLoc.isInvalid()) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_line) << KindStr; continue; } PH.Advance(); } // Skip optional whitespace. PH.SkipWhitespace(); // Next optional token: positive integer or a '+'. unsigned Min = 1; unsigned Max = 1; if (PH.Next(Min)) { PH.Advance(); // A positive integer can be followed by a '+' meaning min // or more, or by a '-' meaning a range from min to max. if (PH.Next("+")) { Max = Directive::MaxCount; PH.Advance(); } else if (PH.Next("-")) { PH.Advance(); if (!PH.Next(Max) || Max < Min) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_invalid_range) << KindStr; continue; } PH.Advance(); } else { Max = Min; } } else if (PH.Next("+")) { // '+' on its own means "1 or more". Max = Directive::MaxCount; PH.Advance(); } // Skip optional whitespace. PH.SkipWhitespace(); // Next token: {{ if (!PH.Next("{{")) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_start) << KindStr; continue; } PH.Advance(); const char* const ContentBegin = PH.C; // mark content begin // Search for token: }} if (!PH.Search("}}")) { Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), diag::err_verify_missing_end) << KindStr; continue; } const char* const ContentEnd = PH.P; // mark content end PH.Advance(); // Build directive text; convert \n to newlines. std::string Text; StringRef NewlineStr = "\\n"; StringRef Content(ContentBegin, ContentEnd-ContentBegin); size_t CPos = 0; size_t FPos; while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) { Text += Content.substr(CPos, FPos-CPos); Text += '\n'; CPos = FPos + NewlineStr.size(); } if (Text.empty()) Text.assign(ContentBegin, ContentEnd); // Construct new directive. Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text, Min, Max); std::string Error; if (D->isValid(Error)) { DL->push_back(D); FoundDirective = true; } else { Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin), diag::err_verify_invalid_content) << KindStr << Error; } } return FoundDirective; }