il2cpp-dump-analyzer-mcp
Version:
Agentic RAG system for analyzing IL2CPP dump.cs files from Unity games
325 lines • 15.1 kB
JavaScript
;
/**
* @fileoverview Analyze Generic Types MCP Tool
*
* Provides comprehensive analysis of IL2CPP generic type relationships including:
* - Generic type definition analysis and constraint mapping
* - Type parameter relationship analysis
* - Generic instantiation tracking and usage patterns
* - Constraint complexity analysis and validation
*
* This tool implements the generic type analysis functionality from TypeAnalyzer
* as an MCP tool following established patterns and TFD methodology.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.analyzeGenericTypesSchema = exports.AnalyzeGenericTypesTool = void 0;
exports.createAnalyzeGenericTypesTool = createAnalyzeGenericTypesTool;
const zod_1 = require("zod");
const base_tool_handler_1 = require("../base-tool-handler");
const mcp_response_formatter_1 = require("../../utils/mcp-response-formatter");
/**
* Zod schema for analyze generic types parameters
*/
const AnalyzeGenericTypesSchema = zod_1.z.object({
target_type: zod_1.z.string().optional().describe('Specific generic type to analyze (optional, analyzes all generic types if not provided)'),
include_constraints: zod_1.z.boolean().default(true).describe('Whether to include constraint analysis'),
include_instantiations: zod_1.z.boolean().default(false).describe('Whether to include generic instantiation analysis'),
complexity_threshold: zod_1.z.number().min(1).max(10).default(1).describe('Minimum complexity threshold for analysis (1-10)')
});
/**
* Analyze Generic Types MCP Tool Implementation
*
* Analyzes IL2CPP generic type relationships and constraints using vector store search.
* Provides comprehensive generic type analysis with constraint mapping and instantiation tracking.
*/
class AnalyzeGenericTypesTool extends base_tool_handler_1.BaseAnalysisToolHandler {
constructor(context) {
super({
name: 'analyze_generic_types',
description: 'Analyze generic type relationships, constraints, and instantiations in IL2CPP dumps',
enableParameterValidation: true,
enableResponseFormatting: true
}, context);
}
/**
* Validate input parameters using Zod schema
*/
async validateParameters(params) {
const errors = [];
const warnings = [];
const adjustedValues = {};
// Validate complexity_threshold parameter
if (params.complexity_threshold !== undefined) {
if (typeof params.complexity_threshold !== 'number' || params.complexity_threshold < 1 || params.complexity_threshold > 10) {
errors.push('complexity_threshold must be a number between 1 and 10');
}
}
else {
adjustedValues.complexity_threshold = 3;
}
// Validate boolean parameters
if (params.include_constraints === undefined) {
adjustedValues.include_constraints = true;
}
if (params.include_instantiations === undefined) {
adjustedValues.include_instantiations = true;
}
// Validate target_type if provided
if (params.target_type && typeof params.target_type !== 'string') {
errors.push('target_type must be a string');
}
return {
isValid: errors.length === 0,
errors,
warnings,
adjustedValues
};
}
/**
* Execute generic type analysis
*/
async executeCore(params) {
return await this.performAnalysis(async () => {
this.context.logger.debug('Starting generic type analysis', { params });
// Step 1: Get generic types or specific target type
let genericDocuments;
if (params.target_type) {
// Search for specific target type
const targetResults = await this.context.vectorStore.searchWithFilter(params.target_type, { type: ['class', 'interface'] }, 1);
if (targetResults.length === 0) {
throw new Error(`Target generic type '${params.target_type}' not found in IL2CPP dump`);
}
// Verify it's actually a generic type
const targetDoc = targetResults[0];
if (!targetDoc.metadata.genericParameters || targetDoc.metadata.genericParameters.length === 0) {
throw new Error(`Target type '${params.target_type}' is not a generic type`);
}
genericDocuments = targetResults;
}
else {
// Get all generic types (classes and interfaces with generic parameters)
const allTypes = await this.context.vectorStore.searchWithFilter('', { type: ['class', 'interface'] }, 1000);
genericDocuments = allTypes.filter(doc => doc.metadata.genericParameters && doc.metadata.genericParameters.length > 0);
}
if (genericDocuments.length === 0) {
throw new Error('No generic types found in IL2CPP dump for analysis');
}
this.context.logger.debug(`Found ${genericDocuments.length} generic types for analysis`);
// Step 2: Analyze generic type definitions
const genericTypeDefinitions = this.analyzeGenericTypeDefinitions(genericDocuments, params);
// Step 3: Analyze constraint relationships if requested
let constraintRelationships = [];
if (params.include_constraints) {
constraintRelationships = this.analyzeConstraintRelationships(genericDocuments);
}
// Step 4: Analyze generic instantiations if requested
let genericInstantiations = [];
if (params.include_instantiations) {
genericInstantiations = await this.analyzeGenericInstantiations();
}
// Step 5: Calculate complexity metrics
const complexityMetrics = this.calculateComplexityMetrics(genericTypeDefinitions);
const result = {
genericTypeDefinitions,
constraintRelationships,
genericInstantiations,
complexityMetrics,
analysisMetadata: {
targetType: params.target_type,
includeConstraints: params.include_constraints ?? true,
includeInstantiations: params.include_instantiations ?? false,
complexityThreshold: params.complexity_threshold ?? 1,
timestamp: new Date().toISOString(),
totalTypesAnalyzed: genericDocuments.length
}
};
this.context.logger.debug('Generic type analysis completed', {
definitions: genericTypeDefinitions.length,
constraints: constraintRelationships.length,
instantiations: genericInstantiations.length,
avgComplexity: complexityMetrics.averageTypeParameters
});
return result;
});
}
/**
* Analyze generic type definitions
*/
analyzeGenericTypeDefinitions(genericDocuments, params) {
const complexityThreshold = params.complexity_threshold ?? 1;
return genericDocuments
.map(doc => {
const genericParameters = doc.metadata.genericParameters || [];
const constraints = doc.metadata.constraints || [];
const complexityScore = genericParameters.length + constraints.length;
return {
typeName: doc.metadata.name,
namespace: doc.metadata.namespace || '',
typeDefIndex: doc.metadata.typeDefIndex || 0,
genericParameters,
constraints,
constraintCount: constraints.length,
complexityScore,
isInterface: doc.metadata.type === 'interface'
};
})
.filter(def => def.genericParameters.length >= complexityThreshold)
.sort((a, b) => b.complexityScore - a.complexityScore);
}
/**
* Analyze constraint relationships between generic types
*/
analyzeConstraintRelationships(genericDocuments) {
const relationships = [];
for (const doc of genericDocuments) {
const typeName = `${doc.metadata.namespace}.${doc.metadata.name}`;
const constraints = doc.metadata.constraints || [];
const genericParameters = doc.metadata.genericParameters || [];
for (const constraint of constraints) {
// Parse constraint format: "T : class", "U : IComparable<T>", etc.
const constraintMatch = constraint.match(/(\w+)\s*:\s*(.+)/);
if (constraintMatch) {
const [, parameter, constraintTarget] = constraintMatch;
if (genericParameters.includes(parameter)) {
relationships.push({
sourceType: typeName,
targetParameter: parameter,
constraintType: this.getConstraintType(constraintTarget),
constraintTarget: constraintTarget.trim(),
isTypeConstraint: this.isTypeConstraint(constraintTarget),
isInterfaceConstraint: this.isInterfaceConstraint(constraintTarget),
isClassConstraint: constraintTarget.includes('class')
});
}
}
}
}
return relationships;
}
/**
* Analyze generic instantiations in the codebase
*/
async analyzeGenericInstantiations() {
const instantiations = [];
// Search for fields and methods that use generic types
const fieldsAndMethods = await this.context.vectorStore.searchWithFilter('', { type: ['field', 'method'] }, 500);
for (const doc of fieldsAndMethods) {
const instantiation = this.extractGenericInstantiation(doc);
if (instantiation) {
instantiations.push(instantiation);
}
}
return instantiations.sort((a, b) => b.complexityScore - a.complexityScore);
}
/**
* Extract generic instantiation from document metadata
*/
extractGenericInstantiation(doc) {
const fieldType = doc.metadata.fieldType || doc.metadata.returnType;
if (!fieldType)
return null;
// Look for generic type patterns like List<string>, Dictionary<int, string>
const genericMatch = fieldType.match(/(\w+)<(.+)>/);
if (!genericMatch)
return null;
const [, baseType, typeArgsStr] = genericMatch;
const typeArguments = typeArgsStr.split(',').map((arg) => arg.trim());
return {
baseType,
typeArguments,
instantiationContext: doc.metadata.parentClass || 'unknown',
usageLocation: `${doc.metadata.type}:${doc.metadata.name}`,
complexityScore: typeArguments.length
};
}
/**
* Calculate complexity metrics for generic types
*/
calculateComplexityMetrics(definitions) {
if (definitions.length === 0) {
return {
totalGenericTypes: 0,
averageTypeParameters: 0,
maxTypeParameters: 0,
constraintComplexity: 0,
nestingDepth: 0
};
}
const totalGenericTypes = definitions.length;
const totalTypeParameters = definitions.reduce((sum, def) => sum + def.genericParameters.length, 0);
const averageTypeParameters = totalTypeParameters / totalGenericTypes;
const maxTypeParameters = Math.max(...definitions.map(def => def.genericParameters.length));
const constraintComplexity = definitions.reduce((sum, def) => sum + def.constraints.length, 0);
// Calculate nesting depth by analyzing generic parameter names
const nestingDepth = Math.max(...definitions.map(def => Math.max(...def.genericParameters.map(param => (param.match(/</g) || []).length), 0)), 0);
return {
totalGenericTypes,
averageTypeParameters,
maxTypeParameters,
constraintComplexity,
nestingDepth
};
}
/**
* Determine constraint type from constraint target
*/
getConstraintType(constraintTarget) {
if (constraintTarget.includes('class'))
return 'class';
if (constraintTarget.includes('struct'))
return 'struct';
if (constraintTarget.includes('new()'))
return 'constructor';
if (constraintTarget.includes('notnull'))
return 'notnull';
if (constraintTarget.startsWith('I') && constraintTarget[1]?.toUpperCase() === constraintTarget[1]) {
return 'interface';
}
return 'type';
}
/**
* Check if constraint is a type constraint
*/
isTypeConstraint(constraintTarget) {
return !['class', 'struct', 'new()', 'notnull'].some(keyword => constraintTarget.includes(keyword));
}
/**
* Check if constraint is an interface constraint
*/
isInterfaceConstraint(constraintTarget) {
return constraintTarget.startsWith('I') &&
constraintTarget[1]?.toUpperCase() === constraintTarget[1] &&
!constraintTarget.includes('<');
}
/**
* Format generic type analysis results
*/
formatResponse(result, warnings = []) {
let response = mcp_response_formatter_1.MCPResponseFormatter.formatAnalysisResults(result, this.config.name, result.analysisMetadata, Date.now() - this.startTime);
if (warnings.length > 0) {
response = mcp_response_formatter_1.MCPResponseFormatter.addWarnings(response, warnings);
}
return response;
}
}
exports.AnalyzeGenericTypesTool = AnalyzeGenericTypesTool;
/**
* Zod schema for analyze generic types tool parameters
*/
exports.analyzeGenericTypesSchema = zod_1.z.object({
target_type: zod_1.z.string().optional().describe("Specific generic type to analyze (optional, analyzes all generic types if not provided)"),
include_constraints: zod_1.z.boolean().optional().default(true).describe("Include generic type constraints in analysis"),
include_instantiations: zod_1.z.boolean().optional().default(false).describe("Include generic instantiation analysis"),
complexity_threshold: zod_1.z.number().min(1).max(10).optional().default(1).describe("Minimum complexity threshold for analysis (1-10)")
});
/**
* Factory function to create and register the analyze generic types tool
*/
function createAnalyzeGenericTypesTool(server, context) {
const handler = new AnalyzeGenericTypesTool(context);
server.tool("analyze_generic_types", exports.analyzeGenericTypesSchema, async (params) => {
return await handler.execute(params);
});
return handler;
}
//# sourceMappingURL=analyze-generic-types-tool.js.map