VariableNameSuggester.java

/*******************************************************************************
 * Copyright (c) 2020 Carsten Hammer.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Carsten Hammer - initial API and implementation
 *******************************************************************************/
package org.sandbox.jdt.ui.helper.views;

import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;

/**
 * Helper class for generating suggested variable names based on existing name and type.
 * This is useful for renaming variables to include type information in their names.
 */
public class VariableNameSuggester {

	private VariableNameSuggester() {
		// Utility class
	}

	/**
	 * Generates a suggested name for a variable based on its current name and type.
	 * The suggestion follows common Java naming conventions.
	 * 
	 * Examples:
	 * - "value" + String -> "stringValue"
	 * - "result" + Integer -> "integerResult"
	 * - "item" + List<String> -> "stringListItem"
	 * - "data" + byte[] -> "byteArrayData"
	 * 
	 * @param variableBinding the variable binding to generate a name for
	 * @return a suggested name incorporating the type
	 */
	public static String suggestName(IVariableBinding variableBinding) {
		String currentName = variableBinding.getName();
		ITypeBinding typeBinding = variableBinding.getType();
		
		if (typeBinding == null) {
			return currentName;
		}
		
		String typePrefix = getTypePrefix(typeBinding);
		
		if (typePrefix.isEmpty()) {
			return currentName;
		}
		
		// Combine type prefix with existing name using camelCase
		return typePrefix + capitalizeFirst(currentName);
	}

	/**
	 * Gets a prefix string based on the type binding.
	 * 
	 * @param typeBinding the type binding
	 * @return a lowercase prefix string representing the type
	 */
	private static String getTypePrefix(ITypeBinding typeBinding) {
		if (typeBinding.isArray()) {
			// Handle array types: int[] -> "intArray", String[] -> "stringArray"
			ITypeBinding elementType = typeBinding.getElementType();
			String elementName = getSimpleTypeName(elementType);
			return lowercaseFirst(elementName) + "Array"; //$NON-NLS-1$
		}
		
		if (typeBinding.isParameterizedType()) {
			// Handle generic types: List<String> -> "stringList"
			ITypeBinding[] typeArguments = typeBinding.getTypeArguments();
			String baseName = getSimpleTypeName(typeBinding);
			
			if (typeArguments != null && typeArguments.length > 0) {
				String argName = getSimpleTypeName(typeArguments[0]);
				return lowercaseFirst(argName) + baseName;
			}
			return lowercaseFirst(baseName);
		}
		
		// Simple type
		String typeName = getSimpleTypeName(typeBinding);
		return lowercaseFirst(typeName);
	}

	/**
	 * Gets the simple name of a type (without package).
	 * 
	 * @param typeBinding the type binding
	 * @return the simple type name
	 */
	private static String getSimpleTypeName(ITypeBinding typeBinding) {
		if (typeBinding.isPrimitive()) {
			// Capitalize primitives for better readability
			return capitalizeFirst(typeBinding.getName());
		}
		
		// Use simple name for reference types
		String name = typeBinding.getName();
		
		// Remove generic parameters if present (e.g., "List<E>" -> "List")
		int genericStart = name.indexOf('<');
		if (genericStart > 0) {
			name = name.substring(0, genericStart);
		}
		
		return name;
	}

	/**
	 * Capitalizes the first character of a string.
	 * 
	 * @param str the string to capitalize
	 * @return the string with first character capitalized
	 */
	private static String capitalizeFirst(String str) {
		if (str == null || str.isEmpty()) {
			return str;
		}
		return Character.toUpperCase(str.charAt(0)) + str.substring(1);
	}

	/**
	 * Lowercases the first character of a string.
	 * 
	 * @param str the string to lowercase
	 * @return the string with first character lowercased
	 */
	private static String lowercaseFirst(String str) {
		if (str == null || str.isEmpty()) {
			return str;
		}
		return Character.toLowerCase(str.charAt(0)) + str.substring(1);
	}
}