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 12#include "clang/Basic/SourceManager.h" 13#include "clang/Tooling/Core/Replacement.h" 14#include "clang/Tooling/Inclusions/IncludeStyle.h" 15#include "llvm/Support/Path.h" 16#include "llvm/Support/Regex.h" 17#include <unordered_map> 18 19namespace clang { 20namespace tooling { 21 22/// This class manages priorities of C++ #include categories and calculates 23/// priorities for headers. 24/// FIXME(ioeric): move this class into implementation file when clang-format's 25/// include sorting functions are also moved here. 26class IncludeCategoryManager { 27public: 28 IncludeCategoryManager(const IncludeStyle &Style, StringRef FileName); 29 30 /// Returns the priority of the category which \p IncludeName belongs to. 31 /// If \p CheckMainHeader is true and \p IncludeName is a main header, returns 32 /// 0. Otherwise, returns the priority of the matching category or INT_MAX. 33 /// NOTE: this API is not thread-safe! 34 int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) const; 35 int getSortIncludePriority(StringRef IncludeName, bool CheckMainHeader) const; 36 37private: 38 bool isMainHeader(StringRef IncludeName) const; 39 40 const IncludeStyle Style; 41 bool IsMainFile; 42 std::string FileName; 43 // This refers to a substring in FileName. 44 StringRef FileStem; 45 SmallVector<llvm::Regex, 4> CategoryRegexs; 46}; 47 48/// Generates replacements for inserting or deleting #include directives in a 49/// file. 50class HeaderIncludes { 51public: 52 HeaderIncludes(llvm::StringRef FileName, llvm::StringRef Code, 53 const IncludeStyle &Style); 54 55 /// Inserts an #include directive of \p Header into the code. If \p IsAngled 56 /// is true, \p Header will be quoted with <> in the directive; otherwise, it 57 /// will be quoted with "". 58 /// 59 /// When searching for points to insert new header, this ignores #include's 60 /// after the #include block(s) in the beginning of a file to avoid inserting 61 /// headers into code sections where new #include's should not be added by 62 /// default. These code sections include: 63 /// - raw string literals (containing #include). 64 /// - #if blocks. 65 /// - Special #include's among declarations (e.g. functions). 66 /// 67 /// Returns a replacement that inserts the new header into a suitable #include 68 /// block of the same category. This respects the order of the existing 69 /// #includes in the block; if the existing #includes are not already sorted, 70 /// this will simply insert the #include in front of the first #include of the 71 /// same category in the code that should be sorted after \p IncludeName. If 72 /// \p IncludeName already exists (with exactly the same spelling), this 73 /// returns None. 74 llvm::Optional<tooling::Replacement> insert(llvm::StringRef Header, 75 bool IsAngled) const; 76 77 /// Removes all existing #includes of \p Header quoted with <> if \p IsAngled 78 /// is true or "" if \p IsAngled is false. 79 /// This doesn't resolve the header file path; it only deletes #includes with 80 /// exactly the same spelling. 81 tooling::Replacements remove(llvm::StringRef Header, bool IsAngled) const; 82 83private: 84 struct Include { 85 Include(StringRef Name, tooling::Range R) : Name(Name), R(R) {} 86 87 // An include header quoted with either <> or "". 88 std::string Name; 89 // The range of the whole line of include directive including any eading 90 // whitespaces and trailing comment. 91 tooling::Range R; 92 }; 93 94 void addExistingInclude(Include IncludeToAdd, unsigned NextLineOffset); 95 96 std::string FileName; 97 std::string Code; 98 99 // Map from include name (quotation trimmed) to a list of existing includes 100 // (in case there are more than one) with the name in the current file. <x> 101 // and "x" will be treated as the same header when deleting #includes. 102 llvm::StringMap<llvm::SmallVector<Include, 1>> ExistingIncludes; 103 104 /// Map from priorities of #include categories to all #includes in the same 105 /// category. This is used to find #includes of the same category when 106 /// inserting new #includes. #includes in the same categories are sorted in 107 /// in the order they appear in the source file. 108 /// See comment for "FormatStyle::IncludeCategories" for details about include 109 /// priorities. 110 std::unordered_map<int, llvm::SmallVector<const Include *, 8>> 111 IncludesByPriority; 112 113 int FirstIncludeOffset; 114 // All new headers should be inserted after this offset (e.g. after header 115 // guards, file comment). 116 unsigned MinInsertOffset; 117 // Max insertion offset in the original code. For example, we want to avoid 118 // inserting new #includes into the actual code section (e.g. after a 119 // declaration). 120 unsigned MaxInsertOffset; 121 IncludeCategoryManager Categories; 122 // Record the offset of the end of the last include in each category. 123 std::unordered_map<int, int> CategoryEndOffsets; 124 125 // All possible priorities. 126 std::set<int> Priorities; 127 128 // Matches a whole #include directive. 129 llvm::Regex IncludeRegex; 130}; 131 132 133} // namespace tooling 134} // namespace clang 135 136#endif // LLVM_CLANG_TOOLING_INCLUSIONS_HEADERINCLUDES_H 137