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.checks.coding; 020 021import com.google.common.collect.Sets; 022import com.puppycrawl.tools.checkstyle.api.AnnotationUtility; 023import com.puppycrawl.tools.checkstyle.api.DetailAST; 024import com.puppycrawl.tools.checkstyle.api.FullIdent; 025import com.puppycrawl.tools.checkstyle.api.TokenTypes; 026import java.util.Set; 027 028/** 029 * <p> 030 * Throwing java.lang.Error or java.lang.RuntimeException 031 * is almost never acceptable. 032 * </p> 033 * Check has following properties: 034 * <p> 035 * <b>illegalClassNames</b> - throw class names to reject. 036 * </p> 037 * <p> 038 * <b>ignoredMethodNames</b> - names of methods to ignore. 039 * </p> 040 * <p> 041 * <b>ignoreOverridenMethods</b> - ignore checking overriden methods (marked with Override 042 * or java.lang.Override annotation) default value is <b>true</b>. 043 * </p> 044 * 045 * @author Oliver Burn 046 * @author John Sirois 047 * @author <a href="mailto:nesterenko-aleksey@list.ru">Aleksey Nesterenko</a> 048 */ 049public final class IllegalThrowsCheck extends AbstractIllegalCheck 050{ 051 052 /** Default ignored method names. */ 053 private static final String[] DEFAULT_IGNORED_METHOD_NAMES = { 054 "finalize", 055 }; 056 057 /** property for ignoring overriden methods. */ 058 private boolean ignoreOverridenMethods = true; 059 060 /** methods which should be ignored. */ 061 private final Set<String> ignoredMethodNames = Sets.newHashSet(); 062 063 /** Creates new instance of the check. */ 064 public IllegalThrowsCheck() 065 { 066 super(new String[] {"Error", 067 "RuntimeException", "Throwable", 068 "java.lang.Error", 069 "java.lang.RuntimeException", 070 "java.lang.Throwable", 071 }); 072 setIgnoredMethodNames(DEFAULT_IGNORED_METHOD_NAMES); 073 } 074 075 @Override 076 public int[] getDefaultTokens() 077 { 078 return new int[] {TokenTypes.LITERAL_THROWS}; 079 } 080 081 @Override 082 public int[] getRequiredTokens() 083 { 084 return getDefaultTokens(); 085 } 086 087 @Override 088 public void visitToken(DetailAST detailAST) 089 { 090 final DetailAST methodDef = detailAST.getParent(); 091 DetailAST token = detailAST.getFirstChild(); 092 // Check if the method with the given name should be ignored. 093 if (!isIgnorableMethod(methodDef)) { 094 while (token != null) { 095 if (token.getType() != TokenTypes.COMMA) { 096 final FullIdent ident = FullIdent.createFullIdent(token); 097 if (isIllegalClassName(ident.getText())) { 098 log(token, "illegal.throw", ident.getText()); 099 } 100 } 101 token = token.getNextSibling(); 102 } 103 } 104 } 105 106 /** 107 * Checks if current method is ignorable due to Check's properties. 108 * @param methodDef {@link TokenTypes#METHOD_DEF METHOD_DEF} 109 * @return true if method is ignorable. 110 */ 111 private boolean isIgnorableMethod(DetailAST methodDef) 112 { 113 return shouldIgnoreMethod(methodDef.findFirstToken(TokenTypes.IDENT).getText()) 114 || ignoreOverridenMethods 115 && (AnnotationUtility.containsAnnotation(methodDef, "Override") 116 || AnnotationUtility.containsAnnotation(methodDef, "java.lang.Override")); 117 } 118 119 /** 120 * Check if the method is specified in the ignore method list 121 * @param name the name to check 122 * @return whether the method with the passed name should be ignored 123 */ 124 private boolean shouldIgnoreMethod(String name) 125 { 126 return ignoredMethodNames.contains(name); 127 } 128 129 /** 130 * Set the list of ignore method names. 131 * @param methodNames array of ignored method names 132 */ 133 public void setIgnoredMethodNames(String[] methodNames) 134 { 135 ignoredMethodNames.clear(); 136 for (String element : methodNames) { 137 ignoredMethodNames.add(element); 138 } 139 } 140 141 /** 142 * Sets <b>ignoreOverridenMethods</b> property value. 143 * @param ignoreOverridenMethods Check's property. 144 */ 145 public void setIgnoreOverridenMethods(boolean ignoreOverridenMethods) 146 { 147 this.ignoreOverridenMethods = ignoreOverridenMethods; 148 } 149}