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