Skip to content

Commit

Permalink
Add ReflectionSupport level to PackageData
Browse files Browse the repository at this point in the history
	Change on 2017/01/03 by zgao <zgao@google.com>

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=143445068
  • Loading branch information
zhouyanggao authored and tomball committed Jan 6, 2017
1 parent 5c73f89 commit 42e63a7
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 0 deletions.
Expand Up @@ -15,9 +15,12 @@
package com.google.devtools.j2objc.util;

import com.google.devtools.j2objc.file.InputFile;
import com.google.j2objc.annotations.ReflectionSupport;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
Expand All @@ -31,6 +34,9 @@ public class PackageInfoLookup {
private final Map<String, PackageData> map = new HashMap<>();
private final FileUtil fileUtil;

private static final String REFLECTION_SUPPORT_REGEX =
"@(?:com\\.google\\.j2objc\\.annotations\\.)?ReflectionSupport\\s*"
+ "\\([^\\)]*(FULL|NATIVE_ONLY)\\s*\\)";
// Avoid allocating a new PackageData instance for packages with no attributes.
private static final PackageData EMPTY_DATA = new PackageData(new PackageDataBuilder());

Expand All @@ -42,10 +48,12 @@ private static class PackageData {

private final String objectiveCName;
private final boolean parametersAreNonnullByDefault;
private final ReflectionSupport.Level reflectionSupportLevel;

private PackageData(PackageDataBuilder builder) {
this.objectiveCName = builder.objectiveCName;
this.parametersAreNonnullByDefault = builder.parametersAreNonnullByDefault;
this.reflectionSupportLevel = builder.reflectionSupportLevel;
}
}

Expand All @@ -54,6 +62,7 @@ private static class PackageDataBuilder {
private boolean isEmpty = true;
private String objectiveCName = null;
private boolean parametersAreNonnullByDefault = false;
private ReflectionSupport.Level reflectionSupportLevel;

private void setObjectiveCName(String objectiveCName) {
this.objectiveCName = objectiveCName;
Expand All @@ -65,6 +74,11 @@ private void setParametersAreNonnullByDefault() {
isEmpty = false;
}

private void setReflectionSupportLevel(ReflectionSupport.Level level) {
this.reflectionSupportLevel = level;
isEmpty = false;
}

private PackageData build() {
return isEmpty ? EMPTY_DATA : new PackageData(this);
}
Expand All @@ -78,6 +92,10 @@ public boolean hasParametersAreNonnullByDefault(String packageName) {
return getPackageData(packageName).parametersAreNonnullByDefault;
}

public ReflectionSupport.Level getReflectionSupportLevel(String packageName) {
return getPackageData(packageName).reflectionSupportLevel;
}

private PackageData getPackageData(String packageName) {
PackageData result = map.get(packageName);
if (result == null) {
Expand Down Expand Up @@ -106,6 +124,34 @@ private PackageData findPackageData(String packageName) {
return EMPTY_DATA;
}

/**
* Return true if pkgInfo has the specified annotation.
*
* @param pkgInfo package-info source code
* @param annotation fully qualified name of the annotation
*/
private static boolean hasAnnotation(String pkgInfo, String annotation) {
if (!annotation.contains(".")) {
ErrorUtil.warning(annotation + " is not a fully qualified name");
}
if (pkgInfo.contains("@" + annotation)) {
return true;
}
int idx = annotation.lastIndexOf(".");
String annotationPackageName = annotation.substring(0, idx);
String annotationSimpleName = annotation.substring(idx + 1);
if (pkgInfo.contains("@" + annotationSimpleName)) {
String importRegex =
"import\\s*" + annotationPackageName + "(\\.\\*|\\." + annotationSimpleName + ")";
Pattern p = Pattern.compile(importRegex);
Matcher m = p.matcher(pkgInfo);
if (m.find()) {
return true;
}
}
return false;
}

private PackageData parseDataFromSourceFile(InputFile file) throws IOException {
PackageDataBuilder builder = new PackageDataBuilder();
String pkgInfo = fileUtil.readFile(file);
Expand All @@ -131,9 +177,22 @@ private PackageData parseDataFromSourceFile(InputFile file) throws IOException {
|| pkgInfo.contains("@javax.annotation.ParametersAreNonnullByDefault")) {
builder.setParametersAreNonnullByDefault();
}

// @ReflectionSupportLevel
if (hasAnnotation(pkgInfo, "com.google.j2objc.annotations.ReflectionSupport")) {
Pattern p = Pattern.compile(REFLECTION_SUPPORT_REGEX);
Matcher m = p.matcher(pkgInfo);
if (m.find()) {
String level = m.group(1);
builder.setReflectionSupportLevel(ReflectionSupport.Level.valueOf(level));
} else {
ErrorUtil.warning("Invalid ReflectionSupport Level in " + file.getUnitName());
}
}
return builder.build();
}

// TODO(user): Support parsing ReflectionSupport annotation from .class files
private PackageData parseDataFromClassFile(InputFile file) throws IOException {
PackageDataBuilder builder = new PackageDataBuilder();
ClassReader classReader = new ClassReader(file.getInputStream());
Expand Down
Expand Up @@ -79,6 +79,7 @@
import com.google.devtools.j2objc.util.ErrorUtilTest;
import com.google.devtools.j2objc.util.FileUtilTest;
import com.google.devtools.j2objc.util.NameTableTest;
import com.google.devtools.j2objc.util.PackageInfoLookupTest;
import com.google.devtools.j2objc.util.PackagePrefixesTest;
import com.google.devtools.j2objc.util.ProGuardUsageParserTest;
import com.google.devtools.j2objc.util.TranslationUtilTest;
Expand Down Expand Up @@ -140,6 +141,7 @@ public class SmallTests {
OptionsTest.class,
OuterReferenceFixerTest.class,
OuterReferenceResolverTest.class,
PackageInfoLookupTest.class,
PackageInfoRewriterTest.class,
PackagePrefixesTest.class,
PrimitiveArrayTest.class,
Expand Down
@@ -0,0 +1,50 @@
/*
* 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.devtools.j2objc.util;

import com.google.devtools.j2objc.GenerationTest;
import com.google.devtools.j2objc.ast.CompilationUnit;
import com.google.j2objc.annotations.ReflectionSupport;
import java.io.IOException;

/**
* Unit tests for the {@link PackageInfoLookup}.
*
* @author Tim Gao
*/
public class PackageInfoLookupTest extends GenerationTest {

public void testReflectionSupportAnnotation() throws IOException {
addSourceFile("@ReflectionSupport(value = ReflectionSupport.Level.FULL) package foo;"
+ "import com.google.j2objc.annotations.ReflectionSupport;", "foo/package-info.java");
CompilationUnit unit = translateType("foo.A", "package foo; public class A {}");
PackageInfoLookup packageInfoLookup = unit.getEnv().options().getPackageInfoLookup();
assert packageInfoLookup.getReflectionSupportLevel("foo") == ReflectionSupport.Level.FULL;

addSourceFile("@ReflectionSupport(ReflectionSupport.Level.FULL) package bar;"
+ "import com.google.j2objc.annotations.*;", "bar/package-info.java");
unit = translateType("bar.A", "package bar; public class A {}");
packageInfoLookup = unit.getEnv().options().getPackageInfoLookup();
assert packageInfoLookup.getReflectionSupportLevel("bar") == ReflectionSupport.Level.FULL;

addSourceFile("@com.google.j2objc.annotations.ReflectionSupport"
+ "(com.google.j2objc.annotations.ReflectionSupport.Level.NATIVE_ONLY) package baz;",
"baz/package-info.java");
unit = translateType("baz.A", "package baz; public class A {}");
packageInfoLookup = unit.getEnv().options().getPackageInfoLookup();
assert
packageInfoLookup.getReflectionSupportLevel("baz") == ReflectionSupport.Level.NATIVE_ONLY;
}
}

0 comments on commit 42e63a7

Please sign in to comment.