1 //===- VerifyDiagnosticConsumer.h - Verifying Diagnostic Client -*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H 10 #define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H 11 12 #include "clang/Basic/Diagnostic.h" 13 #include "clang/Basic/FileManager.h" 14 #include "clang/Basic/LLVM.h" 15 #include "clang/Basic/SourceLocation.h" 16 #include "clang/Lex/Preprocessor.h" 17 #include "llvm/ADT/DenseMap.h" 18 #include "llvm/ADT/PointerIntPair.h" 19 #include "llvm/ADT/StringRef.h" 20 #include <cassert> 21 #include <limits> 22 #include <memory> 23 #include <string> 24 #include <vector> 25 26 namespace clang { 27 28 class FileEntry; 29 class LangOptions; 30 class SourceManager; 31 class TextDiagnosticBuffer; 32 33 /// VerifyDiagnosticConsumer - Create a diagnostic client which will use 34 /// markers in the input source to check that all the emitted diagnostics match 35 /// those expected. See clang/docs/InternalsManual.rst for details about how to 36 /// write tests to verify diagnostics. 37 /// 38 class VerifyDiagnosticConsumer: public DiagnosticConsumer, 39 public CommentHandler { 40 public: 41 /// Directive - Abstract class representing a parsed verify directive. 42 /// 43 class Directive { 44 public: 45 static std::unique_ptr<Directive> 46 create(bool RegexKind, SourceLocation DirectiveLoc, 47 SourceLocation DiagnosticLoc, StringRef Spelling, 48 bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text, 49 unsigned Min, unsigned Max); 50 51 public: 52 /// Constant representing n or more matches. 53 static const unsigned MaxCount = std::numeric_limits<unsigned>::max(); 54 55 SourceLocation DirectiveLoc; 56 SourceLocation DiagnosticLoc; 57 const std::string Spelling; 58 const std::string Text; 59 unsigned Min, Max; 60 bool MatchAnyLine; 61 bool MatchAnyFileAndLine; // `MatchAnyFileAndLine` implies `MatchAnyLine`. 62 63 Directive(const Directive &) = delete; 64 Directive &operator=(const Directive &) = delete; 65 virtual ~Directive() = default; 66 67 // Returns true if directive text is valid. 68 // Otherwise returns false and populates E. 69 virtual bool isValid(std::string &Error) = 0; 70 71 // Returns true on match. 72 virtual bool match(StringRef S) = 0; 73 74 protected: Directive(SourceLocation DirectiveLoc,SourceLocation DiagnosticLoc,StringRef Spelling,bool MatchAnyFileAndLine,bool MatchAnyLine,StringRef Text,unsigned Min,unsigned Max)75 Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, 76 StringRef Spelling, bool MatchAnyFileAndLine, bool MatchAnyLine, 77 StringRef Text, unsigned Min, unsigned Max) 78 : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), 79 Spelling(Spelling), Text(Text), Min(Min), Max(Max), 80 MatchAnyLine(MatchAnyLine || MatchAnyFileAndLine), 81 MatchAnyFileAndLine(MatchAnyFileAndLine) { 82 assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!"); 83 assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) && 84 "DiagnosticLoc is invalid!"); 85 } 86 }; 87 88 using DirectiveList = std::vector<std::unique_ptr<Directive>>; 89 90 /// ExpectedData - owns directive objects and deletes on destructor. 91 struct ExpectedData { 92 DirectiveList Errors; 93 DirectiveList Warnings; 94 DirectiveList Remarks; 95 DirectiveList Notes; 96 ResetExpectedData97 void Reset() { 98 Errors.clear(); 99 Warnings.clear(); 100 Remarks.clear(); 101 Notes.clear(); 102 } 103 }; 104 105 enum DirectiveStatus { 106 HasNoDirectives, 107 HasNoDirectivesReported, 108 HasExpectedNoDiagnostics, 109 HasOtherExpectedDirectives 110 }; 111 112 struct ParsingState { 113 DirectiveStatus Status; 114 std::string FirstNoDiagnosticsDirective; 115 }; 116 117 class MarkerTracker; 118 119 private: 120 DiagnosticsEngine &Diags; 121 DiagnosticConsumer *PrimaryClient; 122 std::unique_ptr<DiagnosticConsumer> PrimaryClientOwner; 123 std::unique_ptr<TextDiagnosticBuffer> Buffer; 124 std::unique_ptr<MarkerTracker> Markers; 125 const Preprocessor *CurrentPreprocessor = nullptr; 126 const LangOptions *LangOpts = nullptr; 127 SourceManager *SrcManager = nullptr; 128 unsigned ActiveSourceFiles = 0; 129 ParsingState State; 130 ExpectedData ED; 131 132 void CheckDiagnostics(); 133 setSourceManager(SourceManager & SM)134 void setSourceManager(SourceManager &SM) { 135 assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!"); 136 SrcManager = &SM; 137 } 138 139 // These facilities are used for validation in debug builds. 140 class UnparsedFileStatus { 141 OptionalFileEntryRef File; 142 bool FoundDirectives; 143 144 public: UnparsedFileStatus(OptionalFileEntryRef File,bool FoundDirectives)145 UnparsedFileStatus(OptionalFileEntryRef File, bool FoundDirectives) 146 : File(File), FoundDirectives(FoundDirectives) {} 147 getFile()148 OptionalFileEntryRef getFile() const { return File; } foundDirectives()149 bool foundDirectives() const { return FoundDirectives; } 150 }; 151 152 using ParsedFilesMap = llvm::DenseMap<FileID, const FileEntry *>; 153 using UnparsedFilesMap = llvm::DenseMap<FileID, UnparsedFileStatus>; 154 155 ParsedFilesMap ParsedFiles; 156 UnparsedFilesMap UnparsedFiles; 157 158 public: 159 /// Create a new verifying diagnostic client, which will issue errors to 160 /// the currently-attached diagnostic client when a diagnostic does not match 161 /// what is expected (as indicated in the source file). 162 VerifyDiagnosticConsumer(DiagnosticsEngine &Diags); 163 ~VerifyDiagnosticConsumer() override; 164 165 void BeginSourceFile(const LangOptions &LangOpts, 166 const Preprocessor *PP) override; 167 168 void EndSourceFile() override; 169 170 enum ParsedStatus { 171 /// File has been processed via HandleComment. 172 IsParsed, 173 174 /// File has diagnostics and may have directives. 175 IsUnparsed, 176 177 /// File has diagnostics but guaranteed no directives. 178 IsUnparsedNoDirectives 179 }; 180 181 /// Update lists of parsed and unparsed files. 182 void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS); 183 184 bool HandleComment(Preprocessor &PP, SourceRange Comment) override; 185 186 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 187 const Diagnostic &Info) override; 188 }; 189 190 } // namespace clang 191 192 #endif // LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H 193