rewriter.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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 VisitImplicitCastExpr(clang::ImplicitCastExpr* expr) -> bool;
  90. auto VisitIntegerLiteral(clang::IntegerLiteral* expr) -> bool;
  91. auto VisitParmVarDecl(clang::ParmVarDecl* decl) -> bool;
  92. auto VisitPointerTypeLoc(clang::PointerTypeLoc type_loc) -> bool;
  93. auto VisitReturnStmt(clang::ReturnStmt* stmt) -> bool;
  94. auto VisitTranslationUnitDecl(clang::TranslationUnitDecl* decl) -> bool;
  95. auto VisitUnaryOperator(clang::UnaryOperator* expr) -> bool;
  96. auto TraverseFunctionDecl(clang::FunctionDecl* decl) -> bool;
  97. auto TraverseVarDecl(clang::VarDecl* decl) -> bool;
  98. auto segments() const -> const SegmentMapType& { return segments_; }
  99. auto segments() -> SegmentMapType& { return segments_; }
  100. private:
  101. // Associates `output_segments` in the output map `this->segments()` with the
  102. // key `node`, so as to declare that, when output is being written, `node`
  103. // should be replaced with the sequence of outputs described by
  104. // `output_segments`.
  105. auto SetReplacement(clang::DynTypedNode node,
  106. std::vector<OutputSegment> output_segments) -> void {
  107. segments_.try_emplace(node, std::move(output_segments));
  108. }
  109. auto SetReplacement(clang::TypeLoc node,
  110. std::vector<OutputSegment> output_segments) -> void {
  111. segments_.try_emplace(node, std::move(output_segments));
  112. }
  113. template <typename T>
  114. auto SetReplacement(const T* node, std::vector<OutputSegment> output_segments)
  115. -> void {
  116. segments_.try_emplace(clang::DynTypedNode::create(*node),
  117. std::move(output_segments));
  118. }
  119. // Invokes the overload of `SetReplacement` defined above. Equivalent to
  120. // `this->SetReplacement(node, std::vector<OutputSegment>(1, segment))`.
  121. template <typename T>
  122. auto SetReplacement(const T* node, OutputSegment segment) -> void {
  123. std::vector<OutputSegment> node_segments;
  124. node_segments.push_back(std::move(segment));
  125. SetReplacement(node, std::move(node_segments));
  126. }
  127. auto SetReplacement(clang::TypeLoc type_loc, OutputSegment segment) -> void {
  128. std::vector<OutputSegment> node_segments;
  129. node_segments.push_back(std::move(segment));
  130. SetReplacement(type_loc, std::move(node_segments));
  131. }
  132. // Returns a `llvm::StringRef` into the source text corresponding to the
  133. // half-open interval starting at `begin` (inclusive) and ending at `end`
  134. // (exclusive).
  135. auto TextFor(clang::SourceLocation begin, clang::SourceLocation end) const
  136. -> llvm::StringRef;
  137. // Returns a `llvm::StringRef` into the source text for the single token
  138. // located at `loc`.
  139. auto TextForTokenAt(clang::SourceLocation loc) const -> llvm::StringRef;
  140. clang::ASTContext& context_;
  141. SegmentMapType& segments_;
  142. };
  143. // An `ASTConsumer` which, when executed, populates a `std::string` with the
  144. // text of a Carbon source file which is a best approximation of of the
  145. // semantics of the corresponding C++ translation unit defined by the consumed
  146. // AST.
  147. class MigrationConsumer : public clang::ASTConsumer {
  148. public:
  149. explicit MigrationConsumer(std::string& result,
  150. std::pair<size_t, size_t> output_range)
  151. : result_(result), output_range_(output_range) {}
  152. auto HandleTranslationUnit(clang::ASTContext& context) -> void override;
  153. private:
  154. RewriteBuilder::SegmentMapType segment_map_;
  155. std::string& result_;
  156. std::pair<size_t, size_t> output_range_;
  157. };
  158. // An `ASTFrontendAction` which constructs a `MigrationConsumer` and invokes it
  159. // on an AST, populating a `std::string` with the text of a Carbon source file
  160. // which is a best approximation of of the semantics of the corresponding C++
  161. // translation unit defined by the consumed AST.
  162. class MigrationAction : public clang::ASTFrontendAction {
  163. public:
  164. // Constructs the `MigrationAction`. The parameter `result` is a reference to
  165. // the `std::string` where output will be written. Only output corresponding
  166. // to text at offsets that fall in between `output_range.first` and
  167. // `output_range.second` will be written.
  168. explicit MigrationAction(std::string& result,
  169. std::pair<size_t, size_t> output_range)
  170. : result_(result), output_range_(output_range) {}
  171. // Returns a `std::unique_ptr` to a `clang::MigrationConsumer` which populates
  172. // the output `result`.
  173. auto CreateASTConsumer(clang::CompilerInstance&, llvm::StringRef)
  174. -> std::unique_ptr<clang::ASTConsumer> override {
  175. return std::make_unique<MigrationConsumer>(result_, output_range_);
  176. }
  177. private:
  178. std::string& result_;
  179. std::pair<size_t, size_t> output_range_;
  180. };
  181. } // namespace Carbon
  182. #endif // CARBON_MIGRATE_CPP_REWRITER_H_