LoopMetadata.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.functional.core.model;
/**
* Metadata about loop characteristics and constraints.
*
* <p>Enforces strict rules for loop refactoring safety (thread-safety and semantics):</p>
* <ul>
* <li>Collection modifications (add/remove/put/clear) on the iterated structure block conversion</li>
* <li>Iterator.remove() usage blocks conversion to enhanced for or stream</li>
* <li>Index variable usage beyond simple element access blocks conversion</li>
* </ul>
*
* @param hasBreak whether the loop contains break statements
* @param hasContinue whether the loop contains continue statements
* @param hasReturn whether the loop contains return statements
* @param modifiesCollection whether the loop modifies the collection being iterated
* @param requiresOrdering whether the loop requires ordering to be preserved
* @param hasIteratorRemove whether the loop calls iterator.remove()
* @param usesIndexBeyondGet whether the index variable is used for more than simple element access
* @since 1.0.0
* @see <a href="https://github.com/carstenartur/sandbox/issues/670">Issue #670</a>
*/
public record LoopMetadata(
boolean hasBreak,
boolean hasContinue,
boolean hasReturn,
boolean modifiesCollection,
boolean requiresOrdering,
boolean hasIteratorRemove,
boolean usesIndexBeyondGet
) {
/**
* Creates a LoopMetadata with all flags set to false.
*/
public static LoopMetadata safe() {
return new LoopMetadata(false, false, false, false, false, false, false);
}
/**
* Checks if the loop can be converted to a stream or enhanced for.
*
* <p>A loop is not convertible if any of the following conditions hold:</p>
* <ul>
* <li>Contains break statements (cannot be expressed in lambdas)</li>
* <li>Contains return statements (changes control flow)</li>
* <li>Modifies the iterated collection (add/remove/put/clear cause ConcurrentModificationException)</li>
* <li>Uses iterator.remove() (not expressible in enhanced for or stream)</li>
* <li>Uses the index variable beyond simple element access (semantics change in enhanced for)</li>
* </ul>
*
* @return true if convertible
* @see <a href="https://github.com/carstenartur/sandbox/issues/670">Issue #670</a>
*/
public boolean isConvertible() {
return !hasBreak && !hasReturn && !modifiesCollection
&& !hasIteratorRemove && !usesIndexBeyondGet;
}
}