analyze kotlin scripts
This commit is contained in:
+4
@@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
Reference in New Issue
Block a user