clang 24.0.0git
HeaderIncludes.h
Go to the documentation of this file.
1//===--- HeaderIncludes.h - Insert/Delete #includes for C++ code--*- 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_TOOLING_INCLUSIONS_HEADERINCLUDES_H
10#define LLVM_CLANG_TOOLING_INCLUSIONS_HEADERINCLUDES_H
11
14#include "llvm/ADT/ArrayRef.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/ADT/StringMap.h"
17#include "llvm/Support/Regex.h"
18#include <list>
19#include <optional>
20#include <set>
21#include <string>
22#include <unordered_map>
23
24namespace clang {
25namespace tooling {
26
27/// This class manages priorities of C++ #include categories and calculates
28/// priorities for headers.
29/// FIXME(ioeric): move this class into implementation file when clang-format's
30/// include sorting functions are also moved here.
32public:
33 IncludeCategoryManager(const IncludeStyle &Style, StringRef FileName);
34
35 /// Returns the priority of the category which \p IncludeName belongs to.
36 /// If \p CheckMainHeader is true and \p IncludeName is a main header, returns
37 /// 0. Otherwise, returns the priority of the matching category or INT_MAX.
38 /// NOTE: this API is not thread-safe!
39 int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) const;
40 int getSortIncludePriority(StringRef IncludeName, bool CheckMainHeader) const;
41
42private:
43 bool isMainHeader(StringRef IncludeName) const;
44
45 const IncludeStyle Style;
46 bool IsMainFile;
47 std::string FileName;
48 SmallVector<llvm::Regex, 4> CategoryRegexs;
49};
50
52
53/// Generates replacements for inserting or deleting #include directives in a
54/// file.
56public:
57 HeaderIncludes(llvm::StringRef FileName, llvm::StringRef Code,
58 const IncludeStyle &Style);
59
60 /// Inserts an #include or #import directive of \p Header into the code.
61 /// If \p IsAngled is true, \p Header will be quoted with <> in the directive;
62 /// otherwise, it will be quoted with "".
63 ///
64 /// When searching for points to insert new header, this ignores #include's
65 /// after the #include block(s) in the beginning of a file to avoid inserting
66 /// headers into code sections where new #include's should not be added by
67 /// default. These code sections include:
68 /// - raw string literals (containing #include).
69 /// - #if blocks.
70 /// - Special #includes among declarations (e.g. functions).
71 ///
72 /// Returns a replacement that inserts the new header into a suitable #include
73 /// block of the same category. This respects the order of the existing
74 /// #includes in the block; if the existing #includes are not already sorted,
75 /// this will simply insert the #include in front of the first #include of the
76 /// same category in the code that should be sorted after \p IncludeName. If
77 /// \p IncludeName already exists (with exactly the same spelling), this
78 /// returns std::nullopt.
79 std::optional<tooling::Replacement> insert(llvm::StringRef Header,
80 bool IsAngled,
82
83 /// Represents a single header directive to be inserted in a batch operation.
84 ///
85 /// Usage:
86 /// - HeaderToInsert("<vector>") -> inserts #include <vector>
87 /// (auto-detects angled)
88 /// - HeaderToInsert("\"foo.h\"") -> inserts #include "foo.h"
89 /// (auto-detects quoted)
90 /// - HeaderToInsert("<foo>", IncludeDirective::Import) -> inserts #import
91 /// <foo>
92 /// - HeaderToInsert("foo.h", IncludeDirective::Include, /*IsAngled=*/false)
93 /// -> explicit IsAngled
95 enum class QuoteStyle { AUTO, ANGLED, QUOTED };
96
97 // The header name, with any surrounding quotes or brackets removed.
98 std::string Header;
99 // Whether to insert #include or #import.
101 // Whether to use <> or "" for the header. This can be set explicitly with
102 // QuoteStyle::ANGLED or QuoteStyle::QUOTED, or auto-detected based on
103 // `RawOrSpelledHeader` with QuoteStyle::AUTO.
105
106 HeaderToInsert(llvm::StringRef RawOrSpelledHeader,
109 };
110
111 /// Inserts a batch of headers into the code, sorting and grouping them
112 /// according to IncludeStyle and returning the replacements.
114
115 /// Removes all existing #includes and #imports of \p Header quoted with <> if
116 /// \p IsAngled is true or "" if \p IsAngled is false.
117 /// This doesn't resolve the header file path; it only deletes #includes and
118 /// #imports with exactly the same spelling.
119 tooling::Replacements remove(llvm::StringRef Header, bool IsAngled) const;
120
121 // Matches a whole #include directive.
122 static const llvm::Regex IncludeRegex;
123
124private:
125 struct Include {
126 Include(llvm::StringRef Name, tooling::Range R, IncludeDirective D)
127 : Name(Name), R(R), Directive(D) {}
128
129 // An include header quoted with either <> or "".
130 std::string Name;
131 // The range of the whole line of include directive including any leading
132 // whitespaces and trailing comment.
134 // Either #include or #import.
136 };
137
138 void addExistingInclude(Include IncludeToAdd, unsigned NextLineOffset);
139
140 std::string FileName;
141 std::string Code;
142
143 // Map from include name (quotation trimmed) to a list of existing includes
144 // (in case there are more than one) with the name in the current file. <x>
145 // and "x" will be treated as the same header when deleting #includes.
146 // std::list is used for pointers stability (see IncludesByPriority)
147 llvm::StringMap<std::list<Include>> ExistingIncludes;
148
149 /// Map from priorities of #include categories to all #includes in the same
150 /// category. This is used to find #includes of the same category when
151 /// inserting new #includes. #includes in the same categories are sorted in
152 /// in the order they appear in the source file.
153 /// See comment for "FormatStyle::IncludeCategories" for details about include
154 /// priorities.
155 std::unordered_map<int, llvm::SmallVector<const Include *, 8>>
156 IncludesByPriority;
157
158 int FirstIncludeOffset;
159 // All new headers should be inserted after this offset (e.g. after header
160 // guards, file comment).
161 unsigned MinInsertOffset;
162 // Max insertion offset in the original code. For example, we want to avoid
163 // inserting new #includes into the actual code section (e.g. after a
164 // declaration).
165 unsigned MaxInsertOffset;
166 // True if we find the main-file header in the Code.
167 bool MainIncludeFound;
168 // True if header insertion should also insert a C++20 global module fragment
169 // declaration (i.e. a 'module;' declaration).
170 bool ShouldInsertGlobalModuleFragmentDecl;
171 IncludeCategoryManager Categories;
172 // Record the offset of the end of the last include in each category.
173 std::unordered_map<int, int> CategoryEndOffsets;
174
175 // All possible priorities.
176 std::set<int> Priorities;
177};
178
179} // namespace tooling
180} // namespace clang
181
182#endif // LLVM_CLANG_TOOLING_INCLUSIONS_HEADERINCLUDES_H
VerifyDiagnosticConsumer::Directive Directive
tooling::Replacements remove(llvm::StringRef Header, bool IsAngled) const
Removes all existing includes and imports of Header quoted with <> if IsAngled is true or "" if IsAng...
static const llvm::Regex IncludeRegex
HeaderIncludes(llvm::StringRef FileName, llvm::StringRef Code, const IncludeStyle &Style)
std::optional< tooling::Replacement > insert(llvm::StringRef Header, bool IsAngled, IncludeDirective Directive) const
Inserts an include or import directive of Header into the code.
This class manages priorities of C++ include categories and calculates priorities for headers.
int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) const
Returns the priority of the category which IncludeName belongs to.
IncludeCategoryManager(const IncludeStyle &Style, StringRef FileName)
int getSortIncludePriority(StringRef IncludeName, bool CheckMainHeader) const
A source range independent of the SourceManager.
Definition Replacement.h:44
Maintains a set of replacements that are conflict-free.
Top level wrappers for InstallAPI frontend operations.
HeaderToInsert(llvm::StringRef RawOrSpelledHeader, IncludeDirective Directive=IncludeDirective::Include, QuoteStyle QuoteStyle=QuoteStyle::AUTO)
Style for sorting and grouping C++ include directives.