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 assert expectedReturnType != null 063 : "functionDescriptor is not yet fully initialized or broken so return type is null " + functionDescriptor; 064 checkFunction(function, expectedReturnType); 065 } 066 for (Map.Entry<JetProperty, PropertyDescriptor> entry : bodiesResolveContext.getProperties().entrySet()) { 067 JetProperty property = entry.getKey(); 068 if (!bodiesResolveContext.completeAnalysisNeeded(property)) continue; 069 PropertyDescriptor propertyDescriptor = entry.getValue(); 070 checkProperty(property, propertyDescriptor); 071 } 072 } 073 074 private void checkDeclarationContainer(JetDeclarationContainer declarationContainer) { 075 // A pseudocode of class/object initialization corresponds to a class/object 076 // or initialization of properties corresponds to a package declared in a file 077 JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetElement) declarationContainer, trace); 078 flowInformationProvider.recordInitializedVariables(); 079 080 if (topDownAnalysisParameters.isDeclaredLocally()) return; 081 082 flowInformationProvider.markUninitializedVariables(); 083 } 084 085 private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) { 086 for (JetPropertyAccessor accessor : property.getAccessors()) { 087 PropertyAccessorDescriptor accessorDescriptor = accessor.isGetter() 088 ? propertyDescriptor.getGetter() 089 : propertyDescriptor.getSetter(); 090 assert accessorDescriptor != null : "no property accessor descriptor " + accessor.getText(); 091 JetType returnType = accessorDescriptor.getReturnType(); 092 assert returnType != null : "property accessor has no return type " + accessorDescriptor; 093 checkFunction(accessor, returnType); 094 } 095 } 096 097 private void checkFunction(@NotNull JetDeclarationWithBody function, @NotNull JetType expectedReturnType) { 098 JetExpression bodyExpression = function.getBodyExpression(); 099 if (bodyExpression == null) return; 100 JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider(function, trace); 101 flowInformationProvider.checkFunction(function, expectedReturnType, topDownAnalysisParameters.isDeclaredLocally()); 102 } 103 }