| /* |
| * Copyright (C) 2007-2010 Júlio Vilmar Gesser. |
| * Copyright (C) 2011, 2013-2015 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; |
| |
| import static com.github.javaparser.PositionUtils.areInOrder; |
| import static com.github.javaparser.PositionUtils.sortByBeginPosition; |
| |
| import com.github.javaparser.ASTParser; |
| import com.github.javaparser.ParseException; |
| import com.github.javaparser.ast.CompilationUnit; |
| import com.github.javaparser.ast.ImportDeclaration; |
| import com.github.javaparser.ast.Node; |
| import com.github.javaparser.ast.body.BodyDeclaration; |
| import com.github.javaparser.ast.comments.Comment; |
| import com.github.javaparser.ast.comments.CommentsCollection; |
| import com.github.javaparser.ast.comments.CommentsParser; |
| import com.github.javaparser.ast.comments.LineComment; |
| import com.github.javaparser.ast.expr.AnnotationExpr; |
| import com.github.javaparser.ast.expr.Expression; |
| import com.github.javaparser.ast.stmt.BlockStmt; |
| import com.github.javaparser.ast.stmt.Statement; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.util.Collections; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| // FIXME this file does not seem to be generated by javacc. Is the doc wrong, or the javacc config? |
| /** |
| * <p> |
| * This class was generated automatically by javacc, do not edit. |
| * </p> |
| * <p> |
| * Parse Java 1.5 source code and creates Abstract Syntax Tree classes. |
| * </p> |
| * |
| * @author Júlio Vilmar Gesser |
| */ |
| public final class JavaParser { |
| private JavaParser() { |
| // hide the constructor |
| } |
| |
| private static boolean _doNotAssignCommentsPreceedingEmptyLines = true; |
| |
| private static boolean _doNotConsiderAnnotationsAsNodeStartForCodeAttribution = false; |
| |
| public static boolean getDoNotConsiderAnnotationsAsNodeStartForCodeAttribution() |
| { |
| return _doNotConsiderAnnotationsAsNodeStartForCodeAttribution; |
| } |
| |
| public static void setDoNotConsiderAnnotationsAsNodeStartForCodeAttribution(boolean doNotConsiderAnnotationsAsNodeStartForCodeAttribution) { |
| _doNotConsiderAnnotationsAsNodeStartForCodeAttribution = doNotConsiderAnnotationsAsNodeStartForCodeAttribution; |
| } |
| |
| public static boolean getDoNotAssignCommentsPreceedingEmptyLines() |
| { |
| return _doNotAssignCommentsPreceedingEmptyLines; |
| } |
| |
| public static void setDoNotAssignCommentsPreceedingEmptyLines(boolean doNotAssignCommentsPreceedingEmptyLines) |
| { |
| _doNotAssignCommentsPreceedingEmptyLines = doNotAssignCommentsPreceedingEmptyLines; |
| } |
| |
| public static CompilationUnit parse(final InputStream in, |
| final String encoding) { |
| return parse(in,encoding,true); |
| } |
| |
| /** |
| * Parses the Java code contained in the {@link InputStream} and returns a |
| * {@link CompilationUnit} that represents it. |
| * |
| * @param in |
| * {@link InputStream} containing Java source code |
| * @param encoding |
| * encoding of the source code |
| * @return CompilationUnit representing the Java source code |
| * @throws ParseException |
| * if the source code has parser errors |
| */ |
| public static CompilationUnit parse(final InputStream in, |
| final String encoding, boolean considerComments) { |
| try { |
| String code = SourcesHelper.streamToString(in, encoding); |
| InputStream in1 = SourcesHelper.stringToStream(code, encoding); |
| CompilationUnit cu = new ASTParser(in1, encoding).CompilationUnit(); |
| if (considerComments){ |
| insertComments(cu,code); |
| } |
| return cu; |
| } catch (IOException ioe){ |
| throw new ParseException(ioe.getMessage()); |
| } |
| } |
| |
| /** |
| * Parses the Java code contained in the {@link InputStream} and returns a |
| * {@link CompilationUnit} that represents it. |
| * |
| * @param in |
| * {@link InputStream} containing Java source code |
| * @return CompilationUnit representing the Java source code |
| * @throws ParseException |
| * if the source code has parser errors |
| */ |
| public static CompilationUnit parse(final InputStream in) |
| { |
| return parse(in, null,true); |
| } |
| |
| public static CompilationUnit parse(final File file, final String encoding) |
| throws ParseException, IOException { |
| return parse(file,encoding,true); |
| } |
| |
| /** |
| * Parses the Java code contained in a {@link File} and returns a |
| * {@link CompilationUnit} that represents it. |
| * |
| * @param file |
| * {@link File} containing Java source code |
| * @param encoding |
| * encoding of the source code |
| * @return CompilationUnit representing the Java source code |
| * @throws ParseException |
| * if the source code has parser errors |
| * @throws IOException |
| */ |
| public static CompilationUnit parse(final File file, final String encoding, boolean considerComments) |
| throws ParseException, IOException { |
| final FileInputStream in = new FileInputStream(file); |
| try { |
| return parse(in, encoding, considerComments); |
| } finally { |
| in.close(); |
| } |
| } |
| |
| /** |
| * Parses the Java code contained in a {@link File} and returns a |
| * {@link CompilationUnit} that represents it. |
| * |
| * @param file |
| * {@link File} containing Java source code |
| * @return CompilationUnit representing the Java source code |
| * @throws ParseException |
| * if the source code has parser errors |
| * @throws IOException |
| */ |
| public static CompilationUnit parse(final File file) throws ParseException, |
| IOException { |
| return parse(file, null,true); |
| } |
| |
| public static CompilationUnit parse(final Reader reader, boolean considerComments) |
| { |
| try { |
| String code = SourcesHelper.readerToString(reader); |
| Reader reader1 = SourcesHelper.stringToReader(code); |
| CompilationUnit cu = new ASTParser(reader1).CompilationUnit(); |
| if (considerComments){ |
| insertComments(cu,code); |
| } |
| return cu; |
| } catch (IOException ioe){ |
| throw new ParseException(ioe.getMessage()); |
| } |
| } |
| |
| /** |
| * Parses the Java block contained in a {@link String} and returns a |
| * {@link BlockStmt} that represents it. |
| * |
| * @param blockStatement |
| * {@link String} containing Java block code |
| * @return BlockStmt representing the Java block |
| * @throws ParseException |
| * if the source code has parser errors |
| */ |
| public static BlockStmt parseBlock(final String blockStatement) |
| { |
| StringReader sr = new StringReader(blockStatement); |
| BlockStmt result = new ASTParser(sr).Block(); |
| sr.close(); |
| return result; |
| } |
| |
| /** |
| * Parses the Java statement contained in a {@link String} and returns a |
| * {@link Statement} that represents it. |
| * |
| * @param statement |
| * {@link String} containing Java statement code |
| * @return Statement representing the Java statement |
| * @throws ParseException |
| * if the source code has parser errors |
| */ |
| public static Statement parseStatement(final String statement) { |
| StringReader sr = new StringReader(statement); |
| Statement stmt = new ASTParser(sr).Statement(); |
| sr.close(); |
| return stmt; |
| } |
| |
| /** |
| * Parses the Java import contained in a {@link String} and returns a |
| * {@link ImportDeclaration} that represents it. |
| * |
| * @param importDeclaration |
| * {@link String} containing Java import code |
| * @return ImportDeclaration representing the Java import declaration |
| * @throws ParseException |
| * if the source code has parser errors |
| */ |
| public static ImportDeclaration parseImport(final String importDeclaration) { |
| StringReader sr = new StringReader(importDeclaration); |
| ImportDeclaration id = new ASTParser(sr).ImportDeclaration(); |
| sr.close(); |
| return id; |
| } |
| |
| /** |
| * Parses the Java expression contained in a {@link String} and returns a |
| * {@link Expression} that represents it. |
| * |
| * @param expression |
| * {@link String} containing Java expression |
| * @return Expression representing the Java expression |
| * @throws ParseException |
| * if the source code has parser errors |
| */ |
| public static Expression parseExpression(final String expression) { |
| StringReader sr = new StringReader(expression); |
| Expression e = new ASTParser(sr).Expression(); |
| sr.close(); |
| return e; |
| } |
| |
| /** |
| * Parses the Java annotation contained in a {@link String} and returns a |
| * {@link AnnotationExpr} that represents it. |
| * |
| * @param annotation |
| * {@link String} containing Java annotation |
| * @return AnnotationExpr representing the Java annotation |
| * @throws ParseException |
| * if the source code has parser errors |
| */ |
| public static AnnotationExpr parseAnnotation(final String annotation) { |
| StringReader sr = new StringReader(annotation); |
| AnnotationExpr ae = new ASTParser(sr).Annotation(); |
| sr.close(); |
| return ae; |
| } |
| |
| /** |
| * Parses the Java body declaration(e.g fields or methods) contained in a |
| * {@link String} and returns a {@link BodyDeclaration} that represents it. |
| * |
| * @param body |
| * {@link String} containing Java body declaration |
| * @return BodyDeclaration representing the Java annotation |
| * @throws ParseException |
| * if the source code has parser errors |
| */ |
| public static BodyDeclaration parseBodyDeclaration(final String body) { |
| StringReader sr = new StringReader(body); |
| BodyDeclaration bd = new ASTParser(sr).AnnotationBodyDeclaration(); |
| sr.close(); |
| return bd; |
| } |
| |
| /** |
| * Comments are attributed to the thing the comment and are removed from |
| * allComments. |
| */ |
| private static void insertCommentsInCu(CompilationUnit cu, CommentsCollection commentsCollection){ |
| if (commentsCollection.size()==0) return; |
| |
| // I should sort all the direct children and the comments, if a comment is the first thing then it |
| // a comment to the CompilationUnit |
| // FIXME if there is no package it could be also a comment to the following class... |
| // so I could use some heuristics in these cases to distinguish the two cases |
| |
| List<Comment> comments = commentsCollection.getAll(); |
| PositionUtils.sortByBeginPosition(comments); |
| List<Node> children = cu.getChildrenNodes(); |
| PositionUtils.sortByBeginPosition(children); |
| |
| if (cu.getPackage()!=null && (children.size()==0 || PositionUtils.areInOrder(comments.get(0), children.get(0)))){ |
| cu.setComment(comments.get(0)); |
| comments.remove(0); |
| } |
| |
| insertCommentsInNode(cu,comments); |
| } |
| |
| private static boolean attributeLineCommentToNodeOrChild(Node node, LineComment lineComment) |
| { |
| // The node start and end at the same line as the comment, |
| // let's give to it the comment |
| if (node.getBeginLine()==lineComment.getBeginLine() && !node.hasComment()) |
| { |
| node.setComment(lineComment); |
| return true; |
| } else { |
| // try with all the children, sorted by reverse position (so the |
| // first one is the nearest to the comment |
| List<Node> children = new LinkedList<Node>(); |
| children.addAll(node.getChildrenNodes()); |
| PositionUtils.sortByBeginPosition(children); |
| Collections.reverse(children); |
| |
| for (Node child : children) |
| { |
| if (attributeLineCommentToNodeOrChild(child, lineComment)) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| } |
| |
| /** |
| * This method try to attributes the nodes received to child of the node. |
| * It returns the node that were not attributed. |
| */ |
| private static void insertCommentsInNode(Node node, List<Comment> commentsToAttribute){ |
| if (commentsToAttribute.size()==0) return; |
| |
| // the comments can: |
| // 1) Inside one of the child, then it is the child that have to associate them |
| // 2) If they are not inside a child they could be preceeding nothing, a comment or a child |
| // if they preceed a child they are assigned to it, otherweise they remain "orphans" |
| |
| List<Node> children = node.getChildrenNodes(); |
| PositionUtils.sortByBeginPosition(children); |
| |
| for (Node child : children){ |
| List<Comment> commentsInsideChild = new LinkedList<Comment>(); |
| for (Comment c : commentsToAttribute){ |
| if (PositionUtils.nodeContains(child, c, _doNotConsiderAnnotationsAsNodeStartForCodeAttribution)){ |
| commentsInsideChild.add(c); |
| } |
| } |
| commentsToAttribute.removeAll(commentsInsideChild); |
| insertCommentsInNode(child,commentsInsideChild); |
| } |
| |
| // I can attribute in line comments to elements preceeding them, if there |
| // is something contained in their line |
| List<Comment> attributedComments = new LinkedList<Comment>(); |
| for (Comment comment : commentsToAttribute) |
| { |
| if (comment.isLineComment()) |
| { |
| for (Node child : children) |
| { |
| if (child.getEndLine()==comment.getBeginLine()) |
| { |
| if (attributeLineCommentToNodeOrChild(child, comment.asLineComment())) |
| { |
| attributedComments.add(comment); |
| } |
| } |
| } |
| } |
| } |
| |
| // at this point I create an ordered list of all remaining comments and children |
| Comment previousComment = null; |
| attributedComments = new LinkedList<Comment>(); |
| List<Node> childrenAndComments = new LinkedList<Node>(); |
| childrenAndComments.addAll(children); |
| childrenAndComments.addAll(commentsToAttribute); |
| PositionUtils.sortByBeginPosition(childrenAndComments, _doNotConsiderAnnotationsAsNodeStartForCodeAttribution); |
| |
| for (Node thing : childrenAndComments){ |
| if (thing instanceof Comment){ |
| previousComment = (Comment)thing; |
| if (!previousComment.isOrphan()) |
| { |
| previousComment = null; |
| } |
| } else { |
| if (previousComment != null && !thing.hasComment()){ |
| if (!_doNotAssignCommentsPreceedingEmptyLines || !thereAreLinesBetween(previousComment, thing)) { |
| thing.setComment(previousComment); |
| attributedComments.add(previousComment); |
| previousComment = null; |
| } |
| } |
| } |
| } |
| |
| commentsToAttribute.removeAll(attributedComments); |
| |
| // all the remaining are orphan nodes |
| for (Comment c : commentsToAttribute){ |
| if (c.isOrphan()) { |
| node.addOrphanComment(c); |
| } |
| } |
| } |
| |
| private static boolean thereAreLinesBetween(Node a, Node b) |
| { |
| if (!PositionUtils.areInOrder(a, b)) |
| { |
| return thereAreLinesBetween(b, a); |
| } |
| int endOfA = a.getEndLine(); |
| return b.getBeginLine()>(a.getEndLine()+1); |
| } |
| |
| private static void insertComments(CompilationUnit cu, String code) throws IOException { |
| CommentsParser commentsParser = new CommentsParser(); |
| CommentsCollection allComments = commentsParser.parse(code); |
| |
| insertCommentsInCu(cu,allComments); |
| } |
| |
| } |