1/*
2 * Copyright (c) 2009, 2017, 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.javac.code;
27
28import java.util.Collections;
29import java.util.EnumSet;
30import java.util.Set;
31
32import javax.lang.model.element.ModuleElement;
33import javax.lang.model.element.ModuleElement.DirectiveVisitor;
34
35import com.sun.tools.javac.code.Symbol.ClassSymbol;
36import com.sun.tools.javac.code.Symbol.ModuleSymbol;
37import com.sun.tools.javac.code.Symbol.PackageSymbol;
38import com.sun.tools.javac.util.DefinedBy;
39import com.sun.tools.javac.util.DefinedBy.Api;
40import com.sun.tools.javac.util.List;
41
42
43/**
44 *  Root class for the directives that may appear in module compilation units.
45 *
46 *  <p><b>This is NOT part of any supported API.
47 *  If you write code that depends on this, you do so at your own risk.
48 *  This code and its internal interfaces are subject to change or
49 *  deletion without notice.</b>
50 */
51public abstract class Directive implements ModuleElement.Directive {
52
53    /** Flags for RequiresDirective. */
54    public enum RequiresFlag {
55        TRANSITIVE(0x0020),
56        STATIC_PHASE(0x0040),
57        SYNTHETIC(0x1000),
58        MANDATED(0x8000),
59        EXTRA(0x10000);
60
61        // overkill? move to ClassWriter?
62        public static int value(Set<RequiresFlag> s) {
63            int v = 0;
64            for (RequiresFlag f: s)
65                v |= f.value;
66            return v;
67        }
68
69        RequiresFlag(int value) {
70            this.value = value;
71        }
72
73        public final int value;
74    }
75
76    /** Flags for ExportsDirective. */
77    public enum ExportsFlag {
78        SYNTHETIC(0x1000),
79        MANDATED(0x8000);
80
81        // overkill? move to ClassWriter?
82        public static int value(Set<ExportsFlag> s) {
83            int v = 0;
84            for (ExportsFlag f: s)
85                v |= f.value;
86            return v;
87        }
88
89        ExportsFlag(int value) {
90            this.value = value;
91        }
92
93        public final int value;
94    }
95
96    /**
97     * 'exports' Package ';'
98     * 'exports' Package 'to' ModuleList ';'
99     */
100    public static class ExportsDirective extends Directive
101            implements ModuleElement.ExportsDirective {
102        public final PackageSymbol packge;
103        public final List<ModuleSymbol> modules;
104        public final Set<ExportsFlag> flags;
105
106        public ExportsDirective(PackageSymbol packge, List<ModuleSymbol> modules) {
107            this(packge, modules, EnumSet.noneOf(ExportsFlag.class));
108        }
109
110        public ExportsDirective(PackageSymbol packge, List<ModuleSymbol> modules, Set<ExportsFlag> flags) {
111            this.packge = packge;
112            this.modules = modules;
113            this.flags = flags;
114        }
115
116        @Override @DefinedBy(Api.LANGUAGE_MODEL)
117        public ModuleElement.DirectiveKind getKind() {
118            return ModuleElement.DirectiveKind.EXPORTS;
119        }
120
121        @Override @DefinedBy(Api.LANGUAGE_MODEL)
122        public PackageSymbol getPackage() {
123            return packge;
124        }
125
126        @Override @DefinedBy(Api.LANGUAGE_MODEL)
127        public java.util.List<ModuleSymbol> getTargetModules() {
128            return modules == null
129                    ? null
130                    : Collections.unmodifiableList(modules);
131        }
132
133        @Override
134        public String toString() {
135            if (modules == null)
136                return "Exports[" + packge + "]";
137            else
138                return "Exports[" + packge + ":" + modules + "]";
139        }
140
141        @Override @DefinedBy(Api.LANGUAGE_MODEL)
142        public <R, P> R accept(DirectiveVisitor<R, P> v, P p) {
143            return v.visitExports(this, p);
144        }
145    }
146
147    /** Flags for OpensDirective. */
148    public enum OpensFlag {
149        SYNTHETIC(0x1000),
150        MANDATED(0x8000);
151
152        // overkill? move to ClassWriter?
153        public static int value(Set<OpensFlag> s) {
154            int v = 0;
155            for (OpensFlag f: s)
156                v |= f.value;
157            return v;
158        }
159
160        OpensFlag(int value) {
161            this.value = value;
162        }
163
164        public final int value;
165    }
166
167    /**
168     * 'opens' Package ';'
169     * 'opens' Package 'to' ModuleList ';'
170     */
171    public static class OpensDirective extends Directive
172            implements ModuleElement.OpensDirective {
173        public final PackageSymbol packge;
174        public final List<ModuleSymbol> modules;
175        public final Set<OpensFlag> flags;
176
177        public OpensDirective(PackageSymbol packge, List<ModuleSymbol> modules) {
178            this(packge, modules, EnumSet.noneOf(OpensFlag.class));
179        }
180
181        public OpensDirective(PackageSymbol packge, List<ModuleSymbol> modules, Set<OpensFlag> flags) {
182            this.packge = packge;
183            this.modules = modules;
184            this.flags = flags;
185        }
186
187        @Override @DefinedBy(Api.LANGUAGE_MODEL)
188        public ModuleElement.DirectiveKind getKind() {
189            return ModuleElement.DirectiveKind.OPENS;
190        }
191
192        @Override @DefinedBy(Api.LANGUAGE_MODEL)
193        public PackageSymbol getPackage() {
194            return packge;
195        }
196
197        @Override @DefinedBy(Api.LANGUAGE_MODEL)
198        public java.util.List<ModuleSymbol> getTargetModules() {
199            return modules == null
200                    ? null
201                    : Collections.unmodifiableList(modules);
202        }
203
204        @Override
205        public String toString() {
206            if (modules == null)
207                return "Opens[" + packge + "]";
208            else
209                return "Opens[" + packge + ":" + modules + "]";
210        }
211
212        @Override @DefinedBy(Api.LANGUAGE_MODEL)
213        public <R, P> R accept(DirectiveVisitor<R, P> v, P p) {
214            return v.visitOpens(this, p);
215        }
216    }
217
218    /**
219     * 'provides' ServiceName 'with' QualifiedIdentifer ';'
220     */
221    public static class ProvidesDirective extends Directive
222            implements ModuleElement.ProvidesDirective {
223        public final ClassSymbol service;
224        public final List<ClassSymbol> impls;
225
226        public ProvidesDirective(ClassSymbol service, List<ClassSymbol> impls) {
227            this.service = service;
228            this.impls = impls;
229        }
230
231        @Override @DefinedBy(Api.LANGUAGE_MODEL)
232        public ModuleElement.DirectiveKind getKind() {
233            return ModuleElement.DirectiveKind.PROVIDES;
234        }
235
236        @Override @DefinedBy(Api.LANGUAGE_MODEL)
237        public ClassSymbol getService() {
238            return service;
239        }
240
241        @Override @DefinedBy(Api.LANGUAGE_MODEL)
242        public List<ClassSymbol> getImplementations() {
243            return impls;
244        }
245
246        @Override
247        public String toString() {
248            return "Provides[" + service + "," + impls + "]";
249        }
250
251        @Override @DefinedBy(Api.LANGUAGE_MODEL)
252        public <R, P> R accept(DirectiveVisitor<R, P> v, P p) {
253            return v.visitProvides(this, p);
254        }
255
256        // TODO: delete?
257        @Override
258        public boolean equals(Object obj) {
259            if (!(obj instanceof ProvidesDirective)) {
260                return false;
261            }
262            ProvidesDirective other = (ProvidesDirective)obj;
263            return service == other.service && impls.equals(other.impls);
264        }
265
266        // TODO: delete?
267        @Override
268        public int hashCode() {
269            return service.hashCode() * 31 + impls.hashCode() * 37;
270        }
271    }
272
273    /**
274     * 'requires' ('static' | 'transitive')* ModuleName ';'
275     */
276    public static class RequiresDirective extends Directive
277            implements ModuleElement.RequiresDirective {
278        public final ModuleSymbol module;
279        public final Set<RequiresFlag> flags;
280
281        public RequiresDirective(ModuleSymbol module) {
282            this(module, EnumSet.noneOf(RequiresFlag.class));
283        }
284
285        public RequiresDirective(ModuleSymbol module, Set<RequiresFlag> flags) {
286            this.module = module;
287            this.flags = flags;
288        }
289
290        @Override @DefinedBy(Api.LANGUAGE_MODEL)
291        public ModuleElement.DirectiveKind getKind() {
292            return ModuleElement.DirectiveKind.REQUIRES;
293        }
294
295        @Override @DefinedBy(Api.LANGUAGE_MODEL)
296        public boolean isStatic() {
297            return flags.contains(RequiresFlag.STATIC_PHASE);
298        }
299
300        @Override @DefinedBy(Api.LANGUAGE_MODEL)
301        public boolean isTransitive() {
302            return flags.contains(RequiresFlag.TRANSITIVE);
303        }
304
305        @Override @DefinedBy(Api.LANGUAGE_MODEL)
306        public ModuleSymbol getDependency() {
307            return module;
308        }
309
310        @Override
311        public String toString() {
312            return "Requires[" + flags + "," + module + "]";
313        }
314
315        @Override @DefinedBy(Api.LANGUAGE_MODEL)
316        public <R, P> R accept(DirectiveVisitor<R, P> v, P p) {
317            return v.visitRequires(this, p);
318        }
319    }
320
321    /**
322     * 'uses' ServiceName ';'
323     */
324    public static class UsesDirective extends Directive
325            implements ModuleElement.UsesDirective {
326        public final ClassSymbol service;
327
328        public UsesDirective(ClassSymbol service) {
329            this.service = service;
330        }
331
332        @Override @DefinedBy(Api.LANGUAGE_MODEL)
333        public ModuleElement.DirectiveKind getKind() {
334            return ModuleElement.DirectiveKind.USES;
335        }
336
337        @Override @DefinedBy(Api.LANGUAGE_MODEL)
338        public ClassSymbol getService() {
339            return service;
340        }
341
342        @Override
343        public String toString() {
344            return "Uses[" + service + "]";
345        }
346
347        @Override @DefinedBy(Api.LANGUAGE_MODEL)
348        public <R, P> R accept(DirectiveVisitor<R, P> v, P p) {
349            return v.visitUses(this, p);
350        }
351
352        // TODO: delete?
353        @Override
354        public boolean equals(Object obj) {
355            if (!(obj instanceof UsesDirective)) {
356                return false;
357            }
358            UsesDirective other = (UsesDirective)obj;
359            return service == other.service;
360        }
361
362        // TODO: delete?
363        @Override
364        public int hashCode() {
365            return service.hashCode() * 31;
366        }
367    }
368}
369