WorkArounds.java revision 3294:9adfb22ff08f
138061Smsmith/*
255939Snsouch * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
370608Snsouch * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
438061Smsmith *
538061Smsmith * This code is free software; you can redistribute it and/or modify it
638061Smsmith * under the terms of the GNU General Public License version 2 only, as
738061Smsmith * published by the Free Software Foundation.  Oracle designates this
838061Smsmith * particular file as subject to the "Classpath" exception as provided
938061Smsmith * by Oracle in the LICENSE file that accompanied this code.
1038061Smsmith *
1138061Smsmith * This code is distributed in the hope that it will be useful, but WITHOUT
1238061Smsmith * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1338061Smsmith * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1438061Smsmith * version 2 for more details (a copy is included in the LICENSE file that
1538061Smsmith * accompanied this code).
1638061Smsmith *
1738061Smsmith * You should have received a copy of the GNU General Public License version
1838061Smsmith * 2 along with this work; if not, write to the Free Software Foundation,
1938061Smsmith * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2038061Smsmith *
2138061Smsmith * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2238061Smsmith * or visit www.oracle.com if you need additional information or have any
2338061Smsmith * questions.
2438061Smsmith */
2538061Smsmith
2638061Smsmithpackage jdk.javadoc.internal.doclets.toolkit;
2738061Smsmith
2838061Smsmithimport java.util.ArrayList;
2938061Smsmithimport java.util.Arrays;
30119418Sobrienimport java.util.Collection;
31119418Sobrienimport java.util.Collections;
32119418Sobrienimport java.util.HashMap;
3355205Speterimport java.util.List;
3438061Smsmithimport java.util.Map;
3538061Smsmithimport java.util.SortedSet;
3655939Snsouchimport java.util.TreeSet;
3755939Snsouch
3838061Smsmithimport javax.lang.model.element.AnnotationMirror;
3938061Smsmithimport javax.lang.model.element.Element;
4038061Smsmithimport javax.lang.model.element.ExecutableElement;
4155205Speterimport javax.lang.model.element.ModuleElement;
4238061Smsmithimport javax.lang.model.element.PackageElement;
4342475Snsouchimport javax.lang.model.element.TypeElement;
4442475Snsouchimport javax.lang.model.element.VariableElement;
4555939Snsouchimport javax.lang.model.type.TypeMirror;
4638061Smsmithimport javax.lang.model.util.Elements;
4738061Smsmithimport javax.tools.JavaFileObject;
4838061Smsmith
4938061Smsmithimport com.sun.source.tree.CompilationUnitTree;
5055939Snsouchimport com.sun.source.util.JavacTask;
5155939Snsouchimport com.sun.source.util.TreePath;
5238061Smsmithimport com.sun.tools.doclint.DocLint;
5338061Smsmithimport com.sun.tools.javac.api.BasicJavacTask;
5438061Smsmithimport com.sun.tools.javac.code.Attribute;
5538061Smsmithimport com.sun.tools.javac.code.Flags;
5638061Smsmithimport com.sun.tools.javac.code.Scope;
5738061Smsmithimport com.sun.tools.javac.code.Symbol;
5838061Smsmithimport com.sun.tools.javac.code.Symbol.ClassSymbol;
5938061Smsmithimport com.sun.tools.javac.code.Symbol.MethodSymbol;
6038061Smsmithimport com.sun.tools.javac.code.Symbol.VarSymbol;
6138061Smsmithimport com.sun.tools.javac.comp.AttrContext;
6238061Smsmithimport com.sun.tools.javac.comp.Env;
6338061Smsmithimport com.sun.tools.javac.model.JavacElements;
6438061Smsmithimport com.sun.tools.javac.model.JavacTypes;
6538061Smsmithimport com.sun.tools.javac.util.Names;
6638061Smsmith
6738061Smsmithimport jdk.javadoc.internal.doclets.toolkit.util.Utils;
6838061Smsmithimport jdk.javadoc.internal.tool.DocEnv;
6938061Smsmithimport jdk.javadoc.internal.tool.RootDocImpl;
7038061Smsmith
7138061Smsmithimport static com.sun.tools.javac.code.Kinds.Kind.*;
7238061Smsmithimport static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
7338061Smsmith
7438061Smsmithimport static javax.lang.model.element.ElementKind.*;
7538061Smsmith
7638061Smsmith/**
7738061Smsmith * A quarantine class to isolate all the workarounds and bridges to
7838061Smsmith * a locality. This class should eventually disappear once all the
7938061Smsmith * standard APIs support the needed interfaces.
8038061Smsmith *
8138061Smsmith *
8238061Smsmith *  <p><b>This is NOT part of any supported API.
8338061Smsmith *  If you write code that depends on this, you do so at your own risk.
8439134Snsouch *  This code and its internal interfaces are subject to change or
8539134Snsouch *  deletion without notice.</b>
8638061Smsmith */
8738061Smsmithpublic class WorkArounds {
8838061Smsmith
8938061Smsmith    public final Configuration configuration;
9038061Smsmith    public final DocEnv env;
9138061Smsmith    public final Utils utils;
9238061Smsmith
9338061Smsmith    private DocLint doclint;
9438061Smsmith
9538061Smsmith    public WorkArounds(Configuration configuration) {
9638061Smsmith        this.configuration = configuration;
9738061Smsmith        this.utils = this.configuration.utils;
9838061Smsmith        this.env = ((RootDocImpl)this.configuration.root).env;
9978645Snsouch    }
10078645Snsouch
10178645Snsouch    Map<CompilationUnitTree, Boolean> shouldCheck = new HashMap<>();
10278645Snsouch    // TODO: fix this up correctly
10378645Snsouch    public void runDocLint(TreePath path) {
10478645Snsouch        CompilationUnitTree unit = path.getCompilationUnit();
10578645Snsouch        if (doclint != null && shouldCheck.computeIfAbsent(unit, doclint::shouldCheck)) {
10678645Snsouch            doclint.scan(path);
10778645Snsouch        }
10878645Snsouch    }
10978645Snsouch
11078645Snsouch    // TODO: fix this up correctly
11178645Snsouch    public void initDocLint(Collection<String> opts, Collection<String> customTagNames, String htmlVersion) {
11278645Snsouch        ArrayList<String> doclintOpts = new ArrayList<>();
11378645Snsouch        boolean msgOptionSeen = false;
11439134Snsouch
11539134Snsouch        for (String opt : opts) {
11639134Snsouch            if (opt.startsWith(DocLint.XMSGS_OPTION)) {
11739134Snsouch                if (opt.equals(DocLint.XMSGS_CUSTOM_PREFIX + "none"))
11845342Speter                    return;
11939134Snsouch                msgOptionSeen = true;
12045342Speter            }
12139134Snsouch            doclintOpts.add(opt);
12239134Snsouch        }
12339134Snsouch
12439134Snsouch        if (!msgOptionSeen) {
12539134Snsouch            doclintOpts.add(DocLint.XMSGS_OPTION);
12638061Smsmith        }
12738061Smsmith
12838061Smsmith        String sep = "";
12938061Smsmith        StringBuilder customTags = new StringBuilder();
13038061Smsmith        for (String customTag : customTagNames) {
13138061Smsmith            customTags.append(sep);
13238061Smsmith            customTags.append(customTag);
13339134Snsouch            sep = DocLint.SEPARATOR;
13439134Snsouch        }
13538061Smsmith        doclintOpts.add(DocLint.XCUSTOM_TAGS_PREFIX + customTags.toString());
13638061Smsmith        doclintOpts.add(DocLint.XHTML_VERSION_PREFIX + htmlVersion);
13738061Smsmith
13838061Smsmith        JavacTask t = BasicJavacTask.instance(env.context);
13938061Smsmith        doclint = new DocLint();
14038061Smsmith        // standard doclet normally generates H1, H2
14138061Smsmith        doclintOpts.add(DocLint.XIMPLICIT_HEADERS + "2");
14239134Snsouch        doclint.init(t, doclintOpts.toArray(new String[doclintOpts.size()]), false);
14338061Smsmith    }
14438061Smsmith
14538061Smsmith    // TODO: fix this up correctly
14638061Smsmith    public boolean haveDocLint() {
14739134Snsouch        return (doclint == null);
14838061Smsmith    }
14938061Smsmith
15038061Smsmith    // TODO: jx.l.m directSuperTypes don't work for things like Enum,
15138061Smsmith    // so we use javac directly, investigate why jx.l.m is not cutting it.
15239134Snsouch    public List<TypeMirror> interfaceTypesOf(TypeMirror type) {
15338061Smsmith        com.sun.tools.javac.util.List<com.sun.tools.javac.code.Type> interfaces =
15438061Smsmith                ((RootDocImpl)configuration.root).env.getTypes().interfaces((com.sun.tools.javac.code.Type)type);
15538061Smsmith        if (interfaces.isEmpty()) {
15638061Smsmith            return Collections.emptyList();
15738061Smsmith        }
15838061Smsmith        List<TypeMirror> list = new ArrayList<>(interfaces.size());
15938061Smsmith        for (com.sun.tools.javac.code.Type t : interfaces) {
16038061Smsmith            list.add((TypeMirror)t);
16138061Smsmith        }
16238061Smsmith        return list;
16338061Smsmith    }
16438061Smsmith
16538061Smsmith    /*
16638061Smsmith     * TODO: This method exists because of a bug in javac which does not
16738061Smsmith     * handle "@deprecated tag in package-info.java", when this issue
16838061Smsmith     * is fixed this method and its uses must be jettisoned.
16938061Smsmith     */
17038061Smsmith    public boolean isDeprecated0(Element e) {
17138061Smsmith        if (!utils.getDeprecatedTrees(e).isEmpty()) {
17238061Smsmith            return true;
17378645Snsouch        }
17478645Snsouch        JavacTypes jctypes = ((RootDocImpl)configuration.root).env.typeutils;
17578645Snsouch        TypeMirror deprecatedType = utils.getDeprecatedType();
17678645Snsouch        for (AnnotationMirror anno : e.getAnnotationMirrors()) {
17738061Smsmith            if (jctypes.isSameType(anno.getAnnotationType().asElement().asType(), deprecatedType))
17838061Smsmith                return true;
17938061Smsmith        }
18038061Smsmith        return false;
18138061Smsmith    }
18238061Smsmith
18338061Smsmith    // TODO: fix jx.l.m add this method.
18478645Snsouch    public boolean isSynthesized(AnnotationMirror aDesc) {
18578645Snsouch        return ((Attribute)aDesc).isSynthesized();
18678645Snsouch    }
18778645Snsouch
18878645Snsouch    // TODO: implement using jx.l.model
18978645Snsouch    public boolean isVisible(TypeElement te) {
19078645Snsouch        return env.isVisible((ClassSymbol)te);
19178645Snsouch    }
19278645Snsouch
19378645Snsouch    // TODO: fix the caller
19478645Snsouch    public Object getConstValue(VariableElement ve) {
19578645Snsouch        return ((VarSymbol)ve).getConstValue();
19678645Snsouch    }
19778645Snsouch
19838061Smsmith    //TODO: DocTrees: Trees.getPath(Element e) is slow a factor 4-5 times.
19938061Smsmith    public Map<Element, TreePath> getElementToTreePath() {
20038061Smsmith        return env.elementToTreePath;
20138061Smsmith    }
20239134Snsouch
20338061Smsmith    // TODO: needs to ported to jx.l.m.
20438061Smsmith    public TypeElement searchClass(TypeElement klass, String className) {
20538061Smsmith        // search by qualified name first
20638061Smsmith        TypeElement te = configuration.root.getElementUtils().getTypeElement(className);
20738061Smsmith        if (te != null) {
20838061Smsmith            return te;
20943433Snsouch        }
21038061Smsmith
21138061Smsmith        // search inner classes
21238061Smsmith        for (TypeElement ite : utils.getClasses(klass)) {
21338061Smsmith            TypeElement innerClass = searchClass(ite, className);
21438061Smsmith            if (innerClass != null) {
21538061Smsmith                return innerClass;
21638061Smsmith            }
21738061Smsmith        }
21839134Snsouch
21938061Smsmith        // check in this package
22038061Smsmith        te = utils.findClassInPackageElement(utils.containingPackage(klass), className);
221185003Sjhb        if (te != null) {
22238061Smsmith            return te;
22338061Smsmith        }
22438061Smsmith
22543433Snsouch        ClassSymbol tsym = (ClassSymbol)klass;
22638061Smsmith        // make sure that this symbol has been completed
22738061Smsmith        // TODO: do we need this anymore ?
22838061Smsmith        if (tsym.completer != null) {
22938061Smsmith            tsym.complete();
23038061Smsmith        }
23138061Smsmith
23239134Snsouch        // search imports
23338061Smsmith        if (tsym.sourcefile != null) {
23438061Smsmith
23538061Smsmith            //### This information is available only for source classes.
236185003Sjhb            Env<AttrContext> compenv = env.getEnv(tsym);
23743433Snsouch            if (compenv == null) {
23843433Snsouch                return null;
23938061Smsmith            }
24038061Smsmith            Names names = tsym.name.table.names;
24138061Smsmith            Scope s = compenv.toplevel.namedImportScope;
24238061Smsmith            for (Symbol sym : s.getSymbolsByName(names.fromString(className))) {
24338061Smsmith                if (sym.kind == TYP) {
24438061Smsmith                    return (TypeElement)sym;
24538061Smsmith                }
24638061Smsmith            }
24739134Snsouch
24838061Smsmith            s = compenv.toplevel.starImportScope;
24938061Smsmith            for (Symbol sym : s.getSymbolsByName(names.fromString(className))) {
25038061Smsmith                if (sym.kind == TYP) {
251185003Sjhb                    return (TypeElement)sym;
25243433Snsouch                }
25343433Snsouch            }
25438061Smsmith        }
25538061Smsmith
25638061Smsmith        return null; // not found
25738061Smsmith    }
25838061Smsmith
25938061Smsmith    // TODO:  need to re-implement this using j.l.m. correctly!, this has
26038061Smsmith    // implications on testInterface, the note here is that javac's supertype
26138061Smsmith    // does the right thing returning Parameters in scope.
26239134Snsouch    /**
26339134Snsouch     * Return the type containing the method that this method overrides.
26439134Snsouch     * It may be a <code>TypeElement</code> or a <code>TypeParameterElement</code>.
26539134Snsouch     * @param method target
26643433Snsouch     * @return a type
26739134Snsouch     */
26843433Snsouch    public TypeMirror overriddenType(ExecutableElement method) {
26939134Snsouch        if (utils.isStatic(method)) {
27039520Snsouch            return null;
27139134Snsouch        }
27239520Snsouch        MethodSymbol sym = (MethodSymbol)method;
27339134Snsouch        ClassSymbol origin = (ClassSymbol) sym.owner;
27439134Snsouch        for (com.sun.tools.javac.code.Type t = env.getTypes().supertype(origin.type);
27538061Smsmith                t.hasTag(com.sun.tools.javac.code.TypeTag.CLASS);
27638061Smsmith                t = env.getTypes().supertype(t)) {
27738061Smsmith            ClassSymbol c = (ClassSymbol) t.tsym;
27855939Snsouch            for (com.sun.tools.javac.code.Symbol sym2 : c.members().getSymbolsByName(sym.name)) {
27938061Smsmith                if (sym.overrides(sym2, origin, env.getTypes(), true)) {
28038061Smsmith                    return t;
28155939Snsouch                }
28255939Snsouch            }
28338061Smsmith        }
28438061Smsmith        return null;
28538061Smsmith    }
28638061Smsmith
28738061Smsmith    // TODO: investigate and reimplement without javac dependencies.
28838061Smsmith    public boolean shouldDocument(Element e) {
28938061Smsmith        return env.shouldDocument(e);
29038061Smsmith    }
29155939Snsouch
29238061Smsmith    //------------------Start of Serializable Implementation---------------------//
29338061Smsmith    private final static Map<TypeElement, NewSerializedForm> serializedForms = new HashMap<>();
29438061Smsmith
29555939Snsouch    public SortedSet<VariableElement> getSerializableFields(Utils utils, TypeElement klass) {
29642475Snsouch        NewSerializedForm sf = serializedForms.get(klass);
29742475Snsouch        if (sf == null) {
29887599Sobrien            sf = new NewSerializedForm(utils, configuration.root.getElementUtils(), klass);
29942475Snsouch            serializedForms.put(klass, sf);
300185003Sjhb        }
30142475Snsouch        return sf.fields;
30238061Smsmith    }
30355939Snsouch
30455939Snsouch    public SortedSet<ExecutableElement>  getSerializationMethods(Utils utils, TypeElement klass) {
30538061Smsmith        NewSerializedForm sf = serializedForms.get(klass);
30655939Snsouch        if (sf == null) {
30738061Smsmith            sf = new NewSerializedForm(utils, configuration.root.getElementUtils(), klass);
30838061Smsmith            serializedForms.put(klass, sf);
30938061Smsmith        }
31038061Smsmith        return sf.methods;
31138061Smsmith    }
31239134Snsouch
31338061Smsmith    public boolean definesSerializableFields(Utils utils, TypeElement klass) {
31439134Snsouch        if (!utils.isSerializable(klass) || utils.isExternalizable(klass)) {
31538061Smsmith            return false;
31639134Snsouch        } else {
317185003Sjhb            NewSerializedForm sf = serializedForms.get(klass);
31838061Smsmith            if (sf == null) {
31955939Snsouch                sf = new NewSerializedForm(utils, configuration.root.getElementUtils(), klass);
32039134Snsouch                serializedForms.put(klass, sf);
32138061Smsmith            }
32239134Snsouch            return sf.definesSerializableFields;
32338061Smsmith        }
32439134Snsouch    }
32538061Smsmith
32639134Snsouch    /* TODO we need a clean port to jx.l.m
32739134Snsouch     * The serialized form is the specification of a class' serialization state.
32839134Snsouch     * <p>
32939134Snsouch     *
33039134Snsouch     * It consists of the following information:
33139134Snsouch     * <p>
33238061Smsmith     *
33339134Snsouch     * <pre>
33455939Snsouch     * 1. Whether class is Serializable or Externalizable.
33539134Snsouch     * 2. Javadoc for serialization methods.
33639134Snsouch     *    a. For Serializable, the optional readObject, writeObject,
33738061Smsmith     *       readResolve and writeReplace.
33838061Smsmith     *       serialData tag describes, in prose, the sequence and type
33938061Smsmith     *       of optional data written by writeObject.
34039134Snsouch     *    b. For Externalizable, writeExternal and readExternal.
34138061Smsmith     *       serialData tag describes, in prose, the sequence and type
34239134Snsouch     *       of optional data written by writeExternal.
34339134Snsouch     * 3. Javadoc for serialization data layout.
34438061Smsmith     *    a. For Serializable, the name,type and description
34555939Snsouch     *       of each Serializable fields.
34639134Snsouch     *    b. For Externalizable, data layout is described by 2(b).
34738061Smsmith     * </pre>
34855939Snsouch     *
34938061Smsmith     */
35039134Snsouch    static class NewSerializedForm {
35138061Smsmith
35238061Smsmith        final Utils utils;
35338061Smsmith        final Elements elements;
35438061Smsmith
35538061Smsmith        final SortedSet<ExecutableElement> methods;
35638061Smsmith
35738061Smsmith        /* List of FieldDocImpl - Serializable fields.
35839134Snsouch         * Singleton list if class defines Serializable fields explicitly.
35938061Smsmith         * Otherwise, list of default serializable fields.
36038061Smsmith         * 0 length list for Externalizable.
36155939Snsouch         */
36239520Snsouch        final SortedSet<VariableElement> fields;
36338061Smsmith
36439520Snsouch        /* True if class specifies serializable fields explicitly.
36555939Snsouch         * using special static member, serialPersistentFields.
366185003Sjhb         */
36739520Snsouch        boolean definesSerializableFields = false;
36878645Snsouch
36955939Snsouch        // Specially treated field/method names defined by Serialization.
37039520Snsouch        private static final String SERIALIZABLE_FIELDS = "serialPersistentFields";
37170608Snsouch        private static final String READOBJECT = "readObject";
37270608Snsouch        private static final String WRITEOBJECT = "writeObject";
37370608Snsouch        private static final String READRESOLVE = "readResolve";
37470608Snsouch        private static final String WRITEREPLACE = "writeReplace";
37555939Snsouch        private static final String READOBJECTNODATA = "readObjectNoData";
37670608Snsouch
37739520Snsouch        NewSerializedForm(Utils utils, Elements elements, TypeElement te) {
37870608Snsouch            this.utils = utils;
37970608Snsouch            this.elements = elements;
38070608Snsouch            methods = new TreeSet<>(utils.makeGeneralPurposeComparator());
38139520Snsouch            fields = new TreeSet<>(utils.makeGeneralPurposeComparator());
38270608Snsouch            if (utils.isExternalizable(te)) {
38370608Snsouch                /* look up required public accessible methods,
38470608Snsouch                 *   writeExternal and readExternal.
38570608Snsouch                 */
38670608Snsouch                String[] readExternalParamArr = {"java.io.ObjectInput"};
38739520Snsouch                String[] writeExternalParamArr = {"java.io.ObjectOutput"};
38870608Snsouch
38970608Snsouch                ExecutableElement md = findMethod(te, "readExternal", Arrays.asList(readExternalParamArr));
39070608Snsouch                if (md != null) {
39170608Snsouch                    methods.add(md);
39270608Snsouch                }
39370608Snsouch                md = findMethod((ClassSymbol) te, "writeExternal", Arrays.asList(writeExternalParamArr));
39470608Snsouch                if (md != null) {
39570608Snsouch                    methods.add(md);
39670608Snsouch                }
39770608Snsouch            } else if (utils.isSerializable(te)) {
39855939Snsouch                VarSymbol dsf = getDefinedSerializableFields((ClassSymbol) te);
39970608Snsouch                if (dsf != null) {
40070608Snsouch                    /* Define serializable fields with array of ObjectStreamField.
40139520Snsouch                     * Each ObjectStreamField should be documented by a
402184130Sjhb                     * serialField tag.
403184130Sjhb                     */
40439520Snsouch                    definesSerializableFields = true;
40539520Snsouch                    fields.add((VariableElement) dsf);
40655939Snsouch                } else {
40739520Snsouch
40839520Snsouch                    /* Calculate default Serializable fields as all
40939520Snsouch                     * non-transient, non-static fields.
41070608Snsouch                     * Fields should be documented by serial tag.
41170608Snsouch                     */
41238061Smsmith                    computeDefaultSerializableFields((ClassSymbol) te);
41338061Smsmith                }
41438061Smsmith
41538061Smsmith                /* Check for optional customized readObject, writeObject,
41638061Smsmith                 * readResolve and writeReplace, which can all contain
41755939Snsouch                 * the serialData tag.        */
41838061Smsmith                addMethodIfExist((ClassSymbol) te, READOBJECT);
419185003Sjhb                addMethodIfExist((ClassSymbol) te, WRITEOBJECT);
42039134Snsouch                addMethodIfExist((ClassSymbol) te, READRESOLVE);
42170608Snsouch                addMethodIfExist((ClassSymbol) te, WRITEREPLACE);
42239520Snsouch                addMethodIfExist((ClassSymbol) te, READOBJECTNODATA);
423184130Sjhb            }
424184130Sjhb        }
42539520Snsouch
42639520Snsouch        private VarSymbol getDefinedSerializableFields(ClassSymbol def) {
42738061Smsmith            Names names = def.name.table.names;
42855939Snsouch
42938061Smsmith            /* SERIALIZABLE_FIELDS can be private,
43039520Snsouch             */
43139520Snsouch            for (Symbol sym : def.members().getSymbolsByName(names.fromString(SERIALIZABLE_FIELDS))) {
43255939Snsouch                if (sym.kind == VAR) {
43339520Snsouch                    VarSymbol f = (VarSymbol) sym;
43438061Smsmith                    if ((f.flags() & Flags.STATIC) != 0
43538061Smsmith                            && (f.flags() & Flags.PRIVATE) != 0) {
43638061Smsmith                        return f;
43738061Smsmith                    }
43838061Smsmith                }
43938061Smsmith            }
44038061Smsmith            return null;
44138061Smsmith        }
44255939Snsouch
44338061Smsmith        /*
44438061Smsmith         * Catalog Serializable method if it exists in current ClassSymbol.
44555939Snsouch         * Do not look for method in superclasses.
44645342Speter         *
44738061Smsmith         * Serialization requires these methods to be non-static.
44855939Snsouch         *
44938061Smsmith         * @param method should be an unqualified Serializable method
45038061Smsmith         *               name either READOBJECT, WRITEOBJECT, READRESOLVE
45138061Smsmith         *               or WRITEREPLACE.
45238061Smsmith         * @param visibility the visibility flag for the given method.
45338061Smsmith         */
45438061Smsmith        private void addMethodIfExist(ClassSymbol def, String methodName) {
45538061Smsmith            Names names = def.name.table.names;
45638061Smsmith
45738061Smsmith            for (Symbol sym : def.members().getSymbolsByName(names.fromString(methodName))) {
45838061Smsmith                if (sym.kind == MTH) {
45955939Snsouch                    MethodSymbol md = (MethodSymbol) sym;
46038061Smsmith                    if ((md.flags() & Flags.STATIC) == 0) {
46138061Smsmith                        /*
46255939Snsouch                         * WARNING: not robust if unqualifiedMethodName is overloaded
46345342Speter                         *          method. Signature checking could make more robust.
46438061Smsmith                         * READOBJECT takes a single parameter, java.io.ObjectInputStream.
46555939Snsouch                         * WRITEOBJECT takes a single parameter, java.io.ObjectOutputStream.
46638061Smsmith                         */
46738061Smsmith                        methods.add(md);
46838061Smsmith                    }
46938061Smsmith                }
47038061Smsmith            }
47138061Smsmith        }
47238061Smsmith
47355939Snsouch        /*
47438061Smsmith         * Compute default Serializable fields from all members of ClassSymbol.
47538061Smsmith         *
47638061Smsmith         * must walk over all members of ClassSymbol.
47738061Smsmith         */
47838061Smsmith        private void computeDefaultSerializableFields(ClassSymbol te) {
47938061Smsmith            for (Symbol sym : te.members().getSymbols(NON_RECURSIVE)) {
48038061Smsmith                if (sym != null && sym.kind == VAR) {
48138061Smsmith                    VarSymbol f = (VarSymbol) sym;
48238061Smsmith                    if ((f.flags() & Flags.STATIC) == 0
48338061Smsmith                            && (f.flags() & Flags.TRANSIENT) == 0) {
48438061Smsmith                        //### No modifier filtering applied here.
48538061Smsmith                        //### Add to beginning.
48638061Smsmith                        //### Preserve order used by old 'javadoc'.
48738061Smsmith                        fields.add(f);
48838061Smsmith                    }
48938061Smsmith                }
49038061Smsmith            }
49138061Smsmith        }
49243433Snsouch
49343433Snsouch        /**
49438061Smsmith         * Find a method in this class scope. Search order: this class, interfaces, superclasses,
49538061Smsmith         * outerclasses. Note that this is not necessarily what the compiler would do!
49638061Smsmith         *
49738061Smsmith         * @param methodName the unqualified name to search for.
49838061Smsmith         * @param paramTypes the array of Strings for method parameter types.
49938061Smsmith         * @return the first MethodDocImpl which matches, null if not found.
50038061Smsmith         */
50138061Smsmith        public ExecutableElement findMethod(TypeElement te, String methodName,
502185003Sjhb                List<String> paramTypes) {
50355939Snsouch            List<? extends Element> allMembers = this.elements.getAllMembers(te);
50438061Smsmith            loop:
50538061Smsmith            for (Element e : allMembers) {
50638061Smsmith                if (e.getKind() != METHOD) {
50738061Smsmith                    continue;
50838061Smsmith                }
50938061Smsmith                ExecutableElement ee = (ExecutableElement) e;
51038061Smsmith                if (!ee.getSimpleName().contentEquals(methodName)) {
51138061Smsmith                    continue;
51238061Smsmith                }
51338061Smsmith                List<? extends VariableElement> parameters = ee.getParameters();
51438061Smsmith                if (paramTypes.size() != parameters.size()) {
51538061Smsmith                    continue;
51638061Smsmith                }
51738061Smsmith                for (int i = 0; i < parameters.size(); i++) {
51838061Smsmith                    VariableElement ve = parameters.get(i);
51938061Smsmith                    if (!ve.asType().toString().equals(paramTypes.get(i))) {
52038061Smsmith                        break loop;
52178645Snsouch                    }
52278645Snsouch                }
52355939Snsouch                return ee;
52478645Snsouch            }
52538061Smsmith            TypeElement encl = utils.getEnclosingTypeElement(te);
52638061Smsmith            if (encl == null) {
52755939Snsouch                return null;
52838061Smsmith            }
52938061Smsmith            return findMethod(encl, methodName, paramTypes);
53055939Snsouch        }
53138061Smsmith    }
53238061Smsmith
53338061Smsmith    // TODO: this is a fast way to get the JavaFileObject for
53438061Smsmith    // a package.html file, however we need to eliminate this.
53538061Smsmith    public JavaFileObject getJavaFileObject(PackageElement pe) {
53638061Smsmith        return env.pkgToJavaFOMap.get(pe);
53738061Smsmith    }
53838061Smsmith
53938061Smsmith    // TODO: we need to eliminate this, as it is hacky.
54038061Smsmith    /**
54178645Snsouch     * Returns a representation of the package truncated to two levels.
54278645Snsouch     * For instance if the given package represents foo.bar.baz will return
54378645Snsouch     * a representation of foo.bar
54478645Snsouch     * @param pkg the PackageElement
54578645Snsouch     * @return an abbreviated PackageElement
54678645Snsouch     */
54778645Snsouch    public PackageElement getAbbreviatedPackageElement(PackageElement pkg) {
548185003Sjhb        String parsedPackageName = utils.parsePackageName(pkg);
54978645Snsouch        ModuleElement encl = (ModuleElement) pkg.getEnclosingElement();
55078645Snsouch        PackageElement abbrevPkg = encl == null
55138061Smsmith                ? utils.elementUtils.getPackageElement(parsedPackageName)
55238061Smsmith                : ((JavacElements) utils.elementUtils).getPackageElement(encl, parsedPackageName);
55338061Smsmith        return abbrevPkg;
55438061Smsmith    }
55538061Smsmith}
55638061Smsmith