1/*
2 * Copyright (c) 2012, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24package org.openjdk.tests.shapegen;
25
26import java.util.ArrayList;
27import java.util.HashSet;
28import java.util.List;
29import java.util.Map;
30import java.util.Set;
31
32/**
33 *
34 * @author Robert Field
35 */
36public class ClassCase {
37
38    public enum Kind {
39        IVAC        (true,  "v"),
40        IPRESENT    (true,  "p"),
41        IDEFAULT    (true,  "d"),
42        CNONE       (false, "n"),
43        CABSTRACT   (false, "a"),
44        CCONCRETE   (false, "c");
45
46        private final String prefix;
47        public final boolean isInterface;
48
49        Kind(boolean isInterface, String prefix) {
50            this.isInterface = isInterface;
51            this.prefix = prefix;
52        }
53
54        public String getPrefix() { return prefix; }
55    }
56
57    public final Kind kind;
58    private final ClassCase superclass;
59    private final List<ClassCase> supertypes;
60
61    private String name;
62    private boolean _OK;
63    private boolean _HasClassMethod;
64    private Set<ClassCase> _mprov;
65    private boolean _IsConcrete;
66    private boolean _HasDefault;
67    private ClassCase _mres;
68    private ClassCase _mdefend;
69
70    private Set<RuleGroup> executed = new HashSet<RuleGroup>();
71
72    public ClassCase(Kind kind, ClassCase superclass, List<ClassCase> interfaces) {
73        this.kind = kind;
74        this.superclass = superclass;
75
76        // Set supertypes from superclass (if any) and interfaces
77        List<ClassCase> lc;
78        if (superclass == null) {
79            lc = interfaces;
80        } else {
81            lc = new ArrayList<>();
82            lc.add(superclass);
83            lc.addAll(interfaces);
84        }
85        this.supertypes = lc;
86    }
87
88    public final boolean isInterface() { return kind.isInterface; }
89    public final boolean isClass() { return !kind.isInterface; }
90
91    public Set<ClassCase> get_mprov() {
92        exec(RuleGroup.PROVENENCE);
93        return _mprov;
94    }
95
96    public void set_mprov(ClassCase cc) {
97        Set<ClassCase> s = new HashSet<>();
98        s.add(cc);
99        _mprov = s;
100    }
101
102    public void set_mprov(Set<ClassCase> s) {
103        _mprov = s;
104    }
105
106    public ClassCase get_mres() {
107        exec(RuleGroup.RESOLUTION);
108        return _mres;
109    }
110
111    public void set_mres(ClassCase cc) {
112        _mres = cc;
113    }
114
115    public ClassCase get_mdefend() {
116        exec(RuleGroup.DEFENDER);
117        return _mdefend;
118    }
119
120    public void set_mdefend(ClassCase cc) {
121        _mdefend = cc;
122    }
123
124    public boolean get_HasClassMethod() {
125        exec(RuleGroup.PROVENENCE);
126        return _HasClassMethod;
127    }
128
129    public void set_HasClassMethod(boolean bool) {
130        _HasClassMethod = bool;
131    }
132
133    public boolean get_HasDefault() {
134        exec(RuleGroup.MARKER);
135        return _HasDefault;
136    }
137
138    public void set_HasDefault(boolean bool) {
139        _HasDefault = bool;
140    }
141
142    public boolean get_IsConcrete() {
143        exec(RuleGroup.MARKER);
144        return _IsConcrete;
145    }
146
147    public void set_IsConcrete(boolean bool) {
148        _IsConcrete = bool;
149    }
150
151    public boolean get_OK() {
152        exec(RuleGroup.CHECKING);
153        return _OK;
154    }
155
156    public void set_OK(boolean bool) {
157        _OK = bool;
158    }
159
160    public boolean isMethodDefined() {
161        for (ClassCase cc : supertypes) {
162            if (cc.isMethodDefined()) {
163                return true;
164            }
165        }
166        switch (kind) {
167            case CCONCRETE:
168            case CABSTRACT:
169            case IPRESENT:
170            case IDEFAULT:
171                return true;
172            default:
173                return false;
174        }
175    }
176
177    public boolean isAbstract() {
178        return isMethodDefined() && (get_mres()==null);
179    }
180
181    public boolean hasSuperclass() {
182        return superclass != null;
183    }
184
185    public ClassCase getSuperclass() {
186        return superclass;
187    }
188
189    public List<ClassCase> getSupertypes() {
190        return supertypes;
191    }
192
193    public List<ClassCase> getInterfaces() {
194        if (superclass != null) {
195            if (supertypes.get(0) != superclass) {
196                throw new AssertionError("superclass missing from supertypes");
197            }
198            return supertypes.subList(1, supertypes.size());
199        } else {
200            return supertypes;
201        }
202    }
203
204    public boolean isSubtypeOf(ClassCase cc) {
205        // S-Refl
206        if (cc.equals(this)) {
207            return true;
208        }
209
210        // S-Def
211        for (ClassCase sp : getSupertypes()) {
212            if (cc.equals(sp)) {
213                return true;
214            }
215        }
216
217        // _S-Trans
218        for (ClassCase sp : getSupertypes()) {
219            if (sp.isSubtypeOf(cc)) {
220                return true;
221            }
222        }
223
224        return false;
225    }
226
227    public void init(Map<String, Integer> namingContext) {
228        if (name != null) {
229            return; // Already inited
230        }
231
232        for (ClassCase sup : supertypes) {
233            sup.init(namingContext);
234        }
235
236        // Build name
237        StringBuilder sb = new StringBuilder();
238        if (!supertypes.isEmpty()) {
239            sb.append(isInterface() ? "I" : "C");
240            for (ClassCase cc : supertypes) {
241                sb.append(cc.getName());
242            }
243            sb.append(kind.isInterface ? "i" : "c");
244        }
245        sb.append(kind.prefix);
246        String pname = sb.toString();
247        Integer icnt = namingContext.get(pname);
248        int cnt = icnt == null ? 0 : icnt;
249        ++cnt;
250        namingContext.put(pname, cnt);
251        if (cnt > 1) {
252            sb.append(cnt);
253        }
254        this.name = sb.toString();
255    }
256
257    public boolean isa(Kind... kinds) {
258        for (Kind k : kinds) {
259            if (kind == k) {
260                return true;
261            }
262        }
263        return false;
264    }
265
266    private void exec(RuleGroup rg ) {
267        if (!executed.contains(rg)) {
268            rg.exec(this);
269            executed.add(rg);
270        }
271    }
272
273    public void collectClasses(Set<ClassCase> seen) {
274        seen.add(this);
275        for (ClassCase cc : supertypes) {
276            cc.collectClasses(seen);
277        }
278    }
279
280    public String getID() {
281        if (name == null) {
282            throw new Error("Access to uninitialized ClassCase");
283        } else {
284            return name;
285        }
286    }
287
288    public final String getName() {
289        if (name == null) {
290            return "ClassCase uninited@" + hashCode();
291        } else {
292            return name;
293        }
294    }
295
296    @Override
297    public boolean equals(Object obj) {
298        return obj instanceof ClassCase && getID().equals(((ClassCase)obj).getID());
299    }
300
301    @Override
302    public int hashCode() {
303        return getID().hashCode();
304    }
305
306    @Override
307    public String toString() {
308        return getName();
309    }
310}
311