001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2019 the original author or authors. 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//////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.coding; 021 022import com.puppycrawl.tools.checkstyle.StatelessCheck; 023import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 024import com.puppycrawl.tools.checkstyle.api.DetailAST; 025import com.puppycrawl.tools.checkstyle.api.TokenTypes; 026 027/** 028 * <p> 029 * Checks if unnecessary semicolon is used in last resource declaration. 030 * </p> 031 * <ul> 032 * <li> 033 * Property {@code allowWhenNoBraceAfterSemicolon} - 034 * Allow unnecessary semicolon if closing paren is not on the same line. 035 * Default value is {@code true}. 036 * </li> 037 * </ul> 038 * <p> 039 * To configure the check: 040 * </p> 041 * <pre> 042 * <module name="UnnecessarySemicolonInTryWithResources"/> 043 * </pre> 044 * <p> 045 * Example of violations 046 * </p> 047 * <pre> 048 * class A { 049 * void method() throws IOException { 050 * try(Reader r1 = new PipedReader();){} // violation 051 * try(Reader r4 = new PipedReader();Reader r5 = new PipedReader() 052 * ;){} // violation 053 * try(Reader r6 = new PipedReader(); 054 * Reader r7 055 * = new PipedReader(); 056 * ){} 057 * } 058 * } 059 * </pre> 060 * <p> 061 * To configure the check to detect unnecessary semicolon 062 * if closing paren is not on same line 063 * </p> 064 * <pre> 065 * <module name="UnnecessarySemicolonInTryWithResources"> 066 * <property name="allowWhenNoBraceAfterSemicolon" value="false"/> 067 * </module> 068 * </pre> 069 * <p> 070 * Example of exclusion 071 * </p> 072 * <pre> 073 * class A { 074 * void method() throws IOException { 075 * try(Reader r1 = new PipedReader();){} // violation 076 * try(Reader r6 = new PipedReader(); 077 * Reader r7 = new PipedReader(); // violation 078 * ){} 079 * } 080 * } 081 * </pre> 082 * 083 * @since 8.22 084 */ 085@StatelessCheck 086public final class UnnecessarySemicolonInTryWithResourcesCheck extends AbstractCheck { 087 088 /** 089 * A key is pointing to the warning message text in "messages.properties" 090 * file. 091 */ 092 public static final String MSG_SEMI = "unnecessary.semicolon"; 093 094 /** Allow unnecessary semicolon if closing paren is not on the same line. */ 095 private boolean allowWhenNoBraceAfterSemicolon = true; 096 097 @Override 098 public int[] getDefaultTokens() { 099 return getRequiredTokens(); 100 } 101 102 @Override 103 public int[] getAcceptableTokens() { 104 return getRequiredTokens(); 105 } 106 107 @Override 108 public int[] getRequiredTokens() { 109 return new int[] { 110 TokenTypes.RESOURCE_SPECIFICATION, 111 }; 112 } 113 114 /** 115 * Setter to allow unnecessary semicolon if closing paren is not on the same line. 116 * @param allowWhenNoBraceAfterSemicolon a value to set. 117 */ 118 public void setAllowWhenNoBraceAfterSemicolon(boolean allowWhenNoBraceAfterSemicolon) { 119 this.allowWhenNoBraceAfterSemicolon = allowWhenNoBraceAfterSemicolon; 120 } 121 122 @Override 123 public void visitToken(DetailAST ast) { 124 final DetailAST closingParen = ast.getLastChild(); 125 final DetailAST tokenBeforeCloseParen = closingParen.getPreviousSibling(); 126 if (tokenBeforeCloseParen.getType() == TokenTypes.SEMI 127 && (!allowWhenNoBraceAfterSemicolon 128 || closingParen.getLineNo() == tokenBeforeCloseParen.getLineNo())) { 129 log(tokenBeforeCloseParen, MSG_SEMI); 130 } 131 } 132 133}