VariableMapping.java
package org.sandbox.jdt.internal.corext.fix.helper.lib;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.core.dom.Expression;
/**
* Represents a one-to-one mapping between variable names in the target code and
* variable names or expressions in the candidate code.
* <p>
* This helper is used by {@link CodeSequenceMatcher} (via
* {@code VariableMappingMatcher}) to normalize variable names when comparing
* AST subtrees. It maintains a bidirectional mapping (target → candidate and
* candidate → target) and enforces consistency: once a name pair is mapped,
* subsequent mappings for either name must match the original pair or the
* mapping is considered invalid.
* <p>
* This class also supports mapping variable names to complex expressions (not just
* simple names), which is useful for cases where a parameter is replaced by a
* method call or other expression.
*/
public class VariableMapping {
// Maps from target variable name to candidate variable name
private final Map<String, String> targetToCandidate = new HashMap<>();
// Maps from candidate variable name to target variable name (for reverse lookup)
private final Map<String, String> candidateToTarget = new HashMap<>();
// Maps from target variable name to candidate expression (for complex expressions)
private final Map<String, Expression> targetToExpression = new HashMap<>();
/**
* Add or verify a mapping between target and candidate variable names
*
* @param targetName Variable name in target code
* @param candidateName Variable name in candidate code
* @return true if mapping is consistent, false if conflict
*/
public boolean addMapping(String targetName, String candidateName) {
// Check if we already have a mapping for this target name
if (targetToCandidate.containsKey(targetName)) {
// Verify consistency: same target name must always map to same candidate name
return targetToCandidate.get(targetName).equals(candidateName);
}
// Check if candidate name is already mapped to a different target name
if (candidateToTarget.containsKey(candidateName)) {
// Verify consistency: same candidate name must always map to same target name
return candidateToTarget.get(candidateName).equals(targetName);
}
// New mapping - add it
targetToCandidate.put(targetName, candidateName);
candidateToTarget.put(candidateName, targetName);
return true;
}
/**
* Add a mapping from a target variable name to a candidate expression
* Used when the candidate uses a complex expression (like a method call)
* where the target uses a simple variable
*
* Note: This method does not perform bidirectional consistency checking like addMapping.
* Callers are responsible for ensuring expression mappings don't conflict with existing
* name mappings. If a simple name mapping already exists for the target name, it will
* be overridden by the expression mapping.
*
* @param targetName Variable name in target code
* @param candidateExpr Expression in candidate code
*/
public void addExpressionMapping(String targetName, Expression candidateExpr) {
targetToExpression.put(targetName, candidateExpr);
}
/**
* Get the candidate name mapped to a target name
*/
public String getCandidateName(String targetName) {
return targetToCandidate.get(targetName);
}
/**
* Get the candidate expression mapped to a target name
*/
public Expression getCandidateExpression(String targetName) {
return targetToExpression.get(targetName);
}
/**
* Check if a target name has an expression mapping (not just a name mapping)
*/
public boolean hasExpressionMapping(String targetName) {
return targetToExpression.containsKey(targetName);
}
/**
* Check if mapping is valid (at least one mapping exists)
*/
public boolean isValid() {
return !targetToCandidate.isEmpty() || !targetToExpression.isEmpty();
}
/**
* Get all target to candidate mappings
*/
public Map<String, String> getMappings() {
return new HashMap<>(targetToCandidate);
}
/**
* Get all target to expression mappings
*/
public Map<String, Expression> getExpressionMappings() {
return new HashMap<>(targetToExpression);
}
}