Files
wehub-resource-sync 41cb1c0170
OpenSSF Scorecard / scorecard (push) Failing after 0s
DCO / dco (push) Failing after 0s
CodeQL SAST / analyze (push) Failing after 1s
Deploy Pages / deploy (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:28:05 +08:00

169 lines
7.5 KiB
C

#ifndef CBM_LSP_JAVA_LSP_H
#define CBM_LSP_JAVA_LSP_H
/*
* java_lsp.h — Pure-C Java semantic resolver.
*
* Reverse-engineered from JLS §6 (Names) and §15 (Expressions) plus the
* algorithm shape used by Eclipse JDT-LS / java-language-server (which both
* delegate to javac.com.sun.source). The goal is parity with what JDT-LS
* exposes through textDocument/definition + textDocument/references for
* call-site resolution, *without* shelling out to javac.
*
* Mirrors the structure of go_lsp.h / c_lsp.h / php_lsp.h / py_lsp.h.
*
* Resolution scheme (single file):
* 1. Tree-sitter parses Java source into AST.
* 2. Build a CBMTypeRegistry from this file's CBMDefinitions + Java
* stdlib (java.lang.*, java.util.*, java.io.*, java.util.function.*,
* java.util.stream.*).
* 3. Walk the AST and for every method_invocation / object_creation /
* field_access expression, evaluate the expression's type using
* JLS-style scope chains (block → method params → class members →
* superclass chain → outer class → import single → import on-demand →
* java.lang → same package).
* 4. Match the textual call (callee name + arity) against the resolved
* receiver type's method set, walking superclasses and interfaces.
* Best-overload resolution falls back to argument count match.
* 5. Emit CBMResolvedCall entries with confidence ≥ 0.6 (the LSP floor
* enforced by lsp_resolve.h).
*/
#include "type_rep.h"
#include "scope.h"
#include "type_registry.h"
#include "../cbm.h"
#include "go_lsp.h" /* CBMLSPDef, CBMResolvedCallArray reused across languages */
/* Java `use`-style import kinds. Mirrors PHP's enum with Java semantics. */
enum {
CBM_JAVA_IMPORT_TYPE = 0, /* import com.foo.Bar; — type import */
CBM_JAVA_IMPORT_STATIC = 1, /* import static com.foo.Bar.method; */
CBM_JAVA_IMPORT_ON_DEMAND = 2, /* import com.foo.*; — package on-demand */
CBM_JAVA_IMPORT_STATIC_OD = 3, /* import static com.foo.Bar.*; */
};
/* Per-file resolution context. */
typedef struct {
CBMArena *arena;
const char *source;
int source_len;
const CBMTypeRegistry *registry;
CBMScope *current_scope;
/* Java package — the package declared in the file ("com.example"), or
* empty string for the unnamed package. Stored in dotted form. */
const char *package_name;
/* The path-derived module QN for this file (passed in from the caller),
* used as the QN prefix for types defined here. */
const char *module_qn;
/* Import map. Each entry is one of CBM_JAVA_IMPORT_*.
* - TYPE: local_name="Bar", target_qn="com.foo.Bar"
* - STATIC: local_name="sqrt", target_qn="java.lang.Math.sqrt"
* - ON_DEMAND: local_name="*", target_qn="com.foo"
* - STATIC_OD: local_name="*", target_qn="java.lang.Math"
*/
const char **import_local_names;
const char **import_target_qns;
int *import_kinds;
int import_count;
int import_cap;
/* Current enclosing context. */
const char *enclosing_method_qn; /* QN of the nearest method/ctor */
const char *enclosing_class_qn; /* QN of the nearest class/interface/enum */
const char *enclosing_super_qn; /* QN of the immediate superclass (NULL ⇒ Object) */
const char *enclosing_class_short; /* short name of enclosing class — for "this" + ctor */
const char **enclosing_class_stack; /* nested-class stack (enclosing_class_qn at each depth) */
int enclosing_class_depth;
int enclosing_class_cap;
/* Output: resolved + diagnostic call edges. */
CBMResolvedCallArray *resolved_calls;
/* Recursion guards. */
int eval_depth;
int statement_depth;
int walk_depth; /* java_resolve_calls_in_node self-recursion (AST nesting) */
/* Debug mode (CBM_LSP_DEBUG env). */
bool debug;
} JavaLSPContext;
/* ── Initialization / configuration ───────────────────────────────── */
void java_lsp_init(JavaLSPContext *ctx, CBMArena *arena, const char *source, int source_len,
const CBMTypeRegistry *registry, const char *package_name, const char *module_qn,
CBMResolvedCallArray *out);
void java_lsp_add_import(JavaLSPContext *ctx, const char *local_name, const char *target_qn,
int kind);
/* ── Walking / resolution ─────────────────────────────────────────── */
void java_lsp_process_file(JavaLSPContext *ctx, TSNode root);
/* Evaluate the type of an arbitrary Java expression node. May return
* cbm_type_unknown(); never returns NULL. */
const CBMType *java_eval_expr_type(JavaLSPContext *ctx, TSNode node);
/* Convert a Java type AST node (type_identifier, generic_type, array_type,
* scoped_type_identifier, void_type, integral_type, ...) into a CBMType. */
const CBMType *java_parse_type_node(JavaLSPContext *ctx, TSNode node);
/* Process a Java statement, binding any declared variables/parameters into
* the current scope. */
void java_process_statement(JavaLSPContext *ctx, TSNode node);
/* Resolve a Java type name (bare or qualified) against the current scope
* (imports + java.lang + same package). Returns the registered FQN or NULL. */
const char *java_resolve_type_name(JavaLSPContext *ctx, const char *name);
/* Lookup a method on a class, walking the super-chain and implemented
* interfaces. Returns the matched function or NULL. */
const CBMRegisteredFunc *java_lookup_method(JavaLSPContext *ctx, const char *class_qn,
const char *method_name, int arg_count);
/* Lookup a field on a class, walking the super-chain. Returns the field's
* type, or cbm_type_unknown() on miss. */
const CBMType *java_lookup_field_type(JavaLSPContext *ctx, const char *class_qn,
const char *field_name);
/* ── Top-level entry points ───────────────────────────────────────── */
/* Single-file LSP: build registry from file defs + stdlib, walk and resolve. */
void cbm_run_java_lsp(CBMArena *arena, CBMFileResult *result, const char *source, int source_len,
TSNode root);
/* Cross-file LSP: build registry from defs + stdlib, re-parse if needed,
* walk and resolve. defs include both local + cross-file definitions. */
void cbm_run_java_lsp_cross(CBMArena *arena, const char *source, int source_len,
const char *module_qn, CBMLSPDef *defs, int def_count,
const char **import_names, const char **import_qns, int import_count,
TSTree *cached_tree, CBMResolvedCallArray *out);
/* Register the Java standard library (java.lang/util/io/etc.) into reg.
* Implementation lives in generated/java_stdlib_data.c. */
void cbm_java_stdlib_register(CBMTypeRegistry *reg, CBMArena *arena);
/* ── Batch cross-file LSP ─────────────────────────────────────────── */
typedef struct {
const char *source;
int source_len;
const char *module_qn;
TSTree *cached_tree;
CBMLSPDef *defs;
int def_count;
const char **import_names;
const char **import_qns;
int import_count;
} CBMBatchJavaLSPFile;
void cbm_batch_java_lsp_cross(CBMArena *arena, CBMBatchJavaLSPFile *files, int file_count,
CBMResolvedCallArray *out);
#endif /* CBM_LSP_JAVA_LSP_H */