rewriter.h 8.4 KB

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