001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2014 Oliver Burn 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019package com.puppycrawl.tools.checkstyle.api; 020 021 022/** 023 * Contains utility methods designed to work with annotations. 024 * 025 * @author Travis Schneeberger 026 */ 027public final class AnnotationUtility 028{ 029 /** 030 * private utility constructor. 031 * @throws UnsupportedOperationException if called 032 */ 033 private AnnotationUtility() 034 { 035 throw new UnsupportedOperationException("do not instantiate."); 036 } 037 038 /** 039 * Checks to see if the AST is annotated with 040 * the passed in annotation. 041 * 042 * <p> 043 * This method will not look for imports or package 044 * statements to detect the passed in annotation. 045 * </p> 046 * 047 * <p> 048 * To check if an AST contains a passed in annotation 049 * taking into account fully-qualified names 050 * (ex: java.lang.Override, Override) 051 * this method will need to be called twice. Once for each 052 * name given. 053 * </p> 054 * 055 * @param ast the current node 056 * @param annotation the annotation name to check for 057 * @return true if contains the annotation 058 * @throws NullPointerException if the ast or 059 * annotation is null 060 */ 061 public static boolean containsAnnotation(final DetailAST ast, 062 String annotation) 063 { 064 return AnnotationUtility.getAnnotation(ast, annotation) != null; 065 } 066 067 /** 068 * Checks to see if the AST is annotated with 069 * any annotation. 070 * 071 * @param ast the current node 072 * @return true if contains an annotation 073 * @throws NullPointerException if the ast is null 074 */ 075 public static boolean containsAnnotation(final DetailAST ast) 076 { 077 final DetailAST holder = AnnotationUtility.getAnnotationHolder(ast); 078 return holder != null && holder.branchContains(TokenTypes.ANNOTATION); 079 } 080 081 /** 082 * Gets the AST that holds a series of annotations for the 083 * potentially annotated AST. Returns <code>null</code> 084 * the passed in AST is not have an Annotation Holder. 085 * 086 * @param ast the current node 087 * @return the Annotation Holder 088 * @throws NullPointerException if the ast is null 089 */ 090 public static DetailAST getAnnotationHolder(DetailAST ast) 091 { 092 if (ast == null) { 093 throw new NullPointerException("the ast is null"); 094 } 095 096 final DetailAST annotationHolder; 097 098 if (ast.getType() == TokenTypes.ENUM_CONSTANT_DEF 099 || ast.getType() == TokenTypes.PACKAGE_DEF) 100 { 101 annotationHolder = ast.findFirstToken(TokenTypes.ANNOTATIONS); 102 } 103 else { 104 annotationHolder = ast.findFirstToken(TokenTypes.MODIFIERS); 105 } 106 107 return annotationHolder; 108 } 109 110 /** 111 * Checks to see if the AST is annotated with 112 * the passed in annotation and return the AST 113 * representing that annotation. 114 * 115 * <p> 116 * This method will not look for imports or package 117 * statements to detect the passed in annotation. 118 * </p> 119 * 120 * <p> 121 * To check if an AST contains a passed in annotation 122 * taking into account fully-qualified names 123 * (ex: java.lang.Override, Override) 124 * this method will need to be called twice. Once for each 125 * name given. 126 * </p> 127 * 128 * @param ast the current node 129 * @param annotation the annotation name to check for 130 * @return the AST representing that annotation 131 * @throws NullPointerException if the ast or 132 * annotation is null 133 */ 134 public static DetailAST getAnnotation(final DetailAST ast, 135 String annotation) 136 { 137 if (ast == null) { 138 throw new NullPointerException("the ast is null"); 139 } 140 141 if (annotation == null) { 142 throw new NullPointerException("the annotation is null"); 143 } 144 145 if (annotation.trim().length() == 0) { 146 throw new IllegalArgumentException("the annotation" 147 + "is empty or spaces"); 148 } 149 150 final DetailAST holder = AnnotationUtility.getAnnotationHolder(ast); 151 152 for (DetailAST child = holder.getFirstChild(); 153 child != null; child = child.getNextSibling()) 154 { 155 if (child.getType() == TokenTypes.ANNOTATION) { 156 final DetailAST at = child.getFirstChild(); 157 final String name = 158 FullIdent.createFullIdent(at.getNextSibling()).getText(); 159 if (annotation.equals(name)) { 160 return child; 161 } 162 } 163 } 164 165 return null; 166 } 167 168 /** 169 * Checks to see what the passed in AST (representing 170 * an annotation) is annotating. 171 * 172 * @param ast the AST representing an annotation. 173 * @return the AST the annotation is annotating. 174 * @throws NullPointerException if the ast is null 175 * @throws IllegalArgumentException if the ast is not 176 * an {@link TokenTypes#ANNOTATION} 177 */ 178 public static DetailAST annotatingWhat(DetailAST ast) 179 { 180 if (ast == null) { 181 throw new NullPointerException("the ast is null"); 182 } 183 184 if (ast.getType() != TokenTypes.ANNOTATION) { 185 throw new IllegalArgumentException( 186 "The ast is not an annotation. AST: " + ast); 187 } 188 189 return ast.getParent().getParent(); 190 } 191 192 /** 193 * Checks to see if the passed in AST (representing 194 * an annotation) is annotating the passed in type. 195 * @param ast the AST representing an annotation 196 * @param tokenType the passed in type 197 * @return true if the annotation is annotating a type 198 * equal to the passed in type 199 * @throws NullPointerException if the ast is null 200 * @throws IllegalArgumentException if the ast is not 201 * an {@link TokenTypes#ANNOTATION} 202 */ 203 public static boolean isAnnotatingType(DetailAST ast, int tokenType) 204 { 205 final DetailAST astNode = AnnotationUtility.annotatingWhat(ast); 206 return astNode.getType() == tokenType; 207 } 208}