blob: 503d94a416772c16dbc0966c2e9d08157e5c3470 [file]
#!/bin/bash -eu
set -o pipefail
function create_base_files {
mkdir -p soong-test/java/integration/impllib
cat > soong-test/java/integration/Android.bp <<'EOF'
java_library {
name: "impl-library",
srcs: [
"impllib/**/*.java",
],
libs: ["provider-library"],
sdk_version: "35",
}
java_library {
name: "provider-library",
srcs: ["provider/**/*.java"],
sdk_version: "35",
}
EOF
cat > soong-test/java/integration/impllib/ExampleImpl1.java <<'EOF'
package soong.java.integration.impllib;
import soong.java.integration.provider.Provider;
class ExampleImpl1 {
public static final int EXAMPLE_1_CONST_1 = 100;
private Provider mProvider;
public ExampleImpl1() {
mProvider = new Provider();
}
public String getClassName() {
return "ExampleInt1";
}
public int getProviderConstant() {
return mProvider.nextProviderConst();
}
}
EOF
mkdir -p soong-test/java/integration/provider
cat > soong-test/java/integration/provider/Provider.java <<'EOF'
package soong.java.integration.provider;
public class Provider {
public static final int PROVIDER_CONST = -1;
private String className;
public Provider() {
this.className = "Provider";
}
public int nextProviderConst() {
return PROVIDER_CONST + 1;
}
private String getProviderName() {
return className;
}
}
EOF
}
function create_ap_files {
mkdir -p soong-test/java/integration/impllib
cat > soong-test/java/integration/Android.bp <<'EOF'
java_library {
name: "impl-library",
srcs: [
"impllib/**/*.java",
":wrapper-annotations-source",
],
libs: ["provider-library"],
plugins: ["wrapper-annotation-processor"],
sdk_version: "35",
}
java_library {
name: "provider-library",
srcs: ["provider/**/*.java"],
sdk_version: "35",
}
java_library_host {
name: "annotation-processor-lib",
srcs: ["annotation/**/*.java"],
}
java_plugin {
name: "wrapper-annotation-processor",
processor_class: "soong.java.integration.annotation.WrapperProcessor",
static_libs: ["annotation-processor-lib"],
installable: false,
generates_api: true,
}
filegroup {
name: "wrapper-annotations-source",
srcs: ["annotation/GenerateWrapper.java"],
}
EOF
mkdir -p soong-test/java/integration/annotation
cat > soong-test/java/integration/annotation/WrapperProcessor.java <<'EOF'
package soong.java.integration.annotation;
import soong.java.integration.annotation.GenerateWrapper;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
@SupportedAnnotationTypes("soong.java.integration.annotation.GenerateWrapper")
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class WrapperProcessor extends AbstractProcessor {
private Filer filer;
private Messager messager;
private Elements elementUtils;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
filer = processingEnv.getFiler();
messager = processingEnv.getMessager();
elementUtils = processingEnv.getElementUtils();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(GenerateWrapper.class)) {
ExecutableElement originalMethod = (ExecutableElement) annotatedElement;
GenerateWrapper annotation = originalMethod.getAnnotation(GenerateWrapper.class);
int methodCount = annotation.methodCount();
TypeElement enclosingClass = (TypeElement) originalMethod.getEnclosingElement();
String packageName = elementUtils.getPackageOf(enclosingClass).getQualifiedName().toString();
String originalClassNameForNaming = enclosingClass.getSimpleName().toString();
String wrapperClassName = originalClassNameForNaming + "Wrapper";
String wrapperMethodName = originalMethod.getSimpleName().toString() + "Wrapper";
try {
generateAlwaysVoidNoParamWrapper(packageName, wrapperClassName, wrapperMethodName, methodCount);
} catch (IOException e) {
throw new RuntimeException("Unable to generate class using annotation");
}
}
return true;
}
private void generateAlwaysVoidNoParamWrapper(String packageName, String wrapperClassName, String originalMethodNameForNaming, int methodCount) throws IOException {
StringBuilder sb = new StringBuilder();
sb.append("package ").append(packageName).append(";\n\n");
sb.append("public final class ").append(wrapperClassName).append(" {\n\n");
for (int i=0; i < methodCount; i++) {
sb.append(" public String ").append(originalMethodNameForNaming + String.valueOf(i)).append("() {\n");
sb.append(" return ").append("\"").append(wrapperClassName).append("\"").append(";\n");
sb.append(" }\n");
}
sb.append("}\n");
JavaFileObject jfo = filer.createSourceFile(packageName + "." + wrapperClassName);
try (Writer writer = jfo.openWriter()) {
writer.write(sb.toString());
}
}
}
EOF
cat > soong-test/java/integration/annotation/GenerateWrapper.java <<'EOF'
package soong.java.integration.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface GenerateWrapper {
int methodCount() default 1;
}
EOF
cat > soong-test/java/integration/impllib/AnnotationUsage.java <<'EOF'
package soong.java.integration.impllib;
import soong.java.integration.annotation.GenerateWrapper;
public class AnnotationUsage {
@GenerateWrapper(methodCount = 2)
public String getClassName() {
return "AnnotationUsage";
}
}
EOF
cat > soong-test/java/integration/impllib/ExampleImpl4.java <<'EOF'
package soong.java.integration.impllib;
import soong.java.integration.impllib.AnnotationUsageWrapper;
public class ExampleImpl4 {
private AnnotationUsageWrapper mAnnotationUsageWrapper;
public ExampleImpl4() {
this.mAnnotationUsageWrapper = new AnnotationUsageWrapper();
}
public String readGenApi() {
return mAnnotationUsageWrapper.getClassNameWrapper1();
}
}
EOF
}
create_example_impl3_file() {
mkdir -p soong-test/java/integration/impllib
cat > soong-test/java/integration/impllib/ExampleImpl3.java <<'EOF'
package soong.java.integration.impllib;
import soong.java.integration.impllib.ExampleImpl1;
public class ExampleImpl3 {
public ExampleImpl3() {
}
public String getClassName() {
return "ExampleImpl3";
}
private int getConstant() {
return ExampleImpl1.EXAMPLE_1_CONST_1;
}
}
EOF
}
modify_example_impl1_file() {
mkdir -p soong-test/java/integration/impllib
cat > soong-test/java/integration/impllib/ExampleImpl1.java <<'EOF'
package soong.java.integration.impllib;
import soong.java.integration.provider.Provider;
class ExampleImpl1 {
public static final int EXAMPLE_1_CONST_1_CHANGED = 10000;
private Provider mProvider;
public ExampleImpl1() {
mProvider = new Provider();
}
public String getClassName() {
return "ExampleInt1";
}
public int getProviderConstant() {
return mProvider.nextProviderConst();
}
}
EOF
}
modify_provider_file() {
mkdir -p soong-test/java/integration/provider
cat > soong-test/java/integration/provider/Provider.java <<'EOF'
package soong.java.integration.provider;
public class Provider {
public static final int PROVIDER_CONST = -1;
private String className;
public Provider() {
this.className = "Provider";
}
public int previousProviderConst() {
return PROVIDER_CONST - 1;
}
private String getProviderName() {
return className;
}
}
EOF
}
function modify_annotation_api {
mkdir -p soong-test/java/integration/impllib
cat > soong-test/java/integration/impllib/AnnotationUsage.java <<'EOF'
package soong.java.integration.impllib;
import soong.java.integration.annotation.GenerateWrapper;
public class AnnotationUsage {
@GenerateWrapper(methodCount = 1)
public String getClassName() {
return "AnnotationUsage";
}
}
EOF
}
function remove_base_dir {
rm -rf soong-test
}
# shellcheck disable=SC2120
function partial_compile_setup {
remove_base_dir
create_base_files
set_partial_compile_flags
local target_to_remove="${1:-}"
if [ -n "$target_to_remove" ]; then # Check if it's non-empty after default
echo "Removing target: $target_to_remove"
rm -rf "$target_to_remove"
fi
local all_files="${2:-}"
local all_files_create=false
if [[ "$all_files" == "true" ]]; then
all_files_create=true
fi
if [[ "$all_files_create" == true ]]; then
echo "Adding All Files:"
create_example_impl3_file
fi
}
function partial_compile_setup_with_ap {
remove_base_dir
create_base_files
create_ap_files
set_partial_compile_flags
}
# shellcheck disable=SC2120
function full_compile_setup {
remove_base_dir
create_base_files
unset_partial_compile_flags
local target_to_remove="${1:-}"
if [ -n "$target_to_remove" ]; then # Check if it's non-empty after default
echo "Removing target: $target_to_remove"
rm -rf "$target_to_remove"
fi
local all_files="${2:-}"
local all_files_create=false
if [[ "$all_files" == "true" ]]; then
all_files_create=true
fi
if [[ "$all_files_create" == true ]]; then
echo "Adding All Files:"
create_example_impl3_file
fi
}
function set_partial_compile_flags {
export SOONG_PARTIAL_COMPILE=true
export SOONG_USE_PARTIAL_COMPILE=true
}
function unset_partial_compile_flags {
export SOONG_PARTIAL_COMPILE=false
}