Allow calling valueOf() on nullable UAST expressions
[idea/community.git] / uast / uast-common / src / org / jetbrains / uast / evaluation / UEvaluationContext.kt
1 /*
2  * Copyright 2000-2017 JetBrains s.r.o.
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 package org.jetbrains.uast.evaluation
17
18 import com.intellij.openapi.util.Key
19 import org.jetbrains.uast.*
20 import org.jetbrains.uast.values.UValue
21 import java.lang.ref.SoftReference
22
23 interface UEvaluationContext {
24     val uastContext: UastContext
25
26     val extensions: List<UEvaluatorExtension>
27
28     fun analyzeAll(file: UFile, state: UEvaluationState = file.createEmptyState()): UEvaluationContext
29
30     fun analyze(declaration: UDeclaration, state: UEvaluationState = declaration.createEmptyState()): UEvaluator
31
32     fun valueOf(expression: UExpression): UValue
33
34     fun getEvaluator(declaration: UDeclaration): UEvaluator
35 }
36
37 fun UFile.analyzeAll(context: UastContext = getUastContext(), extensions: List<UEvaluatorExtension> = emptyList()): UEvaluationContext =
38         MapBasedEvaluationContext(context, extensions).analyzeAll(this)
39
40 @JvmOverloads
41 fun UExpression?.uValueOf(extensions: List<UEvaluatorExtension> = emptyList()): UValue? {
42     if (this == null) return null
43     val declaration = getContainingDeclaration() ?: return null
44     val context = declaration.getEvaluationContextWithCaching(extensions)
45     context.analyze(declaration)
46     return context.valueOf(this)
47 }
48
49 fun UExpression?.uValueOf(vararg extensions: UEvaluatorExtension): UValue? = uValueOf(extensions.asList())
50
51 fun UDeclaration.getEvaluationContextWithCaching(extensions: List<UEvaluatorExtension> = emptyList()): UEvaluationContext {
52     return containingFile?.let { file ->
53         val cachedContext = file.getUserData(EVALUATION_CONTEXT_KEY)?.get()
54         if (cachedContext != null && cachedContext.extensions == extensions)
55             cachedContext
56         else
57             MapBasedEvaluationContext(getUastContext(), extensions).apply {
58                 file.putUserData(EVALUATION_CONTEXT_KEY, SoftReference(this))
59             }
60
61     } ?: MapBasedEvaluationContext(getUastContext(), extensions)
62 }
63
64 val EVALUATION_CONTEXT_KEY = Key<SoftReference<out UEvaluationContext>>("uast.EvaluationContext")