rewriter.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_MIGRATE_CPP_REWRITER_H_
  5. #define CARBON_MIGRATE_CPP_REWRITER_H_
  6. #include <string>
  7. #include <utility>
  8. #include <variant>
  9. #include <vector>
  10. #include "clang/AST/ASTConsumer.h"
  11. #include "clang/AST/ASTTypeTraits.h"
  12. #include "clang/AST/RecursiveASTVisitor.h"
  13. #include "clang/Frontend/CompilerInstance.h"
  14. #include "clang/Frontend/FrontendAction.h"
  15. #include "llvm/ADT/DenseMap.h"
  16. #include "migrate_cpp/output_segment.h"
  17. namespace Carbon {
  18. namespace Internal {
  19. struct Empty {
  20. friend bool operator==(Empty, Empty) { return true; }
  21. };
  22. struct Tombstone {
  23. friend bool operator==(Tombstone, Tombstone) { return true; }
  24. };
  25. // Type alias for the variant representing any of the values that can be
  26. // written with OutputWriter.
  27. using KeyType =
  28. std::variant<clang::DynTypedNode, clang::TypeLoc, Empty, Tombstone>;
  29. // `KeyInfo` is used as a template argument to `llvm::DenseMap` to specify how
  30. // to equality-compare and hash `KeyType`.
  31. struct KeyInfo {
  32. static bool isEqual(const KeyType& lhs, const KeyType& rhs) {
  33. return lhs == rhs;
  34. }
  35. static unsigned getHashValue(const KeyType& x) {
  36. return std::visit(
  37. [](auto x) -> unsigned {
  38. using type = std::decay_t<decltype(x)>;
  39. if constexpr (std::is_same_v<type, clang::DynTypedNode>) {
  40. return clang::DynTypedNode::DenseMapInfo::getHashValue(x);
  41. } else if constexpr (std::is_same_v<type, clang::TypeLoc>) {
  42. // TODO: Improve this.
  43. return reinterpret_cast<uintptr_t>(x.getTypePtr());
  44. } else {
  45. return 0;
  46. }
  47. },
  48. x);
  49. }
  50. static KeyType getEmptyKey() { return Empty{}; }
  51. static KeyType getTombstoneKey() { return Tombstone{}; }
  52. };
  53. } // namespace Internal
  54. // `OutputWriter` is responsible for traversing the tree of `OutputSegment`s
  55. // and writing the correct data to its member `output`.
  56. struct OutputWriter {
  57. using SegmentMapType =
  58. llvm::DenseMap<Internal::KeyType, std::vector<OutputSegment>,
  59. Internal::KeyInfo>;
  60. auto Write(clang::SourceLocation loc, const OutputSegment& segment) const
  61. -> bool;
  62. const SegmentMapType& map;
  63. // Bounds represent the offsets into the primary file (multi-file refactorings
  64. // are not yet supported) that should be output. While primarily this is a
  65. // mechanism to make testing more robust, it can also be used to make local
  66. // changes to sections of C++ code.
  67. std::pair<size_t, size_t> bounds;
  68. clang::SourceManager& source_manager;
  69. std::string& output;
  70. };
  71. // `RewriteBuilder` is a recursive AST visitor. For each node, it computes and
  72. // stores a sequence of `OutputSegment`s describing how this node should be
  73. // replaced.
  74. class RewriteBuilder : public clang::RecursiveASTVisitor<RewriteBuilder> {
  75. public:
  76. using SegmentMapType = typename OutputWriter::SegmentMapType;
  77. // Constructs a `RewriteBuilder` which can read the AST from `context` and
  78. // will write results into `segments`.
  79. explicit RewriteBuilder(clang::ASTContext& context, SegmentMapType& segments)
  80. : context_(context), segments_(segments) {}
  81. // By default, traverse children nodes before their parent. Called by the CRTP
  82. // base class to determine traversal order.
  83. auto shouldTraversePostOrder() const -> bool { return true; }
  84. // Visitor member functions, defining how each node should be processed.
  85. auto VisitBuiltinTypeLoc(clang::BuiltinTypeLoc type_loc) -> bool;
  86. auto VisitCXXBoolLiteralExpr(clang::CXXBoolLiteralExpr* expr) -> bool;
  87. auto VisitDeclRefExpr(clang::DeclRefExpr* expr) -> bool;
  88. auto VisitDeclStmt(clang::DeclStmt* stmt) -> bool;
  89. auto VisitIntegerLiteral(clang::IntegerLiteral* expr) -> bool;
  90. auto VisitPointerTypeLoc(clang::PointerTypeLoc type_loc) -> bool;
  91. auto VisitTranslationUnitDecl(clang::TranslationUnitDecl* decl) -> bool;
  92. auto VisitUnaryOperator(clang::UnaryOperator* expr) -> bool;
  93. auto VisitVarDecl(clang::VarDecl* decl) -> bool;
  94. auto segments() const -> const SegmentMapType& { return segments_; }
  95. auto segments() -> SegmentMapType& { return segments_; }
  96. private:
  97. // Associates `output_segments` in the output map `this->segments()` with the
  98. // key `node`, so as to declare that, when output is being written, `node`
  99. // should be replaced with the sequence of outputs described by
  100. // `output_segments`.
  101. auto SetReplacement(clang::DynTypedNode node,
  102. std::vector<OutputSegment> output_segments) -> void {
  103. segments_.try_emplace(node, std::move(output_segments));
  104. }
  105. auto SetReplacement(clang::TypeLoc node,
  106. std::vector<OutputSegment> output_segments) -> void {
  107. segments_.try_emplace(node, std::move(output_segments));
  108. }
  109. template <typename T>
  110. auto SetReplacement(const T* node, std::vector<OutputSegment> output_segments)
  111. -> void {
  112. segments_.try_emplace(clang::DynTypedNode::create(*node),
  113. std::move(output_segments));
  114. }
  115. // Invokes the overload of `SetReplacement` defined above. Equivalent to
  116. // `this->SetReplacement(node, std::vector<OutputSegment>(1, segment))`.
  117. template <typename T>
  118. auto SetReplacement(const T* node, OutputSegment segment) -> void {
  119. std::vector<OutputSegment> node_segments;
  120. node_segments.push_back(std::move(segment));
  121. SetReplacement(node, std::move(node_segments));
  122. }
  123. auto SetReplacement(clang::TypeLoc type_loc, OutputSegment segment) -> void {
  124. std::vector<OutputSegment> node_segments;
  125. node_segments.push_back(std::move(segment));
  126. SetReplacement(type_loc, std::move(node_segments));
  127. }
  128. // Returns a `llvm::StringRef` into the source text corresponding to the
  129. // half-open interval starting at `begin` (inclusive) and ending at `end`
  130. // (exclusive).
  131. auto TextFor(clang::SourceLocation begin, clang::SourceLocation end) const
  132. -> llvm::StringRef;
  133. // Returns a `llvm::StringRef` into the source text for the single token
  134. // located at `loc`.
  135. auto TextForTokenAt(clang::SourceLocation loc) const -> llvm::StringRef;
  136. clang::ASTContext& context_;
  137. SegmentMapType& segments_;
  138. };
  139. // An `ASTConsumer` which, when executed, populates a `std::string` with the
  140. // text of a Carbon source file which is a best approximation of of the
  141. // semantics of the corresponding C++ translation unit defined by the consumed
  142. // AST.
  143. class MigrationConsumer : public clang::ASTConsumer {
  144. public:
  145. explicit MigrationConsumer(std::string& result,
  146. std::pair<size_t, size_t> output_range)
  147. : result_(result), output_range_(output_range) {}
  148. auto HandleTranslationUnit(clang::ASTContext& context) -> void override;
  149. private:
  150. RewriteBuilder::SegmentMapType segment_map_;
  151. std::string& result_;
  152. std::pair<size_t, size_t> output_range_;
  153. };
  154. // An `ASTFrontendAction` which constructs a `MigrationConsumer` and invokes it
  155. // on an AST, populating a `std::string` with the text of a Carbon source file
  156. // which is a best approximation of of the semantics of the corresponding C++
  157. // translation unit defined by the consumed AST.
  158. class MigrationAction : public clang::ASTFrontendAction {
  159. public:
  160. // Constructs the `MigrationAction`. The parameter `result` is a reference to
  161. // the `std::string` where output will be written. Only output corresponding
  162. // to text at offsets that fall in between `output_range.first` and
  163. // `output_range.second` will be written.
  164. explicit MigrationAction(std::string& result,
  165. std::pair<size_t, size_t> output_range)
  166. : result_(result), output_range_(output_range) {}
  167. // Returns a `std::unique_ptr` to a `clang::MigrationConsumer` which populates
  168. // the output `result`.
  169. auto CreateASTConsumer(clang::CompilerInstance&, llvm::StringRef)
  170. -> std::unique_ptr<clang::ASTConsumer> override {
  171. return std::make_unique<MigrationConsumer>(result_, output_range_);
  172. }
  173. private:
  174. std::string& result_;
  175. std::pair<size_t, size_t> output_range_;
  176. };
  177. } // namespace Carbon
  178. #endif // CARBON_MIGRATE_CPP_REWRITER_H_