com.github.javaparser.printer.lexicalpreservation.RemovedGroup Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of stubparser Show documentation
Show all versions of stubparser Show documentation
This project contains a parser for the Checker Framework's stub files: https://checkerframework.org/manual/#stub . It is a fork of the JavaParser project.
The newest version!
/*
* Copyright (C) 2007-2010 Júlio Vilmar Gesser.
* Copyright (C) 2011, 2013-2024 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