1336815Sdim//===--- HeaderIncludes.h - Insert/Delete #includes for C++ code--*- C++-*-===// 2336815Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6336815Sdim// 7336815Sdim//===----------------------------------------------------------------------===// 8336815Sdim 9336815Sdim#ifndef LLVM_CLANG_TOOLING_INCLUSIONS_HEADERINCLUDES_H 10336815Sdim#define LLVM_CLANG_TOOLING_INCLUSIONS_HEADERINCLUDES_H 11336815Sdim 12336815Sdim#include "clang/Basic/SourceManager.h" 13336815Sdim#include "clang/Tooling/Core/Replacement.h" 14336815Sdim#include "clang/Tooling/Inclusions/IncludeStyle.h" 15336815Sdim#include "llvm/Support/Path.h" 16336815Sdim#include "llvm/Support/Regex.h" 17336815Sdim#include <unordered_map> 18336815Sdim 19336815Sdimnamespace clang { 20336815Sdimnamespace tooling { 21336815Sdim 22336815Sdim/// This class manages priorities of C++ #include categories and calculates 23336815Sdim/// priorities for headers. 24336815Sdim/// FIXME(ioeric): move this class into implementation file when clang-format's 25336815Sdim/// include sorting functions are also moved here. 26336815Sdimclass IncludeCategoryManager { 27336815Sdimpublic: 28336815Sdim IncludeCategoryManager(const IncludeStyle &Style, StringRef FileName); 29336815Sdim 30336815Sdim /// Returns the priority of the category which \p IncludeName belongs to. 31336815Sdim /// If \p CheckMainHeader is true and \p IncludeName is a main header, returns 32336815Sdim /// 0. Otherwise, returns the priority of the matching category or INT_MAX. 33336815Sdim /// NOTE: this API is not thread-safe! 34336815Sdim int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) const; 35360784Sdim int getSortIncludePriority(StringRef IncludeName, bool CheckMainHeader) const; 36336815Sdim 37336815Sdimprivate: 38336815Sdim bool isMainHeader(StringRef IncludeName) const; 39336815Sdim 40336815Sdim const IncludeStyle Style; 41336815Sdim bool IsMainFile; 42336815Sdim std::string FileName; 43336815Sdim // This refers to a substring in FileName. 44336815Sdim StringRef FileStem; 45360784Sdim SmallVector<llvm::Regex, 4> CategoryRegexs; 46336815Sdim}; 47336815Sdim 48336815Sdim/// Generates replacements for inserting or deleting #include directives in a 49336815Sdim/// file. 50336815Sdimclass HeaderIncludes { 51336815Sdimpublic: 52336815Sdim HeaderIncludes(llvm::StringRef FileName, llvm::StringRef Code, 53336815Sdim const IncludeStyle &Style); 54336815Sdim 55336815Sdim /// Inserts an #include directive of \p Header into the code. If \p IsAngled 56336815Sdim /// is true, \p Header will be quoted with <> in the directive; otherwise, it 57336815Sdim /// will be quoted with "". 58336815Sdim /// 59336815Sdim /// When searching for points to insert new header, this ignores #include's 60336815Sdim /// after the #include block(s) in the beginning of a file to avoid inserting 61336815Sdim /// headers into code sections where new #include's should not be added by 62336815Sdim /// default. These code sections include: 63336815Sdim /// - raw string literals (containing #include). 64336815Sdim /// - #if blocks. 65336815Sdim /// - Special #include's among declarations (e.g. functions). 66336815Sdim /// 67336815Sdim /// Returns a replacement that inserts the new header into a suitable #include 68336815Sdim /// block of the same category. This respects the order of the existing 69336815Sdim /// #includes in the block; if the existing #includes are not already sorted, 70336815Sdim /// this will simply insert the #include in front of the first #include of the 71336815Sdim /// same category in the code that should be sorted after \p IncludeName. If 72336815Sdim /// \p IncludeName already exists (with exactly the same spelling), this 73336815Sdim /// returns None. 74336815Sdim llvm::Optional<tooling::Replacement> insert(llvm::StringRef Header, 75336815Sdim bool IsAngled) const; 76336815Sdim 77336815Sdim /// Removes all existing #includes of \p Header quoted with <> if \p IsAngled 78336815Sdim /// is true or "" if \p IsAngled is false. 79336815Sdim /// This doesn't resolve the header file path; it only deletes #includes with 80336815Sdim /// exactly the same spelling. 81336815Sdim tooling::Replacements remove(llvm::StringRef Header, bool IsAngled) const; 82336815Sdim 83336815Sdimprivate: 84336815Sdim struct Include { 85336815Sdim Include(StringRef Name, tooling::Range R) : Name(Name), R(R) {} 86336815Sdim 87336815Sdim // An include header quoted with either <> or "". 88336815Sdim std::string Name; 89336815Sdim // The range of the whole line of include directive including any eading 90336815Sdim // whitespaces and trailing comment. 91336815Sdim tooling::Range R; 92336815Sdim }; 93336815Sdim 94336815Sdim void addExistingInclude(Include IncludeToAdd, unsigned NextLineOffset); 95336815Sdim 96336815Sdim std::string FileName; 97336815Sdim std::string Code; 98336815Sdim 99336815Sdim // Map from include name (quotation trimmed) to a list of existing includes 100336815Sdim // (in case there are more than one) with the name in the current file. <x> 101336815Sdim // and "x" will be treated as the same header when deleting #includes. 102336815Sdim llvm::StringMap<llvm::SmallVector<Include, 1>> ExistingIncludes; 103336815Sdim 104336815Sdim /// Map from priorities of #include categories to all #includes in the same 105336815Sdim /// category. This is used to find #includes of the same category when 106336815Sdim /// inserting new #includes. #includes in the same categories are sorted in 107336815Sdim /// in the order they appear in the source file. 108336815Sdim /// See comment for "FormatStyle::IncludeCategories" for details about include 109336815Sdim /// priorities. 110336815Sdim std::unordered_map<int, llvm::SmallVector<const Include *, 8>> 111336815Sdim IncludesByPriority; 112336815Sdim 113336815Sdim int FirstIncludeOffset; 114336815Sdim // All new headers should be inserted after this offset (e.g. after header 115336815Sdim // guards, file comment). 116336815Sdim unsigned MinInsertOffset; 117336815Sdim // Max insertion offset in the original code. For example, we want to avoid 118336815Sdim // inserting new #includes into the actual code section (e.g. after a 119336815Sdim // declaration). 120336815Sdim unsigned MaxInsertOffset; 121336815Sdim IncludeCategoryManager Categories; 122336815Sdim // Record the offset of the end of the last include in each category. 123336815Sdim std::unordered_map<int, int> CategoryEndOffsets; 124336815Sdim 125336815Sdim // All possible priorities. 126336815Sdim std::set<int> Priorities; 127336815Sdim 128336815Sdim // Matches a whole #include directive. 129336815Sdim llvm::Regex IncludeRegex; 130336815Sdim}; 131336815Sdim 132336815Sdim 133336815Sdim} // namespace tooling 134336815Sdim} // namespace clang 135336815Sdim 136336815Sdim#endif // LLVM_CLANG_TOOLING_INCLUSIONS_HEADERINCLUDES_H 137