reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
//===--- HeaderIncludes.h - Insert/Delete #includes for C++ code--*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLING_INCLUSIONS_HEADERINCLUDES_H
#define LLVM_CLANG_TOOLING_INCLUSIONS_HEADERINCLUDES_H

#include "clang/Basic/SourceManager.h"
#include "clang/Tooling/Core/Replacement.h"
#include "clang/Tooling/Inclusions/IncludeStyle.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Regex.h"
#include <unordered_map>

namespace clang {
namespace tooling {

/// This class manages priorities of C++ #include categories and calculates
/// priorities for headers.
/// FIXME(ioeric): move this class into implementation file when clang-format's
/// include sorting functions are also moved here.
class IncludeCategoryManager {
public:
  IncludeCategoryManager(const IncludeStyle &Style, StringRef FileName);

  /// Returns the priority of the category which \p IncludeName belongs to.
  /// If \p CheckMainHeader is true and \p IncludeName is a main header, returns
  /// 0. Otherwise, returns the priority of the matching category or INT_MAX.
  /// NOTE: this API is not thread-safe!
  int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) const;
  int getSortIncludePriority(StringRef IncludeName, bool CheckMainHeader) const;

private:
  bool isMainHeader(StringRef IncludeName) const;

  const IncludeStyle Style;
  bool IsMainFile;
  std::string FileName;
  // This refers to a substring in FileName.
  StringRef FileStem;
  // Regex is not thread-safe.
  mutable SmallVector<llvm::Regex, 4> CategoryRegexs;
};

/// Generates replacements for inserting or deleting #include directives in a
/// file.
class HeaderIncludes {
public:
  HeaderIncludes(llvm::StringRef FileName, llvm::StringRef Code,
                 const IncludeStyle &Style);

  /// Inserts an #include directive of \p Header into the code. If \p IsAngled
  /// is true, \p Header will be quoted with <> in the directive; otherwise, it
  /// will be quoted with "".
  ///
  /// When searching for points to insert new header, this ignores #include's
  /// after the #include block(s) in the beginning of a file to avoid inserting
  /// headers into code sections where new #include's should not be added by
  /// default. These code sections include:
  ///   - raw string literals (containing #include).
  ///   - #if blocks.
  ///   - Special #include's among declarations (e.g. functions).
  ///
  /// Returns a replacement that inserts the new header into a suitable #include
  /// block of the same category. This respects the order of the existing
  /// #includes in the block; if the existing #includes are not already sorted,
  /// this will simply insert the #include in front of the first #include of the
  /// same category in the code that should be sorted after \p IncludeName. If
  /// \p IncludeName already exists (with exactly the same spelling), this
  /// returns None.
  llvm::Optional<tooling::Replacement> insert(llvm::StringRef Header,
                                              bool IsAngled) const;

  /// Removes all existing #includes of \p Header quoted with <> if \p IsAngled
  /// is true or "" if \p IsAngled is false.
  /// This doesn't resolve the header file path; it only deletes #includes with
  /// exactly the same spelling.
  tooling::Replacements remove(llvm::StringRef Header, bool IsAngled) const;

private:
  struct Include {
    Include(StringRef Name, tooling::Range R) : Name(Name), R(R) {}

    // An include header quoted with either <> or "".
    std::string Name;
    // The range of the whole line of include directive including any eading
    // whitespaces and trailing comment.
    tooling::Range R;
  };

  void addExistingInclude(Include IncludeToAdd, unsigned NextLineOffset);

  std::string FileName;
  std::string Code;

  // Map from include name (quotation trimmed) to a list of existing includes
  // (in case there are more than one) with the name in the current file. <x>
  // and "x" will be treated as the same header when deleting #includes.
  llvm::StringMap<llvm::SmallVector<Include, 1>> ExistingIncludes;

  /// Map from priorities of #include categories to all #includes in the same
  /// category. This is used to find #includes of the same category when
  /// inserting new #includes. #includes in the same categories are sorted in
  /// in the order they appear in the source file.
  /// See comment for "FormatStyle::IncludeCategories" for details about include
  /// priorities.
  std::unordered_map<int, llvm::SmallVector<const Include *, 8>>
      IncludesByPriority;

  int FirstIncludeOffset;
  // All new headers should be inserted after this offset (e.g. after header
  // guards, file comment).
  unsigned MinInsertOffset;
  // Max insertion offset in the original code. For example, we want to avoid
  // inserting new #includes into the actual code section (e.g. after a
  // declaration).
  unsigned MaxInsertOffset;
  IncludeCategoryManager Categories;
  // Record the offset of the end of the last include in each category.
  std::unordered_map<int, int> CategoryEndOffsets;

  // All possible priorities.
  std::set<int> Priorities;

  // Matches a whole #include directive.
  llvm::Regex IncludeRegex;
};


} // namespace tooling
} // namespace clang

#endif // LLVM_CLANG_TOOLING_INCLUSIONS_HEADERINCLUDES_H