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); + } +}