Skip to content

Do not expose Kotlin features with internal access #1549

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 1 commit into from
Dec 4, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion test-app/app/src/main/assets/app/mainpage.js
Original file line number Diff line number Diff line change
@@ -60,4 +60,5 @@ require("./tests/kotlin/properties/testPropertiesSupport");
require("./tests/kotlin/delegation/testDelegationSupport");
require("./tests/kotlin/objects/testObjectsSupport");
require("./tests/kotlin/functions/testTopLevelFunctionsSupport");
require("./tests/kotlin/extensions/testExtensionFunctionsSupport")
require("./tests/kotlin/extensions/testExtensionFunctionsSupport");
require("./tests/kotlin/access/testInternalLanguageFeaturesSupport");
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
describe("Tests Kotlin internal language features should not be visible at runtime", function () {
it("Test Kotlin internal functions in a kt file should not be exposed", function () {
expect(com.tns.tests.kotlin.access.KotlinFileWithInternalFunctionsKt.someInternalFunction).toBe(undefined)
});

it("Test Kotlin internal properties in a kt file should not be exposed", function () {
expect(com.tns.tests.kotlin.access.KotlinFileWithInternalPropertiesKt.someInternalProperty).toBe(undefined)
});

it("Test Kotlin internal class should not be exposed", function () {
expect(com.tns.tests.kotlin.access.KotlinInternalClass).toBe(undefined)
});

it("Test Kotlin internal companion in a class should not be exposed", function () {
expect(com.tns.tests.kotlin.access.KotlinPublicClassWithInternalCompanion.Companion).toBe(undefined)
});

it("Test Kotlin internal methods in a class should not be exposed", function () {
var ktClass = new com.tns.tests.kotlin.access.KotlinPublicClassWithInternalMethods()
expect(ktClass.someInternalMethod).toBe(undefined)
});

it("Test Kotlin internal named companion in a class should not be exposed", function () {
expect(com.tns.tests.kotlin.access.KotlinPublicClassWithInternalCompanion.SomeInternalCompanion).toBe(undefined)
});

it("Test Kotlin internal nested class should not be exposed", function () {
expect(com.tns.tests.kotlin.access.KotlinPublicClassWithInternalNestedClass.SomeNestedClass).toBe(undefined)
});

it("Test Kotlin internal properties in a class should not be exposed", function () {
var ktClass = new com.tns.tests.kotlin.access.KotlinPublicClassWithInternalProperties()
expect(ktClass.someInternalProperty).toBe(undefined)
});

it("Test Kotlin internal object should not be exposed", function () {
expect(com.tns.tests.kotlin.access.KotlinInternalObject).toBe(undefined)
});

it("Test Kotlin internal interface should not be exposed", function () {
expect(com.tns.tests.kotlin.access.KotlinInternalInterface).toBe(undefined)
});

it("Test Kotlin internal enum should not be exposed", function () {
expect(com.tns.tests.kotlin.access.KotlinInternalEnum).toBe(undefined)
});

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.tns.tests.kotlin.access

internal fun someInternalFunction(){

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.tns.tests.kotlin.access

internal val someInternalProperty = 42
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.tns.tests.kotlin.access

internal class KotlinInternalClass
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.tns.tests.kotlin.access

internal enum class KotlinInternalEnum {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.tns.tests.kotlin.access

internal interface KotlinInternalInterface {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.tns.tests.kotlin.access

internal object KotlinInternalObject {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.tns.tests.kotlin.access

class KotlinPublicClassWithInternalCompanion {
internal companion object {
fun someInternalCompanionMethod(){

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.tns.tests.kotlin.access

class KotlinPublicClassWithInternalMethods {
internal fun someInternalMethod(){

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.tns.tests.kotlin.access

class KotlinPublicClassWithInternalNamedCompanion {
internal companion object SomeInternalCompanion {
fun someInternalCompanionMethod() {

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.tns.tests.kotlin.access

class KotlinPublicClassWithInternalNestedClass {
internal class SomeNestedClass
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.tns.tests.kotlin.access

class KotlinPublicClassWithInternalProperties {
internal var someInternalProperty = "pesho"
}
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ compileJava.outputs.dir("$rootDir/dist/classes")

compileKotlin {
kotlinOptions.allWarningsAsErrors = true
kotlinOptions.jvmTarget = "1.8"
}

repositories {
Original file line number Diff line number Diff line change
@@ -3,24 +3,24 @@
import com.telerik.metadata.TreeNode.FieldInfo;
import com.telerik.metadata.TreeNode.MethodInfo;
import com.telerik.metadata.parsing.ClassParser;
import com.telerik.metadata.parsing.classes.MetadataInfoAnnotationDescriptor;
import com.telerik.metadata.parsing.classes.NativeClassDescriptor;
import com.telerik.metadata.parsing.classes.NativeFieldDescriptor;
import com.telerik.metadata.parsing.classes.NativeMethodDescriptor;
import com.telerik.metadata.parsing.classes.NativeTypeDescriptor;
import com.telerik.metadata.parsing.classes.bytecode.JarFile;
import com.telerik.metadata.parsing.classes.kotlin.extensions.ClassNameAndFunctionPair;
import com.telerik.metadata.parsing.classes.kotlin.extensions.ExtensionFunctionsCollector;
import com.telerik.metadata.parsing.classes.kotlin.extensions.KotlinExtensionFunctionDescriptor;
import com.telerik.metadata.parsing.classes.kotlin.extensions.bytecode.BytecodeExtensionFunctionsCollector;
import com.telerik.metadata.parsing.classes.kotlin.metadata.ClassMetadataParser;
import com.telerik.metadata.parsing.classes.kotlin.metadata.bytecode.BytecodeClassMetadataParser;
import com.telerik.metadata.parsing.classes.kotlin.properties.KotlinPropertyDescriptor;
import com.telerik.metadata.parsing.MetadataInfoAnnotationDescriptor;
import com.telerik.metadata.parsing.NativeClassDescriptor;
import com.telerik.metadata.parsing.NativeFieldDescriptor;
import com.telerik.metadata.parsing.NativeMethodDescriptor;
import com.telerik.metadata.parsing.NativePropertyDescriptor;
import com.telerik.metadata.parsing.NativeTypeDescriptor;
import com.telerik.metadata.parsing.bytecode.JarFile;
import com.telerik.metadata.parsing.kotlin.classes.KotlinClassDescriptor;
import com.telerik.metadata.parsing.kotlin.extensions.ClassNameAndFunctionPair;
import com.telerik.metadata.parsing.kotlin.extensions.ExtensionFunctionsCollector;
import com.telerik.metadata.parsing.kotlin.extensions.KotlinExtensionFunctionDescriptor;
import com.telerik.metadata.parsing.kotlin.extensions.bytecode.BytecodeExtensionFunctionsCollector;
import com.telerik.metadata.parsing.kotlin.metadata.ClassMetadataParser;
import com.telerik.metadata.parsing.kotlin.metadata.bytecode.BytecodeClassMetadataParser;
import com.telerik.metadata.storage.functions.FunctionsStorage;
import com.telerik.metadata.storage.functions.extensions.ExtensionFunctionsStorage;

import java.io.File;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -90,9 +90,6 @@ static TreeNode build(List<String> paths) throws Exception {
if (clazz == null) {
throw new ClassNotFoundException("Class " + className + " not found in the input android libraries.");
} else {
if (clazz.getClassName().contains("SomePublicClass")) {
System.out.println("asd");
}
generate(clazz, root);
}
} catch (Throwable e) {
@@ -107,13 +104,16 @@ static TreeNode build(List<String> paths) throws Exception {
}

private static void tryCollectKotlinExtensionFunctions(NativeClassDescriptor classDescriptor) {
ExtensionFunctionsCollector extensionFunctionsCollector = new BytecodeExtensionFunctionsCollector(new BytecodeClassMetadataParser());
Collection<ClassNameAndFunctionPair<KotlinExtensionFunctionDescriptor>> extensionFunctions = extensionFunctionsCollector.collectExtensionFunctions(classDescriptor);
if (classDescriptor instanceof KotlinClassDescriptor) {
ExtensionFunctionsCollector extensionFunctionsCollector = new BytecodeExtensionFunctionsCollector(new BytecodeClassMetadataParser());
Collection<ClassNameAndFunctionPair<KotlinExtensionFunctionDescriptor>> extensionFunctions = extensionFunctionsCollector.collectExtensionFunctions((KotlinClassDescriptor) classDescriptor);

if (!extensionFunctions.isEmpty()) {
FunctionsStorage<KotlinExtensionFunctionDescriptor> extensionFunctionsStorage = ExtensionFunctionsStorage.getInstance();
extensionFunctionsStorage.storeFunctions(extensionFunctions);
if (!extensionFunctions.isEmpty()) {
FunctionsStorage<KotlinExtensionFunctionDescriptor> extensionFunctionsStorage = ExtensionFunctionsStorage.getInstance();
extensionFunctionsStorage.storeFunctions(extensionFunctions);
}
}

}

private static Boolean isClassPublic(NativeClassDescriptor clazz) {
@@ -167,11 +167,11 @@ private static void setNodeMembers(NativeClassDescriptor clazz, TreeNode node, T
}
NativeMethodDescriptor[] extensionFunctions = ExtensionFunctionsStorage.getInstance().retrieveFunctions(clazz.getClassName()).toArray(new NativeMethodDescriptor[0]);
NativeMethodDescriptor[] nonExtensionFunctionMethods = ClassUtil.getAllMethods(clazz);
NativeMethodDescriptor[] allMethods = concatenate(extensionFunctions, nonExtensionFunctionMethods);
NativeMethodDescriptor[] allMethods = concatenateNativeMethodArrays(extensionFunctions, nonExtensionFunctionMethods);

NativeMethodDescriptor[] classImplementedMethods = clazz.getMethods();
NativeMethodDescriptor[] interfaceImplementedMethods = clazz.isClass() ? getDefaultMethodsFromImplementedInterfaces(clazz, classImplementedMethods) : new NativeMethodDescriptor[0];
NativeMethodDescriptor[] methods = concatenate(classImplementedMethods, interfaceImplementedMethods, extensionFunctions);
NativeMethodDescriptor[] methods = concatenateNativeMethodArrays(classImplementedMethods, interfaceImplementedMethods, extensionFunctions);
Arrays.sort(methods, methodNameComparator);

setMethodsInfo(root, node, clazz, methods, allMethods, existingMethods, hasClassMetadataInfo);
@@ -252,8 +252,8 @@ private static void setMethodsInfo(TreeNode root, TreeNode node, NativeClassDesc

}

private static void setPropertiesInfo(TreeNode root, TreeNode node, KotlinPropertyDescriptor[] propertyDescriptors) throws Exception {
for (KotlinPropertyDescriptor propertyDescriptor : propertyDescriptors) {
private static void setPropertiesInfo(TreeNode root, TreeNode node, NativePropertyDescriptor[] propertyDescriptors) throws Exception {
for (NativePropertyDescriptor propertyDescriptor : propertyDescriptors) {
String propertyName = propertyDescriptor.getName();

NativeMethodDescriptor getterMethod = propertyDescriptor.getGetterMethod();
@@ -544,26 +544,24 @@ private static ArrayList<TreeNode> getMethodSignature(TreeNode root,
return sig;
}

private static <T> T[] concatenate(T[] a, T[] b) {
private static NativeMethodDescriptor[] concatenateNativeMethodArrays(NativeMethodDescriptor[] a, NativeMethodDescriptor[] b) {
int aLen = a.length;
int bLen = b.length;

@SuppressWarnings("unchecked")
T[] d = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + bLen);
NativeMethodDescriptor[] d = new NativeMethodDescriptor[aLen + bLen];
System.arraycopy(a, 0, d, 0, aLen);
System.arraycopy(b, 0, d, aLen, bLen);

return d;
}

private static <T> T[] concatenate(T[] a, T[] b, T[] c) {
private static NativeMethodDescriptor[] concatenateNativeMethodArrays(NativeMethodDescriptor[] a, NativeMethodDescriptor[] b, NativeMethodDescriptor[] c) {
int aLen = a.length;
int bLen = b.length;
int cLen = c.length;
int abLen = aLen + bLen;

@SuppressWarnings("unchecked")
T[] d = (T[]) Array.newInstance(a.getClass().getComponentType(), abLen + cLen);
NativeMethodDescriptor[] d = new NativeMethodDescriptor[abLen + cLen];
System.arraycopy(a, 0, d, 0, aLen);
System.arraycopy(b, 0, d, aLen, bLen);
System.arraycopy(c, 0, d, abLen, cLen);
Original file line number Diff line number Diff line change
@@ -2,12 +2,17 @@

import com.telerik.metadata.analytics.AnalyticsCollector;
import com.telerik.metadata.analytics.AnalyticsCollectorProvider;
import com.telerik.metadata.parsing.classes.bytecode.NativeClassBytecodeDescriptor;
import com.telerik.metadata.parsing.classes.NativeClassDescriptor;
import com.telerik.metadata.parsing.classes.kotlin.metadata.ClassMetadataParser;
import com.telerik.metadata.parsing.classes.kotlin.metadata.bytecode.BytecodeClassMetadataParser;
import com.telerik.metadata.parsing.NativeClassDescriptor;
import com.telerik.metadata.parsing.java.classes.JavaClassDescriptor;
import com.telerik.metadata.parsing.kotlin.classes.KotlinClassDescriptor;
import com.telerik.metadata.parsing.kotlin.metadata.ClassMetadataParser;
import com.telerik.metadata.parsing.kotlin.metadata.MetadataAnnotation;
import com.telerik.metadata.parsing.kotlin.metadata.bytecode.BytecodeClassMetadataParser;
import com.telerik.metadata.parsing.kotlin.metadata.bytecode.BytecodeMetadataAnnotation;

import org.apache.bcel.classfile.AnnotationEntry;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;

import java.io.File;
import java.io.IOException;
@@ -67,18 +72,28 @@ private static NativeClassDescriptor getClassDescriptor(String name, File file)
NativeClassDescriptor clazz = null;
if (name.endsWith(CLASS_EXT)) {
ClassParser cp = new ClassParser(file.getAbsolutePath());
clazz = new NativeClassBytecodeDescriptor(cp.parse());
markIfKotlinClass(clazz);
} else if (name.endsWith(DEX_EXT)) {
// TODO:
}
JavaClass javaClass = cp.parse();
boolean isKotlinClass = false;

return clazz;
}
AnnotationEntry[] annotationEntries = javaClass.getAnnotationEntries();
if (annotationEntries != null) {
for (AnnotationEntry annotationEntry : annotationEntries) {
String annotationType = annotationEntry.getAnnotationType();
if ("Lkotlin/Metadata;".equals(annotationType)) {
MetadataAnnotation kotlinClassMetadataAnnotation = new BytecodeMetadataAnnotation(annotationEntry);
NativeClassDescriptor kotlinClassDescriptor = new KotlinClassDescriptor(javaClass, kotlinClassMetadataAnnotation);
isKotlinClass = true;
analyticsCollector.markHasKotlinRuntimeClassesIfNotMarkedAlready();
return kotlinClassDescriptor;
}
}
}

private static void markIfKotlinClass(NativeClassDescriptor classDescriptor) {
if (kotlinClassMetadataParser.wasKotlinClass(classDescriptor)) {
analyticsCollector.markHasKotlinRuntimeClassesIfNotMarkedAlready();
if (!isKotlinClass) {
return new JavaClassDescriptor(javaClass);
}
}

return clazz;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.telerik.metadata;

import com.telerik.metadata.parsing.classes.NativeClassDescriptor;
import com.telerik.metadata.parsing.NativeClassDescriptor;

import java.util.Map;

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.telerik.metadata;

import com.telerik.metadata.parsing.classes.NativeClassDescriptor;
import com.telerik.metadata.parsing.NativeClassDescriptor;

import java.util.ArrayList;
import java.util.Arrays;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.telerik.metadata;

import com.telerik.metadata.parsing.classes.NativeClassDescriptor;
import com.telerik.metadata.parsing.classes.NativeMethodDescriptor;
import com.telerik.metadata.parsing.classes.NativeTypeDescriptor;
import com.telerik.metadata.parsing.NativeClassDescriptor;
import com.telerik.metadata.parsing.NativeMethodDescriptor;
import com.telerik.metadata.parsing.NativeTypeDescriptor;

import java.util.ArrayList;

Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.telerik.metadata;

import com.telerik.metadata.parsing.classes.NativeClassDescriptor;
import com.telerik.metadata.parsing.classes.kotlin.extensions.KotlinExtensionFunctionDescriptor;
import com.telerik.metadata.parsing.classes.NativeMethodDescriptor;
import com.telerik.metadata.parsing.classes.NativeTypeDescriptor;
import com.telerik.metadata.parsing.NativeClassDescriptor;
import com.telerik.metadata.parsing.kotlin.extensions.KotlinExtensionFunctionDescriptor;
import com.telerik.metadata.parsing.NativeMethodDescriptor;
import com.telerik.metadata.parsing.NativeTypeDescriptor;

import java.util.ArrayList;
import java.util.List;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.telerik.metadata.parsing

interface AccessModifiable {
val isPublic: Boolean

val isInternal: Boolean

val isProtected: Boolean
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.telerik.metadata.parsing;

import com.telerik.metadata.ClassRepo;
import com.telerik.metadata.parsing.classes.NativeClassDescriptor;
import com.telerik.metadata.parsing.classes.NativeMethodDescriptor;

import java.util.HashSet;
import java.util.Set;
Loading