1/*
2 * Copyright (c) 1999, 2014, 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
26package com.sun.tools.doclets.internal.toolkit.util;
27
28import java.util.*;
29
30import com.sun.javadoc.*;
31import com.sun.tools.doclets.internal.toolkit.Configuration;
32
33/**
34 * For a given class method, build an array of interface methods which it
35 * implements.
36 *
37 *  <p><b>This is NOT part of any supported API.
38 *  If you write code that depends on this, you do so at your own risk.
39 *  This code and its internal interfaces are subject to change or
40 *  deletion without notice.</b>
41 *
42 * @author Atul M Dambalkar
43 */
44@Deprecated
45public class ImplementedMethods {
46
47    private final Map<MethodDoc,Type> interfaces = new HashMap<>();
48    private final List<MethodDoc> methlist = new ArrayList<>();
49    private final Configuration configuration;
50    private final Utils utils;
51    private final ClassDoc classdoc;
52    private final MethodDoc method;
53
54    public ImplementedMethods(MethodDoc method, Configuration configuration) {
55        this.method = method;
56        this.configuration = configuration;
57        this.utils = configuration.utils;
58        classdoc = method.containingClass();
59    }
60
61    /**
62     * Return the array of interface methods which the method passed in the
63     * constructor is implementing. The search/build order is as follows:
64     * <pre>
65     * 1. Search in all the immediate interfaces which this method's class is
66     *    implementing. Do it recursively for the superinterfaces as well.
67     * 2. Traverse all the superclasses and search recursively in the
68     *    interfaces which those superclasses implement.
69     *</pre>
70     *
71     * @return MethodDoc[] Array of implemented methods.
72     */
73    public MethodDoc[] build(boolean sort) {
74        buildImplementedMethodList(sort);
75        return methlist.toArray(new MethodDoc[methlist.size()]);
76    }
77
78    public MethodDoc[] build() {
79        return build(true);
80    }
81
82    public Type getMethodHolder(MethodDoc methodDoc) {
83        return interfaces.get(methodDoc);
84    }
85
86    /**
87     * Search for the method in the array of interfaces. If found check if it is
88     * overridden by any other subinterface method which this class
89     * implements. If it is not overidden, add it in the method list.
90     * Do this recursively for all the extended interfaces for each interface
91     * from the array passed.
92     */
93    private void buildImplementedMethodList(boolean sort) {
94        List<Type> intfacs = utils.getAllInterfaces(classdoc, configuration, sort);
95        for (Type interfaceType : intfacs) {
96            MethodDoc found = utils.findMethod(interfaceType.asClassDoc(), method);
97            if (found != null) {
98                removeOverriddenMethod(found);
99                if (!overridingMethodFound(found)) {
100                    methlist.add(found);
101                    interfaces.put(found, interfaceType);
102                }
103            }
104        }
105    }
106
107    /**
108     * Search in the method list and check if it contains a method which
109     * is overridden by the method as parameter.  If found, remove the
110     * overridden method from the method list.
111     *
112     * @param method Is this method overriding a method in the method list.
113     */
114    private void removeOverriddenMethod(MethodDoc method) {
115        ClassDoc overriddenClass = method.overriddenClass();
116        if (overriddenClass != null) {
117            for (int i = 0; i < methlist.size(); i++) {
118                ClassDoc cd = methlist.get(i).containingClass();
119                if (cd == overriddenClass || overriddenClass.subclassOf(cd)) {
120                    methlist.remove(i);  // remove overridden method
121                    return;
122                }
123            }
124        }
125    }
126
127    /**
128     * Search in the already found methods' list and check if it contains
129     * a method which is overriding the method parameter or is the method
130     * parameter itself.
131     *
132     * @param method MethodDoc Method to be searched in the Method List for
133     * an overriding method.
134     */
135    private boolean overridingMethodFound(MethodDoc method) {
136        ClassDoc containingClass = method.containingClass();
137        for (MethodDoc listmethod : methlist) {
138            if (containingClass == listmethod.containingClass()) {
139                // it's the same method.
140                return true;
141            }
142            ClassDoc cd = listmethod.overriddenClass();
143            if (cd == null) {
144                continue;
145            }
146            if (cd == containingClass || cd.subclassOf(containingClass)) {
147                return true;
148            }
149        }
150        return false;
151    }
152}
153