001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2017 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.doclets; 021 022import java.io.FileNotFoundException; 023import java.io.FileOutputStream; 024import java.io.OutputStreamWriter; 025import java.io.PrintWriter; 026import java.io.Writer; 027import java.nio.charset.StandardCharsets; 028 029import com.sun.javadoc.ClassDoc; 030import com.sun.javadoc.DocErrorReporter; 031import com.sun.javadoc.FieldDoc; 032import com.sun.javadoc.RootDoc; 033 034/** 035 * Doclet which is used to write property file with short descriptions 036 * (first sentences) of TokenTypes' constants. 037 * Request: 724871 038 * For ide plugins (like the eclipse plugin) it would be useful to have 039 * programmatic access to the first sentence of the TokenType constants, 040 * so they can use them in their configuration gui. 041 * @author o_sukhodolsky 042 */ 043public final class TokenTypesDoclet { 044 /** Command line option to specify file to write output of the doclet. */ 045 private static final String DEST_FILE_OPT = "-destfile"; 046 047 /** Stop instances being created. */ 048 private TokenTypesDoclet() { 049 } 050 051 /** 052 * The doclet's starter method. 053 * @param root {@code RootDoc} given to the doclet 054 * @return true if the given {@code RootDoc} is processed. 055 * @exception FileNotFoundException will be thrown if the doclet 056 * will be unable to write to the specified file. 057 */ 058 public static boolean start(RootDoc root) 059 throws FileNotFoundException { 060 final String fileName = getDestFileName(root.options()); 061 final FileOutputStream fos = new FileOutputStream(fileName); 062 final Writer osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8); 063 final PrintWriter writer = new PrintWriter(osw, false); 064 065 try { 066 final ClassDoc[] classes = root.classes(); 067 final FieldDoc[] fields = classes[0].fields(); 068 for (final FieldDoc field : fields) { 069 if (field.isStatic() && field.isPublic() && field.isFinal() 070 && "int".equals(field.type().qualifiedTypeName())) { 071 if (field.firstSentenceTags().length != 1) { 072 final String message = "Should be only one tag."; 073 throw new IllegalArgumentException(message); 074 } 075 writer.println(field.name() + "=" 076 + field.firstSentenceTags()[0].text()); 077 } 078 } 079 } 080 finally { 081 writer.close(); 082 } 083 084 return true; 085 } 086 087 /** 088 * Returns option length (how many parts are in option). 089 * @param option option name to process 090 * @return option length (how many parts are in option). 091 */ 092 public static int optionLength(String option) { 093 int length = 0; 094 if (DEST_FILE_OPT.equals(option)) { 095 length = 2; 096 } 097 return length; 098 } 099 100 /** 101 * Checks that only valid options was specified. 102 * @param options all parsed options 103 * @param reporter the reporter to report errors. 104 * @return true if only valid options was specified 105 */ 106 public static boolean checkOptions(String[][] options, DocErrorReporter reporter) { 107 boolean foundDestFileOption = false; 108 boolean onlyOneDestFileOption = true; 109 for (final String[] opt : options) { 110 if (DEST_FILE_OPT.equals(opt[0])) { 111 if (foundDestFileOption) { 112 reporter.printError("Only one -destfile option allowed."); 113 onlyOneDestFileOption = false; 114 break; 115 } 116 foundDestFileOption = true; 117 } 118 } 119 if (!foundDestFileOption) { 120 reporter.printError("Usage: javadoc -destfile file -doclet TokenTypesDoclet ..."); 121 } 122 return onlyOneDestFileOption && foundDestFileOption; 123 } 124 125 /** 126 * Reads destination file name. 127 * @param options all specified options. 128 * @return destination file name 129 */ 130 private static String getDestFileName(String[]... options) { 131 String fileName = null; 132 for (final String[] opt : options) { 133 if (DEST_FILE_OPT.equals(opt[0])) { 134 fileName = opt[1]; 135 } 136 } 137 return fileName; 138 } 139}