NamingConflictFilter.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 java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;

/**
 * A filter that shows only variables with naming conflicts - 
 * variables that have the same name but different types.
 * This helps identify potential naming inconsistencies in the codebase.
 */
public class NamingConflictFilter extends ViewerFilter {

	private Set<String> conflictingNames = new HashSet<>();

	/**
	 * Analyzes all elements to find which variable names have type conflicts.
	 * Must be called before the filter is applied.
	 * 
	 * @param elements the elements to analyze
	 */
	public void analyzeElements(Object[] elements) {
		// Map: variable name -> set of type qualified names
		Map<String, Set<String>> nameToTypes = new HashMap<>();
		
		for (Object element : elements) {
			if (element instanceof IVariableBinding variableBinding) {
				String name = variableBinding.getName();
				ITypeBinding typeBinding = variableBinding.getType();
				String typeName = typeBinding != null ? typeBinding.getQualifiedName() : "unknown"; //$NON-NLS-1$
				
				nameToTypes.computeIfAbsent(name, k -> new HashSet<>()).add(typeName);
			}
		}
		
		// Find names that have more than one type
		conflictingNames.clear();
		for (Map.Entry<String, Set<String>> entry : nameToTypes.entrySet()) {
			if (entry.getValue().size() > 1) {
				conflictingNames.add(entry.getKey());
			}
		}
	}

	/**
	 * Returns the set of variable names that have type conflicts.
	 * 
	 * @return set of conflicting variable names
	 */
	public Set<String> getConflictingNames() {
		return new HashSet<>(conflictingNames);
	}

	/**
	 * Returns true if there are any naming conflicts in the analyzed elements.
	 * 
	 * @return true if conflicts exist
	 */
	public boolean hasConflicts() {
		return !conflictingNames.isEmpty();
	}

	@Override
	public boolean select(Viewer viewer, Object parentElement, Object element) {
		if (element instanceof IVariableBinding variableBinding) {
			return conflictingNames.contains(variableBinding.getName());
		}
		return false;
	}
}