Add source location information to diagnostics.
PiperOrigin-RevId: 402541826
diff --git a/rs_bindings_from_cc/ast_visitor.cc b/rs_bindings_from_cc/ast_visitor.cc
index 11dc5b1..205ac25 100644
--- a/rs_bindings_from_cc/ast_visitor.cc
+++ b/rs_bindings_from_cc/ast_visitor.cc
@@ -20,6 +20,7 @@
#include "third_party/llvm/llvm-project/clang/include/clang/AST/RawCommentList.h"
#include "third_party/llvm/llvm-project/clang/include/clang/AST/RecordLayout.h"
#include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h"
+#include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceLocation.h"
#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/llvm/include/llvm/Support/Casting.h"
@@ -47,7 +48,21 @@
return Base::TraverseTranslationUnitDecl(translation_unit_decl);
}
+SourceLoc ConvertSourceLoc(const clang::SourceManager& sm,
+ clang::SourceLocation loc) {
+ auto filename = sm.getFileEntryForID(sm.getFileID(loc))->getName();
+ if (filename.startswith("./")) {
+ filename = filename.substr(2);
+ }
+
+ return SourceLoc{.filename = filename.str(),
+ .line = sm.getSpellingLineNumber(loc),
+ .column = sm.getSpellingColumnNumber(loc)};
+}
+
bool AstVisitor::VisitFunctionDecl(clang::FunctionDecl* function_decl) {
+ auto& sm = function_decl->getASTContext().getSourceManager();
+
std::vector<FuncParam> params;
bool success = true;
@@ -58,7 +73,8 @@
ir_.items.push_back(UnsupportedItem{
.name = function_decl->getQualifiedNameAsString(),
.message = absl::Substitute("Parameter type '$0' is not supported",
- param->getType().getAsString())});
+ param->getType().getAsString()),
+ .source_loc = ConvertSourceLoc(sm, param->getBeginLoc())});
success = false;
continue;
}
@@ -67,7 +83,7 @@
ir_.items.push_back(UnsupportedItem{
.name = function_decl->getQualifiedNameAsString(),
.message = "Empty parameter names are not supported",
- });
+ .source_loc = ConvertSourceLoc(sm, param->getBeginLoc())});
success = false;
continue;
}
@@ -81,7 +97,9 @@
.name = function_decl->getQualifiedNameAsString(),
.message =
absl::Substitute("Return type '$0' is not supported",
- function_decl->getReturnType().getAsString())});
+ function_decl->getReturnType().getAsString()),
+ .source_loc = ConvertSourceLoc(
+ sm, function_decl->getReturnTypeSourceRange().getBegin())});
success = false;
}
std::optional<Identifier> translated_name = GetTranslatedName(function_decl);
diff --git a/rs_bindings_from_cc/ir.cc b/rs_bindings_from_cc/ir.cc
index 4ab4879..a86e9cf 100644
--- a/rs_bindings_from_cc/ir.cc
+++ b/rs_bindings_from_cc/ir.cc
@@ -165,11 +165,19 @@
item["Record"] = std::move(record);
return item;
}
+nlohmann::json SourceLoc::ToJson() const {
+ nlohmann::json source_loc;
+ source_loc["filename"] = filename;
+ source_loc["line"] = line;
+ source_loc["column"] = column;
+ return source_loc;
+}
nlohmann::json UnsupportedItem::ToJson() const {
nlohmann::json unsupported;
unsupported["name"] = name;
unsupported["message"] = message;
+ unsupported["source_loc"] = source_loc.ToJson();
nlohmann::json item;
item["UnsupportedItem"] = std::move(unsupported);
diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h
index a1fb1b3..a52a2ee 100644
--- a/rs_bindings_from_cc/ir.h
+++ b/rs_bindings_from_cc/ir.h
@@ -262,6 +262,19 @@
return o << r.ToJson();
}
+// Source code location
+struct SourceLoc {
+ nlohmann::json ToJson() const;
+
+ std::string filename;
+ uint64 line;
+ uint64 column;
+};
+
+inline std::ostream& operator<<(std::ostream& o, const SourceLoc& r) {
+ return o << r.ToJson();
+}
+
// A placeholder for an item that we can't generate bindings for (yet)
struct UnsupportedItem {
nlohmann::json ToJson() const;
@@ -275,6 +288,7 @@
// Explanation of why we couldn't generate bindings
// TODO(forster): We should support multiple reasons per unsupported item.
std::string message;
+ SourceLoc source_loc;
};
inline std::ostream& operator<<(std::ostream& o, const UnsupportedItem& r) {
diff --git a/rs_bindings_from_cc/ir.rs b/rs_bindings_from_cc/ir.rs
index 7afe5c4..42ce646 100644
--- a/rs_bindings_from_cc/ir.rs
+++ b/rs_bindings_from_cc/ir.rs
@@ -102,9 +102,17 @@
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
+pub struct SourceLoc {
+ pub filename: String,
+ pub line: u64,
+ pub column: u64,
+}
+
+#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
pub struct UnsupportedItem {
pub name: String,
pub message: String,
+ pub source_loc: SourceLoc,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index 71d22f3..11a114a 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -259,8 +259,15 @@
/// Generates Rust source code for a given `UnsupportedItem`.
fn generate_unsupported(item: &UnsupportedItem) -> Result<TokenStream> {
- let message =
- format!("Error while generating bindings for item '{}':\n{}", &item.name, &item.message);
+ let message = format!(
+ // TODO(forster): The "google3" prefix should probably come from a command line argument.
+ "google3/{}:{}:{}\nError while generating bindings for item '{}':\n{}",
+ &item.source_loc.filename,
+ &item.source_loc.line,
+ &item.source_loc.column,
+ &item.name,
+ &item.message
+ );
Ok(quote! { __COMMENT__ #message })
}
diff --git a/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs b/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs
index b657d8a..2eeeba2 100644
--- a/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs
@@ -14,6 +14,7 @@
impl !Unpin for Nontrivial {}
+// rs_bindings_from_cc/test/golden/nontrivial_type.h:5:14
// Error while generating bindings for item 'Nontrivial::Nontrivial':
// Parameter type 'struct Nontrivial &&' is not supported
diff --git a/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs b/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
index 8caf9c1..bdc0727 100644
--- a/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
@@ -13,21 +13,27 @@
pub i: i32,
}
+// rs_bindings_from_cc/test/golden/unsupported.h:8:27
// Error while generating bindings for item 'UnsupportedParamType':
// Parameter type 'struct CustomType' is not supported
+// rs_bindings_from_cc/test/golden/unsupported.h:9:30
// Error while generating bindings for item 'UnsupportedUnnamedParam':
// Empty parameter names are not supported
+// rs_bindings_from_cc/test/golden/unsupported.h:10:1
// Error while generating bindings for item 'UnsupportedReturnType':
// Return type 'struct CustomType' is not supported
+// rs_bindings_from_cc/test/golden/unsupported.h:12:28
// Error while generating bindings for item 'MultipleReasons':
// Parameter type 'struct CustomType' is not supported
+// rs_bindings_from_cc/test/golden/unsupported.h:12:42
// Error while generating bindings for item 'MultipleReasons':
// Empty parameter names are not supported
+// rs_bindings_from_cc/test/golden/unsupported.h:12:1
// Error while generating bindings for item 'MultipleReasons':
// Return type 'struct CustomType' is not supported