Frontend: extracted InlineCallCheckerWrapper to create InlineCallCheckers during run

This commit is contained in:
Alexey Tsvetkov
2014-12-30 20:46:12 +03:00
parent 5e16516d8e
commit 597a191c84
3 changed files with 55 additions and 50 deletions
@@ -30,58 +30,12 @@ public class CallResolverExtensionProvider {
new CompositeChecker(Arrays.asList(
new NeedSyntheticChecker(),
new ReifiedTypeParameterSubstitutionChecker(),
new CapturingInClosureChecker()
new CapturingInClosureChecker(),
new InlineCheckerWrapper()
));
private WeakReference<Map<DeclarationDescriptor, List<CallChecker>>> extensionsCache;
@NotNull
public CallChecker createExtension(@Nullable DeclarationDescriptor descriptor, boolean isAnnotationContext) {
if (descriptor == null || isAnnotationContext) {
return DEFAULT;
}
return new CompositeChecker(createExtensions(descriptor));
}
// create extension list with default one at the end
@NotNull
private List<CallChecker> createExtensions(@NotNull DeclarationDescriptor declaration) {
Map<DeclarationDescriptor, List<CallChecker>> map;
if (extensionsCache == null || (map = extensionsCache.get()) == null) {
map = new HashMap<DeclarationDescriptor, List<CallChecker>>();
extensionsCache = new WeakReference<Map<DeclarationDescriptor, List<CallChecker>>>(map);
}
List<CallChecker> extensions = map.get(declaration);
if (extensions != null) {
return extensions;
}
extensions = new ArrayList<CallChecker>();
DeclarationDescriptor parent = declaration.getContainingDeclaration();
if (parent != null) {
extensions.addAll(createExtensions(parent));
extensions.remove(extensions.size() - 1);//remove default from parent list
}
appendExtensionsFor(declaration, extensions);
List<CallChecker> immutableResult = Collections.unmodifiableList(extensions);
map.put(declaration, immutableResult);
return immutableResult;
}
// with default one at the end
private static void appendExtensionsFor(DeclarationDescriptor declarationDescriptor, List<CallChecker> extensions) {
if (declarationDescriptor instanceof SimpleFunctionDescriptor) {
SimpleFunctionDescriptor descriptor = (SimpleFunctionDescriptor) declarationDescriptor;
if (descriptor.getInlineStrategy().isInline()) {
extensions.add(new InlineChecker(descriptor));
}
}
// add your checkers here
extensions.add(DEFAULT);
return DEFAULT;
}
}
@@ -46,7 +46,7 @@ import java.util.Set;
import static org.jetbrains.kotlin.resolve.InlineDescriptorUtils.allowsNonLocalReturns;
import static org.jetbrains.kotlin.resolve.InlineDescriptorUtils.checkNonLocalReturnUsage;
public class InlineChecker implements CallChecker {
class InlineChecker implements CallChecker {
private final SimpleFunctionDescriptor descriptor;
@@ -0,0 +1,51 @@
/*
* Copyright 2010-2015 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.resolve.calls.checkers
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import java.lang.ref.WeakReference
public class InlineCheckerWrapper : CallChecker {
private var checkersCache: WeakReference<MutableMap<DeclarationDescriptor, CallChecker>>? = null
override fun <F : CallableDescriptor?> check(resolvedCall: ResolvedCall<F>, context: BasicCallResolutionContext) {
if (context.isAnnotationContext) return
var parentDescriptor: DeclarationDescriptor? = context.scope.getContainingDeclaration()
while (parentDescriptor != null) {
val descriptor = parentDescriptor!!
if (descriptor is SimpleFunctionDescriptor && descriptor.getInlineStrategy().isInline()) {
val checker = getChecker(descriptor)
checker.check(resolvedCall, context)
}
parentDescriptor = parentDescriptor?.getContainingDeclaration()
}
}
private fun getChecker(descriptor: SimpleFunctionDescriptor): CallChecker {
val map = checkersCache?.get() ?: hashMapOf()
checkersCache = checkersCache ?: WeakReference(map)
return map.getOrPut(descriptor) { InlineChecker(descriptor) }
}
}