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