21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/Support/Regex.h"
23 #include "llvm/Support/raw_ostream.h"
25 using namespace clang;
32 PrimaryClient(Diags.getClient()), PrimaryClientOwner(Diags.takeClient()),
34 LangOpts(nullptr), SrcManager(nullptr), ActiveSourceFiles(0),
42 assert(!ActiveSourceFiles &&
"Incomplete parsing of source files!");
43 assert(!CurrentPreprocessor &&
"CurrentPreprocessor should be invalid!");
47 "The VerifyDiagnosticConsumer takes over ownership of the client!");
58 : Verify(Verify), SM(SM) { }
77 if (++ActiveSourceFiles == 1) {
79 CurrentPreprocessor = PP;
80 this->LangOpts = &LangOpts;
86 llvm::make_unique<VerifyFileTracker>(*
this, *SrcManager));
91 assert((!PP || CurrentPreprocessor == PP) &&
"Preprocessor changed!");
96 assert(ActiveSourceFiles &&
"No active source files!");
100 if (--ActiveSourceFiles == 0) {
101 if (CurrentPreprocessor)
102 const_cast<Preprocessor*
>(CurrentPreprocessor)->removeCommentHandler(
this);
106 CurrentPreprocessor =
nullptr;
133 if (FE && CurrentPreprocessor && SrcManager->
isLoadedFileID(FID)) {
148 Buffer->HandleDiagnostic(DiagLevel, Info);
162 class StandardDirective :
public Directive {
165 bool MatchAnyLine, StringRef
Text,
unsigned Min,
167 :
Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max) { }
169 bool isValid(std::string &
Error)
override {
174 bool match(StringRef
S)
override {
175 return S.find(Text) != StringRef::npos;
181 class RegexDirective :
public Directive {
184 bool MatchAnyLine, StringRef
Text,
unsigned Min,
unsigned Max,
186 :
Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max),
189 bool isValid(std::string &
Error)
override {
193 bool match(StringRef
S)
override {
194 return Regex.match(S);
204 ParseHelper(StringRef
S)
208 bool Next(StringRef S) {
213 return !memcmp(
P, S.data(), S.size());
218 bool Next(
unsigned &N) {
221 for (; P < End && P[0] >=
'0' &&
P[0] <=
'9'; ++
P) {
234 bool Search(StringRef S,
bool EnsureStartOfWord =
false) {
236 P = std::search(C,
End, S.begin(), S.end());
240 if (!EnsureStartOfWord
244 || (
P > (
Begin + 1) && (
P[-1] ==
'/' ||
P[-1] ==
'*')
254 bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {
259 if (S.startswith(OpenBrace)) {
261 P += OpenBrace.size();
262 }
else if (S.startswith(CloseBrace)) {
265 PEnd =
P + CloseBrace.size();
268 P += CloseBrace.size();
284 void SkipWhitespace() {
294 const char *
const Begin;
295 const char *
const End;
315 bool FoundDirective =
false;
316 for (ParseHelper PH(S); !PH.Done();) {
318 if (!PH.Search(
"expected",
true))
329 if (PH.Next(
"error"))
330 DL = ED ? &ED->
Errors :
nullptr;
331 else if (PH.Next(
"warning"))
333 else if (PH.Next(
"remark"))
334 DL = ED ? &ED->
Remarks :
nullptr;
335 else if (PH.Next(
"note"))
336 DL = ED ? &ED->
Notes :
nullptr;
337 else if (PH.Next(
"no-diagnostics")) {
339 Diags.
Report(Pos, diag::err_verify_invalid_no_diags)
349 Diags.
Report(Pos, diag::err_verify_invalid_no_diags)
361 bool RegexKind =
false;
362 const char* KindStr =
"string";
365 if (PH.Next(
"-re")) {
373 bool MatchAnyLine =
false;
379 bool FoundPlus = PH.Next(
"+");
380 if (FoundPlus || PH.Next(
"-")) {
383 bool Invalid =
false;
385 if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {
386 if (FoundPlus) ExpectedLine +=
Line;
387 else ExpectedLine -=
Line;
390 }
else if (PH.Next(Line)) {
394 }
else if (PP && PH.Search(
":")) {
396 StringRef
Filename(PH.C, PH.P-PH.C);
402 PP->
LookupFile(Pos, Filename,
false,
nullptr,
nullptr, CurDir,
403 nullptr,
nullptr,
nullptr,
nullptr);
406 diag::err_verify_missing_file) << Filename << KindStr;
413 if (PH.Next(Line) && Line > 0)
415 else if (PH.Next(
"*")) {
423 diag::err_verify_missing_line) << KindStr;
442 }
else if (PH.Next(
"-")) {
444 if (!PH.Next(Max) || Max < Min) {
446 diag::err_verify_invalid_range) << KindStr;
453 }
else if (PH.Next(
"+")) {
463 if (!PH.Next(
"{{")) {
465 diag::err_verify_missing_start) << KindStr;
469 const char*
const ContentBegin = PH.C;
472 if (!PH.SearchClosingBrace(
"{{",
"}}")) {
474 diag::err_verify_missing_end) << KindStr;
477 const char*
const ContentEnd = PH.P;
482 StringRef NewlineStr =
"\\n";
483 StringRef Content(ContentBegin, ContentEnd-ContentBegin);
486 while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
487 Text += Content.substr(CPos, FPos-CPos);
489 CPos = FPos + NewlineStr.size();
492 Text.assign(ContentBegin, ContentEnd);
495 if (RegexKind && Text.find(
"{{") == StringRef::npos) {
497 diag::err_verify_missing_regex) << Text;
503 RegexKind, Pos, ExpectedLoc, MatchAnyLine, Text, Min, Max);
506 if (D->isValid(Error)) {
507 DL->push_back(std::move(D));
508 FoundDirective =
true;
511 diag::err_verify_invalid_content)
516 return FoundDirective;
526 if (SrcManager && &SM != SrcManager)
538 size_t loc = C.find(
'\\');
539 if (loc == StringRef::npos) {
545 C2.reserve(C.size());
547 for (
size_t last = 0;; loc = C.find(
'\\', last)) {
548 if (loc == StringRef::npos || loc == C.size()) {
549 C2 += C.substr(last);
552 C2 += C.substr(last, loc-last);
555 if (C[last] ==
'\n' || C[last] ==
'\r') {
560 if (C[last] ==
'\n' || C[last] ==
'\r')
561 if (C[last] != C[last-1])
587 const llvm::MemoryBuffer *FromFile = SM.
getBuffer(FID);
588 Lexer RawLex(FID, FromFile, SM, LangOpts);
599 if (!Tok.
is(tok::comment))
continue;
601 std::string Comment = RawLex.
getSpelling(Tok, SM, LangOpts);
602 if (Comment.empty())
continue;
619 if (diag_begin == diag_end)
return 0;
622 llvm::raw_svector_ostream OS(Fmt);
625 OS <<
"\n (frontend)";
630 OS <<
" File " << File->getName();
633 OS <<
": " <<
I->second;
637 << Kind <<
true << OS.str();
645 std::vector<Directive *> &DL,
const char *
Kind) {
650 llvm::raw_svector_ostream OS(Fmt);
651 for (
auto *DirPtr : DL) {
659 OS <<
" (directive at "
662 OS <<
": " << D.
Text;
666 << Kind <<
false << OS.str();
694 bool IgnoreUnexpected) {
695 std::vector<Directive *> LeftOnly;
698 for (
auto &Owner : Left) {
702 for (
unsigned i = 0; i < D.
Max; ++i) {
703 DiagList::iterator II, IE;
704 for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
707 if (LineNo1 != LineNo2)
714 const std::string &RightText = II->second;
715 if (D.
match(RightText))
720 if (i >= D.
Min)
break;
721 LeftOnly.push_back(&D);
729 unsigned num =
PrintExpected(Diags, SourceMgr, LeftOnly, Label);
730 if (!IgnoreUnexpected)
747 unsigned NumProblems = 0;
779 setSourceManager(SM);
789 UnparsedFiles.erase(FID);
790 ParsedFiles.insert(std::make_pair(FID, FE));
791 }
else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
795 bool FoundDirectives;
797 FoundDirectives =
false;
799 FoundDirectives = !LangOpts ||
findDirectives(SM, FID, *LangOpts);
802 UnparsedFiles.insert(std::make_pair(FID,
803 UnparsedFileStatus(FE, FoundDirectives)));
808 void VerifyDiagnosticConsumer::CheckDiagnostics() {
811 std::unique_ptr<DiagnosticConsumer> Owner = Diags.
takeClient();
821 if (UnparsedFiles.size() > 0) {
823 llvm::SmallPtrSet<const FileEntry *, 8> ParsedFileCache;
824 for (ParsedFilesMap::iterator
I = ParsedFiles.begin(),
825 End = ParsedFiles.end();
I !=
End; ++
I) {
827 ParsedFileCache.insert(FE);
831 for (UnparsedFilesMap::iterator
I = UnparsedFiles.begin(),
832 End = UnparsedFiles.end();
I !=
End; ++
I) {
833 const UnparsedFileStatus &Status =
I->second;
837 if (FE && ParsedFileCache.count(FE))
841 if (Status.foundDirectives()) {
842 llvm::report_fatal_error(Twine(
"-verify directives found after rather"
843 " than during normal parsing of ",
844 StringRef(FE ? FE->
getName() :
"(unknown)")));
849 UnparsedFiles.clear();
869 Buffer->err_end(),
"error");
872 Buffer->warn_end(),
"warn");
875 Buffer->remark_end(),
"remark");
878 Buffer->note_end(),
"note");
881 Diags.
setClient(CurClient, Owner.release() !=
nullptr);
891 bool MatchAnyLine, StringRef
Text,
892 unsigned Min,
unsigned Max) {
894 return llvm::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
895 MatchAnyLine,
Text, Min, Max);
898 std::string RegexStr;
901 if (S.startswith(
"{{")) {
903 size_t RegexMatchLength = S.find(
"}}");
904 assert(RegexMatchLength != StringRef::npos);
907 RegexStr.append(S.data(), RegexMatchLength);
909 S = S.drop_front(RegexMatchLength + 2);
911 size_t VerbatimMatchLength = S.find(
"{{");
912 if (VerbatimMatchLength == StringRef::npos)
913 VerbatimMatchLength = S.size();
915 RegexStr += llvm::Regex::escape(S.substr(0, VerbatimMatchLength));
916 S = S.drop_front(VerbatimMatchLength);
920 return llvm::make_unique<RegexDirective>(
921 DirectiveLoc, DiagnosticLoc, MatchAnyLine,
Text, Min, Max, RegexStr);
SourceManager & getSourceManager() const
const_iterator warn_end() const
static unsigned getSpelling(const Token &Tok, const char *&Buffer, const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *Invalid=nullptr)
getSpelling - This method is used to get the spelling of a token into a preallocated buffer...
SourceLocation getEnd() const
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens...
DiagnosticConsumer * getClient()
VerifyDiagnosticConsumer - Create a diagnostic client which will use markers in the input source to c...
bool isLoadedFileID(FileID FID) const
Returns true if FID came from a PCH/Module.
Defines the clang::FileManager interface and associated types.
const_iterator note_begin() const
static LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t', '\f', '\v', '\n', '\r'.
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
unsigned NumErrors
Number of errors reported.
void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS)
Update lists of parsed and unparsed files.
unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const TextDiagnosticBuffer &Buffer, ExpectedData &ED)
CheckResults - This compares the expected results to those that were actually reported.
VerifyDiagnosticConsumer(DiagnosticsEngine &Diags)
Create a new verifying diagnostic client, which will issue errors to the currently-attached diagnosti...
const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const
Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer...
const_iterator err_end() const
llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
File has been processed via HandleComment.
VerifyDiagnosticConsumer::DirectiveList DirectiveList
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
std::unique_ptr< llvm::MemoryBuffer > Buffer
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
std::unique_ptr< DiagnosticConsumer > takeClient()
Return the current diagnostic client along with ownership of that client.
float __ovld __cnfn distance(float p0, float p1)
Returns the distance between p0 and p1.
virtual void EndSourceFile()
Callback to inform the diagnostic client that processing of a source file has ended.
SourceLocation DiagnosticLoc
const FileEntry * LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled, const DirectoryLookup *FromDir, const FileEntry *FromFile, const DirectoryLookup *&CurDir, SmallVectorImpl< char > *SearchPath, SmallVectorImpl< char > *RelativePath, ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool SkipCache=false)
Given a "foo" or <foo> reference, look up the indicated file.
static std::unique_ptr< Directive > create(bool RegexKind, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
This interface provides a way to observe the actions of the preprocessor as it does its thing...
TextDiagnosticBuffer::DiagList DiagList
VerifyDiagnosticConsumer::ExpectedData ExpectedData
TextDiagnosticBuffer::const_iterator const_diag_iterator
void EndSourceFile() override
Callback to inform the diagnostic client that processing of a source file has ended.
void setClient(DiagnosticConsumer *client, bool ShouldOwnClient=true)
Set the diagnostic client associated with this diagnostic object.
ExpectedData - owns directive objects and deletes on destructor.
SourceLocation DirectiveLoc
Token - This structure provides full information about a lexed token.
void setKind(tok::TokenKind K)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
SourceManager & getSourceManager() const
VerifyDiagnosticConsumer::Directive Directive
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
const SourceLocation & getLocation() const
SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const
Gets the location of the immediate macro caller, one level up the stack toward the initial macro type...
Concrete class used by the front-end to report problems and issues.
HeaderSearch & getHeaderSearchInfo() const
StringRef getName() const
static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr, std::vector< Directive * > &DL, const char *Kind)
Takes a list of diagnostics that were expected to have been generated but were not and produces a dia...
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
SourceLocation translateFileLineCol(const FileEntry *SourceFile, unsigned Line, unsigned Col) const
Get the source location for the given file:line:col triplet.
detail::InMemoryDirectory::const_iterator I
const_iterator remark_end() const
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
File has diagnostics but guaranteed no directives.
const_iterator remark_begin() const
StringRef getFilename(SourceLocation SpellingLoc) const
Return the filename of the file containing a SourceLocation.
SourceLocation translateLineCol(FileID FID, unsigned Line, unsigned Col) const
Get the source location in FID for the given line:col.
bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const
Returns true if the spelling locations for both SourceLocations are part of the same file buffer...
FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID=0, unsigned LoadedOffset=0)
Create a new FileID that represents the specified file being #included from the specified IncludePosi...
Defines the clang::Preprocessor interface.
static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceMgr, const_diag_iterator diag_begin, const_diag_iterator diag_end, const char *Kind)
Takes a list of diagnostics that have been generated but not matched by an expected-* directive and p...
bool isWrittenInMainFile(SourceLocation Loc) const
Returns true if the spelling location for the given location is in the main file buffer.
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file. ...
const_iterator note_end() const
bool isNot(tok::TokenKind K) const
DirectoryLookup - This class represents one entry in the search list that specifies the search order ...
bool HandleComment(Preprocessor &PP, SourceRange Comment) override
HandleComment - Hook into the preprocessor and extract comments containing expected errors and warnin...
const_iterator warn_begin() const
std::vector< std::pair< SourceLocation, std::string > > DiagList
static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc)
Determine whether two source locations come from the same file.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
Cached information about one file (either on disk or in the virtual file system). ...
DiagList::const_iterator const_iterator
DiagnosticsEngine & getDiagnostics() const
DiagnosticOptions & getDiagnosticOptions() const
Retrieve the diagnostic options.
SourceLocation getBegin() const
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {...
virtual bool match(StringRef S)=0
File has diagnostics and may have directives.
DiagnosticsEngine & getDiagnostics() const
const DiagnosticBuilder & setForceEmit() const
Forces the diagnostic to be emitted.
std::vector< std::unique_ptr< Directive > > DirectiveList
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T-> getSizeExpr()))
virtual bool isValid(std::string &Error)=0
bool hasSourceManager() const
static bool findDirectives(SourceManager &SM, FileID FID, const LangOptions &LangOpts)
Lex the specified source file to determine whether it contains any expected-* directives.
static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, Preprocessor *PP, SourceLocation Pos, VerifyDiagnosticConsumer::DirectiveStatus &Status)
ParseDirective - Go through the comment and see if it indicates expected diagnostics.
detail::InMemoryDirectory::const_iterator E
FileID translateFile(const FileEntry *SourceFile) const
Get the FileID for the given file.
~VerifyDiagnosticConsumer() override
bool hasSourceManager() const
SourceManager & getSourceManager() const
static const unsigned MaxCount
Constant representing n or more matches.
Level
The level of the diagnostic, after it has been through mapping.
static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const char *Label, DirectiveList &Left, const_diag_iterator d2_begin, const_diag_iterator d2_end, bool IgnoreUnexpected)
CheckLists - Compare expected to seen diagnostic lists and return the the difference between them...
void SetCommentRetentionState(bool Mode)
SetCommentRetentionMode - Change the comment retention mode of the lexer to the specified mode...
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
DiagnosticLevelMask
A bitmask representing the diagnostic levels used by VerifyDiagnosticConsumer.
bool ownsClient() const
Determine whether this DiagnosticsEngine object own its client.
A trivial tuple used to represent a source range.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
Directive - Abstract class representing a parsed verify directive.
virtual void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP=nullptr)
Callback to inform the diagnostic client that processing of a source file is beginning.
This class handles loading and caching of source files into memory.
const_iterator err_begin() const
void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP) override
Callback to inform the diagnostic client that processing of a source file is beginning.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.