blob: f221036acb44aa999fb7204311946476b0d4fa43 [file] [log] [blame]
Michael Forsterb3503e02022-04-25 00:24:14 -07001// Part of the Crubit 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 CRUBIT_RS_BINDINGS_FROM_CC_DECL_IMPORTER_H_
6#define CRUBIT_RS_BINDINGS_FROM_CC_DECL_IMPORTER_H_
7
Devin Jeanpierre257f0f62023-05-08 11:52:01 -07008#include <memory>
Googlera6c60bb2022-12-20 07:32:17 -08009#include <optional>
Devin Jeanpierre257f0f62023-05-08 11:52:01 -070010#include <set>
11#include <string>
12#include <vector>
Googlera6c60bb2022-12-20 07:32:17 -080013
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070014#include "absl/container/flat_hash_map.h"
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -070015#include "absl/log/check.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070016#include "absl/status/statusor.h"
Michael Forsterb3503e02022-04-25 00:24:14 -070017#include "lifetime_annotations/lifetime_annotations.h"
18#include "rs_bindings_from_cc/bazel_types.h"
19#include "rs_bindings_from_cc/ir.h"
Googler1bff6372023-03-24 10:06:29 -070020#include "clang/AST/Type.h"
Michael Forsterb3503e02022-04-25 00:24:14 -070021
22namespace crubit {
23
24// Top-level parameters as well as return value of an importer invocation.
25class Invocation {
26 public:
Lukasz Anforowicz121338a2022-11-01 14:28:32 -070027 Invocation(BazelLabel target, absl::Span<const HeaderName> public_headers,
Devin Jeanpierre7571ece2023-01-13 11:39:26 -080028 const absl::flat_hash_map<HeaderName, BazelLabel>& header_targets)
Michael Forsterb3503e02022-04-25 00:24:14 -070029 : target_(target),
Lukasz Anforowicz121338a2022-11-01 14:28:32 -070030 public_headers_(public_headers),
Michael Forsterb3503e02022-04-25 00:24:14 -070031 lifetime_context_(std::make_shared<
32 clang::tidy::lifetimes::LifetimeAnnotationContext>()),
33 header_targets_(header_targets) {
34 // Caller should verify that the inputs are non-empty.
Lukasz Anforowicz121338a2022-11-01 14:28:32 -070035 CHECK(!public_headers_.empty());
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -070036 CHECK(!header_targets_.empty());
Michael Forsterb3503e02022-04-25 00:24:14 -070037
Lukasz Anforowicz121338a2022-11-01 14:28:32 -070038 ir_.public_headers.insert(ir_.public_headers.end(), public_headers_.begin(),
39 public_headers.end());
Michael Forsterb3503e02022-04-25 00:24:14 -070040 ir_.current_target = target_;
41 }
42
43 // Returns the target of a header, if any.
44 std::optional<BazelLabel> header_target(const HeaderName header) const {
45 auto it = header_targets_.find(header);
46 return (it != header_targets_.end()) ? std::optional(it->second)
47 : std::nullopt;
48 }
49
50 // The main target from which we are importing.
51 const BazelLabel target_;
52
Lukasz Anforowicz121338a2022-11-01 14:28:32 -070053 // The headers from which the import starts. See the doc comment of
54 // `IR::public_headers` and `HeaderName` for more details.
55 const absl::Span<const HeaderName> public_headers_;
Michael Forsterb3503e02022-04-25 00:24:14 -070056
57 const std::shared_ptr<clang::tidy::lifetimes::LifetimeAnnotationContext>
58 lifetime_context_;
59
60 // The main output of the import process
61 IR ir_;
62
63 private:
Devin Jeanpierre7571ece2023-01-13 11:39:26 -080064 const absl::flat_hash_map<HeaderName, BazelLabel>& header_targets_;
Michael Forsterb3503e02022-04-25 00:24:14 -070065};
66
Michael Forsterb3503e02022-04-25 00:24:14 -070067// Explicitly defined interface that defines how `DeclImporter`s are allowed to
68// interface with the global state of the importer.
69class ImportContext {
70 public:
71 ImportContext(Invocation& invocation, clang::ASTContext& ctx,
72 clang::Sema& sema)
Lukasz Anforowiczff16f642022-05-27 16:56:50 -070073 : invocation_(invocation), ctx_(ctx), sema_(sema) {}
Devin Jeanpierre257f0f62023-05-08 11:52:01 -070074 virtual ~ImportContext() = default;
Michael Forsterb3503e02022-04-25 00:24:14 -070075
76 // Imports all decls contained in a `DeclContext`.
77 virtual void ImportDeclsFromDeclContext(
78 const clang::DeclContext* decl_context) = 0;
79
80 // Imports an unsupported item with a single error message.
81 virtual IR::Item ImportUnsupportedItem(const clang::Decl* decl,
82 std::string error) = 0;
83
84 // Imports an unsupported item with multiple error messages.
85 virtual IR::Item ImportUnsupportedItem(const clang::Decl* decl,
86 std::set<std::string> errors) = 0;
87
Michael VanBemmel7a4d4c02022-07-27 13:21:47 -070088 // Imports a decl and creates an IR item (or error messages). This allows
89 // importers to recursively delegate to other importers.
90 // Does not use or update the cache.
91 virtual std::optional<IR::Item> ImportDecl(clang::Decl* decl) = 0;
92
Devin Jeanpierre6af160e2022-09-21 05:30:34 -070093 // Returns the Item of a Decl, importing it first if necessary.
94 // Updates the cache.
95 virtual std::optional<IR::Item> GetDeclItem(clang::Decl* decl) = 0;
96
Kinuko Yasuda6ff59f12022-08-11 08:41:45 -070097 virtual std::optional<IR::Item> GetImportedItem(const clang::Decl* decl) = 0;
98
Lukasz Anforowicz0b3b70c2022-09-02 10:00:40 -070099 // Imports children of `decl`.
100 //
101 // Returns item ids of the children that belong to the current target. This
102 // includes ids of comments within `decl`. The returned ids are ordered by
103 // their source order.
Michael Forsterb3503e02022-04-25 00:24:14 -0700104 virtual std::vector<ItemId> GetItemIdsInSourceOrder(clang::Decl* decl) = 0;
105
106 // Mangles the name of a named decl.
107 virtual std::string GetMangledName(
108 const clang::NamedDecl* named_decl) const = 0;
109
110 // Returs the label of the target that contains a decl.
111 virtual BazelLabel GetOwningTarget(const clang::Decl* decl) const = 0;
112
113 // Checks if the given decl belongs to the current target. Does not look into
114 // other redeclarations of the decl.
115 virtual bool IsFromCurrentTarget(const clang::Decl* decl) const = 0;
116
117 // Gets an IR UnqualifiedIdentifier for the named decl.
118 //
119 // If the decl's name is an identifier, this returns that identifier as-is.
120 //
121 // If the decl is a special member function or operator overload, this returns
122 // a SpecialName.
123 //
Lukasz Anforowicz5837b7d2023-02-23 16:39:02 -0800124 // If the name can't be translated (or is empty), this returns an error.
125 virtual absl::StatusOr<UnqualifiedIdentifier> GetTranslatedName(
Michael Forsterb3503e02022-04-25 00:24:14 -0700126 const clang::NamedDecl* named_decl) const = 0;
127
128 // GetTranslatedName, but only for identifier names. This is the common case.
Lukasz Anforowicz5837b7d2023-02-23 16:39:02 -0800129 // If the name can't be translated (or is empty), this returns an error.
130 virtual absl::StatusOr<Identifier> GetTranslatedIdentifier(
Michael Forsterb3503e02022-04-25 00:24:14 -0700131 const clang::NamedDecl* named_decl) const = 0;
132
133 // Gets the doc comment of the declaration.
Googlera6c60bb2022-12-20 07:32:17 -0800134 virtual std::optional<std::string> GetComment(
Michael Forsterb3503e02022-04-25 00:24:14 -0700135 const clang::Decl* decl) const = 0;
136
137 // Converts a Clang source location to IR.
Googler442733c2023-01-23 01:05:35 -0800138 virtual std::string ConvertSourceLocation(
139 clang::SourceLocation loc) const = 0;
Michael Forsterb3503e02022-04-25 00:24:14 -0700140
Lukasz Anforowicz63559d32022-05-27 16:42:36 -0700141 // Converts the Clang type `qual_type` into an equivalent `MappedType`.
142 // Lifetimes for the type can optionally be specified using `lifetimes`.
143 // If `qual_type` is a pointer type, `nullable` specifies whether the
144 // pointer can be null.
145 // TODO(b/209390498): Currently, we're able to specify nullability only for
146 // top-level pointers. Extend this so that we can specify nullability for
147 // all pointers contained in `qual_type`, in the same way that `lifetimes`
148 // specifies lifetimes for all these pointers. Once this is done, make sure
149 // that all callers pass in the appropriate information, derived from
150 // nullability annotations.
151 virtual absl::StatusOr<MappedType> ConvertQualType(
152 clang::QualType qual_type,
153 std::optional<clang::tidy::lifetimes::ValueLifetimes>& lifetimes,
Googler1bff6372023-03-24 10:06:29 -0700154 std::optional<clang::RefQualifierKind> ref_qualifier_kind,
Lukasz Anforowicz14732b22022-06-02 09:11:08 -0700155 bool nullable = true) = 0;
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700156
Lukasz Anforowicz0233f982022-05-27 16:38:20 -0700157 // Marks `decl` as successfully imported. Other pieces of code can check
158 // HasBeenAlreadySuccessfullyImported to avoid introducing dangling ItemIds
159 // that refer to an unimportable `decl`.
Devin Jeanpierre3c4354b2023-05-26 16:01:49 -0700160 virtual void MarkAsSuccessfullyImported(const clang::NamedDecl* decl) = 0;
Lukasz Anforowicz0233f982022-05-27 16:38:20 -0700161
Lukasz Anforowicz5258f762022-05-27 16:14:46 -0700162 // Returns whether the `decl` has been already successfully imported (maybe
163 // partially - e.g. CXXRecordDeclImporter::Import marks the import as success
Lukasz Anforowicz0233f982022-05-27 16:38:20 -0700164 // before importing the fields, because the latter cannot fail). See also
165 // MarkAsSuccessfullyImported.
Lukasz Anforowicz5258f762022-05-27 16:14:46 -0700166 virtual bool HasBeenAlreadySuccessfullyImported(
Devin Jeanpierre3c4354b2023-05-26 16:01:49 -0700167 const clang::NamedDecl* decl) const = 0;
Lukasz Anforowicz5258f762022-05-27 16:14:46 -0700168
Devin Jeanpierre61804f72022-10-04 20:26:13 -0700169 // Returns whether the `decl` will be successfully imported. If it hasn't been
170 // imported yet, attempts to import it now, calling
171 // MarkAsSuccessfullyImported.
Devin Jeanpierre3c4354b2023-05-26 16:01:49 -0700172 virtual bool EnsureSuccessfullyImported(clang::NamedDecl* decl) = 0;
Devin Jeanpierre61804f72022-10-04 20:26:13 -0700173
Michael Forsterb3503e02022-04-25 00:24:14 -0700174 Invocation& invocation_;
175 clang::ASTContext& ctx_;
176 clang::Sema& sema_;
Michael Forsterb3503e02022-04-25 00:24:14 -0700177};
178
179// Interface for components that can import decls of a certain category.
180class DeclImporter {
181 public:
Devin Jeanpierre257f0f62023-05-08 11:52:01 -0700182 explicit DeclImporter(ImportContext& ictx) : ictx_(ictx) {}
183 virtual ~DeclImporter() = default;
Michael Forsterb3503e02022-04-25 00:24:14 -0700184
Devin Jeanpierrec2c39ff2023-05-08 11:42:21 -0700185 // Returns an IR item for a decl, or `std::nullopt` if it could not be
186 // imported.
187 // If it can't be imported, other DeclImporters may be attempted.
188 // To indicate that an item can't be imported, and no other importers should
189 // be attempted, return UnsupportedItem.
Michael Forsterb3503e02022-04-25 00:24:14 -0700190 virtual std::optional<IR::Item> ImportDecl(clang::Decl*) = 0;
191
192 protected:
193 ImportContext& ictx_;
194};
195
196// Common implementation for defining `DeclImporter`s that determine their
197// applicability by the dynamic type of the decl.
198template <typename D>
199class DeclImporterBase : public DeclImporter {
200 public:
Devin Jeanpierre257f0f62023-05-08 11:52:01 -0700201 explicit DeclImporterBase(ImportContext& context) : DeclImporter(context) {}
Michael Forsterb3503e02022-04-25 00:24:14 -0700202
203 protected:
Devin Jeanpierre257f0f62023-05-08 11:52:01 -0700204 std::optional<IR::Item> ImportDecl(clang::Decl* decl) override {
Devin Jeanpierrec2c39ff2023-05-08 11:42:21 -0700205 auto* typed_decl = clang::dyn_cast<D>(decl);
206 if (typed_decl == nullptr) return std::nullopt;
207 return Import(typed_decl);
Michael Forsterb3503e02022-04-25 00:24:14 -0700208 }
Googlerf596aec2022-05-05 22:02:24 -0700209 virtual std::optional<IR::Item> Import(D*) = 0;
Michael Forsterb3503e02022-04-25 00:24:14 -0700210};
211
212} // namespace crubit
213
214#endif // CRUBIT_RS_BINDINGS_FROM_CC_DECL_IMPORTER_H_