Account for textual headers when determining the owning target of a decl
Before this cl, we did not generate bindings for decls coming from textual headers, as they didn't belong to any target/crate. Now, when we inspect a decl coming from a textual header, we go up the #include stack to locate the first header that has an owning target, and that target becomes the owner of the decl.
PiperOrigin-RevId: 423281830
diff --git a/rs_bindings_from_cc/ast_visitor.cc b/rs_bindings_from_cc/ast_visitor.cc
index 7bcb74f..10344bc 100644
--- a/rs_bindings_from_cc/ast_visitor.cc
+++ b/rs_bindings_from_cc/ast_visitor.cc
@@ -38,6 +38,7 @@
#include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceManager.h"
#include "third_party/llvm/llvm-project/clang/include/clang/Basic/Specifiers.h"
#include "third_party/llvm/llvm-project/clang/include/clang/Sema/Sema.h"
+#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/Optional.h"
#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Casting.h"
#include "util/gtl/flat_map.h"
@@ -322,17 +323,36 @@
BlazeLabel AstVisitor::GetOwningTarget(const clang::Decl* decl) const {
clang::SourceManager& source_manager = ctx_->getSourceManager();
- llvm::StringRef filename = source_manager.getFilename(decl->getLocation());
+ auto source_location = decl->getLocation();
+ auto id = source_manager.getFileID(source_location);
- if (filename.startswith("./")) filename = filename.substr(2);
- auto target_iterator = headers_to_targets_.find(HeaderName(filename.str()));
- if (target_iterator == headers_to_targets_.end()) {
- // TODO(b/208377928): replace this hack with a
- // CHECK(target_iterator != headers_to_targets_.end()) once we generate
- // bindings for headers in Clang's resource dir.
- return BlazeLabel("//:virtual_clang_resource_dir_target");
+ // If the header this decl comes from is not associated with a target we
+ // consider it a textual header. In that case we go up the include stack
+ // until we find a header that has an owning target.
+
+ // TODO(b/208377928): We currently don't have a target for the headers in
+ // Clang's resource directory, so for the time being we return a fictional
+ // "//:virtual_clang_resource_dir_target" for system headers.
+ while (source_location.isValid() &&
+ !source_manager.isInSystemHeader(source_location)) {
+ llvm::Optional<llvm::StringRef> filename =
+ source_manager.getNonBuiltinFilenameForID(id);
+ if (!filename) {
+ return BlazeLabel("//:builtin");
+ }
+ if (filename->startswith("./")) {
+ filename = filename->substr(2);
+ }
+ auto target_iterator =
+ headers_to_targets_.find(HeaderName(filename->str()));
+ if (target_iterator != headers_to_targets_.end()) {
+ return target_iterator->second;
+ }
+ source_location = source_manager.getIncludeLoc(id);
+ id = source_manager.getFileID(source_location);
}
- return target_iterator->second;
+
+ return BlazeLabel("//:virtual_clang_resource_dir_target");
}
bool AstVisitor::IsFromCurrentTarget(const clang::Decl* decl) const {
diff --git a/rs_bindings_from_cc/test/textual_headers/includes_struct_through_layers_of_textual_headers.h b/rs_bindings_from_cc/test/textual_headers/includes_struct_through_layers_of_textual_headers.h
new file mode 100644
index 0000000..154c23f
--- /dev/null
+++ b/rs_bindings_from_cc/test/textual_headers/includes_struct_through_layers_of_textual_headers.h
@@ -0,0 +1,12 @@
+// Part of the Crubit project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEXTUAL_HEADERS_INCLUDES_STRUCT_THROUGH_LAYERS_OF_TEXTUAL_HEADERS_H_
+#define CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEXTUAL_HEADERS_INCLUDES_STRUCT_THROUGH_LAYERS_OF_TEXTUAL_HEADERS_H_
+
+#include "rs_bindings_from_cc/test/textual_headers/includes_textual_header.inc"
+
+inline int getValue(MyStruct s) { return s.value; }
+
+#endif // CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEXTUAL_HEADERS_INCLUDES_STRUCT_THROUGH_LAYERS_OF_TEXTUAL_HEADERS_H_
diff --git a/rs_bindings_from_cc/test/textual_headers/includes_textual_header.h b/rs_bindings_from_cc/test/textual_headers/includes_textual_header.h
new file mode 100644
index 0000000..74a0439
--- /dev/null
+++ b/rs_bindings_from_cc/test/textual_headers/includes_textual_header.h
@@ -0,0 +1,12 @@
+// Part of the Crubit project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEXTUAL_HEADERS_INCLUDES_TEXTUAL_HEADER_H_
+#define CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEXTUAL_HEADERS_INCLUDES_TEXTUAL_HEADER_H_
+
+#include "rs_bindings_from_cc/test/textual_headers/struct_in_textual_header.inc"
+
+inline int getValue(MyStruct s) { return s.value; }
+
+#endif // CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEXTUAL_HEADERS_INCLUDES_TEXTUAL_HEADER_H_
diff --git a/rs_bindings_from_cc/test/textual_headers/includes_textual_header.inc b/rs_bindings_from_cc/test/textual_headers/includes_textual_header.inc
new file mode 100644
index 0000000..a819486
--- /dev/null
+++ b/rs_bindings_from_cc/test/textual_headers/includes_textual_header.inc
@@ -0,0 +1,10 @@
+// Part of the Crubit project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEXTUAL_HEADERS_INCLUDES_TEXTUAL_HEADER_INC_
+#define CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEXTUAL_HEADERS_INCLUDES_TEXTUAL_HEADER_INC_
+
+#include "rs_bindings_from_cc/test/textual_headers/struct_in_textual_header.inc"
+
+#endif // CRUBIT_RS_BINDINGS_FROM_CC_TEST_TEXTUAL_HEADERS_INCLUDES_TEXTUAL_HEADER_INC_
diff --git a/rs_bindings_from_cc/test/textual_headers/struct_in_textual_header.inc b/rs_bindings_from_cc/test/textual_headers/struct_in_textual_header.inc
new file mode 100644
index 0000000..c26caf6
--- /dev/null
+++ b/rs_bindings_from_cc/test/textual_headers/struct_in_textual_header.inc
@@ -0,0 +1,7 @@
+// Part of the Crubit project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+struct MyStruct {
+ int value;
+};
diff --git a/rs_bindings_from_cc/test/textual_headers/textual.inc b/rs_bindings_from_cc/test/textual_headers/textual.inc
index 9c15f8d..6b67ec2 100644
--- a/rs_bindings_from_cc/test/textual_headers/textual.inc
+++ b/rs_bindings_from_cc/test/textual_headers/textual.inc
@@ -7,4 +7,4 @@
#ifndef USING_TEXTUAL_HEADER_IS_FINE
#error "define USING_TEXTUAL_HEADER_IS_FINE to make this textual header work"
-#endif
\ No newline at end of file
+#endif
diff --git a/rs_bindings_from_cc/test/textual_headers/uses_struct_from_layers_of_textual_headers.rs b/rs_bindings_from_cc/test/textual_headers/uses_struct_from_layers_of_textual_headers.rs
new file mode 100644
index 0000000..64f2384
--- /dev/null
+++ b/rs_bindings_from_cc/test/textual_headers/uses_struct_from_layers_of_textual_headers.rs
@@ -0,0 +1,17 @@
+// Part of the Crubit project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#[cfg(test)]
+mod tests {
+
+ #[test]
+ fn test_access_to_struct_through_the_right_crate() {
+ // MyStruct was defined in a textual header of :defines_struct_in_textual_hdr,
+ // but we should consider that header to belong to whichever target
+ // ends up including it in a nontextual header, in this case
+ // :uses_struct_from_textual_hdr_in_textual_hdr.
+ let x = uses_struct_from_textual_hdr_in_textual_hdr::MyStruct { value: 3 };
+ assert_eq!(uses_struct_from_textual_hdr_in_textual_hdr::getValue(x), 3);
+ }
+}
diff --git a/rs_bindings_from_cc/test/textual_headers/uses_struct_from_textual_header.rs b/rs_bindings_from_cc/test/textual_headers/uses_struct_from_textual_header.rs
new file mode 100644
index 0000000..9e16849
--- /dev/null
+++ b/rs_bindings_from_cc/test/textual_headers/uses_struct_from_textual_header.rs
@@ -0,0 +1,17 @@
+// Part of the Crubit project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#[cfg(test)]
+mod tests {
+
+ #[test]
+ fn test_access_to_struct_from_textual_header() {
+ // MyStruct was defined in a textual header of :defines_struct_in_textual_hdr,
+ // but we should consider that header to belong to whichever target
+ // ends up including it through a nontextual header, in this case
+ // :uses_struct_from_textual_hdr.
+ let x = uses_struct_from_textual_hdr::MyStruct { value: 3 };
+ assert_eq!(uses_struct_from_textual_hdr::getValue(x), 3);
+ }
+}