1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.googlejavaformat.java; 16 17 import com.sun.source.tree.ClassTree; 18 import com.sun.source.tree.CompoundAssignmentTree; 19 import com.sun.source.tree.ExpressionTree; 20 import com.sun.source.tree.IdentifierTree; 21 import com.sun.source.tree.MemberSelectTree; 22 import com.sun.source.tree.MethodInvocationTree; 23 import com.sun.source.tree.ParenthesizedTree; 24 import com.sun.source.tree.Tree; 25 import com.sun.source.util.TreePath; 26 import com.sun.tools.javac.tree.JCTree; 27 import com.sun.tools.javac.tree.Pretty; 28 import com.sun.tools.javac.tree.TreeInfo; 29 import java.io.IOError; 30 import java.io.IOException; 31 import javax.lang.model.element.Name; 32 33 /** Utilities for working with {@link Tree}s. */ 34 class Trees { 35 /** Returns the length of the source for the node. */ getLength(Tree tree, TreePath path)36 static int getLength(Tree tree, TreePath path) { 37 return getEndPosition(tree, path) - getStartPosition(tree); 38 } 39 40 /** Returns the source start position of the node. */ getStartPosition(Tree expression)41 static int getStartPosition(Tree expression) { 42 return ((JCTree) expression).getStartPosition(); 43 } 44 45 /** Returns the source end position of the node. */ getEndPosition(Tree expression, TreePath path)46 static int getEndPosition(Tree expression, TreePath path) { 47 return ((JCTree) expression) 48 .getEndPosition(((JCTree.JCCompilationUnit) path.getCompilationUnit()).endPositions); 49 } 50 51 /** Returns the source text for the node. */ getSourceForNode(Tree node, TreePath path)52 static String getSourceForNode(Tree node, TreePath path) { 53 CharSequence source; 54 try { 55 source = path.getCompilationUnit().getSourceFile().getCharContent(false); 56 } catch (IOException e) { 57 throw new IOError(e); 58 } 59 return source.subSequence(getStartPosition(node), getEndPosition(node, path)).toString(); 60 } 61 62 /** Returns the simple name of a (possibly qualified) method invocation expression. */ getMethodName(MethodInvocationTree methodInvocation)63 static Name getMethodName(MethodInvocationTree methodInvocation) { 64 ExpressionTree select = methodInvocation.getMethodSelect(); 65 return select instanceof MemberSelectTree 66 ? ((MemberSelectTree) select).getIdentifier() 67 : ((IdentifierTree) select).getName(); 68 } 69 70 /** Returns the receiver of a qualified method invocation expression, or {@code null}. */ getMethodReceiver(MethodInvocationTree methodInvocation)71 static ExpressionTree getMethodReceiver(MethodInvocationTree methodInvocation) { 72 ExpressionTree select = methodInvocation.getMethodSelect(); 73 return select instanceof MemberSelectTree ? ((MemberSelectTree) select).getExpression() : null; 74 } 75 76 /** Returns the string name of an operator, including assignment and compound assignment. */ operatorName(ExpressionTree expression)77 static String operatorName(ExpressionTree expression) { 78 JCTree.Tag tag = ((JCTree) expression).getTag(); 79 if (tag == JCTree.Tag.ASSIGN) { 80 return "="; 81 } 82 boolean assignOp = expression instanceof CompoundAssignmentTree; 83 if (assignOp) { 84 tag = tag.noAssignOp(); 85 } 86 String name = new Pretty(/*writer*/ null, /*sourceOutput*/ true).operatorName(tag); 87 return assignOp ? name + "=" : name; 88 } 89 90 /** Returns the precedence of an expression's operator. */ precedence(ExpressionTree expression)91 static int precedence(ExpressionTree expression) { 92 return TreeInfo.opPrec(((JCTree) expression).getTag()); 93 } 94 95 /** 96 * Returns the enclosing type declaration (class, enum, interface, or annotation) for the given 97 * path. 98 */ getEnclosingTypeDeclaration(TreePath path)99 static ClassTree getEnclosingTypeDeclaration(TreePath path) { 100 for (; path != null; path = path.getParentPath()) { 101 switch (path.getLeaf().getKind()) { 102 case CLASS: 103 case ENUM: 104 case INTERFACE: 105 case ANNOTATED_TYPE: 106 return (ClassTree) path.getLeaf(); 107 default: 108 break; 109 } 110 } 111 throw new AssertionError(); 112 } 113 114 /** Skips a single parenthesized tree. */ skipParen(ExpressionTree node)115 static ExpressionTree skipParen(ExpressionTree node) { 116 return ((ParenthesizedTree) node).getExpression(); 117 } 118 } 119