1 //===---------- IncludeInserter.h - clang-tidy ----------------------------===//
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_TOOLS_EXTRA_CLANG_TIDY_INCLUDEINSERTER_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDEINSERTER_H
11 
12 #include "IncludeSorter.h"
13 #include "clang/Basic/Diagnostic.h"
14 #include "llvm/ADT/StringSet.h"
15 #include <memory>
16 #include <optional>
17 
18 namespace clang {
19 class Preprocessor;
20 namespace tidy::utils {
21 
22 /// Produces fixes to insert specified includes to source files, if not
23 /// yet present.
24 ///
25 /// ``IncludeInserter`` can be used in clang-tidy checks in the following way:
26 /// \code
27 /// #include "../ClangTidyCheck.h"
28 /// #include "../utils/IncludeInserter.h"
29 ///
30 /// namespace clang {
31 /// namespace tidy {
32 ///
33 /// class MyCheck : public ClangTidyCheck {
34 ///  public:
35 ///   void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
36 ///                            Preprocessor *ModuleExpanderPP) override {
37 ///     Inserter.registerPreprocessor(PP);
38 ///   }
39 ///
40 ///   void registerMatchers(ast_matchers::MatchFinder* Finder) override { ... }
41 ///
42 ///   void check(
43 ///       const ast_matchers::MatchFinder::MatchResult& Result) override {
44 ///     ...
45 ///     Inserter.createMainFileIncludeInsertion("path/to/Header.h");
46 ///     ...
47 ///   }
48 ///
49 ///  private:
50 ///   utils::IncludeInserter Inserter{utils::IncludeSorter::IS_Google};
51 /// };
52 /// } // namespace tidy
53 /// } // namespace clang
54 /// \endcode
55 class IncludeInserter {
56 public:
57   /// Initializes the IncludeInserter using the IncludeStyle \p Style.
58   /// In most cases the \p Style will be retrieved from the ClangTidyOptions
59   /// using \code
60   ///   Options.getLocalOrGlobal("IncludeStyle", <DefaultStyle>)
61   /// \endcode
62   explicit IncludeInserter(IncludeSorter::IncludeStyle Style,
63                            bool SelfContainedDiags);
64 
65   /// Registers this with the Preprocessor \p PP, must be called before this
66   /// class is used.
67   void registerPreprocessor(Preprocessor *PP);
68 
69   /// Creates a \p Header inclusion directive fixit in the File \p FileID.
70   /// When \p Header is enclosed in angle brackets, uses angle brackets in the
71   /// inclusion directive, otherwise uses quotes.
72   /// Returns ``std::nullopt`` on error or if the inclusion directive already
73   /// exists.
74   std::optional<FixItHint> createIncludeInsertion(FileID FileID,
75                                                   llvm::StringRef Header);
76 
77   /// Creates a \p Header inclusion directive fixit in the main file.
78   /// When \p Header is enclosed in angle brackets, uses angle brackets in the
79   /// inclusion directive, otherwise uses quotes.
80   /// Returns ``std::nullopt`` on error or if the inclusion directive already
81   /// exists.
82   std::optional<FixItHint>
83   createMainFileIncludeInsertion(llvm::StringRef Header);
84 
getStyle()85   IncludeSorter::IncludeStyle getStyle() const { return Style; }
86 
87 private:
88   void addInclude(StringRef FileName, bool IsAngled,
89                   SourceLocation HashLocation, SourceLocation EndLocation);
90 
91   IncludeSorter &getOrCreate(FileID FileID);
92 
93   llvm::DenseMap<FileID, std::unique_ptr<IncludeSorter>> IncludeSorterByFile;
94   llvm::DenseMap<FileID, llvm::StringSet<>> InsertedHeaders;
95   const SourceManager *SourceMgr{nullptr};
96   const IncludeSorter::IncludeStyle Style;
97   const bool SelfContainedDiags;
98   friend class IncludeInserterCallback;
99 };
100 
101 } // namespace tidy::utils
102 } // namespace clang
103 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_INCLUDEINSERTER_H
104