/**
 * TaintMatcherPass
 *
 * First pass in the analysis pipeline. Merges language-plugin built-in
 * sources/sinks into the config, runs config-based taint matching, and
 * extracts @sanitizer-annotated method names from type declarations.
 */
import { analyzeTaint } from '../taint-matcher.js';
import { getLanguagePlugin } from '../../languages/index.js';
import { createWithJdkTypes } from '../../resolution/type-hierarchy.js';
export class TaintMatcherPass {
    name = 'taint-matcher';
    category = 'security';
    run(ctx) {
        const { graph, language, config, code } = ctx;
        const { calls, types } = graph.ir;
        // Merge language-plugin built-in sources/sinks.
        // Plugins (e.g. Bash) define patterns directly on the plugin rather than
        // in YAML config files; splice them in here so they behave identically.
        let mergedConfig = config;
        const plugin = getLanguagePlugin(language);
        if (plugin) {
            const pluginSources = plugin.getBuiltinSources();
            const pluginSinks = plugin.getBuiltinSinks();
            if (pluginSources.length > 0 || pluginSinks.length > 0) {
                mergedConfig = {
                    ...config,
                    sources: [
                        ...config.sources,
                        ...pluginSources.map(s => ({
                            method: s.method,
                            class: s.class,
                            annotation: s.annotation,
                            type: s.type,
                            severity: s.severity,
                            return_tainted: s.returnTainted ?? false,
                        })),
                    ],
                    sinks: [
                        ...config.sinks,
                        ...pluginSinks.map(s => ({
                            method: s.method,
                            class: s.class,
                            type: s.type,
                            cwe: s.cwe,
                            severity: s.severity,
                            arg_positions: s.argPositions,
                        })),
                    ],
                };
            }
        }
        // Build a local TypeHierarchyResolver so that sink patterns match subtype
        // receivers (e.g. PreparedStatement.executeQuery() matches Statement sink).
        const hierarchy = createWithJdkTypes();
        hierarchy.addFromIR(graph.ir, graph.ir.meta.file);
        const taint = analyzeTaint(calls, types, mergedConfig, hierarchy, language, code);
        // Extract method names annotated with @sanitizer (Javadoc comments).
        const sanitizerMethods = [];
        for (const type of types) {
            for (const method of type.methods) {
                if (method.annotations.includes('sanitizer')) {
                    sanitizerMethods.push(method.name);
                }
            }
        }
        return {
            sources: taint.sources,
            sinks: taint.sinks,
            sanitizers: taint.sanitizers ?? [],
            sanitizerMethods,
            config: mergedConfig,
        };
    }
}
//# sourceMappingURL=taint-matcher-pass.js.map