Skip to content

Commit c8e6501

Browse files
committed
refine llmcc-cpp
1 parent cbf1ac6 commit c8e6501

17 files changed

Lines changed: 1284 additions & 540 deletions

crates/llmcc-core/src/context.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,27 +242,35 @@ impl<'tcx> CompileUnit<'tcx> {
242242

243243
/// Return the symbol referenced by `symbol.type_of()` and its graph block id.
244244
pub fn try_type_of_with_block_id(self, symbol: &Symbol) -> Option<(&'tcx Symbol, BlockId)> {
245-
let type_id = symbol.type_of()?;
246-
self.try_symbol_with_block_id(type_id)
245+
let type_symbol = self.try_resolved_type_link(symbol)?;
246+
let block_id = type_symbol.block_id()?;
247+
Some((type_symbol, block_id))
247248
}
248249

249250
/// Resolve `symbol.type_of()` through type links and return its graph block id.
250251
pub fn try_type_of_block_id(self, symbol: &Symbol) -> Option<BlockId> {
251-
let type_id = symbol.type_of()?;
252-
self.try_type_block_id(type_id)
252+
self.try_resolved_type_link(symbol)?.block_id()
253253
}
254254

255255
/// Resolve a symbol id through its type link, falling back to the symbol's own block.
256256
pub fn try_type_block_id(self, symbol_id: SymId) -> Option<BlockId> {
257257
let symbol = self.try_symbol(symbol_id)?;
258-
self.try_type(symbol).unwrap_or(symbol).block_id()
258+
self.try_resolved_type_link(symbol)
259+
.unwrap_or(symbol)
260+
.block_id()
259261
}
260262

261263
/// Resolve the graph type block for a block-owned symbol.
262264
pub fn try_type_ref_block_id(self, symbol: Option<&Symbol>) -> Option<BlockId> {
263265
let symbol = symbol?;
264266

265-
if let Some(type_symbol) = self.try_type(symbol) {
267+
let resolved = if matches!(symbol.kind(), SymKind::TypeAlias | SymKind::TypeParameter) {
268+
self.try_resolved_type_link(symbol)
269+
} else {
270+
self.try_type(symbol)
271+
};
272+
273+
if let Some(type_symbol) = resolved {
266274
return type_symbol.block_id();
267275
}
268276

@@ -288,6 +296,27 @@ impl<'tcx> CompileUnit<'tcx> {
288296
Some(type_symbol)
289297
}
290298

299+
fn try_resolved_type_link(self, symbol: &Symbol) -> Option<&'tcx Symbol> {
300+
let mut current = self.try_type(symbol)?;
301+
302+
for _ in 0..32 {
303+
if !matches!(current.kind(), SymKind::TypeAlias | SymKind::TypeParameter) {
304+
return Some(current);
305+
}
306+
307+
let Some(next) = self.try_type(current) else {
308+
return Some(current);
309+
};
310+
current = next;
311+
}
312+
313+
tracing::warn!(
314+
symbol_id = symbol.id().0,
315+
"type resolution chain exceeded limit"
316+
);
317+
Some(current)
318+
}
319+
291320
/// Return a scope by id, panicking when it is missing.
292321
pub fn scope(self, scope_id: ScopeId) -> &'tcx Scope<'tcx> {
293322
self.try_scope(scope_id)

crates/llmcc-core/src/graph_builder.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,14 +222,10 @@ impl<'tcx, L: Language> GraphBuilder<'tcx, L> {
222222
BasicBlock::Return(self.unit.alloc_block(id, block))
223223
}
224224
BlockKind::Alias => {
225-
let block = BlockAlias::new_with_name(
226-
id,
227-
node,
228-
parent,
229-
children,
230-
query.try_first_ident_name(),
231-
symbol,
232-
);
225+
let name = symbol
226+
.map(|symbol| self.unit.resolve_name(symbol.name))
227+
.or_else(|| query.try_first_ident_name());
228+
let block = BlockAlias::new_with_name(id, node, parent, children, name, symbol);
233229
BasicBlock::Alias(self.unit.alloc_block(id, block))
234230
}
235231
BlockKind::Module => {

crates/llmcc-cpp/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# llmcc-cpp
2+
3+
C/C++ language support for llmcc architecture and dependency graphs.
4+
5+
This crate is a production best-effort analyzer for graph extraction, not a C++ compiler frontend. It uses tree-sitter syntax plus llmcc symbol collection, binding, and type inference to recover project structure and common type dependencies.
6+
7+
## Supported Semantics
8+
9+
- Translation-unit discovery for common C/C++ source and header extensions.
10+
- Global, file, namespace, class, struct, union, enum, function, method, field, parameter, variable, and alias symbols.
11+
- Cross-file qualified namespace lookup for paths such as `models::User`.
12+
- Basic inheritance edges from class/struct base clauses, including qualified base names.
13+
- Field, parameter, and return type binding for primitive, identifier, qualified, and common wrapper type nodes.
14+
- Type aliases from `using Alias = Type` and `typedef Type Alias`, including alias-chain resolution for graph type references.
15+
- Structural overload separation for same-name free functions by parameter signature, with call binding that prefers matching arity and exact primitive argument types.
16+
- Member lookup through resolved receiver types for ordinary field/method expressions.
17+
- Architecture graph dependencies through direct qualified types and alias-mediated types.
18+
19+
## Intentional Limits
20+
21+
- No full preprocessor, macro expansion, include-path, or `compile_commands.json` semantics.
22+
- No compiler-grade overload resolution, implicit conversions, ADL, access checking, or SFINAE. Current overload handling is structural: arity plus exact primitive type matches, without conversion ranking.
23+
- Template support is structural and best-effort; it does not instantiate templates or fully evaluate dependent names.
24+
- Standard-library types are resolved only when symbols are available in the analyzed input or built-in primitives.
25+
- Results are designed for architecture/dependency graphs, not for proving C++ type correctness.
26+
27+
When correctness requires exact C++ compiler semantics, integrate clang tooling and use llmcc output as a graph-oriented projection of that semantic data.

crates/llmcc-cpp/build.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use std::env;
22
use std::fs;
33
use std::path::PathBuf;
44

5-
fn main() {
6-
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
5+
fn main() -> Result<(), Box<dyn std::error::Error>> {
6+
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
77
let config_path = manifest_dir.join("./src/token_map.toml");
88
let node_types = manifest_dir.join("../../third_party/tree-sitter-cpp/src/node-types.json");
99

@@ -15,10 +15,10 @@ fn main() {
1515
tree_sitter_cpp::LANGUAGE.into(),
1616
&node_types,
1717
&config_path,
18-
)
19-
.unwrap();
18+
)?;
2019

21-
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
20+
let out_dir = PathBuf::from(env::var("OUT_DIR")?);
2221
let out_file = out_dir.join("cpp_tokens.rs");
23-
fs::write(&out_file, contents).unwrap();
22+
fs::write(&out_file, contents)?;
23+
Ok(())
2424
}

0 commit comments

Comments
 (0)