PatternCleanupHelper.java
/*******************************************************************************
* Copyright (c) 2026 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
*******************************************************************************/
package org.sandbox.jdt.triggerpattern.cleanup;
import java.util.List;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.sandbox.jdt.triggerpattern.api.CleanupPattern;
import org.sandbox.jdt.triggerpattern.api.Match;
import org.sandbox.jdt.triggerpattern.api.Pattern;
import org.sandbox.jdt.triggerpattern.api.TriggerPatternEngine;
/**
* Helper class that provides TriggerPattern cleanup functionality via composition.
* This is the delegate used by cleanup plugins that need to maintain their own inheritance hierarchy
* (e.g., JUnit plugins extending AbstractTool) but want to use TriggerPattern features.
*
* <p>For cleanup plugins that don't have inheritance constraints, consider using
* {@link AbstractPatternCleanupPlugin} directly via inheritance instead.</p>
*
* @since 1.3.0
*/
public class PatternCleanupHelper {
private static final TriggerPatternEngine ENGINE = new TriggerPatternEngine();
private final Class<?> pluginClass;
/**
* Creates a helper for the given plugin class.
*
* @param pluginClass the plugin class (used to read @CleanupPattern annotation)
*/
public PatternCleanupHelper(Class<?> pluginClass) {
this.pluginClass = pluginClass;
}
/**
* Returns the Pattern extracted from the @CleanupPattern annotation.
*
* @return the pattern for matching, or null if no @CleanupPattern annotation is present
*/
public Pattern getPattern() {
CleanupPattern annotation = pluginClass.getAnnotation(CleanupPattern.class);
if (annotation == null) {
return null;
}
String qualifiedType = annotation.qualifiedType().isEmpty() ? null : annotation.qualifiedType();
return new Pattern(annotation.value(), annotation.kind(), null, null, qualifiedType, null, null);
}
/**
* Returns the patterns to match in the compilation unit.
* Default implementation returns a single pattern from @CleanupPattern annotation.
*
* @return list of patterns to match, or empty list if no pattern is configured
*/
public List<Pattern> getPatterns() {
Pattern pattern = getPattern();
if (pattern != null) {
return List.of(pattern);
}
return List.of();
}
/**
* Returns the cleanup ID from the @CleanupPattern annotation.
*
* @return the cleanup ID, or empty string if annotation is not present or cleanupId is not set
*/
public String getCleanupId() {
CleanupPattern annotation = pluginClass.getAnnotation(CleanupPattern.class);
return annotation != null ? annotation.cleanupId() : ""; //$NON-NLS-1$
}
/**
* Returns the description from the @CleanupPattern annotation.
*
* @return the description, or empty string if annotation is not present or description is not set
*/
public String getDescription() {
CleanupPattern annotation = pluginClass.getAnnotation(CleanupPattern.class);
return annotation != null ? annotation.description() : ""; //$NON-NLS-1$
}
/**
* Finds all matches using TriggerPatternEngine.
*
* @param compilationUnit the compilation unit to search
* @param patterns the patterns to match
* @return list of all matches
*/
public List<Match> findAllMatches(org.eclipse.jdt.core.dom.CompilationUnit compilationUnit, List<Pattern> patterns) {
java.util.List<Match> allMatches = new java.util.ArrayList<>();
for (Pattern pattern : patterns) {
List<Match> matches = ENGINE.findMatches(compilationUnit, pattern);
allMatches.addAll(matches);
}
return allMatches;
}
/**
* Validates that the node's type binding matches the expected qualified type.
*
* @param node the AST node to validate
* @param qualifiedType the expected fully qualified type name
* @return true if types match, false otherwise
*/
public boolean validateQualifiedType(ASTNode node, String qualifiedType) {
if (node instanceof Annotation) {
Annotation annotation = (Annotation) node;
ITypeBinding binding = annotation.resolveTypeBinding();
if (binding != null) {
return qualifiedType.equals(binding.getQualifiedName());
}
// Fallback: check simple name
return annotation.getTypeName().getFullyQualifiedName().equals(
qualifiedType.substring(qualifiedType.lastIndexOf('.') + 1));
}
// Add more type checks as needed
return true;
}
}