CallbackExprModel.java revision 6047998943beebd81e0ae1068df39c0cbee38628
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.processing.ErrorMessages;
206047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.processing.Scope;
216047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.processing.ScopedException;
226047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.store.Location;
236047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.util.L;
246047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport android.databinding.tool.util.Preconditions;
256047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
266047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport java.util.ArrayList;
276047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport java.util.List;
286047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarimport java.util.Map;
296047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
306047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar/**
316047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * Callbacks are evaluated when event happens, not when execute pending is run. To separate their
326047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * expressions, we provide a separate model for them that extends the main model. This allows them
336047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar * to introduce their own variables etc. without mixing them with other expressions.
346047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar */
356047998943beebd81e0ae1068df39c0cbee38628Yigit Boyarpublic class CallbackExprModel extends ExprModel {
366047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    // used for imports and other stuff.
376047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    final ExprModel mOriginal;
386047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    final List<CallbackArgExpr> mArguments = new ArrayList<CallbackArgExpr>();
396047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public CallbackExprModel(ExprModel original) {
406047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        mOriginal = original;
416047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
426047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
436047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    @Override
446047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public Map<String, String> getImports() {
456047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return mOriginal.getImports();
466047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
476047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
486047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    @Override
496047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public StaticIdentifierExpr addImport(String alias, String type, Location location) {
506047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return mOriginal.addImport(alias, type, location);
516047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
526047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
536047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    @Override
546047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public <T extends Expr> T register(T expr) {
556047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        // locations are only synced to main model so we need to sync overselves here.
566047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        setCurrentLocationInFile(mOriginal.getCurrentLocationInFile());
576047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        setCurrentParserContext(mOriginal.getCurrentParserContext());
586047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return super.register(expr);
596047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
606047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
616047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    @Override
626047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public void seal() {
636047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        // ensure all types are calculated
646047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        for (Expr expr : mExprMap.values()) {
656047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            expr.getResolvedType();
666047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            expr.markAsUsedInCallback();
676047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
686047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        markSealed();
696047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        // we do not resolve dependencies for these expression because they are resolved via
706047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        // ExecutionPath and should not interfere with the main expr model's dependency graph.
716047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
726047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
736047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    @Override
746047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public IdentifierExpr identifier(String name) {
756047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        CallbackArgExpr arg = findArgByName(name);
766047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        if (arg != null) {
776047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            return arg;
786047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
796047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        IdentifierExpr id = new IdentifierExpr(name);
806047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        final Expr existing = mExprMap.get(id.getUniqueKey());
816047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        if (existing == null) {
826047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar             // this is not a method variable reference. register it in the main model
836047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            final IdentifierExpr identifier = mOriginal.identifier(name);
846047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            mExprMap.put(identifier.getUniqueKey(), identifier);
856047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            identifier.markAsUsedInCallback();
866047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            return identifier;
876047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
886047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return (IdentifierExpr) existing;
896047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
906047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
916047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    private CallbackArgExpr findArgByName(String name) {
926047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        for (CallbackArgExpr arg : mArguments) {
936047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            if (name.equals(arg.getName())) {
946047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                return arg;
956047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            }
966047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
976047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return null;
986047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
996047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
1006047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public CallbackArgExpr callbackArg(String name) {
1016047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        Preconditions.checkNull(findArgByName(name),
1026047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                ErrorMessages.DUPLICATE_CALLBACK_ARGUMENT, name);
1036047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        final CallbackArgExpr id = new CallbackArgExpr(mArguments.size(), name);
1046047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        final CallbackArgExpr added = register(id);
1056047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        mArguments.add(added);
1066047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
1076047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        try {
1086047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            Scope.enter(added);
1096047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            IdentifierExpr identifierWithSameName = mOriginal.findIdentifier(name);
1106047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            if (identifierWithSameName != null) {
1116047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                L.w(ErrorMessages.CALLBACK_VARIABLE_NAME_CLASH, name, name,
1126047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar                        identifierWithSameName.getUserDefinedType());
1136047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            }
1146047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        } finally {
1156047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar            Scope.exit();
1166047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        }
1176047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return added;
1186047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
1196047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
1206047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public int getArgCount() {
1216047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return mArguments.size();
1226047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
1236047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar
1246047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    public List<CallbackArgExpr> getArguments() {
1256047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar        return mArguments;
1266047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar    }
1276047998943beebd81e0ae1068df39c0cbee38628Yigit Boyar}
128