output_segment.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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_OUTPUT_SEGMENT_H_
  5. #define CARBON_MIGRATE_CPP_OUTPUT_SEGMENT_H_
  6. #include <string>
  7. #include <type_traits>
  8. #include <utility>
  9. #include <variant>
  10. #include "clang/AST/ASTTypeTraits.h"
  11. #include "common/check.h"
  12. namespace Carbon {
  13. // Represents a segment of the output string. `OutputSegment`s come in two
  14. // flavors: Text and Node. A text segment holds string text that should be used
  15. // to be added to the output. A node segment holds a node in Clang's AST and
  16. // indicates that the output associated to that node should be the output
  17. // segment that the `RewriteBuilder` (defined below) has attached to that AST
  18. // node.
  19. //
  20. // For example, the output for a binary operator node corresponding to the C++
  21. // code snippet `f() + 3 * 5`, would be the sequence of three output segments:
  22. //
  23. // {Node(lhs), Text(" + "), Node(rhs)}
  24. //
  25. // The left-hand side and right-hand side can then be queried recursively to
  26. // determine what their output should be.
  27. class OutputSegment {
  28. public:
  29. // Returns whether or not the type T is an acceptable node type from which an
  30. // OutputSegment can be constructed. We intentionally do not want to support
  31. // `clang::Type` because we support traversing through `clang::TypeLoc`
  32. // instead. However, most other types we intend to support as they become
  33. // necessary.
  34. template <typename T>
  35. static constexpr auto IsSupportedClangASTNodeType() -> bool {
  36. return std::is_convertible_v<T*, clang::Stmt*> ||
  37. std::is_convertible_v<T*, clang::Decl*>;
  38. }
  39. // Creates a text-based `OutputSegment`.
  40. explicit OutputSegment(std::string content) : content_(std::move(content)) {}
  41. explicit OutputSegment(llvm::StringRef content) : content_(content.str()) {}
  42. explicit OutputSegment(const char* content) : content_(content) {}
  43. // Creates a node-based `OutputSegment` from `node`.
  44. explicit OutputSegment(const clang::DynTypedNode& node) : content_(node) {}
  45. template <typename T,
  46. std::enable_if_t<OutputSegment::IsSupportedClangASTNodeType<T>(),
  47. int> = 0>
  48. explicit OutputSegment(const T* node);
  49. // Creates a TypeLoc-based `OutputSegment` from `type_loc`.
  50. explicit OutputSegment(clang::TypeLoc type_loc)
  51. : content_(PassThroughQualifiedTypeLoc(type_loc)) {}
  52. private:
  53. friend struct OutputWriter;
  54. template <typename T>
  55. auto AssertNotNull(T* ptr) -> T& {
  56. CARBON_CHECK(ptr != nullptr);
  57. return *ptr;
  58. }
  59. // Traversals for TypeLocs have some sharp corners. In particular,
  60. // QualifiedTypeLocs are silently passed through to their unqualified part.
  61. // This means that when constructing output segments we also need to match
  62. // this behavior.
  63. static auto PassThroughQualifiedTypeLoc(clang::TypeLoc type_loc)
  64. -> clang::TypeLoc {
  65. auto qtl = type_loc.getAs<clang::QualifiedTypeLoc>();
  66. return qtl.isNull() ? type_loc : qtl.getUnqualifiedLoc();
  67. }
  68. std::variant<std::string, clang::DynTypedNode, clang::TypeLoc> content_;
  69. };
  70. template <typename T, std::enable_if_t<
  71. OutputSegment::IsSupportedClangASTNodeType<T>(), int>>
  72. OutputSegment::OutputSegment(const T* node)
  73. : content_(clang::DynTypedNode::create(AssertNotNull(node))) {}
  74. } // namespace Carbon
  75. #endif // CARBON_MIGRATE_CPP_OUTPUT_SEGMENT_H_