diff --git a/cpp/libclang/integration_test/cases/inherit_external_base/BUILD b/cpp/libclang/integration_test/cases/inherit_external_base/BUILD new file mode 100644 index 00000000..b3673c15 --- /dev/null +++ b/cpp/libclang/integration_test/cases/inherit_external_base/BUILD @@ -0,0 +1,28 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +load("//cpp/libclang/integration_test:test_rules.bzl", "cpp_parser_integration_test") + +cc_library( + name = "inherit_external_base", + srcs = ["inherit_external.cpp"], + visibility = ["//cpp/libclang:__subpackages__"], + deps = [ + "@flatbuffers//:runtime_cc", + ], +) + +cpp_parser_integration_test( + name = "test_inherit_external_base", + expected_output = ["expected.json"], + target = ":inherit_external_base", +) diff --git a/cpp/libclang/integration_test/cases/inherit_external_base/expected.json b/cpp/libclang/integration_test/cases/inherit_external_base/expected.json new file mode 100644 index 00000000..931b72a4 --- /dev/null +++ b/cpp/libclang/integration_test/cases/inherit_external_base/expected.json @@ -0,0 +1,26 @@ +{ + "types": { + "my_ns::MyNativeObject": { + "id": "my_ns::MyNativeObject", + "name": "MyNativeObject", + "enclosing_namespace_id": "my_ns", + "entity_type": "Class", + "enum_literals": [], + "methods": [], + "relationships": [], + "template_parameters": null, + "type_aliases": [], + "variables": [ + { + "name": "value", + "data_type": "int", + "is_static": false, + "visibility": "public" + } + ], + "source_file": "cpp/libclang/integration_test/cases/inherit_external_base/inherit_external.cpp", + "source_line": 23 + } + }, + "functions": [] +} diff --git a/cpp/libclang/integration_test/cases/inherit_external_base/inherit_external.cpp b/cpp/libclang/integration_test/cases/inherit_external_base/inherit_external.cpp new file mode 100644 index 00000000..fa012570 --- /dev/null +++ b/cpp/libclang/integration_test/cases/inherit_external_base/inherit_external.cpp @@ -0,0 +1,28 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +// Regression test: a workspace class that inherits from an external-library +// base class must not cause the AST parser to panic. The base class is +// filtered out during the visit phase (path contains "external/"), so it is +// not present in the type map. The expected result is that the workspace +// class is emitted without any inheritance relationship. +#include "flatbuffers/flatbuffers.h" + +namespace my_ns { + +class MyNativeObject : public flatbuffers::NativeTable { +public: + int value{}; +}; + +} // namespace my_ns diff --git a/cpp/libclang/integration_test/cases/inherit_external_base/run_test.rs b/cpp/libclang/integration_test/cases/inherit_external_base/run_test.rs new file mode 100644 index 00000000..d7e2d0e2 --- /dev/null +++ b/cpp/libclang/integration_test/cases/inherit_external_base/run_test.rs @@ -0,0 +1,18 @@ +// ******************************************************************************* +// Copyright (c) 2026 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// This program and the accompanying materials are made available under the +// terms of the Apache License Version 2.0 which is available at +// +// +// SPDX-License-Identifier: Apache-2.0 +// ******************************************************************************* + +use test_framework::run_parser_case; +#[test] +fn test_inherit_external_base() { + run_parser_case(); +} diff --git a/cpp/libclang/src/visitor/src/class_visitor.rs b/cpp/libclang/src/visitor/src/class_visitor.rs index 05fb5b6e..c09f22d9 100644 --- a/cpp/libclang/src/visitor/src/class_visitor.rs +++ b/cpp/libclang/src/visitor/src/class_visitor.rs @@ -357,12 +357,17 @@ fn build_relationships_for_class(ctx: &mut VisitContext, builder: &ParsedClassIn ) }); - let target_class = ctx.types.get(resolved_base).unwrap_or_else(|| { - panic!( - "Resolved base type '{}' missing in type map for '{}'", + let Some(target_class) = ctx.types.get(resolved_base) else { + // Base type is not in the type map — it is likely an external dependency + // that was filtered out during the visit phase. Skip the relationship + // rather than panicking so analysis of workspace classes can proceed. + eprintln!( + "Warning: base type '{}' not found in type map for '{}'; \ + skipping inheritance relationship (external dependency?)", resolved_base, builder.id - ) - }); + ); + continue; + }; let relation_type = if target_class.entity_type == EntityType::Interface { RelationType::Implementation