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.extension;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.jet.lang.descriptors.*;
021 import org.jetbrains.jet.lang.diagnostics.Errors;
022 import org.jetbrains.jet.lang.psi.*;
023 import org.jetbrains.jet.lang.resolve.BindingTrace;
024 import org.jetbrains.jet.lang.resolve.FunctionAnalyzerExtension;
025 import org.jetbrains.jet.lang.types.JetType;
026 import org.jetbrains.jet.lang.types.lang.InlineUtil;
027 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
028
029 import java.util.List;
030
031 public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.AnalyzerExtension {
032
033 public static final InlineAnalyzerExtension INSTANCE = new InlineAnalyzerExtension();
034
035 private InlineAnalyzerExtension() {
036
037 }
038
039 @Override
040 public void process(
041 @NotNull final FunctionDescriptor descriptor, @NotNull JetNamedFunction function, @NotNull final BindingTrace trace
042 ) {
043 assert descriptor instanceof SimpleFunctionDescriptor && ((SimpleFunctionDescriptor) descriptor).getInlineStrategy().isInline() :
044 "This method should be invoced on inline function: " + descriptor;
045
046 checkDefaults(descriptor, function, trace);
047 checkNotVirtual(descriptor, function, trace);
048 checkHasInlinableAndNullability(descriptor, function, trace);
049
050 JetVisitorVoid visitor = new JetVisitorVoid() {
051
052 @Override
053 public void visitJetElement(@NotNull JetElement element) {
054 super.visitJetElement(element);
055 element.acceptChildren(this);
056 }
057
058 @Override
059 public void visitClass(@NotNull JetClass klass) {
060 trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(klass, klass, descriptor));
061 }
062
063 @Override
064 public void visitObjectDeclaration(@NotNull JetObjectDeclaration declaration) {
065 trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(declaration, declaration, descriptor));
066 }
067
068 @Override
069 public void visitNamedFunction(@NotNull JetNamedFunction function) {
070 trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(function, function, descriptor));
071 }
072 };
073
074 function.acceptChildren(visitor);
075 }
076
077 private static void checkDefaults(
078 @NotNull FunctionDescriptor functionDescriptor,
079 @NotNull JetFunction function,
080 @NotNull BindingTrace trace
081 ) {
082 int index = 0;
083 List<JetParameter> jetParameters = function.getValueParameters();
084 for (ValueParameterDescriptor parameter : functionDescriptor.getValueParameters()) {
085 if (parameter.hasDefaultValue()) {
086 JetParameter jetParameter = jetParameters.get(index);
087 trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(jetParameter, jetParameter, functionDescriptor));
088 }
089 index++;
090 }
091 }
092
093 private static void checkNotVirtual(
094 @NotNull FunctionDescriptor functionDescriptor,
095 @NotNull JetFunction function,
096 @NotNull BindingTrace trace
097 ) {
098 if (functionDescriptor.getVisibility() == Visibilities.PRIVATE || functionDescriptor.getModality() == Modality.FINAL) {
099 return;
100 }
101
102 if (functionDescriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor) {
103 return;
104 }
105
106 trace.report(Errors.DECLARATION_CANT_BE_INLINED.on(function));
107 }
108
109
110 private static void checkHasInlinableAndNullability(
111 @NotNull FunctionDescriptor functionDescriptor,
112 @NotNull JetFunction function,
113 @NotNull BindingTrace trace
114 ) {
115 boolean hasInlinable = false;
116 List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
117 int index = 0;
118 for (ValueParameterDescriptor parameter : parameters) {
119 hasInlinable |= checkInlinableParameter(parameter, function.getValueParameters().get(index++), functionDescriptor, trace);
120 }
121 ReceiverParameterDescriptor receiverParameter = functionDescriptor.getReceiverParameter();
122 if (receiverParameter != null) {
123 JetTypeReference receiver = function.getReceiverTypeRef();
124 assert receiver != null : "Descriptor has a receiver but psi doesn't " + function.getText();
125 hasInlinable |= checkInlinableParameter(receiverParameter, receiver, functionDescriptor, trace);
126 }
127
128 if (!hasInlinable) {
129 trace.report(Errors.NOTHING_TO_INLINE.on(function, functionDescriptor));
130 }
131 }
132
133 private static boolean checkInlinableParameter(
134 @NotNull CallableDescriptor parameter,
135 @NotNull JetElement expression,
136 @NotNull FunctionDescriptor functionDescriptor,
137 @NotNull BindingTrace trace
138 ) {
139 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
140 JetType type = parameter.getReturnType();
141 if (type != null && builtIns.isExactFunctionOrExtensionFunctionType(type)) {
142 if (!InlineUtil.hasNoinlineAnnotation(parameter)) {
143 if (type.isNullable()) {
144 trace.report(Errors.NULLABLE_INLINE_PARAMETER.on(expression, expression, functionDescriptor));
145 }
146 else {
147 return true;
148 }
149 }
150 }
151 return false;
152 }
153 }