analyze kotlin scripts

This commit is contained in:
Stepan Koltsov
2012-05-23 02:52:29 +04:00
parent 5fc73a4cd4
commit d6bf8876a3
12 changed files with 162 additions and 27 deletions
@@ -52,6 +52,10 @@ public class DeclarationDescriptorVisitor<R, D> {
return visitFunctionDescriptor(constructorDescriptor, data);
}
public R visitScriptDescriptor(ScriptDescriptor scriptDescriptor, D data) {
return visitDeclarationDescriptor(scriptDescriptor, data);
}
public R visitLocalVariableDescriptor(LocalVariableDescriptor descriptor, D data) {
return visitVariableDescriptor(descriptor, data);
}
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2012 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.jet.lang.descriptors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import java.util.Collections;
/**
* @author Stepan Koltsov
*/
public class ScriptDescriptor extends DeclarationDescriptorImpl {
private JetType returnType;
public ScriptDescriptor(@Nullable DeclarationDescriptor containingDeclaration) {
super(containingDeclaration, Collections.<AnnotationDescriptor>emptyList(), "<script>");
}
public void initialize(@NotNull JetType returnType) {
this.returnType = returnType;
}
@Override
public DeclarationDescriptor substitute(TypeSubstitutor substitutor) {
throw new IllegalStateException("nothing to substitute in script");
}
@Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitScriptDescriptor(this, data);
}
}
@@ -17,8 +17,11 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* @author Stepan Koltsov
*/
@@ -33,6 +36,11 @@ public class JetScript extends JetDeclaration {
return findNotNullChildByClass(JetBlockExpression.class);
}
@NotNull
public List<JetImportDirective> getImportDirectives() {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JetImportDirective.class);
}
@Override
public void accept(@NotNull JetVisitorVoid visitor) {
visitor.visitScript(this);
@@ -129,6 +129,7 @@ public interface BindingContext {
WritableSlice<PsiElement, NamespaceDescriptor> NAMESPACE = Slices.<PsiElement, NamespaceDescriptor>sliceBuilder().setOpposite((WritableSlice) BindingContextUtils.DESCRIPTOR_TO_DECLARATION).build();
WritableSlice<PsiElement, ClassDescriptor> CLASS = Slices.<PsiElement, ClassDescriptor>sliceBuilder().setOpposite((WritableSlice) BindingContextUtils.DESCRIPTOR_TO_DECLARATION).build();
WritableSlice<PsiElement, ScriptDescriptor> SCRIPT = Slices.<PsiElement, ScriptDescriptor>sliceBuilder().setOpposite((WritableSlice) BindingContextUtils.DESCRIPTOR_TO_DECLARATION).build();
WritableSlice<JetTypeParameter, TypeParameterDescriptor> TYPE_PARAMETER = Slices.<JetTypeParameter, TypeParameterDescriptor>sliceBuilder().setOpposite((WritableSlice) BindingContextUtils.DESCRIPTOR_TO_DECLARATION).build();
/** @see BindingContextUtils#recordFunctionDeclarationToDescriptor(BindingTrace, PsiElement, SimpleFunctionDescriptor)} */
WritableSlice<PsiElement, SimpleFunctionDescriptor> FUNCTION = Slices.<PsiElement, SimpleFunctionDescriptor>sliceBuilder().setOpposite((WritableSlice) BindingContextUtils.DESCRIPTOR_TO_DECLARATION).build();
@@ -33,7 +33,10 @@ import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.expressions.CoercionStrategy;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
import org.jetbrains.jet.lang.types.expressions.LabelResolver;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.util.Box;
@@ -109,6 +112,8 @@ public class BodyResolver {
resolveSecondaryConstructorBodies();
resolveFunctionBodies();
resolveScripts();
if (!topDownAnalysisParameters.isDeclaredLocally()) {
computeDeferredTypes();
}
@@ -613,4 +618,24 @@ public class BodyResolver {
}
}
}
private void resolveScripts() {
for (Map.Entry<JetScript, ScriptDescriptor> e : context.getScripts().entrySet()) {
JetScript declaration = e.getKey();
ScriptDescriptor descriptor = e.getValue();
JetScope scope = context.getScriptScopes().get(declaration);
ExpressionTypingContext context = ExpressionTypingContext.newContext(
expressionTypingServices,
Maps.<JetPattern, DataFlowInfo>newHashMap(),
Maps.<JetPattern, List<VariableDescriptor>>newHashMap(),
new LabelResolver(),
trace,
this.context.getRootScope(),
DataFlowInfo.EMPTY,
NO_EXPECTED_TYPE,
false);
JetType returnType = expressionTypingServices.getBlockReturnedType(scope, declaration.getBlockExpression(), CoercionStrategy.NO_COERCION, context, trace);
descriptor.initialize(returnType);
}
}
}
@@ -77,34 +77,42 @@ public class ImportsResolver {
private void processImports(boolean onlyClasses) {
for (JetFile file : context.getNamespaceDescriptors().keySet()) {
JetScope rootScope = context.getRootScope();
WritableScope namespaceScope = context.getNamespaceScopes().get(file);
Importer.DelayedImporter delayedImporter = new Importer.DelayedImporter(namespaceScope);
if (!onlyClasses) {
namespaceScope.clearImports();
}
Map<JetImportDirective, DeclarationDescriptor> resolvedDirectives = Maps.newHashMap();
Collection<JetImportDirective> defaultImportDirectives = Lists.newArrayList();
configuration.addDefaultImports(defaultImportDirectives);
for (JetImportDirective defaultImportDirective : defaultImportDirectives) {
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); //not to trace errors of default imports
qualifiedExpressionResolver.processImportReference(defaultImportDirective, rootScope, namespaceScope, delayedImporter, temporaryTrace, onlyClasses);
}
processImportsInFile(onlyClasses, namespaceScope, file.getImportDirectives());
}
for (JetScript script : context.getScripts().keySet()) {
WritableScope scriptScope = context.getScriptScopes().get(script);
processImportsInFile(onlyClasses, scriptScope, script.getImportDirectives());
}
}
List<JetImportDirective> importDirectives = file.getImportDirectives();
private void processImportsInFile(boolean onlyClasses, WritableScope namespaceScope, List<JetImportDirective> importDirectives) {
JetScope rootScope = context.getRootScope();
Importer.DelayedImporter delayedImporter = new Importer.DelayedImporter(namespaceScope);
if (!onlyClasses) {
namespaceScope.clearImports();
}
Map<JetImportDirective, DeclarationDescriptor> resolvedDirectives = Maps.newHashMap();
Collection<JetImportDirective> defaultImportDirectives = Lists.newArrayList();
configuration.addDefaultImports(defaultImportDirectives);
for (JetImportDirective defaultImportDirective : defaultImportDirectives) {
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); //not to trace errors of default imports
qualifiedExpressionResolver.processImportReference(defaultImportDirective, rootScope, namespaceScope, delayedImporter, temporaryTrace, onlyClasses);
}
for (JetImportDirective importDirective : importDirectives) {
Collection<? extends DeclarationDescriptor> descriptors =
qualifiedExpressionResolver.processImportReference(importDirective, rootScope, namespaceScope, delayedImporter, trace, onlyClasses);
if (descriptors.size() == 1) {
resolvedDirectives.put(importDirective, descriptors.iterator().next());
}
}
delayedImporter.processImports();
if (!onlyClasses) {
for (JetImportDirective importDirective : importDirectives) {
Collection<? extends DeclarationDescriptor> descriptors =
qualifiedExpressionResolver.processImportReference(importDirective, rootScope, namespaceScope, delayedImporter, trace, onlyClasses);
if (descriptors.size() == 1) {
resolvedDirectives.put(importDirective, descriptors.iterator().next());
}
}
delayedImporter.processImports();
if (!onlyClasses) {
for (JetImportDirective importDirective : importDirectives) {
reportUselessImport(importDirective, namespaceScope, resolvedDirectives);
}
reportUselessImport(importDirective, namespaceScope, resolvedDirectives);
}
}
}
@@ -54,6 +54,9 @@ public class TopDownAnalysisContext {
public final Map<JetDeclarationContainer, JetScope> normalScope = Maps.newHashMap();
private final Map<JetScript, ScriptDescriptor> scripts = Maps.newLinkedHashMap();
private final Map<JetScript, WritableScope> scriptScopes = Maps.newHashMap();
private StringBuilder debugOutput;
@@ -120,6 +123,16 @@ public class TopDownAnalysisContext {
return namespaceDescriptors;
}
@NotNull
public Map<JetScript, ScriptDescriptor> getScripts() {
return scripts;
}
@NotNull
public Map<JetScript, WritableScope> getScriptScopes() {
return scriptScopes;
}
public Map<JetParameter, PropertyDescriptor> getPrimaryConstructorParameterProperties() {
return primaryConstructorParameterProperties;
}
@@ -186,6 +186,12 @@ public class TypeHierarchyResolver {
declaration.accept(new JetVisitorVoid() {
@Override
public void visitJetFile(JetFile file) {
if (file.isScript()) {
JetScript script = file.getScript();
processScript(script);
return;
}
NamespaceDescriptorImpl namespaceDescriptor = namespaceFactory.createNamespaceDescriptorPathIfNeeded(
file, outerScope, RedeclarationHandler.DO_NOTHING);
context.getNamespaceDescriptors().put(file, namespaceDescriptor);
@@ -198,6 +204,17 @@ public class TypeHierarchyResolver {
prepareForDeferredCall(namespaceScope, namespaceDescriptor, file);
}
private void processScript(JetScript script) {
NamespaceDescriptorImpl ns = namespaceFactory.createNamespaceDescriptorPathIfNeeded(FqName.ROOT);
ScriptDescriptor scriptDescriptor = new ScriptDescriptor(ns);
WriteThroughScope scriptScope = new WriteThroughScope(
outerScope, ns.getMemberScope(), new TraceBasedRedeclarationHandler(trace));
scriptScope.changeLockLevel(WritableScope.LockLevel.BOTH);
context.getScriptScopes().put(script, scriptScope);
context.getScripts().put(script, scriptDescriptor);
trace.record(BindingContext.SCRIPT, script, scriptDescriptor);
}
@Override
public void visitClass(JetClass klass) {
MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
@@ -610,4 +627,4 @@ public class TypeHierarchyResolver {
}
}
}
}
}
@@ -187,7 +187,7 @@ public class ExpressionTypingServices {
}
@Nullable
/*package*/ JetType getBlockReturnedType(@NotNull JetScope outerScope, @NotNull JetBlockExpression expression, @NotNull CoercionStrategy coercionStrategyForLastExpression, ExpressionTypingContext context, BindingTrace trace) {
public JetType getBlockReturnedType(@NotNull JetScope outerScope, @NotNull JetBlockExpression expression, @NotNull CoercionStrategy coercionStrategyForLastExpression, ExpressionTypingContext context, BindingTrace trace) {
List<JetElement> block = expression.getStatements();
if (block.isEmpty()) {
return DataFlowUtils.checkType(JetStandardClasses.getUnitType(), expression, context);
@@ -0,0 +1,3 @@
val x = <!UNRESOLVED_REFERENCE!>y<!>
val y = 2
@@ -0,0 +1,5 @@
fun foo(x: Int) = 1
val y = 2
foo(y)
@@ -0,0 +1 @@
val x = 1