Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  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.
  36. ///
  37. /// INVOKING THE DIAGNOSTIC CHECKER:
  38. ///
  39. /// VerifyDiagnosticConsumer is typically invoked via the "-verify" option to
  40. /// "clang -cc1".  "-verify" is equivalent to "-verify=expected", so all
  41. /// diagnostics are typically specified with the prefix "expected".  For
  42. /// example:
  43. ///
  44. /// \code
  45. ///   int A = B; // expected-error {{use of undeclared identifier 'B'}}
  46. /// \endcode
  47. ///
  48. /// Custom prefixes can be specified as a comma-separated sequence.  Each
  49. /// prefix must start with a letter and contain only alphanumeric characters,
  50. /// hyphens, and underscores.  For example, given just "-verify=foo,bar",
  51. /// the above diagnostic would be ignored, but the following diagnostics would
  52. /// be recognized:
  53. ///
  54. /// \code
  55. ///   int A = B; // foo-error {{use of undeclared identifier 'B'}}
  56. ///   int C = D; // bar-error {{use of undeclared identifier 'D'}}
  57. /// \endcode
  58. ///
  59. /// Multiple occurrences accumulate prefixes.  For example,
  60. /// "-verify -verify=foo,bar -verify=baz" is equivalent to
  61. /// "-verify=expected,foo,bar,baz".
  62. ///
  63. /// SPECIFYING DIAGNOSTICS:
  64. ///
  65. /// Indicating that a line expects an error or a warning is simple. Put a
  66. /// comment on the line that has the diagnostic, use:
  67. ///
  68. /// \code
  69. ///   expected-{error,warning,remark,note}
  70. /// \endcode
  71. ///
  72. /// to tag if it's an expected error, remark or warning, and place the expected
  73. /// text between {{ and }} markers. The full text doesn't have to be included,
  74. /// only enough to ensure that the correct diagnostic was emitted.
  75. ///
  76. /// Here's an example:
  77. ///
  78. /// \code
  79. ///   int A = B; // expected-error {{use of undeclared identifier 'B'}}
  80. /// \endcode
  81. ///
  82. /// You can place as many diagnostics on one line as you wish. To make the code
  83. /// more readable, you can use slash-newline to separate out the diagnostics.
  84. ///
  85. /// Alternatively, it is possible to specify the line on which the diagnostic
  86. /// should appear by appending "@<line>" to "expected-<type>", for example:
  87. ///
  88. /// \code
  89. ///   #warning some text
  90. ///   // expected-warning@10 {{some text}}
  91. /// \endcode
  92. ///
  93. /// The line number may be absolute (as above), or relative to the current
  94. /// line by prefixing the number with either '+' or '-'.
  95. ///
  96. /// If the diagnostic is generated in a separate file, for example in a shared
  97. /// header file, it may be beneficial to be able to declare the file in which
  98. /// the diagnostic will appear, rather than placing the expected-* directive in
  99. /// the actual file itself.  This can be done using the following syntax:
  100. ///
  101. /// \code
  102. ///   // expected-error@path/include.h:15 {{error message}}
  103. /// \endcode
  104. ///
  105. /// The path can be absolute or relative and the same search paths will be used
  106. /// as for #include directives.  The line number in an external file may be
  107. /// substituted with '*' meaning that any line number will match (useful where
  108. /// the included file is, for example, a system header where the actual line
  109. /// number may change and is not critical).
  110. ///
  111. /// As an alternative to specifying a fixed line number, the location of a
  112. /// diagnostic can instead be indicated by a marker of the form "#<marker>".
  113. /// Markers are specified by including them in a comment, and then referenced
  114. /// by appending the marker to the diagnostic with "@#<marker>":
  115. ///
  116. /// \code
  117. ///   #warning some text  // #1
  118. ///   // expected-warning@#1 {{some text}}
  119. /// \endcode
  120. ///
  121. /// The name of a marker used in a directive must be unique within the
  122. /// compilation.
  123. ///
  124. /// The simple syntax above allows each specification to match exactly one
  125. /// error.  You can use the extended syntax to customize this. The extended
  126. /// syntax is "expected-<type> <n> {{diag text}}", where \<type> is one of
  127. /// "error", "warning" or "note", and \<n> is a positive integer. This allows
  128. /// the diagnostic to appear as many times as specified. Example:
  129. ///
  130. /// \code
  131. ///   void f(); // expected-note 2 {{previous declaration is here}}
  132. /// \endcode
  133. ///
  134. /// Where the diagnostic is expected to occur a minimum number of times, this
  135. /// can be specified by appending a '+' to the number. Example:
  136. ///
  137. /// \code
  138. ///   void f(); // expected-note 0+ {{previous declaration is here}}
  139. ///   void g(); // expected-note 1+ {{previous declaration is here}}
  140. /// \endcode
  141. ///
  142. /// In the first example, the diagnostic becomes optional, i.e. it will be
  143. /// swallowed if it occurs, but will not generate an error if it does not
  144. /// occur.  In the second example, the diagnostic must occur at least once.
  145. /// As a short-hand, "one or more" can be specified simply by '+'. Example:
  146. ///
  147. /// \code
  148. ///   void g(); // expected-note + {{previous declaration is here}}
  149. /// \endcode
  150. ///
  151. /// A range can also be specified by "<n>-<m>".  Example:
  152. ///
  153. /// \code
  154. ///   void f(); // expected-note 0-1 {{previous declaration is here}}
  155. /// \endcode
  156. ///
  157. /// In this example, the diagnostic may appear only once, if at all.
  158. ///
  159. /// Regex matching mode may be selected by appending '-re' to type and
  160. /// including regexes wrapped in double curly braces in the directive, such as:
  161. ///
  162. /// \code
  163. ///   expected-error-re {{format specifies type 'wchar_t **' (aka '{{.+}}')}}
  164. /// \endcode
  165. ///
  166. /// Examples matching error: "variable has incomplete type 'struct s'"
  167. ///
  168. /// \code
  169. ///   // expected-error {{variable has incomplete type 'struct s'}}
  170. ///   // expected-error {{variable has incomplete type}}
  171. ///
  172. ///   // expected-error-re {{variable has type 'struct {{.}}'}}
  173. ///   // expected-error-re {{variable has type 'struct {{.*}}'}}
  174. ///   // expected-error-re {{variable has type 'struct {{(.*)}}'}}
  175. ///   // expected-error-re {{variable has type 'struct{{[[:space:]](.*)}}'}}
  176. /// \endcode
  177. ///
  178. /// VerifyDiagnosticConsumer expects at least one expected-* directive to
  179. /// be found inside the source code.  If no diagnostics are expected the
  180. /// following directive can be used to indicate this:
  181. ///
  182. /// \code
  183. ///   // expected-no-diagnostics
  184. /// \endcode
  185. ///
  186. class VerifyDiagnosticConsumer: public DiagnosticConsumer,
  187.                                 public CommentHandler {
  188. public:
  189.   /// Directive - Abstract class representing a parsed verify directive.
  190.   ///
  191.   class Directive {
  192.   public:
  193.     static std::unique_ptr<Directive>
  194.     create(bool RegexKind, SourceLocation DirectiveLoc,
  195.            SourceLocation DiagnosticLoc, bool MatchAnyFileAndLine,
  196.            bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max);
  197.  
  198.   public:
  199.     /// Constant representing n or more matches.
  200.     static const unsigned MaxCount = std::numeric_limits<unsigned>::max();
  201.  
  202.     SourceLocation DirectiveLoc;
  203.     SourceLocation DiagnosticLoc;
  204.     const std::string Text;
  205.     unsigned Min, Max;
  206.     bool MatchAnyLine;
  207.     bool MatchAnyFileAndLine; // `MatchAnyFileAndLine` implies `MatchAnyLine`.
  208.  
  209.     Directive(const Directive &) = delete;
  210.     Directive &operator=(const Directive &) = delete;
  211.     virtual ~Directive() = default;
  212.  
  213.     // Returns true if directive text is valid.
  214.     // Otherwise returns false and populates E.
  215.     virtual bool isValid(std::string &Error) = 0;
  216.  
  217.     // Returns true on match.
  218.     virtual bool match(StringRef S) = 0;
  219.  
  220.   protected:
  221.     Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
  222.               bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
  223.               unsigned Min, unsigned Max)
  224.         : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), Text(Text),
  225.           Min(Min), Max(Max), MatchAnyLine(MatchAnyLine || MatchAnyFileAndLine),
  226.           MatchAnyFileAndLine(MatchAnyFileAndLine) {
  227.       assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!");
  228.       assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) &&
  229.              "DiagnosticLoc is invalid!");
  230.     }
  231.   };
  232.  
  233.   using DirectiveList = std::vector<std::unique_ptr<Directive>>;
  234.  
  235.   /// ExpectedData - owns directive objects and deletes on destructor.
  236.   struct ExpectedData {
  237.     DirectiveList Errors;
  238.     DirectiveList Warnings;
  239.     DirectiveList Remarks;
  240.     DirectiveList Notes;
  241.  
  242.     void Reset() {
  243.       Errors.clear();
  244.       Warnings.clear();
  245.       Remarks.clear();
  246.       Notes.clear();
  247.     }
  248.   };
  249.  
  250.   enum DirectiveStatus {
  251.     HasNoDirectives,
  252.     HasNoDirectivesReported,
  253.     HasExpectedNoDiagnostics,
  254.     HasOtherExpectedDirectives
  255.   };
  256.  
  257.   class MarkerTracker;
  258.  
  259. private:
  260.   DiagnosticsEngine &Diags;
  261.   DiagnosticConsumer *PrimaryClient;
  262.   std::unique_ptr<DiagnosticConsumer> PrimaryClientOwner;
  263.   std::unique_ptr<TextDiagnosticBuffer> Buffer;
  264.   std::unique_ptr<MarkerTracker> Markers;
  265.   const Preprocessor *CurrentPreprocessor = nullptr;
  266.   const LangOptions *LangOpts = nullptr;
  267.   SourceManager *SrcManager = nullptr;
  268.   unsigned ActiveSourceFiles = 0;
  269.   DirectiveStatus Status;
  270.   ExpectedData ED;
  271.  
  272.   void CheckDiagnostics();
  273.  
  274.   void setSourceManager(SourceManager &SM) {
  275.     assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!");
  276.     SrcManager = &SM;
  277.   }
  278.  
  279.   // These facilities are used for validation in debug builds.
  280.   class UnparsedFileStatus {
  281.     llvm::PointerIntPair<const FileEntry *, 1, bool> Data;
  282.  
  283.   public:
  284.     UnparsedFileStatus(const FileEntry *File, bool FoundDirectives)
  285.         : Data(File, FoundDirectives) {}
  286.  
  287.     const FileEntry *getFile() const { return Data.getPointer(); }
  288.     bool foundDirectives() const { return Data.getInt(); }
  289.   };
  290.  
  291.   using ParsedFilesMap = llvm::DenseMap<FileID, const FileEntry *>;
  292.   using UnparsedFilesMap = llvm::DenseMap<FileID, UnparsedFileStatus>;
  293.  
  294.   ParsedFilesMap ParsedFiles;
  295.   UnparsedFilesMap UnparsedFiles;
  296.  
  297. public:
  298.   /// Create a new verifying diagnostic client, which will issue errors to
  299.   /// the currently-attached diagnostic client when a diagnostic does not match
  300.   /// what is expected (as indicated in the source file).
  301.   VerifyDiagnosticConsumer(DiagnosticsEngine &Diags);
  302.   ~VerifyDiagnosticConsumer() override;
  303.  
  304.   void BeginSourceFile(const LangOptions &LangOpts,
  305.                        const Preprocessor *PP) override;
  306.  
  307.   void EndSourceFile() override;
  308.  
  309.   enum ParsedStatus {
  310.     /// File has been processed via HandleComment.
  311.     IsParsed,
  312.  
  313.     /// File has diagnostics and may have directives.
  314.     IsUnparsed,
  315.  
  316.     /// File has diagnostics but guaranteed no directives.
  317.     IsUnparsedNoDirectives
  318.   };
  319.  
  320.   /// Update lists of parsed and unparsed files.
  321.   void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS);
  322.  
  323.   bool HandleComment(Preprocessor &PP, SourceRange Comment) override;
  324.  
  325.   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
  326.                         const Diagnostic &Info) override;
  327. };
  328.  
  329. } // namespace clang
  330.  
  331. #endif // LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H
  332.