Skip to content

Commit

Permalink
8224922: Access JavaFileObject from Element(s)
Browse files Browse the repository at this point in the history
Co-authored-by: Jan Lahoda <jlahoda@openjdk.org>
Reviewed-by: jjg
  • Loading branch information
jddarcy and lahodaj committed Nov 21, 2021
1 parent 0a9e76c commit 4ff4301
Show file tree
Hide file tree
Showing 9 changed files with 752 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -69,7 +69,13 @@
* originating elements are the classes or interfaces or packages
* (representing {@code package-info} files) or modules (representing
* {@code module-info} files) which caused an annotation processor to
* attempt to create a new file. For example, if an annotation
* attempt to create a new file.
* In other words, the originating elements are intended to have the
* granularity of <em>compilation units</em> (JLS section {@jls 7.3}),
* essentially file-level granularity, rather than finer-scale
* granularity of, say, a method or field declaration.
*
* <p>For example, if an annotation
* processor tries to create a source file, {@code
* GeneratedFromUserSource}, in response to processing
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -131,6 +131,12 @@ public interface ExecutableElement extends Element, Parameterizable {
*/
AnnotationValue getDefaultValue();

/**
* {@return the class or interface defining the executable}
*/
@Override
Element getEnclosingElement();

/**
* {@return the simple name of a constructor, method, or
* initializer} For a constructor, the name {@code "<init>"} is
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -36,19 +36,20 @@
* appearing inside method bodies, such as local variables and
* anonymous classes.
*
* <p>When used in the context of annotation processing, an accurate
* model of the element being represented must be returned. As this
* is a language model, the source code provides the fiducial
* (reference) representation of the construct in question rather than
* a representation in an executable output like a class file.
* Executable output may serve as the basis for creating a modeling
* element. However, the process of translating source code to
* executable output may not permit recovering some aspects of the
* source code representation. For example, annotations with
* {@linkplain java.lang.annotation.RetentionPolicy#SOURCE source}
* {@linkplain java.lang.annotation.Retention retention} cannot be
* recovered from class files and class files might not be able to
* provide source position information.
* <p id="accurate_model">When used in the context of annotation
* processing, an accurate model of the element being represented must
* be returned. As this is a language model, the source code provides
* the fiducial (reference) representation of the construct in
* question rather than a representation in an executable output like
* a class file. Executable output may serve as the basis for
* creating a modeling element. However, the process of translating
* source code to executable output may not permit recovering some
* aspects of the source code representation. For example,
* annotations with {@linkplain
* java.lang.annotation.RetentionPolicy#SOURCE source} {@linkplain
* java.lang.annotation.Retention retention} cannot be recovered from
* class files and class files might not be able to provide source
* position information.
*
* Names of {@linkplain
* javax.lang.model.element.ExecutableElement#getParameters()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -761,4 +761,100 @@ default RecordComponentElement recordComponentFor(ExecutableElement accessor) {
}
return null;
}

/**
* {@return the file object for this element or {@code null} if
* there is no such file object}
*
* <p>The returned file object is for the <a
* href="../element/package-summary.html#accurate_model">reference
* representation</a> of the information used to construct the
* element. For example, if during compilation or annotation
* processing, a source file for class {@code Foo} is compiled
* into a class file, the file object returned for the element
* representing {@code Foo} would be for the source file and
* <em>not</em> for the class file.
*
* <p>An implementation may choose to not support the
* functionality of this method, in which case {@link
* UnsupportedOperationException} is thrown.
*
* <p>In the context of annotation processing, a non-{@code null}
* value is returned if the element was included as part of the
* initial inputs or the containing file was created during the
* run of the annotation processing tool. Otherwise, a {@code
* null} may be returned. In annotation processing, if a
* {@linkplain javax.annotation.processing.Filer#createClassFile
* class file is created}, that class file can serve as the
* reference representation for elements.
*
* <p>If it has a file object, the file object for a package will
* be a {@code package-info} file. A package may exist and not
* have any {@code package-info} file even if the package is
* (implicitly) created during an annotation processing run from
* the creation of source or class files in that package. An
* {@linkplain PackageElement#isUnnamed unnamed package} will have
* a {@code null} file since it cannot be declared in a
* compilation unit.
*
* <p>If it has a file object, the file object for a module will
* be a {@code module-info} file. An {@linkplain
* ModuleElement#isUnnamed unnamed module} will have a {@code
* null} file since it cannot be declared in a compilation unit.
* An {@linkplain #isAutomaticModule automatic module} will have a
* {@code null} file since it is implicitly declared.
*
* <p>If it has a file object, the file object for a top-level
* {@code public} class or interface will be a source or class
* file corresponding to that class or interface. In this case,
* typically the leading portion of the name of the file will
* match the name of the class or interface. A single compilation
* unit can define multiple top-level classes and interfaces, such
* as a primary {@code public} class or interfaces whose name
* corresponds to the file name and one or more <em>auxiliary</em>
* classes or interfaces whose names do not correspond to the file
* name. If a source file is providing the reference
* representation of an auxiliary class or interface, the file for
* the primary class is returned. (An auxiliary class or interface
* can also be defined in a {@code package-info} source file, in
* which case the file for the {@code package-info} file is
* returned.) If a class file is providing the reference
* representation of an auxiliary class or interface, the separate
* class file for the auxiliary class is returned.
*
* <p>For a nested class or interface, if it has a file object:
*
* <ul>
*
* <li>if a source file is providing the reference representation,
* the file object will be that of the {@linkplain
* #getOutermostTypeElement(Element) outermost enclosing} class or
* interface
*
* <li>if a class file is providing the reference representation,
* the file object will be that of the nested class or interface
* itself
*
* </ul>
*
* <p>For other lexically enclosed elements, such as {@linkplain
* VariableElement#getEnclosingElement() variables}, {@linkplain
* ExecutableElement#getEnclosingElement() methods, and
* constructors}, if they have a file object, the file object will
* be the object associated with the {@linkplain
* Element#getEnclosingElement() enclosing element} of the
* lexically enclosed element.
*
* @implSpec The default implementation unconditionally throws
* {@link UnsupportedOperationException}.
*
* @throws UnsupportedOperationException if this functionality is
* not supported
*
* @param e the element to find a file object for
* @since 18
*/
default javax.tools.JavaFileObject getFileObjectOf(Element e) {
throw new UnsupportedOperationException();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -376,7 +376,7 @@ public void visitTopLevel(JCCompilationUnit tree) {
Name name = names.package_info;
ClassSymbol c = syms.enterClass(tree.modle, name, tree.packge);
c.flatname = names.fromString(tree.packge + "." + name);
c.sourcefile = tree.sourcefile;
c.classfile = c.sourcefile = tree.sourcefile;
c.completer = Completer.NULL_COMPLETER;
c.members_field = WriteableScope.create(c);
tree.packge.package_info = c;
Expand Down Expand Up @@ -495,7 +495,7 @@ public void visitClassDef(JCClassDecl tree) {
// Fill out class fields.
c.completer = Completer.NULL_COMPLETER; // do not allow the initial completer linger on.
c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree);
c.sourcefile = env.toplevel.sourcefile;
c.classfile = c.sourcefile = env.toplevel.sourcefile;
c.members_field = WriteableScope.create(c);
c.clearAnnotationMetadata();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ private void enterModule(JCCompilationUnit toplevel, ClassSymbol c, Set<ModuleSy
}
}
sym.completer = getSourceCompleter(toplevel);
sym.module_info.sourcefile = toplevel.sourcefile;
sym.module_info.classfile = sym.module_info.sourcefile = toplevel.sourcefile;
decl.sym = sym;

if (multiModuleMode || modules.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,30 @@ public boolean isAutomaticModule(ModuleElement module) {
return (msym.flags() & Flags.AUTOMATIC_MODULE) != 0;
}

@Override @DefinedBy(Api.LANGUAGE_MODEL)
public JavaFileObject getFileObjectOf(Element e) {
Symbol sym = (Symbol) e;
return switch(sym.kind) {
case PCK -> {
PackageSymbol psym = (PackageSymbol) sym;
if (psym.package_info == null) {
yield null;
}
yield psym.package_info.classfile;
}

case MDL -> {
ModuleSymbol msym = (ModuleSymbol) sym;
if (msym.module_info == null) {
yield null;
}
yield msym.module_info.classfile;
}
case TYP -> ((ClassSymbol) sym).classfile;
default -> sym.enclClass().classfile;
};
}

/**
* Returns the tree node and compilation unit corresponding to this
* element, or null if they can't be found.
Expand Down
Loading

1 comment on commit 4ff4301

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.