001 /*
002 * Copyright 2010-2013 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.jet.lang.resolve;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
021 import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor;
022 import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
023 import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
024 import org.jetbrains.jet.lang.psi.*;
025 import org.jetbrains.jet.lang.types.JetType;
026
027 import javax.inject.Inject;
028 import java.util.Map;
029
030 import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
031
032 public class ControlFlowAnalyzer {
033 private TopDownAnalysisParameters topDownAnalysisParameters;
034 private BindingTrace trace;
035
036 @Inject
037 public void setTopDownAnalysisParameters(TopDownAnalysisParameters topDownAnalysisParameters) {
038 this.topDownAnalysisParameters = topDownAnalysisParameters;
039 }
040
041 @Inject
042 public void setTrace(BindingTrace trace) {
043 this.trace = trace;
044 }
045
046 public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
047 for (JetFile file : bodiesResolveContext.getFiles()) {
048 if (!bodiesResolveContext.completeAnalysisNeeded(file)) continue;
049 checkDeclarationContainer(file);
050 }
051 for (JetClassOrObject aClass : bodiesResolveContext.getClasses().keySet()) {
052 if (!bodiesResolveContext.completeAnalysisNeeded(aClass)) continue;
053 checkDeclarationContainer(aClass);
054 }
055 for (Map.Entry<JetNamedFunction, SimpleFunctionDescriptor> entry : bodiesResolveContext.getFunctions().entrySet()) {
056 JetNamedFunction function = entry.getKey();
057 SimpleFunctionDescriptor functionDescriptor = entry.getValue();
058 if (!bodiesResolveContext.completeAnalysisNeeded(function)) continue;
059 JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType()
060 ? NO_EXPECTED_TYPE
061 : functionDescriptor.getReturnType();
062 checkFunction(function, expectedReturnType);
063 }
064 for (Map.Entry<JetProperty, PropertyDescriptor> entry : bodiesResolveContext.getProperties().entrySet()) {
065 JetProperty property = entry.getKey();
066 if (!bodiesResolveContext.completeAnalysisNeeded(property)) continue;
067 PropertyDescriptor propertyDescriptor = entry.getValue();
068 checkProperty(property, propertyDescriptor);
069 }
070 }
071
072 private void checkDeclarationContainer(JetDeclarationContainer declarationContainer) {
073 // A pseudocode of class/object initialization corresponds to a class/object
074 // or initialization of properties corresponds to a package declared in a file
075 JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetElement) declarationContainer, trace);
076 flowInformationProvider.recordInitializedVariables();
077
078 if (topDownAnalysisParameters.isDeclaredLocally()) return;
079
080 flowInformationProvider.markUninitializedVariables();
081 }
082
083 private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) {
084 for (JetPropertyAccessor accessor : property.getAccessors()) {
085 PropertyAccessorDescriptor accessorDescriptor = accessor.isGetter()
086 ? propertyDescriptor.getGetter()
087 : propertyDescriptor.getSetter();
088 assert accessorDescriptor != null;
089 checkFunction(accessor, accessorDescriptor.getReturnType());
090 }
091 }
092
093 private void checkFunction(JetDeclarationWithBody function, @NotNull JetType expectedReturnType) {
094 assert function instanceof JetDeclaration;
095
096 JetExpression bodyExpression = function.getBodyExpression();
097 if (bodyExpression == null) return;
098 JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) function, trace);
099
100 boolean isPropertyAccessor = function instanceof JetPropertyAccessor;
101 if (!isPropertyAccessor) {
102 flowInformationProvider.recordInitializedVariables();
103 }
104
105 if (topDownAnalysisParameters.isDeclaredLocally()) return;
106
107 flowInformationProvider.checkDefiniteReturn(expectedReturnType);
108
109 if (!isPropertyAccessor) {
110 // Property accessor is checked through initialization of a class/object or package properties (at 'checkDeclarationContainer')
111 flowInformationProvider.markUninitializedVariables();
112 }
113
114 flowInformationProvider.markUnusedVariables();
115
116 flowInformationProvider.markUnusedLiteralsInBlock();
117 }
118 }