1d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar/* 2d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Copyright (C) 2015 The Android Open Source Project 3d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * 4d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * you may not use this file except in compliance with the License. 6d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * You may obtain a copy of the License at 7d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * 8d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * 10d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * Unless required by applicable law or agreed to in writing, software 11d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * See the License for the specific language governing permissions and 14d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar * limitations under the License. 15d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar */ 16d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool.expr; 18d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 19d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport static android.databinding.tool.reflection.Callable.DYNAMIC; 20d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport static android.databinding.tool.reflection.Callable.STATIC; 21d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 22731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyarimport android.databinding.tool.processing.Scope; 23fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.Callable; 24fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.Callable.Type; 25fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelAnalyzer; 26fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelClass; 27fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.reflection.ModelMethod; 28fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.L; 29e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mountimport android.databinding.tool.writer.KCode; 30d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 31d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.ArrayList; 32d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarimport java.util.List; 33e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount 34d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 35d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyarpublic class MethodCallExpr extends Expr { 36d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar final String mName; 37d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 38e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount Callable mGetter; 39d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 402611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar static List<Expr> concat(Expr e, List<Expr> list) { 419784c9aaedeb863018f5fcaa0a598e8e2f8ed2f3Yigit Boyar List<Expr> merged = new ArrayList<Expr>(); 422611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar merged.add(e); 432611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar merged.addAll(list); 442611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar return merged; 452611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar } 462611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar 47d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar MethodCallExpr(Expr target, String name, List<Expr> args) { 482611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar super(concat(target, args)); 49d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar mName = name; 50d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 51d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 52d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar @Override 5318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount public void updateExpr(ModelAnalyzer modelAnalyzer) { 54731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar try { 55731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar Scope.enter(this); 56731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar resolveType(modelAnalyzer); 57731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar super.updateExpr(modelAnalyzer); 58731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar } finally { 59731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar Scope.exit(); 60731b74f7f44e67312a1fc4161c4e0aae221b2417Yigit Boyar } 6118243f6f1b7527272ef4feccdf4327d80d9f2241George Mount } 6218243f6f1b7527272ef4feccdf4327d80d9f2241George Mount 6318243f6f1b7527272ef4feccdf4327d80d9f2241George Mount @Override 64d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount protected KCode generateCode(boolean expand) { 65e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount KCode code = new KCode() 66d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .app("", getTarget().toCode(expand)) 67e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount .app(".") 68e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount .app(getGetter().name) 69e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount .app("("); 70e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount boolean first = true; 71e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount for (Expr arg : getArgs()) { 72e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount if (first) { 73e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount first = false; 74e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount } else { 75e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount code.app(", "); 76e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount } 77d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount code.app("", arg.toCode(expand)); 78e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount } 79e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount code.app(")"); 80e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount return code; 81e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount } 82e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount 83e52882df6130221462bf07f5f2b52de5c4b0f8deGeorge Mount @Override 8479fc7f3727815ab35bb1bb2e060bfb7db3176eedGeorge Mount protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) { 85d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar if (mGetter == null) { 86895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar List<ModelClass> args = new ArrayList<ModelClass>(); 877920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount for (Expr expr : getArgs()) { 88d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar args.add(expr.getResolvedType()); 89d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 9018243f6f1b7527272ef4feccdf4327d80d9f2241George Mount 9118243f6f1b7527272ef4feccdf4327d80d9f2241George Mount Expr target = getTarget(); 92a70fed6415aa1e8bbbe929aee776402ac3b81c86George Mount boolean isStatic = target instanceof StaticIdentifierExpr; 93fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount ModelMethod method = target.getResolvedType().getMethod(mName, args, isStatic); 94fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount if (method == null) { 95fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount String message = "cannot find method '" + mName + "' in class " + 96fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount target.getResolvedType().toJavaCode(); 97fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount IllegalArgumentException e = new IllegalArgumentException(message); 98fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount L.e(e, "cannot find method %s in class %s", mName, 99fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount target.getResolvedType().toJavaCode()); 100fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount throw e; 101fa9fe12980ef1103fabe33bf5ff0e2f53042a204George Mount } 102ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar if (!isStatic && method.isStatic()) { 103ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar // found a static method on an instance. Use class instead 104ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar target.getParents().remove(this); 105ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar getChildren().remove(target); 106ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar StaticIdentifierExpr staticId = getModel() 107ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar .staticIdentifierFor(target.getResolvedType()); 108ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar getChildren().add(staticId); 109ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar staticId.getParents().add(this); 110ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar // make sure we update this in case we access it below 111ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar target = getTarget(); 112ec2f3896c21a504b464bf591cdb45b62692b6760Yigit Boyar } 113019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar int flags = DYNAMIC; 114019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar if (method.isStatic()) { 115019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar flags |= STATIC; 116019c36b97c7c172ac03997f6bf170e65b2ed7fe4Yigit Boyar } 117d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount mGetter = new Callable(Type.METHOD, method.getName(), null, method.getReturnType(args), 11888ce44ccc65e74a8553244ca246cc9f4c48483e0Yigit Boyar method.getParameterTypes().length, flags); 119d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 120d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar return mGetter.resolvedType; 121d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 122d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 123d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar @Override 124d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar protected List<Dependency> constructDependencies() { 125dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar final List<Dependency> dependencies = constructDynamicChildrenDependencies(); 126dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar for (Dependency dependency : dependencies) { 1277920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount if (dependency.getOther() == getTarget()) { 128dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar dependency.setMandatory(true); 129dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar } 130dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar } 131dc69f49d687ec036947f26a9bf9025a305de0721Yigit Boyar return dependencies; 132d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 133d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 134d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar @Override 135d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar protected String computeUniqueKey() { 1362611838bffef5a009ca71e3e9e59a93f29b098edYigit Boyar return join(getTarget().computeUniqueKey(), mName, 1377920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount super.computeUniqueKey()); 138d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 139d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 140d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar public Expr getTarget() { 1417920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount return getChildren().get(0); 142d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 143d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 144d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar public String getName() { 145d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar return mName; 146d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 147d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 148d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar public List<Expr> getArgs() { 1497920e17f7b501d5792e7e3250e9dbb69eca86adeGeorge Mount return getChildren().subList(1, getChildren().size()); 150d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 151d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar 152e6c6d3bf4fac3fa11c5780cfd3bc14cdb0caaea1George Mount public Callable getGetter() { 153d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar return mGetter; 154d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar } 155d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 156d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount @Override 157d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public String getInvertibleError() { 158d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return "Method calls may not be used in two-way expressions"; 159d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 160d7af42b29ddf22f0068f7496c5ac6f4f34b543b6Yigit Boyar} 161