Skip to content

Commit

Permalink
[KT] Add support for package-info.java file in the Kotlin frontend.
Browse files Browse the repository at this point in the history
Koltin does not have the notion of package-info files where you can define annotation on a package. We let the `package-info.java` files present in the source  go to the Kotlin frontend. We parse them with the `JdtParser` and initialize correctly the `PackageInfoCache`.

PiperOrigin-RevId: 570850258
  • Loading branch information
jDramaix authored and copybara-github committed Oct 4, 2023
1 parent 0dbfc62 commit 3e37f32
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 75 deletions.
10 changes: 7 additions & 3 deletions build_defs/internal_do_not_use/j2cl_java_library.bzl
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""J2CL library rules."""

load(":provider.bzl", "J2clInfo", "J2ktInfo")
load(":j2cl_common.bzl", "J2CL_TOOLCHAIN_ATTRS", "j2cl_common", "split_srcs")
load(":j2kt_common.bzl", "j2kt_common")
load(":j2cl_js_common.bzl", "J2CL_JS_ATTRS", "JS_PROVIDER_NAME", "j2cl_js_provider")
load(":j2kt_common.bzl", "j2kt_common")
load(":provider.bzl", "J2clInfo", "J2ktInfo")

def _impl_j2cl_library(ctx):
if ctx.attr.j2kt_web_experiment_enabled:
Expand All @@ -21,7 +21,11 @@ def _impl_j2cl_library(ctx):
javac_opts = ctx.attr.javacopts,
)

srcs = js_srcs
# Pass the package-info.java files as srcs so Kotlin frontend can correctly resolved
# JsPackage annotations.
# TODO(dramaix): extract package-info from src-jar of the jvm compilation to include
# generated package-info.java files.
srcs = js_srcs + [f for f in jvm_srcs if f.basename == "package-info.java"]
kt_common_srcs = j2kt_provider._private_.transpile_kt_out

else:
Expand Down
11 changes: 8 additions & 3 deletions transpiler/java/com/google/j2cl/transpiler/BazelJ2clBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,9 @@ private J2clTranspilerOptions createOptions(Output output, Problems problems) {
ImmutableList<FileInfo> allKotlinSources =
allSources.stream().filter(p -> p.sourcePath().endsWith(".kt")).collect(toImmutableList());

// TODO(dramaix): add support for transpiling java and kotlin simultaneously.
if (!allJavaSources.isEmpty() && !allKotlinSources.isEmpty()) {
// For now, only package-info.java files are allowed with Kotlin sources.
if (allJavaSources.stream().anyMatch(f -> !f.sourcePath().endsWith("package-info.java"))
&& !allKotlinSources.isEmpty()) {
throw new AssertionError(
"Transpilation of Java and Kotlin files together is not supported yet.");
}
Expand All @@ -175,7 +176,11 @@ private J2clTranspilerOptions createOptions(Output output, Problems problems) {
.forEach(f -> output.copyFile(f.sourcePath(), f.targetPath()));

return J2clTranspilerOptions.newBuilder()
.setSources(allKotlinSources.isEmpty() ? allJavaSources : allKotlinSources)
.setSources(
ImmutableList.<FileInfo>builder()
.addAll(allJavaSources)
.addAll(allKotlinSources)
.build())
.setNativeSources(allNativeSources)
.setClasspaths(getPathEntries(this.classPath))
.setOutput(output)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.MoreCollectors.onlyElement;
import static com.google.j2cl.transpiler.frontend.jdt.JdtAnnotationUtils.isNullMarked;
import static com.google.j2cl.transpiler.frontend.jdt.JsInteropAnnotationUtils.getJsNamespace;
import static com.google.j2cl.transpiler.frontend.jdt.KtInteropAnnotationUtils.getKtObjectiveCName;
import static java.util.Arrays.stream;
import static java.util.Map.Entry.comparingByKey;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toList;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Iterables;
Expand Down Expand Up @@ -102,11 +104,9 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import javax.annotation.Nullable;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.ArrayType;
Expand All @@ -117,7 +117,6 @@
import org.eclipse.jdt.core.dom.EnumDeclaration;
import org.eclipse.jdt.core.dom.ExpressionMethodReference;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
Expand All @@ -126,6 +125,7 @@
import org.eclipse.jdt.core.dom.LambdaExpression;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
Expand All @@ -148,19 +148,17 @@ private CompilationUnit convert(
this.jdtCompilationUnit = jdtCompilationUnit;

setCurrentSourceFile(sourceFilePath);
PackageDeclaration packageDeclaration = jdtCompilationUnit.getPackage();
String packageName =
jdtCompilationUnit.getPackage() == null
? ""
: jdtCompilationUnit.getPackage().getName().getFullyQualifiedName();
packageDeclaration == null ? "" : packageDeclaration.getName().getFullyQualifiedName();
setCurrentCompilationUnit(CompilationUnit.createForFile(sourceFilePath, packageName));
// Records information about package-info files supplied as source code.
if (getCurrentSourceFile().endsWith("package-info.java")
&& jdtCompilationUnit.getPackage() != null) {
if (getCurrentSourceFile().endsWith("package-info.java") && packageDeclaration != null) {
setPackagePropertiesFromSource(
packageName,
getPackageJsNamespace(jdtCompilationUnit),
getObjectiveCName(jdtCompilationUnit),
isNullMarked(jdtCompilationUnit));
getJsNamespace(packageDeclaration),
getKtObjectiveCName(packageDeclaration),
isNullMarked(packageDeclaration));
}
for (Object object : jdtCompilationUnit.types()) {
AbstractTypeDeclaration abstractTypeDeclaration = (AbstractTypeDeclaration) object;
Expand All @@ -169,49 +167,6 @@ private CompilationUnit convert(

return getCurrentCompilationUnit();
}

@Nullable
private IAnnotationBinding getAnnotationBinding(
org.eclipse.jdt.core.dom.CompilationUnit jdtCompilationUnit,
Predicate<IAnnotationBinding> whichAnnotation) {
List<Annotation> packageAnnotations =
JdtEnvironment.asTypedList(jdtCompilationUnit.getPackage().annotations());
if (packageAnnotations == null) {
return null;
}

Optional<IAnnotationBinding> annotationBinding =
packageAnnotations.stream()
.map(Annotation::resolveAnnotationBinding)
.filter(whichAnnotation)
.findFirst();

return annotationBinding.orElse(null);
}

@Nullable
private String getObjectiveCName(org.eclipse.jdt.core.dom.CompilationUnit jdtCompilationUnit) {
IAnnotationBinding annotationBinding =
getAnnotationBinding(jdtCompilationUnit, KtInteropAnnotationUtils::isKtObjectiveCName);
return annotationBinding != null
? KtInteropAnnotationUtils.getKtObjectiveCName(annotationBinding)
: null;
}

@Nullable
private String getPackageJsNamespace(
org.eclipse.jdt.core.dom.CompilationUnit jdtCompilationUnit) {
IAnnotationBinding annotationBinding =
getAnnotationBinding(jdtCompilationUnit, JsInteropAnnotationUtils::isJsPackageAnnotation);
return annotationBinding != null
? JsInteropAnnotationUtils.getJsNamespace(annotationBinding)
: null;
}

private boolean isNullMarked(org.eclipse.jdt.core.dom.CompilationUnit jdtCompilationUnit) {
return JdtEnvironment.isNullMarked(jdtCompilationUnit.getPackage());
}

private Type convert(AbstractTypeDeclaration typeDeclaration) {
switch (typeDeclaration.getNodeType()) {
case ASTNode.ANNOTATION_TYPE_DECLARATION:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@
import static com.google.j2cl.transpiler.frontend.jdt.KtInteropAnnotationUtils.getSuppressWarningsAnnotation;
import static java.util.Arrays.stream;

import com.google.common.base.Predicate;
import com.google.common.base.VerifyException;
import com.google.j2cl.transpiler.frontend.common.Nullability;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.internal.compiler.impl.BooleanConstant;
import org.eclipse.jdt.internal.compiler.impl.IntConstant;
import org.eclipse.jdt.internal.compiler.impl.StringConstant;
Expand Down Expand Up @@ -130,6 +136,23 @@ private static AnnotationBinding getAnnotationBinding(IAnnotationBinding annotat
}
}

public static IAnnotationBinding getAnnotationBinding(
PackageDeclaration packageDeclaration, Predicate<IAnnotationBinding> whichAnnotation) {
List<Annotation> packageAnnotations =
JdtEnvironment.asTypedList(packageDeclaration.annotations());
if (packageAnnotations == null) {
return null;
}

Optional<IAnnotationBinding> annotationBinding =
packageAnnotations.stream()
.map(Annotation::resolveAnnotationBinding)
.filter(whichAnnotation)
.findFirst();

return annotationBinding.orElse(null);
}

public static boolean isWarningSuppressed(
IAnnotationBinding[] annotationBindings, String warning) {
IAnnotationBinding annotationBinding = getSuppressWarningsAnnotation(annotationBindings);
Expand All @@ -141,5 +164,12 @@ public static boolean isWarningSuppressed(
return stream(suppressions).anyMatch(warning::equals);
}

public static boolean isNullMarked(PackageDeclaration packageDeclaration) {
return getAnnotationBinding(
packageDeclaration,
(a) -> Nullability.isNullMarkedAnnotation(a.getAnnotationType().getQualifiedName()))
!= null;
}

private JdtAnnotationUtils() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
Expand All @@ -70,7 +69,6 @@
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.PostfixExpression;
import org.eclipse.jdt.core.dom.PrefixExpression;

Expand Down Expand Up @@ -1258,18 +1256,6 @@ public TypeDeclaration createDeclarationForType(final ITypeBinding typeBinding)
return typeDeclaration;
}

public static boolean isNullMarked(PackageDeclaration packageDeclaration) {
List<Annotation> packageAnnotations =
JdtEnvironment.asTypedList(packageDeclaration.annotations());

if (packageAnnotations == null) {
return false;
}

return hasNullMarkedAnnotation(
packageAnnotations.stream().map(Annotation::resolveAnnotationBinding));
}

private boolean isNullMarked(ITypeBinding typeBinding, PackageInfoCache packageInfoCache) {
return hasNullMarkedAnnotation(typeBinding)
|| packageInfoCache.isNullMarked(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
import static com.google.j2cl.transpiler.frontend.common.FrontendConstants.JS_PROPERTY_ANNOTATION_NAME;
import static com.google.j2cl.transpiler.frontend.common.FrontendConstants.JS_TYPE_ANNOTATION_NAME;
import static com.google.j2cl.transpiler.frontend.common.FrontendConstants.SUPPRESS_WARNINGS_ANNOTATION_NAME;
import static com.google.j2cl.transpiler.frontend.jdt.JdtAnnotationUtils.getAnnotationBinding;
import static java.util.Arrays.stream;

import java.util.Optional;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.PackageDeclaration;

/** Utility methods to get information about Js Interop annotations. */
public class JsInteropAnnotationUtils {
Expand Down Expand Up @@ -120,6 +122,12 @@ public static boolean isUnusableByJsSuppressed(IBinding binding) {
return stream(suppressions).anyMatch("unusable-by-js"::equals);
}

public static String getJsNamespace(PackageDeclaration packageDeclaration) {
IAnnotationBinding annotationBinding =
getAnnotationBinding(packageDeclaration, JsInteropAnnotationUtils::isJsPackageAnnotation);
return JsInteropAnnotationUtils.getJsNamespace(annotationBinding);
}

/** The namespace specified on a package, type, method or field. */
public static String getJsNamespace(ITypeBinding typeBinding) {
return getJsNamespace(getJsTypeOrJsEnumAnnotation(typeBinding));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
import static com.google.j2cl.transpiler.frontend.common.FrontendConstants.KT_THROWS_ANNOTATION_NAME;
import static com.google.j2cl.transpiler.frontend.common.FrontendConstants.SUPPRESS_WARNINGS_ANNOTATION_NAME;
import static com.google.j2cl.transpiler.frontend.jdt.JdtAnnotationUtils.findAnnotationBindingByName;
import static com.google.j2cl.transpiler.frontend.jdt.JdtAnnotationUtils.getAnnotationBinding;
import static com.google.j2cl.transpiler.frontend.jdt.JdtAnnotationUtils.getStringAttribute;

import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.PackageDeclaration;

/** Utility methods to get information about Kotlin Interop annotations. */
public class KtInteropAnnotationUtils {
Expand Down Expand Up @@ -55,6 +57,11 @@ public static String getKtObjectiveCName(IAnnotationBinding annotationBinding) {
return getStringAttribute(annotationBinding, "value");
}

public static String getKtObjectiveCName(PackageDeclaration packageDeclaration) {
return getKtObjectiveCName(
getAnnotationBinding(packageDeclaration, KtInteropAnnotationUtils::isKtObjectiveCName));
}

public static boolean isKtObjectiveCName(IAnnotationBinding annotationBinding) {
return annotationBinding.getAnnotationType().getQualifiedName().equals(KT_OBJECTIVE_C_NAME);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ kt_jvm_library(
srcs = glob(["*.kt"]),
deps = [
"//third_party:guava",
"//third_party:jdt-core",
"//third_party:kotlin_compiler",
"//transpiler/java/com/google/j2cl/common",
"//transpiler/java/com/google/j2cl/transpiler/ast",
"//transpiler/java/com/google/j2cl/transpiler/frontend/common",
"//transpiler/java/com/google/j2cl/transpiler/frontend/jdt",
],
)

0 comments on commit 3e37f32

Please sign in to comment.