• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.databinding.tool;
18 
19 import android.databinding.tool.expr.Dependency;
20 import android.databinding.tool.expr.Expr;
21 import android.databinding.tool.expr.ExprModel;
22 import android.databinding.tool.expr.IdentifierExpr;
23 import android.databinding.tool.processing.Scope;
24 import android.databinding.tool.processing.scopes.FileScopeProvider;
25 import android.databinding.tool.store.Location;
26 import android.databinding.tool.store.ResourceBundle;
27 import android.databinding.tool.store.ResourceBundle.BindingTargetBundle;
28 import android.databinding.tool.util.L;
29 import android.databinding.tool.util.Preconditions;
30 import android.databinding.tool.writer.LayoutBinderWriter;
31 import android.databinding.tool.writer.LayoutBinderWriterKt;
32 
33 import org.antlr.v4.runtime.misc.Nullable;
34 
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.Comparator;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.List;
41 
42 /**
43  * Keeps all information about the bindings per layout file
44  */
45 public class LayoutBinder implements FileScopeProvider {
46     private static final Comparator<BindingTarget> COMPARE_FIELD_NAME = new Comparator<BindingTarget>() {
47         @Override
48         public int compare(BindingTarget first, BindingTarget second) {
49             final String fieldName1 = LayoutBinderWriterKt.getFieldName(first);
50             final String fieldName2 = LayoutBinderWriterKt.getFieldName(second);
51             return fieldName1.compareTo(fieldName2);
52         }
53     };
54 
55     /*
56     * val pkg: String, val projectPackage: String, val baseClassName: String,
57         val layoutName:String, val lb: LayoutExprBinding*/
58     private final ExprModel mExprModel;
59     private final ExpressionParser mExpressionParser;
60     private final List<BindingTarget> mBindingTargets;
61     private final List<BindingTarget> mSortedBindingTargets;
62     private String mModulePackage;
63     private final HashMap<String, String> mUserDefinedVariables = new HashMap<String, String>();
64 
65     private LayoutBinderWriter mWriter;
66     private ResourceBundle.LayoutFileBundle mBundle;
67     private static final String[] sJavaLangClasses = {
68             "Deprecated",
69             "Override",
70             "SafeVarargs",
71             "SuppressWarnings",
72             "Appendable",
73             "AutoCloseable",
74             "CharSequence",
75             "Cloneable",
76             "Comparable",
77             "Iterable",
78             "Readable",
79             "Runnable",
80             "Thread.UncaughtExceptionHandler",
81             "Boolean",
82             "Byte",
83             "Character",
84             "Character.Subset",
85             "Character.UnicodeBlock",
86             "Class",
87             "ClassLoader",
88             "Compiler",
89             "Double",
90             "Enum",
91             "Float",
92             "InheritableThreadLocal",
93             "Integer",
94             "Long",
95             "Math",
96             "Number",
97             "Object",
98             "Package",
99             "Process",
100             "ProcessBuilder",
101             "Runtime",
102             "RuntimePermission",
103             "SecurityManager",
104             "Short",
105             "StackTraceElement",
106             "StrictMath",
107             "String",
108             "StringBuffer",
109             "StringBuilder",
110             "System",
111             "Thread",
112             "ThreadGroup",
113             "ThreadLocal",
114             "Throwable",
115             "Void",
116             "Thread.State",
117             "ArithmeticException",
118             "ArrayIndexOutOfBoundsException",
119             "ArrayStoreException",
120             "ClassCastException",
121             "ClassNotFoundException",
122             "CloneNotSupportedException",
123             "EnumConstantNotPresentException",
124             "Exception",
125             "IllegalAccessException",
126             "IllegalArgumentException",
127             "IllegalMonitorStateException",
128             "IllegalStateException",
129             "IllegalThreadStateException",
130             "IndexOutOfBoundsException",
131             "InstantiationException",
132             "InterruptedException",
133             "NegativeArraySizeException",
134             "NoSuchFieldException",
135             "NoSuchMethodException",
136             "NullPointerException",
137             "NumberFormatException",
138             "ReflectiveOperationException",
139             "RuntimeException",
140             "SecurityException",
141             "StringIndexOutOfBoundsException",
142             "TypeNotPresentException",
143             "UnsupportedOperationException",
144             "AbstractMethodError",
145             "AssertionError",
146             "ClassCircularityError",
147             "ClassFormatError",
148             "Error",
149             "ExceptionInInitializerError",
150             "IllegalAccessError",
151             "IncompatibleClassChangeError",
152             "InstantiationError",
153             "InternalError",
154             "LinkageError",
155             "NoClassDefFoundError",
156             "NoSuchFieldError",
157             "NoSuchMethodError",
158             "OutOfMemoryError",
159             "StackOverflowError",
160             "ThreadDeath",
161             "UnknownError",
162             "UnsatisfiedLinkError",
163             "UnsupportedClassVersionError",
164             "VerifyError",
165             "VirtualMachineError",
166     };
167 
LayoutBinder(ResourceBundle.LayoutFileBundle layoutBundle)168     public LayoutBinder(ResourceBundle.LayoutFileBundle layoutBundle) {
169         try {
170             Scope.enter(this);
171             mExprModel = new ExprModel();
172             mExpressionParser = new ExpressionParser(mExprModel);
173             mBindingTargets = new ArrayList<BindingTarget>();
174             mBundle = layoutBundle;
175             mModulePackage = layoutBundle.getModulePackage();
176             HashSet<String> names = new HashSet<String>();
177             // copy over data.
178             for (ResourceBundle.VariableDeclaration variable : mBundle.getVariables()) {
179                 addVariable(variable.name, variable.type, variable.location, variable.declared);
180                 names.add(variable.name);
181             }
182 
183             for (ResourceBundle.NameTypeLocation userImport : mBundle.getImports()) {
184                 mExprModel.addImport(userImport.name, userImport.type, userImport.location);
185                 names.add(userImport.name);
186             }
187             if (!names.contains("context")) {
188                 mExprModel.builtInVariable("context", "android.content.Context",
189                         "getRoot().getContext()");
190                 names.add("context");
191             }
192             for (String javaLangClass : sJavaLangClasses) {
193                 mExprModel.addImport(javaLangClass, "java.lang." + javaLangClass, null);
194             }
195             // First resolve all the View fields
196             // Ensure there are no conflicts with variable names
197             for (BindingTargetBundle targetBundle : mBundle.getBindingTargetBundles()) {
198                 try {
199                     Scope.enter(targetBundle);
200                     final BindingTarget bindingTarget = createBindingTarget(targetBundle);
201                     if (bindingTarget.getId() != null) {
202                         final String fieldName = LayoutBinderWriterKt.
203                                 getReadableName(bindingTarget);
204                         if (names.contains(fieldName)) {
205                             L.w("View field %s collides with a variable or import", fieldName);
206                         } else {
207                             names.add(fieldName);
208                             mExprModel.viewFieldExpr(bindingTarget);
209                         }
210                     }
211                 } finally {
212                     Scope.exit();
213                 }
214             }
215 
216             for (BindingTarget bindingTarget : mBindingTargets) {
217                 try {
218                     Scope.enter(bindingTarget.mBundle);
219                     for (BindingTargetBundle.BindingBundle bindingBundle : bindingTarget.mBundle
220                             .getBindingBundleList()) {
221                         try {
222                             Scope.enter(bindingBundle.getValueLocation());
223                             bindingTarget.addBinding(bindingBundle.getName(),
224                                     parse(bindingBundle.getExpr(), bindingBundle.isTwoWay(),
225                                             bindingBundle.getValueLocation()));
226                         } finally {
227                             Scope.exit();
228                         }
229                     }
230                     bindingTarget.resolveTwoWayExpressions();
231                     bindingTarget.resolveMultiSetters();
232                     bindingTarget.resolveListeners();
233                 } finally {
234                     Scope.exit();
235                 }
236             }
237             mSortedBindingTargets = new ArrayList<BindingTarget>(mBindingTargets);
238             Collections.sort(mSortedBindingTargets, COMPARE_FIELD_NAME);
239         } finally {
240             Scope.exit();
241         }
242     }
243 
resolveWhichExpressionsAreUsed()244     public void resolveWhichExpressionsAreUsed() {
245         List<Expr> used = new ArrayList<Expr>();
246         for (BindingTarget target : mBindingTargets) {
247             for (Binding binding : target.getBindings()) {
248                 binding.getExpr().setIsUsed(true);
249                 used.add(binding.getExpr());
250             }
251         }
252         while (!used.isEmpty()) {
253             Expr e = used.remove(used.size() - 1);
254             for (Dependency dep : e.getDependencies()) {
255                 if (!dep.getOther().isUsed()) {
256                     used.add(dep.getOther());
257                     dep.getOther().setIsUsed(true);
258                 }
259             }
260         }
261     }
262 
addVariable(String name, String type, Location location, boolean declared)263     public IdentifierExpr addVariable(String name, String type, Location location,
264             boolean declared) {
265         Preconditions.check(!mUserDefinedVariables.containsKey(name),
266                 "%s has already been defined as %s", name, type);
267         final IdentifierExpr id = mExprModel.identifier(name);
268         id.setUserDefinedType(type);
269         id.enableDirectInvalidation();
270         if (location != null) {
271             id.addLocation(location);
272         }
273         mUserDefinedVariables.put(name, type);
274         if (declared) {
275             id.setDeclared();
276         }
277         return id;
278     }
279 
getUserDefinedVariables()280     public HashMap<String, String> getUserDefinedVariables() {
281         return mUserDefinedVariables;
282     }
283 
createBindingTarget(ResourceBundle.BindingTargetBundle targetBundle)284     public BindingTarget createBindingTarget(ResourceBundle.BindingTargetBundle targetBundle) {
285         final BindingTarget target = new BindingTarget(targetBundle);
286         mBindingTargets.add(target);
287         target.setModel(mExprModel);
288         return target;
289     }
290 
parse(String input, boolean isTwoWay, @Nullable Location locationInFile)291     public Expr parse(String input, boolean isTwoWay, @Nullable Location locationInFile) {
292         final Expr parsed = mExpressionParser.parse(input, locationInFile);
293         parsed.setBindingExpression(true);
294         parsed.setTwoWay(isTwoWay);
295         return parsed;
296     }
297 
getBindingTargets()298     public List<BindingTarget> getBindingTargets() {
299         return mBindingTargets;
300     }
301 
getSortedTargets()302     public List<BindingTarget> getSortedTargets() {
303         return mSortedBindingTargets;
304     }
305 
isEmpty()306     public boolean isEmpty() {
307         return mExprModel.size() == 0;
308     }
309 
getModel()310     public ExprModel getModel() {
311         return mExprModel;
312     }
313 
ensureWriter()314     private void ensureWriter() {
315         if (mWriter == null) {
316             mWriter = new LayoutBinderWriter(this);
317         }
318     }
319 
sealModel()320     public void sealModel() {
321         mExprModel.seal();
322     }
323 
writeViewBinderBaseClass(boolean forLibrary)324     public String writeViewBinderBaseClass(boolean forLibrary) {
325         ensureWriter();
326         return mWriter.writeBaseClass(forLibrary);
327     }
328 
writeViewBinder(int minSdk)329     public String writeViewBinder(int minSdk) {
330         ensureWriter();
331         Preconditions.checkNotNull(getPackage(), "package cannot be null");
332         Preconditions.checkNotNull(getClassName(), "base class name cannot be null");
333         return mWriter.write(minSdk);
334     }
335 
getPackage()336     public String getPackage() {
337         return mBundle.getBindingClassPackage();
338     }
339 
isMerge()340     public boolean isMerge() {
341         return mBundle.isMerge();
342     }
343 
getModulePackage()344     public String getModulePackage() {
345         return mModulePackage;
346     }
347 
getLayoutname()348     public String getLayoutname() {
349         return mBundle.getFileName();
350     }
351 
getImplementationName()352     public String getImplementationName() {
353         if (hasVariations()) {
354             return mBundle.getBindingClassName() + mBundle.getConfigName() + "Impl";
355         } else {
356             return mBundle.getBindingClassName();
357         }
358     }
359 
getClassName()360     public String getClassName() {
361         return mBundle.getBindingClassName();
362     }
363 
getTag()364     public String getTag() {
365         return mBundle.getDirectory() + "/" + mBundle.getFileName();
366     }
367 
hasVariations()368     public boolean hasVariations() {
369         return mBundle.hasVariations();
370     }
371 
372     @Override
provideScopeFilePath()373     public String provideScopeFilePath() {
374         return mBundle.getAbsoluteFilePath();
375     }
376 }
377