16047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar/* 26047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * Copyright (C) 2016 The Android Open Source Project 36047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * 46047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 56047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * you may not use this file except in compliance with the License. 66047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * You may obtain a copy of the License at 76047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * 86047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 96047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * 106047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * Unless required by applicable law or agreed to in writing, software 116047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 126047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * See the License for the specific language governing permissions and 146047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * limitations under the License. 156047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar */ 166047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 176047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarpackage android.databinding.tool.expr; 186047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 196047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.CallbackWrapper; 206047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.reflection.ModelAnalyzer; 216047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.reflection.ModelClass; 226047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.reflection.ModelMethod; 236047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.solver.ExecutionPath; 246047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.util.Preconditions; 256047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.writer.KCode; 266047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.writer.LayoutBinderWriterKt; 276047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 286047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport java.util.Collections; 296047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport java.util.List; 306047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport java.util.concurrent.atomic.AtomicInteger; 316047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 326047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarpublic class LambdaExpr extends Expr { 336047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar private static AtomicInteger sIdCounter = new AtomicInteger(); 346047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar private final int mId = sIdCounter.incrementAndGet(); 356047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar private CallbackWrapper mCallbackWrapper; 366047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar // set when Binding resolves the receiver 376047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar private final CallbackExprModel mCallbackExprModel; 386047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar private int mCallbackId; 396047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar private ExecutionPath mExecutionPath; 406047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 416047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public LambdaExpr(Expr expr, CallbackExprModel callbackExprModel) { 426047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar super(expr); 436047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar mCallbackExprModel = callbackExprModel; 446047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 456047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 466047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public Expr getExpr() { 476047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return getChildren().get(0); 486047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 496047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 506047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public CallbackExprModel getCallbackExprModel() { 516047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return mCallbackExprModel; 526047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 536047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 546047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar @Override 556047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) { 566047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar Preconditions.checkNotNull(mCallbackWrapper, "Lambda expression must be resolved to its" 576047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar + " setter first to get the type."); 586047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return mCallbackWrapper.klass; 596047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 606047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 616047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar @Override 626047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar protected List<Dependency> constructDependencies() { 636047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return Collections.emptyList(); 646047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 656047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 666047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public CallbackWrapper getCallbackWrapper() { 676047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return mCallbackWrapper; 686047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 696047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 706047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar @Override 716047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public Expr resolveListeners(ModelClass valueType, Expr parent) { 726047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return this; 736047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 746047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 756047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar @Override 766047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar protected String computeUniqueKey() { 776047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return "callback" + mId; 786047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 796047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 806047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar @Override 816047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public boolean isDynamic() { 826047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return false; 836047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 846047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 856047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar @Override 86bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount protected KCode generateCode() { 876047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar Preconditions 886047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar .checkNotNull(mCallbackWrapper, "Cannot find the callback method for %s", this); 896047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar KCode code = new KCode(""); 906047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar final int minApi = mCallbackWrapper.getMinApi(); 916047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar final String fieldName = LayoutBinderWriterKt.getFieldName(this); 926047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar if (minApi > 1) { 936047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar code.app("(getBuildSdkInt() < " + minApi + " ? null : ").app(fieldName).app(")"); 946047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } else { 956047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar code.app(fieldName); 966047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 976047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return code; 986047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 996047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 100bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount @Override 101bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount public Expr cloneToModel(ExprModel model) { 102bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount return model.lambdaExpr(getExpr().cloneToModel(model), (CallbackExprModel) model); 103bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount } 104bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount 1056047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public String generateConstructor() { 1066047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return getCallbackWrapper().constructForIdentifier(mCallbackId); 1076047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 1086047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 1096047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar @Override 1106047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public void markAsUsed() { 1116047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar super.markAsUsed(); 1126047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 1136047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 1146047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar @Override 1156047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar protected String getInvertibleError() { 1166047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return "Lambda expressions cannot be inverted"; 1176047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 1186047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 1196047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar @Override 1206047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public List<ExecutionPath> toExecutionPath(List<ExecutionPath> paths) { 1216047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar // i'm not involved. 1226047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar throw new UnsupportedOperationException("should not call toExecutionPath on a lambda" 1236047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar + " expression"); 1246047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 1256047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 1266047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public final ExecutionPath getExecutionPath() { 1276047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return mExecutionPath; 1286047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 1296047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 1306047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public int getCallbackId() { 1316047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar return mCallbackId; 1326047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 1336047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar 1346047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar public void setup(ModelClass klass, ModelMethod method, int callbackId) { 1356047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar mCallbackId = callbackId; 1366047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar mCallbackWrapper = getModel().callbackWrapper(klass, method); 1376047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar // now register the arguments as variables. 1386047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar final ModelClass[] parameterTypes = method.getParameterTypes(); 1396047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar final List<CallbackArgExpr> args = mCallbackExprModel.getArguments(); 1406047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar if (parameterTypes.length == args.size()) { 1416047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar for (int i = 0; i < parameterTypes.length; i++) { 1426047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar args.get(i).setClassFromCallback(parameterTypes[i]); 1436047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 1446047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 1456047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar // first convert to execution path because we may add additional expressions 1466047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar mExecutionPath = ExecutionPath.createRoot(); 1476047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar getExpr().toExecutionPath(mExecutionPath); 1486047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar mCallbackExprModel.seal(); 1496047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar } 1506047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar} 151