/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of 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.
*
* The Whole Platform 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.java.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Comment;
import org.eclipse.jdt.core.dom.Javadoc;
import org.whole.lang.bindings.BindingManagerFactory;
import org.whole.lang.iterators.IEntityIterator;
import org.whole.lang.iterators.IteratorFactory;
import org.whole.lang.model.IEntity;
import org.whole.lang.util.StringUtils;
/**
* @author Enrico Persiani
*/
public class JDTCommentsMapper {
private String source;
private List<Comment> comments;
private IEntity orphanComments;
public JDTCommentsMapper(String source) {
this.source = source;
this.comments = Collections.emptyList();
this.orphanComments = BindingManagerFactory.instance.createTuple();
}
public void setComments(List<Comment> comments) {
this.comments = comments != null ? new ArrayList<Comment>(comments) : Collections.<Comment>emptyList();
}
public boolean removeJavadoc(Javadoc comment) {
return comments.remove(comment);
}
public void appendOrphanCommentsToBlock(IEntity block) {
IEntityIterator<IEntity> iterator = IteratorFactory.childIterator();
iterator.reset(orphanComments);
for (IEntity child : iterator) {
block.wAdd(child);
iterator.remove();
}
}
public void addOrphanComment(IEntity comment) {
orphanComments.wAdd(comment);
}
protected String sourceSubString(int beginIndex, int endIndex) {
return source != null ? source.substring(beginIndex, endIndex) : "";
}
protected boolean isAdjacentTo(ASTNode node, ASTNode toNode, boolean newLinesAllowed) {
int nodeEnd = node.getStartPosition()+node.getLength();
int toNodeStart = toNode.getStartPosition();
return isAdjacentTo(nodeEnd, toNodeStart, newLinesAllowed);
}
protected boolean isAdjacentTo(int from, int to, boolean newLinesAllowed) {
if (from > to)
return false;
String betweenText = sourceSubString(from, to);
for (char c : betweenText.toCharArray())
if (!Character.isWhitespace(c) || (!newLinesAllowed && StringUtils.isNewLineChar(c)))
return false;
return true;
}
protected boolean isLineComment(Comment comment) {
return comment.getNodeType() == ASTNode.LINE_COMMENT ||
!containsNewLineChar(getText(comment));
}
public List<Comment> extractNodeComments(ASTNode node) {
List<Comment> extracted = new ArrayList<Comment>();
boolean findAdjacentComment = false;
ASTNode prevNode = node;
// search backward
int i=comments.size();
while (--i >=0) {
Comment comment = comments.get(i);
// look for a following comment line
if (!findAdjacentComment && isLineComment(comment) && isAdjacentTo(node, comment, false)) {
extracted.add(0, comment);
comments.remove(i);
} else if (isAdjacentTo(comment, prevNode, true)) {
prevNode = comment;
extracted.add(0, comment);
comments.remove(i);
findAdjacentComment = true;
} else if (findAdjacentComment)
break;
}
return extracted;
}
public List<Comment> extractContainerComments(ASTNode container) {
List<Comment> extracted = new ArrayList<Comment>();
Comment node = null;
int i=comments.size();
while (--i>=0) {
Comment comment = comments.get(i);
if (node == null) {
int from = comment.getStartPosition()+comment.getLength();
int to = container.getStartPosition()+container.getLength()-1;
if (isAdjacentTo(from, to, true)) {
extracted.add(0, node = comment);
comments.remove(i);
}
} else if (isAdjacentTo(comment, node, true)) {
extracted.add(0, node = comment);
comments.remove(i);
} else
break;
}
return extracted;
}
public String getText(Comment comment) {
int start = comment.getStartPosition();
switch (comment.getNodeType()) {
case ASTNode.LINE_COMMENT:
return sourceSubString(start+2, start+comment.getLength());
case ASTNode.BLOCK_COMMENT:
return sourceSubString(start+2, start+comment.getLength()-2);
case ASTNode.JAVADOC:
default:
return sourceSubString(start+3, start+comment.getLength()-2);
}
}
public static boolean containsNewLineChar(String s) {
for (int i=0; i<s.length(); i++)
if (StringUtils.isNewLineChar(s.charAt(i)))
return true;
return false;
}
public Javadoc getPackageJavadoc() {
Comment comment;
if (comments.isEmpty() || (comment = comments.get(0)).getNodeType() != ASTNode.JAVADOC)
return null;
String text = sourceSubString(0, comment.getStartPosition());
return text.matches("\\p{javaWhitespace}*") ?
(Javadoc) comment : null;
}
}