From 75aa9bf96f0cf0c66c6dbc386eee2dab99790634 Mon Sep 17 00:00:00 2001 From: George Mount Date: Mon, 30 Mar 2015 12:20:20 -0700 Subject: [PATCH] Require only one pass to make BR.java file. Bug 19985005 Because the generation of Binding files created @Bindable annotations, the BR file generation had to wait until a second annotation pass. This caused errors to be generated that were later cleared, causing confusion. I moved the BR file generation to the same annotation processing stage that generates the Binding files to clear up the error generation. TODO: merge the annotation processing stages so that there is less cross-talk between annotation processors. --- .../annotationprocessor/ProcessBindable.java | 71 +++++++++++++------ .../ProcessDataBinding.java | 5 +- .../ProcessExpressions.java | 9 ++- .../databinding/tool/CompilerChef.java | 16 +++++ .../tool/writer/LayoutBinderWriter.kt | 1 - 5 files changed, 78 insertions(+), 24 deletions(-) diff --git a/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java b/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java index 30f996218011d..d4582cb8b35f1 100644 --- a/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java +++ b/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java @@ -20,6 +20,7 @@ import com.google.common.base.Preconditions; import android.databinding.Bindable; import android.databinding.BindingBuildInfo; +import android.databinding.tool.CompilerChef.BindableHolder; import android.databinding.tool.util.GenerationalClassUtil; import android.databinding.tool.util.L; @@ -45,43 +46,58 @@ import javax.lang.model.type.TypeKind; // binding app info and library info are necessary to trigger this. @SupportedSourceVersion(SourceVersion.RELEASE_7) -public class ProcessBindable extends ProcessDataBinding.ProcessingStep { +public class ProcessBindable extends ProcessDataBinding.ProcessingStep implements BindableHolder { private static final String INTERMEDIATE_FILE_EXT = "-br.bin"; Intermediate mProperties; + HashMap> mLayoutVariables = new HashMap<>(); @Override public boolean onHandleStep(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv, BindingBuildInfo buildInfo) { if (mProperties == null) { mProperties = new IntermediateV1(buildInfo.modulePackage()); - } - for (Element element : AnnotationUtil.getElementsAnnotatedWith(roundEnv, Bindable.class)) { - Element enclosingElement = element.getEnclosingElement(); - ElementKind kind = enclosingElement.getKind(); - if (kind != ElementKind.CLASS && kind != ElementKind.INTERFACE) { - L.e("Bindable must be on a member field or method. The enclosing type is %s", - enclosingElement.getKind()); + mergeLayoutVariables(); + mLayoutVariables.clear(); + for (Element element : AnnotationUtil + .getElementsAnnotatedWith(roundEnv, Bindable.class)) { + Element enclosingElement = element.getEnclosingElement(); + ElementKind kind = enclosingElement.getKind(); + if (kind != ElementKind.CLASS && kind != ElementKind.INTERFACE) { + L.e("Bindable must be on a member field or method. The enclosing type is %s", + enclosingElement.getKind()); + } + TypeElement enclosing = (TypeElement) enclosingElement; + String name = getPropertyName(element); + if (name != null) { + Preconditions + .checkNotNull(mProperties, "Must receive app / library info before " + + "Bindable fields."); + mProperties.addProperty(enclosing.getQualifiedName().toString(), name); + } } - TypeElement enclosing = (TypeElement) enclosingElement; - String name = getPropertyName(element); - if (name != null) { - Preconditions.checkNotNull(mProperties, "Must receive app / library info before " - + "Bindable fields."); - mProperties.addProperty(enclosing.getQualifiedName().toString(), name); + if (mProperties.hasValues()) { + GenerationalClassUtil.writeIntermediateFile(processingEnv, + mProperties.getPackage(), + createIntermediateFileName(mProperties.getPackage()), mProperties); + generateBRClasses(!buildInfo.isLibrary(), mProperties.getPackage()); } } return false; } + @Override + public void addVariable(String variableName, String containingClassName) { + HashSet variableNames = mLayoutVariables.get(containingClassName); + if (variableNames == null) { + variableNames = new HashSet<>(); + mLayoutVariables.put(containingClassName, variableNames); + } + variableNames.add(variableName); + } + @Override public void onProcessingOver(RoundEnvironment roundEnvironment, ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) { - if (mProperties != null) { - GenerationalClassUtil.writeIntermediateFile(processingEnvironment, - mProperties.getPackage(), - createIntermediateFileName(mProperties.getPackage()), mProperties); - generateBRClasses(!buildInfo.isLibrary(), mProperties.getPackage()); - } } private String createIntermediateFileName(String appPkg) { @@ -183,6 +199,14 @@ public class ProcessBindable extends ProcessDataBinding.ProcessingStep { propertyName.subSequence(1, propertyName.length()); } + private void mergeLayoutVariables() { + for (String containingClass : mLayoutVariables.keySet()) { + for (String variable : mLayoutVariables.get(containingClass)) { + mProperties.addProperty(containingClass, variable); + } + } + } + private static boolean prefixes(CharSequence sequence, String prefix) { boolean prefixes = false; if (sequence.length() > prefix.length()) { @@ -234,6 +258,8 @@ public class ProcessBindable extends ProcessDataBinding.ProcessingStep { void addProperty(String className, String propertyName); + boolean hasValues(); + String getPackage(); } @@ -265,6 +291,11 @@ public class ProcessBindable extends ProcessDataBinding.ProcessingStep { properties.add(propertyName); } + @Override + public boolean hasValues() { + return !mProperties.isEmpty(); + } + @Override public String getPackage() { return mPackage; diff --git a/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java b/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java index 2b1321e5f9d29..944cc20a1ad12 100644 --- a/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java +++ b/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java @@ -69,10 +69,11 @@ public class ProcessDataBinding extends AbstractProcessor { } private void initProcessingSteps() { + ProcessBindable processBindable = new ProcessBindable(); mProcessingSteps = Arrays.asList( new ProcessMethodAdapters(), - new ProcessExpressions(), - new ProcessBindable() + new ProcessExpressions(processBindable), + processBindable ); AnnotationJavaFileWriter javaFileWriter = new AnnotationJavaFileWriter(processingEnv); for (ProcessingStep step : mProcessingSteps) { diff --git a/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java b/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java index 31a04ec33ee28..8f8914308a6e8 100644 --- a/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java +++ b/tools/data-binding/annotationprocessor/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java @@ -45,6 +45,13 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep { private static final String LAYOUT_INFO_FILE_SUFFIX = "-layoutinfo.bin"; + private final ProcessBindable mProcessBindable; + + public ProcessExpressions(ProcessBindable processBindable) { + mProcessBindable = processBindable; + } + + @Override public boolean onHandleStep(RoundEnvironment roundEnvironment, ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) { @@ -79,7 +86,6 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep { @Override public void onProcessingOver(RoundEnvironment roundEnvironment, ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) { - } private void generateBinders(ResourceBundle resourceBundle, BindingBuildInfo buildInfo, @@ -117,6 +123,7 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep { throws JAXBException { CompilerChef compilerChef = CompilerChef.createChef(resourceBundle, getWriter()); if (compilerChef.hasAnythingToGenerate()) { + compilerChef.addBRVariables(mProcessBindable); compilerChef.writeViewBinderInterfaces(); if (!forLibraryModule) { compilerChef.writeDbrFile(); diff --git a/tools/data-binding/compiler/src/main/java/android/databinding/tool/CompilerChef.java b/tools/data-binding/compiler/src/main/java/android/databinding/tool/CompilerChef.java index 527cf8d8cc4aa..200c33bf00ccb 100644 --- a/tools/data-binding/compiler/src/main/java/android/databinding/tool/CompilerChef.java +++ b/tools/data-binding/compiler/src/main/java/android/databinding/tool/CompilerChef.java @@ -66,6 +66,18 @@ public class CompilerChef { mFileWriter.writeToFile(pkg + "." + dbr.getClassName(), dbr.write()); } } + + /** + * Adds variables to list of Bindables. + */ + public void addBRVariables(BindableHolder bindables) { + ensureDataBinder(); + for (LayoutBinder layoutBinder : mDataBinder.mLayoutBinders) { + for (String variableName : layoutBinder.getUserDefinedVariables().keySet()) { + bindables.addVariable(variableName, layoutBinder.getInterfaceName()); + } + } + } public void writeViewBinderInterfaces() { ensureDataBinder(); @@ -76,4 +88,8 @@ public class CompilerChef { ensureDataBinder(); mDataBinder.writeBinders(); } + + public interface BindableHolder { + void addVariable(String variableName, String containingClassName); + } } diff --git a/tools/data-binding/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt b/tools/data-binding/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt index 1ecdf67e3883e..ef57f5b45aac5 100644 --- a/tools/data-binding/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt +++ b/tools/data-binding/compiler/src/main/kotlin/android/databinding/tool/writer/LayoutBinderWriter.kt @@ -810,7 +810,6 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { nl("") variables.forEach { if (it.getUserDefinedType() != null) { - tab("@Bindable") //it.getExpandedUserDefinedType(ModelAnalyzer.getInstance()); val type = ModelAnalyzer.getInstance().applyImports(it.getUserDefinedType(), model.getImports()) tab("public abstract void ${it.setterName}(${type} ${it.readableUniqueName});")