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