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.*;
023    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
024    import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorImpl;
025    import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
026    import org.jetbrains.jet.lang.parsing.JetScriptDefinition;
027    import org.jetbrains.jet.lang.parsing.JetScriptDefinitionProvider;
028    import org.jetbrains.jet.lang.psi.JetFile;
029    import org.jetbrains.jet.lang.psi.JetNamespaceHeader;
030    import org.jetbrains.jet.lang.psi.JetScript;
031    import org.jetbrains.jet.lang.resolve.name.FqName;
032    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
033    import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler;
034    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
035    import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
036    import org.jetbrains.jet.lang.types.DependencyClassByQualifiedNameResolver;
037    import org.jetbrains.jet.lang.types.JetType;
038    import org.jetbrains.jet.lang.types.TypeUtils;
039    import org.jetbrains.jet.lang.types.ref.JetTypeName;
040    
041    import javax.inject.Inject;
042    import java.util.*;
043    
044    public 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    }