| 1 | /******************************************************************************* |
|---|---|
| 2 | * Copyright (c) 2017 IBM Corporation and others. |
| 3 | * |
| 4 | * This program and the accompanying materials |
| 5 | * are made available under the terms of the Eclipse Public License 2.0 |
| 6 | * which accompanies this distribution, and is available at |
| 7 | * https://www.eclipse.org/legal/epl-2.0/ |
| 8 | * |
| 9 | * SPDX-License-Identifier: EPL-2.0 |
| 10 | * |
| 11 | * IBM Corporation - initial API and implementation |
| 12 | *******************************************************************************/ |
| 13 | package org.eclipse.jdt.core.dom; |
| 14 | |
| 15 | import java.util.ArrayList; |
| 16 | import java.util.HashMap; |
| 17 | import java.util.Iterator; |
| 18 | import java.util.List; |
| 19 | import java.util.Map; |
| 20 | |
| 21 | /** |
| 22 | * Module Modifier node - represents the modifiers for the requires directive in module declaration (added in JLS9 API). |
| 23 | * <pre> |
| 24 | * ModuleModifier: |
| 25 | * <b>static</b> |
| 26 | * <b>transitive</b> |
| 27 | * </pre> |
| 28 | * <p> |
| 29 | * The numeric values of these flags match the ones for class |
| 30 | * files as described in the Java Virtual Machine Specification. |
| 31 | * Note that the value of <b>static</b> does <b>not</b> correspond to the value of {@link Modifier#STATIC}! |
| 32 | * </p> |
| 33 | * |
| 34 | * @since 3.14 |
| 35 | * @noinstantiate This class is not intended to be instantiated by clients. |
| 36 | */ |
| 37 | @SuppressWarnings({"rawtypes", "unchecked"}) |
| 38 | public final class ModuleModifier extends ASTNode { |
| 39 | |
| 40 | /** |
| 41 | * Module Modifier keywords (typesafe enumeration). |
| 42 | */ |
| 43 | public static class ModuleModifierKeyword { |
| 44 | |
| 45 | /** "static" modifier with flag value {@link ModuleModifier#STATIC_PHASE}. */ |
| 46 | public static final ModuleModifierKeyword STATIC_KEYWORD = new ModuleModifierKeyword("static", STATIC_PHASE);//$NON-NLS-1$ |
| 47 | |
| 48 | /** "transitive" modifier with flag value {@link ModuleModifier#TRANSITIVE}. */ |
| 49 | public static final ModuleModifierKeyword TRANSITIVE_KEYWORD = new ModuleModifierKeyword("transitive", TRANSITIVE);//$NON-NLS-1$ |
| 50 | |
| 51 | |
| 52 | /** |
| 53 | * Map from token to operator (key type: <code>String</code>; |
| 54 | * value type: <code>Operator</code>). |
| 55 | */ |
| 56 | private static final Map KEYWORDS; |
| 57 | |
| 58 | static { |
| 59 | KEYWORDS = new HashMap(2); |
| 60 | ModuleModifierKeyword[] ops = { |
| 61 | STATIC_KEYWORD, |
| 62 | TRANSITIVE_KEYWORD, |
| 63 | }; |
| 64 | for (int i = 0; i < ops.length; i++) { |
| 65 | KEYWORDS.put(ops[i].toString(), ops[i]); |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | /** |
| 70 | * Returns the module modifier corresponding to the given single-bit flag value, |
| 71 | * or <code>null</code> if none or if more than one bit is set. |
| 72 | * <p> |
| 73 | * <code>fromFlagValue</code> is the converse of <code>toFlagValue</code>: |
| 74 | * that is, <code>ModuleModifierKind.fromFlagValue(k.toFlagValue()) == k</code> for |
| 75 | * all module modifier keywords <code>k</code>. |
| 76 | * </p> |
| 77 | * |
| 78 | * @param flagValue the single-bit flag value for the module modifier |
| 79 | * @return the module modifier keyword, or <code>null</code> if none |
| 80 | * @see #toFlagValue() |
| 81 | */ |
| 82 | public static ModuleModifierKeyword fromFlagValue(int flagValue) { |
| 83 | for (Iterator it = KEYWORDS.values().iterator(); it.hasNext(); ) { |
| 84 | ModuleModifierKeyword k = (ModuleModifierKeyword) it.next(); |
| 85 | if (k.toFlagValue() == flagValue) { |
| 86 | return k; |
| 87 | } |
| 88 | } |
| 89 | return null; |
| 90 | } |
| 91 | |
| 92 | /** |
| 93 | * Returns the module modifier corresponding to the given string, |
| 94 | * or <code>null</code> if none. |
| 95 | * <p> |
| 96 | * <code>toKeyword</code> is the converse of <code>toString</code>: |
| 97 | * that is, <code>ModuleModifierKind.toKeyword(k.toString()) == k</code> for |
| 98 | * all module modifier keywords <code>k</code>. |
| 99 | * </p> |
| 100 | * |
| 101 | * @param keyword the lowercase string name for the module modifier |
| 102 | * @return the module modifier keyword, or <code>null</code> if none |
| 103 | * @see #toString() |
| 104 | */ |
| 105 | public static ModuleModifierKeyword toKeyword(String keyword) { |
| 106 | return (ModuleModifierKeyword) KEYWORDS.get(keyword); |
| 107 | } |
| 108 | |
| 109 | /** |
| 110 | * The flag value for the module modifier. |
| 111 | */ |
| 112 | private int flagValue; |
| 113 | |
| 114 | /** |
| 115 | * The keyword module modifier string. |
| 116 | */ |
| 117 | private String keyword; |
| 118 | |
| 119 | /** |
| 120 | * Creates a new module modifier with the given keyword. |
| 121 | * <p> |
| 122 | * Note: this constructor is private. The only instances |
| 123 | * ever created are the ones for the standard modifiers. |
| 124 | * </p> |
| 125 | * |
| 126 | * @param keyword the character sequence for the module modifier |
| 127 | * @param flagValue flag value as described in the Java Virtual Machine Specification |
| 128 | */ |
| 129 | private ModuleModifierKeyword(String keyword, int flagValue) { |
| 130 | this.keyword = keyword; |
| 131 | this.flagValue = flagValue; |
| 132 | } |
| 133 | |
| 134 | /** |
| 135 | * Returns the module modifier flag value corresponding to this module modifier keyword. |
| 136 | * These flag values are as described in the Java Virtual Machine Specification. |
| 137 | * |
| 138 | * @return one of the <code>ModuleModifier</code> constants |
| 139 | * @see #fromFlagValue(int) |
| 140 | */ |
| 141 | public int toFlagValue() { |
| 142 | return this.flagValue; |
| 143 | } |
| 144 | |
| 145 | /** |
| 146 | * Returns the keyword for the module modifier. |
| 147 | * |
| 148 | * @return the keyword for the module modifier |
| 149 | * @see #toKeyword(String) |
| 150 | */ |
| 151 | @Override |
| 152 | public String toString() { |
| 153 | return this.keyword; |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | /** |
| 158 | * The "keyword" structural property of this node type (type: {@link ModuleModifier.ModuleModifierKeyword}). |
| 159 | */ |
| 160 | public static final SimplePropertyDescriptor KEYWORD_PROPERTY = |
| 161 | new SimplePropertyDescriptor(ModuleModifier.class, "keyword", ModuleModifier.ModuleModifierKeyword.class, MANDATORY); //$NON-NLS-1$ |
| 162 | |
| 163 | /** |
| 164 | * Module Modifier constant (bit mask, value 0) indicating no module modifiers. |
| 165 | */ |
| 166 | public static final int NONE = 0x0000; |
| 167 | |
| 168 | /** |
| 169 | * "static" module modifier constant (bit mask). |
| 170 | * Applicable to requires directive. |
| 171 | * <p> |
| 172 | * Note that the value of <b>static</b> does <b>not</b> correspond to the value of {@link Modifier#STATIC}! |
| 173 | * </p> |
| 174 | */ |
| 175 | public static final int STATIC_PHASE = 0x0040; |
| 176 | |
| 177 | /** |
| 178 | * "transitive" module modifier constant (bit mask). |
| 179 | * Applicable only to requires directive. |
| 180 | */ |
| 181 | public static final int TRANSITIVE = 0x0080; |
| 182 | |
| 183 | /** |
| 184 | * A list of property descriptors (element type: |
| 185 | * {@link StructuralPropertyDescriptor}), |
| 186 | * or null if uninitialized. |
| 187 | */ |
| 188 | private static final List PROPERTY_DESCRIPTORS; |
| 189 | |
| 190 | static { |
| 191 | List properyList = new ArrayList(2); |
| 192 | createPropertyList(ModuleModifier.class, properyList); |
| 193 | addProperty(KEYWORD_PROPERTY, properyList); |
| 194 | PROPERTY_DESCRIPTORS = reapPropertyList(properyList); |
| 195 | } |
| 196 | |
| 197 | /** |
| 198 | * Returns whether the given flags includes the "transitive" module modifier. |
| 199 | * |
| 200 | * @param flags the module modifier flags |
| 201 | * @return <code>true</code> if the <code>TRANSITIVE</code> bit is |
| 202 | * set, and <code>false</code> otherwise |
| 203 | */ |
| 204 | public static boolean isTransitive(int flags) { |
| 205 | return (flags & TRANSITIVE) != 0; |
| 206 | } |
| 207 | |
| 208 | /** |
| 209 | * Returns whether the given flags includes the "static" module modifier. |
| 210 | * |
| 211 | * @param flags the module modifier flags |
| 212 | * @return <code>true</code> if the <code>STATIC</code> bit is |
| 213 | * set, and <code>false</code> otherwise |
| 214 | */ |
| 215 | public static boolean isStatic(int flags) { |
| 216 | return (flags & STATIC_PHASE) != 0; |
| 217 | } |
| 218 | |
| 219 | /** |
| 220 | * Returns a list of structural property descriptors for this node type. |
| 221 | * Clients must not modify the result. |
| 222 | * |
| 223 | * @param apiLevel the API level; one of the |
| 224 | * <code>AST.JLS*</code> constants |
| 225 | |
| 226 | * @return a list of property descriptors (element type: |
| 227 | * {@link StructuralPropertyDescriptor}) |
| 228 | */ |
| 229 | public static List propertyDescriptors(int apiLevel) { |
| 230 | return PROPERTY_DESCRIPTORS; |
| 231 | } |
| 232 | |
| 233 | /** |
| 234 | * The modifier keyword; defaults to an unspecified modifier. |
| 235 | */ |
| 236 | private ModuleModifierKeyword modifierKeyword = ModuleModifierKeyword.STATIC_KEYWORD; |
| 237 | |
| 238 | /** |
| 239 | * Creates a new unparented MODULE modifier node owned by the given AST. |
| 240 | * By default, the node has unspecified (but legal) modifier. |
| 241 | * <p> |
| 242 | * N.B. This constructor is package-private. |
| 243 | * </p> |
| 244 | * |
| 245 | * @param ast the AST that is to own this node |
| 246 | */ |
| 247 | ModuleModifier(AST ast) { |
| 248 | super(ast); |
| 249 | unsupportedBelow9(); |
| 250 | } |
| 251 | |
| 252 | @Override |
| 253 | void accept0(ASTVisitor visitor) { |
| 254 | visitor.visit(this); |
| 255 | visitor.endVisit(this); |
| 256 | } |
| 257 | |
| 258 | @Override |
| 259 | ASTNode clone0(AST target) { |
| 260 | ModuleModifier result = new ModuleModifier(target); |
| 261 | result.setSourceRange(getStartPosition(), getLength()); |
| 262 | result.setKeyword(getKeyword()); |
| 263 | return result; |
| 264 | } |
| 265 | |
| 266 | /** |
| 267 | * Returns the modifier keyword of this modifier node. |
| 268 | * |
| 269 | * @return the modifier keyword |
| 270 | */ |
| 271 | public ModuleModifierKeyword getKeyword() { |
| 272 | return this.modifierKeyword; |
| 273 | } |
| 274 | |
| 275 | /** |
| 276 | * Sets the module modifier keyword of this module modifier node. |
| 277 | * |
| 278 | * @param modifierKeyord the module modifier keyword |
| 279 | * @exception IllegalArgumentException if the argument is <code>null</code> |
| 280 | */ |
| 281 | public void setKeyword(ModuleModifierKeyword modifierKeyord) { |
| 282 | if (modifierKeyord == null) { |
| 283 | throw new IllegalArgumentException(); |
| 284 | } |
| 285 | preValueChange(KEYWORD_PROPERTY); |
| 286 | this.modifierKeyword = modifierKeyord; |
| 287 | postValueChange(KEYWORD_PROPERTY); |
| 288 | } |
| 289 | |
| 290 | @Override |
| 291 | final int getNodeType0() { |
| 292 | return MODULE_MODIFIER; |
| 293 | } |
| 294 | |
| 295 | @Override |
| 296 | final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { |
| 297 | if (property == KEYWORD_PROPERTY) { |
| 298 | if (get) { |
| 299 | return getKeyword(); |
| 300 | } else { |
| 301 | setKeyword((ModuleModifierKeyword) value); |
| 302 | return null; |
| 303 | } |
| 304 | } |
| 305 | // allow default implementation to flag the error |
| 306 | return super.internalGetSetObjectProperty(property, get, value); |
| 307 | } |
| 308 | |
| 309 | @Override |
| 310 | final List internalStructuralPropertiesForType(int apiLevel) { |
| 311 | return propertyDescriptors(apiLevel); |
| 312 | } |
| 313 | |
| 314 | /** |
| 315 | * Answer true if the receiver is the static module modifier, false otherwise. |
| 316 | * |
| 317 | * @return true if the receiver is the static module modifier, false otherwise |
| 318 | */ |
| 319 | public boolean isStatic() { |
| 320 | return this.modifierKeyword == ModuleModifierKeyword.STATIC_KEYWORD; |
| 321 | } |
| 322 | |
| 323 | /** |
| 324 | * Answer true if the receiver is the transitive module modifier, false otherwise. |
| 325 | * |
| 326 | * @return true if the receiver is the transitive module modifier, false otherwise |
| 327 | */ |
| 328 | public boolean isTransitive() { |
| 329 | return this.modifierKeyword == ModuleModifierKeyword.TRANSITIVE_KEYWORD; |
| 330 | } |
| 331 | |
| 332 | @Override |
| 333 | int memSize() { |
| 334 | // treat ModifierKeyword as free |
| 335 | return BASE_NODE_SIZE + 1 * 4; |
| 336 | } |
| 337 | |
| 338 | @Override |
| 339 | final boolean subtreeMatch0(ASTMatcher matcher, Object other) { |
| 340 | // dispatch to correct overloaded match method |
| 341 | return matcher.match(this, other); |
| 342 | } |
| 343 | |
| 344 | @Override |
| 345 | int treeSize() { |
| 346 | return memSize(); |
| 347 | } |
| 348 | } |
| 349 |
Members