1 /*
   2  * Copyright (c) 2015, 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 
  26 package jdk.javadoc.internal.doclets.toolkit;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Arrays;
  30 import java.util.Collection;
  31 import java.util.Collections;
  32 import java.util.HashMap;
  33 import java.util.List;
  34 import java.util.Map;
  35 import java.util.SortedSet;
  36 import java.util.TreeSet;
  37 
  38 import javax.lang.model.element.AnnotationMirror;
  39 import javax.lang.model.element.Element;
  40 import javax.lang.model.element.ExecutableElement;
  41 import javax.lang.model.element.ModuleElement;
  42 import javax.lang.model.element.PackageElement;
  43 import javax.lang.model.element.TypeElement;
  44 import javax.lang.model.element.VariableElement;
  45 import javax.lang.model.type.TypeMirror;
  46 import javax.lang.model.util.Elements;
  47 import javax.tools.FileObject;
  48 import javax.tools.JavaFileManager.Location;
  49 
  50 import com.sun.source.tree.CompilationUnitTree;
  51 import com.sun.source.util.JavacTask;
  52 import com.sun.source.util.TreePath;
  53 import com.sun.tools.doclint.DocLint;
  54 import com.sun.tools.javac.api.BasicJavacTask;
  55 import com.sun.tools.javac.code.Attribute;
  56 import com.sun.tools.javac.code.Flags;
  57 import com.sun.tools.javac.code.Scope;
  58 import com.sun.tools.javac.code.Symbol;
  59 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  60 import com.sun.tools.javac.code.Symbol.MethodSymbol;
  61 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
  62 import com.sun.tools.javac.code.Symbol.PackageSymbol;
  63 import com.sun.tools.javac.code.Symbol.VarSymbol;
  64 import com.sun.tools.javac.code.TypeTag;
  65 import com.sun.tools.javac.comp.AttrContext;
  66 import com.sun.tools.javac.comp.Env;
  67 import com.sun.tools.javac.model.JavacElements;
  68 import com.sun.tools.javac.model.JavacTypes;
  69 import com.sun.tools.javac.util.Names;
  70 
  71 import jdk.javadoc.internal.doclets.toolkit.util.Utils;
  72 import jdk.javadoc.internal.tool.ToolEnvironment;
  73 import jdk.javadoc.internal.tool.DocEnvImpl;
  74 
  75 import static com.sun.tools.javac.code.Kinds.Kind.*;
  76 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
  77 
  78 import static javax.lang.model.element.ElementKind.*;
  79 
  80 /**
  81  * A quarantine class to isolate all the workarounds and bridges to
  82  * a locality. This class should eventually disappear once all the
  83  * standard APIs support the needed interfaces.
  84  *
  85  *
  86  *  <p><b>This is NOT part of any supported API.
  87  *  If you write code that depends on this, you do so at your own risk.
  88  *  This code and its internal interfaces are subject to change or
  89  *  deletion without notice.</b>
  90  */
  91 public class WorkArounds {
  92 
  93     public final BaseConfiguration configuration;
  94     public final ToolEnvironment toolEnv;
  95     public final Utils utils;
  96 
  97     private DocLint doclint;
  98 
  99     public WorkArounds(BaseConfiguration configuration) {
 100         this.configuration = configuration;
 101         this.utils = this.configuration.utils;
 102         this.toolEnv = ((DocEnvImpl)this.configuration.docEnv).toolEnv;
 103     }
 104 
 105     Map<CompilationUnitTree, Boolean> shouldCheck = new HashMap<>();
 106     // TODO: fix this up correctly
 107     public void runDocLint(TreePath path) {
 108         CompilationUnitTree unit = path.getCompilationUnit();
 109         if (doclint != null && shouldCheck.computeIfAbsent(unit, doclint::shouldCheck)) {
 110             doclint.scan(path);
 111         }
 112     }
 113 
 114     // TODO: fix this up correctly
 115     public void initDocLint(Collection<String> opts, Collection<String> customTagNames, String htmlVersion) {
 116         ArrayList<String> doclintOpts = new ArrayList<>();
 117         boolean msgOptionSeen = false;
 118 
 119         for (String opt : opts) {
 120             if (opt.startsWith(DocLint.XMSGS_OPTION)) {
 121                 if (opt.equals(DocLint.XMSGS_CUSTOM_PREFIX + "none"))
 122                     return;
 123                 msgOptionSeen = true;
 124             }
 125             doclintOpts.add(opt);
 126         }
 127 
 128         if (!msgOptionSeen) {
 129             doclintOpts.add(DocLint.XMSGS_OPTION);
 130         }
 131 
 132         String sep = "";
 133         StringBuilder customTags = new StringBuilder();
 134         for (String customTag : customTagNames) {
 135             customTags.append(sep);
 136             customTags.append(customTag);
 137             sep = DocLint.SEPARATOR;
 138         }
 139         doclintOpts.add(DocLint.XCUSTOM_TAGS_PREFIX + customTags.toString());
 140         doclintOpts.add(DocLint.XHTML_VERSION_PREFIX + htmlVersion);
 141 
 142         JavacTask t = BasicJavacTask.instance(toolEnv.context);
 143         doclint = new DocLint();
 144         // standard doclet normally generates H1, H2
 145         doclintOpts.add(DocLint.XIMPLICIT_HEADERS + "2");
 146         doclint.init(t, doclintOpts.toArray(new String[doclintOpts.size()]), false);
 147     }
 148 
 149     // TODO: fix this up correctly
 150     public boolean haveDocLint() {
 151         return (doclint == null);
 152     }
 153 
 154     // TODO: jx.l.m directSuperTypes don't work for things like Enum,
 155     // so we use javac directly, investigate why jx.l.m is not cutting it.
 156     public List<TypeMirror> interfaceTypesOf(TypeMirror type) {
 157         com.sun.tools.javac.util.List<com.sun.tools.javac.code.Type> interfaces =
 158                 ((DocEnvImpl)configuration.docEnv).toolEnv.getTypes().interfaces((com.sun.tools.javac.code.Type)type);
 159         if (interfaces.isEmpty()) {
 160             return Collections.emptyList();
 161         }
 162         List<TypeMirror> list = new ArrayList<>(interfaces.size());
 163         for (com.sun.tools.javac.code.Type t : interfaces) {
 164             list.add((TypeMirror)t);
 165         }
 166         return list;
 167     }
 168 
 169     /*
 170      * TODO: This method exists because of a bug in javac which does not
 171      * handle "@deprecated tag in package-info.java", when this issue
 172      * is fixed this method and its uses must be jettisoned.
 173      */
 174     public boolean isDeprecated0(Element e) {
 175         if (!utils.getDeprecatedTrees(e).isEmpty()) {
 176             return true;
 177         }
 178         JavacTypes jctypes = ((DocEnvImpl)configuration.docEnv).toolEnv.typeutils;
 179         TypeMirror deprecatedType = utils.getDeprecatedType();
 180         for (AnnotationMirror anno : e.getAnnotationMirrors()) {
 181             if (jctypes.isSameType(anno.getAnnotationType().asElement().asType(), deprecatedType))
 182                 return true;
 183         }
 184         return false;
 185     }
 186 
 187     // TODO: fix jx.l.m add this method.
 188     public boolean isSynthesized(AnnotationMirror aDesc) {
 189         return ((Attribute)aDesc).isSynthesized();
 190     }
 191 
 192     // TODO: fix the caller
 193     public Object getConstValue(VariableElement ve) {
 194         return ((VarSymbol)ve).getConstValue();
 195     }
 196 
 197     // TODO: DocTrees: Trees.getPath(Element e) is slow a factor 4-5 times.
 198     public Map<Element, TreePath> getElementToTreePath() {
 199         return toolEnv.elementToTreePath;
 200     }
 201 
 202     // TODO: we need ElementUtils.getPackage to cope with input strings
 203     // to return the proper unnamedPackage for all supported releases.
 204     PackageElement getUnnamedPackage() {
 205         return (toolEnv.source.allowModules())
 206                 ? toolEnv.syms.unnamedModule.unnamedPackage
 207                 : toolEnv.syms.noModule.unnamedPackage;
 208     }
 209 
 210     // TODO: implement in either jx.l.m API (preferred) or DocletEnvironment.
 211     FileObject getJavaFileObject(PackageElement packageElement) {
 212         return ((PackageSymbol)packageElement).sourcefile;
 213     }
 214 
 215     // TODO: needs to ported to jx.l.m.
 216     public TypeElement searchClass(TypeElement klass, String className) {
 217         // search by qualified name first
 218         TypeElement te = configuration.docEnv.getElementUtils().getTypeElement(className);
 219         if (te != null) {
 220             return te;
 221         }
 222 
 223         // search inner classes
 224         for (TypeElement ite : utils.getClasses(klass)) {
 225             TypeElement innerClass = searchClass(ite, className);
 226             if (innerClass != null) {
 227                 return innerClass;
 228             }
 229         }
 230 
 231         // check in this package
 232         te = utils.findClassInPackageElement(utils.containingPackage(klass), className);
 233         if (te != null) {
 234             return te;
 235         }
 236 
 237         ClassSymbol tsym = (ClassSymbol)klass;
 238         // make sure that this symbol has been completed
 239         // TODO: do we need this anymore ?
 240         if (tsym.completer != null) {
 241             tsym.complete();
 242         }
 243 
 244         // search imports
 245         if (tsym.sourcefile != null) {
 246 
 247             //### This information is available only for source classes.
 248             Env<AttrContext> compenv = toolEnv.getEnv(tsym);
 249             if (compenv == null) {
 250                 return null;
 251             }
 252             Names names = tsym.name.table.names;
 253             Scope s = compenv.toplevel.namedImportScope;
 254             for (Symbol sym : s.getSymbolsByName(names.fromString(className))) {
 255                 if (sym.kind == TYP) {
 256                     return (TypeElement)sym;
 257                 }
 258             }
 259 
 260             s = compenv.toplevel.starImportScope;
 261             for (Symbol sym : s.getSymbolsByName(names.fromString(className))) {
 262                 if (sym.kind == TYP) {
 263                     return (TypeElement)sym;
 264                 }
 265             }
 266         }
 267 
 268         return null; // not found
 269     }
 270 
 271     // TODO:  need to re-implement this using j.l.m. correctly!, this has
 272     // implications on testInterface, the note here is that javac's supertype
 273     // does the right thing returning Parameters in scope.
 274     /**
 275      * Return the type containing the method that this method overrides.
 276      * It may be a <code>TypeElement</code> or a <code>TypeParameterElement</code>.
 277      * @param method target
 278      * @return a type
 279      */
 280     public TypeMirror overriddenType(ExecutableElement method) {
 281         if (utils.isStatic(method)) {
 282             return null;
 283         }
 284         MethodSymbol sym = (MethodSymbol)method;
 285         ClassSymbol origin = (ClassSymbol) sym.owner;
 286         for (com.sun.tools.javac.code.Type t = toolEnv.getTypes().supertype(origin.type);
 287                 t.hasTag(TypeTag.CLASS);
 288                 t = toolEnv.getTypes().supertype(t)) {
 289             ClassSymbol c = (ClassSymbol) t.tsym;
 290             for (com.sun.tools.javac.code.Symbol sym2 : c.members().getSymbolsByName(sym.name)) {
 291                 if (sym.overrides(sym2, origin, toolEnv.getTypes(), true)) {
 292                     // Ignore those methods that may be a simple overridden
 293                     // and allow the real API method to be found.
 294                     if (sym2.type.hasTag(TypeTag.METHOD) &&
 295                             utils.isSimpleOverride((MethodSymbol)sym2)) {
 296                         continue;
 297                     }
 298                     return t;
 299                 }
 300             }
 301         }
 302         return null;
 303     }
 304 
 305     // TODO: the method jx.l.m.Elements::overrides does not check
 306     // the return type, see JDK-8174840 until that is resolved,
 307     // use a  copy of the same method, with a return type check.
 308 
 309     // Note: the rider.overrides call in this method *must* be consistent
 310     // with the call in overrideType(....), the method above.
 311     public boolean overrides(ExecutableElement e1, ExecutableElement e2, TypeElement cls) {
 312         MethodSymbol rider = (MethodSymbol)e1;
 313         MethodSymbol ridee = (MethodSymbol)e2;
 314         ClassSymbol origin = (ClassSymbol)cls;
 315 
 316         return rider.name == ridee.name &&
 317 
 318                // not reflexive as per JLS
 319                rider != ridee &&
 320 
 321                // we don't care if ridee is static, though that wouldn't
 322                // compile
 323                !rider.isStatic() &&
 324 
 325                // Symbol.overrides assumes the following
 326                ridee.isMemberOf(origin, toolEnv.getTypes()) &&
 327 
 328                // check access, signatures and check return types
 329                rider.overrides(ridee, origin, toolEnv.getTypes(), true);
 330     }
 331 
 332     // TODO: jx.l.m ?
 333     public Location getLocationForModule(ModuleElement mdle) {
 334         ModuleSymbol msym = (ModuleSymbol)mdle;
 335         return msym.sourceLocation != null
 336                 ? msym.sourceLocation
 337                 : msym.classLocation;
 338     }
 339 
 340     //------------------Start of Serializable Implementation---------------------//
 341     private final static Map<TypeElement, NewSerializedForm> serializedForms = new HashMap<>();
 342 
 343     public SortedSet<VariableElement> getSerializableFields(Utils utils, TypeElement klass) {
 344         NewSerializedForm sf = serializedForms.get(klass);
 345         if (sf == null) {
 346             sf = new NewSerializedForm(utils, configuration.docEnv.getElementUtils(), klass);
 347             serializedForms.put(klass, sf);
 348         }
 349         return sf.fields;
 350     }
 351 
 352     public SortedSet<ExecutableElement>  getSerializationMethods(Utils utils, TypeElement klass) {
 353         NewSerializedForm sf = serializedForms.get(klass);
 354         if (sf == null) {
 355             sf = new NewSerializedForm(utils, configuration.docEnv.getElementUtils(), klass);
 356             serializedForms.put(klass, sf);
 357         }
 358         return sf.methods;
 359     }
 360 
 361     public boolean definesSerializableFields(Utils utils, TypeElement klass) {
 362         if (!utils.isSerializable(klass) || utils.isExternalizable(klass)) {
 363             return false;
 364         } else {
 365             NewSerializedForm sf = serializedForms.get(klass);
 366             if (sf == null) {
 367                 sf = new NewSerializedForm(utils, configuration.docEnv.getElementUtils(), klass);
 368                 serializedForms.put(klass, sf);
 369             }
 370             return sf.definesSerializableFields;
 371         }
 372     }
 373 
 374     /* TODO we need a clean port to jx.l.m
 375      * The serialized form is the specification of a class' serialization state.
 376      * <p>
 377      *
 378      * It consists of the following information:
 379      * <p>
 380      *
 381      * <pre>
 382      * 1. Whether class is Serializable or Externalizable.
 383      * 2. Javadoc for serialization methods.
 384      *    a. For Serializable, the optional readObject, writeObject,
 385      *       readResolve and writeReplace.
 386      *       serialData tag describes, in prose, the sequence and type
 387      *       of optional data written by writeObject.
 388      *    b. For Externalizable, writeExternal and readExternal.
 389      *       serialData tag describes, in prose, the sequence and type
 390      *       of optional data written by writeExternal.
 391      * 3. Javadoc for serialization data layout.
 392      *    a. For Serializable, the name,type and description
 393      *       of each Serializable fields.
 394      *    b. For Externalizable, data layout is described by 2(b).
 395      * </pre>
 396      *
 397      */
 398     static class NewSerializedForm {
 399 
 400         final Utils utils;
 401         final Elements elements;
 402 
 403         final SortedSet<ExecutableElement> methods;
 404 
 405         /* List of FieldDocImpl - Serializable fields.
 406          * Singleton list if class defines Serializable fields explicitly.
 407          * Otherwise, list of default serializable fields.
 408          * 0 length list for Externalizable.
 409          */
 410         final SortedSet<VariableElement> fields;
 411 
 412         /* True if class specifies serializable fields explicitly.
 413          * using special static member, serialPersistentFields.
 414          */
 415         boolean definesSerializableFields = false;
 416 
 417         // Specially treated field/method names defined by Serialization.
 418         private static final String SERIALIZABLE_FIELDS = "serialPersistentFields";
 419         private static final String READOBJECT = "readObject";
 420         private static final String WRITEOBJECT = "writeObject";
 421         private static final String READRESOLVE = "readResolve";
 422         private static final String WRITEREPLACE = "writeReplace";
 423         private static final String READOBJECTNODATA = "readObjectNoData";
 424 
 425         NewSerializedForm(Utils utils, Elements elements, TypeElement te) {
 426             this.utils = utils;
 427             this.elements = elements;
 428             methods = new TreeSet<>(utils.makeGeneralPurposeComparator());
 429             fields = new TreeSet<>(utils.makeGeneralPurposeComparator());
 430             if (utils.isExternalizable(te)) {
 431                 /* look up required public accessible methods,
 432                  *   writeExternal and readExternal.
 433                  */
 434                 String[] readExternalParamArr = {"java.io.ObjectInput"};
 435                 String[] writeExternalParamArr = {"java.io.ObjectOutput"};
 436 
 437                 ExecutableElement md = findMethod(te, "readExternal", Arrays.asList(readExternalParamArr));
 438                 if (md != null) {
 439                     methods.add(md);
 440                 }
 441                 md = findMethod((ClassSymbol) te, "writeExternal", Arrays.asList(writeExternalParamArr));
 442                 if (md != null) {
 443                     methods.add(md);
 444                 }
 445             } else if (utils.isSerializable(te)) {
 446                 VarSymbol dsf = getDefinedSerializableFields((ClassSymbol) te);
 447                 if (dsf != null) {
 448                     /* Define serializable fields with array of ObjectStreamField.
 449                      * Each ObjectStreamField should be documented by a
 450                      * serialField tag.
 451                      */
 452                     definesSerializableFields = true;
 453                     fields.add((VariableElement) dsf);
 454                 } else {
 455 
 456                     /* Calculate default Serializable fields as all
 457                      * non-transient, non-static fields.
 458                      * Fields should be documented by serial tag.
 459                      */
 460                     computeDefaultSerializableFields((ClassSymbol) te);
 461                 }
 462 
 463                 /* Check for optional customized readObject, writeObject,
 464                  * readResolve and writeReplace, which can all contain
 465                  * the serialData tag.        */
 466                 addMethodIfExist((ClassSymbol) te, READOBJECT);
 467                 addMethodIfExist((ClassSymbol) te, WRITEOBJECT);
 468                 addMethodIfExist((ClassSymbol) te, READRESOLVE);
 469                 addMethodIfExist((ClassSymbol) te, WRITEREPLACE);
 470                 addMethodIfExist((ClassSymbol) te, READOBJECTNODATA);
 471             }
 472         }
 473 
 474         private VarSymbol getDefinedSerializableFields(ClassSymbol def) {
 475             Names names = def.name.table.names;
 476 
 477             /* SERIALIZABLE_FIELDS can be private,
 478              */
 479             for (Symbol sym : def.members().getSymbolsByName(names.fromString(SERIALIZABLE_FIELDS))) {
 480                 if (sym.kind == VAR) {
 481                     VarSymbol f = (VarSymbol) sym;
 482                     if ((f.flags() & Flags.STATIC) != 0
 483                             && (f.flags() & Flags.PRIVATE) != 0) {
 484                         return f;
 485                     }
 486                 }
 487             }
 488             return null;
 489         }
 490 
 491         /*
 492          * Catalog Serializable method if it exists in current ClassSymbol.
 493          * Do not look for method in superclasses.
 494          *
 495          * Serialization requires these methods to be non-static.
 496          *
 497          * @param method should be an unqualified Serializable method
 498          *               name either READOBJECT, WRITEOBJECT, READRESOLVE
 499          *               or WRITEREPLACE.
 500          * @param visibility the visibility flag for the given method.
 501          */
 502         private void addMethodIfExist(ClassSymbol def, String methodName) {
 503             Names names = def.name.table.names;
 504 
 505             for (Symbol sym : def.members().getSymbolsByName(names.fromString(methodName))) {
 506                 if (sym.kind == MTH) {
 507                     MethodSymbol md = (MethodSymbol) sym;
 508                     if ((md.flags() & Flags.STATIC) == 0) {
 509                         /*
 510                          * WARNING: not robust if unqualifiedMethodName is overloaded
 511                          *          method. Signature checking could make more robust.
 512                          * READOBJECT takes a single parameter, java.io.ObjectInputStream.
 513                          * WRITEOBJECT takes a single parameter, java.io.ObjectOutputStream.
 514                          */
 515                         methods.add(md);
 516                     }
 517                 }
 518             }
 519         }
 520 
 521         /*
 522          * Compute default Serializable fields from all members of ClassSymbol.
 523          *
 524          * must walk over all members of ClassSymbol.
 525          */
 526         private void computeDefaultSerializableFields(ClassSymbol te) {
 527             for (Symbol sym : te.members().getSymbols(NON_RECURSIVE)) {
 528                 if (sym != null && sym.kind == VAR) {
 529                     VarSymbol f = (VarSymbol) sym;
 530                     if ((f.flags() & Flags.STATIC) == 0
 531                             && (f.flags() & Flags.TRANSIENT) == 0) {
 532                         //### No modifier filtering applied here.
 533                         //### Add to beginning.
 534                         //### Preserve order used by old 'javadoc'.
 535                         fields.add(f);
 536                     }
 537                 }
 538             }
 539         }
 540 
 541         /**
 542          * Find a method in this class scope. Search order: this class, interfaces, superclasses,
 543          * outerclasses. Note that this is not necessarily what the compiler would do!
 544          *
 545          * @param methodName the unqualified name to search for.
 546          * @param paramTypes the array of Strings for method parameter types.
 547          * @return the first MethodDocImpl which matches, null if not found.
 548          */
 549         public ExecutableElement findMethod(TypeElement te, String methodName,
 550                 List<String> paramTypes) {
 551             List<? extends Element> allMembers = this.elements.getAllMembers(te);
 552             loop:
 553             for (Element e : allMembers) {
 554                 if (e.getKind() != METHOD) {
 555                     continue;
 556                 }
 557                 ExecutableElement ee = (ExecutableElement) e;
 558                 if (!ee.getSimpleName().contentEquals(methodName)) {
 559                     continue;
 560                 }
 561                 List<? extends VariableElement> parameters = ee.getParameters();
 562                 if (paramTypes.size() != parameters.size()) {
 563                     continue;
 564                 }
 565                 for (int i = 0; i < parameters.size(); i++) {
 566                     VariableElement ve = parameters.get(i);
 567                     if (!ve.asType().toString().equals(paramTypes.get(i))) {
 568                         break loop;
 569                     }
 570                 }
 571                 return ee;
 572             }
 573             TypeElement encl = utils.getEnclosingTypeElement(te);
 574             if (encl == null) {
 575                 return null;
 576             }
 577             return findMethod(encl, methodName, paramTypes);
 578         }
 579     }
 580 
 581     // TODO: we need to eliminate this, as it is hacky.
 582     /**
 583      * Returns a representation of the package truncated to two levels.
 584      * For instance if the given package represents foo.bar.baz will return
 585      * a representation of foo.bar
 586      * @param pkg the PackageElement
 587      * @return an abbreviated PackageElement
 588      */
 589     public PackageElement getAbbreviatedPackageElement(PackageElement pkg) {
 590         String parsedPackageName = utils.parsePackageName(pkg);
 591         ModuleElement encl = (ModuleElement) pkg.getEnclosingElement();
 592         PackageElement abbrevPkg = encl == null
 593                 ? utils.elementUtils.getPackageElement(parsedPackageName)
 594                 : ((JavacElements) utils.elementUtils).getPackageElement(encl, parsedPackageName);
 595         return abbrevPkg;
 596     }
 597 }