1 /*
2  * Copyright (c) 1997, 2018, 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 com.sun.tools.javadoc.main;
27 
28 import com.sun.source.util.TreePath;
29 import java.lang.reflect.Modifier;
30 
31 import com.sun.javadoc.*;
32 
33 import com.sun.tools.javac.code.Flags;
34 import com.sun.tools.javac.code.Symbol.ClassSymbol;
35 import com.sun.tools.javac.code.Symbol.VarSymbol;
36 
37 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
38 
39 /**
40  * Represents a field in a java class.
41  *
42  *  <p><b>This is NOT part of any supported API.
43  *  If you write code that depends on this, you do so at your own risk.
44  *  This code and its internal interfaces are subject to change or
45  *  deletion without notice.</b>
46  *
47  * @see MemberDocImpl
48  *
49  * @since 1.2
50  * @author Robert Field
51  * @author Neal Gafter (rewrite)
52  * @author Scott Seligman (generics, enums, annotations)
53  */
54 @Deprecated(since="9", forRemoval=true)
55 @SuppressWarnings("removal")
56 public class FieldDocImpl extends MemberDocImpl implements FieldDoc {
57 
58     protected final VarSymbol sym;
59 
60     /**
61      * Constructor.
62      */
FieldDocImpl(DocEnv env, VarSymbol sym, TreePath treePath)63     public FieldDocImpl(DocEnv env, VarSymbol sym, TreePath treePath) {
64         super(env, sym, treePath);
65         this.sym = sym;
66     }
67 
68     /**
69      * Constructor.
70      */
FieldDocImpl(DocEnv env, VarSymbol sym)71     public FieldDocImpl(DocEnv env, VarSymbol sym) {
72         this(env, sym, null);
73     }
74 
75     /**
76      * Returns the flags in terms of javac's flags
77      */
getFlags()78     protected long getFlags() {
79         return sym.flags();
80     }
81 
82     /**
83      * Identify the containing class
84      */
getContainingClass()85     protected ClassSymbol getContainingClass() {
86         return sym.enclClass();
87     }
88 
89     /**
90      * Get type of this field.
91      */
type()92     public com.sun.javadoc.Type type() {
93         return TypeMaker.getType(env, sym.type, false);
94     }
95 
96     /**
97      * Get the value of a constant field.
98      *
99      * @return the value of a constant field. The value is
100      * automatically wrapped in an object if it has a primitive type.
101      * If the field is not constant, returns null.
102      */
constantValue()103     public Object constantValue() {
104         Object result = sym.getConstValue();
105         if (result != null && sym.type.hasTag(BOOLEAN))
106             // javac represents false and true as Integers 0 and 1
107             result = Boolean.valueOf(((Integer)result).intValue() != 0);
108         return result;
109     }
110 
111     /**
112      * Get the value of a constant field.
113      *
114      * @return the text of a Java language expression whose value
115      * is the value of the constant. The expression uses no identifiers
116      * other than primitive literals. If the field is
117      * not constant, returns null.
118      */
constantValueExpression()119     public String constantValueExpression() {
120         return constantValueExpression(constantValue());
121     }
122 
123     /**
124      * A static version of the above.
125      */
constantValueExpression(Object cb)126     static String constantValueExpression(Object cb) {
127         if (cb == null) return null;
128         if (cb instanceof Character) return sourceForm(((Character)cb).charValue());
129         if (cb instanceof Byte) return sourceForm(((Byte)cb).byteValue());
130         if (cb instanceof String) return sourceForm((String)cb);
131         if (cb instanceof Double) return sourceForm(((Double)cb).doubleValue(), 'd');
132         if (cb instanceof Float) return sourceForm(((Float)cb).doubleValue(), 'f');
133         if (cb instanceof Long) return cb + "L";
134         return cb.toString(); // covers int, short
135     }
136         // where
sourceForm(double v, char suffix)137         private static String sourceForm(double v, char suffix) {
138             if (Double.isNaN(v))
139                 return "0" + suffix + "/0" + suffix;
140             if (v == Double.POSITIVE_INFINITY)
141                 return "1" + suffix + "/0" + suffix;
142             if (v == Double.NEGATIVE_INFINITY)
143                 return "-1" + suffix + "/0" + suffix;
144             return v + (suffix == 'f' || suffix == 'F' ? "" + suffix : "");
145         }
sourceForm(char c)146         private static String sourceForm(char c) {
147             StringBuilder buf = new StringBuilder(8);
148             buf.append('\'');
149             sourceChar(c, buf);
150             buf.append('\'');
151             return buf.toString();
152         }
sourceForm(byte c)153         private static String sourceForm(byte c) {
154             return "0x" + Integer.toString(c & 0xff, 16);
155         }
sourceForm(String s)156         private static String sourceForm(String s) {
157             StringBuilder buf = new StringBuilder(s.length() + 5);
158             buf.append('\"');
159             for (int i=0; i<s.length(); i++) {
160                 char c = s.charAt(i);
161                 sourceChar(c, buf);
162             }
163             buf.append('\"');
164             return buf.toString();
165         }
sourceChar(char c, StringBuilder buf)166         private static void sourceChar(char c, StringBuilder buf) {
167             switch (c) {
168             case '\b': buf.append("\\b"); return;
169             case '\t': buf.append("\\t"); return;
170             case '\n': buf.append("\\n"); return;
171             case '\f': buf.append("\\f"); return;
172             case '\r': buf.append("\\r"); return;
173             case '\"': buf.append("\\\""); return;
174             case '\'': buf.append("\\\'"); return;
175             case '\\': buf.append("\\\\"); return;
176             default:
177                 if (isPrintableAscii(c)) {
178                     buf.append(c); return;
179                 }
180                 unicodeEscape(c, buf);
181                 return;
182             }
183         }
unicodeEscape(char c, StringBuilder buf)184         private static void unicodeEscape(char c, StringBuilder buf) {
185             final String chars = "0123456789abcdef";
186             buf.append("\\u");
187             buf.append(chars.charAt(15 & (c>>12)));
188             buf.append(chars.charAt(15 & (c>>8)));
189             buf.append(chars.charAt(15 & (c>>4)));
190             buf.append(chars.charAt(15 & (c>>0)));
191         }
isPrintableAscii(char c)192         private static boolean isPrintableAscii(char c) {
193             return c >= ' ' && c <= '~';
194         }
195 
196     /**
197      * Return true if this field is included in the active set.
198      */
isIncluded()199     public boolean isIncluded() {
200         return containingClass().isIncluded() && env.shouldDocument(sym);
201     }
202 
203     /**
204      * Is this Doc item a field (but not an enum constant?
205      */
206     @Override
isField()207     public boolean isField() {
208         return !isEnumConstant();
209     }
210 
211     /**
212      * Is this Doc item an enum constant?
213      * (For legacy doclets, return false.)
214      */
215     @Override
isEnumConstant()216     public boolean isEnumConstant() {
217         return (getFlags() & Flags.ENUM) != 0 &&
218                !env.legacyDoclet;
219     }
220 
221     /**
222      * Return true if this field is transient
223      */
isTransient()224     public boolean isTransient() {
225         return Modifier.isTransient(getModifiers());
226     }
227 
228     /**
229      * Return true if this field is volatile
230      */
isVolatile()231     public boolean isVolatile() {
232         return Modifier.isVolatile(getModifiers());
233     }
234 
235     /**
236      * Returns true if this field was synthesized by the compiler.
237      */
isSynthetic()238     public boolean isSynthetic() {
239         return (getFlags() & Flags.SYNTHETIC) != 0;
240     }
241 
242     /**
243      * Return the serialField tags in this FieldDocImpl item.
244      *
245      * @return an array of <tt>SerialFieldTagImpl</tt> containing all
246      *         <code>&#64;serialField</code> tags.
247      */
serialFieldTags()248     public SerialFieldTag[] serialFieldTags() {
249         return comment().serialFieldTags();
250     }
251 
name()252     public String name() {
253         if (name == null) {
254             name = sym.name.toString();
255         }
256         return name;
257     }
258 
259     private String name;
260 
qualifiedName()261     public String qualifiedName() {
262         if (qualifiedName == null) {
263             qualifiedName = sym.enclClass().getQualifiedName() + "." + name();
264         }
265         return qualifiedName;
266     }
267 
268     private String qualifiedName;
269 
270     /**
271      * Return the source position of the entity, or null if
272      * no position is available.
273      */
274     @Override
position()275     public SourcePosition position() {
276         if (sym.enclClass().sourcefile == null) return null;
277         return SourcePositionImpl.make(sym.enclClass().sourcefile,
278                                        (tree==null) ? 0 : tree.pos,
279                                        lineMap);
280     }
281 }
282