1 /* 2 * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.javadoc.internal.doclets.toolkit.taglets; 27 28 29 import javax.lang.model.element.Element; 30 import javax.lang.model.element.TypeElement; 31 import javax.lang.model.element.VariableElement; 32 import javax.lang.model.util.Elements; 33 34 import com.sun.source.doctree.DocTree; 35 import jdk.javadoc.internal.doclets.toolkit.Configuration; 36 import jdk.javadoc.internal.doclets.toolkit.Content; 37 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; 38 import jdk.javadoc.internal.doclets.toolkit.util.Utils; 39 40 import static com.sun.source.doctree.DocTree.Kind.*; 41 42 /** 43 * An inline Taglet representing the value tag. This tag should only be used with 44 * constant fields that have a value. It is used to access the value of constant 45 * fields. This inline tag has an optional field name parameter. If the name is 46 * specified, the constant value is retrieved from the specified field. A link 47 * is also created to the specified field. If a name is not specified, the value 48 * is retrieved for the field that the inline tag appears on. The name is specifed 49 * in the following format: [fully qualified class name]#[constant field name]. 50 * 51 * <p><b>This is NOT part of any supported API. 52 * If you write code that depends on this, you do so at your own risk. 53 * This code and its internal interfaces are subject to change or 54 * deletion without notice.</b> 55 * 56 * @author Jamie Ho 57 * @since 1.4 58 */ 59 60 public class ValueTaglet extends BaseInlineTaglet { 61 62 /** 63 * Construct a new ValueTaglet. 64 */ 65 public ValueTaglet() { 66 name = VALUE.tagName; 67 } 68 69 /** 70 * Will return false because this inline tag may 71 * only appear in Fields. 72 * @return false since this is not a method. 73 */ 74 public boolean inMethod() { 75 return true; 76 } 77 78 /** 79 * Will return false because this inline tag may 80 * only appear in Fields. 81 * @return false since this is not a method. 82 */ 83 public boolean inConstructor() { 84 return true; 85 } 86 87 /** 88 * Will return false because this inline tag may 89 * only appear in Fields. 90 * @return false since this is not a method. 91 */ 92 public boolean inOverview() { 93 return true; 94 } 95 96 /** 97 * Will return false because this inline tag may 98 * only appear in Fields. 99 * @return false since this is not a method. 100 */ 101 public boolean inPackage() { 102 return true; 103 } 104 105 /** 106 * Will return false because this inline tag may 107 * only appear in Fields. 108 * @return false since this is not a method. 109 */ 110 public boolean inType() { 111 return true; 112 } 113 114 /** 115 * Given the name of the field, return the corresponding VariableElement. Return null 116 * due to invalid use of value tag if the name is null or empty string and if 117 * the value tag is not used on a field. 118 * 119 * @param holder the element holding the tag 120 * @param config the current configuration of the doclet. 121 * @param tag the value tag. 122 * 123 * @return the corresponding VariableElement. If the name is null or empty string, 124 * return field that the value tag was used in. Return null if the name is null 125 * or empty string and if the value tag is not used on a field. 126 */ 127 private VariableElement getVariableElement(Element holder, Configuration config, DocTree tag) { 128 Utils utils = config.utils; 129 CommentHelper ch = utils.getCommentHelper(holder); 130 String signature = ch.getReferencedSignature(tag); 131 132 if (signature == null) { // no reference 133 //Base case: no label. 134 if (utils.isVariableElement(holder)) { 135 return (VariableElement)(holder); 136 } else { 137 // If the value tag does not specify a parameter which is a valid field and 138 // it is not used within the comments of a valid field, return null. 139 return null; 140 } 141 } 142 143 String[] sigValues = signature.split("#"); 144 String memberName = null; 145 TypeElement te = null; 146 if (sigValues.length == 1) { 147 //Case 2: @value in same class. 148 if (utils.isExecutableElement(holder) || utils.isVariableElement(holder)) { 149 te = utils.getEnclosingTypeElement(holder); 150 } else if (utils.isTypeElement(holder)) { 151 te = utils.getTopMostContainingTypeElement(holder); 152 } 153 memberName = sigValues[0]; 154 } else { 155 //Case 3: @value in different class. 156 Elements elements = config.root.getElementUtils(); 157 te = elements.getTypeElement(sigValues[0]); 158 memberName = sigValues[1]; 159 } 160 if (te == null) { 161 return null; 162 } 163 for (Element field : utils.getFields(te)) { 164 if (utils.getSimpleName(field).equals(memberName)) { 165 return (VariableElement)field; 166 } 167 } 168 return null; 169 } 170 171 /** 172 * {@inheritDoc} 173 */ 174 public Content getTagletOutput(Element holder, DocTree tag, TagletWriter writer) { 175 Utils utils = writer.configuration().utils; 176 VariableElement field = getVariableElement(holder, writer.configuration(), tag); 177 if (field == null) { 178 if (tag.toString().isEmpty()) { 179 //Invalid use of @value 180 writer.getMsgRetriever().warning(holder, 181 "doclet.value_tag_invalid_use"); 182 } else { 183 //Reference is unknown. 184 writer.getMsgRetriever().warning(holder, 185 "doclet.value_tag_invalid_reference", tag.toString()); 186 } 187 } else if (field.getConstantValue() != null) { 188 return writer.valueTagOutput(field, 189 utils.constantValueExpresion(field), 190 // TODO: investigate and cleanup 191 // in the j.l.m world, equals will not be accurate 192 // !field.equals(tag.holder()) 193 !utils.elementsEqual(field, holder) 194 ); 195 } else { 196 //Referenced field is not a constant. 197 writer.getMsgRetriever().warning(holder, 198 "doclet.value_tag_invalid_constant", utils.getSimpleName(field)); 199 } 200 return writer.getOutputInstance(); 201 } 202 }