diff --git a/transpiler/java/com/google/j2cl/transpiler/BazelJ2wasmExportsGenerator.java b/transpiler/java/com/google/j2cl/transpiler/BazelJ2wasmExportsGenerator.java index 1a41deb4bc..2ab79a1174 100644 --- a/transpiler/java/com/google/j2cl/transpiler/BazelJ2wasmExportsGenerator.java +++ b/transpiler/java/com/google/j2cl/transpiler/BazelJ2wasmExportsGenerator.java @@ -93,7 +93,7 @@ protected void run(Problems problems) { // not be complete and cannot be fully resolved to descriptors. .filter(not(ITypeBinding::isAnnotation)) .collect(ImmutableList.toImmutableList()); - var environment = new JdtEnvironment(); + var environment = new JdtEnvironment(parser); PackageInfoCache.init(classPathEntries, problems); environment.initWellKnownTypes( diff --git a/transpiler/java/com/google/j2cl/transpiler/frontend/Frontend.java b/transpiler/java/com/google/j2cl/transpiler/frontend/Frontend.java index 7939a9caf2..2c25450abb 100644 --- a/transpiler/java/com/google/j2cl/transpiler/frontend/Frontend.java +++ b/transpiler/java/com/google/j2cl/transpiler/frontend/Frontend.java @@ -41,7 +41,7 @@ public List compile(FrontendOptions options, Problems problems) /* useTargetPath= */ options.getGenerateKytheIndexingMetadata(), options.getForbiddenAnnotations()); problems.abortIfHasErrors(); - return CompilationUnitBuilder.build(compilationUnitsAndTypeBindings); + return CompilationUnitBuilder.build(compilationUnitsAndTypeBindings, parser); } @Override diff --git a/transpiler/java/com/google/j2cl/transpiler/frontend/common/AbstractCompilationUnitBuilder.java b/transpiler/java/com/google/j2cl/transpiler/frontend/common/AbstractCompilationUnitBuilder.java index 30ada80ca8..e7f934bef6 100644 --- a/transpiler/java/com/google/j2cl/transpiler/frontend/common/AbstractCompilationUnitBuilder.java +++ b/transpiler/java/com/google/j2cl/transpiler/frontend/common/AbstractCompilationUnitBuilder.java @@ -31,28 +31,12 @@ /** Base class for implementing that AST conversion from different front ends. */ public abstract class AbstractCompilationUnitBuilder { - private final PackageInfoCache packageInfoCache = PackageInfoCache.get(); - /** Type stack to keep track of the lexically enclosing types as they are being created. */ private final List typeStack = new ArrayList<>(); private String currentSourceFile; private CompilationUnit currentCompilationUnit; - /** - * Sets the JS namespace and whether it defines a null marked scope for a package that is being - * compiled from source. - */ - protected void setPackagePropertiesFromSource( - String packageName, String jsNamespace, String objectiveCName, boolean isNullMarked) { - packageInfoCache.setPackageProperties( - PackageInfoCache.SOURCE_CLASS_PATH_ENTRY, - packageName, - jsNamespace, - objectiveCName, - isNullMarked); - } - protected String getCurrentSourceFile() { return currentSourceFile; } diff --git a/transpiler/java/com/google/j2cl/transpiler/frontend/common/PackageInfoCache.java b/transpiler/java/com/google/j2cl/transpiler/frontend/common/PackageInfoCache.java index 213c15b7c2..c962500b19 100644 --- a/transpiler/java/com/google/j2cl/transpiler/frontend/common/PackageInfoCache.java +++ b/transpiler/java/com/google/j2cl/transpiler/frontend/common/PackageInfoCache.java @@ -94,7 +94,7 @@ public PackageReport build() { * When nothing is known about a particular package in a particular class path entry the answers * to questions about package properties are taken from this instance. */ - private static final PackageReport DEFAULT_PACKAGE_REPORT = PackageReport.newBuilder().build(); + public static final PackageReport DEFAULT_PACKAGE_REPORT = PackageReport.newBuilder().build(); /** Allows for the initialization/retrieval of one shared PackageInfoCache instance per thread. */ private static final ThreadLocal packageInfoCacheStorage = new ThreadLocal<>(); diff --git a/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/CompilationUnitBuilder.java b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/CompilationUnitBuilder.java index 3946fb19f1..e8b95906af 100644 --- a/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/CompilationUnitBuilder.java +++ b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/CompilationUnitBuilder.java @@ -19,16 +19,11 @@ 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.Predicates; -import com.google.common.collect.ComparisonChain; import com.google.common.collect.Iterables; import com.google.j2cl.common.FilePosition; import com.google.j2cl.common.SourcePosition; @@ -99,7 +94,6 @@ import com.google.j2cl.transpiler.ast.WhileStatement; import com.google.j2cl.transpiler.frontend.common.AbstractCompilationUnitBuilder; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -136,7 +130,7 @@ /** Creates a J2CL Java AST from the AST provided by JDT. */ public class CompilationUnitBuilder extends AbstractCompilationUnitBuilder { - private final JdtEnvironment environment = new JdtEnvironment(); + private final JdtEnvironment environment; private class ASTConverter { private org.eclipse.jdt.core.dom.CompilationUnit jdtCompilationUnit; @@ -152,14 +146,7 @@ private CompilationUnit convert( String packageName = 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") && packageDeclaration != null) { - setPackagePropertiesFromSource( - packageName, - getJsNamespace(packageDeclaration), - getKtObjectiveCName(packageDeclaration), - isNullMarked(packageDeclaration)); - } + for (Object object : jdtCompilationUnit.types()) { AbstractTypeDeclaration abstractTypeDeclaration = (AbstractTypeDeclaration) object; getCurrentCompilationUnit().addType(convert(abstractTypeDeclaration)); @@ -1426,43 +1413,29 @@ private CompilationUnit buildCompilationUnit( } public static List build( - CompilationUnitsAndTypeBindings compilationUnitsAndTypeBindings) { + CompilationUnitsAndTypeBindings compilationUnitsAndTypeBindings, JdtParser jdtParser) { + JdtEnvironment environment = + new JdtEnvironment( + PackageAnnotationsResolver.create( + compilationUnitsAndTypeBindings.getCompilationUnitsByFilePath().entrySet().stream() + .filter(e -> e.getKey().endsWith("package-info.java")) + .map(Entry::getValue), + jdtParser)); Map jdtUnitsByFilePath = compilationUnitsAndTypeBindings.getCompilationUnitsByFilePath(); List wellKnownTypeBindings = compilationUnitsAndTypeBindings.getTypeBindings(); CompilationUnitBuilder compilationUnitBuilder = - new CompilationUnitBuilder(wellKnownTypeBindings); - - List> entries = - new ArrayList<>(jdtUnitsByFilePath.entrySet()); - // Ensure that all source package-info classes come before all other classes so that the - // freshness of the PackageInfoCache can be trusted. - sortPackageInfoFirst(entries); + new CompilationUnitBuilder(wellKnownTypeBindings, environment); - return entries.stream() + return jdtUnitsByFilePath.entrySet().stream() .map(entry -> compilationUnitBuilder.buildCompilationUnit(entry.getKey(), entry.getValue())) .collect(toImmutableList()); } - private static void sortPackageInfoFirst( - List> entries) { - // Ensure that all source package-info classes come before all other classes so that the - // freshness of the PackageInfoCache can be trusted. - Collections.sort( - entries, - comparingByKey( - (thisFilePath, thatFilePath) -> { - boolean thisIsPackageInfo = thisFilePath.endsWith("package-info.java"); - boolean thatIsPackageInfo = thatFilePath.endsWith("package-info.java"); - return ComparisonChain.start() - .compareTrueFirst(thisIsPackageInfo, thatIsPackageInfo) - .compare(thisFilePath, thatFilePath) - .result(); - })); - } - - private CompilationUnitBuilder(List wellKnownTypeBindings) { + private CompilationUnitBuilder( + List wellKnownTypeBindings, JdtEnvironment environment) { + this.environment = environment; environment.initWellKnownTypes(wellKnownTypeBindings); } } diff --git a/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JdtEnvironment.java b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JdtEnvironment.java index e44d6506bf..c0fda35a73 100644 --- a/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JdtEnvironment.java +++ b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JdtEnvironment.java @@ -49,13 +49,11 @@ import com.google.j2cl.transpiler.ast.Variable; import com.google.j2cl.transpiler.ast.Visibility; import com.google.j2cl.transpiler.frontend.common.Nullability; -import com.google.j2cl.transpiler.frontend.common.PackageInfoCache; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; import javax.annotation.Nullable; @@ -88,6 +86,16 @@ public class JdtEnvironment { private final Map cachedFieldDescriptorByVariableBinding = new HashMap<>(); + private final PackageAnnotationsResolver packageAnnotationsResolver; + + public JdtEnvironment(JdtParser jdtParser) { + this.packageAnnotationsResolver = PackageAnnotationsResolver.create(Stream.of(), jdtParser); + } + + public JdtEnvironment(PackageAnnotationsResolver packageAnnotationsResolver) { + this.packageAnnotationsResolver = packageAnnotationsResolver; + } + @Nullable public static BinaryOperator getBinaryOperator(InfixExpression.Operator operator) { switch (operator.toString()) { @@ -491,16 +499,6 @@ private static NullabilityAnnotation getNullabilityAnnotation( return NullabilityAnnotation.NO_ANNOTATION; } - /** - * In case the given type binding is nested, return the outermost possible enclosing type binding. - */ - private static ITypeBinding toTopLevelTypeBinding(ITypeBinding typeBinding) { - ITypeBinding topLevelClass = typeBinding; - while (topLevelClass.getDeclaringClass() != null) { - topLevelClass = topLevelClass.getDeclaringClass(); - } - return topLevelClass; - } private static boolean isIntersectionType(ITypeBinding binding) { return binding.isIntersectionType() @@ -1114,27 +1112,25 @@ private static String getJsName(final ITypeBinding typeBinding) { } @Nullable - private String getObjectiveCNamePrefix( - ITypeBinding typeBinding, PackageInfoCache packageInfoCache) { - return getPropertyIfTopLevel(typeBinding, packageInfoCache::getObjectiveCName); + private String getObjectiveCNamePrefix(ITypeBinding typeBinding) { + checkArgument(!typeBinding.isPrimitive()); + String objectiveCNamePrefix = KtInteropAnnotationUtils.getKtObjectiveCName(typeBinding); + boolean isTopLevelType = typeBinding.getDeclaringClass() == null; + + return objectiveCNamePrefix != null || !isTopLevelType + ? objectiveCNamePrefix + : packageAnnotationsResolver.getObjectiveCNamePrefix(typeBinding.getPackage().getName()); } @Nullable - private String getJsNamespace(ITypeBinding typeBinding, PackageInfoCache packageInfoCache) { + private String getJsNamespace(ITypeBinding typeBinding) { checkArgument(!typeBinding.isPrimitive()); String jsNamespace = JsInteropAnnotationUtils.getJsNamespace(typeBinding); - return jsNamespace != null - ? jsNamespace - : getPropertyIfTopLevel(typeBinding, packageInfoCache::getJsNamespace); - } - - @Nullable - private String getPropertyIfTopLevel( - ITypeBinding typeBinding, Function propertyForBinaryName) { boolean isTopLevelType = typeBinding.getDeclaringClass() == null; - return isTopLevelType - ? propertyForBinaryName.apply(getBinaryNameFromTypeBinding(typeBinding)) - : null; + + return jsNamespace != null || !isTopLevelType + ? jsNamespace + : packageAnnotationsResolver.getJsNameSpace(typeBinding.getPackage().getName()); } @Nullable @@ -1155,17 +1151,6 @@ public TypeDeclaration createDeclarationForType(final ITypeBinding typeBinding) checkArgument(!typeBinding.isWildcardType()); checkArgument(!typeBinding.isCapture()); - PackageInfoCache packageInfoCache = PackageInfoCache.get(); - - ITypeBinding topLevelTypeBinding = toTopLevelTypeBinding(typeBinding); - if (topLevelTypeBinding.isFromSource()) { - // Let the PackageInfoCache know that this class is Source, otherwise it would have to rummage - // around in the class path to figure it out and it might even come up with the wrong answer - // for example if this class has also been globbed into some other library that is a - // dependency of this one. - PackageInfoCache.get().markAsSource(getBinaryNameFromTypeBinding(topLevelTypeBinding)); - } - // Compute these first since they're reused in other calculations. String packageName = typeBinding.getPackage() == null ? null : typeBinding.getPackage().getName(); @@ -1185,7 +1170,7 @@ public TypeDeclaration createDeclarationForType(final ITypeBinding typeBinding) .map(this::createFieldDescriptor) .collect(toImmutableList()); - boolean isNullMarked = isNullMarked(typeBinding, packageInfoCache); + boolean isNullMarked = isNullMarked(typeBinding); IBinding declaringMemberBinding = getDeclaringMethodOrFieldBinding(typeBinding); typeDeclaration = @@ -1225,8 +1210,8 @@ public TypeDeclaration createDeclarationForType(final ITypeBinding typeBinding) .setAnonymous(typeBinding.isAnonymous()) .setLocal(isLocal(typeBinding)) .setSimpleJsName(getJsName(typeBinding)) - .setCustomizedJsNamespace(getJsNamespace(typeBinding, packageInfoCache)) - .setObjectiveCNamePrefix(getObjectiveCNamePrefix(typeBinding, packageInfoCache)) + .setCustomizedJsNamespace(getJsNamespace(typeBinding)) + .setObjectiveCNamePrefix(getObjectiveCNamePrefix(typeBinding)) .setKtTypeInfo(KtInteropUtils.getKtTypeInfo(typeBinding)) .setKtObjcInfo(KtInteropUtils.getKtObjcInfo(typeBinding)) .setNullMarked(isNullMarked) @@ -1249,10 +1234,9 @@ public TypeDeclaration createDeclarationForType(final ITypeBinding typeBinding) return typeDeclaration; } - private boolean isNullMarked(ITypeBinding typeBinding, PackageInfoCache packageInfoCache) { + private boolean isNullMarked(ITypeBinding typeBinding) { return hasNullMarkedAnnotation(typeBinding) - || packageInfoCache.isNullMarked( - getBinaryNameFromTypeBinding(toTopLevelTypeBinding(typeBinding))); + || packageAnnotationsResolver.isNullMarked(typeBinding.getPackage().getName()); } /** diff --git a/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JdtParser.java b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JdtParser.java index d80f5b2fa2..b74948d485 100644 --- a/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JdtParser.java +++ b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JdtParser.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import javax.annotation.Nullable; import org.eclipse.jdt.core.BindingKey; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.IProblem; @@ -132,6 +133,15 @@ public List resolveBindings(Collection binaryNames) { .getTypeBindings(); } + @Nullable + public ITypeBinding resolveBinding(String qualifiedBinaryName) { + List bindings = resolveBindings(ImmutableList.of(qualifiedBinaryName)); + if (bindings.isEmpty()) { + return null; + } + return Iterables.getOnlyElement(bindings); + } + private ASTParser newASTParser() { ASTParser parser = ASTParser.newParser(AST_JLS_VERSION); diff --git a/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JsInteropAnnotationUtils.java b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JsInteropAnnotationUtils.java index 4776c660fb..67f9749db7 100644 --- a/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JsInteropAnnotationUtils.java +++ b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/JsInteropAnnotationUtils.java @@ -99,6 +99,11 @@ public static IAnnotationBinding getJsOverlayAnnotation(IBinding methodBinding) methodBinding.getAnnotations(), JS_OVERLAY_ANNOTATION_NAME); } + public static IAnnotationBinding getJsPackageAnnotation(ITypeBinding packageBinding) { + return JdtAnnotationUtils.findAnnotationBindingByName( + packageBinding.getAnnotations(), JS_PACKAGE_ANNOTATION_NAME); + } + public static boolean isJsPackageAnnotation(IAnnotationBinding annotation) { return annotation.getAnnotationType().getQualifiedName().equals(JS_PACKAGE_ANNOTATION_NAME); } diff --git a/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/KtInteropAnnotationUtils.java b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/KtInteropAnnotationUtils.java index 0af8abcbc0..f96e05c5f1 100644 --- a/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/KtInteropAnnotationUtils.java +++ b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/KtInteropAnnotationUtils.java @@ -29,6 +29,7 @@ import static com.google.j2cl.transpiler.frontend.jdt.JdtAnnotationUtils.getStringAttribute; import org.eclipse.jdt.core.dom.IAnnotationBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.PackageDeclaration; /** Utility methods to get information about Kotlin Interop annotations. */ @@ -53,6 +54,11 @@ public static IAnnotationBinding getKtDisabledAnnotation( return findAnnotationBindingByName(annotationBindings, KT_DISABLED_ANNOTATION_NAME); } + /** The namespace specified on a package, type, method or field. */ + public static String getKtObjectiveCName(ITypeBinding typeBinding) { + return getKtObjectiveCName(getKtObjectiveCNameAnnotation(typeBinding.getAnnotations())); + } + public static String getKtObjectiveCName(IAnnotationBinding annotationBinding) { return getStringAttribute(annotationBinding, "value"); } diff --git a/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/PackageAnnotationsResolver.java b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/PackageAnnotationsResolver.java new file mode 100644 index 0000000000..68d3c86907 --- /dev/null +++ b/transpiler/java/com/google/j2cl/transpiler/frontend/jdt/PackageAnnotationsResolver.java @@ -0,0 +1,141 @@ +/* + * Copyright 2023 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.j2cl.transpiler.frontend.jdt; + +import static com.google.common.base.Preconditions.checkState; +import static com.google.j2cl.transpiler.frontend.common.PackageInfoCache.DEFAULT_PACKAGE_REPORT; +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 com.google.common.collect.ImmutableList; +import com.google.j2cl.common.SourceUtils.FileInfo; +import com.google.j2cl.transpiler.frontend.common.Nullability; +import com.google.j2cl.transpiler.frontend.common.PackageInfoCache.PackageReport; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ITypeBinding; + +/** A utility class to resolve and cache package annotations. */ +public final class PackageAnnotationsResolver { + + private final Map packageReportByPackageName = new HashMap<>(); + private final JdtParser parser; + + /** Create a PackageAnnotationResolver with the source package-info CompilationUnits. */ + public static PackageAnnotationsResolver create( + Stream packageInfoCompilationUnits, JdtParser parser) { + var packageAnnotationResolver = new PackageAnnotationsResolver(parser); + packageAnnotationResolver.populateFromCompilationUnits(packageInfoCompilationUnits); + return packageAnnotationResolver; + } + + /** Create a PackageAnnotationResolver with package infos in sources. */ + public static PackageAnnotationsResolver create(List sources, JdtParser parser) { + return create(parsePackageInfoFiles(sources, parser), parser); + } + + public String getJsNameSpace(String packageName) { + return getPackageReport(packageName).getJsNamespace(); + } + + public String getObjectiveCNamePrefix(String packageName) { + return getPackageReport(packageName).getObjectiveCName(); + } + + public boolean isNullMarked(String packageName) { + return getPackageReport(packageName).isNullMarked(); + } + + /** Parser package-info files from sources. */ + private static Stream parsePackageInfoFiles( + List sources, JdtParser parser) { + + if (sources.isEmpty()) { + return Stream.of(); + } + + var parsingResult = parser.parseFiles(sources, false, ImmutableList.of()); + return parsingResult.getCompilationUnitsByFilePath().values().stream(); + } + + /** Populates the cache for the annotations in package-info compilation units. */ + private void populateFromCompilationUnits(Stream packageInfoCompilationUnits) { + packageInfoCompilationUnits.forEach( + cu -> { + var packageDeclaration = cu.getPackage(); + + // Sanity check, package-info.java files declare no types. + checkState(cu.types().isEmpty()); + + // Records information about package-info files supplied as source code. + if (packageDeclaration != null) { + setPackageProperties( + packageDeclaration.getName().getFullyQualifiedName(), + getJsNamespace(packageDeclaration), + getKtObjectiveCName(packageDeclaration), + JdtAnnotationUtils.isNullMarked(packageDeclaration)); + } + }); + } + + public void setPackageProperties( + String packageName, String jsNamespace, String objectiveCName, boolean isNullMarked) { + packageReportByPackageName.put( + packageName, + PackageReport.newBuilder() + .setJsNamespace(jsNamespace) + .setObjectiveCName(objectiveCName) + .setNullMarked(isNullMarked) + .build()); + } + + private PackageReport getPackageReport(String packageName) { + return packageReportByPackageName.computeIfAbsent(packageName, this::createPackageReport); + } + + private PackageReport createPackageReport(String packageName) { + ITypeBinding packageInfoBinding = parser.resolveBinding(packageName + ".package-info"); + if (packageInfoBinding == null) { + return DEFAULT_PACKAGE_REPORT; + } + + boolean isNullMarked = + stream(packageInfoBinding.getAnnotations()) + .anyMatch( + a -> Nullability.isNullMarkedAnnotation(a.getAnnotationType().getQualifiedName())); + + String objectiveCName = + getKtObjectiveCName( + KtInteropAnnotationUtils.getKtObjectiveCNameAnnotation( + packageInfoBinding.getAnnotations())); + + String jsNamespace = + getJsNamespace(JsInteropAnnotationUtils.getJsPackageAnnotation(packageInfoBinding)); + return PackageReport.newBuilder() + .setJsNamespace(jsNamespace) + .setObjectiveCName(objectiveCName) + .setNullMarked(isNullMarked) + .build(); + } + + private PackageAnnotationsResolver(JdtParser parser) { + this.parser = parser; + } +}