1 /* 2 * Copyright (C) 2016 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.expr; 18 19 import android.databinding.tool.processing.ErrorMessages; 20 import android.databinding.tool.processing.Scope; 21 import android.databinding.tool.store.Location; 22 import android.databinding.tool.util.L; 23 import android.databinding.tool.util.Preconditions; 24 25 import java.util.ArrayList; 26 import java.util.List; 27 import java.util.Map; 28 29 /** 30 * Callbacks are evaluated when event happens, not when execute pending is run. To separate their 31 * expressions, we provide a separate model for them that extends the main model. This allows them 32 * to introduce their own variables etc. without mixing them with other expressions. 33 */ 34 public class CallbackExprModel extends ExprModel { 35 // used for imports and other stuff. 36 final ExprModel mOriginal; 37 final List<CallbackArgExpr> mArguments = new ArrayList<CallbackArgExpr>(); CallbackExprModel(ExprModel original)38 public CallbackExprModel(ExprModel original) { 39 mOriginal = original; 40 } 41 42 @Override getImports()43 public Map<String, String> getImports() { 44 return mOriginal.getImports(); 45 } 46 47 @Override addImport(String alias, String type, Location location)48 public StaticIdentifierExpr addImport(String alias, String type, Location location) { 49 return mOriginal.addImport(alias, type, location); 50 } 51 52 @Override register(T expr)53 public <T extends Expr> T register(T expr) { 54 // locations are only synced to main model so we need to sync overselves here. 55 setCurrentLocationInFile(mOriginal.getCurrentLocationInFile()); 56 setCurrentParserContext(mOriginal.getCurrentParserContext()); 57 return super.register(expr); 58 } 59 60 @Override seal()61 public void seal() { 62 // ensure all types are calculated 63 for (Expr expr : mExprMap.values()) { 64 expr.getResolvedType(); 65 expr.markAsUsedInCallback(); 66 } 67 markSealed(); 68 // we do not resolve dependencies for these expression because they are resolved via 69 // ExecutionPath and should not interfere with the main expr model's dependency graph. 70 } 71 72 @Override identifier(String name)73 public IdentifierExpr identifier(String name) { 74 CallbackArgExpr arg = findArgByName(name); 75 if (arg != null) { 76 return arg; 77 } 78 IdentifierExpr id = new IdentifierExpr(name); 79 final Expr existing = mExprMap.get(id.getUniqueKey()); 80 if (existing == null) { 81 // this is not a method variable reference. register it in the main model 82 final IdentifierExpr identifier = mOriginal.identifier(name); 83 mExprMap.put(identifier.getUniqueKey(), identifier); 84 identifier.markAsUsedInCallback(); 85 return identifier; 86 } 87 return (IdentifierExpr) existing; 88 } 89 findArgByName(String name)90 private CallbackArgExpr findArgByName(String name) { 91 for (CallbackArgExpr arg : mArguments) { 92 if (name.equals(arg.getName())) { 93 return arg; 94 } 95 } 96 return null; 97 } 98 callbackArg(String name)99 public CallbackArgExpr callbackArg(String name) { 100 Preconditions.checkNull(findArgByName(name), 101 ErrorMessages.DUPLICATE_CALLBACK_ARGUMENT, name); 102 final CallbackArgExpr id = new CallbackArgExpr(mArguments.size(), name); 103 final CallbackArgExpr added = register(id); 104 mArguments.add(added); 105 106 try { 107 Scope.enter(added); 108 IdentifierExpr identifierWithSameName = mOriginal.findIdentifier(name); 109 if (identifierWithSameName != null) { 110 L.w(ErrorMessages.CALLBACK_VARIABLE_NAME_CLASH, name, name, 111 identifierWithSameName.getUserDefinedType()); 112 } 113 } finally { 114 Scope.exit(); 115 } 116 return added; 117 } 118 getArgCount()119 public int getArgCount() { 120 return mArguments.size(); 121 } 122 getArguments()123 public List<CallbackArgExpr> getArguments() { 124 return mArguments; 125 } 126 } 127