001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.resolve;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
022 import org.jetbrains.kotlin.cfg.ControlFlowInformationProvider;
023 import org.jetbrains.kotlin.config.LanguageVersionSettings;
024 import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor;
025 import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
026 import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
027 import org.jetbrains.kotlin.psi.*;
028 import org.jetbrains.kotlin.types.KotlinType;
029
030 import java.util.Map;
031
032 import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
033
034 public class ControlFlowAnalyzer {
035 @NotNull private final BindingTrace trace;
036 @NotNull private final KotlinBuiltIns builtIns;
037 @NotNull private final LanguageVersionSettings languageVersionSettings;
038
039 public ControlFlowAnalyzer(
040 @NotNull BindingTrace trace, @NotNull KotlinBuiltIns builtIns, @NotNull LanguageVersionSettings languageVersionSettings
041 ) {
042 this.trace = trace;
043 this.builtIns = builtIns;
044 this.languageVersionSettings = languageVersionSettings;
045 }
046
047 public void process(@NotNull BodiesResolveContext c) {
048 for (KtFile file : c.getFiles()) {
049 checkDeclarationContainer(c, file);
050 }
051 for (KtClassOrObject aClass : c.getDeclaredClasses().keySet()) {
052 checkDeclarationContainer(c, aClass);
053 }
054 for (KtScript script : c.getScripts().keySet()) {
055 checkDeclarationContainer(c, script);
056 }
057 for (KtSecondaryConstructor constructor : c.getSecondaryConstructors().keySet()) {
058 checkSecondaryConstructor(constructor);
059 }
060 for (Map.Entry<KtNamedFunction, SimpleFunctionDescriptor> entry : c.getFunctions().entrySet()) {
061 KtNamedFunction function = entry.getKey();
062 SimpleFunctionDescriptor functionDescriptor = entry.getValue();
063 KotlinType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType()
064 ? NO_EXPECTED_TYPE
065 : functionDescriptor.getReturnType();
066 checkFunction(c, function, expectedReturnType);
067 }
068 for (Map.Entry<KtProperty, PropertyDescriptor> entry : c.getProperties().entrySet()) {
069 KtProperty property = entry.getKey();
070 PropertyDescriptor propertyDescriptor = entry.getValue();
071 checkProperty(c, property, propertyDescriptor);
072 }
073 }
074
075 private void checkSecondaryConstructor(@NotNull KtSecondaryConstructor constructor) {
076 ControlFlowInformationProvider controlFlowInformationProvider =
077 new ControlFlowInformationProvider(constructor, trace, languageVersionSettings);
078 controlFlowInformationProvider.checkDeclaration();
079 controlFlowInformationProvider.checkFunction(builtIns.getUnitType());
080 }
081
082 private void checkDeclarationContainer(@NotNull BodiesResolveContext c, KtDeclarationContainer declarationContainer) {
083 // A pseudocode of class/object initialization corresponds to a class/object
084 // or initialization of properties corresponds to a package declared in a file
085 ControlFlowInformationProvider controlFlowInformationProvider =
086 new ControlFlowInformationProvider((KtElement) declarationContainer, trace, languageVersionSettings);
087 if (c.getTopDownAnalysisMode().isLocalDeclarations()) {
088 controlFlowInformationProvider.checkForLocalClassOrObjectMode();
089 return;
090 }
091 controlFlowInformationProvider.checkDeclaration();
092 }
093
094 private void checkProperty(@NotNull BodiesResolveContext c, KtProperty property, PropertyDescriptor propertyDescriptor) {
095 for (KtPropertyAccessor accessor : property.getAccessors()) {
096 PropertyAccessorDescriptor accessorDescriptor = accessor.isGetter()
097 ? propertyDescriptor.getGetter()
098 : propertyDescriptor.getSetter();
099 assert accessorDescriptor != null : "no property accessor descriptor " + accessor.getText();
100 KotlinType returnType = accessorDescriptor.getReturnType();
101 checkFunction(c, accessor, returnType);
102 }
103 }
104
105 private void checkFunction(@NotNull BodiesResolveContext c, @NotNull KtDeclarationWithBody function, @Nullable KotlinType expectedReturnType) {
106 if (!function.hasBody()) return;
107 ControlFlowInformationProvider controlFlowInformationProvider =
108 new ControlFlowInformationProvider(function, trace, languageVersionSettings);
109 if (c.getTopDownAnalysisMode().isLocalDeclarations()) {
110 controlFlowInformationProvider.checkForLocalClassOrObjectMode();
111 return;
112 }
113 controlFlowInformationProvider.checkDeclaration();
114 controlFlowInformationProvider.checkFunction(expectedReturnType);
115 }
116 }