All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.javaparser.printer.lexicalpreservation.RemovedGroup Maven / Gradle / Ivy

There is a newer version: 3.26.2
Show newest version
/*
 * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
 * Copyright (C) 2011, 2013-2023 The JavaParser Team.
 *
 * This file is part of JavaParser.
 *
 * JavaParser can be used either under the terms of
 * a) the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * b) the terms of the Apache License
 *
 * You should have received a copy of both licenses in LICENCE.LGPL and
 * LICENCE.APACHE. Please refer to those files for details.
 *
 * JavaParser is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 */
package com.github.javaparser.printer.lexicalpreservation;

import com.github.javaparser.JavaToken;
import com.github.javaparser.TokenRange;
import com.github.javaparser.TokenTypes;
import com.github.javaparser.ast.Node;
import com.github.javaparser.printer.concretesyntaxmodel.CsmToken;

import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * This class represents a group of {@link Removed} elements.
 * The {@link Removed} elements are ideally consecutive for the methods in this class to work correctly.
 *
 * This class consists of methods that calculate information to better handle the difference application for the
 * containing {@link Removed} elements.
 *
 * @see Iterable
 *
 * @author ThLeu
 */
final class RemovedGroup implements Iterable {

    private final Integer firstElementIndex;

    private final List removedList;

    private boolean isProcessed = false;

    private RemovedGroup(Integer firstElementIndex, List removedList) {
        if (firstElementIndex == null) {
            throw new IllegalArgumentException("firstElementIndex should not be null");
        }
        if (removedList == null || removedList.isEmpty()) {
            throw new IllegalArgumentException("removedList should not be null or empty");
        }
        this.firstElementIndex = firstElementIndex;
        this.removedList = removedList;
    }

    /**
     * Factory method to create a RemovedGroup which consists of consecutive Removed elements
     *
     * @param firstElementIndex the difference index at which the RemovedGroup starts
     * @param removedList list of the consecutive Removed elements
     * @return a RemovedGroup object
     * @throws IllegalArgumentException if the firstElementIndex is null or the removedList is empty or null
     */
    public static RemovedGroup of(Integer firstElementIndex, List removedList) {
        return new RemovedGroup(firstElementIndex, removedList);
    }

    /**
     * Marks the RemovedGroup as processed which indicates that it should not be processed again
     */
    final void processed() {
        isProcessed = true;
    }

    /**
     * Returns whether the RemovedGroup was already processed and should not be processed again
     *
     * @return wheter the RemovedGroup was already processed
     */
    final boolean isProcessed() {
        return isProcessed;
    }

    private List getIndicesBeingRemoved() {
        return IntStream.range(firstElementIndex, firstElementIndex + removedList.size()).boxed().collect(Collectors.toList());
    }

    /**
     * Returns the difference index of the last element being removed with this RemovedGroup
     *
     * @return the last difference incex of this RemovedGroup
     */
    final Integer getLastElementIndex() {
        List indicesBeingRemoved = getIndicesBeingRemoved();
        return indicesBeingRemoved.get(indicesBeingRemoved.size() - 1);
    }

    /**
     * Returns the first element of this RemovedGroup
     *
     * @return the first element of this RemovedGroup
     */
    final Removed getFirstElement() {
        return removedList.get(0);
    }

    /**
     * Returns the last element of this RemovedGroup
     *
     * @return the last element of this RemovedGroup
     */
    final Removed getLastElement() {
        return removedList.get(removedList.size() - 1);
    }
    
    /**
     * Returns true if the specified element is the last element of this RemovedGroup
     *
     */
    final boolean isLastElement(Removed element) {
        return getLastElement().equals(element);
    }

    /**
     * Returns true if the RemovedGroup equates to a complete line
     * This is the case if there are only spaces and tabs left on the line besides the Removed elements.
     * 
* Example: *
     * "  [Removed] [EOL]" -> this would be a complete line, regardless of spaces or tabs before or after the [Removed] element
     * "  [Removed] void [EOL]" -> this would not be a complete line because of the "void"
     * "  public [Removed] [EOL]" -> this would not be a complete line because of the "public"
     * 
* * @return true if the RemovedGroup equates to a complete line */ final boolean isACompleteLine() { return hasOnlyWhitespace(getFirstElement(), hasOnlyWhitespaceInFrontFunction) && hasOnlyWhitespace(getLastElement(), hasOnlyWhitespaceBehindFunction); } private final Function hasOnlyWhitespaceJavaTokenInFrontFunction = begin -> hasOnlyWhiteSpaceForTokenFunction(begin, token -> token.getPreviousToken()); private final Function hasOnlyWhitespaceJavaTokenBehindFunction = end -> hasOnlyWhiteSpaceForTokenFunction(end, token -> token.getNextToken()); private final Function hasOnlyWhitespaceInFrontFunction = tokenRange -> hasOnlyWhitespaceJavaTokenInFrontFunction.apply(tokenRange.getBegin()); private final Function hasOnlyWhitespaceBehindFunction = tokenRange -> hasOnlyWhitespaceJavaTokenBehindFunction.apply(tokenRange.getEnd()); private boolean hasOnlyWhitespace(Removed startElement, Function hasOnlyWhitespaceFunction) { boolean hasOnlyWhitespace = false; if (startElement.isChild()) { LexicalDifferenceCalculator.CsmChild csmChild = (LexicalDifferenceCalculator.CsmChild) startElement.getElement(); Node child = csmChild.getChild(); Optional tokenRange = child.getTokenRange(); if (tokenRange.isPresent()) { hasOnlyWhitespace = hasOnlyWhitespaceFunction.apply(tokenRange.get()); } } else if (startElement.isToken()) { CsmToken token = (CsmToken) startElement.getElement(); if (token.isNewLine()) { hasOnlyWhitespace = true; } } return hasOnlyWhitespace; } private boolean hasOnlyWhiteSpaceForTokenFunction(JavaToken token, Function> tokenFunction) { Optional tokenResult = tokenFunction.apply(token); if (tokenResult.isPresent()) { if (TokenTypes.isWhitespaceButNotEndOfLine(tokenResult.get().getKind())) { return hasOnlyWhiteSpaceForTokenFunction(tokenResult.get(), tokenFunction); } if (TokenTypes.isEndOfLineToken(tokenResult.get().getKind())) { return true; } return false; } return true; } /** * Returns the indentation in front of this RemovedGroup if possible. * Sometimes the first deleted element may be a line break because the ConcreteSyntaxModel generates a line break before the members (for example FieldDeclaration). * In this case a remove operation on the member will generate the deletion of the first line break. * It is therefore necessary to avoid taking this element into account so we're looking for the first element that isn't a line break.. * For example * class Foo { * int x; * } * If there is something else than whitespace in front this element, Optional.empty() is returned. * * @return the indentation in front of this RemovedGroup or Optional.empty() */ final Optional getIndentation() { Removed firstElement = null; int indentation = 0; // search for the first element which is not a new line Iterator it = iterator(); while (it.hasNext()) { firstElement = (Removed) it.next(); if (firstElement.isNewLine()) continue; break; } if (firstElement.isChild()) { LexicalDifferenceCalculator.CsmChild csmChild = (LexicalDifferenceCalculator.CsmChild) firstElement.getElement(); Node child = csmChild.getChild(); Optional tokenRange = child.getTokenRange(); if (tokenRange.isPresent()) { JavaToken begin = tokenRange.get().getBegin(); if (hasOnlyWhitespaceJavaTokenInFrontFunction.apply(begin)) { Optional previousToken = begin.getPreviousToken(); while (previousToken.isPresent() && (TokenTypes.isWhitespaceButNotEndOfLine(previousToken.get().getKind()))) { indentation++; previousToken = previousToken.get().getPreviousToken(); } if (previousToken.isPresent()) { if (TokenTypes.isEndOfLineToken(previousToken.get().getKind())) { return Optional.of(Integer.valueOf(indentation)); } return Optional.empty(); } return Optional.of(Integer.valueOf(indentation)); } } } return Optional.empty(); } @Override public final Iterator iterator() { return new Iterator() { private int currentIndex = 0; @Override public boolean hasNext() { return currentIndex < removedList.size() && removedList.get(currentIndex) != null; } @Override public Removed next() { return removedList.get(currentIndex++); } }; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy