From 1534be723b6d8f4d6e1ff0043f27d39d311c056e Mon Sep 17 00:00:00 2001 From: Melody Ma Date: Tue, 1 Sep 2026 17:14:08 +0800 Subject: [PATCH] [Cpp Parser] Add docs for cpp parser --- cpp/libclang/docs/ast-traversal.md | 62 ++++++++++ cpp/libclang/docs/function-extraction.md | 138 +++++++++++++++++++++++ cpp/libclang/docs/type-extraction.md | 84 ++++++++++++++ 3 files changed, 284 insertions(+) create mode 100644 cpp/libclang/docs/ast-traversal.md create mode 100644 cpp/libclang/docs/function-extraction.md create mode 100644 cpp/libclang/docs/type-extraction.md diff --git a/cpp/libclang/docs/ast-traversal.md b/cpp/libclang/docs/ast-traversal.md new file mode 100644 index 00000000..b6df9556 --- /dev/null +++ b/cpp/libclang/docs/ast-traversal.md @@ -0,0 +1,62 @@ + + +# libclang C++ source analysis + +This document is the entry point for the parser's analysis of a C++ source +file. The parser creates one libclang translation unit for each input file and +walks its AST recursively. It extracts a class-diagram model and a callable +control-flow model from eligible entities. + +Detailed extraction contracts are documented separately: + +- [Function extraction and control flow](function-extraction.md) +- [Class and enum extraction](type-extraction.md) + +## Translation units and the main file + +In libclang terminology, the *main file* is the input file of one parse +operation; it is not necessarily the C++ program's `main.cpp`. For example, +when parsing `src/service.cpp`, declarations and definitions in that file are +in the main file, while entities brought in through `#include` are not. + +Function extraction keeps only callable definitions from the main file. This +avoids extracting an inline function from a shared header once for every +translation unit that includes it. A header-only function is extracted when +that header is itself an input file. + +## Analysis flow + +`Visitor` recursively walks the translation-unit AST. For each entity that is +not filtered out, it dispatches to the relevant specialized visitor: + +| Entity kind | Analysis | +| --- | --- | +| `ClassDecl`, `StructDecl`, `ClassTemplate`, and `ClassTemplatePartialSpecialization` | Extract class/struct entities, members, aliases, bases, and relationship inputs. | +| `EnumDecl` | Extract enum entities and literals. | +| `FunctionDecl` and `Method` | Extract callable definitions and their body control flow. | + +After traversal, class relationship resolution uses the collected base, +variable, and method type information to populate the class-diagram +relationships. + +## Source filtering + +Before dispatch, the parser omits entities located in system or external paths, +or entities in excluded namespaces such as `std`. Namespace cursors are +traversal containers; visitors derive namespace and type ownership from each +entity's semantic-parent chain rather than retaining mutable namespace state. + +This filtering is distinct from the main-file rule: source filtering controls +whether an entity belongs in the parsed model at all, while the main-file rule +prevents duplicated callable definitions from project headers. diff --git a/cpp/libclang/docs/function-extraction.md b/cpp/libclang/docs/function-extraction.md new file mode 100644 index 00000000..c988f2e4 --- /dev/null +++ b/cpp/libclang/docs/function-extraction.md @@ -0,0 +1,138 @@ + + +# libclang function extraction and control flow + +This document records the current contract for extracting C++ callable +definitions and their control flow. It describes the assumptions made by +`FunctionVisitor`, rather than the complete libclang API. For the overall +per-source-file analysis flow, see [libclang C++ source analysis](ast-traversal.md). + +## Function extraction + +A callable becomes a `FunctionDef` only when all of the following hold: + +1. it is located in the current translation unit's main file; +2. a `FunctionId` can be derived; +3. its cursor kind maps to a supported `FunctionKind`; +4. it owns a direct `CompoundStmt` body. + +A declaration-only function therefore does not produce a `FunctionDef`. This +is important because an empty function body and the absence of any function +body have different meanings. + +The function visitor first derives the function identity. Subsequent diagnostic +messages can then include a qualified name rather than only an unqualified +cursor spelling. + +### Function body processing + +A function cursor's direct children include parameter declarations and, for a +normal definition, a `CompoundStmt`. The visitor locates that `CompoundStmt` +and passes it to `process_scope`. + +`process_scope` processes direct statements in source order: + +- `IfStmt` is represented as one `BodyItem::Branch` with ordered cases. A case + has an optional `GuardExpression`, a body, and a source location; a final + `else` case has no guard. When libclang exposes supported unary and binary + cursor layouts, a guard preserves `&&`, `||`, and `!` as a tree so condition + calls retain their C++ short-circuit execution prerequisites. Other + expressions remain source-backed opaque leaves. An `else if` chain is + flattened into additional cases. Unsupported `IfStmt` child layouts use a + conservative fallback that preserves reachable calls without inventing an + unreliable branch shape; +- `ForStmt`, `WhileStmt`, and `DoStmt` are represented as `BodyItem::Loop` + with a typed `LoopKind`; +- `CallExpr` is represented as `BodyItem::Call` when its target has a different + owner; +- other non-control-flow statements are searched recursively for calls. + +Calls nested within another call are emitted before their enclosing call. This +is structural nesting order only: the visitor does not claim an evaluation +order between sibling C++ call arguments. + +## Callable scope and identity + +A `FunctionId` contains a callable name and a structured `Scope`. + +```text +FunctionId = Scope + function name +``` + +`Scope` distinguishes: + +- `Global` for global functions; +- `Namespace(path)` for namespace functions; +- `Type { namespace, type_path }` for member functions. + +Keeping the scope structured prevents a namespace and a type with the same +spelling from being treated as the same owner. It also preserves nested types. +For example: + +```cpp +namespace app { +class Outer { +public: + class Inner { + public: + void run(); + }; +}; +} +``` + +is represented conceptually as: + +```text +Scope::Type { + namespace: ["app"], + type_path: ["Outer", "Inner"], +} +FunctionId: app::Outer::Inner::run +``` + +The scope adapter extracts this information from semantic parents. It keeps +namespace paths distinct from type paths because they have different C++ +semantics. + +### Overloads + +The current `FunctionId` does not include parameter types. Consequently, +overloads in the same scope currently share an identity for call-resolution +purposes. Do not use `FunctionId` as a single-value de-duplication key until a +signature is added to the model. + +## Supported cursor kinds + +The top-level visitor currently dispatches these cursor kinds to +`FunctionVisitor`: + +| libclang cursor kind | Function kind | +| --- | --- | +| `FunctionDecl` | `Free` | +| `Method` | `Method` or `StaticMethod` | + +C++ member operator overloads such as `operator+` and `operator[]` are normally +reported as `Method`; the current model does not use a distinct operator-method +kind. + +`FunctionVisitor` has internal kind mappings for `Constructor`, `Destructor`, +and `ConversionFunction`, but the top-level visitor currently logs and ignores +those cursor kinds. Therefore they do not currently produce `FunctionDef` +entries. A conversion operator such as `operator bool()` is a +`ConversionFunction` and is distinct from a normal operator overload. + +Function templates are not currently part of function extraction. Class visitor +handling of method templates is independent from extraction of function bodies +and call relationships. diff --git a/cpp/libclang/docs/type-extraction.md b/cpp/libclang/docs/type-extraction.md new file mode 100644 index 00000000..3b6def35 --- /dev/null +++ b/cpp/libclang/docs/type-extraction.md @@ -0,0 +1,84 @@ + + +# libclang class and enum extraction + +This document records the current contract for extracting C++ classes, structs, +and enums. It describes the implementation choices in `ClassVisitor` and +`EnumVisitor`, rather than the complete libclang API. For the overall +per-source-file analysis flow, see [libclang C++ source analysis](ast-traversal.md). + +## Traversal and source filtering + +`Visitor` recursively walks the translation-unit AST and dispatches matching +cursors to specialized visitors: + +- `ClassVisitor` handles classes, structs, class templates, and partial class + template specializations; +- `EnumVisitor` handles enums; +- `FunctionVisitor` handles function definitions and control flow, documented + in [function-extraction.md](function-extraction.md). + +Namespace nodes are traversal containers. Visitors derive namespaces and type +owners from each entity's semantic-parent chain instead of maintaining mutable +namespace state. Before dispatch, entities in system or external paths and +entities in excluded namespaces such as `std` are omitted. + +`Entity::visit_children` is used for direct-child inspection where a visitor +needs control over recursion. The top-level visitor recursively traverses the +translation unit, so nested classes and nested enums are discovered separately. + +## Class, struct, interface, and abstract-class extraction + +Named `ClassDecl`, `StructDecl`, `ClassTemplate`, and +`ClassTemplatePartialSpecialization` cursors are represented as class-diagram +entities. Anonymous classes and structs are skipped because they have no stable +name. Their resulting entity type is inferred from the cursor kind and member +set as `Struct`, `Class`, `Interface`, or `AbstractClass`. + +The classification rules are: + +- `Struct`: the source cursor is `StructDecl`; +- `Class`: the cursor is not a struct and has no pure-virtual method; +- `Interface`: the class has at least one pure-virtual method, no data member, + and no concrete non-constructor/destructor method; +- `AbstractClass`: the class has at least one pure-virtual method but does not + meet the `Interface` conditions, because it has a data member or a concrete + non-constructor/destructor method. + +For each direct member cursor, `ClassVisitor` currently extracts: + +- base specifiers and their resolved types; +- methods, constructors, destructors, and method templates; +- fields and variable declarations; +- `using` aliases and `typedef` declarations. + +Method parameter types normally come from libclang's argument list. When that +list is unavailable for a cursor such as `FunctionTemplate`, the visitor falls +back to direct `ParmDecl` children. Template parameters are retained for class +templates, partial specializations, and method templates. + +The visitor records intermediate type information for base classes, variables, +and methods. After the translation unit has been traversed, relationship +resolution derives the class-diagram relationships from that collected type +information. + +## Enum extraction + +Named `EnumDecl` cursors are represented as enum entities. Anonymous enums are +skipped because they have no stable name. + +Each direct `EnumConstantDecl` becomes an enum literal with its name, numeric +value, and source location. The visitor reads the enum's underlying type to +choose the unsigned value supplied by libclang for unsigned enums; values are +stored as `i128` so every `u64` and `i64` value can be serialized safely.