diff --git a/upb/reflection/def.hpp b/upb/reflection/def.hpp index da8495ab28..206f5db744 100644 --- a/upb/reflection/def.hpp +++ b/upb/reflection/def.hpp @@ -515,6 +515,10 @@ class FileDefPtr { return FieldDefPtr(upb_FileDef_TopLevelExtension(ptr_, index)); } + bool resolves(const char* path) const { + return upb_FileDef_Resolves(ptr_, path); + } + explicit operator bool() const { return ptr_ != nullptr; } friend bool operator==(FileDefPtr lhs, FileDefPtr rhs) { diff --git a/upb/reflection/file_def.c b/upb/reflection/file_def.c index e287d7efa3..34774f3df0 100644 --- a/upb/reflection/file_def.c +++ b/upb/reflection/file_def.c @@ -170,6 +170,17 @@ const upb_MiniTableExtension* _upb_FileDef_ExtensionMiniTable( return f->ext_layouts[i]; } +// Note: Import cycles are not allowed so this will terminate. +bool upb_FileDef_Resolves(const upb_FileDef* f, const char* path) { + if (!strcmp(f->name, path)) return true; + + for (int i = 0; i < upb_FileDef_PublicDependencyCount(f); i++) { + const upb_FileDef* dep = upb_FileDef_PublicDependency(f, i); + if (upb_FileDef_Resolves(dep, path)) return true; + } + return false; +} + static char* strviewdup(upb_DefBuilder* ctx, upb_StringView view) { char* ret = upb_strdup2(view.data, view.size, _upb_DefBuilder_Arena(ctx)); if (!ret) _upb_DefBuilder_OomErr(ctx); diff --git a/upb/reflection/file_def.h b/upb/reflection/file_def.h index e3a74427e4..40170e8e15 100644 --- a/upb/reflection/file_def.h +++ b/upb/reflection/file_def.h @@ -51,6 +51,9 @@ int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f); const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i); int upb_FileDef_WeakDependencyCount(const upb_FileDef* f); +// Returns whether |symbol| is transitively included by |f| +bool upb_FileDef_Resolves(const upb_FileDef* f, const char* symbol); + #ifdef __cplusplus } /* extern "C" */ #endif