/*
 * Copyright 2010-2017 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jetbrains.kotlin.contracts.parsing

import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.description.ContractDescription
import org.jetbrains.kotlin.contracts.description.ContractProviderKey
import org.jetbrains.kotlin.contracts.description.LazyContractProvider
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.isContractDescriptionCallPsiCheck
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.storage.StorageManager

class ContractParsingServices(val languageVersionSettings: LanguageVersionSettings, private val storageManager: StorageManager) {
    /**
     * ! IMPORTANT NOTICE !
     *
     * This function has very important non-obvious implicit contract:
     * it *must* call [org.jetbrains.kotlin.contracts.description.LazyContractProvider.setContractDescription]
     * if FunctionDescriptor had [LazyContractProvider] in the user data.
     *
     * Otherwise, it may lead to inconsistent resolve state and failed assertions
     */
    fun checkContractAndRecordIfPresent(expression: KtExpression, trace: BindingTrace, ownerDescriptor: FunctionDescriptor) {
        // Fastpath. Note that it doesn't violates invariant described in KDoc, because 'isContractDescriptionCallPsiCheck'
        // is a *necessary* (but not sufficient, actually) condition for presence of 'LazyContractProvider'
        if (!expression.isContractDescriptionCallPsiCheck()) return

        val callContext = ContractCallContext(expression, ownerDescriptor, trace, languageVersionSettings)
        val contractProviderIfAny = ownerDescriptor.getUserData(ContractProviderKey) as? LazyContractProvider?
