Skip to content

CppContainerList throws "The item belongs already to a container" when parsing VTK 9.5 headers Body #122

Description

@wudong-lab

Description

When parsing VTK 9.5 headers with CppParser.ParseFile, an ArgumentException is thrown:

System.ArgumentException: The item belongs already to a container
   at CppAst.CppContainerList`1.Add(TElement item)
   at CppAst.CppContainerList`1.AddRange(IEnumerable`1 collection)
   at CppAst.CppModelBuilder.GetCppTypeInternal(CXCursor cursor, CXType type, CXCursor parent, Void* data)

Reproduction

var options = new CppParserOptions();
options.ConfigureForWindowsMsvc(CppTargetCpu.X86_64, CppVisualStudioVersion.VS2022);
options.IncludeFolders.Add(@"C:\Program Files\VTK\include\vtk-9.5");
var compilation = CppParser.ParseFile(@"C:\Program Files\VTK\include\vtk-9.5\vtkActor.h", options);

Environment: VTK 9.5 headers, CppAst 0.25.0, ClangSharp 21.1.8.3, Windows x64.

Root Cause

The problem is in CppContainerList<T>.Add() — it enforces strict single-parent ownership:

public void Add(TElement item)
{
    if (item.Parent != null)
        throw new ArgumentException("The item belongs already to a container");
    ...
}

During GetCppTypeInternalCXType_Unexposed handling, ParseTemplateSpecializedArguments resolves template arguments that return type instances already belonging to a container (e.g., a CppClass that was added to compilation.Classes). When these same instances are added to CppUnexposedType.TemplateParameters via AddRange, the strict check fails.

The stack trace consistently points to:

GetCppTypeInternal → VisitElaboratedDecl → GetCppType → GetCppTypeInternal → VisitFunctionDecl → CppContainerList.AddRange

Suggested Fix

Relax Add and Insert to allow re-parenting. Skip duplicates in the same container, otherwise allow the element to move:

public void Add(TElement item)
{
    if (item.Parent == Container)
        return; // Already in this container
    item.Parent = Container;
    _elements.Add(item);
}

public void Insert(int index, TElement item)
{
    if (item.Parent == Container)
        return; // Already in this container
    item.Parent = Container;
    _elements.Insert(index, item);
}

This is the same approach taken by XML DOM implementations — a node can be moved from one parent to another without error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions