Implement modules in IDE
IDE: Rewrite AnalyzerFacade and implementations for JS and JVM to support creating separate analyzers for each module Introduce ModuleInfo which is an intermediate entity between configuration (tests or idea modules) and ModuleDescriptor Implement IdeaModuleInfos which represent IDEA modules, sdks and libraries Add (somewhat thin) test checking their behaviour Implement getModuleInfo() - utility to obtain IdeaModuleInfo for PsiElement Drop Project.getLazyResolveSession() - not possible to obtain resolve session for the whole project any more Adjust JavaResolveExtension accordingly KotlinSignature Intention/Marker - make sure that analyzed element is cls element (he's not in resolve scope otherwise) LightClasses: Create separate package light classes for each module Java code can only reference light class from the first module among it's dependencies Duplicate jvm signature is only reported on package declarations inside one module Injectors: Receive GlobalSearchScope as paramer for VirtualFileFinder and JavaClassFinder which allows to narrow analyzer scope JDR: Introduce ModuleClassResolver resolves java classes in correct java descriptor resolver (corresponding ModuleDescriptor) Add test checking that java classes belong to correct module Debugger: Provide context to analyze files created by debugger in Converter: Postprocessor now needs a context to analyze resulting code in JetPsiFactory: Add verification that files created by psi factory are not analyzed without context (that is almost never a good idea) Other: Use new API in various tests, utilities, run configuration producers and builtin serializers Various "TODO: (module refactoring)" which mark the unfinished parts
This commit is contained in:
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.analyzer;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface AnalyzerFacade {
|
||||
|
||||
interface Setup {
|
||||
@NotNull
|
||||
ResolveSession getLazyResolveSession();
|
||||
}
|
||||
|
||||
class BasicSetup implements Setup {
|
||||
|
||||
private final ResolveSession resolveSession;
|
||||
|
||||
public BasicSetup(@NotNull ResolveSession session) {
|
||||
resolveSession = session;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ResolveSession getLazyResolveSession() {
|
||||
return resolveSession;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Setup createSetup(
|
||||
@NotNull Project project,
|
||||
@NotNull Collection<JetFile> syntheticFiles,
|
||||
@NotNull GlobalSearchScope filesScope
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.analyzer
|
||||
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession
|
||||
import org.jetbrains.jet.lang.resolve.name.Name
|
||||
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
|
||||
import java.util.HashMap
|
||||
import org.jetbrains.jet.lang.resolve.ImportPath
|
||||
import org.jetbrains.jet.lang.PlatformToKotlinClassMap
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.jet.context.GlobalContext
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||
import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.jet.lang.psi.JetFile
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
public trait ResolverForModule {
|
||||
public val lazyResolveSession: ResolveSession
|
||||
}
|
||||
|
||||
public trait ResolverForProject<M : ModuleInfo, R : ResolverForModule> {
|
||||
public fun resolverForModule(moduleInfo: M): R
|
||||
public fun descriptorForModule(moduleInfo: M): ModuleDescriptor
|
||||
}
|
||||
|
||||
public class ResolverForProjectImpl<M : ModuleInfo, R : ResolverForModule>(
|
||||
val descriptorByModule: Map<M, ModuleDescriptorImpl>
|
||||
) : ResolverForProject<M, R> {
|
||||
val resolverByModuleDescriptor: MutableMap<ModuleDescriptor, R> = HashMap()
|
||||
|
||||
private val allModules: Collection<M> by Delegates.lazy {
|
||||
descriptorByModule.keySet()
|
||||
}
|
||||
|
||||
private fun assertCorrectModuleInfo(moduleInfo: M) {
|
||||
if (moduleInfo !in allModules) {
|
||||
throw AssertionError("Requested data for $moduleInfo not contained in this resolver.\nThis resolver was created for following infos:\n${allModules.joinToString("\n")}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun resolverForModule(moduleInfo: M): R {
|
||||
assertCorrectModuleInfo(moduleInfo)
|
||||
val descriptor = descriptorByModule[moduleInfo]!!
|
||||
return resolverByModuleDescriptor[descriptor]!!
|
||||
}
|
||||
|
||||
override fun descriptorForModule(moduleInfo: M): ModuleDescriptorImpl {
|
||||
assertCorrectModuleInfo(moduleInfo)
|
||||
return descriptorByModule[moduleInfo]!!
|
||||
}
|
||||
}
|
||||
|
||||
public data class ModuleContent(
|
||||
public val syntheticFiles: Collection<JetFile>,
|
||||
public val moduleContentScope: GlobalSearchScope
|
||||
)
|
||||
|
||||
public trait PlatformAnalysisParameters
|
||||
|
||||
public trait ModuleInfo {
|
||||
public val name: Name
|
||||
public fun dependencies(): List<ModuleInfo>
|
||||
public fun dependencyOnBuiltins(): DependencyOnBuiltins = DependenciesOnBuiltins.LAST
|
||||
|
||||
//TODO: (module refactoring) provide dependency on builtins after runtime in IDEA
|
||||
public trait DependencyOnBuiltins {
|
||||
public fun adjustDependencies(builtinsModule: ModuleDescriptorImpl, dependencies: MutableList<ModuleDescriptorImpl>)
|
||||
}
|
||||
|
||||
public enum class DependenciesOnBuiltins : DependencyOnBuiltins {
|
||||
|
||||
override fun adjustDependencies(builtinsModule: ModuleDescriptorImpl, dependencies: MutableList<ModuleDescriptorImpl>) {
|
||||
//TODO: KT-5457
|
||||
}
|
||||
|
||||
NONE {
|
||||
override fun adjustDependencies(builtinsModule: ModuleDescriptorImpl, dependencies: MutableList<ModuleDescriptorImpl>) {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
LAST {
|
||||
override fun adjustDependencies(builtinsModule: ModuleDescriptorImpl, dependencies: MutableList<ModuleDescriptorImpl>) {
|
||||
dependencies.add(builtinsModule)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: (module refactoring) extract project context
|
||||
public trait AnalyzerFacade<out A : ResolverForModule, in P : PlatformAnalysisParameters> {
|
||||
public fun <M : ModuleInfo> setupResolverForProject(
|
||||
globalContext: GlobalContext,
|
||||
project: Project,
|
||||
modules: Collection<M>,
|
||||
modulesContent: (M) -> ModuleContent,
|
||||
platformParameters: P
|
||||
): ResolverForProject<M, A> {
|
||||
|
||||
fun createResolverForProject(): ResolverForProjectImpl<M, A> {
|
||||
val descriptorByModule = HashMap<M, ModuleDescriptorImpl>()
|
||||
modules.forEach {
|
||||
module ->
|
||||
descriptorByModule[module] = ModuleDescriptorImpl(module.name, defaultImports, platformToKotlinClassMap)
|
||||
}
|
||||
return ResolverForProjectImpl(descriptorByModule)
|
||||
}
|
||||
|
||||
val resolverForProject = createResolverForProject()
|
||||
|
||||
fun setupModuleDependencies() {
|
||||
modules.forEach {
|
||||
module ->
|
||||
val currentModule = resolverForProject.descriptorForModule(module)
|
||||
val dependenciesDescriptors = module.dependencies().mapTo(ArrayList<ModuleDescriptorImpl>()) {
|
||||
dependencyInfo ->
|
||||
resolverForProject.descriptorForModule(dependencyInfo as M)
|
||||
}
|
||||
|
||||
val builtinsModule = KotlinBuiltIns.getInstance().getBuiltInsModule()
|
||||
module.dependencyOnBuiltins().adjustDependencies(builtinsModule, dependenciesDescriptors)
|
||||
dependenciesDescriptors.forEach { currentModule.addDependencyOnModule(it) }
|
||||
}
|
||||
|
||||
resolverForProject.descriptorByModule.values().forEach { it.seal() }
|
||||
}
|
||||
|
||||
setupModuleDependencies()
|
||||
|
||||
fun initializeResolverForProject() {
|
||||
modules.forEach {
|
||||
module ->
|
||||
val descriptor = resolverForProject.descriptorForModule(module)
|
||||
val resolverForModule = createResolverForModule(
|
||||
project, globalContext, descriptor, modulesContent(module), platformParameters, resolverForProject
|
||||
)
|
||||
assert(descriptor.isInitialized, "ModuleDescriptorImpl#initialize() should be called in createResolverForModule")
|
||||
resolverForProject.resolverByModuleDescriptor[descriptor] = resolverForModule
|
||||
}
|
||||
}
|
||||
|
||||
initializeResolverForProject()
|
||||
return resolverForProject
|
||||
}
|
||||
|
||||
protected fun <M : ModuleInfo> createResolverForModule(
|
||||
project: Project,
|
||||
globalContext: GlobalContext,
|
||||
moduleDescriptor: ModuleDescriptorImpl,
|
||||
moduleContent: ModuleContent,
|
||||
platformParameters: P,
|
||||
resolverForProject: ResolverForProject<M, A>
|
||||
): A
|
||||
|
||||
public val defaultImports: List<ImportPath>
|
||||
public val platformToKotlinClassMap: PlatformToKotlinClassMap
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
package org.jetbrains.jet.di;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.jet.context.GlobalContextImpl;
|
||||
import org.jetbrains.jet.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.jet.context.GlobalContext;
|
||||
import org.jetbrains.jet.storage.StorageManager;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProviderFactory;
|
||||
@@ -52,8 +52,8 @@ import javax.annotation.PreDestroy;
|
||||
public class InjectorForLazyResolve {
|
||||
|
||||
private final Project project;
|
||||
private final GlobalContextImpl globalContext;
|
||||
private final LockBasedStorageManager lockBasedStorageManager;
|
||||
private final GlobalContext globalContext;
|
||||
private final StorageManager storageManager;
|
||||
private final ModuleDescriptorImpl moduleDescriptor;
|
||||
private final PlatformToKotlinClassMap platformToKotlinClassMap;
|
||||
private final DeclarationProviderFactory declarationProviderFactory;
|
||||
@@ -82,14 +82,14 @@ public class InjectorForLazyResolve {
|
||||
|
||||
public InjectorForLazyResolve(
|
||||
@NotNull Project project,
|
||||
@NotNull GlobalContextImpl globalContext,
|
||||
@NotNull GlobalContext globalContext,
|
||||
@NotNull ModuleDescriptorImpl moduleDescriptor,
|
||||
@NotNull DeclarationProviderFactory declarationProviderFactory,
|
||||
@NotNull BindingTrace bindingTrace
|
||||
) {
|
||||
this.project = project;
|
||||
this.globalContext = globalContext;
|
||||
this.lockBasedStorageManager = globalContext.getStorageManager();
|
||||
this.storageManager = globalContext.getStorageManager();
|
||||
this.moduleDescriptor = moduleDescriptor;
|
||||
this.platformToKotlinClassMap = moduleDescriptor.getPlatformToKotlinClassMap();
|
||||
this.declarationProviderFactory = declarationProviderFactory;
|
||||
@@ -125,7 +125,7 @@ public class InjectorForLazyResolve {
|
||||
this.resolveSession.setTypeResolver(typeResolver);
|
||||
|
||||
annotationResolver.setCallResolver(callResolver);
|
||||
annotationResolver.setStorageManager(lockBasedStorageManager);
|
||||
annotationResolver.setStorageManager(storageManager);
|
||||
annotationResolver.setTypeResolver(typeResolver);
|
||||
|
||||
callResolver.setArgumentTypeResolver(argumentTypeResolver);
|
||||
@@ -163,7 +163,7 @@ public class InjectorForLazyResolve {
|
||||
descriptorResolver.setAnnotationResolver(annotationResolver);
|
||||
descriptorResolver.setDelegatedPropertyResolver(delegatedPropertyResolver);
|
||||
descriptorResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
descriptorResolver.setStorageManager(lockBasedStorageManager);
|
||||
descriptorResolver.setStorageManager(storageManager);
|
||||
descriptorResolver.setTypeResolver(typeResolver);
|
||||
|
||||
delegatedPropertyResolver.setCallResolver(callResolver);
|
||||
|
||||
@@ -26,10 +26,17 @@ import org.jetbrains.jet.lang.resolve.ImportPath
|
||||
import org.jetbrains.jet.lexer.JetKeywordToken
|
||||
import org.jetbrains.jet.plugin.JetFileType
|
||||
import org.jetbrains.jet.lang.psi.JetPsiFactory.CallableBuilder.Target
|
||||
import com.intellij.openapi.util.Key
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
|
||||
public fun JetPsiFactory(project: Project?): JetPsiFactory = JetPsiFactory(project!!)
|
||||
public fun JetPsiFactory(contextElement: JetElement): JetPsiFactory = JetPsiFactory(contextElement.getProject())
|
||||
|
||||
public var JetFile.doNotAnalyze: String? by UserDataProperty(Key.create("DO_NOT_ANALYZE"))
|
||||
public var JetFile.analysisContext: PsiElement? by UserDataProperty(Key.create("ANALYSIS_CONTEXT"))
|
||||
|
||||
public class JetPsiFactory(private val project: Project) {
|
||||
|
||||
public fun createValNode(): ASTNode {
|
||||
@@ -114,10 +121,33 @@ public class JetPsiFactory(private val project: Project) {
|
||||
return createFile("dummy.kt", text)
|
||||
}
|
||||
|
||||
public fun createFile(fileName: String, text: String): JetFile {
|
||||
private fun doCreateFile(fileName: String, text: String): JetFile {
|
||||
return PsiFileFactory.getInstance(project).createFileFromText(fileName, JetFileType.INSTANCE, text, LocalTimeCounter.currentTime(), false) as JetFile
|
||||
}
|
||||
|
||||
public fun createFile(fileName: String, text: String): JetFile {
|
||||
val file = doCreateFile(fileName, text)
|
||||
//TODO: KotlinInternalMode should be used here
|
||||
if (ApplicationManager.getApplication()!!.isInternal()) {
|
||||
val sw = StringWriter()
|
||||
Exception().printStackTrace(PrintWriter(sw))
|
||||
file.doNotAnalyze = "This file was created by JetPsiFactory and should not be analyzed. It was created at:\n" + sw.toString()
|
||||
}
|
||||
else {
|
||||
file.doNotAnalyze = "This file was created by JetPsiFactory and should not be analyzed\n" +
|
||||
"Enable kotlin internal mode get more info for debugging\n" +
|
||||
"Use createAnalyzableFile to create file that can be analyzed\n"
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
public fun createAnalyzableFile(fileName: String, text: String, contextToAnalyzeIn: PsiElement): JetFile {
|
||||
val file = doCreateFile(fileName, text)
|
||||
file.analysisContext = contextToAnalyzeIn
|
||||
return file
|
||||
}
|
||||
|
||||
public fun createPhysicalFile(fileName: String, text: String): JetFile {
|
||||
return PsiFileFactory.getInstance(project).createFileFromText(fileName, JetFileType.INSTANCE, text, LocalTimeCounter.currentTime(), true) as JetFile
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.psi
|
||||
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import com.intellij.openapi.util.Key
|
||||
|
||||
public class UserDataProperty<T : Any>(val key: Key<T>) : ReadWriteProperty<JetFile, T?> {
|
||||
override fun get(thisRef: JetFile, desc: kotlin.PropertyMetadata): T? {
|
||||
return thisRef.getUserData(key)
|
||||
}
|
||||
|
||||
override fun set(thisRef: JetFile, desc: kotlin.PropertyMetadata, value: T?) {
|
||||
thisRef.putUserData(key, value)
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import kotlin.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.ReadOnly;
|
||||
import org.jetbrains.jet.context.GlobalContextImpl;
|
||||
import org.jetbrains.jet.context.GlobalContext;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
@@ -111,12 +111,13 @@ public class ResolveSession implements KotlinCodeAnalyzer {
|
||||
@Deprecated
|
||||
public ResolveSession(
|
||||
@NotNull Project project,
|
||||
@NotNull GlobalContextImpl globalContext,
|
||||
@NotNull GlobalContext globalContext,
|
||||
@NotNull ModuleDescriptorImpl rootDescriptor,
|
||||
@NotNull DeclarationProviderFactory declarationProviderFactory,
|
||||
@NotNull BindingTrace delegationTrace
|
||||
) {
|
||||
LockBasedLazyResolveStorageManager lockBasedLazyResolveStorageManager = new LockBasedLazyResolveStorageManager(globalContext.getStorageManager());
|
||||
LockBasedLazyResolveStorageManager lockBasedLazyResolveStorageManager = new LockBasedLazyResolveStorageManager(
|
||||
(LockBasedStorageManager) globalContext.getStorageManager());
|
||||
this.storageManager = lockBasedLazyResolveStorageManager;
|
||||
this.exceptionTracker = globalContext.getExceptionTracker();
|
||||
this.trace = lockBasedLazyResolveStorageManager.createSafeTrace(delegationTrace);
|
||||
|
||||
@@ -53,15 +53,8 @@ public class MainFunctionDetector {
|
||||
};
|
||||
}
|
||||
|
||||
/** Uses the {@code resolveSession} to resolve the function declaration. Suitable when the function declaration is not resolved yet. */
|
||||
public MainFunctionDetector(@NotNull final ResolveSession resolveSession) {
|
||||
this.getFunctionDescriptor = new NotNullFunction<JetNamedFunction, FunctionDescriptor>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public FunctionDescriptor fun(JetNamedFunction function) {
|
||||
return (FunctionDescriptor) resolveSession.resolveToDescriptor(function);
|
||||
}
|
||||
};
|
||||
public MainFunctionDetector(@NotNull NotNullFunction<JetNamedFunction, FunctionDescriptor> functionResolver) {
|
||||
this.getFunctionDescriptor = functionResolver;
|
||||
}
|
||||
|
||||
public boolean hasMain(@NotNull List<JetDeclaration> declarations) {
|
||||
|
||||
Reference in New Issue
Block a user