1 //===- VerifyDiagnosticConsumer.h - Verifying Diagnostic Client -*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H 11 #define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H 12 13 #include "clang/Basic/Diagnostic.h" 14 #include "clang/Lex/Preprocessor.h" 15 #include "llvm/ADT/DenseMap.h" 16 #include "llvm/ADT/PointerIntPair.h" 17 #include "llvm/ADT/STLExtras.h" 18 #include <climits> 19 #include <memory> 20 21 namespace clang { 22 23 class DiagnosticsEngine; 24 class TextDiagnosticBuffer; 25 class FileEntry; 26 27 /// VerifyDiagnosticConsumer - Create a diagnostic client which will use 28 /// markers in the input source to check that all the emitted diagnostics match 29 /// those expected. 30 /// 31 /// USING THE DIAGNOSTIC CHECKER: 32 /// 33 /// Indicating that a line expects an error or a warning is simple. Put a 34 /// comment on the line that has the diagnostic, use: 35 /// 36 /// \code 37 /// expected-{error,warning,remark,note} 38 /// \endcode 39 /// 40 /// to tag if it's an expected error, remark or warning, and place the expected 41 /// text between {{ and }} markers. The full text doesn't have to be included, 42 /// only enough to ensure that the correct diagnostic was emitted. 43 /// 44 /// Here's an example: 45 /// 46 /// \code 47 /// int A = B; // expected-error {{use of undeclared identifier 'B'}} 48 /// \endcode 49 /// 50 /// You can place as many diagnostics on one line as you wish. To make the code 51 /// more readable, you can use slash-newline to separate out the diagnostics. 52 /// 53 /// Alternatively, it is possible to specify the line on which the diagnostic 54 /// should appear by appending "@<line>" to "expected-<type>", for example: 55 /// 56 /// \code 57 /// #warning some text 58 /// // expected-warning@10 {{some text}} 59 /// \endcode 60 /// 61 /// The line number may be absolute (as above), or relative to the current 62 /// line by prefixing the number with either '+' or '-'. 63 /// 64 /// If the diagnostic is generated in a separate file, for example in a shared 65 /// header file, it may be beneficial to be able to declare the file in which 66 /// the diagnostic will appear, rather than placing the expected-* directive in 67 /// the actual file itself. This can be done using the following syntax: 68 /// 69 /// \code 70 /// // expected-error@path/include.h:15 {{error message}} 71 /// \endcode 72 /// 73 /// The path can be absolute or relative and the same search paths will be used 74 /// as for #include directives. The line number in an external file may be 75 /// substituted with '*' meaning that any line number will match (useful where 76 /// the included file is, for example, a system header where the actual line 77 /// number may change and is not critical). 78 /// 79 /// The simple syntax above allows each specification to match exactly one 80 /// error. You can use the extended syntax to customize this. The extended 81 /// syntax is "expected-<type> <n> {{diag text}}", where \<type> is one of 82 /// "error", "warning" or "note", and \<n> is a positive integer. This allows 83 /// the diagnostic to appear as many times as specified. Example: 84 /// 85 /// \code 86 /// void f(); // expected-note 2 {{previous declaration is here}} 87 /// \endcode 88 /// 89 /// Where the diagnostic is expected to occur a minimum number of times, this 90 /// can be specified by appending a '+' to the number. Example: 91 /// 92 /// \code 93 /// void f(); // expected-note 0+ {{previous declaration is here}} 94 /// void g(); // expected-note 1+ {{previous declaration is here}} 95 /// \endcode 96 /// 97 /// In the first example, the diagnostic becomes optional, i.e. it will be 98 /// swallowed if it occurs, but will not generate an error if it does not 99 /// occur. In the second example, the diagnostic must occur at least once. 100 /// As a short-hand, "one or more" can be specified simply by '+'. Example: 101 /// 102 /// \code 103 /// void g(); // expected-note + {{previous declaration is here}} 104 /// \endcode 105 /// 106 /// A range can also be specified by "<n>-<m>". Example: 107 /// 108 /// \code 109 /// void f(); // expected-note 0-1 {{previous declaration is here}} 110 /// \endcode 111 /// 112 /// In this example, the diagnostic may appear only once, if at all. 113 /// 114 /// Regex matching mode may be selected by appending '-re' to type and 115 /// including regexes wrapped in double curly braces in the directive, such as: 116 /// 117 /// \code 118 /// expected-error-re {{format specifies type 'wchar_t **' (aka '{{.+}}')}} 119 /// \endcode 120 /// 121 /// Examples matching error: "variable has incomplete type 'struct s'" 122 /// 123 /// \code 124 /// // expected-error {{variable has incomplete type 'struct s'}} 125 /// // expected-error {{variable has incomplete type}} 126 /// 127 /// // expected-error-re {{variable has type 'struct {{.}}'}} 128 /// // expected-error-re {{variable has type 'struct {{.*}}'}} 129 /// // expected-error-re {{variable has type 'struct {{(.*)}}'}} 130 /// // expected-error-re {{variable has type 'struct{{[[:space:]](.*)}}'}} 131 /// \endcode 132 /// 133 /// VerifyDiagnosticConsumer expects at least one expected-* directive to 134 /// be found inside the source code. If no diagnostics are expected the 135 /// following directive can be used to indicate this: 136 /// 137 /// \code 138 /// // expected-no-diagnostics 139 /// \endcode 140 /// 141 class VerifyDiagnosticConsumer: public DiagnosticConsumer, 142 public CommentHandler { 143 public: 144 /// Directive - Abstract class representing a parsed verify directive. 145 /// 146 class Directive { 147 public: 148 static std::unique_ptr<Directive> create(bool RegexKind, 149 SourceLocation DirectiveLoc, 150 SourceLocation DiagnosticLoc, 151 bool MatchAnyLine, StringRef Text, 152 unsigned Min, unsigned Max); 153 154 public: 155 /// Constant representing n or more matches. 156 static const unsigned MaxCount = UINT_MAX; 157 158 SourceLocation DirectiveLoc; 159 SourceLocation DiagnosticLoc; 160 const std::string Text; 161 unsigned Min, Max; 162 bool MatchAnyLine; 163 ~Directive()164 virtual ~Directive() { } 165 166 // Returns true if directive text is valid. 167 // Otherwise returns false and populates E. 168 virtual bool isValid(std::string &Error) = 0; 169 170 // Returns true on match. 171 virtual bool match(StringRef S) = 0; 172 173 protected: Directive(SourceLocation DirectiveLoc,SourceLocation DiagnosticLoc,bool MatchAnyLine,StringRef Text,unsigned Min,unsigned Max)174 Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, 175 bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max) 176 : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), 177 Text(Text), Min(Min), Max(Max), MatchAnyLine(MatchAnyLine) { 178 assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!"); 179 assert(!DiagnosticLoc.isInvalid() && "DiagnosticLoc is invalid!"); 180 } 181 182 private: 183 Directive(const Directive &) = delete; 184 void operator=(const Directive &) = delete; 185 }; 186 187 typedef std::vector<std::unique_ptr<Directive>> DirectiveList; 188 189 /// ExpectedData - owns directive objects and deletes on destructor. 190 /// 191 struct ExpectedData { 192 DirectiveList Errors; 193 DirectiveList Warnings; 194 DirectiveList Remarks; 195 DirectiveList Notes; 196 ResetExpectedData197 void Reset() { 198 Errors.clear(); 199 Warnings.clear(); 200 Remarks.clear(); 201 Notes.clear(); 202 } 203 }; 204 205 enum DirectiveStatus { 206 HasNoDirectives, 207 HasNoDirectivesReported, 208 HasExpectedNoDiagnostics, 209 HasOtherExpectedDirectives 210 }; 211 212 private: 213 DiagnosticsEngine &Diags; 214 DiagnosticConsumer *PrimaryClient; 215 std::unique_ptr<DiagnosticConsumer> PrimaryClientOwner; 216 std::unique_ptr<TextDiagnosticBuffer> Buffer; 217 const Preprocessor *CurrentPreprocessor; 218 const LangOptions *LangOpts; 219 SourceManager *SrcManager; 220 unsigned ActiveSourceFiles; 221 DirectiveStatus Status; 222 ExpectedData ED; 223 224 void CheckDiagnostics(); setSourceManager(SourceManager & SM)225 void setSourceManager(SourceManager &SM) { 226 assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!"); 227 SrcManager = &SM; 228 } 229 230 // These facilities are used for validation in debug builds. 231 class UnparsedFileStatus { 232 llvm::PointerIntPair<const FileEntry *, 1, bool> Data; 233 public: UnparsedFileStatus(const FileEntry * File,bool FoundDirectives)234 UnparsedFileStatus(const FileEntry *File, bool FoundDirectives) 235 : Data(File, FoundDirectives) {} getFile()236 const FileEntry *getFile() const { return Data.getPointer(); } foundDirectives()237 bool foundDirectives() const { return Data.getInt(); } 238 }; 239 typedef llvm::DenseMap<FileID, const FileEntry *> ParsedFilesMap; 240 typedef llvm::DenseMap<FileID, UnparsedFileStatus> UnparsedFilesMap; 241 ParsedFilesMap ParsedFiles; 242 UnparsedFilesMap UnparsedFiles; 243 244 public: 245 /// Create a new verifying diagnostic client, which will issue errors to 246 /// the currently-attached diagnostic client when a diagnostic does not match 247 /// what is expected (as indicated in the source file). 248 VerifyDiagnosticConsumer(DiagnosticsEngine &Diags); 249 ~VerifyDiagnosticConsumer() override; 250 251 void BeginSourceFile(const LangOptions &LangOpts, 252 const Preprocessor *PP) override; 253 254 void EndSourceFile() override; 255 256 enum ParsedStatus { 257 /// File has been processed via HandleComment. 258 IsParsed, 259 260 /// File has diagnostics and may have directives. 261 IsUnparsed, 262 263 /// File has diagnostics but guaranteed no directives. 264 IsUnparsedNoDirectives 265 }; 266 267 /// \brief Update lists of parsed and unparsed files. 268 void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS); 269 270 bool HandleComment(Preprocessor &PP, SourceRange Comment) override; 271 272 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 273 const Diagnostic &Info) override; 274 }; 275 276 } // end namspace clang 277 278 #endif 279