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
017package org.jetbrains.jet.lang.resolve;
018
019import com.google.common.collect.Lists;
020import com.intellij.openapi.util.Key;
021import org.jetbrains.annotations.NotNull;
022import org.jetbrains.jet.lang.descriptors.*;
023import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
024import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorImpl;
025import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
026import org.jetbrains.jet.lang.parsing.JetScriptDefinition;
027import org.jetbrains.jet.lang.parsing.JetScriptDefinitionProvider;
028import org.jetbrains.jet.lang.psi.JetFile;
029import org.jetbrains.jet.lang.psi.JetNamespaceHeader;
030import org.jetbrains.jet.lang.psi.JetScript;
031import org.jetbrains.jet.lang.resolve.name.FqName;
032import org.jetbrains.jet.lang.resolve.scopes.JetScope;
033import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler;
034import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
035import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
036import org.jetbrains.jet.lang.types.DependencyClassByQualifiedNameResolver;
037import org.jetbrains.jet.lang.types.JetType;
038import org.jetbrains.jet.lang.types.TypeUtils;
039import org.jetbrains.jet.lang.types.ref.JetTypeName;
040
041import javax.inject.Inject;
042import java.util.*;
043
044public class ScriptHeaderResolver {
045
046    public static final Key<Integer> PRIORITY_KEY = Key.create(JetScript.class.getName() + ".priority");
047
048    @NotNull
049    private NamespaceFactory namespaceFactory;
050    @NotNull
051    private DependencyClassByQualifiedNameResolver dependencyClassByQualifiedNameResolver;
052    @NotNull
053    private TopDownAnalysisContext context;
054    @NotNull
055    private BindingTrace trace;
056    @NotNull
057    private TopDownAnalysisParameters topDownAnalysisParameters;
058
059    @Inject
060    public void setNamespaceFactory(@NotNull NamespaceFactory namespaceFactory) {
061        this.namespaceFactory = namespaceFactory;
062    }
063
064    @Inject
065    public void setDependencyClassByQualifiedNameResolver(@NotNull DependencyClassByQualifiedNameResolver dependencyClassByQualifiedNameResolver) {
066        this.dependencyClassByQualifiedNameResolver = dependencyClassByQualifiedNameResolver;
067    }
068
069    @Inject
070    public void setContext(@NotNull TopDownAnalysisContext context) {
071        this.context = context;
072    }
073
074    @Inject
075    public void setTrace(@NotNull BindingTrace trace) {
076        this.trace = trace;
077    }
078
079    @Inject
080    public void setTopDownAnalysisParameters(@NotNull TopDownAnalysisParameters topDownAnalysisParameters) {
081        this.topDownAnalysisParameters = topDownAnalysisParameters;
082    }
083
084
085    @NotNull
086    private ClassDescriptor resolveClass(@NotNull FqName className) {
087        ClassDescriptor classDescriptor = dependencyClassByQualifiedNameResolver.resolveClass(className);
088        if (classDescriptor == null) {
089            throw new IllegalStateException("dependency class not found by name: " + className);
090        }
091        return classDescriptor;
092    }
093
094    @NotNull
095    public JetType resolveTypeName(@NotNull JetTypeName typeName) {
096        List<JetType> typeArguments = new ArrayList<JetType>();
097        for (JetTypeName typeArgumentName : typeName.getArguments()) {
098            typeArguments.add(resolveTypeName(typeArgumentName));
099        }
100        ClassDescriptor classDescriptor = resolveClass(typeName.getClassName());
101        return TypeUtils.substituteParameters(classDescriptor, typeArguments);
102    }
103
104
105    @NotNull
106    private ValueParameterDescriptor resolveScriptParameter(
107            @NotNull AnalyzerScriptParameter scriptParameter,
108            int index,
109            @NotNull ScriptDescriptor script) {
110        JetType type = resolveTypeName(scriptParameter.getType());
111        return new ValueParameterDescriptorImpl(script, index, Collections.<AnnotationDescriptor>emptyList(), scriptParameter.getName(), type, false, null);
112    }
113
114    public void processScriptHierarchy(@NotNull JetScript script, @NotNull JetScope outerScope) {
115        JetFile file = (JetFile) script.getContainingFile();
116        JetNamespaceHeader namespaceHeader = file.getNamespaceHeader();
117        FqName fqName = namespaceHeader != null ? new FqName(namespaceHeader.getQualifiedName()) : FqName.ROOT;
118        NamespaceDescriptorImpl ns = namespaceFactory.createNamespaceDescriptorPathIfNeeded(fqName);
119
120        Integer priority = script.getUserData(PRIORITY_KEY);
121        if (priority == null) {
122            priority = 0;
123        }
124
125        ScriptDescriptor scriptDescriptor = new ScriptDescriptor(ns, priority, script, outerScope);
126        //WriteThroughScope scriptScope = new WriteThroughScope(
127        //        outerScope, ns.getMemberScope(), new TraceBasedRedeclarationHandler(trace));
128        WritableScopeImpl scriptScope = new WritableScopeImpl(outerScope, scriptDescriptor, RedeclarationHandler.DO_NOTHING, "script");
129        scriptScope.changeLockLevel(WritableScope.LockLevel.BOTH);
130
131        context.getScriptScopes().put(script, scriptScope);
132        context.getScripts().put(script, scriptDescriptor);
133
134        trace.record(BindingContext.SCRIPT, script, scriptDescriptor);
135
136        ((WritableScope)outerScope).addClassifierDescriptor(scriptDescriptor.getClassDescriptor());
137    }
138
139    public void resolveScriptDeclarations() {
140        for (Map.Entry<JetScript, ScriptDescriptor> e : context.getScripts().entrySet()) {
141            JetScript declaration = e.getKey();
142            ScriptDescriptor descriptor = e.getValue();
143            WritableScope scope = context.getScriptScopes().get(declaration);
144
145            List<ValueParameterDescriptor> valueParameters = Lists.newArrayList();
146
147            scope.setImplicitReceiver(descriptor.getThisAsReceiverParameter());
148
149            JetFile file = (JetFile) declaration.getContainingFile();
150            JetScriptDefinition scriptDefinition = JetScriptDefinitionProvider.getInstance(file.getProject()).findScriptDefinition(file);
151
152            int index = 0;
153            List<AnalyzerScriptParameter> scriptParameters = !scriptDefinition.getScriptParameters().isEmpty()
154                                                       ? scriptDefinition.getScriptParameters()
155                                                       : topDownAnalysisParameters.getScriptParameters();
156
157            for (AnalyzerScriptParameter scriptParameter : scriptParameters) {
158                ValueParameterDescriptor parameter = resolveScriptParameter(scriptParameter, index, descriptor);
159                valueParameters.add(parameter);
160                scope.addVariableDescriptor(parameter);
161                ++index;
162            }
163
164            descriptor.setValueParameters(valueParameters);
165        }
166    }
167}