dissolve-python 0.3.0

A tool to dissolve deprecated calls in Python codebases
Documentation
// Copyright (C) 2024 Jelmer Vernooij <jelmer@samba.org>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Refactored versions of large functions broken down into smaller, focused functions

// Removed unused Result import
use std::collections::{HashMap, HashSet};

// Example of how to refactor the large dependency collection function
// This breaks down the 246-line function into smaller, focused functions

/// Configuration for dependency collection
pub struct DependencyCollectionConfig<'a> {
    pub max_depth: i32,
    pub additional_paths: &'a [String],
    pub visited_modules: &'a mut HashSet<String>,
}

/// Result of processing imports for a single module
#[derive(Debug, Default)]
pub struct ModuleProcessingResult {
    pub replacements: HashMap<String, String>,
    pub inheritance_map: HashMap<String, Vec<String>>,
    pub class_methods: HashMap<String, Vec<String>>,
    pub imports: Vec<String>,
}

// Group imports function removed - was placeholder only

// Process single module function removed - was placeholder only

/// Merges results from multiple modules
pub fn merge_module_results(results: Vec<ModuleProcessingResult>) -> ModuleProcessingResult {
    let mut merged = ModuleProcessingResult::default();

    for result in results {
        // Merge replacements
        merged.replacements.extend(result.replacements);

        // Merge inheritance maps
        for (key, value) in result.inheritance_map {
            merged.inheritance_map.insert(key, value);
        }

        // Merge class methods
        for (key, value) in result.class_methods {
            merged.class_methods.insert(key, value);
        }

        // Merge imports
        merged.imports.extend(result.imports);
    }

    merged
}

// This function was removed as it contained only placeholder implementations

// Helper function removed - was unused

/// Example of how to refactor parameter mapping to reduce clones
pub struct OptimizedParameterMapper<'a> {
    // Use string references where possible
    param_names: Vec<&'a str>,
    // Only store owned strings when necessary
    dynamic_params: HashMap<String, String>,
}

impl<'a> OptimizedParameterMapper<'a> {
    pub fn new(param_names: Vec<&'a str>) -> Self {
        Self {
            param_names,
            dynamic_params: HashMap::new(),
        }
    }

    /// Map parameters without cloning the parameter names
    pub fn map_parameters(&mut self, args: &[&'a str]) -> HashMap<&'a str, &'a str> {
        let mut param_map = HashMap::new();

        for (i, &arg) in args.iter().enumerate() {
            if let Some(&param_name) = self.param_names.get(i) {
                param_map.insert(param_name, arg);
            }
        }

        param_map
    }

    /// Add a dynamic parameter (only when string ownership is required)
    pub fn add_dynamic_param(&mut self, name: String, value: String) {
        self.dynamic_params.insert(name, value);
    }
}

/// Example of refactoring string replacement to use Cow<str>
pub fn optimize_string_replacement<'a>(
    template: &'a str,
    replacements: &HashMap<&str, &str>,
) -> std::borrow::Cow<'a, str> {
    let mut needs_replacement = false;

    // First pass: check if any replacements are needed
    for key in replacements.keys() {
        if template.contains(key) {
            needs_replacement = true;
            break;
        }
    }

    if !needs_replacement {
        // No replacements needed - return borrowed
        return std::borrow::Cow::Borrowed(template);
    }

    // Replacements needed - create owned string
    let mut result = template.to_string();
    for (key, value) in replacements {
        result = result.replace(key, value);
    }

    std::borrow::Cow::Owned(result)
}

#[cfg(test)]
mod tests {
    use super::*;

    // Test for group_imports_by_module removed - function was placeholder only

    #[test]
    fn test_optimized_parameter_mapper() {
        let param_names = vec!["param1", "param2", "param3"];
        let mut mapper = OptimizedParameterMapper::new(param_names);

        let args = vec!["value1", "value2", "value3"];
        let mapped = mapper.map_parameters(&args);

        assert_eq!(mapped.get("param1"), Some(&"value1"));
        assert_eq!(mapped.get("param2"), Some(&"value2"));
        assert_eq!(mapped.get("param3"), Some(&"value3"));
    }

    #[test]
    fn test_optimize_string_replacement() {
        let mut replacements = HashMap::new();
        replacements.insert("{name}", "John");
        replacements.insert("{age}", "30");

        // Template with replacements needed
        let result1 = optimize_string_replacement("Hello {name}, age {age}", &replacements);
        assert!(matches!(result1, std::borrow::Cow::Owned(_)));
        assert_eq!(result1, "Hello John, age 30");

        // Template with no replacements needed
        let result2 = optimize_string_replacement("Hello World", &replacements);
        assert!(matches!(result2, std::borrow::Cow::Borrowed(_)));
        assert_eq!(result2, "Hello World");
    }

    #[test]
    fn test_merge_module_results() {
        let results = vec![
            ModuleProcessingResult {
                replacements: [("func1".to_string(), "replacement1".to_string())].into(),
                inheritance_map: [("class1".to_string(), vec!["base1".to_string()])].into(),
                class_methods: HashMap::new(),
                imports: vec!["module1".to_string()],
            },
            ModuleProcessingResult {
                replacements: [("func2".to_string(), "replacement2".to_string())].into(),
                inheritance_map: [("class2".to_string(), vec!["base2".to_string()])].into(),
                class_methods: HashMap::new(),
                imports: vec!["module2".to_string()],
            },
        ];

        let merged = merge_module_results(results);
        assert_eq!(merged.replacements.len(), 2);
        assert_eq!(merged.inheritance_map.len(), 2);
        assert_eq!(merged.imports.len(), 2);
    }
}